From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- toolkit/crashreporter/CrashAnnotations.cpp | 53 + toolkit/crashreporter/CrashAnnotations.h.in | 105 + toolkit/crashreporter/CrashAnnotations.yaml | 1028 + toolkit/crashreporter/CrashReports.sys.mjs | 81 + toolkit/crashreporter/CrashSubmit.sys.mjs | 666 + toolkit/crashreporter/InjectCrashReporter.cpp | 77 + toolkit/crashreporter/InjectCrashReporter.h | 27 + toolkit/crashreporter/LoadLibraryRemote.cpp | 459 + toolkit/crashreporter/LoadLibraryRemote.h | 23 + .../linux/crash_generation/client_info.h | 68 + .../crash_generation/crash_generation_client.cc | 105 + .../crash_generation/crash_generation_client.h | 65 + .../crash_generation/crash_generation_server.cc | 383 + .../crash_generation/crash_generation_server.h | 135 + .../breakpad-client/linux/data/linux-gate-amd.sym | 3 + .../linux/data/linux-gate-intel.sym | 3 + .../linux/dump_writer_common/mapping_info.h | 75 + .../linux/dump_writer_common/raw_context_cpu.h | 53 + .../linux/dump_writer_common/thread_info.cc | 305 + .../linux/dump_writer_common/thread_info.h | 91 + .../linux/dump_writer_common/ucontext_reader.cc | 259 + .../linux/dump_writer_common/ucontext_reader.h | 65 + .../linux/handler/exception_handler.cc | 876 + .../linux/handler/exception_handler.h | 289 + .../linux/handler/exception_handler_unittest.cc | 1290 ++ .../linux/handler/guid_generator.cc | 108 + .../breakpad-client/linux/handler/guid_generator.h | 48 + .../linux/handler/microdump_extra_info.h | 52 + .../linux/handler/minidump_descriptor.cc | 96 + .../linux/handler/minidump_descriptor.h | 199 + .../crashreporter/breakpad-client/linux/log/log.cc | 84 + .../crashreporter/breakpad-client/linux/log/log.h | 55 + .../linux/microdump_writer/microdump_writer.cc | 664 + .../linux/microdump_writer/microdump_writer.h | 68 + .../microdump_writer/microdump_writer_unittest.cc | 421 + .../linux/minidump_writer/cpu_set.h | 144 + .../linux/minidump_writer/cpu_set_unittest.cc | 164 + .../linux/minidump_writer/directory_reader.h | 106 + .../minidump_writer/directory_reader_unittest.cc | 78 + .../linux/minidump_writer/line_reader.h | 131 + .../linux/minidump_writer/line_reader_unittest.cc | 169 + .../linux/minidump_writer/linux_core_dumper.cc | 308 + .../linux/minidump_writer/linux_core_dumper.h | 130 + .../minidump_writer/linux_core_dumper_unittest.cc | 192 + .../linux/minidump_writer/linux_dumper.cc | 999 + .../linux/minidump_writer/linux_dumper.h | 333 + .../linux_dumper_unittest_helper.cc | 95 + .../linux/minidump_writer/linux_ptrace_dumper.cc | 403 + .../linux/minidump_writer/linux_ptrace_dumper.h | 106 + .../linux_ptrace_dumper_unittest.cc | 580 + .../linux/minidump_writer/minidump_writer.cc | 1562 ++ .../linux/minidump_writer/minidump_writer.h | 143 + .../minidump_writer/minidump_writer_unittest.cc | 934 + .../minidump_writer_unittest_utils.cc | 66 + .../minidump_writer_unittest_utils.h | 49 + .../linux/minidump_writer/proc_cpuinfo_reader.h | 130 + .../proc_cpuinfo_reader_unittest.cc | 199 + .../crashreporter/breakpad-client/linux/moz.build | 47 + .../mac/crash_generation/client_info.h | 49 + .../crash_generation/crash_generation_client.cc | 74 + .../mac/crash_generation/crash_generation_client.h | 66 + .../crash_generation/crash_generation_server.cc | 164 + .../mac/crash_generation/crash_generation_server.h | 151 + .../breakpad-client/mac/crash_generation/moz.build | 18 + .../mac/handler/breakpad_nlist_64.cc | 402 + .../mac/handler/breakpad_nlist_64.h | 48 + .../breakpad-client/mac/handler/dynamic_images.cc | 625 + .../breakpad-client/mac/handler/dynamic_images.h | 386 + .../mac/handler/exception_handler.cc | 991 + .../mac/handler/exception_handler.h | 297 + .../breakpad-client/mac/handler/mach_vm_compat.h | 88 + .../mac/handler/minidump_generator.cc | 2135 ++ .../mac/handler/minidump_generator.h | 290 + .../minidump_test.xcodeproj/project.pbxproj | 843 + .../breakpad-client/mac/handler/moz.build | 22 + .../mac/handler/protected_memory_allocator.cc | 92 + .../mac/handler/protected_memory_allocator.h | 85 + .../mac/handler/testcases/DynamicImagesTests.cc | 79 + .../mac/handler/testcases/DynamicImagesTests.h | 52 + .../mac/handler/testcases/breakpad_nlist_test.cc | 106 + .../mac/handler/testcases/breakpad_nlist_test.h | 62 + .../mac/handler/testcases/dwarftests.h | 46 + .../mac/handler/testcases/dwarftests.mm | 60 + .../testcases/testdata/dump_syms_dwarf_data | Bin 0 -> 702795 bytes .../testcases/testdata/dump_syms_i386_breakpad.sym | 5300 +++++ .../breakpad-client/mac/handler/ucontext_compat.h | 47 + .../mac/tests/BreakpadFramework_Test.mm | 217 + .../mac/tests/crash_generation_server_test.cc | 398 + .../mac/tests/exception_handler_test.cc | 714 + .../mac/tests/minidump_generator_test.cc | 320 + .../mac/tests/minidump_generator_test_helper.cc | 74 + .../mac/tests/spawn_child_process.h | 149 + .../breakpad-client/mac/tests/testlogging.h | 9 + .../breakpad-client/minidump_file_writer-inl.h | 97 + .../breakpad-client/minidump_file_writer.cc | 402 + .../breakpad-client/minidump_file_writer.h | 281 + .../minidump_file_writer_unittest.cc | 179 + toolkit/crashreporter/breakpad-client/moz.build | 33 + .../windows/common/auto_critical_section.h | 81 + .../breakpad-client/windows/common/ipc_protocol.h | 181 + .../windows/common/minidump_callback.cc | 319 + .../windows/common/minidump_callback.h | 78 + .../breakpad-client/windows/common/objs.mozbuild | 14 + .../windows/crash_generation/ReadMe.txt | 58 + .../windows/crash_generation/client_info.cc | 258 + .../windows/crash_generation/client_info.h | 182 + .../crash_generation/crash_generation_client.cc | 406 + .../crash_generation/crash_generation_client.h | 182 + .../crash_generation/crash_generation_server.cc | 996 + .../crash_generation/crash_generation_server.h | 318 + .../windows/crash_generation/minidump_generator.cc | 581 + .../windows/crash_generation/minidump_generator.h | 203 + .../windows/crash_generation/objs.mozbuild | 17 + .../windows/handler/exception_handler.cc | 1121 + .../windows/handler/exception_handler.h | 547 + .../breakpad-client/windows/handler/objs.mozbuild | 17 + .../windows/sender/crash_report_sender.cc | 140 + .../windows/sender/crash_report_sender.h | 122 + .../breakpad-client/windows/sender/objs.mozbuild | 14 + .../unittests/crash_generation_server_test.cc | 303 + .../windows/unittests/dump_analysis.cc | 184 + .../windows/unittests/dump_analysis.h | 102 + .../unittests/exception_handler_death_test.cc | 587 + .../unittests/exception_handler_nesting_test.cc | 327 + .../windows/unittests/exception_handler_test.cc | 503 + .../windows/unittests/exception_handler_test.h | 61 + .../windows/unittests/minidump_test.cc | 332 + .../breakpad-patches/00-arm-exidx-rollup.patch | 1352 ++ .../02-define-print-mach-result.patch | 24 + .../03-strstr-libc-replacement.patch | 54 + .../breakpad-patches/04-update-headers.patch | 6039 +++++ .../breakpad-patches/09-json-upload.patch | 333 + .../breakpad-patches/10-macho-cpu-subtype.patch | 47 + .../12-macho-cpu-subtype-fix.patch | 22 + .../13-improve-arm64-stack-walking.patch | 79 + ...dle-non-fixed-size-amd64-and-x86-contexts.patch | 344 + .../15-freebsd-profiler-support.patch | 107 + .../breakpad-patches/16-get-last-error.patch | 181 + .../breakpad-patches/17-unloaded-modules.patch | 251 + .../breakpad-patches/18-fastfail-codes.patch | 359 + .../breakpad-patches/19-updated-ntstatus.patch | 3500 +++ .../breakpad-patches/20-mac-crash-info.patch | 516 + .../breakpad-patches/21-thread-names.patch | 661 + .../breakpad-patches/22-winerror-codes.patch | 22069 +++++++++++++++++++ .../23-si-user-si-kernel-siginfo.patch | 76 + .../breakpad-patches/24-macos-exc-resource.patch | 155 + .../breakpad-patches/25-macos-exc-guard.patch | 349 + .../breakpad-patches/26-print-thread-tid.patch | 44 + .../27-fix-unified-builds-bug-1733547.patch | 22 + .../28-no-garbage-in-code-ids.patch | 34 + .../breakpad-patches/29-cpu-context-packing.patch | 118 + .../breakpad-patches/30-sign-compare.patch | 11 + toolkit/crashreporter/breakpad-patches/README | 4 + .../breakpad-windows-libxul/moz.build | 29 + .../breakpad-windows-standalone/moz.build | 29 + toolkit/crashreporter/client/Makefile.in | 19 + toolkit/crashreporter/client/Throbber-small.avi | Bin 0 -> 3584 bytes toolkit/crashreporter/client/Throbber-small.gif | Bin 0 -> 825 bytes toolkit/crashreporter/client/crashreporter.cpp | 852 + .../client/crashreporter.exe.manifest | 42 + toolkit/crashreporter/client/crashreporter.h | 158 + toolkit/crashreporter/client/crashreporter.ico | Bin 0 -> 25214 bytes toolkit/crashreporter/client/crashreporter.rc | 143 + .../client/crashreporter_gtk_common.cpp | 361 + .../client/crashreporter_gtk_common.h | 50 + .../crashreporter/client/crashreporter_linux.cpp | 525 + toolkit/crashreporter/client/crashreporter_osx.h | 108 + toolkit/crashreporter/client/crashreporter_osx.mm | 805 + .../client/crashreporter_unix_common.cpp | 139 + toolkit/crashreporter/client/crashreporter_win.cpp | 1266 ++ .../client/macbuild/Contents/Info.plist | 36 + .../crashreporter/client/macbuild/Contents/PkgInfo | 2 + .../Resources/English.lproj/InfoPlist.strings.in | 8 + .../English.lproj/MainMenu.nib/classes.nib | 100 + .../Resources/English.lproj/MainMenu.nib/info.nib | 18 + .../English.lproj/MainMenu.nib/keyedobjects.nib | Bin 0 -> 25518 bytes .../English.lproj/MainMenuRTL.nib/classes.nib | 100 + .../English.lproj/MainMenuRTL.nib/info.nib | 18 + .../English.lproj/MainMenuRTL.nib/keyedobjects.nib | Bin 0 -> 27032 bytes .../macbuild/Contents/Resources/crashreporter.icns | Bin 0 -> 61743 bytes toolkit/crashreporter/client/moz.build | 97 + toolkit/crashreporter/client/ping.cpp | 324 + toolkit/crashreporter/client/resource.h | 35 + toolkit/crashreporter/content/crashes.css | 67 + toolkit/crashreporter/content/crashes.html | 99 + toolkit/crashreporter/content/crashes.js | 316 + toolkit/crashreporter/crashreporter.mozbuild | 34 + .../docs/Using_the_Mozilla_symbol_server.rst | 180 + .../crashreporter/docs/img/snip_20170901070042.png | Bin 0 -> 15434 bytes .../crashreporter/docs/img/snip_20170901081816.png | Bin 0 -> 3821 bytes .../docs/img/symbol-server-windbg-menu.jpg | Bin 0 -> 17919 bytes .../crashreporter/docs/img/vs_tools_options.png | Bin 0 -> 12084 bytes toolkit/crashreporter/docs/index.rst | 266 + .../generate_crash_reporter_sources.py | 259 + toolkit/crashreporter/google-breakpad/.gitignore | 90 + toolkit/crashreporter/google-breakpad/AUTHORS | 1 + toolkit/crashreporter/google-breakpad/ChangeLog | 0 toolkit/crashreporter/google-breakpad/DEPS | 84 + toolkit/crashreporter/google-breakpad/GIT-INFO | 1 + toolkit/crashreporter/google-breakpad/INSTALL | 370 + toolkit/crashreporter/google-breakpad/LICENSE | 50 + toolkit/crashreporter/google-breakpad/Makefile.am | 1576 ++ toolkit/crashreporter/google-breakpad/Makefile.in | 8223 +++++++ toolkit/crashreporter/google-breakpad/NEWS | 0 .../crashreporter/google-breakpad/README.ANDROID | 139 + toolkit/crashreporter/google-breakpad/README.md | 82 + toolkit/crashreporter/google-breakpad/aclocal.m4 | 1304 ++ .../google-breakpad/android/common-functions.sh | 372 + .../android/google_breakpad/Android.mk | 104 + .../google-breakpad/android/run-checks.sh | 555 + .../google-breakpad/android/sample_app/README | 32 + .../android/sample_app/jni/Android.mk | 44 + .../android/sample_app/jni/Application.mk | 32 + .../android/sample_app/jni/test_breakpad.cpp | 57 + .../google-breakpad/android/test-driver | 131 + .../google-breakpad/android/test-shell.sh | 131 + .../google-breakpad/breakpad-client.pc.in | 10 + .../crashreporter/google-breakpad/breakpad.pc.in | 10 + .../google-breakpad/codereview.settings | 3 + toolkit/crashreporter/google-breakpad/configure | 9231 ++++++++ toolkit/crashreporter/google-breakpad/configure.ac | 271 + toolkit/crashreporter/google-breakpad/default.xml | 43 + .../src/breakpad_googletest_includes.h | 57 + .../google-breakpad/src/build/all.gyp | 41 + .../google-breakpad/src/build/common.gypi | 1045 + .../google-breakpad/src/build/filename_rules.gypi | 57 + .../google-breakpad/src/build/gyp_breakpad | 67 + .../google-breakpad/src/build/testing.gyp | 90 + .../src/common/android/include/asm-mips/README.md | 9 + .../src/common/android/include/asm-mips/asm.h | 270 + .../src/common/android/include/asm-mips/fpregdef.h | 117 + .../src/common/android/include/asm-mips/regdef.h | 125 + .../src/common/android/include/elf.h | 157 + .../src/common/android/include/link.h | 77 + .../src/common/android/include/stab.h | 100 + .../src/common/android/include/sys/procfs.h | 124 + .../src/common/android/include/sys/user.h | 69 + .../src/common/android/testing/include/wchar.h | 76 + .../src/common/android/testing/mkdtemp.h | 110 + .../src/common/android/testing/pthread_fixes.h | 94 + .../google-breakpad/src/common/arm_ex_reader.cc | 487 + .../google-breakpad/src/common/arm_ex_reader.h | 114 + .../google-breakpad/src/common/arm_ex_to_module.cc | 209 + .../google-breakpad/src/common/arm_ex_to_module.h | 119 + .../google-breakpad/src/common/basictypes.h | 58 + .../google-breakpad/src/common/byte_cursor.h | 265 + .../src/common/byte_cursor_unittest.cc | 776 + .../google-breakpad/src/common/common.gyp | 260 + .../google-breakpad/src/common/convert_UTF.cc | 591 + .../google-breakpad/src/common/convert_UTF.h | 159 + .../src/common/dwarf/bytereader-inl.h | 170 + .../google-breakpad/src/common/dwarf/bytereader.cc | 250 + .../google-breakpad/src/common/dwarf/bytereader.h | 315 + .../src/common/dwarf/bytereader_unittest.cc | 707 + .../src/common/dwarf/cfi_assembler.cc | 204 + .../src/common/dwarf/cfi_assembler.h | 271 + .../src/common/dwarf/dwarf2diehandler.cc | 199 + .../src/common/dwarf/dwarf2diehandler.h | 365 + .../src/common/dwarf/dwarf2diehandler_unittest.cc | 527 + .../google-breakpad/src/common/dwarf/dwarf2enums.h | 679 + .../src/common/dwarf/dwarf2reader.cc | 2815 +++ .../src/common/dwarf/dwarf2reader.h | 1331 ++ .../src/common/dwarf/dwarf2reader_cfi_unittest.cc | 2582 +++ .../src/common/dwarf/dwarf2reader_die_unittest.cc | 487 + .../src/common/dwarf/dwarf2reader_test_common.h | 149 + .../google-breakpad/src/common/dwarf/elf_reader.cc | 1274 ++ .../google-breakpad/src/common/dwarf/elf_reader.h | 166 + .../src/common/dwarf/functioninfo.cc | 234 + .../src/common/dwarf/functioninfo.h | 190 + .../src/common/dwarf/line_state_machine.h | 61 + .../google-breakpad/src/common/dwarf/types.h | 51 + .../src/common/dwarf_cfi_to_module.cc | 295 + .../src/common/dwarf_cfi_to_module.h | 202 + .../src/common/dwarf_cfi_to_module_unittest.cc | 306 + .../src/common/dwarf_cu_to_module.cc | 1243 ++ .../src/common/dwarf_cu_to_module.h | 345 + .../src/common/dwarf_cu_to_module_unittest.cc | 1854 ++ .../src/common/dwarf_line_to_module.cc | 143 + .../src/common/dwarf_line_to_module.h | 188 + .../src/common/dwarf_line_to_module_unittest.cc | 391 + .../src/common/dwarf_range_list_handler.cc | 60 + .../src/common/dwarf_range_list_handler.h | 79 + .../google-breakpad/src/common/language.cc | 197 + .../google-breakpad/src/common/language.h | 105 + .../src/common/linux/breakpad_getcontext.S | 486 + .../src/common/linux/breakpad_getcontext.h | 56 + .../common/linux/breakpad_getcontext_unittest.cc | 194 + .../google-breakpad/src/common/linux/crc32.cc | 70 + .../google-breakpad/src/common/linux/crc32.h | 53 + .../src/common/linux/dump_symbols.cc | 1218 + .../src/common/linux/dump_symbols.h | 93 + .../src/common/linux/dump_symbols_unittest.cc | 208 + .../src/common/linux/eintr_wrapper.h | 58 + .../src/common/linux/elf_core_dump.cc | 179 + .../src/common/linux/elf_core_dump.h | 149 + .../src/common/linux/elf_core_dump_unittest.cc | 265 + .../src/common/linux/elf_gnu_compat.h | 51 + .../src/common/linux/elf_symbols_to_module.cc | 178 + .../src/common/linux/elf_symbols_to_module.h | 58 + .../common/linux/elf_symbols_to_module_unittest.cc | 370 + .../src/common/linux/elfutils-inl.h | 74 + .../google-breakpad/src/common/linux/elfutils.cc | 241 + .../google-breakpad/src/common/linux/elfutils.h | 135 + .../google-breakpad/src/common/linux/file_id.cc | 200 + .../google-breakpad/src/common/linux/file_id.h | 88 + .../src/common/linux/file_id_unittest.cc | 372 + .../src/common/linux/google_crashdump_uploader.cc | 207 + .../src/common/linux/google_crashdump_uploader.h | 107 + .../common/linux/google_crashdump_uploader_test.cc | 170 + .../src/common/linux/guid_creator.cc | 189 + .../src/common/linux/guid_creator.h | 48 + .../src/common/linux/http_upload.cc | 210 + .../google-breakpad/src/common/linux/http_upload.h | 84 + .../google-breakpad/src/common/linux/ignore_ret.h | 40 + .../src/common/linux/libcurl_wrapper.cc | 338 + .../src/common/linux/libcurl_wrapper.h | 119 + .../src/common/linux/linux_libc_support.cc | 248 + .../src/common/linux/linux_libc_support.h | 98 + .../common/linux/linux_libc_support_unittest.cc | 213 + .../src/common/linux/memory_mapped_file.cc | 107 + .../src/common/linux/memory_mapped_file.h | 87 + .../common/linux/memory_mapped_file_unittest.cc | 208 + .../google-breakpad/src/common/linux/moz.build | 42 + .../src/common/linux/safe_readlink.cc | 53 + .../src/common/linux/safe_readlink.h | 65 + .../src/common/linux/safe_readlink_unittest.cc | 89 + .../src/common/linux/symbol_collector_client.cc | 195 + .../src/common/linux/symbol_collector_client.h | 88 + .../src/common/linux/symbol_upload.cc | 284 + .../src/common/linux/symbol_upload.h | 76 + .../google-breakpad/src/common/linux/synth_elf.cc | 263 + .../google-breakpad/src/common/linux/synth_elf.h | 197 + .../src/common/linux/synth_elf_unittest.cc | 413 + .../src/common/linux/tests/auto_testfile.h | 124 + .../src/common/linux/tests/crash_generator.cc | 329 + .../src/common/linux/tests/crash_generator.h | 117 + .../src/common/linux/ucontext_constants.h | 153 + .../src/common/long_string_dictionary.cc | 178 + .../src/common/long_string_dictionary.h | 87 + .../src/common/long_string_dictionary_unittest.cc | 301 + .../src/common/mac/Breakpad.xcconfig | 52 + .../src/common/mac/BreakpadDebug.xcconfig | 32 + .../src/common/mac/BreakpadRelease.xcconfig | 34 + .../google-breakpad/src/common/mac/GTMDefines.h | 396 + .../google-breakpad/src/common/mac/GTMLogger.h | 504 + .../google-breakpad/src/common/mac/GTMLogger.m | 611 + .../src/common/mac/HTTPMultipartUpload.h | 61 + .../src/common/mac/HTTPMultipartUpload.m | 262 + .../google-breakpad/src/common/mac/MachIPC.h | 303 + .../google-breakpad/src/common/mac/MachIPC.mm | 306 + .../src/common/mac/arch_utilities.cc | 264 + .../src/common/mac/arch_utilities.h | 47 + .../src/common/mac/bootstrap_compat.cc | 42 + .../src/common/mac/bootstrap_compat.h | 54 + .../google-breakpad/src/common/mac/byteswap.h | 73 + .../google-breakpad/src/common/mac/dump_syms.cc | 679 + .../google-breakpad/src/common/mac/dump_syms.h | 196 + .../google-breakpad/src/common/mac/file_id.cc | 106 + .../google-breakpad/src/common/mac/file_id.h | 81 + .../src/common/mac/launch_reporter.cc | 84 + .../src/common/mac/launch_reporter.h | 43 + .../google-breakpad/src/common/mac/macho_id.cc | 369 + .../google-breakpad/src/common/mac/macho_id.h | 131 + .../google-breakpad/src/common/mac/macho_reader.cc | 558 + .../google-breakpad/src/common/mac/macho_reader.h | 464 + .../src/common/mac/macho_reader_unittest.cc | 1902 ++ .../src/common/mac/macho_utilities.cc | 155 + .../src/common/mac/macho_utilities.h | 95 + .../google-breakpad/src/common/mac/macho_walker.cc | 272 + .../google-breakpad/src/common/mac/macho_walker.h | 119 + .../google-breakpad/src/common/mac/moz.build | 27 + .../src/common/mac/scoped_task_suspend-inl.h | 56 + .../src/common/mac/string_utilities.cc | 84 + .../src/common/mac/string_utilities.h | 52 + .../src/common/mac/super_fat_arch.h | 88 + .../src/common/mac/testing/GTMSenTestCase.h | 1110 + .../src/common/mac/testing/GTMSenTestCase.m | 428 + .../google-breakpad/src/common/macros.h | 45 + .../google-breakpad/src/common/md5.cc | 251 + .../crashreporter/google-breakpad/src/common/md5.h | 27 + .../google-breakpad/src/common/memory_allocator.h | 252 + .../src/common/memory_allocator_unittest.cc | 124 + .../google-breakpad/src/common/memory_range.h | 145 + .../src/common/memory_range_unittest.cc | 193 + .../src/common/minidump_type_helper.h | 56 + .../google-breakpad/src/common/module.cc | 387 + .../google-breakpad/src/common/module.h | 376 + .../google-breakpad/src/common/module_unittest.cc | 674 + .../google-breakpad/src/common/moz.build | 19 + .../google-breakpad/src/common/path_helper.cc | 55 + .../google-breakpad/src/common/path_helper.h | 44 + .../google-breakpad/src/common/scoped_ptr.h | 404 + .../src/common/simple_string_dictionary.cc | 45 + .../src/common/simple_string_dictionary.h | 279 + .../common/simple_string_dictionary_unittest.cc | 339 + .../src/common/solaris/dump_symbols.cc | 681 + .../src/common/solaris/dump_symbols.h | 49 + .../google-breakpad/src/common/solaris/file_id.cc | 197 + .../google-breakpad/src/common/solaris/file_id.h | 66 + .../src/common/solaris/guid_creator.cc | 84 + .../src/common/solaris/guid_creator.h | 50 + .../src/common/solaris/message_output.h | 54 + .../google-breakpad/src/common/stabs_reader.cc | 315 + .../google-breakpad/src/common/stabs_reader.h | 325 + .../src/common/stabs_reader_unittest.cc | 611 + .../google-breakpad/src/common/stabs_to_module.cc | 199 + .../google-breakpad/src/common/stabs_to_module.h | 143 + .../src/common/stabs_to_module_unittest.cc | 258 + .../google-breakpad/src/common/stdio_wrapper.h | 43 + .../src/common/string_conversion.cc | 155 + .../google-breakpad/src/common/string_conversion.h | 68 + .../src/common/string_conversion_unittest.cc | 64 + .../google-breakpad/src/common/symbol_data.h | 42 + .../google-breakpad/src/common/test_assembler.cc | 359 + .../google-breakpad/src/common/test_assembler.h | 484 + .../src/common/test_assembler_unittest.cc | 1662 ++ .../src/common/testdata/func-line-pairing.h | 676 + .../src/common/tests/auto_tempdir.h | 100 + .../google-breakpad/src/common/tests/file_utils.cc | 153 + .../google-breakpad/src/common/tests/file_utils.h | 52 + .../google-breakpad/src/common/unordered.h | 62 + .../google-breakpad/src/common/using_std_string.h | 65 + .../src/common/windows/common_windows.gyp | 112 + .../google-breakpad/src/common/windows/dia_util.cc | 92 + .../google-breakpad/src/common/windows/dia_util.h | 64 + .../src/common/windows/guid_string.cc | 76 + .../src/common/windows/guid_string.h | 58 + .../src/common/windows/http_upload.cc | 493 + .../src/common/windows/http_upload.h | 125 + .../src/common/windows/module_info.h | 75 + .../src/common/windows/objs.mozbuild | 15 + .../google-breakpad/src/common/windows/omap.cc | 716 + .../google-breakpad/src/common/windows/omap.h | 72 + .../src/common/windows/omap_internal.h | 140 + .../src/common/windows/omap_unittest.cc | 329 + .../src/common/windows/pdb_source_line_writer.cc | 1194 + .../src/common/windows/pdb_source_line_writer.h | 226 + .../src/common/windows/pe_source_line_writer.cc | 77 + .../src/common/windows/pe_source_line_writer.h | 69 + .../google-breakpad/src/common/windows/pe_util.cc | 407 + .../google-breakpad/src/common/windows/pe_util.h | 78 + .../src/common/windows/string_utils-inl.h | 142 + .../src/common/windows/string_utils.cc | 133 + .../src/common/windows/symbol_collector_client.cc | 155 + .../src/common/windows/symbol_collector_client.h | 89 + .../crashreporter/google-breakpad/src/config.h.in | 94 + .../src/google_breakpad/common/breakpad_types.h | 68 + .../google_breakpad/common/minidump_cpu_amd64.h | 235 + .../src/google_breakpad/common/minidump_cpu_arm.h | 151 + .../google_breakpad/common/minidump_cpu_arm64.h | 192 + .../src/google_breakpad/common/minidump_cpu_mips.h | 176 + .../src/google_breakpad/common/minidump_cpu_ppc.h | 159 + .../google_breakpad/common/minidump_cpu_ppc64.h | 134 + .../google_breakpad/common/minidump_cpu_sparc.h | 163 + .../src/google_breakpad/common/minidump_cpu_x86.h | 174 + .../common/minidump_exception_fuchsia.h | 58 + .../common/minidump_exception_linux.h | 129 + .../common/minidump_exception_mac.h | 314 + .../common/minidump_exception_ps3.h | 67 + .../common/minidump_exception_solaris.h | 94 + .../common/minidump_exception_win32.h | 5575 +++++ .../src/google_breakpad/common/minidump_format.h | 1178 + .../src/google_breakpad/common/minidump_size.h | 113 + .../processor/basic_source_line_resolver.h | 148 + .../src/google_breakpad/processor/call_stack.h | 97 + .../src/google_breakpad/processor/code_module.h | 104 + .../src/google_breakpad/processor/code_modules.h | 108 + .../src/google_breakpad/processor/dump_context.h | 116 + .../src/google_breakpad/processor/dump_object.h | 53 + .../google_breakpad/processor/exception_record.h | 124 + .../src/google_breakpad/processor/exploitability.h | 82 + .../processor/fast_source_line_resolver.h | 100 + .../src/google_breakpad/processor/memory_region.h | 79 + .../src/google_breakpad/processor/microdump.h | 135 + .../processor/microdump_processor.h | 64 + .../src/google_breakpad/processor/minidump.h | 1498 ++ .../google_breakpad/processor/minidump_processor.h | 147 + .../google_breakpad/processor/proc_maps_linux.h | 60 + .../src/google_breakpad/processor/process_result.h | 66 + .../src/google_breakpad/processor/process_state.h | 220 + .../processor/source_line_resolver_base.h | 128 + .../processor/source_line_resolver_interface.h | 117 + .../src/google_breakpad/processor/stack_frame.h | 144 + .../google_breakpad/processor/stack_frame_cpu.h | 405 + .../processor/stack_frame_symbolizer.h | 110 + .../src/google_breakpad/processor/stackwalker.h | 257 + .../google_breakpad/processor/symbol_supplier.h | 99 + .../src/google_breakpad/processor/system_info.h | 106 + .../src/processor/address_map-inl.h | 93 + .../google-breakpad/src/processor/address_map.h | 85 + .../src/processor/address_map_unittest.cc | 196 + .../src/processor/basic_code_module.h | 121 + .../src/processor/basic_code_modules.cc | 152 + .../src/processor/basic_code_modules.h | 97 + .../src/processor/basic_source_line_resolver.cc | 657 + .../processor/basic_source_line_resolver_types.h | 179 + .../basic_source_line_resolver_unittest.cc | 744 + .../google-breakpad/src/processor/call_stack.cc | 56 + .../src/processor/cfi_frame_info-inl.h | 119 + .../src/processor/cfi_frame_info.cc | 186 + .../google-breakpad/src/processor/cfi_frame_info.h | 275 + .../src/processor/cfi_frame_info_unittest.cc | 546 + .../src/processor/contained_range_map-inl.h | 197 + .../src/processor/contained_range_map.h | 150 + .../src/processor/contained_range_map_unittest.cc | 263 + .../src/processor/convert_old_arm64_context.cc | 67 + .../src/processor/convert_old_arm64_context.h | 42 + .../src/processor/disassembler_x86.cc | 240 + .../src/processor/disassembler_x86.h | 127 + .../src/processor/disassembler_x86_unittest.cc | 233 + .../google-breakpad/src/processor/dump_context.cc | 664 + .../google-breakpad/src/processor/dump_object.cc | 39 + .../src/processor/exploitability.cc | 120 + .../src/processor/exploitability_linux.cc | 626 + .../src/processor/exploitability_linux.h | 129 + .../src/processor/exploitability_unittest.cc | 306 + .../src/processor/exploitability_win.cc | 283 + .../src/processor/exploitability_win.h | 55 + .../src/processor/fast_source_line_resolver.cc | 275 + .../processor/fast_source_line_resolver_types.h | 185 + .../fast_source_line_resolver_unittest.cc | 492 + .../google-breakpad/src/processor/linked_ptr.h | 193 + .../google-breakpad/src/processor/logging.cc | 114 + .../google-breakpad/src/processor/logging.h | 188 + .../src/processor/map_serializers-inl.h | 266 + .../src/processor/map_serializers.h | 168 + .../src/processor/map_serializers_unittest.cc | 386 + .../google-breakpad/src/processor/microdump.cc | 405 + .../src/processor/microdump_processor.cc | 97 + .../src/processor/microdump_processor_unittest.cc | 285 + .../src/processor/microdump_stackwalk.cc | 181 + .../microdump_stackwalk_machine_readable_test | 43 + .../src/processor/microdump_stackwalk_test | 43 + .../src/processor/microdump_stackwalk_test_vars | 1 + .../google-breakpad/src/processor/minidump.cc | 6445 ++++++ .../google-breakpad/src/processor/minidump_dump.cc | 291 + .../src/processor/minidump_dump_test | 36 + .../src/processor/minidump_processor.cc | 2146 ++ .../src/processor/minidump_processor_unittest.cc | 769 + .../src/processor/minidump_stackwalk.cc | 179 + .../minidump_stackwalk_machine_readable_test | 37 + .../src/processor/minidump_stackwalk_test | 37 + .../src/processor/minidump_unittest.cc | 1628 ++ .../src/processor/module_comparer.cc | 302 + .../src/processor/module_comparer.h | 98 + .../google-breakpad/src/processor/module_factory.h | 72 + .../src/processor/module_serializer.cc | 207 + .../src/processor/module_serializer.h | 127 + .../google-breakpad/src/processor/moz.build | 76 + .../src/processor/pathname_stripper.cc | 56 + .../src/processor/pathname_stripper.h | 53 + .../src/processor/pathname_stripper_unittest.cc | 87 + .../src/processor/postfix_evaluator-inl.h | 363 + .../src/processor/postfix_evaluator.h | 179 + .../src/processor/postfix_evaluator_unittest.cc | 403 + .../src/processor/proc_maps_linux.cc | 106 + .../src/processor/proc_maps_linux_unittest.cc | 251 + .../google-breakpad/src/processor/process_state.cc | 71 + .../google-breakpad/src/processor/processor.gyp | 187 + .../src/processor/processor_tools.gypi | 57 + .../google-breakpad/src/processor/proto/README | 20 + .../src/processor/proto/process_state.proto | 210 + .../google-breakpad/src/processor/range_map-inl.h | 291 + .../google-breakpad/src/processor/range_map.h | 171 + .../processor/range_map_truncate_lower_unittest.cc | 346 + .../processor/range_map_truncate_upper_unittest.cc | 354 + .../src/processor/range_map_unittest.cc | 559 + .../src/processor/simple_serializer-inl.h | 260 + .../src/processor/simple_serializer.h | 63 + .../src/processor/simple_symbol_supplier.cc | 204 + .../src/processor/simple_symbol_supplier.h | 140 + .../src/processor/source_line_resolver_base.cc | 341 + .../processor/source_line_resolver_base_types.h | 167 + .../src/processor/stack_frame_cpu.cc | 79 + .../src/processor/stack_frame_symbolizer.cc | 144 + .../src/processor/stackwalk_common.cc | 1036 + .../src/processor/stackwalk_common.h | 49 + .../google-breakpad/src/processor/stackwalker.cc | 333 + .../src/processor/stackwalker_address_list.cc | 92 + .../src/processor/stackwalker_address_list.h | 72 + .../processor/stackwalker_address_list_unittest.cc | 197 + .../src/processor/stackwalker_amd64.cc | 326 + .../src/processor/stackwalker_amd64.h | 108 + .../src/processor/stackwalker_amd64_unittest.cc | 934 + .../src/processor/stackwalker_arm.cc | 297 + .../src/processor/stackwalker_arm.h | 107 + .../src/processor/stackwalker_arm64.cc | 351 + .../src/processor/stackwalker_arm64.h | 121 + .../src/processor/stackwalker_arm64_unittest.cc | 881 + .../src/processor/stackwalker_arm_unittest.cc | 979 + .../src/processor/stackwalker_mips.cc | 442 + .../src/processor/stackwalker_mips.h | 85 + .../src/processor/stackwalker_mips64_unittest.cc | 716 + .../src/processor/stackwalker_mips_unittest.cc | 704 + .../src/processor/stackwalker_ppc.cc | 155 + .../src/processor/stackwalker_ppc.h | 79 + .../src/processor/stackwalker_ppc64.cc | 146 + .../src/processor/stackwalker_ppc64.h | 77 + .../src/processor/stackwalker_selftest.cc | 433 + .../src/processor/stackwalker_selftest_sol.s | 111 + .../src/processor/stackwalker_sparc.cc | 147 + .../src/processor/stackwalker_sparc.h | 78 + .../src/processor/stackwalker_unittest_utils.h | 220 + .../src/processor/stackwalker_x86.cc | 680 + .../src/processor/stackwalker_x86.h | 117 + .../src/processor/stackwalker_x86_unittest.cc | 2266 ++ .../src/processor/static_address_map-inl.h | 71 + .../src/processor/static_address_map.h | 78 + .../src/processor/static_address_map_unittest.cc | 236 + .../src/processor/static_contained_range_map-inl.h | 92 + .../src/processor/static_contained_range_map.h | 96 + .../static_contained_range_map_unittest.cc | 320 + .../google-breakpad/src/processor/static_map-inl.h | 176 + .../google-breakpad/src/processor/static_map.h | 144 + .../src/processor/static_map_iterator-inl.h | 147 + .../src/processor/static_map_iterator.h | 112 + .../src/processor/static_map_unittest.cc | 386 + .../src/processor/static_range_map-inl.h | 130 + .../src/processor/static_range_map.h | 106 + .../src/processor/static_range_map_unittest.cc | 421 + .../src/processor/symbolic_constants_win.cc | 10958 +++++++++ .../src/processor/symbolic_constants_win.h | 61 + .../src/processor/synth_minidump.cc | 421 + .../google-breakpad/src/processor/synth_minidump.h | 398 + .../src/processor/synth_minidump_unittest.cc | 336 + .../src/processor/synth_minidump_unittest_data.h | 418 + .../google-breakpad/src/processor/tokenize.cc | 79 + .../google-breakpad/src/processor/tokenize.h | 63 + .../src/processor/windows_frame_info.h | 209 + .../google-breakpad/src/third_party/curl/COPYING | 22 + .../google-breakpad/src/third_party/curl/curl.h | 2864 +++ .../google-breakpad/src/third_party/curl/curlver.h | 77 + .../google-breakpad/src/third_party/curl/easy.h | 112 + .../google-breakpad/src/third_party/curl/multi.h | 441 + .../google-breakpad/src/third_party/curl/system.h | 493 + .../src/third_party/curl/typecheck-gcc.h | 700 + .../google-breakpad/src/third_party/curl/urlapi.h | 122 + .../src/third_party/glog/Makefile.in | 1553 ++ .../src/third_party/libdisasm/LICENSE | 137 + .../src/third_party/libdisasm/Makefile.am | 43 + .../src/third_party/libdisasm/README.breakpad | 9 + .../google-breakpad/src/third_party/libdisasm/TODO | 43 + .../src/third_party/libdisasm/ia32_implicit.c | 422 + .../src/third_party/libdisasm/ia32_implicit.h | 13 + .../src/third_party/libdisasm/ia32_insn.c | 623 + .../src/third_party/libdisasm/ia32_insn.h | 506 + .../src/third_party/libdisasm/ia32_invariant.c | 313 + .../src/third_party/libdisasm/ia32_invariant.h | 11 + .../src/third_party/libdisasm/ia32_modrm.c | 310 + .../src/third_party/libdisasm/ia32_modrm.h | 13 + .../src/third_party/libdisasm/ia32_opcode_tables.c | 2939 +++ .../src/third_party/libdisasm/ia32_opcode_tables.h | 57 + .../src/third_party/libdisasm/ia32_operand.c | 425 + .../src/third_party/libdisasm/ia32_operand.h | 11 + .../src/third_party/libdisasm/ia32_reg.c | 234 + .../src/third_party/libdisasm/ia32_reg.h | 41 + .../src/third_party/libdisasm/ia32_settings.c | 13 + .../src/third_party/libdisasm/ia32_settings.h | 27 + .../src/third_party/libdisasm/libdis.h | 832 + .../src/third_party/libdisasm/libdisasm.gyp | 67 + .../src/third_party/libdisasm/qword.h | 14 + .../src/third_party/libdisasm/swig/Makefile | 70 + .../src/third_party/libdisasm/swig/README | 128 + .../src/third_party/libdisasm/swig/libdisasm.i | 508 + .../src/third_party/libdisasm/swig/libdisasm_oop.i | 1114 + .../third_party/libdisasm/swig/perl/Makefile-swig | 65 + .../third_party/libdisasm/swig/perl/Makefile.PL | 7 + .../libdisasm/swig/python/Makefile-swig | 64 + .../third_party/libdisasm/swig/ruby/Makefile-swig | 68 + .../src/third_party/libdisasm/swig/ruby/extconf.rb | 4 + .../third_party/libdisasm/swig/tcl/Makefile-swig | 63 + .../src/third_party/libdisasm/x86_disasm.c | 210 + .../src/third_party/libdisasm/x86_format.c | 1430 ++ .../src/third_party/libdisasm/x86_imm.c | 70 + .../src/third_party/libdisasm/x86_imm.h | 18 + .../src/third_party/libdisasm/x86_insn.c | 182 + .../src/third_party/libdisasm/x86_misc.c | 71 + .../src/third_party/libdisasm/x86_operand_list.c | 191 + .../src/third_party/libdisasm/x86_operand_list.h | 8 + .../google-breakpad/src/third_party/lss/.gitignore | 3 + .../google-breakpad/src/third_party/lss/README.md | 137 + .../src/third_party/lss/codereview.settings | 5 + .../src/third_party/lss/linux_syscall_support.h | 4553 ++++ .../src/third_party/lss/tests/.gitignore | 4 + .../src/third_party/lss/tests/Makefile | 131 + .../src/third_party/lss/tests/README.md | 52 + .../src/third_party/lss/tests/fallocate.c | 67 + .../src/third_party/lss/tests/sigtimedwait.c | 58 + .../src/third_party/lss/tests/test_skel.h | 70 + .../src/third_party/lss/tests/unlink.c | 48 + .../src/third_party/mac_headers/README | 2 + .../mac_headers/architecture/byte_order.h | 45 + .../src/third_party/mac_headers/i386/_types.h | 34 + .../src/third_party/mac_headers/mach-o/arch.h | 105 + .../src/third_party/mac_headers/mach-o/fat.h | 64 + .../src/third_party/mac_headers/mach-o/loader.h | 1402 ++ .../src/third_party/mac_headers/mach-o/nlist.h | 312 + .../src/third_party/mac_headers/mach/boolean.h | 88 + .../third_party/mac_headers/mach/i386/boolean.h | 74 + .../third_party/mac_headers/mach/i386/vm_param.h | 157 + .../third_party/mac_headers/mach/i386/vm_types.h | 140 + .../src/third_party/mac_headers/mach/machine.h | 347 + .../third_party/mac_headers/mach/machine/boolean.h | 40 + .../mac_headers/mach/machine/thread_state.h | 9 + .../mac_headers/mach/machine/thread_status.h | 1 + .../mac_headers/mach/machine/vm_types.h | 40 + .../third_party/mac_headers/mach/thread_status.h | 94 + .../src/third_party/mac_headers/mach/vm_prot.h | 140 + .../google-breakpad/src/third_party/musl/COPYRIGHT | 163 + .../google-breakpad/src/third_party/musl/README | 23 + .../src/third_party/musl/README.breakpad | 3 + .../google-breakpad/src/third_party/musl/VERSION | 1 + .../src/third_party/musl/include/elf.h | 3234 +++ .../src/tools/linux/core2md/core2md.cc | 72 + .../src/tools/linux/dump_syms/dump_syms.cc | 137 + .../src/tools/linux/md2core/minidump-2-core.cc | 1428 ++ .../tools/linux/md2core/minidump_memory_range.h | 89 + .../md2core/minidump_memory_range_unittest.cc | 258 + .../src/tools/linux/symupload/minidump_upload.cc | 153 + .../src/tools/linux/symupload/sym_upload.cc | 210 + .../src/tools/linux/tools_linux.gypi | 83 + .../src/tools/mac/crash_report/crash_report.mm | 408 + .../crash_report.xcodeproj/project.pbxproj | 618 + .../mac/crash_report/on_demand_symbol_supplier.h | 111 + .../mac/crash_report/on_demand_symbol_supplier.mm | 314 + .../dump_syms/dump_syms.xcodeproj/project.pbxproj | 1857 ++ .../src/tools/mac/dump_syms/dump_syms_tool.cc | 264 + .../src/tools/mac/dump_syms/macho_dump.cc | 203 + .../src/tools/mac/symupload/minidump_upload.m | 135 + .../src/tools/mac/symupload/symupload.m | 204 + .../symupload/symupload.xcodeproj/project.pbxproj | 254 + .../google-breakpad/src/tools/mac/tools_mac.gypi | 116 + .../mac/upload_system_symbols/arch_constants.h | 67 + .../tools/mac/upload_system_symbols/arch_reader.go | 69 + .../upload_system_symbols/upload_system_symbols.go | 432 + .../src/tools/python/deps-to-manifest.py | 167 + .../src/tools/python/filter_syms.py | 204 + .../src/tools/python/tests/filter_syms_unittest.py | 138 + .../src/tools/solaris/dump_syms/Makefile | 64 + .../src/tools/solaris/dump_syms/Makefile.in | 5 + .../src/tools/solaris/dump_syms/dump_syms.cc | 54 + .../src/tools/solaris/dump_syms/run_regtest.sh | 51 + .../dump_syms/testdata/dump_syms_regtest.cc | 64 + .../solaris/dump_syms/testdata/dump_syms_regtest.o | Bin 0 -> 14204 bytes .../dump_syms/testdata/dump_syms_regtest.stabs | 129 + .../dump_syms/testdata/dump_syms_regtest.sym | 33 + .../google-breakpad/src/tools/tools.gyp | 38 + .../src/tools/windows/binaries/dump_syms.exe | Bin 0 -> 141824 bytes .../src/tools/windows/binaries/symupload.exe | Bin 0 -> 243712 bytes .../converter/ms_symbol_server_converter.cc | 752 + .../converter/ms_symbol_server_converter.gyp | 46 + .../windows/converter/ms_symbol_server_converter.h | 235 + .../converter/ms_symbol_server_converter.vcproj | 368 + .../src/tools/windows/converter_exe/configure.cmd | 33 + .../src/tools/windows/converter_exe/converter.cc | 807 + .../src/tools/windows/converter_exe/converter.gyp | 57 + .../src/tools/windows/converter_exe/escaping.cc | 757 + .../src/tools/windows/converter_exe/escaping.h | 99 + .../src/tools/windows/converter_exe/http_client.h | 96 + .../tools/windows/converter_exe/http_download.cc | 326 + .../tools/windows/converter_exe/http_download.h | 62 + .../windows/converter_exe/missing_symbols_test.txt | 5 + .../src/tools/windows/converter_exe/symsrv.yes | 2 + .../src/tools/windows/converter_exe/tokenizer.cc | 61 + .../src/tools/windows/converter_exe/tokenizer.h | 51 + .../tools/windows/converter_exe/winhttp_client.cc | 307 + .../tools/windows/converter_exe/winhttp_client.h | 40 + .../tools/windows/converter_exe/wininet_client.cc | 278 + .../tools/windows/converter_exe/wininet_client.h | 40 + .../src/tools/windows/converter_exe/winsymconv.cmd | 86 + .../windows/converter_exe/winsymconv_test.cmd | 72 + .../src/tools/windows/dump_syms/dump_syms.cc | 73 + .../src/tools/windows/dump_syms/dump_syms.gyp | 64 + .../src/tools/windows/dump_syms/dump_syms.vcproj | 242 + .../tools/windows/dump_syms/dump_syms_unittest.cc | 244 + .../src/tools/windows/dump_syms/run_regtest.sh | 53 + .../src/tools/windows/refresh_binaries.bat | 23 + .../src/tools/windows/symupload/symupload.cc | 394 + .../src/tools/windows/symupload/symupload.gyp | 50 + .../src/tools/windows/tools_windows.gyp | 46 + toolkit/crashreporter/injector/injector.cpp | 35 + toolkit/crashreporter/injector/moz.build | 27 + toolkit/crashreporter/jar.mn | 10 + toolkit/crashreporter/mac_utils.h | 14 + toolkit/crashreporter/mac_utils.mm | 29 + .../minidump-analyzer/MinidumpAnalyzerUtils.h | 115 + .../minidump-analyzer/MozStackFrameSymbolizer.cpp | 116 + .../minidump-analyzer/MozStackFrameSymbolizer.h | 48 + .../Win64ModuleUnwindMetadata.cpp | 226 + .../minidump-analyzer/Win64ModuleUnwindMetadata.h | 56 + .../minidump-analyzer/minidump-analyzer.cpp | 603 + .../minidump-analyzer.exe.manifest | 19 + toolkit/crashreporter/minidump-analyzer/moz.build | 43 + toolkit/crashreporter/moz.build | 141 + .../crashreporter/mozannotation_client/Cargo.toml | 11 + .../mozannotation_client/cbindgen.toml | 15 + .../crashreporter/mozannotation_client/moz.build | 17 + .../crashreporter/mozannotation_client/src/lib.rs | 354 + .../crashreporter/mozannotation_server/Cargo.toml | 25 + .../mozannotation_server/cbindgen.toml | 15 + .../crashreporter/mozannotation_server/moz.build | 17 + .../mozannotation_server/src/errors.rs | 81 + .../crashreporter/mozannotation_server/src/lib.rs | 217 + .../mozannotation_server/src/process_reader.rs | 18 + .../src/process_reader/linux.rs | 312 + .../src/process_reader/macos.rs | 214 + .../src/process_reader/windows.rs | 193 + toolkit/crashreporter/mozwer-rust/Cargo.toml | 37 + toolkit/crashreporter/mozwer-rust/lib.rs | 868 + toolkit/crashreporter/mozwer-rust/moz.build | 13 + toolkit/crashreporter/mozwer/moz.build | 17 + toolkit/crashreporter/mozwer/mozwer.cpp | 20 + toolkit/crashreporter/mozwer/mozwer.def | 5 + toolkit/crashreporter/nsDummyExceptionHandler.cpp | 242 + toolkit/crashreporter/nsExceptionHandler.cpp | 3926 ++++ toolkit/crashreporter/nsExceptionHandler.h | 323 + toolkit/crashreporter/nsExceptionHandlerUtils.cpp | 51 + toolkit/crashreporter/nsExceptionHandlerUtils.h | 12 + toolkit/crashreporter/process_reader/Cargo.toml | 23 + toolkit/crashreporter/process_reader/src/error.rs | 30 + toolkit/crashreporter/process_reader/src/lib.rs | 13 + .../process_reader/src/process_reader.rs | 6 + .../process_reader/src/process_reader/windows.rs | 218 + .../rust_minidump_writer_linux/Cargo.toml | 15 + .../rust_minidump_writer_linux/cbindgen.toml | 15 + .../rust_minidump_writer_linux/moz.build | 17 + .../rust_minidump_writer_linux/src/lib.rs | 137 + toolkit/crashreporter/test/CrashTestUtils.sys.mjs | 106 + toolkit/crashreporter/test/ExceptionThrower.cpp | 3 + toolkit/crashreporter/test/ExceptionThrower.h | 1 + toolkit/crashreporter/test/browser/browser.toml | 21 + .../test/browser/browser_aboutCrashes.js | 82 + .../test/browser/browser_aboutCrashesResubmit.js | 202 + .../test/browser/browser_bug471404.js | 61 + .../test/browser/browser_clearReports.js | 134 + .../test/browser/browser_cpu_microcode.js | 25 + .../test/browser/browser_sandbox_crash.js | 77 + toolkit/crashreporter/test/browser/crashreport.sjs | 176 + toolkit/crashreporter/test/browser/head.js | 163 + toolkit/crashreporter/test/dumputils.cpp | 83 + toolkit/crashreporter/test/moz.build | 67 + toolkit/crashreporter/test/nsTestCrasher.cpp | 370 + .../test/unit/crasher_subprocess_head.js | 32 + .../test/unit/crasher_subprocess_tail.js | 20 + .../crashreporter/test/unit/head_crashreporter.js | 347 + toolkit/crashreporter/test/unit/head_win64cfi.js | 215 + .../test/unit/test_crash_AsyncShutdown.js | 68 + .../crashreporter/test/unit/test_crash_abort.js | 17 + ...test_crash_after_js_large_allocation_failure.js | 23 + ..._after_js_large_allocation_failure_reporting.js | 27 + .../test/unit/test_crash_after_js_oom_recovered.js | 22 + .../test/unit/test_crash_after_js_oom_reported.js | 36 + .../unit/test_crash_after_js_oom_reported_2.js | 28 + .../unit/test_crash_backgroundtask_moz_crash.js | 25 + .../test/unit/test_crash_exc_guard.js | 30 + .../test/unit/test_crash_heap_corruption.js | 27 + .../crashreporter/test/unit/test_crash_modules.js | 44 + .../test/unit/test_crash_moz_crash.js | 17 + toolkit/crashreporter/test/unit/test_crash_oom.js | 21 + toolkit/crashreporter/test/unit/test_crash_phc.js | 59 + .../test/unit/test_crash_purevirtual.js | 21 + .../test/unit/test_crash_rust_panic.js | 15 + .../test/unit/test_crash_rust_panic_multiline.js | 15 + .../test/unit/test_crash_stack_overflow.js | 21 + .../test/unit/test_crash_terminator.js | 39 + .../test/unit/test_crash_uncaught_exception.js | 17 + .../test/unit/test_crash_win64cfi_alloc_large.js | 6 + .../test/unit/test_crash_win64cfi_alloc_small.js | 6 + .../test/unit/test_crash_win64cfi_epilog.js | 6 + .../test_crash_win64cfi_infinite_code_chain.exe | Bin 0 -> 1440 bytes .../test_crash_win64cfi_infinite_code_chain.js | 22 + .../test_crash_win64cfi_infinite_entry_chain.exe | Bin 0 -> 1440 bytes .../test_crash_win64cfi_infinite_entry_chain.js | 22 + .../test_crash_win64cfi_invalid_exception_rva.exe | Bin 0 -> 1440 bytes .../test_crash_win64cfi_invalid_exception_rva.js | 21 + .../test/unit/test_crash_win64cfi_not_a_pe.exe | 1 + .../test/unit/test_crash_win64cfi_not_a_pe.js | 20 + .../test/unit/test_crash_win64cfi_push_nonvol.js | 6 + .../test/unit/test_crash_win64cfi_save_nonvol.js | 6 + .../unit/test_crash_win64cfi_save_nonvol_far.js | 6 + .../test/unit/test_crash_win64cfi_save_xmm128.js | 6 + .../unit/test_crash_win64cfi_save_xmm128_far.js | 6 + .../test/unit/test_crash_win64cfi_unknown_op.js | 12 + .../test/unit/test_crash_with_memory_report.js | 49 + .../crashreporter/test/unit/test_crashreporter.js | 90 + .../test/unit/test_crashreporter_appmem.js | 13 + .../test/unit/test_crashreporter_crash.js | 223 + .../crashreporter/test/unit/test_event_files.js | 56 + toolkit/crashreporter/test/unit/test_kill.js | 43 + .../crashreporter/test/unit/test_oom_annotation.js | 71 + .../test/unit/test_override_exception_handler.js | 11 + toolkit/crashreporter/test/unit/xpcshell-phc.toml | 12 + toolkit/crashreporter/test/unit/xpcshell.toml | 152 + .../test/unit_ipc/test_content_annotation.js | 33 + .../test_content_exception_time_annotation.js | 21 + .../test/unit_ipc/test_content_large_annotation.js | 25 + .../test/unit_ipc/test_content_memory_list.js | 33 + .../test/unit_ipc/test_content_oom_annotation.js | 33 + .../test/unit_ipc/test_content_phc.js | 31 + .../test/unit_ipc/test_content_phc2.js | 34 + .../test/unit_ipc/test_content_phc3.js | 35 + .../test/unit_ipc/test_content_rust_panic.js | 23 + .../unit_ipc/test_content_rust_panic_multiline.js | 23 + .../crashreporter/test/unit_ipc/xpcshell-phc.toml | 13 + toolkit/crashreporter/test/unit_ipc/xpcshell.toml | 24 + .../crashreporter/test/win64UnwindInfoTests.asm | 378 + toolkit/crashreporter/tools/python.toml | 3 + toolkit/crashreporter/tools/symbolstore.py | 1095 + toolkit/crashreporter/tools/unit-symbolstore.py | 617 + toolkit/crashreporter/tools/upload_symbols.py | 306 + toolkit/crashreporter/update-breakpad.sh | 72 + 911 files changed, 294006 insertions(+) create mode 100644 toolkit/crashreporter/CrashAnnotations.cpp create mode 100644 toolkit/crashreporter/CrashAnnotations.h.in create mode 100644 toolkit/crashreporter/CrashAnnotations.yaml create mode 100644 toolkit/crashreporter/CrashReports.sys.mjs create mode 100644 toolkit/crashreporter/CrashSubmit.sys.mjs create mode 100644 toolkit/crashreporter/InjectCrashReporter.cpp create mode 100644 toolkit/crashreporter/InjectCrashReporter.h create mode 100644 toolkit/crashreporter/LoadLibraryRemote.cpp create mode 100644 toolkit/crashreporter/LoadLibraryRemote.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/data/linux-gate-amd.sym create mode 100644 toolkit/crashreporter/breakpad-client/linux/data/linux-gate-intel.sym create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/mapping_info.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/raw_context_cpu.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/microdump_extra_info.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/log/log.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/log/log.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper_unittest_helper.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader.h create mode 100644 toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/linux/moz.build create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/crash_generation/moz.build create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/mach_vm_compat.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/minidump_test.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/moz.build create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.mm create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_dwarf_data create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym create mode 100644 toolkit/crashreporter/breakpad-client/mac/handler/ucontext_compat.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/BreakpadFramework_Test.mm create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/crash_generation_server_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/exception_handler_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test_helper.cc create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/spawn_child_process.h create mode 100644 toolkit/crashreporter/breakpad-client/mac/tests/testlogging.h create mode 100644 toolkit/crashreporter/breakpad-client/minidump_file_writer-inl.h create mode 100644 toolkit/crashreporter/breakpad-client/minidump_file_writer.cc create mode 100644 toolkit/crashreporter/breakpad-client/minidump_file_writer.h create mode 100644 toolkit/crashreporter/breakpad-client/minidump_file_writer_unittest.cc create mode 100644 toolkit/crashreporter/breakpad-client/moz.build create mode 100644 toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/ReadMe.txt create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild create mode 100644 toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild create mode 100644 toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/crash_generation_server_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_death_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_nesting_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.cc create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.h create mode 100644 toolkit/crashreporter/breakpad-client/windows/unittests/minidump_test.cc create mode 100644 toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch create mode 100644 toolkit/crashreporter/breakpad-patches/02-define-print-mach-result.patch create mode 100644 toolkit/crashreporter/breakpad-patches/03-strstr-libc-replacement.patch create mode 100644 toolkit/crashreporter/breakpad-patches/04-update-headers.patch create mode 100644 toolkit/crashreporter/breakpad-patches/09-json-upload.patch create mode 100644 toolkit/crashreporter/breakpad-patches/10-macho-cpu-subtype.patch create mode 100644 toolkit/crashreporter/breakpad-patches/12-macho-cpu-subtype-fix.patch create mode 100644 toolkit/crashreporter/breakpad-patches/13-improve-arm64-stack-walking.patch create mode 100644 toolkit/crashreporter/breakpad-patches/14-handle-non-fixed-size-amd64-and-x86-contexts.patch create mode 100644 toolkit/crashreporter/breakpad-patches/15-freebsd-profiler-support.patch create mode 100644 toolkit/crashreporter/breakpad-patches/16-get-last-error.patch create mode 100644 toolkit/crashreporter/breakpad-patches/17-unloaded-modules.patch create mode 100644 toolkit/crashreporter/breakpad-patches/18-fastfail-codes.patch create mode 100644 toolkit/crashreporter/breakpad-patches/19-updated-ntstatus.patch create mode 100644 toolkit/crashreporter/breakpad-patches/20-mac-crash-info.patch create mode 100644 toolkit/crashreporter/breakpad-patches/21-thread-names.patch create mode 100644 toolkit/crashreporter/breakpad-patches/22-winerror-codes.patch create mode 100644 toolkit/crashreporter/breakpad-patches/23-si-user-si-kernel-siginfo.patch create mode 100644 toolkit/crashreporter/breakpad-patches/24-macos-exc-resource.patch create mode 100644 toolkit/crashreporter/breakpad-patches/25-macos-exc-guard.patch create mode 100644 toolkit/crashreporter/breakpad-patches/26-print-thread-tid.patch create mode 100644 toolkit/crashreporter/breakpad-patches/27-fix-unified-builds-bug-1733547.patch create mode 100644 toolkit/crashreporter/breakpad-patches/28-no-garbage-in-code-ids.patch create mode 100644 toolkit/crashreporter/breakpad-patches/29-cpu-context-packing.patch create mode 100644 toolkit/crashreporter/breakpad-patches/30-sign-compare.patch create mode 100644 toolkit/crashreporter/breakpad-patches/README create mode 100644 toolkit/crashreporter/breakpad-windows-libxul/moz.build create mode 100644 toolkit/crashreporter/breakpad-windows-standalone/moz.build create mode 100644 toolkit/crashreporter/client/Makefile.in create mode 100644 toolkit/crashreporter/client/Throbber-small.avi create mode 100644 toolkit/crashreporter/client/Throbber-small.gif create mode 100644 toolkit/crashreporter/client/crashreporter.cpp create mode 100644 toolkit/crashreporter/client/crashreporter.exe.manifest create mode 100644 toolkit/crashreporter/client/crashreporter.h create mode 100644 toolkit/crashreporter/client/crashreporter.ico create mode 100755 toolkit/crashreporter/client/crashreporter.rc create mode 100644 toolkit/crashreporter/client/crashreporter_gtk_common.cpp create mode 100644 toolkit/crashreporter/client/crashreporter_gtk_common.h create mode 100644 toolkit/crashreporter/client/crashreporter_linux.cpp create mode 100644 toolkit/crashreporter/client/crashreporter_osx.h create mode 100644 toolkit/crashreporter/client/crashreporter_osx.mm create mode 100644 toolkit/crashreporter/client/crashreporter_unix_common.cpp create mode 100644 toolkit/crashreporter/client/crashreporter_win.cpp create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Info.plist create mode 100644 toolkit/crashreporter/client/macbuild/Contents/PkgInfo create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib create mode 100644 toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns create mode 100644 toolkit/crashreporter/client/moz.build create mode 100644 toolkit/crashreporter/client/ping.cpp create mode 100644 toolkit/crashreporter/client/resource.h create mode 100644 toolkit/crashreporter/content/crashes.css create mode 100644 toolkit/crashreporter/content/crashes.html create mode 100644 toolkit/crashreporter/content/crashes.js create mode 100644 toolkit/crashreporter/crashreporter.mozbuild create mode 100644 toolkit/crashreporter/docs/Using_the_Mozilla_symbol_server.rst create mode 100644 toolkit/crashreporter/docs/img/snip_20170901070042.png create mode 100644 toolkit/crashreporter/docs/img/snip_20170901081816.png create mode 100644 toolkit/crashreporter/docs/img/symbol-server-windbg-menu.jpg create mode 100644 toolkit/crashreporter/docs/img/vs_tools_options.png create mode 100644 toolkit/crashreporter/docs/index.rst create mode 100644 toolkit/crashreporter/generate_crash_reporter_sources.py create mode 100644 toolkit/crashreporter/google-breakpad/.gitignore create mode 100644 toolkit/crashreporter/google-breakpad/AUTHORS create mode 100644 toolkit/crashreporter/google-breakpad/ChangeLog create mode 100644 toolkit/crashreporter/google-breakpad/DEPS create mode 100644 toolkit/crashreporter/google-breakpad/GIT-INFO create mode 100644 toolkit/crashreporter/google-breakpad/INSTALL create mode 100644 toolkit/crashreporter/google-breakpad/LICENSE create mode 100644 toolkit/crashreporter/google-breakpad/Makefile.am create mode 100644 toolkit/crashreporter/google-breakpad/Makefile.in create mode 100644 toolkit/crashreporter/google-breakpad/NEWS create mode 100644 toolkit/crashreporter/google-breakpad/README.ANDROID create mode 100644 toolkit/crashreporter/google-breakpad/README.md create mode 100644 toolkit/crashreporter/google-breakpad/aclocal.m4 create mode 100755 toolkit/crashreporter/google-breakpad/android/common-functions.sh create mode 100644 toolkit/crashreporter/google-breakpad/android/google_breakpad/Android.mk create mode 100755 toolkit/crashreporter/google-breakpad/android/run-checks.sh create mode 100644 toolkit/crashreporter/google-breakpad/android/sample_app/README create mode 100644 toolkit/crashreporter/google-breakpad/android/sample_app/jni/Android.mk create mode 100644 toolkit/crashreporter/google-breakpad/android/sample_app/jni/Application.mk create mode 100644 toolkit/crashreporter/google-breakpad/android/sample_app/jni/test_breakpad.cpp create mode 100755 toolkit/crashreporter/google-breakpad/android/test-driver create mode 100755 toolkit/crashreporter/google-breakpad/android/test-shell.sh create mode 100644 toolkit/crashreporter/google-breakpad/breakpad-client.pc.in create mode 100644 toolkit/crashreporter/google-breakpad/breakpad.pc.in create mode 100644 toolkit/crashreporter/google-breakpad/codereview.settings create mode 100755 toolkit/crashreporter/google-breakpad/configure create mode 100644 toolkit/crashreporter/google-breakpad/configure.ac create mode 100644 toolkit/crashreporter/google-breakpad/default.xml create mode 100644 toolkit/crashreporter/google-breakpad/src/breakpad_googletest_includes.h create mode 100644 toolkit/crashreporter/google-breakpad/src/build/all.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/build/common.gypi create mode 100644 toolkit/crashreporter/google-breakpad/src/build/filename_rules.gypi create mode 100755 toolkit/crashreporter/google-breakpad/src/build/gyp_breakpad create mode 100644 toolkit/crashreporter/google-breakpad/src/build/testing.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/README.md create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/asm.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/fpregdef.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/regdef.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/link.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/basictypes.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/common.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/common/convert_UTF.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/language.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/language.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.S create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/linux/ucontext_constants.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m create mode 100644 toolkit/crashreporter/google-breakpad/src/common/macros.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/md5.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/md5.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/memory_allocator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/memory_allocator_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/memory_range.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/common/path_helper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/path_helper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/string_conversion.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/string_conversion_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/symbol_data.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/test_assembler.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/unordered.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/using_std_string.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/module_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/omap.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/config.h.in create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/breakpad_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_amd64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_mips.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_sparc.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_x86.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_fuchsia.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_linux.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_mac.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_ps3.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_solaris.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_win32.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_format.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_size.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/basic_source_line_resolver.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/call_stack.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_modules.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_context.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_object.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exception_record.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exploitability.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/fast_source_line_resolver.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/memory_region.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump_processor.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump_processor.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/proc_maps_linux.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_result.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_state.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_base.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_interface.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_cpu.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_symbolizer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/symbol_supplier.h create mode 100644 toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/system_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/address_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/address_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/address_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_code_module.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/call_stack.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/contained_range_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/contained_range_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/contained_range_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/dump_context.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/dump_object.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/linked_ptr.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/logging.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/logging.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/map_serializers-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/map_serializers.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/map_serializers_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/microdump.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/microdump_processor.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/microdump_processor_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk.cc create mode 100755 toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_machine_readable_test create mode 100755 toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test_vars create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump_dump.cc create mode 100755 toolkit/crashreporter/google-breakpad/src/processor/minidump_dump_test create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump_processor.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump_processor_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk.cc create mode 100755 toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_machine_readable_test create mode 100755 toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_test create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/minidump_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/module_comparer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/module_comparer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/module_factory.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/module_serializer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/module_serializer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/moz.build create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/process_state.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/processor.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/processor_tools.gypi create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/proto/README create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/proto/process_state.proto create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/range_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/range_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_lower_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_upper_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/range_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/simple_serializer-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/simple_serializer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stack_frame_cpu.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stack_frame_symbolizer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips64_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest_sol.s create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_unittest_utils.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_address_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_address_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_address_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_range_map-inl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_range_map.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/static_range_map_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest_data.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/tokenize.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/tokenize.h create mode 100644 toolkit/crashreporter/google-breakpad/src/processor/windows_frame_info.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/COPYING create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/curl.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/curlver.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/easy.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/multi.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/system.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/typecheck-gcc.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/curl/urlapi.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/glog/Makefile.in create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/LICENSE create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/Makefile.am create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/README.breakpad create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/TODO create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdis.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdisasm.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/qword.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/Makefile create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/README create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm.i create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm_oop.i create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile-swig create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile.PL create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/python/Makefile-swig create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/Makefile-swig create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/extconf.rb create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/tcl/Makefile-swig create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_disasm.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_format.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_insn.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_misc.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/.gitignore create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/README.md create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/codereview.settings create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/.gitignore create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/Makefile create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/README.md create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/fallocate.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/sigtimedwait.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/test_skel.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/unlink.c create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/README create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/architecture/byte_order.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/i386/_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/arch.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/fat.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/loader.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/nlist.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/boolean.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/boolean.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_param.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/boolean.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_state.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_status.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/vm_types.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/thread_status.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/vm_prot.h create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/musl/COPYRIGHT create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/musl/README create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/musl/README.breakpad create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/musl/VERSION create mode 100644 toolkit/crashreporter/google-breakpad/src/third_party/musl/include/elf.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go create mode 100755 toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/tools.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc create mode 100755 toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp create mode 100644 toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp create mode 100644 toolkit/crashreporter/injector/injector.cpp create mode 100644 toolkit/crashreporter/injector/moz.build create mode 100644 toolkit/crashreporter/jar.mn create mode 100644 toolkit/crashreporter/mac_utils.h create mode 100644 toolkit/crashreporter/mac_utils.mm create mode 100644 toolkit/crashreporter/minidump-analyzer/MinidumpAnalyzerUtils.h create mode 100644 toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.cpp create mode 100644 toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.h create mode 100644 toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.cpp create mode 100644 toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.h create mode 100644 toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp create mode 100644 toolkit/crashreporter/minidump-analyzer/minidump-analyzer.exe.manifest create mode 100644 toolkit/crashreporter/minidump-analyzer/moz.build create mode 100644 toolkit/crashreporter/moz.build create mode 100644 toolkit/crashreporter/mozannotation_client/Cargo.toml create mode 100644 toolkit/crashreporter/mozannotation_client/cbindgen.toml create mode 100644 toolkit/crashreporter/mozannotation_client/moz.build create mode 100644 toolkit/crashreporter/mozannotation_client/src/lib.rs create mode 100644 toolkit/crashreporter/mozannotation_server/Cargo.toml create mode 100644 toolkit/crashreporter/mozannotation_server/cbindgen.toml create mode 100644 toolkit/crashreporter/mozannotation_server/moz.build create mode 100644 toolkit/crashreporter/mozannotation_server/src/errors.rs create mode 100644 toolkit/crashreporter/mozannotation_server/src/lib.rs create mode 100644 toolkit/crashreporter/mozannotation_server/src/process_reader.rs create mode 100644 toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs create mode 100644 toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs create mode 100644 toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs create mode 100644 toolkit/crashreporter/mozwer-rust/Cargo.toml create mode 100644 toolkit/crashreporter/mozwer-rust/lib.rs create mode 100644 toolkit/crashreporter/mozwer-rust/moz.build create mode 100644 toolkit/crashreporter/mozwer/moz.build create mode 100644 toolkit/crashreporter/mozwer/mozwer.cpp create mode 100644 toolkit/crashreporter/mozwer/mozwer.def create mode 100644 toolkit/crashreporter/nsDummyExceptionHandler.cpp create mode 100644 toolkit/crashreporter/nsExceptionHandler.cpp create mode 100644 toolkit/crashreporter/nsExceptionHandler.h create mode 100644 toolkit/crashreporter/nsExceptionHandlerUtils.cpp create mode 100644 toolkit/crashreporter/nsExceptionHandlerUtils.h create mode 100644 toolkit/crashreporter/process_reader/Cargo.toml create mode 100644 toolkit/crashreporter/process_reader/src/error.rs create mode 100644 toolkit/crashreporter/process_reader/src/lib.rs create mode 100644 toolkit/crashreporter/process_reader/src/process_reader.rs create mode 100644 toolkit/crashreporter/process_reader/src/process_reader/windows.rs create mode 100644 toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml create mode 100644 toolkit/crashreporter/rust_minidump_writer_linux/cbindgen.toml create mode 100644 toolkit/crashreporter/rust_minidump_writer_linux/moz.build create mode 100644 toolkit/crashreporter/rust_minidump_writer_linux/src/lib.rs create mode 100644 toolkit/crashreporter/test/CrashTestUtils.sys.mjs create mode 100644 toolkit/crashreporter/test/ExceptionThrower.cpp create mode 100644 toolkit/crashreporter/test/ExceptionThrower.h create mode 100644 toolkit/crashreporter/test/browser/browser.toml create mode 100644 toolkit/crashreporter/test/browser/browser_aboutCrashes.js create mode 100644 toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js create mode 100644 toolkit/crashreporter/test/browser/browser_bug471404.js create mode 100644 toolkit/crashreporter/test/browser/browser_clearReports.js create mode 100644 toolkit/crashreporter/test/browser/browser_cpu_microcode.js create mode 100644 toolkit/crashreporter/test/browser/browser_sandbox_crash.js create mode 100644 toolkit/crashreporter/test/browser/crashreport.sjs create mode 100644 toolkit/crashreporter/test/browser/head.js create mode 100644 toolkit/crashreporter/test/dumputils.cpp create mode 100644 toolkit/crashreporter/test/moz.build create mode 100644 toolkit/crashreporter/test/nsTestCrasher.cpp create mode 100644 toolkit/crashreporter/test/unit/crasher_subprocess_head.js create mode 100644 toolkit/crashreporter/test/unit/crasher_subprocess_tail.js create mode 100644 toolkit/crashreporter/test/unit/head_crashreporter.js create mode 100644 toolkit/crashreporter/test/unit/head_win64cfi.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_abort.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_backgroundtask_moz_crash.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_exc_guard.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_heap_corruption.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_modules.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_moz_crash.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_oom.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_phc.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_purevirtual.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_rust_panic.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_rust_panic_multiline.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_stack_overflow.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_terminator.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_uncaught_exception.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_large.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_small.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_epilog.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.exe create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.exe create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.exe create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.exe create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_push_nonvol.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol_far.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128_far.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_win64cfi_unknown_op.js create mode 100644 toolkit/crashreporter/test/unit/test_crash_with_memory_report.js create mode 100644 toolkit/crashreporter/test/unit/test_crashreporter.js create mode 100644 toolkit/crashreporter/test/unit/test_crashreporter_appmem.js create mode 100644 toolkit/crashreporter/test/unit/test_crashreporter_crash.js create mode 100644 toolkit/crashreporter/test/unit/test_event_files.js create mode 100644 toolkit/crashreporter/test/unit/test_kill.js create mode 100644 toolkit/crashreporter/test/unit/test_oom_annotation.js create mode 100644 toolkit/crashreporter/test/unit/test_override_exception_handler.js create mode 100644 toolkit/crashreporter/test/unit/xpcshell-phc.toml create mode 100644 toolkit/crashreporter/test/unit/xpcshell.toml create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_annotation.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_exception_time_annotation.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_large_annotation.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_oom_annotation.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_phc.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_phc2.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_phc3.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js create mode 100644 toolkit/crashreporter/test/unit_ipc/test_content_rust_panic_multiline.js create mode 100644 toolkit/crashreporter/test/unit_ipc/xpcshell-phc.toml create mode 100644 toolkit/crashreporter/test/unit_ipc/xpcshell.toml create mode 100644 toolkit/crashreporter/test/win64UnwindInfoTests.asm create mode 100644 toolkit/crashreporter/tools/python.toml create mode 100755 toolkit/crashreporter/tools/symbolstore.py create mode 100755 toolkit/crashreporter/tools/unit-symbolstore.py create mode 100644 toolkit/crashreporter/tools/upload_symbols.py create mode 100755 toolkit/crashreporter/update-breakpad.sh (limited to 'toolkit/crashreporter') diff --git a/toolkit/crashreporter/CrashAnnotations.cpp b/toolkit/crashreporter/CrashAnnotations.cpp new file mode 100644 index 0000000000..87a9ac594e --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.cpp @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CrashAnnotations.h" + +#include +#include +#include + +using std::begin; +using std::end; +using std::find_if; + +namespace CrashReporter { + +bool AnnotationFromString(Annotation& aResult, const char* aValue) { + const auto* elem = find_if( + begin(kAnnotationStrings), end(kAnnotationStrings), + [&aValue](const char* aString) { return strcmp(aString, aValue) == 0; }); + + if (elem == end(kAnnotationStrings)) { + return false; + } + + aResult = static_cast(elem - begin(kAnnotationStrings)); + return true; +} + +bool IsAnnotationAllowedForPing(Annotation aAnnotation) { + const auto* elem = find_if( + begin(kCrashPingAllowedList), end(kCrashPingAllowedList), + [&aAnnotation](Annotation aElement) { return aElement == aAnnotation; }); + + return elem != end(kCrashPingAllowedList); +} + +bool ShouldIncludeAnnotation(Annotation aAnnotation, const char* aValue) { + const auto* elem = find_if(begin(kSkipIfList), end(kSkipIfList), + [&aAnnotation](AnnotationSkipValue aElement) { + return aElement.annotation == aAnnotation; + }); + + if (elem != end(kSkipIfList)) { + if (strcmp(aValue, elem->value) == 0) { + return false; + } + } + + return true; +} + +} // namespace CrashReporter diff --git a/toolkit/crashreporter/CrashAnnotations.h.in b/toolkit/crashreporter/CrashAnnotations.h.in new file mode 100644 index 0000000000..7ea8c98bc1 --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.h.in @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CrashAnnotations_h +#define CrashAnnotations_h + +#include +#include + +namespace CrashReporter { + +// Typed enum representing all crash annotations +enum class Annotation : uint32_t { +${enum} +}; + +// Stringified crash annotation names +const char* const kAnnotationStrings[] = { +${strings} +}; + +// Type of each annotation +enum class AnnotationType : uint8_t { + String = 0, // Any type of string, const char*, nsCString, etc... + Boolean = 1, // Stored as a byte + U32 = 2, // C/C++'s uint32_t or Rust's u32 + U64 = 3, // C/C++'s uint64_t or Rust's u64 + USize = 4, // C/C++'s size_t or Rust's usize +}; + +// Type of each annotation +const AnnotationType kAnnotationTypes[] = { +${types} +}; + +// Allowlist of crash annotations that can be included in a crash ping +const Annotation kCrashPingAllowedList[] = { +${allowedlist} +}; + +// Annotations which should be skipped when they have specific values +struct AnnotationSkipValue { + Annotation annotation; + const char* value; +}; + +const AnnotationSkipValue kSkipIfList[] = { +${skiplist} +}; + +/** + * Return the string representation of a crash annotation. + * + * @param aAnnotation a crash annotation + * @returns A constant string holding the annotation name + */ +static inline const char* AnnotationToString(Annotation aAnnotation) { + return kAnnotationStrings[static_cast(aAnnotation)]; +} + +/** + * Converts a string to its corresponding crash annotation. + * + * @param aResult a reference where the annotation will be stored + * @param aValue the string to be converted + * @return true if the string was successfully converted, false if it did not + * correspond to any known annotation + */ +bool AnnotationFromString(Annotation& aResult, const char* aValue); + +/** + * Checks if the given crash annotation is allowed for inclusion in the crash + * ping. + * + * @param aAnnotation the crash annotation to be checked + * @return true if the annotation can be included in the crash ping, false + * otherwise + */ +bool IsAnnotationAllowedForPing(Annotation aAnnotation); + +/** + * Checks if the annotation should be included. Some annotations are skipped if + * their value matches a specific one (like the value 0). + * + * @param aAnnotation the crash annotation to be checked + * @param aValue the contents of the annotation as a string + * @return true if the annotation should be included, false otherwise + */ +bool ShouldIncludeAnnotation(Annotation aAnnotation, const char* aValue); + +/** + * Abstract annotation writer, this is needed only for code that writes out + * annotations in the exception handler. + */ +class AnnotationWriter { + public: + virtual void Write(Annotation aAnnotation, const char* aValue, + size_t aLen = 0) = 0; + virtual void Write(Annotation aAnnotation, uint64_t aValue) = 0; +}; + +} // namespace CrashReporter + +#endif // CrashAnnotations_h diff --git a/toolkit/crashreporter/CrashAnnotations.yaml b/toolkit/crashreporter/CrashAnnotations.yaml new file mode 100644 index 0000000000..8f6bb2e8c2 --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.yaml @@ -0,0 +1,1028 @@ +# This lists all the available crash annotations. +# +# Mandatory fields for each entry are: +# - description: A string describing the annotation +# - type: the annotation type, currently `string`, `boolean`, `u32`, `u64` or +# `usize`. Note that `boolean` values are stringified to `1` for +# true and `0` for false. +# +# Additionally a field can have the following optional fields: +# - altname: A string that will be used when writing out the annotation to the +# .extra file instead of the annotation name +# - ping: A boolean that indicates whether the annotation is allowed for +# inclusion in the crash ping, if not specified this defaults to false +# - skip_if: A string that will cause the annotation not to be included in the +# crash report if the contents match it. + +AbortMessage: + description: > + Message passed to NS_DebugBreak(). + type: string + +Accessibility: + description: > + Set to "Active" by the accessibility service when it is active. + type: string + +AccessibilityClient: + description: > + Accessibility client ID. + type: string + +AccessibilityInProcClient: + description: > + Hexadecimal mask of in-process accessibility consumers, see + accessible/windows/msaa/Compatibility.h for the mappings. + type: string + +AdapterDeviceID: + description: > + Graphics adapter name. + type: string + +AdapterDriverVendor: + description: > + Graphics adapter driver vendor. + type: string + +AdapterDriverVersion: + description: > + Graphics adapter driver version. + type: string + +AdapterSubsysID: + description: > + Graphics adapter subsystem ID. + type: string + +AdapterVendorID: + description: > + Graphics adapter vendor name. + type: string + +additional_minidumps: + description: > + Comma separated list of additional minidumps for this crash, each element + in the list represent the suffix used in the dump filename. E.g. the + "browser" entry for crash fa909194-737b-4b93-b8da-da110ac785e0 implies the + existence of the fa909194-737b-4b93-b8da-da110ac785e0-browser.dmp file. + type: string + +Addons: + description: > + List of currently enabled add-ons. + type: string + altname: Add-ons + +Android_Board: + description: > + The name of the underlying board used by the Android device. e.g. "k68v1_64" + type: string + +Android_Brand: + description: > + The consumer-visible brand associated with this Android device. e.g. "vivo" + type: string + +Android_CPU_ABI: + description: > + The Android primary CPU ABI being used. e.g. "arm64-v8a" + type: string + +Android_CPU_ABI2: + description: > + The Android secondary CPU ABI being used. e.g. "armeabi-v7a" + type: string + +Android_Device: + description: > + Android device name. e.g. "1907" + type: string + +Android_Display: + description: > + End-user visible display name of the build id for the Android build. + e.g. "SP1A.210812.003 release-keys" + type: string + +Android_Fingerprint: + description: > + A string that uniquely identifies the Android build. e.g. + "vivo/1907/1907:12/SP1A.210812.003/compiler03091510:user/release-keys" + type: string + +Android_Hardware: + description: > + The name of the Android hardware from "/proc". e.g. "mt6768" + type: string + +Android_Manufacturer: + description: > + Android device manufacturer. e.g. "vivo" + type: string + +Android_Model: + description: > + End-user visible Android device model name. e.g. "vivo 1907" + type: string + +Android_PackageName: + description: > + The package name of an Android application that uniquely identifies the + application on the device, Google Play Store, and third-party Android + stores. e.g. "com.example.referencebrowser" + type: string + +Android_Version: + description: > + The developer preview revision of a prerelease SDK plus The current + development codename, or the string "REL" if this is a release build. + e.g. "31 (REL)" + type: string + +AppInitDLLs: + description: > + List of DLLs loaded when launching any application on Windows, this + reflects the contents of the AppInit_DLLs registry key. + type: string + +ApplicationBuildID: + description: > + Product application's build ID. + type: string + +AsyncShutdownTimeout: + description: > + This annotation is present if a shutdown blocker was not released in time + and the browser was crashed instead of waiting for shutdown to finish. The + condition that caused the hang is contained in the annotation. + type: string + ping: true + +AvailablePageFile: + description: > + Available commit-space in bytes. + - Under Windows, computed from the PERFORMANCE_INFORMATION structure by substracting + the CommitTotal field from the CommitLimit field. + - Under Linux, computed from /proc/meminfo's CommitLimit - Committed_AS. Note that + the kernel is not guaranteed to enforce that CommittedLimit >= Committed_AS. If + Committed_AS > CommittedLimit, this value is set to 0. + - Not available on other platforms. + type: usize + ping: true + +AvailablePhysicalMemory: + description: > + Amount of free physical memory in bytes. + - Under Windows, populated with the contents of the MEMORYSTATUSEX's structure + ullAvailPhys field. + - Under macOS, populated with vm_statistics64_data_t::free_count. + - Under Linux, populated with /proc/meminfo's MemFree. + - Not available on other platforms. + type: usize + ping: true + +AvailableSwapMemory: + description: > + Amount of free swap space in bytes. + - Under macOS, populated with the contents of + sysctl "vm.swapusage" :: xsu_avail. + - Under Linux, populated with /proc/meminfo's SwapFree. + - Not available on other platforms. + type: usize + ping: true + +AvailableVirtualMemory: + description: > + Amount of free virtual memory in bytes + - Under Windows, populated with the contents of the MEMORYSTATUSEX's structure ullAvailVirtual field. + - Under Linux, populated with /proc/meminfo's MemAvailable. + - Not available on other platforms. + - For macOS, see AvailableSwapMemory, AvailablePhysicalMemory and PurgeablePhysicalMemory. + type: usize + ping: true + +BackgroundTaskMode: + description: > + True if the app was invoked in background task mode via `--backgroundtask ...`, false otherwise. + type: boolean + +BackgroundTaskName: + description: > + If the app was invoked in background task mode via `--backgroundtask `, the string "task name". + type: string + ping: true + +BlockedDllList: + description: > + Comma-separated list of blocked DLLS, Windows-only + type: string + ping: true + +BlocklistInitFailed: + description: > + Set to 1 if the DLL blocklist could not be initialized. + type: boolean + ping: true + skip_if: "0" + +Breadcrumbs: + description: > + Trail of events that occurred before a report. this will consist of multiple breadcrumbs with + timestamp, message, category, level, type and data in JSON format. + type: string + +BuildID: + description: > + Application build ID, the format is YYYYMMDDHHMMSS. + type: string + ping: true + +ContentSandboxCapabilities: + description: > + List of capabilities of the content process sandbox. + type: u32 + +ContentSandboxEnabled: + description: > + Set to 1 when content process sandboxing is enabled. + type: boolean + +ContentSandboxCapable: + description: > + Set to 1 if the client is capable of content sandboxing. + type: boolean + +ContentSandboxLevel: + description: > + Content sandbox level. + type: u32 + +ContentSandboxWin32kState: + description: > + Content sandbox Win32k state + type: string + +GpuSandboxLevel: + description: > + GPU sandbox level. + type: u32 + +CPUMicrocodeVersion: + description: > + Version of the CPU microcode. + type: string + +CrashTime: + description: > + Crash time in seconds since the Epoch. + type: string + ping: true + +CycleCollector: + description: > + Reason why the cycle collector crashed. + type: string + +DesktopEnvironment: + description: > + Desktop environment used on Linux, e.g. GNOME, KDE, XFCE, etc. + type: string + +DeviceResetReason: + description: > + Reason why a DirectX device has been reset, Windows only. + type: u32 + +DOMFissionEnabled: + description: > + Set to 1 when DOM fission is enabled, and subframes are potentially loaded + in a separate process. + type: boolean + ping: true + +DOMIPCEnabled: + description: > + Set to 1 when a tab is running in a content process + type: boolean + +DumperError: + description: > + Error message of the minidump writer, in case there was an error during dumping. + type: string + +EMCheckCompatibility: + description: > + Set to true if add-on compatibility checking is enabled. Technically this + annotation should be a boolean, but historically it's been set by JavaScript + code as a string, so keep it as such for the time being. + type: string + +EventLoopNestingLevel: + description: > + Present only if higher than 0, indicates that we're running in a nested + event loop and indicates the nesting level. + type: u32 + ping: true + skip_if: "0" + +ExperimentalFeatures: + description: > + Comma-separated list of enabled experimental features from about:preferences#experimental. + type: string + ping: true + +FontName: + description: > + Set before attempting to load a font to help diagnose crashes during loading. + type: string + ping: true + +GMPLibraryPath: + description: > + Holds the path to the GMP plugin library. + type: string + +GMPPlugin: + description: > + Set to 1 if the GMP plugin is enabled. + type: boolean + +GPUProcessLaunchCount: + description: > + Number of times the GPU process was launched. + type: u32 + ping: true + +GPUProcessStatus: + description: > + Status of the GPU process, can be set to "Running" or "Destroyed" + type: string + +GraphicsCompileShader: + description: > + Name of the shader we are in the process of compiling, if applicable. See + file names in gfx/wr/webrender/res/* for the possible values. + type: string + +GraphicsCriticalError: + description: > + Information of a critical error that occurred within the graphics code. + type: string + +GraphicsDrawShader: + description: > + Name of the shader that is currently bound for a draw call, if applicable. + See file names in gfx/wr/webrender/res/* for the possible values. + type: string + +GraphicsNumActiveRenderers: + description: > + Number of webrender renderer instances that are not in a paused state. + type: usize + +GraphicsNumRenderers: + description: > + Total number of webrender renderer instances. + type: usize + +GraphicsStartupTest: + description: > + Set to 1 by the graphics driver crash guard when it's activated. + type: boolean + +HeadlessMode: + description: > + True if the app was invoked in headless mode via `--headless ...` or `--backgroundtask ...`, false otherwise. + type: boolean + ping: true + +PHCKind: + description: > + The allocation kind, if the crash involved a bad access of a special PHC + allocation. + type: string + +PHCBaseAddress: + description: > + The allocation's base address, if the crash involved a bad access of a + special PHC allocation. Encoded as a decimal address. + type: string + +PHCUsableSize: + description: > + The allocation's usable size, if the crash involved a bad access of a + special PHC allocation. + # A 32-bit integer is enough because the maximum usable size of a special PHC + # allocation is far less than 2 GiB. + type: u32 + +PHCAllocStack: + description: > + The allocation's allocation stack trace, if the crash involved a bad access + of a special PHC allocation. Encoded as a comma-separated list of decimal + addresses. + type: string + +PHCFreeStack: + description: > + The allocation's free stack trace, if the crash involved a bad access + of a special PHC allocation. Encoded as a comma-separated list of decimal + addresses. + type: string + +HasDeviceTouchScreen: + description: > + Set to 1 if the device had a touch-screen, this only applies to Firefox + desktop as on mobile devices we assume a touch-screen is always present. + type: boolean + +InstallTime: + description: > + The time when Firefox was installed expressed as seconds since the Epoch + type: string # This should be u64 but we currently handle it as a string + +ipc_channel_error: + description: > + Set before a content process crashes because of an IPC channel error, holds + a description of the error. + type: string + ping: true + +IpcCreatePipeCloExecErrno: + description: > + errno value retrieved after failing to set the O_CLOEXEC flag on a pipe + used for IPC. + type: u32 + +IpcCreatePipeFcntlErrno: + description: > + errno value retrieved after a call to fcntl() on a pipe used for IPC failed. + type: u32 + +IpcCreatePipeSocketPairErrno: + description: > + errno value retrieved after a socketpair() call failed while creating an IPC + transport object. + type: u32 + +IPCFatalErrorMsg: + description: > + Describes a fatal error that occurred during IPC operation. + type: string + +IPCFatalErrorProtocol: + description: > + Name of the protocol used by IPC when a fatal error occurred. + type: string + +IPCMessageName: + description: > + Name of the IPC message that caused a crash because it was too large. + type: string + +IPCMessageSize: + description: > + Size of the IPC message that caused a crash because it was too large. + type: u32 + +IPCReadErrorReason: + description: > + Reason why reading an object via IPC failed. + type: string + +IPCShutdownState: + description: > + IPC shutdown state, can be set to either "RecvShutdown" or + "SendFinishShutdown" by a content process while it's shutting down. + type: string + +IPCSystemError: + description: > + Description of the last system error that occurred during IPC operation. + type: u32 + +Hang: + description: > + Set if the crash was the result of a hang, with a value which describes the + type of hang (e.g. "ui" or "shutdown"). + type: string + ping: true + +IsGarbageCollecting: + description: > + If true then the JavaScript garbage collector was running when the crash + occurred. + type: boolean + ping: true + skip_if: "0" + +IsWayland: + description: > + If true then the Wayland windowing system was in use. + type: boolean + +IsWebRenderResourcePathOverridden: + description: > + If true then the WebRender resources (i.e. shaders) are loaded from a user specified path. + type: boolean + +JavaException: + description: > + JSON structured Java stack trace, only present on Firefox for Android if we encounter an + uncaught Java exception. + type: string + +JavaStackTrace: + description: > + Java stack trace, only present on Firefox for Android if we encounter an + uncaught Java exception. + type: string + +JSActorMessage: + description: > + If an actor is currently treating a message, this is the name of the message. + Otherwise, empty. + type: string + +JSActorName: + description: > + If an actor is currently treating a message, this is the name of the actor. + Otherwise, empty. + type: string + +JSLargeAllocationFailure: + description: > + A large allocation couldn't be satisfied, check the JSOutOfMemory + description for the possible values of this annotation. + type: string + +JSModuleLoadError: + description: > + The error raised when attempting to import a critical JS module from C++ + type: string + +JSOutOfMemory: + description: > + A small allocation couldn't be satisfied, the annotation may contain the + "Reporting", "Reported" or "Recovered" value. The first one means that + we crashed while responding to the OOM condition (possibly while running a + memory-pressure observers), the second that we crashed after having tried to + free some memory, and the last that the GC had managed to free enough memory + to satisfy the allocation. + type: string + + +LastInteractionDuration: + description: > + How long the user had been inactive in seconds if the user was inactive + at crash. The value is not set if the user state was active. + type: u64 + ping: true + +LastStartupWasCrash: + description: > + True if the last startup was detected to have been a crash. + type: boolean + +MacMemoryPressure: + description: > + The current memory pressure state as provided by the macOS memory pressure + dispatch source. The annotation value is one of "Normal" for no memory + pressure, "Unset" indicating a memory pressure event has not been received, + "Warning" or "Critical" mapping to the system memory pressure levels, + or "Unexpected" for an unexpected level. This is a Mac-specific annotation. + type: string + +MacMemoryPressureNormalTime: + description: > + The time when the memory pressure state last transitioned to 'Normal' + expressed as seconds since the Epoch. + type: string + +MacMemoryPressureWarningTime: + description: > + The time when the memory pressure state last transitioned to 'Warning' + expressed as seconds since the Epoch. + type: string + +MacMemoryPressureCriticalTime: + description: > + The time when the memory pressure state last transitioned to 'Critical' + expressed as seconds since the Epoch. + type: string + +MacMemoryPressureSysctl: + description: > + The value of the memory pressure sysctl + 'kern.memorystatus_vm_pressure_level'. Indicates which memory + pressure level the system is in at the time of the crash. The expected + values are one of 4 (Critical), 2 (Warning), or 1 (Normal). + type: u32 + +MacAvailableMemorySysctl: + description: > + The value of the available memory sysctl 'kern.memorystatus_level'. + Expected to be a percentage integer value. + type: u32 + +LinuxUnderMemoryPressure: + description: > + Set to true if the memory pressure watcher was under memory pressure when + the crash occurred. + type: boolean + +LauncherProcessState: + description: > + Launcher process enabled state. The integer value of this annotation must + match with one of the values in the + mozilla::LauncherRegistryInfo::EnableState enum + type: u32 + +LowPhysicalMemoryEvents: + description: > + Number of times the available memory tracker has detected that free + physical memory is running low. This is a Windows-specific annotation. + type: u32 + ping: true + skip_if: "0" + +MainThreadRunnableName: + description: > + Name of the currently executing nsIRunnable on the main thread. + type: string + ping: true + +MozCrashReason: + description: > + Plaintext description of why Firefox crashed, this is usually set by + assertions and the like. + type: string + ping: true + +Notes: + description: > + Miscellaneous notes that can be appended to a crash. + type: string + +OOMAllocationSize: + description: > + Size of the allocation that caused an out-of-memory condition. + type: usize + ping: true + skip_if: "0" + +PluginFilename: + description: > + Plugin filename, only the process holding the plugin has this annotation. + type: string + +PluginName: + description: > + Display name of a plugin, only the process holding the plugin has this + annotation. + type: string + +PluginVersion: + description: > + Version of a plugin, only the process holding the plugin has this + annotation. + type: string + +ProcessType: + description: > + Type of the process that crashed, the possible values are defined in + GeckoProcessTypes.h. + type: string + +ProductName: + description: > + Application name (e.g. Firefox). + type: string + ping: true + +ProductID: + description: > + Application UUID (e.g. ec8030f7-c20a-464f-9b0e-13a3a9e97384). + type: string + ping: true + +ProfilerChildShutdownPhase: + description: > + When a child process shuts down, this describes if the profiler is running, + and the point the profiler shutdown sequence has reached. + type: string + ping: true + +PurgeablePhysicalMemory: + description: > + macOS only. Amount of physical memory currently allocated but which may + be deallocated by the system in case of memory pressure. Populated from + vm_statistics64_data_t::purgeable_count * vm_page_size. + type: usize + ping: true + +QuotaManagerShutdownTimeout: + description: > + This annotation is present if the quota manager shutdown (resp. the shutdown + of the quota manager clients) was not finished in time and the browser was + crashed instead of waiting for the shutdown to finish. The status of objects + which were blocking completion of the shutdown when reaching the timeout + is contained in the annotation. + + In the case of IndexedDB, objects are divided into three groups: + FactoryOperations, LiveDatabases and DatabaseMaintenances. + + In the case of LocalStorage, objects are divided into three groups: + PrepareDatastoreOperations, Datastores and LiveDatabases. + + In the case of Cache API, objects are in one group only: + Managers. + + Each group is reported separately and contains the number of objects in the + group and the status of individual objects in the group (duplicate entries + are removed): + "GroupName: N (objectStatus1, objectStatus2, ...)" where N is the number of + objects in the group. + + The status of individual objects is constructed by taking selected object + properties. Properties which contain origin strings are anonymized. + + In addition, intermediate steps are recorded for change events after shutdown + started. These include the time difference and the type of object. + type: string + ping: true + +RDDProcessStatus: + description: > + Status of the RDD process, can be set to "Running" or "Destroyed" + type: string + +ReleaseChannel: + description: > + Application release channel (e.g. default, beta, ...) + type: string + ping: true + +RemoteType: + description: > + Type of the content process, can be set to "web", "file" or "extension". + type: string + ping: true + +SafeMode: + description: > + Set to 1 if the browser was started in safe mode. + type: boolean + +SecondsSinceLastCrash: + description: > + Time in seconds since the last crash occurred. + type: u64 + ping: true + +ServerURL: + description: > + URL used to post the crash report. + type: string + +ShutdownProgress: + description: > + Shutdown step at which the browser crashed, can be set to "quit-application", + "profile-change-teardown", "profile-before-change", "xpcom-will-shutdown" or + "xpcom-shutdown". + type: string + ping: true + +ShutdownReason: + description: > + One out of "Unknown", "AppClose", "AppRestart", "OSForceClose", + "OSSessionEnd", "OSShutdown" or "WinUnexpectedMozQuit". + type: string + ping: true + +StartupCacheValid: + description: > + True if the startup cache was deemed valid and usable. Will be false if the + last session used a different browser version or had a startup cache. + type: boolean + +StartupCrash: + description: > + If set to 1 then this crash occurred during startup. + type: boolean + ping: true + +StartupTime: + description: > + The time when Firefox was launched expressed in seconds since the Epoch. + type: u64 + +StorageConnectionNotClosed: + description: > + This annotation is added when a mozStorage connection has not been properly + closed during shutdown. The annotation holds the filename of the database + associated with the connection. + type: string + +SubmittedFrom: + description: > + This annotation can hold one of the following five values depending on how + this crash was submitted by the user: + * Auto: the user had opted-in to auto-submission + * Infobar: the user clicked on the infobar to submit the crash + * AboutCrashes: the user sent the crash from the about:crashes page + * CrashedTab: the user sent the crash from a crashed tab page + * Client: the user sent the crash using the crash reporter client + type: string + +SystemMemoryUsePercentage: + description: > + Windows-only, percentage of physical memory in use. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure dwMemoryLoad + field. + type: u32 + ping: true + +TelemetryClientId: + description: > + Telemetry client ID. + type: string + +TelemetryEnvironment: + description: > + The telemetry environment in JSON format. + type: string + +TelemetryServerURL: + description: > + Telemetry server URL. Used to send main process crash pings directly from + the crashreporter client. + type: string + +TelemetrySessionId: + description: > + Telemetry session ID. + type: string + +TestKey: + description: > + Annotation used in tests. + type: string + +TestUnicode: + description: > + Annotation used in tests. + type: string + +TextureUsage: + description: > + Amount of memory in bytes consumed by textures. + type: usize + ping: true + skip_if: "0" + +Throttleable: + description: > + Whether Socorro can selectively discard this crash report or not. If set + to "0" the crash report will always be processed by Socorro. Do not set + this annotation within Gecko code, it's only supposed to be used by the + crash reporting machinery. + type: boolean + +TotalPageFile: + description: > + Maximum amount of memory that can be committed without extending the swap/page file. + - Under Windows, populated with the contents of the PERFORMANCE_INFORMATION's + structure CommitLimit field. + - Under Linux, populated with /proc/meminfo MemTotal + SwapTotal. The swap file + typically cannot be extended, so that's a hard limit. + - Not available on other systems. + type: usize + ping: true + +TotalPhysicalMemory: + description: > + Amount of physical memory in bytes. + - Under Windows, populated with the contents of the MEMORYSTATUSEX's structure + ullTotalPhys field. + - Under macOS, populated with sysctl "hw.memsize". + - Under Linux, populated with /proc/meminfo's "MemTotal". + - Not available on other systems. + type: usize + ping: true + +TotalVirtualMemory: + description: > + Size of the virtual address space. + - Under Windows, populated with the contents of the MEMORYSTATUSEX's structure + ullTotalVirtual field. + - Not available on other platforms. + type: usize + ping: true + +UnknownNetAddrSocketFamily: + description: > + An unknown network address family was requested to Necko. The value is the + requested family number. + type: u32 + +UptimeTS: + description: > + Uptime in seconds. This annotation uses a string instead of an integer + because it has a fractional component. + type: string # This is a floating-point number but we treat it as a string + ping: true + +URL: + description: > + URL being loaded. + type: string + +URLSegments: + description: > + The offsets of the nsStandardURL segments that fail a sanity check + type: string + +User32BeforeBlocklist: + description: > + Set to 1 if user32.dll was loaded before we could install the DLL blocklist. + type: boolean + ping: true + skip_if: "0" + +useragent_locale: + description: > + User-agent locale. + type: string + +UtilityProcessStatus: + description: > + Status of the Utility process, can be set to "Running" or "Destroyed" + type: string + +UtilityActorsName: + description: > + Comma-separated list of IPC actors name running on this Utility process instance + type: string + ping: true + +Vendor: + description: > + Application vendor (e.g. Mozilla). + type: string + +Version: + description: > + Product version. + type: string + +VRProcessStatus: + description: > + Status of the VR process, can be set to "Running" or "Destroyed" + type: string + +WasmLibrarySandboxMallocFailed: + description: > + Set to 1 if a rlbox wasm library sandbox ran out of memory, causing a + malloc inside the sandbox to fail. + type: boolean + +WindowsFileDialogErrorCode: + description: > + The HRESULT returned from a Win32 system call leading to termination of the + file-dialog utility process. MozCrashReason is expected to provide context + for the value. + type: u32 # This is an HRESULT which is defined as signed, but we don't want to print it as a signed integer + ping: true + +WindowsPackageFamilyName: + description: > + If running in a Windows package context, the package family name, per + https://docs.microsoft.com/en-us/windows/win32/api/appmodel/nf-appmodel-getcurrentpackagefamilyname. + + The package family name is only included when it is likely to have been produced by Mozilla: it + starts "Mozilla." or "MozillaCorporation.". + type: string + ping: true + +WindowsErrorReporting: + description: > + Set to 1 if this crash was intercepted via the Windows Error Reporting + runtime exception module. + type: boolean + ping: true + +Winsock_LSP: + description: > + Information on winsock LSPs injected in our networking stack. + type: string + +XPCOMSpinEventLoopStack: + description: > + If we crash while some code is spinning manually the event loop on the + main thread, we will see the stack of nested annotations here. + If the crashing process was killed (e.g. due to an IPC error), this + annotation may refer to the parent process that killed it, look out for + the prefix ("default" means parent) and see bug 1741131 for details. + type: string diff --git a/toolkit/crashreporter/CrashReports.sys.mjs b/toolkit/crashreporter/CrashReports.sys.mjs new file mode 100644 index 0000000000..3f66da1ec3 --- /dev/null +++ b/toolkit/crashreporter/CrashReports.sys.mjs @@ -0,0 +1,81 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export var CrashReports = { + pendingDir: null, + reportsDir: null, + submittedDir: null, + getReports: function CrashReports_getReports() { + let reports = []; + + try { + // Ignore any non http/https urls + if (!/^https?:/i.test(Services.prefs.getCharPref("breakpad.reportURL"))) { + return reports; + } + } catch (e) {} + + if (this.submittedDir.exists() && this.submittedDir.isDirectory()) { + let entries = this.submittedDir.directoryEntries; + while (entries.hasMoreElements()) { + let file = entries.nextFile; + let leaf = file.leafName; + if (leaf.startsWith("bp-") && leaf.endsWith(".txt")) { + let entry = { + id: leaf.slice(0, -4), + date: file.lastModifiedTime, + pending: false, + }; + reports.push(entry); + } + } + } + + if (this.pendingDir.exists() && this.pendingDir.isDirectory()) { + let uuidRegex = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + let entries = this.pendingDir.directoryEntries; + while (entries.hasMoreElements()) { + let file = entries.nextFile; + let leaf = file.leafName; + let id = leaf.slice(0, -4); + if (leaf.endsWith(".dmp") && uuidRegex.test(id)) { + let entry = { + id, + date: file.lastModifiedTime, + pending: true, + }; + reports.push(entry); + } + } + } + + // Sort reports descending by date + return reports.sort((a, b) => b.date - a.date); + }, +}; + +function CrashReports_pendingDir() { + let pendingDir = Services.dirsvc.get("UAppData", Ci.nsIFile); + pendingDir.append("Crash Reports"); + pendingDir.append("pending"); + return pendingDir; +} + +function CrashReports_reportsDir() { + let reportsDir = Services.dirsvc.get("UAppData", Ci.nsIFile); + reportsDir.append("Crash Reports"); + return reportsDir; +} + +function CrashReports_submittedDir() { + let submittedDir = Services.dirsvc.get("UAppData", Ci.nsIFile); + submittedDir.append("Crash Reports"); + submittedDir.append("submitted"); + return submittedDir; +} + +CrashReports.pendingDir = CrashReports_pendingDir(); +CrashReports.reportsDir = CrashReports_reportsDir(); +CrashReports.submittedDir = CrashReports_submittedDir(); diff --git a/toolkit/crashreporter/CrashSubmit.sys.mjs b/toolkit/crashreporter/CrashSubmit.sys.mjs new file mode 100644 index 0000000000..28647c5a83 --- /dev/null +++ b/toolkit/crashreporter/CrashSubmit.sys.mjs @@ -0,0 +1,666 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { FileUtils } from "resource://gre/modules/FileUtils.sys.mjs"; + +const SUCCESS = "success"; +const FAILED = "failed"; +const SUBMITTING = "submitting"; + +const UUID_REGEX = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; +const SUBMISSION_REGEX = + /^bp-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + +// TODO: this is still synchronous; need an async INI parser to make it async +function parseINIStrings(path) { + let file = new FileUtils.File(path); + let factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].getService( + Ci.nsIINIParserFactory + ); + let parser = factory.createINIParser(file); + let obj = {}; + for (let key of parser.getKeys("Strings")) { + obj[key] = parser.getString("Strings", key); + } + return obj; +} + +// Since we're basically re-implementing (with async) part of the crashreporter +// client here, we'll just steal the strings we need from crashreporter.ini +async function getL10nStrings() { + let path = PathUtils.join( + Services.dirsvc.get("GreD", Ci.nsIFile).path, + "crashreporter.ini" + ); + let pathExists = await IOUtils.exists(path); + + if (!pathExists) { + // we if we're on a mac + let parentDir = PathUtils.parent(path); + path = PathUtils.join( + parentDir, + "MacOS", + "crashreporter.app", + "Contents", + "Resources", + "crashreporter.ini" + ); + + let pathExists = await IOUtils.exists(path); + + if (!pathExists) { + // This happens on Android where everything is in an APK. + // Android users can't see the contents of the submitted files + // anyway, so just hardcode some fallback strings. + return { + crashid: "Crash ID: %s", + reporturl: "You can view details of this crash at %s", + }; + } + } + + let crstrings = parseINIStrings(path); + let strings = { + crashid: crstrings.CrashID, + reporturl: crstrings.CrashDetailsURL, + }; + + path = PathUtils.join( + Services.dirsvc.get("XCurProcD", Ci.nsIFile).path, + "crashreporter-override.ini" + ); + pathExists = await IOUtils.exists(path); + + if (pathExists) { + crstrings = parseINIStrings(path); + + if ("CrashID" in crstrings) { + strings.crashid = crstrings.CrashID; + } + + if ("CrashDetailsURL" in crstrings) { + strings.reporturl = crstrings.CrashDetailsURL; + } + } + + return strings; +} + +function getDir(name) { + let uAppDataPath = Services.dirsvc.get("UAppData", Ci.nsIFile).path; + return PathUtils.join(uAppDataPath, "Crash Reports", name); +} + +async function writeFileAsync(dirName, fileName, data) { + let dirPath = getDir(dirName); + let filePath = PathUtils.join(dirPath, fileName); + await IOUtils.makeDirectory(dirPath, { permissions: 0o700 }); + await IOUtils.writeUTF8(filePath, data); +} + +function getPendingMinidump(id) { + let pendingDir = getDir("pending"); + + return [".dmp", ".extra", ".memory.json.gz"].map(suffix => { + return PathUtils.join(pendingDir, `${id}${suffix}`); + }); +} + +async function writeSubmittedReportAsync(crashID, viewURL) { + let strings = await getL10nStrings(); + let data = strings.crashid.replace("%s", crashID); + + if (viewURL) { + data += "\n" + strings.reporturl.replace("%s", viewURL); + } + + await writeFileAsync("submitted", `${crashID}.txt`, data); +} + +// the Submitter class represents an individual submission. +function Submitter(id, recordSubmission, noThrottle, extraExtraKeyVals) { + this.id = id; + this.recordSubmission = recordSubmission; + this.noThrottle = noThrottle; + this.additionalDumps = []; + this.extraKeyVals = extraExtraKeyVals; + // mimic deferred Promise behavior + this.submitStatusPromise = new Promise((resolve, reject) => { + this.resolveSubmitStatusPromise = resolve; + this.rejectSubmitStatusPromise = reject; + }); +} + +Submitter.prototype = { + submitSuccess: async function Submitter_submitSuccess(ret) { + // Write out the details file to submitted + await writeSubmittedReportAsync(ret.CrashID, ret.ViewURL); + + try { + let toDelete = [this.dump, this.extra]; + + if (this.memory) { + toDelete.push(this.memory); + } + + for (let entry of this.additionalDumps) { + toDelete.push(entry.dump); + } + + await Promise.all( + toDelete.map(path => { + return IOUtils.remove(path, { ignoreAbsent: true }); + }) + ); + } catch (ex) { + console.error(ex); + } + + this.notifyStatus(SUCCESS, ret); + this.cleanup(); + }, + + cleanup: function Submitter_cleanup() { + // drop some references just to be nice + this.iframe = null; + this.dump = null; + this.extra = null; + this.memory = null; + this.additionalDumps = null; + // remove this object from the list of active submissions + let idx = CrashSubmit._activeSubmissions.indexOf(this); + if (idx != -1) { + CrashSubmit._activeSubmissions.splice(idx, 1); + } + }, + + parseResponse: function Submitter_parseResponse(response) { + let parsedResponse = {}; + + for (let line of response.split("\n")) { + let data = line.split("="); + + if ( + (data.length == 2 && + data[0] == "CrashID" && + SUBMISSION_REGEX.test(data[1])) || + data[0] == "ViewURL" + ) { + parsedResponse[data[0]] = data[1]; + } + } + + return parsedResponse; + }, + + submitForm: function Submitter_submitForm() { + if (!("ServerURL" in this.extraKeyVals)) { + return false; + } + let serverURL = this.extraKeyVals.ServerURL; + delete this.extraKeyVals.ServerURL; + + // Override the submission URL from the environment + let envOverride = Services.env.get("MOZ_CRASHREPORTER_URL"); + if (envOverride != "") { + serverURL = envOverride; + } + + let xhr = new XMLHttpRequest(); + xhr.open("POST", serverURL, true); + + let formData = new FormData(); + + // tell the server not to throttle this if requested + this.extraKeyVals.Throttleable = this.noThrottle ? "0" : "1"; + + // add the data + let payload = Object.assign({}, this.extraKeyVals); + let json = new Blob([JSON.stringify(payload)], { + type: "application/json", + }); + formData.append("extra", json); + + // add the minidumps + let promises = [ + File.createFromFileName(this.dump, { + type: "application/octet-stream", + }).then(file => { + formData.append("upload_file_minidump", file); + }), + ]; + + if (this.memory) { + promises.push( + File.createFromFileName(this.memory, { + type: "application/gzip", + }).then(file => { + formData.append("memory_report", file); + }) + ); + } + + if (this.additionalDumps.length) { + let names = []; + for (let i of this.additionalDumps) { + names.push(i.name); + promises.push( + File.createFromFileName(i.dump, { + type: "application/octet-stream", + }).then(file => { + formData.append("upload_file_minidump_" + i.name, file); + }) + ); + } + } + + let manager = Services.crashmanager; + let submissionID = manager.generateSubmissionID(); + + xhr.addEventListener("readystatechange", evt => { + if (xhr.readyState == 4) { + let ret = + xhr.status === 200 ? this.parseResponse(xhr.responseText) : {}; + let submitted = !!ret.CrashID; + let p = Promise.resolve(); + + if (this.recordSubmission) { + let result = submitted + ? manager.SUBMISSION_RESULT_OK + : manager.SUBMISSION_RESULT_FAILED; + p = manager.addSubmissionResult( + this.id, + submissionID, + new Date(), + result + ); + if (submitted) { + manager.setRemoteCrashID(this.id, ret.CrashID); + } + } + + p.then(() => { + if (submitted) { + this.submitSuccess(ret); + } else { + this.notifyStatus(FAILED); + this.cleanup(); + } + }); + } + }); + + let p = Promise.all(promises); + let id = this.id; + + if (this.recordSubmission) { + p = p.then(() => { + return manager.addSubmissionAttempt(id, submissionID, new Date()); + }); + } + p.then(() => { + xhr.send(formData); + }); + return true; + }, + + notifyStatus: function Submitter_notify(status, ret) { + let propBag = Cc["@mozilla.org/hash-property-bag;1"].createInstance( + Ci.nsIWritablePropertyBag2 + ); + propBag.setPropertyAsAString("minidumpID", this.id); + if (status == SUCCESS) { + propBag.setPropertyAsAString("serverCrashID", ret.CrashID); + } + + let extraKeyValsBag = Cc["@mozilla.org/hash-property-bag;1"].createInstance( + Ci.nsIWritablePropertyBag2 + ); + for (let key in this.extraKeyVals) { + extraKeyValsBag.setPropertyAsAString(key, this.extraKeyVals[key]); + } + propBag.setPropertyAsInterface("extra", extraKeyValsBag); + + Services.obs.notifyObservers(propBag, "crash-report-status", status); + + switch (status) { + case SUCCESS: + this.resolveSubmitStatusPromise(ret.CrashID); + break; + case FAILED: + this.rejectSubmitStatusPromise(FAILED); + break; + default: + // no callbacks invoked. + } + }, + + readAnnotations: async function Submitter_readAnnotations(extra) { + // These annotations are used only by the crash reporter client and should + // not be submitted to Socorro. + const strippedAnnotations = [ + "StackTraces", + "TelemetryClientId", + "TelemetrySessionId", + "TelemetryServerURL", + ]; + let extraKeyVals = await IOUtils.readJSON(extra); + + this.extraKeyVals = { ...extraKeyVals, ...this.extraKeyVals }; + strippedAnnotations.forEach(key => delete this.extraKeyVals[key]); + }, + + submit: async function Submitter_submit() { + if (this.recordSubmission) { + await Services.crashmanager.ensureCrashIsPresent(this.id); + } + + let [dump, extra, memory] = getPendingMinidump(this.id); + let [dumpExists, extraExists, memoryExists] = await Promise.all([ + IOUtils.exists(dump), + IOUtils.exists(extra), + IOUtils.exists(memory), + ]); + + if (!dumpExists || !extraExists) { + this.notifyStatus(FAILED); + this.cleanup(); + return this.submitStatusPromise; + } + + this.dump = dump; + this.extra = extra; + this.memory = memoryExists ? memory : null; + await this.readAnnotations(extra); + + let additionalDumps = []; + + if ("additional_minidumps" in this.extraKeyVals) { + let dumpsExistsPromises = []; + let names = this.extraKeyVals.additional_minidumps.split(","); + + for (let name of names) { + let [dump /* , extra, memory */] = getPendingMinidump( + this.id + "-" + name + ); + + dumpsExistsPromises.push(IOUtils.exists(dump)); + additionalDumps.push({ name, dump }); + } + + let dumpsExist = await Promise.all(dumpsExistsPromises); + let allDumpsExist = dumpsExist.every(exists => exists); + + if (!allDumpsExist) { + this.notifyStatus(FAILED); + this.cleanup(); + return this.submitStatusPromise; + } + } + + this.notifyStatus(SUBMITTING); + this.additionalDumps = additionalDumps; + + if (!(await this.submitForm())) { + this.notifyStatus(FAILED); + this.cleanup(); + } + + return this.submitStatusPromise; + }, +}; + +// =================================== +// External API goes here +export var CrashSubmit = { + // A set of strings representing how a user subnmitted a given crash + SUBMITTED_FROM_AUTO: "Auto", + SUBMITTED_FROM_INFOBAR: "Infobar", + SUBMITTED_FROM_ABOUT_CRASHES: "AboutCrashes", + SUBMITTED_FROM_CRASH_TAB: "CrashedTab", + + /** + * Submit the crash report named id.dmp from the "pending" directory. + * + * @param id + * Filename (minus .dmp extension) of the minidump to submit. + * @param submittedFrom + * One of the SUBMITTED_FROM_* constants representing how the + * user submitted this crash. + * @param params + * An object containing any of the following optional parameters: + * - recordSubmission + * If true, a submission event is recorded in CrashManager. + * - noThrottle + * If true, this crash report should be submitted with + * the Throttleable annotation set to "0" indicating that + * it should be processed right away. This should be set + * when the report is being submitted and the user expects + * to see the results immediately. Defaults to false. + * - extraExtraKeyVals + * An object whose key-value pairs will be merged with the data from + * the ".extra" file submitted with the report. The properties of + * this object will override properties of the same name in the + * .extra file. + * + * @return a Promise that is fulfilled with the server crash ID when the + * submission succeeds and rejected otherwise. + */ + submit: function CrashSubmit_submit(id, submittedFrom, params) { + params = params || {}; + let recordSubmission = false; + let noThrottle = false; + let extraExtraKeyVals = {}; + + if ("recordSubmission" in params) { + recordSubmission = params.recordSubmission; + } + + if ("noThrottle" in params) { + noThrottle = params.noThrottle; + } + + if ("extraExtraKeyVals" in params) { + extraExtraKeyVals = params.extraExtraKeyVals; + } + + extraExtraKeyVals.SubmittedFrom = submittedFrom; + + let submitter = new Submitter( + id, + recordSubmission, + noThrottle, + extraExtraKeyVals + ); + CrashSubmit._activeSubmissions.push(submitter); + return submitter.submit(); + }, + + /** + * Delete the minidup from the "pending" directory. + * + * @param id + * Filename (minus .dmp extension) of the minidump to delete. + * + * @return a Promise that is fulfilled when the minidump is deleted and + * rejected otherwise + */ + delete: async function CrashSubmit_delete(id) { + await Promise.all( + getPendingMinidump(id).map(path => { + return IOUtils.remove(path); + }) + ); + }, + + /** + * Add a .dmg.ignore file along side the .dmp file to indicate that the user + * shouldn't be prompted to submit this crash report again. + * + * @param id + * Filename (minus .dmp extension) of the report to ignore + * + * @return a Promise that is fulfilled when (if) the .dmg.ignore is created + * and rejected otherwise. + */ + ignore: async function CrashSubmit_ignore(id) { + let [dump /* , extra, memory */] = getPendingMinidump(id); + const ignorePath = `${dump}.ignore`; + await IOUtils.writeUTF8(ignorePath, "", { mode: "create" }); + }, + + /** + * Get the list of pending crash IDs, excluding those marked to be ignored + * @param minFileDate + * A Date object. Any files last modified before that date will be ignored + * + * @return a Promise that is fulfilled with an array of string, each + * being an ID as expected to be passed to submit() or ignore() + */ + pendingIDs: async function CrashSubmit_pendingIDs(minFileDate) { + let ids = []; + let pendingDir = getDir("pending"); + + if (!(await IOUtils.exists(pendingDir))) { + return ids; + } + + let children; + try { + children = await IOUtils.getChildren(pendingDir); + } catch (ex) { + console.error(ex); + throw ex; + } + + try { + const entries = Object.create(null); + const ignored = Object.create(null); + + for (const child of children) { + const info = await IOUtils.stat(child); + + if (info.type !== "directory") { + const name = PathUtils.filename(child); + const matches = name.match(/(.+)\.dmp$/); + if (matches) { + const id = matches[1]; + + if (UUID_REGEX.test(id)) { + entries[id] = info; + } + } else { + // maybe it's a .ignore file + const matchesIgnore = name.match(/(.+)\.dmp.ignore$/); + if (matchesIgnore) { + const id = matchesIgnore[1]; + + if (UUID_REGEX.test(id)) { + ignored[id] = true; + } + } + } + } + } + + for (const [id, info] of Object.entries(entries)) { + const accessDate = new Date(info.lastAccessed); + if (!(id in ignored) && accessDate > minFileDate) { + ids.push(id); + } + } + } catch (ex) { + console.error(ex); + throw ex; + } + + return ids; + }, + + /** + * Prune the saved dumps. + * + * @return a Promise that is fulfilled when the daved dumps are deleted and + * rejected otherwise + */ + pruneSavedDumps: async function CrashSubmit_pruneSavedDumps() { + const KEEP = 10; + + let dirEntries = []; + let pendingDir = getDir("pending"); + + let children; + try { + children = await IOUtils.getChildren(pendingDir); + } catch (ex) { + if (DOMException.isInstance(ex) && ex.name === "NotFoundError") { + return []; + } + + throw ex; + } + + for (const path of children) { + let infoPromise; + try { + infoPromise = IOUtils.stat(path); + } catch (ex) { + console.error(ex); + throw ex; + } + + const name = PathUtils.filename(path); + + if (name.match(/(.+)\.extra$/)) { + dirEntries.push({ + name, + path, + infoPromise, + }); + } + } + + dirEntries.sort(async (a, b) => { + let dateA = (await a.infoPromise).lastModified; + let dateB = (await b.infoPromise).lastModified; + + if (dateA < dateB) { + return -1; + } + + if (dateB < dateA) { + return 1; + } + + return 0; + }); + + if (dirEntries.length > KEEP) { + let toDelete = []; + + for (let i = 0; i < dirEntries.length - KEEP; ++i) { + let extra = dirEntries[i]; + let matches = extra.leafName.match(/(.+)\.extra$/); + + if (matches) { + let pathComponents = PathUtils.split(extra.path); + pathComponents[pathComponents.length - 1] = matches[1]; + let path = PathUtils.join(...pathComponents); + + toDelete.push(extra.path, `${path}.dmp`, `${path}.memory.json.gz`); + } + } + + await Promise.all( + toDelete.map(path => { + return IOUtils.remove(path, { ignoreAbsent: true }); + }) + ); + } + }, + + // List of currently active submit objects + _activeSubmissions: [], +}; diff --git a/toolkit/crashreporter/InjectCrashReporter.cpp b/toolkit/crashreporter/InjectCrashReporter.cpp new file mode 100644 index 0000000000..d9e6d062e5 --- /dev/null +++ b/toolkit/crashreporter/InjectCrashReporter.cpp @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InjectCrashReporter.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "windows/crash_generation/crash_generation_client.h" +#include "nsExceptionHandler.h" +#include "LoadLibraryRemote.h" +#include "nsWindowsHelpers.h" + +using CrashReporter::GetChildNotificationPipe; +using google_breakpad::CrashGenerationClient; + +namespace mozilla { + +InjectCrashRunnable::InjectCrashRunnable(DWORD pid) + : Runnable("InjectCrashRunnable"), mPID(pid) { + nsCOMPtr dll; + nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dll)); + if (NS_SUCCEEDED(rv)) { + dll->Append(u"breakpadinjector.dll"_ns); + dll->GetPath(mInjectorPath); + } +} + +NS_IMETHODIMP +InjectCrashRunnable::Run() { + if (mInjectorPath.IsEmpty()) return NS_OK; + + nsAutoHandle hProcess(OpenProcess( + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE | + PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, + FALSE, mPID)); + if (!hProcess) { + NS_WARNING( + "Unable to open remote process handle for crashreporter injection."); + return NS_OK; + } + + void* proc = + LoadRemoteLibraryAndGetAddress(hProcess, mInjectorPath.get(), "Start"); + if (!proc) { + NS_WARNING("Unable to inject crashreporter DLL."); + return NS_OK; + } + + HANDLE hRemotePipe = CrashGenerationClient::DuplicatePipeToClientProcess( + NS_ConvertASCIItoUTF16(GetChildNotificationPipe()).get(), hProcess); + if (INVALID_HANDLE_VALUE == hRemotePipe) { + NS_WARNING("Unable to duplicate crash reporter pipe to process."); + return NS_OK; + } + + nsAutoHandle hThread(CreateRemoteThread(hProcess, nullptr, 0, + (LPTHREAD_START_ROUTINE)proc, + (void*)hRemotePipe, 0, nullptr)); + if (!hThread) { + NS_WARNING("Unable to CreateRemoteThread"); + + // We have to close the remote pipe or else our crash generation client + // will be stuck unable to accept other remote requests. + HANDLE toClose = INVALID_HANDLE_VALUE; + if (DuplicateHandle(hProcess, hRemotePipe, ::GetCurrentProcess(), &toClose, + 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + CloseHandle(toClose); + return NS_OK; + } + } + + return NS_OK; +} + +} // namespace mozilla diff --git a/toolkit/crashreporter/InjectCrashReporter.h b/toolkit/crashreporter/InjectCrashReporter.h new file mode 100644 index 0000000000..a7a305f763 --- /dev/null +++ b/toolkit/crashreporter/InjectCrashReporter.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef InjectCrashReporter_h +#define InjectCrashReporter_h + +#include "nsThreadUtils.h" +#include + +namespace mozilla { + +class InjectCrashRunnable : public Runnable { + public: + explicit InjectCrashRunnable(DWORD pid); + + NS_IMETHOD Run() override; + + private: + DWORD mPID; + nsString mInjectorPath; +}; + +} // Namespace mozilla + +#endif diff --git a/toolkit/crashreporter/LoadLibraryRemote.cpp b/toolkit/crashreporter/LoadLibraryRemote.cpp new file mode 100644 index 0000000000..d0422edd08 --- /dev/null +++ b/toolkit/crashreporter/LoadLibraryRemote.cpp @@ -0,0 +1,459 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __GNUC__ +// disable warnings about pointer <-> DWORD conversions +# pragma warning(disable : 4311 4312) +#endif + +#ifdef _WIN64 +# define POINTER_TYPE ULONGLONG +#else +# define POINTER_TYPE DWORD +#endif + +#include +#include +#include +#ifdef DEBUG_OUTPUT +# include +#endif + +#include "nsWindowsHelpers.h" + +typedef const unsigned char* FileView; + +template <> +class nsAutoRefTraits { + public: + typedef FileView RawRef; + static FileView Void() { return nullptr; } + + static void Release(RawRef aView) { + if (nullptr != aView) UnmapViewOfFile(aView); + } +}; + +#ifndef IMAGE_SIZEOF_BASE_RELOCATION +// Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!? +# define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION)) +#endif + +#include "LoadLibraryRemote.h" + +typedef struct { + PIMAGE_NT_HEADERS headers; + unsigned char* localCodeBase; + unsigned char* remoteCodeBase; + HMODULE* modules; + int numModules; +} MEMORYMODULE, *PMEMORYMODULE; + +typedef BOOL(WINAPI* DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, + LPVOID lpReserved); + +#define GET_HEADER_DICTIONARY(module, idx) \ + &(module)->headers->OptionalHeader.DataDirectory[idx] + +#ifdef DEBUG_OUTPUT +static void OutputLastError(const char* msg) { + char* tmp; + char* tmpmsg; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&tmp, 0, + nullptr); + tmpmsg = (char*)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); + sprintf(tmpmsg, "%s: %s", msg, tmp); + OutputDebugStringA(tmpmsg); + LocalFree(tmpmsg); + LocalFree(tmp); +} +#endif + +static void CopySections(const unsigned char* data, + PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) { + int i; + unsigned char* codeBase = module->localCodeBase; + unsigned char* dest; + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + for (i = 0; i < module->headers->FileHeader.NumberOfSections; + i++, section++) { + dest = codeBase + section->VirtualAddress; + memset(dest, 0, section->Misc.VirtualSize); + if (section->SizeOfRawData) { + memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); + } + // section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + + // section->VirtualAddress; + } +} + +static bool CopyRegion(HANDLE hRemoteProcess, void* remoteAddress, + void* localAddress, DWORD size, DWORD protect) { + if (size > 0) { + // Copy the data from local->remote and set the memory protection + if (!VirtualAllocEx(hRemoteProcess, remoteAddress, size, MEM_COMMIT, + PAGE_READWRITE)) + return false; + + if (!WriteProcessMemory(hRemoteProcess, remoteAddress, localAddress, size, + nullptr)) { +#ifdef DEBUG_OUTPUT + OutputLastError("Error writing remote memory.\n"); +#endif + return false; + } + + DWORD oldProtect; + if (VirtualProtectEx(hRemoteProcess, remoteAddress, size, protect, + &oldProtect) == 0) { +#ifdef DEBUG_OUTPUT + OutputLastError("Error protecting memory page"); +#endif + return false; + } + } + return true; +} +// Protection flags for memory pages (Executable, Readable, Writeable) +static int ProtectionFlags[2][2][2] = { + { + // not executable + {PAGE_NOACCESS, PAGE_WRITECOPY}, + {PAGE_READONLY, PAGE_READWRITE}, + }, + { + // executable + {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, + {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, + }, +}; + +static bool FinalizeSections(PMEMORYMODULE module, HANDLE hRemoteProcess) { +#ifdef DEBUG_OUTPUT + fprintf(stderr, "Finalizing sections: local base %p, remote base %p\n", + module->localCodeBase, module->remoteCodeBase); +#endif + + int i; + int numSections = module->headers->FileHeader.NumberOfSections; + + if (numSections < 1) return false; + + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + + // Copy any data before the first section (i.e. the image header) + if (!CopyRegion(hRemoteProcess, module->remoteCodeBase, module->localCodeBase, + section->VirtualAddress, PAGE_READONLY)) + return false; + + // loop through all sections and change access flags + for (i = 0; i < numSections; i++, section++) { + DWORD protect, size; + int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; + int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; + int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; + + // determine protection flags based on characteristics + protect = ProtectionFlags[executable][readable][writeable]; + if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) { + protect |= PAGE_NOCACHE; + } + + void* remoteAddress = module->remoteCodeBase + section->VirtualAddress; + void* localAddress = module->localCodeBase + section->VirtualAddress; + + // determine size of region + size = section->Misc.VirtualSize; +#ifdef DEBUG_OUTPUT + fprintf(stderr, + "Copying section %s to %p, size %x, executable %i readable %i " + "writeable %i\n", + section->Name, remoteAddress, size, executable, readable, + writeable); +#endif + if (!CopyRegion(hRemoteProcess, remoteAddress, localAddress, size, protect)) + return false; + } + return true; +} + +static void PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta) { + DWORD i; + unsigned char* codeBase = module->localCodeBase; + + PIMAGE_DATA_DIRECTORY directory = + GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); + if (directory->Size > 0) { + PIMAGE_BASE_RELOCATION relocation = + (PIMAGE_BASE_RELOCATION)(codeBase + directory->VirtualAddress); + for (; relocation->VirtualAddress > 0;) { + unsigned char* dest = codeBase + relocation->VirtualAddress; + unsigned short* relInfo = (unsigned short*)((unsigned char*)relocation + + IMAGE_SIZEOF_BASE_RELOCATION); + for (i = 0; + i < ((relocation->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2); + i++, relInfo++) { + DWORD* patchAddrHL; +#ifdef _WIN64 + ULONGLONG* patchAddr64; +#endif + int type, offset; + + // the upper 4 bits define the type of relocation + type = *relInfo >> 12; + // the lower 12 bits define the offset + offset = *relInfo & 0xfff; + + switch (type) { + case IMAGE_REL_BASED_ABSOLUTE: + // skip relocation + break; + + case IMAGE_REL_BASED_HIGHLOW: + // change complete 32 bit address + patchAddrHL = (DWORD*)(dest + offset); + *patchAddrHL += delta; + break; + +#ifdef _WIN64 + case IMAGE_REL_BASED_DIR64: + patchAddr64 = (ULONGLONG*)(dest + offset); + *patchAddr64 += delta; + break; +#endif + + default: + // printf("Unknown relocation: %d\n", type); + break; + } + } + + // advance to next relocation block + relocation = (PIMAGE_BASE_RELOCATION)(((char*)relocation) + + relocation->SizeOfBlock); + } + } +} + +static int BuildImportTable(PMEMORYMODULE module) { + int result = 1; + unsigned char* codeBase = module->localCodeBase; + + PIMAGE_DATA_DIRECTORY directory = + GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); + if (directory->Size > 0) { + PIMAGE_IMPORT_DESCRIPTOR importDesc = + (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress); + PIMAGE_IMPORT_DESCRIPTOR importEnd = + (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress + + directory->Size); + + for (; importDesc < importEnd && importDesc->Name; importDesc++) { + POINTER_TYPE* thunkRef; + FARPROC* funcRef; + HMODULE handle = GetModuleHandleA((LPCSTR)(codeBase + importDesc->Name)); + if (handle == nullptr) { +#if DEBUG_OUTPUT + OutputLastError("Can't load library"); +#endif + result = 0; + break; + } + + module->modules = (HMODULE*)realloc( + module->modules, (module->numModules + 1) * (sizeof(HMODULE))); + if (module->modules == nullptr) { + result = 0; + break; + } + + module->modules[module->numModules++] = handle; + if (importDesc->OriginalFirstThunk) { + thunkRef = (POINTER_TYPE*)(codeBase + importDesc->OriginalFirstThunk); + funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk); + } else { + // no hint table + thunkRef = (POINTER_TYPE*)(codeBase + importDesc->FirstThunk); + funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk); + } + for (; *thunkRef; thunkRef++, funcRef++) { + if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { + *funcRef = + (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); + } else { + PIMAGE_IMPORT_BY_NAME thunkData = + (PIMAGE_IMPORT_BY_NAME)(codeBase + (*thunkRef)); + *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name); + } + if (*funcRef == 0) { + result = 0; + break; + } + } + + if (!result) { + break; + } + } + } + + return result; +} + +static void* MemoryGetProcAddress(PMEMORYMODULE module, const char* name); + +void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess, + const WCHAR* library, const char* symbol) { + // Map the DLL into memory + nsAutoHandle hLibrary(CreateFile(library, GENERIC_READ, FILE_SHARE_READ, + nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr)); + if (INVALID_HANDLE_VALUE == hLibrary) { +#if DEBUG_OUTPUT + OutputLastError("Couldn't CreateFile the library.\n"); +#endif + return nullptr; + } + + nsAutoHandle hMapping( + CreateFileMapping(hLibrary, nullptr, PAGE_READONLY, 0, 0, nullptr)); + if (!hMapping) { +#if DEBUG_OUTPUT + OutputLastError("Couldn't CreateFileMapping.\n"); +#endif + return nullptr; + } + + nsAutoRef data( + (const unsigned char*)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)); + if (!data) { +#if DEBUG_OUTPUT + OutputLastError("Couldn't MapViewOfFile.\n"); +#endif + return nullptr; + } + + SIZE_T locationDelta; + + PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)data.get(); + if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { +#if DEBUG_OUTPUT + OutputDebugStringA("Not a valid executable file.\n"); +#endif + return nullptr; + } + + PIMAGE_NT_HEADERS old_header = + (PIMAGE_NT_HEADERS)(data + dos_header->e_lfanew); + if (old_header->Signature != IMAGE_NT_SIGNATURE) { +#if DEBUG_OUTPUT + OutputDebugStringA("No PE header found.\n"); +#endif + return nullptr; + } + + // reserve memory for image of library in this process and the target process + unsigned char* localCode = (unsigned char*)VirtualAlloc( + nullptr, old_header->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if (!localCode) { +#if DEBUG_OUTPUT + OutputLastError("Can't reserve local memory."); +#endif + } + + unsigned char* remoteCode = (unsigned char*)VirtualAllocEx( + hRemoteProcess, nullptr, old_header->OptionalHeader.SizeOfImage, + MEM_RESERVE, PAGE_EXECUTE_READ); + if (!remoteCode) { +#if DEBUG_OUTPUT + OutputLastError("Can't reserve remote memory."); +#endif + } + + MEMORYMODULE result; + result.localCodeBase = localCode; + result.remoteCodeBase = remoteCode; + result.numModules = 0; + result.modules = nullptr; + + // copy PE header to code + memcpy(localCode, dos_header, + dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); + result.headers = + reinterpret_cast(localCode + dos_header->e_lfanew); + + // update position + result.headers->OptionalHeader.ImageBase = (POINTER_TYPE)remoteCode; + + // copy sections from DLL file block to new memory location + CopySections(data, old_header, &result); + + // adjust base address of imported data + locationDelta = (SIZE_T)(remoteCode - old_header->OptionalHeader.ImageBase); + if (locationDelta != 0) { + PerformBaseRelocation(&result, locationDelta); + } + + // load required dlls and adjust function table of imports + if (!BuildImportTable(&result)) { + return nullptr; + } + + // mark memory pages depending on section headers and release + // sections that are marked as "discardable" + if (!FinalizeSections(&result, hRemoteProcess)) { + return nullptr; + } + + return MemoryGetProcAddress(&result, symbol); +} + +static void* MemoryGetProcAddress(PMEMORYMODULE module, const char* name) { + unsigned char* localCodeBase = module->localCodeBase; + int idx = -1; + DWORD i, *nameRef; + WORD* ordinal; + PIMAGE_EXPORT_DIRECTORY exports; + PIMAGE_DATA_DIRECTORY directory = + GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT); + if (directory->Size == 0) { + // no export table found + return nullptr; + } + + exports = + (PIMAGE_EXPORT_DIRECTORY)(localCodeBase + directory->VirtualAddress); + if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { + // DLL doesn't export anything + return nullptr; + } + + // search function name in list of exported names + nameRef = (DWORD*)(localCodeBase + exports->AddressOfNames); + ordinal = (WORD*)(localCodeBase + exports->AddressOfNameOrdinals); + for (i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++) { + if (stricmp(name, (const char*)(localCodeBase + (*nameRef))) == 0) { + idx = *ordinal; + break; + } + } + + if (idx == -1) { + // exported symbol not found + return nullptr; + } + + if ((DWORD)idx > exports->NumberOfFunctions) { + // name <-> ordinal number don't match + return nullptr; + } + + // AddressOfFunctions contains the RVAs to the "real" functions + return module->remoteCodeBase + + (*(DWORD*)(localCodeBase + exports->AddressOfFunctions + (idx * 4))); +} diff --git a/toolkit/crashreporter/LoadLibraryRemote.h b/toolkit/crashreporter/LoadLibraryRemote.h new file mode 100644 index 0000000000..4aa5d2df19 --- /dev/null +++ b/toolkit/crashreporter/LoadLibraryRemote.h @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef LoadLibraryRemote_h +#define LoadLibraryRemote_h + +#include + +/** + * Inject a library into a remote process. This injection has the following + * restrictions: + * + * - The DLL being injected must only depend on kernel32 and user32. + * - The entry point of the DLL is not run. If the DLL uses the CRT, it is + * the responsibility of the caller to make sure that _CRT_INIT is called. + * - There is no support for unloading a library once it has been loaded. + * - The symbol must be a named symbol and not an ordinal. + */ +void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess, + const WCHAR* library, const char* symbol); + +#endif // LoadLibraryRemote_h diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h new file mode 100644 index 0000000000..3de2606b7b --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h @@ -0,0 +1,68 @@ +// Copyright (c) 2010 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_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ +#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ + +namespace google_breakpad { + +class CrashGenerationServer; + +class ClientInfo { + public: + ClientInfo(pid_t pid, CrashGenerationServer* crash_server) + : crash_server_(crash_server), + pid_(pid) {} + + CrashGenerationServer* crash_server() const { return crash_server_; } + pid_t pid() const { return pid_; } + void set_error_msg(nsCString &error_msg) { + had_error_ = true; + error_msg_ = error_msg; + } + + const nsCString* error_msg() const { + return &error_msg_; + } + + bool had_error() const { + return had_error_; + } + + private: + CrashGenerationServer* crash_server_; + pid_t pid_; + bool had_error_ = false; + nsCString error_msg_; // Possible error message of the minidumper in + // case there was an error during dumping +}; + +} + +#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc new file mode 100644 index 0000000000..02dc66f355 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2010 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 "linux/crash_generation/crash_generation_client.h" + +#include +#include +#include + +#include + +#include "common/linux/eintr_wrapper.h" +#include "common/linux/ignore_ret.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +namespace { + +class CrashGenerationClientImpl : public CrashGenerationClient { + public: + explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} + virtual ~CrashGenerationClientImpl() {} + + virtual bool RequestDump(const void* blob, size_t blob_size) { + int fds[2]; + if (sys_pipe(fds) < 0) + return false; + static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int)); + + struct kernel_iovec iov; + iov.iov_base = const_cast(blob); + iov.iov_len = blob_size; + + struct kernel_msghdr msg = { 0 }; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + char cmsg[kControlMsgSize] = ""; + msg.msg_control = cmsg; + msg.msg_controllen = sizeof(cmsg); + + struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); + hdr->cmsg_level = SOL_SOCKET; + hdr->cmsg_type = SCM_RIGHTS; + hdr->cmsg_len = CMSG_LEN(sizeof(int)); + int* p = reinterpret_cast(CMSG_DATA(hdr)); + *p = fds[1]; + + ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)); + sys_close(fds[1]); + if (ret < 0) { + sys_close(fds[0]); + return false; + } + + // Wait for an ACK from the server. + char b; + IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); + sys_close(fds[0]); + + return true; + } + + private: + int server_fd_; + + DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl); +}; + +} // namespace + +// static +CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) { + if (server_fd < 0) + return NULL; + return new CrashGenerationClientImpl(server_fd); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h new file mode 100644 index 0000000000..4e68424ae8 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h @@ -0,0 +1,65 @@ +// Copyright (c) 2010 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_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ +#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ + +#include "common/basictypes.h" + +#include + +namespace google_breakpad { + +// CrashGenerationClient is an interface for implementing out-of-process crash +// dumping. The default implementation, accessed via the TryCreate() factory, +// works in conjunction with the CrashGenerationServer to generate a minidump +// via a remote process. +class CrashGenerationClient { + public: + CrashGenerationClient() {} + virtual ~CrashGenerationClient() {} + + // Request the crash server to generate a dump. |blob| is an opaque + // CrashContext pointer from exception_handler.h. + // Returns true if the dump was successful; false otherwise. + virtual bool RequestDump(const void* blob, size_t blob_size) = 0; + + // Returns a new CrashGenerationClient if |server_fd| is valid and + // connects to a CrashGenerationServer. Otherwise, return NULL. + // The returned CrashGenerationClient* is owned by the caller of + // this function. + static CrashGenerationClient* TryCreate(int server_fd); + + private: + DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc new file mode 100644 index 0000000000..58baa31d10 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc @@ -0,0 +1,383 @@ +// Copyright (c) 2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nsThreadUtils.h" + +#include "linux/crash_generation/crash_generation_server.h" +#include "linux/crash_generation/client_info.h" +#include "linux/handler/exception_handler.h" +#include "linux/handler/guid_generator.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/safe_readlink.h" + +#if defined(MOZ_OXIDIZED_BREAKPAD) +# include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h" +# include +# include "nsString.h" +#endif + +static const char kCommandQuit = 'x'; + +namespace google_breakpad { + +CrashGenerationServer::CrashGenerationServer( + const int listen_fd, + OnClientDumpRequestCallback dump_callback, + void* dump_context, + OnClientExitingCallback exit_callback, + void* exit_context, + bool generate_dumps, + const string* dump_path) : + server_fd_(listen_fd), + dump_callback_(dump_callback), + dump_context_(dump_context), + exit_callback_(exit_callback), + exit_context_(exit_context), + generate_dumps_(generate_dumps), + started_(false) +{ + if (dump_path) + dump_dir_ = *dump_path; + else + dump_dir_ = "/tmp"; +} + +CrashGenerationServer::~CrashGenerationServer() +{ + if (started_) + Stop(); +} + +bool +CrashGenerationServer::Start() +{ + if (started_ || 0 > server_fd_) + return false; + + int control_pipe[2]; + if (pipe(control_pipe)) + return false; + + if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC)) + return false; + if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC)) + return false; + + if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK)) + return false; + + control_pipe_in_ = control_pipe[0]; + control_pipe_out_ = control_pipe[1]; + + if (pthread_create(&thread_, NULL, + ThreadMain, reinterpret_cast(this))) + return false; + + started_ = true; + return true; +} + +void +CrashGenerationServer::Stop() +{ + assert(pthread_self() != thread_); + + if (!started_) + return; + + HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1)); + + void* dummy; + pthread_join(thread_, &dummy); + + close(control_pipe_in_); + close(control_pipe_out_); + + started_ = false; +} + +//static +bool +CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd) +{ + int fds[2]; + + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)) + return false; + + static const int on = 1; + // Enable passcred on the server end of the socket + if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) + return false; + + if (fcntl(fds[1], F_SETFL, O_NONBLOCK)) + return false; + if (fcntl(fds[1], F_SETFD, FD_CLOEXEC)) + return false; + + *client_fd = fds[0]; + *server_fd = fds[1]; + return true; +} + +// The following methods/functions execute on the server thread + +void +CrashGenerationServer::Run() +{ + struct pollfd pollfds[2]; + memset(&pollfds, 0, sizeof(pollfds)); + + pollfds[0].fd = server_fd_; + pollfds[0].events = POLLIN; + + pollfds[1].fd = control_pipe_in_; + pollfds[1].events = POLLIN; + + while (true) { + // infinite timeout + int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); + if (-1 == nevents) { + if (EINTR == errno) { + continue; + } else { + return; + } + } + + if (pollfds[0].revents && !ClientEvent(pollfds[0].revents)) + return; + + if (pollfds[1].revents && !ControlEvent(pollfds[1].revents)) + return; + } +} + +bool +CrashGenerationServer::ClientEvent(short revents) +{ + if (POLLHUP & revents) + return false; + assert(POLLIN & revents); + + // A process has crashed and has signaled us by writing a datagram + // to the death signal socket. The datagram contains the crash context needed + // for writing the minidump as well as a file descriptor and a credentials + // block so that they can't lie about their pid. + + // The length of the control message: + static const unsigned kControlMsgSize = + CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); + // The length of the regular payload: + static const unsigned kCrashContextSize = + sizeof(google_breakpad::ExceptionHandler::CrashContext); + + struct msghdr msg = {0}; + struct iovec iov[1]; + char crash_context[kCrashContextSize]; + char control[kControlMsgSize]; + const ssize_t expected_msg_size = sizeof(crash_context); + + iov[0].iov_base = crash_context; + iov[0].iov_len = sizeof(crash_context); + msg.msg_iov = iov; + msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]); + msg.msg_control = control; + msg.msg_controllen = kControlMsgSize; + + const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0)); + if (msg_size != expected_msg_size) + return true; + + if (msg.msg_controllen != kControlMsgSize || + msg.msg_flags & ~MSG_TRUNC) + return true; + + // Walk the control payload and extract the file descriptor and validated pid. + pid_t crashing_pid = -1; + int signal_fd = -1; + for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; + hdr = CMSG_NXTHDR(&msg, hdr)) { + if (hdr->cmsg_level != SOL_SOCKET) + continue; + if (hdr->cmsg_type == SCM_RIGHTS) { + const unsigned len = hdr->cmsg_len - + (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); + assert(len % sizeof(int) == 0u); + const unsigned num_fds = len / sizeof(int); + if (num_fds > 1 || num_fds == 0) { + // A nasty process could try and send us too many descriptors and + // force a leak. + for (unsigned i = 0; i < num_fds; ++i) + close(reinterpret_cast(CMSG_DATA(hdr))[i]); + return true; + } else { + signal_fd = reinterpret_cast(CMSG_DATA(hdr))[0]; + } + } else if (hdr->cmsg_type == SCM_CREDENTIALS) { + const struct ucred *cred = + reinterpret_cast(CMSG_DATA(hdr)); + crashing_pid = cred->pid; + } + } + + if (crashing_pid == -1 || signal_fd == -1) { + if (signal_fd != -1) + close(signal_fd); + return true; + } + + string minidump_filename; + if (!MakeMinidumpFilename(minidump_filename)) + return true; + +#if defined(MOZ_OXIDIZED_BREAKPAD) + ExceptionHandler::CrashContext* breakpad_cc = + reinterpret_cast(crash_context); + nsCString error_msg; + siginfo_t& si = breakpad_cc->siginfo; + signalfd_siginfo signalfd_si = {}; + signalfd_si.ssi_signo = si.si_signo; + signalfd_si.ssi_errno = si.si_errno; + signalfd_si.ssi_code = si.si_code; + + switch (si.si_signo) { + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + case SIGSYS: + signalfd_si.ssi_addr = reinterpret_cast(si.si_addr); + break; + } + + // Ignoring the return-value here for now. + // The function always creates an empty minidump file even in case of an + // error. So we'll report that as well via the callback-functions. + bool res = write_minidump_linux_with_context( + minidump_filename.c_str(), crashing_pid, &breakpad_cc->context, +# ifndef __arm__ + reinterpret_cast(&breakpad_cc->float_state), +# else + nullptr, +# endif // __arm__ + &signalfd_si, breakpad_cc->tid, &error_msg); +#else + if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), + crashing_pid, crash_context, + kCrashContextSize)) { + close(signal_fd); + return true; + } +#endif + + ClientInfo info(crashing_pid, this); +#if defined(MOZ_OXIDIZED_BREAKPAD) + if (!res) { + info.set_error_msg(error_msg); + } +#endif + if (dump_callback_) { + dump_callback_(dump_context_, info, minidump_filename); + } + + // Send the done signal to the process: it can exit now. + // (Closing this will make the child's sys_read unblock and return 0.) + close(signal_fd); + + if (exit_callback_) { + exit_callback_(exit_context_, info); + } + + return true; +} + +bool +CrashGenerationServer::ControlEvent(short revents) +{ + if (POLLHUP & revents) + return false; + assert(POLLIN & revents); + + char command; + if (read(control_pipe_in_, &command, 1)) + return false; + + switch (command) { + case kCommandQuit: + return false; + default: + assert(0); + } + + return true; +} + +bool +CrashGenerationServer::MakeMinidumpFilename(string& outFilename) +{ + GUID guid; + char guidString[kGUIDStringLength+1]; + + if (!(CreateGUID(&guid) + && GUIDToString(&guid, guidString, sizeof(guidString)))) + return false; + + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString); + + outFilename = path; + return true; +} + +// static +void* +CrashGenerationServer::ThreadMain(void *arg) +{ + NS_SetCurrentThreadName("Breakpad Server"); + reinterpret_cast(arg)->Run(); + return NULL; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h new file mode 100644 index 0000000000..83b626ab1e --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h @@ -0,0 +1,135 @@ +// Copyright (c) 2010 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_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ +#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ + +#include + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +class ClientInfo; + +class CrashGenerationServer { +public: + // WARNING: callbacks may be invoked on a different thread + // than that which creates the CrashGenerationServer. They must + // be thread safe. + typedef void (*OnClientDumpRequestCallback)(void* context, + const ClientInfo& client_info, + const string& file_path); + + typedef void (*OnClientExitingCallback)(void* context, + const ClientInfo& client_info); + + // Create an instance with the given parameters. + // + // Parameter listen_fd: The server fd created by CreateReportChannel(). + // Parameter dump_callback: Callback for a client crash dump request. + // Parameter dump_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 int listen_fd, + OnClientDumpRequestCallback dump_callback, + void* dump_context, + OnClientExitingCallback exit_callback, + void* exit_context, + bool generate_dumps, + const string* dump_path); + + ~CrashGenerationServer(); + + // Perform initialization steps needed to start listening to clients. + // + // Return true if initialization is successful; false otherwise. + bool Start(); + + // Stop the server. + void Stop(); + + // Create a "channel" that can be used by clients to report crashes + // to a CrashGenerationServer. |*server_fd| should be passed to + // this class's constructor, and |*client_fd| should be passed to + // the ExceptionHandler constructor in the client process. + static bool CreateReportChannel(int* server_fd, int* client_fd); + +private: + // Run the server's event loop + void Run(); + + // Invoked when an child process (client) event occurs + // Returning true => "keep running", false => "exit loop" + bool ClientEvent(short revents); + + // Invoked when the controlling thread (main) event occurs + // Returning true => "keep running", false => "exit loop" + bool ControlEvent(short revents); + + // Return a unique filename at which a minidump can be written + bool MakeMinidumpFilename(string& outFilename); + + // Trampoline to |Run()| + static void* ThreadMain(void* arg); + + int server_fd_; + + OnClientDumpRequestCallback dump_callback_; + void* dump_context_; + + OnClientExitingCallback exit_callback_; + void* exit_context_; + + bool generate_dumps_; + + string dump_dir_; + + bool started_; + + pthread_t thread_; + int control_pipe_in_; + int control_pipe_out_; + + // disable these + CrashGenerationServer(const CrashGenerationServer&); + CrashGenerationServer& operator=(const CrashGenerationServer&); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-amd.sym b/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-amd.sym new file mode 100644 index 0000000000..e042a5ec42 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-amd.sym @@ -0,0 +1,3 @@ +MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so +PUBLIC 400 0 __kernel_vsyscall +STACK WIN 4 400 100 1 1 0 0 0 0 0 1 diff --git a/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-intel.sym b/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-intel.sym new file mode 100644 index 0000000000..c20facaf08 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/data/linux-gate-intel.sym @@ -0,0 +1,3 @@ +MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so +PUBLIC 400 0 __kernel_vsyscall +STACK WIN 4 400 200 3 3 0 0 0 0 0 1 diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/mapping_info.h b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/mapping_info.h new file mode 100644 index 0000000000..c358539f58 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/mapping_info.h @@ -0,0 +1,75 @@ +// Copyright (c) 2014, 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_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ + +#include +#include +#include +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// One of these is produced for each mapping in the process (i.e. line in +// /proc/$x/maps). +struct MappingInfo { + // On Android, relocation packing can mean that the reported start + // address of the mapping must be adjusted by a bias in order to + // compensate for the compression of the relocation section. The + // following two members hold (after LateInit) the adjusted mapping + // range. See crbug.com/606972 for more information. + uintptr_t start_addr; + size_t size; + // When Android relocation packing causes |start_addr| and |size| to + // be modified with a load bias, we need to remember the unbiased + // address range. The following structure holds the original mapping + // address range as reported by the operating system. + struct { + uintptr_t start_addr; + uintptr_t end_addr; + } system_mapping_info; + size_t offset; // offset into the backed file. + bool exec; // true if the mapping has the execute bit set. + char name[NAME_MAX]; +}; + +struct MappingEntry { + MappingInfo first; + std::vector second; +}; + +// A list of +typedef std::list MappingList; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/raw_context_cpu.h b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/raw_context_cpu.h new file mode 100644 index 0000000000..07d9171a0a --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/raw_context_cpu.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014, 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_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386__) +typedef MDRawContextX86 RawContextCPU; +#elif defined(__x86_64) +typedef MDRawContextAMD64 RawContextCPU; +#elif defined(__ARM_EABI__) +typedef MDRawContextARM RawContextCPU; +#elif defined(__aarch64__) +typedef MDRawContextARM64_Old RawContextCPU; +#elif defined(__mips__) +typedef MDRawContextMIPS RawContextCPU; +#else +#error "This code has not been ported to your platform yet." +#endif + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.cc b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.cc new file mode 100644 index 0000000000..5d9708c70c --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.cc @@ -0,0 +1,305 @@ +// Copyright (c) 2014, 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 "linux/dump_writer_common/thread_info.h" + +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace { + +#if defined(__i386__) +// Write a uint16_t to memory +// out: memory location to write to +// v: value to write. +void U16(void* out, uint16_t v) { + my_memcpy(out, &v, sizeof(v)); +} + +// Write a uint32_t to memory +// out: memory location to write to +// v: value to write. +void U32(void* out, uint32_t v) { + my_memcpy(out, &v, sizeof(v)); +} +#endif + +} + +namespace google_breakpad { + +#if defined(__i386__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.eip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_X86_ALL; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->gs = regs.xgs; + out->fs = regs.xfs; + out->es = regs.xes; + out->ds = regs.xds; + + out->edi = regs.edi; + out->esi = regs.esi; + out->ebx = regs.ebx; + out->edx = regs.edx; + out->ecx = regs.ecx; + out->eax = regs.eax; + + out->ebp = regs.ebp; + out->eip = regs.eip; + out->cs = regs.xcs; + out->eflags = regs.eflags; + out->esp = regs.esp; + out->ss = regs.xss; + + out->float_save.control_word = fpregs.cwd; + out->float_save.status_word = fpregs.swd; + out->float_save.tag_word = fpregs.twd; + out->float_save.error_offset = fpregs.fip; + out->float_save.error_selector = fpregs.fcs; + out->float_save.data_offset = fpregs.foo; + out->float_save.data_selector = fpregs.fos; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); + + // This matches the Intel fpsave format. + U16(out->extended_registers + 0, fpregs.cwd); + U16(out->extended_registers + 2, fpregs.swd); + U16(out->extended_registers + 4, fpregs.twd); + U16(out->extended_registers + 6, fpxregs.fop); + U32(out->extended_registers + 8, fpxregs.fip); + U16(out->extended_registers + 12, fpxregs.fcs); + U32(out->extended_registers + 16, fpregs.foo); + U16(out->extended_registers + 20, fpregs.fos); + U32(out->extended_registers + 24, fpxregs.mxcsr); + + my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); + my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); +} + +#elif defined(__x86_64) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.rip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_AMD64_FULL | + MD_CONTEXT_AMD64_SEGMENTS; + + out->cs = regs.cs; + + out->ds = regs.ds; + out->es = regs.es; + out->fs = regs.fs; + out->gs = regs.gs; + + out->ss = regs.ss; + out->eflags = regs.eflags; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->rax = regs.rax; + out->rcx = regs.rcx; + out->rdx = regs.rdx; + out->rbx = regs.rbx; + + out->rsp = regs.rsp; + + out->rbp = regs.rbp; + out->rsi = regs.rsi; + out->rdi = regs.rdi; + out->r8 = regs.r8; + out->r9 = regs.r9; + out->r10 = regs.r10; + out->r11 = regs.r11; + out->r12 = regs.r12; + out->r13 = regs.r13; + out->r14 = regs.r14; + out->r15 = regs.r15; + + out->rip = regs.rip; + + out->flt_save.control_word = fpregs.cwd; + out->flt_save.status_word = fpregs.swd; + out->flt_save.tag_word = fpregs.ftw; + out->flt_save.error_opcode = fpregs.fop; + out->flt_save.error_offset = fpregs.rip; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_offset = fpregs.rdp; + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs.mxcsr; + out->flt_save.mx_csr_mask = fpregs.mxcr_mask; + + my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.uregs[15]; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM_FULL; + + for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) + out->iregs[i] = regs.uregs[i]; + // No CPSR register in ThreadInfo(it's not accessible via ptrace) + out->cpsr = 0; +#if !defined(__ANDROID__) + out->float_save.fpscr = fpregs.fpsr | + (static_cast(fpregs.fpcr) << 32); + // TODO: sort this out, actually collect floating point registers + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +#endif +} + +#elif defined(__aarch64__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.pc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; + + out->cpsr = static_cast(regs.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = regs.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc; + + out->float_save.fpsr = fpregs.fpsr; + out->float_save.fpcr = fpregs.fpcr; + my_memcpy(&out->float_save.regs, &fpregs.vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return mcontext.pc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { +#if _MIPS_SIM == _ABI64 + out->context_flags = MD_CONTEXT_MIPS64_FULL; +#elif _MIPS_SIM == _ABIO32 + out->context_flags = MD_CONTEXT_MIPS_FULL; +#else +# error "This mips ABI is currently not supported (n32)" +#endif + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = mcontext.gregs[i]; + + out->mdhi = mcontext.mdhi; + out->mdlo = mcontext.mdlo; + out->dsp_control = mcontext.dsp; + + out->hi[0] = mcontext.hi1; + out->lo[0] = mcontext.lo1; + out->hi[1] = mcontext.hi2; + out->lo[1] = mcontext.lo2; + out->hi[2] = mcontext.hi3; + out->lo[2] = mcontext.lo3; + + out->epc = mcontext.pc; + out->badvaddr = 0; // Not stored in mcontext + out->status = 0; // Not stored in mcontext + out->cause = 0; // Not stored in mcontext + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs; + + out->float_save.fpcsr = mcontext.fpc_csr; +#if _MIPS_SIM == _ABIO32 + out->float_save.fir = mcontext.fpc_eir; +#endif +} +#endif // __mips__ + +void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { + assert(gp_regs || size); +#if defined(__mips__) + if (gp_regs) + *gp_regs = mcontext.gregs; + if (size) + *size = sizeof(mcontext.gregs); +#else + if (gp_regs) + *gp_regs = ®s; + if (size) + *size = sizeof(regs); +#endif +} + +void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) { + assert(fp_regs || size); +#if defined(__mips__) + if (fp_regs) + *fp_regs = &mcontext.fpregs; + if (size) + *size = sizeof(mcontext.fpregs); +#else + if (fp_regs) + *fp_regs = &fpregs; + if (size) + *size = sizeof(fpregs); +#endif +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.h b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.h new file mode 100644 index 0000000000..4173d239c4 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/thread_info.h @@ -0,0 +1,91 @@ +// Copyright (c) 2014, 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_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ + +#include +#include + +#include "linux/dump_writer_common/raw_context_cpu.h" +#include "common/memory_allocator.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386) || defined(__x86_64) +typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t; +#endif + +// We produce one of these structures for each thread in the crashed process. +struct ThreadInfo { + pid_t tgid; // thread group id + pid_t ppid; // parent process + + uintptr_t stack_pointer; // thread stack pointer + + +#if defined(__i386) || defined(__x86_64) + user_regs_struct regs; + user_fpregs_struct fpregs; + static const unsigned kNumDebugRegisters = 8; + debugreg_t dregs[8]; +#if defined(__i386) + user_fpxregs_struct fpxregs; +#endif // defined(__i386) + +#elif defined(__ARM_EABI__) + // Mimicking how strace does this(see syscall.c, search for GETREGS) + struct user_regs regs; + struct user_fpregs fpregs; +#elif defined(__aarch64__) + // Use the structures defined in + struct user_regs_struct regs; + struct user_fpsimd_struct fpregs; +#elif defined(__mips__) + // Use the structure defined in . + mcontext_t mcontext; +#endif + + // Returns the instruction pointer (platform-dependent impl.). + uintptr_t GetInstructionPointer() const; + + // Fills a RawContextCPU using the context in the ThreadInfo object. + void FillCPUContext(RawContextCPU* out) const; + + // Returns the pointer and size of general purpose register area. + void GetGeneralPurposeRegisters(void** gp_regs, size_t* size); + + // Returns the pointer and size of float point register area. + void GetFloatingPointRegisters(void** fp_regs, size_t* size); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.cc b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.cc new file mode 100644 index 0000000000..5145ede3d8 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2014, 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 "linux/dump_writer_common/ucontext_reader.h" + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Minidump defines register structures which are different from the raw +// structures which we get from the kernel. These are platform specific +// functions to juggle the ucontext_t and user structures into minidump format. + +#if defined(__i386__) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.gregs[REG_ESP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.gregs[REG_EIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + const fpstate_t* fp) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_X86_FULL | + MD_CONTEXT_X86_FLOATING_POINT; + + out->gs = regs[REG_GS]; + out->fs = regs[REG_FS]; + out->es = regs[REG_ES]; + out->ds = regs[REG_DS]; + + out->edi = regs[REG_EDI]; + out->esi = regs[REG_ESI]; + out->ebx = regs[REG_EBX]; + out->edx = regs[REG_EDX]; + out->ecx = regs[REG_ECX]; + out->eax = regs[REG_EAX]; + + out->ebp = regs[REG_EBP]; + out->eip = regs[REG_EIP]; + out->cs = regs[REG_CS]; + out->eflags = regs[REG_EFL]; + out->esp = regs[REG_UESP]; + out->ss = regs[REG_SS]; + + out->float_save.control_word = fp->cw; + out->float_save.status_word = fp->sw; + out->float_save.tag_word = fp->tag; + out->float_save.error_offset = fp->ipoff; + out->float_save.error_selector = fp->cssel; + out->float_save.data_offset = fp->dataoff; + out->float_save.data_selector = fp->datasel; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); +} + +#elif defined(__x86_64) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.gregs[REG_RSP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.gregs[REG_RIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + const fpstate_t* fpregs) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_AMD64_FULL; + + out->cs = regs[REG_CSGSFS] & 0xffff; + + out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; + out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; + + out->eflags = regs[REG_EFL]; + + out->rax = regs[REG_RAX]; + out->rcx = regs[REG_RCX]; + out->rdx = regs[REG_RDX]; + out->rbx = regs[REG_RBX]; + + out->rsp = regs[REG_RSP]; + out->rbp = regs[REG_RBP]; + out->rsi = regs[REG_RSI]; + out->rdi = regs[REG_RDI]; + out->r8 = regs[REG_R8]; + out->r9 = regs[REG_R9]; + out->r10 = regs[REG_R10]; + out->r11 = regs[REG_R11]; + out->r12 = regs[REG_R12]; + out->r13 = regs[REG_R13]; + out->r14 = regs[REG_R14]; + out->r15 = regs[REG_R15]; + + out->rip = regs[REG_RIP]; + + out->flt_save.control_word = fpregs->cwd; + out->flt_save.status_word = fpregs->swd; + out->flt_save.tag_word = fpregs->ftw; + out->flt_save.error_opcode = fpregs->fop; + out->flt_save.error_offset = fpregs->rip; + out->flt_save.data_offset = fpregs->rdp; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs->mxcsr; + out->flt_save.mx_csr_mask = fpregs->mxcr_mask; + my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.arm_sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.arm_pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) { + out->context_flags = MD_CONTEXT_ARM_FULL; + + out->iregs[0] = uc->uc_mcontext.arm_r0; + out->iregs[1] = uc->uc_mcontext.arm_r1; + out->iregs[2] = uc->uc_mcontext.arm_r2; + out->iregs[3] = uc->uc_mcontext.arm_r3; + out->iregs[4] = uc->uc_mcontext.arm_r4; + out->iregs[5] = uc->uc_mcontext.arm_r5; + out->iregs[6] = uc->uc_mcontext.arm_r6; + out->iregs[7] = uc->uc_mcontext.arm_r7; + out->iregs[8] = uc->uc_mcontext.arm_r8; + out->iregs[9] = uc->uc_mcontext.arm_r9; + out->iregs[10] = uc->uc_mcontext.arm_r10; + + out->iregs[11] = uc->uc_mcontext.arm_fp; + out->iregs[12] = uc->uc_mcontext.arm_ip; + out->iregs[13] = uc->uc_mcontext.arm_sp; + out->iregs[14] = uc->uc_mcontext.arm_lr; + out->iregs[15] = uc->uc_mcontext.arm_pc; + + out->cpsr = uc->uc_mcontext.arm_cpsr; + + // TODO: fix this after fixing ExceptionHandler + out->float_save.fpscr = 0; + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +} + +#elif defined(__aarch64__) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + const struct fpsimd_context* fpregs) { + out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; + + out->cpsr = static_cast(uc->uc_mcontext.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = uc->uc_mcontext.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; + + out->float_save.fpsr = fpregs->fpsr; + out->float_save.fpcr = fpregs->fpcr; + my_memcpy(&out->float_save.regs, &fpregs->vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) { + return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) { +#if _MIPS_SIM == _ABI64 + out->context_flags = MD_CONTEXT_MIPS64_FULL; +#elif _MIPS_SIM == _ABIO32 + out->context_flags = MD_CONTEXT_MIPS_FULL; +#else +#error "This mips ABI is currently not supported (n32)" +#endif + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = uc->uc_mcontext.gregs[i]; + + out->mdhi = uc->uc_mcontext.mdhi; + out->mdlo = uc->uc_mcontext.mdlo; + + out->hi[0] = uc->uc_mcontext.hi1; + out->hi[1] = uc->uc_mcontext.hi2; + out->hi[2] = uc->uc_mcontext.hi3; + out->lo[0] = uc->uc_mcontext.lo1; + out->lo[1] = uc->uc_mcontext.lo2; + out->lo[2] = uc->uc_mcontext.lo3; + out->dsp_control = uc->uc_mcontext.dsp; + + out->epc = uc->uc_mcontext.pc; + out->badvaddr = 0; // Not reported in signal context. + out->status = 0; // Not reported in signal context. + out->cause = 0; // Not reported in signal context. + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; + + out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; +#if _MIPS_SIM == _ABIO32 + out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. +#endif +} +#endif + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.h b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.h new file mode 100644 index 0000000000..390520be41 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/dump_writer_common/ucontext_reader.h @@ -0,0 +1,65 @@ +// Copyright (c) 2014, 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_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H + +#include +#include + +#include "linux/dump_writer_common/raw_context_cpu.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "common/memory_allocator.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Wraps platform-dependent implementations of accessors to ucontext_t structs. +struct UContextReader { + static uintptr_t GetStackPointer(const ucontext_t* uc); + + static uintptr_t GetInstructionPointer(const ucontext_t* uc); + + // Juggle a arch-specific ucontext into a minidump format + // out: the minidump structure + // info: the collection of register structures. +#if defined(__i386__) || defined(__x86_64) + static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + const fpstate_t* fp); +#elif defined(__aarch64__) + static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc, + const struct fpsimd_context* fpregs); +#else + static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc); +#endif +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc new file mode 100644 index 0000000000..92a0443d79 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc @@ -0,0 +1,876 @@ +// Copyright (c) 2010 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 ExceptionHandler object installs signal handlers for a number of +// signals. We rely on the signal handler running on the thread which crashed +// in order to identify it. This is true of the synchronous signals (SEGV etc), +// but not true of ABRT. Thus, if you send ABRT to yourself in a program which +// uses ExceptionHandler, you need to use tgkill to direct it to the current +// thread. +// +// The signal flow looks like this: +// +// SignalHandler (uses a global stack of ExceptionHandler objects to find +// | one to handle the signal. If the first rejects it, try +// | the second etc...) +// V +// HandleSignal ----------------------------| (clones a new process which +// | | shares an address space with +// (wait for cloned | the crashed process. This +// process) | allows us to ptrace the crashed +// | | process) +// V V +// (set signal handler to ThreadEntry (static function to bounce +// SIG_DFL and rethrow, | back into the object) +// killing the crashed | +// process) V +// DoDump (writes minidump) +// | +// V +// sys_exit +// + +// This code is a little fragmented. Different functions of the ExceptionHandler +// class run in a number of different contexts. Some of them run in a normal +// context and are easy to code, others run in a compromised context and the +// restrictions at the top of minidump_writer.cc apply: no libc and use the +// alternative malloc. Each function should have comment above it detailing the +// context which it runs in. + +#include "linux/handler/exception_handler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "common/basictypes.h" +#include "common/linux/breakpad_getcontext.h" +#include "common/linux/linux_libc_support.h" +#include "common/memory_allocator.h" +#include "linux/log/log.h" +#include "linux/microdump_writer/microdump_writer.h" +#include "linux/minidump_writer/linux_dumper.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "common/linux/eintr_wrapper.h" +#include "third_party/lss/linux_syscall_support.h" +#if defined(MOZ_OXIDIZED_BREAKPAD) +#include "nsString.h" +#include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h" +#endif + +#ifdef MOZ_PHC +#include "PHC.h" +#endif + +#if defined(__ANDROID__) +#include "linux/sched.h" +#endif + +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif + +#define SKIP_SIGILL(sig) if (g_skip_sigill_ && (sig == SIGILL)) continue; + +namespace google_breakpad { + +namespace { +// The list of signals which we consider to be crashes. The default action for +// all these signals must be Core (see man 7 signal) because we rethrow the +// signal after handling it and expect that it'll be fatal. +const int kExceptionSignals[] = { + SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGTRAP +}; +const int kNumHandledSignals = + sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); +struct sigaction old_handlers[kNumHandledSignals]; +bool handlers_installed = false; + +// InstallAlternateStackLocked will store the newly installed stack in new_stack +// and (if it exists) the previously installed stack in old_stack. +stack_t old_stack; +stack_t new_stack; +bool stack_installed = false; + +// Create an alternative stack to run the signal handlers on. This is done since +// the signal might have been caused by a stack overflow. +// Runs before crashing: normal context. +void InstallAlternateStackLocked() { + if (stack_installed) + return; + + memset(&old_stack, 0, sizeof(old_stack)); + memset(&new_stack, 0, sizeof(new_stack)); + + // SIGSTKSZ may be too small to prevent the signal handlers from overrunning + // the alternative stack. Ensure that the size of the alternative stack is + // large enough. + static const size_t kSigStackSize = std::max(size_t(16384), size_t(SIGSTKSZ)); + + // Only set an alternative stack if there isn't already one, or if the current + // one is too small. + if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || + old_stack.ss_size < kSigStackSize) { + new_stack.ss_sp = calloc(1, kSigStackSize); + new_stack.ss_size = kSigStackSize; + + if (sys_sigaltstack(&new_stack, NULL) == -1) { + free(new_stack.ss_sp); + return; + } + stack_installed = true; + } +} + +// Runs before crashing: normal context. +void RestoreAlternateStackLocked() { + if (!stack_installed) + return; + + stack_t current_stack; + if (sys_sigaltstack(NULL, ¤t_stack) == -1) + return; + + // Only restore the old_stack if the current alternative stack is the one + // installed by the call to InstallAlternateStackLocked. + if (current_stack.ss_sp == new_stack.ss_sp) { + if (old_stack.ss_sp) { + if (sys_sigaltstack(&old_stack, NULL) == -1) + return; + } else { + stack_t disable_stack; + disable_stack.ss_flags = SS_DISABLE; + if (sys_sigaltstack(&disable_stack, NULL) == -1) + return; + } + } + + free(new_stack.ss_sp); + stack_installed = false; +} + +void InstallDefaultHandler(int sig) { +#if defined(__ANDROID__) + // Android L+ expose signal and sigaction symbols that override the system + // ones. There is a bug in these functions where a request to set the handler + // to SIG_DFL is ignored. In that case, an infinite loop is entered as the + // signal is repeatedly sent to breakpad's signal handler. + // To work around this, directly call the system's sigaction. + struct kernel_sigaction sa; + memset(&sa, 0, sizeof(sa)); + sys_sigemptyset(&sa.sa_mask); + sa.sa_handler_ = SIG_DFL; + sa.sa_flags = SA_RESTART; + sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t)); +#else + signal(sig, SIG_DFL); +#endif +} + +// The global exception handler stack. This is needed because there may exist +// multiple ExceptionHandler instances in a process. Each will have itself +// registered in this stack. +std::vector* g_handler_stack_ = NULL; +pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; + +// sizeof(CrashContext) can be too big w.r.t the size of alternatate stack +// for SignalHandler(). Keep the crash context as a .bss field. Exception +// handlers are serialized by the |g_handler_stack_mutex_| and at most one at a +// time can use |g_crash_context_|. +ExceptionHandler::CrashContext g_crash_context_; + +FirstChanceHandler g_first_chance_handler_ = nullptr; +bool g_skip_sigill_ = false; +} // namespace + +// Runs before crashing: normal context. +ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + bool install_handler, + const int server_fd) + : filter_(filter), + callback_(callback), + callback_context_(callback_context), + minidump_descriptor_(descriptor), + crash_handler_(NULL) { + + g_skip_sigill_ = getenv("MOZ_DISABLE_EXCEPTION_HANDLER_SIGILL") ? true : false; + if (server_fd >= 0) + crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); + + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && + !minidump_descriptor_.IsMicrodumpOnConsole()) + minidump_descriptor_.UpdatePath(); + +#if defined(__ANDROID__) + if (minidump_descriptor_.IsMicrodumpOnConsole()) + logger::initializeCrashLogWriter(); +#endif + + pthread_mutex_lock(&g_handler_stack_mutex_); + + // Pre-fault the crash context struct. This is to avoid failing due to OOM + // if handling an exception when the process ran out of virtual memory. + memset(&g_crash_context_, 0, sizeof(g_crash_context_)); + + if (!g_handler_stack_) + g_handler_stack_ = new std::vector; + if (install_handler) { + InstallAlternateStackLocked(); + InstallHandlersLocked(); + } + g_handler_stack_->push_back(this); + pthread_mutex_unlock(&g_handler_stack_mutex_); +} + +// Runs before crashing: normal context. +ExceptionHandler::~ExceptionHandler() { + pthread_mutex_lock(&g_handler_stack_mutex_); + std::vector::iterator handler = + std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this); + g_handler_stack_->erase(handler); + if (g_handler_stack_->empty()) { + delete g_handler_stack_; + g_handler_stack_ = NULL; + RestoreAlternateStackLocked(); + RestoreHandlersLocked(); + } + pthread_mutex_unlock(&g_handler_stack_mutex_); +} + +// Runs before crashing: normal context. +// static +bool ExceptionHandler::InstallHandlersLocked() { + if (handlers_installed) + return false; + + // Fail if unable to store all the old handlers. + for (int i = 0; i < kNumHandledSignals; ++i) { + SKIP_SIGILL(kExceptionSignals[i]); + if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) + return false; + } + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + // Mask all exception signals when we're handling one of them. + for (int i = 0; i < kNumHandledSignals; ++i) { + SKIP_SIGILL(kExceptionSignals[i]); + sigaddset(&sa.sa_mask, kExceptionSignals[i]); + } + + sa.sa_sigaction = SignalHandler; + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + + for (int i = 0; i < kNumHandledSignals; ++i) { + SKIP_SIGILL(kExceptionSignals[i]); + if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) { + // At this point it is impractical to back out changes, and so failure to + // install a signal is intentionally ignored. + } + } + handlers_installed = true; + return true; +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +// static +void ExceptionHandler::RestoreHandlersLocked() { + if (!handlers_installed) + return; + + for (int i = 0; i < kNumHandledSignals; ++i) { + SKIP_SIGILL(kExceptionSignals[i]); + if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) { + InstallDefaultHandler(kExceptionSignals[i]); + } + } + handlers_installed = false; +} + +// void ExceptionHandler::set_crash_handler(HandlerCallback callback) { +// crash_handler_ = callback; +// } + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +// static +void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { + + // Give the first chance handler a chance to recover from this signal + // + // This is primarily used by V8. V8 uses guard regions to guarantee memory + // safety in WebAssembly. This means some signals might be expected if they + // originate from Wasm code while accessing the guard region. We give V8 the + // chance to handle and recover from these signals first. + if (g_first_chance_handler_ != nullptr && + g_first_chance_handler_(sig, info, uc)) { + return; + } + + // All the exception signals are blocked at this point. + pthread_mutex_lock(&g_handler_stack_mutex_); + + // Sometimes, Breakpad runs inside a process where some other buggy code + // saves and restores signal handlers temporarily with 'signal' + // instead of 'sigaction'. This loses the SA_SIGINFO flag associated + // with this function. As a consequence, the values of 'info' and 'uc' + // become totally bogus, generally inducing a crash. + // + // The following code tries to detect this case. When it does, it + // resets the signal handlers with sigaction + SA_SIGINFO and returns. + // This forces the signal to be thrown again, but this time the kernel + // will call the function with the right arguments. + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) == 0 && + cur_handler.sa_sigaction == SignalHandler && + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + // Reset signal handler with the right flags. + sigemptyset(&cur_handler.sa_mask); + sigaddset(&cur_handler.sa_mask, sig); + + cur_handler.sa_sigaction = SignalHandler; + cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO; + + if (sigaction(sig, &cur_handler, NULL) == -1) { + // When resetting the handler fails, try to reset the + // default one to avoid an infinite loop here. + InstallDefaultHandler(sig); + } + pthread_mutex_unlock(&g_handler_stack_mutex_); + return; + } + + bool handled = false; + for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) { + handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc); + } + + // Upon returning from this signal handler, sig will become unmasked and then + // it will be retriggered. If one of the ExceptionHandlers handled it + // successfully, restore the default handler. Otherwise, restore the + // previously installed handler. Then, when the signal is retriggered, it will + // be delivered to the appropriate handler. + if (handled) { + InstallDefaultHandler(sig); + } else { + RestoreHandlersLocked(); + } + + pthread_mutex_unlock(&g_handler_stack_mutex_); + + // info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise). + if (info->si_code <= 0 || sig == SIGABRT) { + // This signal was triggered by somebody sending us the signal with kill(). + // In order to retrigger it, we have to queue a new signal by calling + // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is + // due to the kernel sending a SIGABRT from a user request via SysRQ. + if (sys_tgkill(getpid(), syscall(__NR_gettid), sig) < 0) { + // If we failed to kill ourselves (e.g. because a sandbox disallows us + // to do so), we instead resort to terminating our process. This will + // result in an incorrect exit code. + _exit(1); + } + } else { + // This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV). + // No need to reissue the signal. It will automatically trigger again, + // when we return from the signal handler. + } +} + +struct ThreadArgument { + pid_t pid; // the crashing process + const MinidumpDescriptor* minidump_descriptor; + ExceptionHandler* handler; + const void* context; // a CrashContext structure + size_t context_size; +}; + +// This is the entry function for the cloned process. We are in a compromised +// context here: see the top of the file. +// static +int ExceptionHandler::ThreadEntry(void *arg) { + const ThreadArgument *thread_arg = reinterpret_cast(arg); + + // Close the write end of the pipe. This allows us to fail if the parent dies + // while waiting for the continue signal. + sys_close(thread_arg->handler->fdes[1]); + + // Block here until the crashing process unblocks us when + // we're allowed to use ptrace + thread_arg->handler->WaitForContinueSignal(); + sys_close(thread_arg->handler->fdes[0]); + + return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context, + thread_arg->context_size) == false; +} + +#ifdef MOZ_PHC +static void GetPHCAddrInfo(siginfo_t* siginfo, + mozilla::phc::AddrInfo* addr_info) { + // Is this a crash involving a PHC allocation? + if (siginfo->si_signo == SIGSEGV || siginfo->si_signo == SIGBUS) { + mozilla::phc::IsPHCAllocation(siginfo->si_addr, addr_info); + } +} +#endif + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +bool ExceptionHandler::HandleSignal(int /*sig*/, siginfo_t* info, void* uc) { + mozilla::phc::AddrInfo* addr_info = nullptr; +#ifdef MOZ_PHC + addr_info = &mozilla::phc::gAddrInfo; + GetPHCAddrInfo(info, addr_info); +#endif + + if (filter_ && !filter_(callback_context_)) + return false; + + // Allow ourselves to be dumped if the signal is trusted. + bool signal_trusted = info->si_code > 0; + bool signal_pid_trusted = info->si_code == SI_USER || + info->si_code == SI_TKILL; + if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { + sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + } + + // Fill in all the holes in the struct to make Valgrind happy. + memset(&g_crash_context_, 0, sizeof(g_crash_context_)); + memcpy(&g_crash_context_.siginfo, info, sizeof(siginfo_t)); + memcpy(&g_crash_context_.context, uc, sizeof(ucontext_t)); +#if defined(__aarch64__) + ucontext_t* uc_ptr = (ucontext_t*)uc; + struct fpsimd_context* fp_ptr = + (struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved; + if (fp_ptr->head.magic == FPSIMD_MAGIC) { + memcpy(&g_crash_context_.float_state, fp_ptr, + sizeof(g_crash_context_.float_state)); + } +#elif !defined(__ARM_EABI__) && !defined(__mips__) + // FP state is not part of user ABI on ARM Linux. + // In case of MIPS Linux FP state is already part of ucontext_t + // and 'float_state' is not a member of CrashContext. + ucontext_t* uc_ptr = (ucontext_t*)uc; + if (uc_ptr->uc_mcontext.fpregs) { + memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs, + sizeof(g_crash_context_.float_state)); + } +#endif + g_crash_context_.tid = syscall(__NR_gettid); + if (crash_handler_ != NULL) { + if (crash_handler_(&g_crash_context_, sizeof(g_crash_context_), + callback_context_)) { + return true; + } + } + + return GenerateDump(&g_crash_context_, addr_info); +} + +// This is a public interface to HandleSignal that allows the client to +// generate a crash dump. This function may run in a compromised context. +bool ExceptionHandler::SimulateSignalDelivery(int sig) { + siginfo_t siginfo = {}; + // Mimic a trusted signal to allow tracing the process (see + // ExceptionHandler::HandleSignal(). + siginfo.si_code = SI_USER; + siginfo.si_pid = getpid(); + ucontext_t context; + getcontext(&context); + return HandleSignal(sig, &siginfo, &context); +} + +// This function may run in a compromised context: see the top of the file. +bool ExceptionHandler::GenerateDump( + CrashContext *context, const mozilla::phc::AddrInfo* addr_info) { + if (IsOutOfProcess()) { + bool success = + crash_generation_client_->RequestDump(context, sizeof(*context)); + + if (callback_) { + success = + callback_(minidump_descriptor_, callback_context_, addr_info, success); + } + + return success; + } + + // Allocating too much stack isn't a problem, and better to err on the side + // of caution than smash it into random locations. + static const unsigned kChildStackSize = 16000; + PageAllocator allocator; + uint8_t* stack = reinterpret_cast(allocator.Alloc(kChildStackSize)); + if (!stack) + return false; + // clone() needs the top-most address. (scrub just to be safe) + stack += kChildStackSize; + my_memset(stack - 16, 0, 16); + + ThreadArgument thread_arg; + thread_arg.handler = this; + thread_arg.minidump_descriptor = &minidump_descriptor_; + thread_arg.pid = getpid(); + thread_arg.context = context; + thread_arg.context_size = sizeof(*context); + + // We need to explicitly enable ptrace of parent processes on some + // kernels, but we need to know the PID of the cloned process before we + // can do this. Create a pipe here which we can use to block the + // cloned process after creating it, until we have explicitly enabled ptrace + if (sys_pipe(fdes) == -1) { + // Creating the pipe failed. We'll log an error but carry on anyway, + // as we'll probably still get a useful crash report. All that will happen + // is the write() and read() calls will fail with EBADF + static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump " + "sys_pipe failed:"; + logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + + // Ensure fdes[0] and fdes[1] are invalid file descriptors. + fdes[0] = fdes[1] = -1; + } + + const pid_t child = sys_clone( + ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL, + NULL); + if (child == -1) { + sys_close(fdes[0]); + sys_close(fdes[1]); + return false; + } + + if (child != 0) { + static const char clonedMsg[] = + "ExceptionHandler::GenerateDump cloned child "; + char pidMsg[32] = {}; + + unsigned int pidLen = my_uint_len(child); + my_uitos(pidMsg, child, pidLen); + + logger::write(clonedMsg, my_strlen(clonedMsg)); + logger::write(pidMsg, pidLen); + logger::write("\n", 1); + } else { + static const char childMsg[] = + "ExceptionHandler::GenerateDump I'm the child\n"; + logger::write(childMsg, my_strlen(childMsg)); + } + + // Close the read end of the pipe. + sys_close(fdes[0]); + // Allow the child to ptrace us + sys_prctl(PR_SET_PTRACER, child, 0, 0, 0); + SendContinueSignalToChild(); + int status = 0; + const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL)); + + sys_close(fdes[1]); + + if (r == -1) { + static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } + + bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0; + if (callback_) + success = + callback_(minidump_descriptor_, callback_context_, addr_info, success); + return success; +} + +// This function runs in a compromised context: see the top of the file. +void ExceptionHandler::SendContinueSignalToChild() { + static const char okToContinueMessage = 'a'; + int r; + r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char))); + if (r == -1) { + static const char msg[] = "ExceptionHandler::SendContinueSignalToChild " + "sys_write failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } + + const char* msg = "ExceptionHandler::SendContinueSignalToChild sent continue signal to child\n"; + logger::write(msg, my_strlen(msg)); +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the cloned process. +void ExceptionHandler::WaitForContinueSignal() { + int r; + char receivedMessage; + + const char* waitMsg = "ExceptionHandler::WaitForContinueSignal waiting for continue signal...\n"; + logger::write(waitMsg, my_strlen(waitMsg)); + + r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char))); + if (r == -1) { + static const char msg[] = "ExceptionHandler::WaitForContinueSignal " + "sys_read failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the cloned process. +bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, + size_t context_size) { + const bool may_skip_dump = + minidump_descriptor_.skip_dump_if_principal_mapping_not_referenced(); + const uintptr_t principal_mapping_address = + minidump_descriptor_.address_within_principal_mapping(); + const bool sanitize_stacks = minidump_descriptor_.sanitize_stacks(); + if (minidump_descriptor_.IsMicrodumpOnConsole()) { + return google_breakpad::WriteMicrodump( + crashing_process, + context, + context_size, + mapping_list_, + may_skip_dump, + principal_mapping_address, + sanitize_stacks, + *minidump_descriptor_.microdump_extra_info()); + } + if (minidump_descriptor_.IsFD()) { + return google_breakpad::WriteMinidump(minidump_descriptor_.fd(), + minidump_descriptor_.size_limit(), + crashing_process, + context, + context_size, + mapping_list_, + app_memory_list_, + may_skip_dump, + principal_mapping_address, + sanitize_stacks); + } + return google_breakpad::WriteMinidump(minidump_descriptor_.path(), + minidump_descriptor_.size_limit(), + crashing_process, + context, + context_size, + mapping_list_, + app_memory_list_, + may_skip_dump, + principal_mapping_address, + sanitize_stacks); +} + +// static +bool ExceptionHandler::WriteMinidump(const string& dump_path, + MinidumpCallback callback, + void* callback_context) { + MinidumpDescriptor descriptor(dump_path); + ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1); + return eh.WriteMinidump(); +} + +// In order to making using EBP to calculate the desired value for ESP +// a valid operation, ensure that this function is compiled with a +// frame pointer using the following attribute. This attribute +// is supported on GCC but not on clang. +#if defined(__i386__) && defined(__GNUC__) && !defined(__clang__) +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +bool ExceptionHandler::WriteMinidump() { + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && + !minidump_descriptor_.IsMicrodumpOnConsole()) { + // Update the path of the minidump so that this can be called multiple times + // and new files are created for each minidump. This is done before the + // generation happens, as clients may want to access the MinidumpDescriptor + // after this call to find the exact path to the minidump file. + minidump_descriptor_.UpdatePath(); + } else if (minidump_descriptor_.IsFD()) { + // Reposition the FD to its beginning and resize it to get rid of the + // previous minidump info. + lseek(minidump_descriptor_.fd(), 0, SEEK_SET); + ignore_result(ftruncate(minidump_descriptor_.fd(), 0)); + } + + // Allow this process to be dumped. + sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + + CrashContext context; + int getcontext_result = getcontext(&context.context); + if (getcontext_result) + return false; + +#if defined(__i386__) + // In CPUFillFromUContext in minidumpwriter.cc the stack pointer is retrieved + // from REG_UESP instead of from REG_ESP. REG_UESP is the user stack pointer + // and it only makes sense when running in kernel mode with a different stack + // pointer. When WriteMiniDump is called during normal processing REG_UESP is + // zero which leads to bad minidump files. + if (!context.context.uc_mcontext.gregs[REG_UESP]) { + // If REG_UESP is set to REG_ESP then that includes the stack space for the + // CrashContext object in this function, which is about 128 KB. Since the + // Linux dumper only records 32 KB of stack this would mean that nothing + // useful would be recorded. A better option is to set REG_UESP to REG_EBP, + // perhaps with a small negative offset in case there is any code that + // objects to them being equal. + context.context.uc_mcontext.gregs[REG_UESP] = + context.context.uc_mcontext.gregs[REG_EBP] - 16; + // The stack saving is based off of REG_ESP so it must be set to match the + // new REG_UESP. + context.context.uc_mcontext.gregs[REG_ESP] = + context.context.uc_mcontext.gregs[REG_UESP]; + } +#endif + +#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) + // FPU state is not part of ARM EABI ucontext_t. + memcpy(&context.float_state, context.context.uc_mcontext.fpregs, + sizeof(context.float_state)); +#endif + context.tid = sys_gettid(); + + // Add an exception stream to the minidump for better reporting. + memset(&context.siginfo, 0, sizeof(context.siginfo)); + context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED; +#if defined(__i386__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.gregs[REG_EIP]); +#elif defined(__x86_64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.gregs[REG_RIP]); +#elif defined(__arm__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.arm_pc); +#elif defined(__aarch64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); +#elif defined(__mips__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); +#else +#error "This code has not been ported to your platform yet." +#endif + + // nullptr here for phc::AddrInfo* is ok because this is not a crash. + return GenerateDump(&context, nullptr); +} + +void ExceptionHandler::AddMappingInfo(const string& name, + const wasteful_vector& identifier, + uintptr_t start_address, + size_t mapping_size, + size_t file_offset) { + MappingInfo info; + info.start_addr = start_address; + info.size = mapping_size; + info.offset = file_offset; + strncpy(info.name, name.c_str(), sizeof(info.name) - 1); + info.name[sizeof(info.name) - 1] = '\0'; + + MappingEntry mapping; + mapping.first = info; + mapping.second.assign(identifier.begin(), identifier.end()); + mapping_list_.push_back(mapping); +} + +void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { + AppMemoryList::iterator iter = + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); + if (iter != app_memory_list_.end()) { + // Don't allow registering the same pointer twice. + return; + } + + AppMemory app_memory; + app_memory.ptr = ptr; + app_memory.length = length; + app_memory_list_.push_back(app_memory); +} + +void ExceptionHandler::UnregisterAppMemory(void* ptr) { + AppMemoryList::iterator iter = + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); + if (iter != app_memory_list_.end()) { + app_memory_list_.erase(iter); + } +} + +// static +bool ExceptionHandler::WriteMinidumpForChild(pid_t child, + pid_t child_blamed_thread, + const string& dump_path, + MinidumpCallback callback, + void* callback_context) { + // This function is not run in a compromised context. + MinidumpDescriptor descriptor(dump_path); + descriptor.UpdatePath(); +#if defined(MOZ_OXIDIZED_BREAKPAD) + nsCString error_msg; + if (!write_minidump_linux(descriptor.path(), child, child_blamed_thread, &error_msg)) + return false; +#else + if (!google_breakpad::WriteMinidump(descriptor.path(), + child, + child_blamed_thread)) + return false; +#endif + + // nullptr here for phc::AddrInfo* is ok because this is not a crash. + return callback ? callback(descriptor, callback_context, nullptr, true) + : true; +} + +void SetFirstChanceExceptionHandler(FirstChanceHandler callback) { + g_first_chance_handler_ = callback; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h new file mode 100644 index 0000000000..46ad399419 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h @@ -0,0 +1,289 @@ +// Copyright (c) 2010 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_LINUX_HANDLER_EXCEPTION_HANDLER_H_ +#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ + +#include +#include +#include +#include + +#include + +#include "linux/crash_generation/crash_generation_client.h" +#include "linux/handler/minidump_descriptor.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" + +#ifdef MOZ_PHC +#include "PHC.h" +#else +namespace mozilla { namespace phc { class AddrInfo {}; } } +#endif + +namespace google_breakpad { + +// 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 full path or file descriptor of the minidump. The +// caller can collect and write additional application state to that minidump, +// and 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. + // |descriptor| contains the file descriptor or file path containing the + // minidump. |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 MinidumpDescriptor& descriptor, + void* context, + const mozilla::phc::AddrInfo* addr_info, + bool succeeded); + + // In certain cases, a user may wish to handle the generation of the minidump + // themselves. In this case, they can install a handler callback which is + // called when a crash has occurred. If this function returns true, no other + // processing of occurs and the process will shortly be crashed. If this + // returns false, the normal processing continues. + typedef bool (*HandlerCallback)(const void* crash_context, + size_t crash_context_size, + void* context); + + // 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. The minidump content will be written to the file path or file + // descriptor from |descriptor|, 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. + // If |server_fd| is valid, the minidump is generated out-of-process. If it + // is -1, in-process generation will always be used. + ExceptionHandler(const MinidumpDescriptor& descriptor, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + bool install_handler, + const int server_fd); + ~ExceptionHandler(); + + const MinidumpDescriptor& minidump_descriptor() const { + return minidump_descriptor_; + } + + void set_minidump_descriptor(const MinidumpDescriptor& descriptor) { + minidump_descriptor_ = descriptor; + } + + void set_crash_handler(HandlerCallback callback) { + crash_handler_ = callback; + } + + void set_crash_generation_client(CrashGenerationClient* client) { + crash_generation_client_.reset(client); + } + + // Writes a minidump immediately. This can be used to capture the execution + // state independently of a crash. + // Returns true on success. + // If the ExceptionHandler has been created with a path, a new file is + // generated for each minidump. The file path can be retrieved in the + // MinidumpDescriptor passed to the MinidumpCallback or by accessing the + // MinidumpDescriptor directly from the ExceptionHandler (with + // minidump_descriptor()). + // If the ExceptionHandler has been created with a file descriptor, the file + // descriptor is repositioned to its beginning and the previous generated + // minidump is overwritten. + // Note that this method is not supposed to be called from a compromised + // context as it uses the heap. + 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); + + // Write a minidump of |child| immediately. This can be used to + // capture the execution state of |child| independently of a crash. + // Pass a meaningful |child_blamed_thread| to make that thread in + // the child process the one from which a crash signature is + // extracted. + // + // WARNING: the return of this function *must* happen before + // the code that will eventually reap |child| executes. + // Otherwise there's a pernicious race condition in which |child| + // exits, is reaped, another process created with its pid, then that + // new process dumped. + static bool WriteMinidumpForChild(pid_t child, + pid_t child_blamed_thread, + const string& dump_path, + MinidumpCallback callback, + void* callback_context); + + // This structure is passed to minidump_writer.h:WriteMinidump via an opaque + // blob. It shouldn't be needed in any user code. + struct CrashContext { + siginfo_t siginfo; + pid_t tid; // the crashing thread. + ucontext_t context; +#if !defined(__ARM_EABI__) && !defined(__mips__) + // #ifdef this out because FP state is not part of user ABI for Linux ARM. + // In case of MIPS Linux FP state is already part of ucontext_t so + // 'float_state' is not required. + fpstate_t float_state; +#endif + }; + + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { + return crash_generation_client_.get() != NULL; + } + + // Add information about a memory mapping. This can be used if + // a custom library loader is used that maps things in a way + // that the linux dumper can't handle by reading the maps file. + void AddMappingInfo(const string& name, + const wasteful_vector& identifier, + uintptr_t start_address, + size_t mapping_size, + size_t file_offset); + + // Register a block of memory of length bytes starting at address ptr + // to be copied to the minidump when a crash happens. + void RegisterAppMemory(void* ptr, size_t length); + + // Unregister a block of memory that was registered with RegisterAppMemory. + void UnregisterAppMemory(void* ptr); + + // Force signal handling for the specified signal. + bool SimulateSignalDelivery(int sig); + + // Report a crash signal from an SA_SIGINFO signal handler. + bool HandleSignal(int sig, siginfo_t* info, void* uc); + + private: + // Save the old signal handlers and install new ones. + static bool InstallHandlersLocked(); + // Restore the old signal handlers. + static void RestoreHandlersLocked(); + + void PreresolveSymbols(); + bool GenerateDump(CrashContext *context, + const mozilla::phc::AddrInfo* addr_info); + void SendContinueSignalToChild(); + void WaitForContinueSignal(); + + static void SignalHandler(int sig, siginfo_t* info, void* uc); + static int ThreadEntry(void* arg); + bool DoDump(pid_t crashing_process, const void* context, + size_t context_size); + + const FilterCallback filter_; + const MinidumpCallback callback_; + void* const callback_context_; + + scoped_ptr crash_generation_client_; + + MinidumpDescriptor minidump_descriptor_; + + // Must be volatile. The compiler is unaware of the code which runs in + // the signal handler which reads this variable. Without volatile the + // compiler is free to optimise away writes to this variable which it + // believes are never read. + volatile HandlerCallback crash_handler_; + + // We need to explicitly enable ptrace of parent processes on some + // kernels, but we need to know the PID of the cloned process before we + // can do this. We create a pipe which we can use to block the + // cloned process after creating it, until we have explicitly enabled + // ptrace. This is used to store the file descriptors for the pipe + int fdes[2] = {-1, -1}; + + // Callers can add extra info about mappings for cases where the + // dumper code cannot extract enough information from /proc//maps. + MappingList mapping_list_; + + // Callers can request additional memory regions to be included in + // the dump. + AppMemoryList app_memory_list_; +}; + +typedef bool (*FirstChanceHandler)(int, siginfo_t*, void*); +void SetFirstChanceExceptionHandler(FirstChanceHandler callback); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc new file mode 100644 index 0000000000..8fa59456c9 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc @@ -0,0 +1,1290 @@ +// Copyright (c) 2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__mips__) +#include +#endif + +#include + +#include "breakpad_googletest_includes.h" +#include "linux/handler/exception_handler.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/ignore_ret.h" +#include "common/linux/linux_libc_support.h" +#include "common/tests/auto_tempdir.h" +#include "common/using_std_string.h" +#include "third_party/lss/linux_syscall_support.h" +#include "google_breakpad/processor/minidump.h" + +using namespace google_breakpad; + +namespace { + +// Flush the instruction cache for a given memory range. +// Only required on ARM and mips. +void FlushInstructionCache(const char* memory, uint32_t memory_size) { +#if defined(__arm__) + long begin = reinterpret_cast(memory); + long end = begin + static_cast(memory_size); +# if defined(__ANDROID__) + // Provided by Android's + cacheflush(begin, end, 0); +# elif defined(__linux__) + // GLibc/ARM doesn't provide a wrapper for it, do a direct syscall. +# ifndef __ARM_NR_cacheflush +# define __ARM_NR_cacheflush 0xf0002 +# endif + syscall(__ARM_NR_cacheflush, begin, end, 0); +# else +# error "Your operating system is not supported yet" +# endif +#elif defined(__mips__) +# if defined(__ANDROID__) + // Provided by Android's + long begin = reinterpret_cast(memory); + long end = begin + static_cast(memory_size); +#if _MIPS_SIM == _ABIO32 + cacheflush(begin, end, 0); +#else + syscall(__NR_cacheflush, begin, end, ICACHE); +#endif +# elif defined(__linux__) + // See http://www.linux-mips.org/wiki/Cacheflush_Syscall. + cacheflush(const_cast(memory), memory_size, ICACHE); +# else +# error "Your operating system is not supported yet" +# endif +#endif +} + +void sigchld_handler(int signo) { } + +int CreateTMPFile(const string& dir, string* path) { + string file = dir + "/exception-handler-unittest.XXXXXX"; + const char* c_file = file.c_str(); + // Copy that string, mkstemp needs a C string it can modify. + char* c_path = strdup(c_file); + const int fd = mkstemp(c_path); + if (fd >= 0) + *path = c_path; + free(c_path); + return fd; +} + +class ExceptionHandlerTest : public ::testing::Test { + protected: + void SetUp() { + // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigchld_handler; + ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1); + } + + void TearDown() { + sigaction(SIGCHLD, &old_action, NULL); + } + + struct sigaction old_action; +}; + + +void WaitForProcessToTerminate(pid_t process_id, int expected_status) { + int status; + ASSERT_NE(HANDLE_EINTR(waitpid(process_id, &status, 0)), -1); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_EQ(expected_status, WTERMSIG(status)); +} + +// Reads the minidump path sent over the pipe |fd| and sets it in |path|. +void ReadMinidumpPathFromPipe(int fd, string* path) { + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fd; + pfd.events = POLLIN | POLLERR; + + const int r = HANDLE_EINTR(poll(&pfd, 1, 0)); + ASSERT_EQ(1, r); + ASSERT_TRUE(pfd.revents & POLLIN); + + int32_t len; + ASSERT_EQ(static_cast(sizeof(len)), read(fd, &len, sizeof(len))); + ASSERT_LT(len, 2048); + char* filename = static_cast(malloc(len + 1)); + ASSERT_EQ(len, read(fd, filename, len)); + filename[len] = 0; + close(fd); + *path = filename; + free(filename); +} + +} // namespace + +TEST(ExceptionHandlerTest, SimpleWithPath) { + AutoTempDir temp_dir; + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + EXPECT_EQ(temp_dir.path(), handler.minidump_descriptor().directory()); + string temp_subdir = temp_dir.path() + "/subdir"; + handler.set_minidump_descriptor(MinidumpDescriptor(temp_subdir)); + EXPECT_EQ(temp_subdir, handler.minidump_descriptor().directory()); +} + +TEST(ExceptionHandlerTest, SimpleWithFD) { + AutoTempDir temp_dir; + string path; + const int fd = CreateTMPFile(temp_dir.path(), &path); + ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1); + close(fd); +} + +static bool DoneCallback(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + if (!succeeded) + return false; + + if (!descriptor.IsFD()) { + int fd = reinterpret_cast(context); + uint32_t len = 0; + len = my_strlen(descriptor.path()); + IGNORE_RET(HANDLE_EINTR(sys_write(fd, &len, sizeof(len)))); + IGNORE_RET(HANDLE_EINTR(sys_write(fd, descriptor.path(), len))); + } + return true; +} + +#ifndef ADDRESS_SANITIZER + +// This is a replacement for "*reinterpret_cast(NULL) = 0;" +// It is needed because GCC is allowed to assume that the program will +// not execute any undefined behavior (UB) operation. Further, when GCC +// observes that UB statement is reached, it can assume that all statements +// leading to the UB one are never executed either, and can completely +// optimize them out. In the case of ExceptionHandlerTest::ExternalDumper, +// GCC-4.9 optimized out the entire set up of ExceptionHandler, causing +// test failure. +volatile int *p_null; // external linkage, so GCC can't tell that it + // remains NULL. Volatile just for a good measure. +static void DoNullPointerDereference() { + *p_null = 1; +} + +void ChildCrash(bool use_fd) { + AutoTempDir temp_dir; + int fds[2] = {0}; + int minidump_fd = -1; + string minidump_path; + if (use_fd) { + minidump_fd = CreateTMPFile(temp_dir.path(), &minidump_path); + } else { + ASSERT_NE(pipe(fds), -1); + } + + const pid_t child = fork(); + if (child == 0) { + { + google_breakpad::scoped_ptr handler; + if (use_fd) { + handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd), + NULL, NULL, NULL, true, -1)); + } else { + close(fds[0]); // Close the reading end. + void* fd_param = reinterpret_cast(fds[1]); + handler.reset(new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), + NULL, DoneCallback, fd_param, + true, -1)); + } + // Crash with the exception handler in scope. + DoNullPointerDereference(); + } + } + if (!use_fd) + close(fds[1]); // Close the writting end. + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); + + if (!use_fd) + ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); + + struct stat st; + ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + unlink(minidump_path.c_str()); +} + +TEST(ExceptionHandlerTest, ChildCrashWithPath) { + ASSERT_NO_FATAL_FAILURE(ChildCrash(false)); +} + +TEST(ExceptionHandlerTest, ChildCrashWithFD) { + ASSERT_NO_FATAL_FAILURE(ChildCrash(true)); +} + +#if !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__ +static void* SleepFunction(void* unused) { + while (true) usleep(1000000); + return NULL; +} + +static void* CrashFunction(void* b_ptr) { + pthread_barrier_t* b = reinterpret_cast(b_ptr); + pthread_barrier_wait(b); + DoNullPointerDereference(); + return NULL; +} + +// Tests that concurrent crashes do not enter a loop by alternately triggering +// the signal handler. +TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { + AutoTempDir temp_dir; + const pid_t child = fork(); + if (child == 0) { + google_breakpad::scoped_ptr handler( + new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, + NULL, true, -1)); + + // We start a number of threads to make sure handling the signal takes + // enough time for the second thread to enter the signal handler. + int num_sleep_threads = 100; + google_breakpad::scoped_array sleep_threads( + new pthread_t[num_sleep_threads]); + for (int i = 0; i < num_sleep_threads; ++i) { + ASSERT_EQ(0, pthread_create(&sleep_threads[i], NULL, SleepFunction, + NULL)); + } + + int num_crash_threads = 2; + google_breakpad::scoped_array crash_threads( + new pthread_t[num_crash_threads]); + // Barrier to synchronize crashing both threads at the same time. + pthread_barrier_t b; + ASSERT_EQ(0, pthread_barrier_init(&b, NULL, num_crash_threads + 1)); + for (int i = 0; i < num_crash_threads; ++i) { + ASSERT_EQ(0, pthread_create(&crash_threads[i], NULL, CrashFunction, &b)); + } + pthread_barrier_wait(&b); + for (int i = 0; i < num_crash_threads; ++i) { + ASSERT_EQ(0, pthread_join(crash_threads[i], NULL)); + } + } + + // Wait a while until the child should have crashed. + usleep(1000000); + // Kill the child if it is still running. + kill(child, SIGKILL); + + // If the child process terminated by itself, it will have returned SIGSEGV. + // If however it got stuck in a loop, it will have been killed by the + // SIGKILL. + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); +} +#endif // !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__ + +static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + return false; +} + +static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + return true; +} + +static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + raise(SIGKILL); + return true; +} + +static bool FilterCallbackReturnFalse(void* context) { + return false; +} + +static bool FilterCallbackReturnTrue(void* context) { + return true; +} + +// SIGKILL cannot be blocked and a handler cannot be installed for it. In the +// following tests, if the child dies with signal SIGKILL, then the signal was +// redelivered to this handler. If the child dies with SIGSEGV then it wasn't. +static void RaiseSIGKILL(int sig) { + raise(SIGKILL); +} + +static bool InstallRaiseSIGKILL() { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = RaiseSIGKILL; + return sigaction(SIGSEGV, &sa, NULL) != -1; +} + +static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter, + ExceptionHandler::MinidumpCallback done, + string path) { + ExceptionHandler handler( + MinidumpDescriptor(path), filter, done, NULL, true, -1); + // Crash with the exception handler in scope. + DoNullPointerDereference(); +} + +TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ASSERT_TRUE(InstallRaiseSIGKILL()); + CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + } + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ASSERT_TRUE(InstallRaiseSIGKILL()); + CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); + } + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ASSERT_TRUE(InstallRaiseSIGKILL()); + CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path()); + } + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); +} + +TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ASSERT_TRUE(InstallRaiseSIGKILL()); + CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path()); + } + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); +} + +TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + // Custom signal handlers, which may have been installed by a test launcher, + // are undesirable in this child. + signal(SIGSEGV, SIG_DFL); + + CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + } + + // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child + // with SIGSEGV. + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); +} + +// Check that saving and restoring the signal handler with 'signal' +// instead of 'sigaction' doesn't make the Breakpad signal handler +// crash. See comments in ExceptionHandler::SignalHandler for full +// details. +TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) { + AutoTempDir temp_dir; + const pid_t child = fork(); + if (child == 0) { + // Install the RaiseSIGKILL handler for SIGSEGV. + ASSERT_TRUE(InstallRaiseSIGKILL()); + + // Create a new exception handler, this installs a new SIGSEGV + // handler, after saving the old one. + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, + DoneCallbackReturnFalse, NULL, true, -1); + + // Install the default SIGSEGV handler, saving the current one. + // Then re-install the current one with 'signal', this loses the + // SA_SIGINFO flag associated with the Breakpad handler. + sighandler_t old_handler = signal(SIGSEGV, SIG_DFL); + ASSERT_NE(reinterpret_cast(old_handler), + reinterpret_cast(SIG_ERR)); + ASSERT_NE(reinterpret_cast(signal(SIGSEGV, old_handler)), + reinterpret_cast(SIG_ERR)); + + // Crash with the exception handler in scope. + DoNullPointerDereference(); + } + // SIGKILL means Breakpad's signal handler didn't crash. + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), + NULL, + NULL, + NULL, + true, + -1); + CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path()); + } + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), + NULL, + DoneCallbackRaiseSIGKILL, + NULL, + true, + -1); + CrashWithCallbacks(NULL, NULL, temp_dir.path()); + } + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); +} + +TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), + NULL, + DoneCallbackRaiseSIGKILL, + NULL, + true, + -1); + CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); + } + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), + NULL, + DoneCallbackRaiseSIGKILL, + NULL, + true, + -1); + CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); + } + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); +} + +namespace { +const int kSimpleFirstChanceReturnStatus = 42; +bool SimpleFirstChanceHandler(int, siginfo_t*, void*) { + _exit(kSimpleFirstChanceReturnStatus); +} +} + +TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) { + AutoTempDir temp_dir; + + const pid_t child = fork(); + if (child == 0) { + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler); + DoNullPointerDereference(); + } + int status; + ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1); + ASSERT_TRUE(WIFEXITED(status)); + ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status)); +} + +#endif // !ADDRESS_SANITIZER + +const unsigned char kIllegalInstruction[] = { +#if defined(__mips__) + // mfc2 zero,Impl - usually illegal in userspace. + 0x48, 0x00, 0x00, 0x48 +#else + // This crashes with SIGILL on x86/x86-64/arm. + 0xff, 0xff, 0xff, 0xff +#endif +}; + +// Test that memory around the instruction pointer is written +// to the dump as a MinidumpMemoryRegion. +TEST(ExceptionHandlerTest, InstructionPointerMemory) { + AutoTempDir temp_dir; + int fds[2]; + ASSERT_NE(pipe(fds), -1); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = 256; // bytes + const int kOffset = kMemorySize / 2; + + const pid_t child = fork(); + if (child == 0) { + close(fds[0]); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + DoneCallback, reinterpret_cast(fds[1]), + true, -1); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them in the middle + // of the block of memory, because the minidump should contain 128 + // bytes on either side of the instruction pointer. + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); + FlushInstructionCache(memory, kMemorySize); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + } + close(fds[1]); + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); + + string minidump_path; + ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); + + struct stat st; + ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_path); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT(0U, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemorySize, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t prefix_bytes[kOffset]; + uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + sizeof(kIllegalInstruction)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), + suffix_bytes, sizeof(suffix_bytes)) == 0); + + unlink(minidump_path.c_str()); +} + +// Test that the memory region around the instruction pointer is +// bounded correctly on the low end. +TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { + AutoTempDir temp_dir; + int fds[2]; + ASSERT_NE(pipe(fds), -1); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = 256; // bytes + const int kOffset = 0; + + const pid_t child = fork(); + if (child == 0) { + close(fds[0]); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + DoneCallback, reinterpret_cast(fds[1]), + true, -1); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them in the middle + // of the block of memory, because the minidump should contain 128 + // bytes on either side of the instruction pointer. + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); + FlushInstructionCache(memory, kMemorySize); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + } + close(fds[1]); + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); + + string minidump_path; + ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); + + struct stat st; + ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_path); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT(0U, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemorySize / 2, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)]; + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + sizeof(kIllegalInstruction)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), + suffix_bytes, sizeof(suffix_bytes)) == 0); + unlink(minidump_path.c_str()); +} + +// Test that the memory region around the instruction pointer is +// bounded correctly on the high end. +TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { + AutoTempDir temp_dir; + int fds[2]; + ASSERT_NE(pipe(fds), -1); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + // Use 4k here because the OS will hand out a single page even + // if a smaller size is requested, and this test wants to + // test the upper bound of the memory range. + const uint32_t kMemorySize = 4096; // bytes + const int kOffset = kMemorySize - sizeof(kIllegalInstruction); + + const pid_t child = fork(); + if (child == 0) { + close(fds[0]); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + DoneCallback, reinterpret_cast(fds[1]), + true, -1); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them in the middle + // of the block of memory, because the minidump should contain 128 + // bytes on either side of the instruction pointer. + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); + FlushInstructionCache(memory, kMemorySize); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + } + close(fds[1]); + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); + + string minidump_path; + ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); + + struct stat st; + ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + // Read the minidump. Locate the exception record and the memory list, and + // then ensure that there is a memory region in the memory list that covers + // the instruction pointer from the exception record. + Minidump minidump(minidump_path); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT(0U, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + const size_t kPrefixSize = 128; // bytes + EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t prefix_bytes[kPrefixSize]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); + EXPECT_TRUE(memcmp(bytes + kPrefixSize, + kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); + + unlink(minidump_path.c_str()); +} + +#ifndef ADDRESS_SANITIZER + +// Ensure that an extra memory block doesn't get added when the instruction +// pointer is not in mapped memory. +TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { + AutoTempDir temp_dir; + int fds[2]; + ASSERT_NE(pipe(fds), -1); + + const pid_t child = fork(); + if (child == 0) { + close(fds[0]); + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, + DoneCallback, reinterpret_cast(fds[1]), + true, -1); + // Try calling a NULL pointer. + typedef void (*void_function)(void); + // Volatile markings are needed to keep Clang from generating invalid + // opcodes. See http://crbug.com/498354 for details. + volatile void_function memory_function = + reinterpret_cast(NULL); + memory_function(); + // not reached + exit(1); + } + close(fds[1]); + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); + + string minidump_path; + ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); + + struct stat st; + ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is no memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_path); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + ASSERT_TRUE(exception); + + MinidumpContext* exception_context = exception->GetContext(); + ASSERT_TRUE(exception_context); + + uint64_t instruction_pointer; + ASSERT_TRUE(exception_context->GetInstructionPointer(&instruction_pointer)); + EXPECT_EQ(instruction_pointer, 0u); + + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(memory_list); + + unsigned int region_count = memory_list->region_count(); + ASSERT_GE(region_count, 1u); + + for (unsigned int region_index = 0; + region_index < region_count; + ++region_index) { + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionAtIndex(region_index); + uint64_t region_base = region->GetBase(); + EXPECT_FALSE(instruction_pointer >= region_base && + instruction_pointer < region_base + region->GetSize()); + } + + unlink(minidump_path.c_str()); +} + +#endif // !ADDRESS_SANITIZER + +// Test that anonymous memory maps can be annotated with names and IDs. +TEST(ExceptionHandlerTest, ModuleInfo) { + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); + const char* kMemoryName = "a fake module"; + const uint8_t kModuleGUID[sizeof(MDGUID)] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + const string module_identifier = "33221100554477668899AABBCCDDEEFF0"; + + // Get some memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + PageAllocator allocator; + auto_wasteful_vector guid(&allocator); + guid.assign(std::begin(kModuleGUID), std::end(kModuleGUID)); + AutoTempDir temp_dir; + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + + // Add info about the anonymous memory mapping. + handler.AddMappingInfo(kMemoryName, + guid, + kMemoryAddress, + kMemorySize, + 0); + ASSERT_TRUE(handler.WriteMinidump()); + + const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); + // Read the minidump. Load the module list, and ensure that the mmap'ed + // |memory| is listed with the given module name and debug ID. + Minidump minidump(minidump_desc.path()); + ASSERT_TRUE(minidump.Read()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* module = + module_list->GetModuleForAddress(kMemoryAddress); + ASSERT_TRUE(module); + + EXPECT_EQ(kMemoryAddress, module->base_address()); + EXPECT_EQ(kMemorySize, module->size()); + EXPECT_EQ(kMemoryName, module->code_file()); + EXPECT_EQ(module_identifier, module->debug_identifier()); + + unlink(minidump_desc.path()); +} + +#ifndef ADDRESS_SANITIZER + +static const unsigned kControlMsgSize = + CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); + +static bool +CrashHandler(const void* crash_context, size_t crash_context_size, + void* context) { + const int fd = (intptr_t) context; + int fds[2]; + if (pipe(fds) == -1) { + // There doesn't seem to be any way to reliably handle + // this failure without the parent process hanging + // At least make sure that this process doesn't access + // unexpected file descriptors + fds[0] = -1; + fds[1] = -1; + } + struct kernel_msghdr msg = {0}; + struct kernel_iovec iov; + iov.iov_base = const_cast(crash_context); + iov.iov_len = crash_context_size; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + char cmsg[kControlMsgSize]; + memset(cmsg, 0, kControlMsgSize); + msg.msg_control = cmsg; + msg.msg_controllen = sizeof(cmsg); + + struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); + hdr->cmsg_level = SOL_SOCKET; + hdr->cmsg_type = SCM_RIGHTS; + hdr->cmsg_len = CMSG_LEN(sizeof(int)); + *((int*) CMSG_DATA(hdr)) = fds[1]; + hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr); + hdr->cmsg_level = SOL_SOCKET; + hdr->cmsg_type = SCM_CREDENTIALS; + hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + struct ucred *cred = reinterpret_cast(CMSG_DATA(hdr)); + cred->uid = getuid(); + cred->gid = getgid(); + cred->pid = getpid(); + + ssize_t ret = HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)); + sys_close(fds[1]); + if (ret <= 0) + return false; + + char b; + IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); + + return true; +} + +TEST(ExceptionHandlerTest, ExternalDumper) { + int fds[2]; + ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1); + static const int on = 1; + setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[0]); + ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL, + reinterpret_cast(fds[1]), true, -1); + handler.set_crash_handler(CrashHandler); + DoNullPointerDereference(); + } + close(fds[1]); + struct msghdr msg = {0}; + struct iovec iov; + static const unsigned kCrashContextSize = + sizeof(ExceptionHandler::CrashContext); + char context[kCrashContextSize]; + char control[kControlMsgSize]; + iov.iov_base = context; + iov.iov_len = kCrashContextSize; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = kControlMsgSize; + + const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0)); + ASSERT_EQ(static_cast(kCrashContextSize), n); + ASSERT_EQ(kControlMsgSize, msg.msg_controllen); + ASSERT_EQ(static_cast<__typeof__(msg.msg_flags)>(0), msg.msg_flags); + ASSERT_EQ(0, close(fds[0])); + + pid_t crashing_pid = -1; + int signal_fd = -1; + for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr; + hdr = CMSG_NXTHDR(&msg, hdr)) { + if (hdr->cmsg_level != SOL_SOCKET) + continue; + if (hdr->cmsg_type == SCM_RIGHTS) { + const unsigned len = hdr->cmsg_len - + (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); + ASSERT_EQ(sizeof(int), len); + signal_fd = *(reinterpret_cast(CMSG_DATA(hdr))); + } else if (hdr->cmsg_type == SCM_CREDENTIALS) { + const struct ucred *cred = + reinterpret_cast(CMSG_DATA(hdr)); + crashing_pid = cred->pid; + } + } + + ASSERT_NE(crashing_pid, -1); + ASSERT_NE(signal_fd, -1); + + AutoTempDir temp_dir; + string templ = temp_dir.path() + "/exception-handler-unittest"; + ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context, + kCrashContextSize)); + static const char b = 0; + ASSERT_EQ(1, (HANDLE_EINTR(write(signal_fd, &b, 1)))); + ASSERT_EQ(0, close(signal_fd)); + + ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); + + struct stat st; + ASSERT_EQ(0, stat(templ.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + unlink(templ.c_str()); +} + +#endif // !ADDRESS_SANITIZER + +TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) { + AutoTempDir temp_dir; + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, + NULL, false, -1); + ASSERT_TRUE(handler.WriteMinidump()); + + string minidump_path = handler.minidump_descriptor().path(); + + // Read the minidump and check the exception stream. + Minidump minidump(minidump_path); + ASSERT_TRUE(minidump.Read()); + MinidumpException* exception = minidump.GetException(); + ASSERT_TRUE(exception); + const MDRawExceptionStream* raw = exception->exception(); + ASSERT_TRUE(raw); + EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, + raw->exception_record.exception_code); +} + +TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) { + AutoTempDir temp_dir; + string path; + const int fd = CreateTMPFile(temp_dir.path(), &path); + ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1); + ASSERT_TRUE(handler.WriteMinidump()); + // Check by the size of the data written to the FD that a minidump was + // generated. + off_t size = lseek(fd, 0, SEEK_CUR); + ASSERT_GT(size, 0); + + // Generate another minidump. + ASSERT_TRUE(handler.WriteMinidump()); + size = lseek(fd, 0, SEEK_CUR); + ASSERT_GT(size, 0); +} + +TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) { + AutoTempDir temp_dir; + ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, + NULL, false, -1); + ASSERT_TRUE(handler.WriteMinidump()); + + const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor(); + struct stat st; + ASSERT_EQ(0, stat(minidump_1.path(), &st)); + ASSERT_GT(st.st_size, 0); + string minidump_1_path(minidump_1.path()); + // Check it is a valid minidump. + Minidump minidump1(minidump_1_path); + ASSERT_TRUE(minidump1.Read()); + unlink(minidump_1.path()); + + // Generate another minidump, it should go to a different file. + ASSERT_TRUE(handler.WriteMinidump()); + const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor(); + ASSERT_EQ(0, stat(minidump_2.path(), &st)); + ASSERT_GT(st.st_size, 0); + string minidump_2_path(minidump_2.path()); + // Check it is a valid minidump. + Minidump minidump2(minidump_2_path); + ASSERT_TRUE(minidump2.Read()); + unlink(minidump_2.path()); + + // 2 distinct files should be produced. + ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str()); +} + +// Test that an additional memory region can be added to the minidump. +TEST(ExceptionHandlerTest, AdditionalMemory) { + const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); + + // Get some heap memory. + uint8_t* memory = new uint8_t[kMemorySize]; + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + // Stick some data into the memory so the contents can be verified. + for (uint32_t i = 0; i < kMemorySize; ++i) { + memory[i] = i % 255; + } + + AutoTempDir temp_dir; + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + + // Add the memory region to the list of memory to be included. + handler.RegisterAppMemory(memory, kMemorySize); + handler.WriteMinidump(); + + const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); + + // Read the minidump. Ensure that the memory region is present + Minidump minidump(minidump_desc.path()); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(dump_memory_list); + const MinidumpMemoryRegion* region = + dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemoryAddress, region->GetBase()); + EXPECT_EQ(kMemorySize, region->GetSize()); + + // Verify memory contents. + EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize)); + + delete[] memory; +} + +// Test that a memory region that was previously registered +// can be unregistered. +TEST(ExceptionHandlerTest, AdditionalMemoryRemove) { + const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); + + // Get some heap memory. + uint8_t* memory = new uint8_t[kMemorySize]; + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + AutoTempDir temp_dir; + ExceptionHandler handler( + MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); + + // Add the memory region to the list of memory to be included. + handler.RegisterAppMemory(memory, kMemorySize); + + // ...and then remove it + handler.UnregisterAppMemory(memory); + handler.WriteMinidump(); + + const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); + + // Read the minidump. Ensure that the memory region is not present. + Minidump minidump(minidump_desc.path()); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(dump_memory_list); + const MinidumpMemoryRegion* region = + dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); + EXPECT_FALSE(region); + + delete[] memory; +} + +static bool SimpleCallback(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + string* filename = reinterpret_cast(context); + *filename = descriptor.path(); + return true; +} + +TEST(ExceptionHandlerTest, WriteMinidumpForChild) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + HANDLE_EINTR(read(fds[0], &b, sizeof(b))); + close(fds[0]); + syscall(__NR_exit); + } + close(fds[0]); + + AutoTempDir temp_dir; + string minidump_filename; + ASSERT_TRUE( + ExceptionHandler::WriteMinidumpForChild(child, child, + temp_dir.path(), SimpleCallback, + (void*)&minidump_filename)); + + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + // Check that the crashing thread is the main thread of |child| + MinidumpException* exception = minidump.GetException(); + ASSERT_TRUE(exception); + uint32_t thread_id; + ASSERT_TRUE(exception->GetThreadID(&thread_id)); + EXPECT_EQ(child, static_cast(thread_id)); + + const MDRawExceptionStream* raw = exception->exception(); + ASSERT_TRUE(raw); + EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, + raw->exception_record.exception_code); + + close(fds[1]); + unlink(minidump_filename.c_str()); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.cc b/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.cc new file mode 100644 index 0000000000..b0ef05bd9d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.cc @@ -0,0 +1,108 @@ +// 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 "linux/handler/guid_generator.h" + +#include +#include +#include +#include +#include +#include + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID since Linux has +// no native GUID generator. This should be OK since we don't expect +// crash to happen very offen. +// +class GUIDGenerator { + public: + static uint16_t BytesToUInt16(const uint8_t bytes[]) { + return ((uint16_t) bytes[1] << 8) | ((uint16_t) bytes[0]); + } + + // The last field in a GUID is 48 bits long so we're converting only 6 bytes + static uint64_t BytesToUInt48(const uint8_t bytes[]) { + return ((uint64_t) bytes[0] << 40) | ((uint64_t) bytes[1] << 32) | + ((uint64_t) bytes[2] << 24) | ((uint64_t) bytes[3] << 16) | + ((uint64_t) bytes[4] << 8) | (uint64_t) bytes[5]; + } + + static void UInt32ToBytes(uint8_t bytes[], uint32_t n) { + bytes[0] = n & 0xff; + bytes[1] = (n >> 8) & 0xff; + bytes[2] = (n >> 16) & 0xff; + bytes[3] = (n >> 24) & 0xff; + } + + static bool CreateGUID(GUID *guid) { + InitOnce(); + guid->data1 = random(); + guid->data2 = (uint16_t)(random()); + guid->data3 = (uint16_t)(random()); + UInt32ToBytes(&guid->data4[0], random()); + UInt32ToBytes(&guid->data4[4], random()); + return true; + } + + private: + static void InitOnce() { + pthread_once(&once_control, &InitOnceImpl); + } + + static void InitOnceImpl() { + srandom(time(NULL)); + } + + static pthread_once_t once_control; +}; + +pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; + +bool CreateGUID(GUID *guid) { + return GUIDGenerator::CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, size_t buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + GUIDGenerator::BytesToUInt16(&(guid->data4[0])), + GUIDGenerator::BytesToUInt48(&(guid->data4[2]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.h b/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.h new file mode 100644 index 0000000000..de97eda1cb --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/guid_generator.h @@ -0,0 +1,48 @@ +// 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 LINUX_HANDLER_GUID_GENERATOR_H__ +#define LINUX_HANDLER_GUID_GENERATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +const char kGUIDFormatString[] = "%08x-%04x-%04x-%04x-%012" PRIx64; +// Length of GUID string. Don't count the ending '\0'. +const size_t kGUIDStringLength = 36; + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, size_t buf_len); + +#endif diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/microdump_extra_info.h b/toolkit/crashreporter/breakpad-client/linux/handler/microdump_extra_info.h new file mode 100644 index 0000000000..bf01f0c7b1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/microdump_extra_info.h @@ -0,0 +1,52 @@ +// Copyright 2015 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_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_ +#define CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_ + +namespace google_breakpad { + +struct MicrodumpExtraInfo { + // Strings pointed to by this struct are not copied, and are + // expected to remain valid for the lifetime of the process. + const char* build_fingerprint; + const char* product_info; + const char* gpu_fingerprint; + const char* process_type; + + MicrodumpExtraInfo() + : build_fingerprint(NULL), + product_info(NULL), + gpu_fingerprint(NULL), + process_type(NULL) {} +}; + +} + +#endif // CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.cc b/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.cc new file mode 100644 index 0000000000..21cf4b0dce --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.cc @@ -0,0 +1,96 @@ +// Copyright (c) 2012 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 + +#include "linux/handler/guid_generator.h" +#include "linux/handler/minidump_descriptor.h" + +namespace google_breakpad { + +//static +const MinidumpDescriptor::MicrodumpOnConsole + MinidumpDescriptor::kMicrodumpOnConsole = {}; + +MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor) + : mode_(descriptor.mode_), + fd_(descriptor.fd_), + directory_(descriptor.directory_), + c_path_(NULL), + size_limit_(descriptor.size_limit_), + address_within_principal_mapping_( + descriptor.address_within_principal_mapping_), + skip_dump_if_principal_mapping_not_referenced_( + descriptor.skip_dump_if_principal_mapping_not_referenced_), + sanitize_stacks_(descriptor.sanitize_stacks_), + microdump_extra_info_(descriptor.microdump_extra_info_) { + // The copy constructor is not allowed to be called on a MinidumpDescriptor + // with a valid path_, as getting its c_path_ would require the heap which + // can cause problems in compromised environments. + assert(descriptor.path_.empty()); +} + +MinidumpDescriptor& MinidumpDescriptor::operator=( + const MinidumpDescriptor& descriptor) { + assert(descriptor.path_.empty()); + + mode_ = descriptor.mode_; + fd_ = descriptor.fd_; + directory_ = descriptor.directory_; + path_.clear(); + if (c_path_) { + // This descriptor already had a path set, so generate a new one. + c_path_ = NULL; + UpdatePath(); + } + size_limit_ = descriptor.size_limit_; + address_within_principal_mapping_ = + descriptor.address_within_principal_mapping_; + skip_dump_if_principal_mapping_not_referenced_ = + descriptor.skip_dump_if_principal_mapping_not_referenced_; + sanitize_stacks_ = descriptor.sanitize_stacks_; + microdump_extra_info_ = descriptor.microdump_extra_info_; + return *this; +} + +void MinidumpDescriptor::UpdatePath() { + assert(mode_ == kWriteMinidumpToFile && !directory_.empty()); + + GUID guid; + char guid_str[kGUIDStringLength + 1]; + if (!CreateGUID(&guid) || !GUIDToString(&guid, guid_str, sizeof(guid_str))) { + assert(false); + } + + path_.clear(); + path_ = directory_ + "/" + guid_str + ".dmp"; + c_path_ = path_.c_str(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h b/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h new file mode 100644 index 0000000000..c3deae8a74 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h @@ -0,0 +1,199 @@ +// Copyright (c) 2012 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_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ +#define CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ + +#include +#include + +#include + +#include "linux/handler/microdump_extra_info.h" +#include "common/using_std_string.h" + +// This class describes how a crash dump should be generated, either: +// - Writing a full minidump to a file in a given directory (the actual path, +// inside the directory, is determined by this class). +// - Writing a full minidump to a given fd. +// - Writing a reduced microdump to the console (logcat on Android). +namespace google_breakpad { + +class MinidumpDescriptor { + public: + struct MicrodumpOnConsole {}; + static const MicrodumpOnConsole kMicrodumpOnConsole; + + MinidumpDescriptor() + : mode_(kUninitialized), + fd_(-1), + size_limit_(-1), + address_within_principal_mapping_(0), + skip_dump_if_principal_mapping_not_referenced_(false) {} + + explicit MinidumpDescriptor(const string& directory) + : mode_(kWriteMinidumpToFile), + fd_(-1), + directory_(directory), + c_path_(NULL), + size_limit_(-1), + address_within_principal_mapping_(0), + skip_dump_if_principal_mapping_not_referenced_(false), + sanitize_stacks_(false) { + assert(!directory.empty()); + } + + explicit MinidumpDescriptor(int fd) + : mode_(kWriteMinidumpToFd), + fd_(fd), + c_path_(NULL), + size_limit_(-1), + address_within_principal_mapping_(0), + skip_dump_if_principal_mapping_not_referenced_(false), + sanitize_stacks_(false) { + assert(fd != -1); + } + + explicit MinidumpDescriptor(const MicrodumpOnConsole&) + : mode_(kWriteMicrodumpToConsole), + fd_(-1), + size_limit_(-1), + address_within_principal_mapping_(0), + skip_dump_if_principal_mapping_not_referenced_(false), + sanitize_stacks_(false) {} + + explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor); + MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor); + + static MinidumpDescriptor getMicrodumpDescriptor(); + + bool IsFD() const { return mode_ == kWriteMinidumpToFd; } + + int fd() const { return fd_; } + + string directory() const { return directory_; } + + const char* path() const { return c_path_; } + + bool IsMicrodumpOnConsole() const { + return mode_ == kWriteMicrodumpToConsole; + } + + // Updates the path so it is unique. + // Should be called from a normal context: this methods uses the heap. + void UpdatePath(); + + off_t size_limit() const { return size_limit_; } + void set_size_limit(off_t limit) { size_limit_ = limit; } + + uintptr_t address_within_principal_mapping() const { + return address_within_principal_mapping_; + } + void set_address_within_principal_mapping( + uintptr_t address_within_principal_mapping) { + address_within_principal_mapping_ = address_within_principal_mapping; + } + + bool skip_dump_if_principal_mapping_not_referenced() { + return skip_dump_if_principal_mapping_not_referenced_; + } + void set_skip_dump_if_principal_mapping_not_referenced( + bool skip_dump_if_principal_mapping_not_referenced) { + skip_dump_if_principal_mapping_not_referenced_ = + skip_dump_if_principal_mapping_not_referenced; + } + + bool sanitize_stacks() const { return sanitize_stacks_; } + void set_sanitize_stacks(bool sanitize_stacks) { + sanitize_stacks_ = sanitize_stacks; + } + + MicrodumpExtraInfo* microdump_extra_info() { + assert(IsMicrodumpOnConsole()); + return µdump_extra_info_; + } + + private: + enum DumpMode { + kUninitialized = 0, + kWriteMinidumpToFile, + kWriteMinidumpToFd, + kWriteMicrodumpToConsole + }; + + // Specifies the dump mode (see DumpMode). + DumpMode mode_; + + // The file descriptor where the minidump is generated. + int fd_; + + // The directory where the minidump should be generated. + string directory_; + + // The full path to the generated minidump. + string path_; + + // The C string of |path_|. Precomputed so it can be access from a compromised + // context. + const char* c_path_; + + off_t size_limit_; + + // This member points somewhere into the main module for this + // process (the module that is considerered interesting for the + // purposes of debugging crashes). + uintptr_t address_within_principal_mapping_; + + // If set, threads that do not reference the address range + // associated with |address_within_principal_mapping_| will not have their + // stacks logged. + bool skip_dump_if_principal_mapping_not_referenced_; + + // If set, stacks are sanitized to remove PII. This involves + // overwriting any pointer-aligned words that are not either + // pointers into a process mapping or small integers (+/-4096). This + // leaves enough information to unwind stacks, and preserve some + // register values, but elides strings and other program data. + bool sanitize_stacks_; + + // The extra microdump data (e.g. product name/version, build + // fingerprint, gpu fingerprint) that should be appended to the dump + // (microdump only). Microdumps don't have the ability of appending + // extra metadata after the dump is generated (as opposite to + // minidumps MIME fields), therefore the extra data must be provided + // upfront. Any memory pointed to by members of the + // MicrodumpExtraInfo struct must be valid for the lifetime of the + // process (read: the caller has to guarantee that it is stored in + // global static storage.) + MicrodumpExtraInfo microdump_extra_info_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/log/log.cc b/toolkit/crashreporter/breakpad-client/linux/log/log.cc new file mode 100644 index 0000000000..3346acc6d8 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/log/log.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2012 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 "linux/log/log.h" + +#if defined(__ANDROID__) +#include +#include +#else +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace logger { + +#if defined(__ANDROID__) +namespace { + +// __android_log_buf_write() is not exported in the NDK and is being used by +// dynamic runtime linking. Its declaration is taken from Android's +// system/core/include/log/log.h. +using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag, + const char *text); +const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h. +const char kAndroidLogTag[] = "google-breakpad"; + +bool g_crash_log_initialized = false; +AndroidLogBufferWriteFunc g_android_log_buf_write = nullptr; + +} // namespace + +void initializeCrashLogWriter() { + if (g_crash_log_initialized) + return; + g_android_log_buf_write = reinterpret_cast( + dlsym(RTLD_DEFAULT, "__android_log_buf_write")); + g_crash_log_initialized = true; +} + +int writeToCrashLog(const char* buf) { + // Try writing to the crash log ring buffer. If not available, fall back to + // the standard log buffer. + if (g_android_log_buf_write) { + return g_android_log_buf_write(kAndroidCrashLogId, ANDROID_LOG_FATAL, + kAndroidLogTag, buf); + } + return __android_log_write(ANDROID_LOG_FATAL, kAndroidLogTag, buf); +} +#endif + +int write(const char* buf, size_t nbytes) { +#if defined(__ANDROID__) + return __android_log_write(ANDROID_LOG_WARN, kAndroidLogTag, buf); +#else + return sys_write(2, buf, nbytes); +#endif +} + +} // namespace logger diff --git a/toolkit/crashreporter/breakpad-client/linux/log/log.h b/toolkit/crashreporter/breakpad-client/linux/log/log.h new file mode 100644 index 0000000000..f94bbd5fb7 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/log/log.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012, 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_LINUX_LOG_LOG_H_ +#define CLIENT_LINUX_LOG_LOG_H_ + +#include + +namespace logger { + +int write(const char* buf, size_t nbytes); + +// In the case of Android the log can be written to the default system log +// (default behavior of write() above, or to the crash log (see +// writeToCrashLog() below). +#if defined(__ANDROID__) + +// The logger must be initialized in a non-compromised context. +void initializeCrashLogWriter(); + +// Once initialized, writeToCrashLog is safe to use in a compromised context, +// even if the initialization failed, in which case this will silently fall +// back on write(). +int writeToCrashLog(const char* buf); +#endif + +} // namespace logger + +#endif // CLIENT_LINUX_LOG_LOG_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.cc b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.cc new file mode 100644 index 0000000000..8f25b7be02 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.cc @@ -0,0 +1,664 @@ +// Copyright (c) 2014, 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. + +// This translation unit generates microdumps into the console (logcat on +// Android). See crbug.com/410294 for more info and design docs. + +#include "linux/microdump_writer/microdump_writer.h" + +#include + +#include + +#include "linux/dump_writer_common/thread_info.h" +#include "linux/dump_writer_common/ucontext_reader.h" +#include "linux/handler/exception_handler.h" +#include "linux/handler/microdump_extra_info.h" +#include "linux/log/log.h" +#include "linux/minidump_writer/linux_ptrace_dumper.h" +#include "common/linux/file_id.h" +#include "common/linux/linux_libc_support.h" +#include "common/memory_allocator.h" + +namespace { + +using google_breakpad::auto_wasteful_vector; +using google_breakpad::ExceptionHandler; +using google_breakpad::kDefaultBuildIdSize; +using google_breakpad::LinuxDumper; +using google_breakpad::LinuxPtraceDumper; +using google_breakpad::MappingInfo; +using google_breakpad::MappingList; +using google_breakpad::MicrodumpExtraInfo; +using google_breakpad::RawContextCPU; +using google_breakpad::ThreadInfo; +using google_breakpad::UContextReader; + +const size_t kLineBufferSize = 2048; + +#if !defined(__LP64__) +// The following are only used by DumpFreeSpace, so need to be compiled +// in conditionally in the same way. + +template +Dst saturated_cast(Src src) { + if (src >= std::numeric_limits::max()) + return std::numeric_limits::max(); + if (src <= std::numeric_limits::min()) + return std::numeric_limits::min(); + return static_cast(src); +} + +int Log2Floor(uint64_t n) { + // Copied from chromium src/base/bits.h + if (n == 0) + return -1; + int log = 0; + uint64_t value = n; + for (int i = 5; i >= 0; --i) { + int shift = (1 << i); + uint64_t x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + assert(value == 1u); + return log; +} + +bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) { + // Because of load biasing, we can end up with a situation where two + // mappings actually overlap. So we will define adjacency to also include a + // b start address that lies within a's address range (including starting + // immediately after a). + // Because load biasing only ever moves the start address backwards, the end + // address should still increase. + return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr; +} + +bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) { + // Return true if mapping a is before mapping b. + // For the same reason (load biasing) we compare end addresses, which - unlike + // start addresses - will not have been modified. + return a->start_addr + a->size < b->start_addr + b->size; +} + +size_t NextOrderedMapping( + const google_breakpad::wasteful_vector& mappings, + size_t curr) { + // Find the mapping that directly follows mappings[curr]. + // If no such mapping exists, return |invalid| to indicate this. + const size_t invalid = std::numeric_limits::max(); + size_t best = invalid; + for (size_t next = 0; next < mappings.size(); ++next) { + if (MappingLessThan(mappings[curr], mappings[next]) && + (best == invalid || MappingLessThan(mappings[next], mappings[best]))) { + best = next; + } + } + return best; +} + +#endif // !__LP64__ + +class MicrodumpWriter { + public: + MicrodumpWriter(const ExceptionHandler::CrashContext* context, + const MappingList& mappings, + bool skip_dump_if_principal_mapping_not_referenced, + uintptr_t address_within_principal_mapping, + bool sanitize_stack, + const MicrodumpExtraInfo& microdump_extra_info, + LinuxDumper* dumper) + : ucontext_(context ? &context->context : NULL), +#if !defined(__ARM_EABI__) && !defined(__mips__) + float_state_(context ? &context->float_state : NULL), +#endif + dumper_(dumper), + mapping_list_(mappings), + skip_dump_if_principal_mapping_not_referenced_( + skip_dump_if_principal_mapping_not_referenced), + address_within_principal_mapping_(address_within_principal_mapping), + sanitize_stack_(sanitize_stack), + microdump_extra_info_(microdump_extra_info), + log_line_(NULL), + stack_copy_(NULL), + stack_len_(0), + stack_lower_bound_(0), + stack_pointer_(0) { + log_line_ = reinterpret_cast(Alloc(kLineBufferSize)); + if (log_line_) + log_line_[0] = '\0'; // Clear out the log line buffer. + } + + ~MicrodumpWriter() { dumper_->ThreadsResume(); } + + bool Init() { + // In the exceptional case where the system was out of memory and there + // wasn't even room to allocate the line buffer, bail out. There is nothing + // useful we can possibly achieve without the ability to Log. At least let's + // try to not crash. + if (!dumper_->Init() || !log_line_) + return false; + return dumper_->ThreadsSuspend() && dumper_->LateInit(); + } + + void Dump() { + CaptureResult stack_capture_result = CaptureCrashingThreadStack(-1); + if (stack_capture_result == CAPTURE_UNINTERESTING) { + LogLine("Microdump skipped (uninteresting)"); + return; + } + + LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); + DumpProductInformation(); + DumpOSInformation(); + DumpProcessType(); + DumpCrashReason(); + DumpGPUInformation(); +#if !defined(__LP64__) + DumpFreeSpace(); +#endif + if (stack_capture_result == CAPTURE_OK) + DumpThreadStack(); + DumpCPUState(); + DumpMappings(); + LogLine("-----END BREAKPAD MICRODUMP-----"); + } + + private: + enum CaptureResult { CAPTURE_OK, CAPTURE_FAILED, CAPTURE_UNINTERESTING }; + + // Writes one line to the system log. + void LogLine(const char* msg) { +#if defined(__ANDROID__) + logger::writeToCrashLog(msg); +#else + logger::write(msg, my_strlen(msg)); + logger::write("\n", 1); +#endif + } + + // Stages the given string in the current line buffer. + void LogAppend(const char* str) { + my_strlcat(log_line_, str, kLineBufferSize); + } + + // As above (required to take precedence over template specialization below). + void LogAppend(char* str) { + LogAppend(const_cast(str)); + } + + // Stages the hex repr. of the given int type in the current line buffer. + template + void LogAppend(T value) { + // Make enough room to hex encode the largest int type + NUL. + static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + char hexstr[sizeof(T) * 2 + 1]; + for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4) + hexstr[i] = HEX[static_cast(value) & 0x0F]; + hexstr[sizeof(T) * 2] = '\0'; + LogAppend(hexstr); + } + + // Stages the buffer content hex-encoded in the current line buffer. + void LogAppend(const void* buf, size_t length) { + const uint8_t* ptr = reinterpret_cast(buf); + for (size_t i = 0; i < length; ++i, ++ptr) + LogAppend(*ptr); + } + + // Writes out the current line buffer on the system log. + void LogCommitLine() { + LogLine(log_line_); + log_line_[0] = 0; + } + + CaptureResult CaptureCrashingThreadStack(int max_stack_len) { + stack_pointer_ = UContextReader::GetStackPointer(ucontext_); + + if (!dumper_->GetStackInfo(reinterpret_cast(&stack_lower_bound_), + &stack_len_, stack_pointer_)) { + return CAPTURE_FAILED; + } + + if (max_stack_len >= 0 && + stack_len_ > static_cast(max_stack_len)) { + stack_len_ = max_stack_len; + } + + stack_copy_ = reinterpret_cast(Alloc(stack_len_)); + dumper_->CopyFromProcess(stack_copy_, dumper_->crash_thread(), + reinterpret_cast(stack_lower_bound_), + stack_len_); + + if (!skip_dump_if_principal_mapping_not_referenced_) return CAPTURE_OK; + + const MappingInfo* principal_mapping = + dumper_->FindMappingNoBias(address_within_principal_mapping_); + if (!principal_mapping) return CAPTURE_UNINTERESTING; + + uintptr_t low_addr = principal_mapping->system_mapping_info.start_addr; + uintptr_t high_addr = principal_mapping->system_mapping_info.end_addr; + uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_); + if (low_addr <= pc && pc <= high_addr) return CAPTURE_OK; + + if (dumper_->StackHasPointerToMapping(stack_copy_, stack_len_, + stack_pointer_ - stack_lower_bound_, + *principal_mapping)) { + return CAPTURE_OK; + } + return CAPTURE_UNINTERESTING; + } + + void DumpProductInformation() { + LogAppend("V "); + if (microdump_extra_info_.product_info) { + LogAppend(microdump_extra_info_.product_info); + } else { + LogAppend("UNKNOWN:0.0.0.0"); + } + LogCommitLine(); + } + + void DumpProcessType() { + LogAppend("P "); + if (microdump_extra_info_.process_type) { + LogAppend(microdump_extra_info_.process_type); + } else { + LogAppend("UNKNOWN"); + } + LogCommitLine(); + } + + void DumpCrashReason() { + LogAppend("R "); + LogAppend(dumper_->crash_signal()); + LogAppend(" "); + LogAppend(dumper_->GetCrashSignalString()); + LogAppend(" "); + LogAppend(dumper_->crash_address()); + LogCommitLine(); + } + + void DumpOSInformation() { + const uint8_t n_cpus = static_cast(sysconf(_SC_NPROCESSORS_CONF)); + +#if defined(__ANDROID__) + const char kOSId[] = "A"; +#else + const char kOSId[] = "L"; +#endif + +// Dump the runtime architecture. On multiarch devices it might not match the +// hw architecture (the one returned by uname()), for instance in the case of +// a 32-bit app running on a aarch64 device. +#if defined(__aarch64__) + const char kArch[] = "arm64"; +#elif defined(__ARMEL__) + const char kArch[] = "arm"; +#elif defined(__x86_64__) + const char kArch[] = "x86_64"; +#elif defined(__i386__) + const char kArch[] = "x86"; +#elif defined(__mips__) +# if _MIPS_SIM == _ABIO32 + const char kArch[] = "mips"; +# elif _MIPS_SIM == _ABI64 + const char kArch[] = "mips64"; +# else +# error "This mips ABI is currently not supported (n32)" +#endif +#else +#error "This code has not been ported to your platform yet" +#endif + + LogAppend("O "); + LogAppend(kOSId); + LogAppend(" "); + LogAppend(kArch); + LogAppend(" "); + LogAppend(n_cpus); + LogAppend(" "); + + // Dump the HW architecture (e.g., armv7l, aarch64). + struct utsname uts; + const bool has_uts_info = (uname(&uts) == 0); + const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch"; + LogAppend(hwArch); + LogAppend(" "); + + // If the client has attached a build fingerprint to the MinidumpDescriptor + // use that one. Otherwise try to get some basic info from uname(). + if (microdump_extra_info_.build_fingerprint) { + LogAppend(microdump_extra_info_.build_fingerprint); + } else if (has_uts_info) { + LogAppend(uts.release); + LogAppend(" "); + LogAppend(uts.version); + } else { + LogAppend("no build fingerprint available"); + } + LogCommitLine(); + } + + void DumpGPUInformation() { + LogAppend("G "); + if (microdump_extra_info_.gpu_fingerprint) { + LogAppend(microdump_extra_info_.gpu_fingerprint); + } else { + LogAppend("UNKNOWN"); + } + LogCommitLine(); + } + + void DumpThreadStack() { + if (sanitize_stack_) { + dumper_->SanitizeStackCopy(stack_copy_, stack_len_, stack_pointer_, + stack_pointer_ - stack_lower_bound_); + } + + LogAppend("S 0 "); + LogAppend(stack_pointer_); + LogAppend(" "); + LogAppend(stack_lower_bound_); + LogAppend(" "); + LogAppend(stack_len_); + LogCommitLine(); + + const size_t STACK_DUMP_CHUNK_SIZE = 384; + for (size_t stack_off = 0; stack_off < stack_len_; + stack_off += STACK_DUMP_CHUNK_SIZE) { + LogAppend("S "); + LogAppend(stack_lower_bound_ + stack_off); + LogAppend(" "); + LogAppend(stack_copy_ + stack_off, + std::min(STACK_DUMP_CHUNK_SIZE, stack_len_ - stack_off)); + LogCommitLine(); + } + } + + void DumpCPUState() { + RawContextCPU cpu; + my_memset(&cpu, 0, sizeof(RawContextCPU)); +#if !defined(__ARM_EABI__) && !defined(__mips__) + UContextReader::FillCPUContext(&cpu, ucontext_, float_state_); +#else + UContextReader::FillCPUContext(&cpu, ucontext_); +#endif + LogAppend("C "); + LogAppend(&cpu, sizeof(cpu)); + LogCommitLine(); + } + + // If there is caller-provided information about this mapping + // in the mapping_list_ list, return true. Otherwise, return false. + bool HaveMappingInfo(const MappingInfo& mapping) { + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + // Ignore any mappings that are wholly contained within + // mappings in the mapping_info_ list. + if (mapping.start_addr >= iter->first.start_addr && + (mapping.start_addr + mapping.size) <= + (iter->first.start_addr + iter->first.size)) { + return true; + } + } + return false; + } + + // Dump information about the provided |mapping|. If |identifier| is non-NULL, + // use it instead of calculating a file ID from the mapping. + void DumpModule(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + const std::vector* identifier) { + + auto_wasteful_vector identifier_bytes( + dumper_->allocator()); + + if (identifier) { + // GUID was provided by caller. + identifier_bytes.insert(identifier_bytes.end(), + identifier->begin(), + identifier->end()); + } else { + dumper_->ElfFileIdentifierForMapping( + mapping, + member, + mapping_id, + identifier_bytes); + } + + // Copy as many bytes of |identifier| as will fit into a MDGUID + MDGUID module_identifier = {0}; + memcpy(&module_identifier, &identifier_bytes[0], + std::min(sizeof(MDGUID), identifier_bytes.size())); + + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + dumper_->GetMappingEffectiveNameAndPath( + mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); + + LogAppend("M "); + LogAppend(static_cast(mapping.start_addr)); + LogAppend(" "); + LogAppend(mapping.offset); + LogAppend(" "); + LogAppend(mapping.size); + LogAppend(" "); + LogAppend(module_identifier.data1); + LogAppend(module_identifier.data2); + LogAppend(module_identifier.data3); + LogAppend(module_identifier.data4[0]); + LogAppend(module_identifier.data4[1]); + LogAppend(module_identifier.data4[2]); + LogAppend(module_identifier.data4[3]); + LogAppend(module_identifier.data4[4]); + LogAppend(module_identifier.data4[5]); + LogAppend(module_identifier.data4[6]); + LogAppend(module_identifier.data4[7]); + LogAppend("0 "); // Age is always 0 on Linux. + LogAppend(file_name); + LogCommitLine(); + } + +#if !defined(__LP64__) + void DumpFreeSpace() { + const MappingInfo* stack_mapping = nullptr; + ThreadInfo info; + if (dumper_->GetThreadInfoByIndex(dumper_->GetMainThreadIndex(), &info)) { + stack_mapping = dumper_->FindMappingNoBias(info.stack_pointer); + } + + const google_breakpad::wasteful_vector& mappings = + dumper_->mappings(); + if (mappings.size() == 0) return; + + // This is complicated by the fact that mappings is not in order. It should + // be mostly in order, however the mapping that contains the entry point for + // the process is always at the front of the vector. + + static const int HBITS = sizeof(size_t) * 8; + size_t hole_histogram[HBITS]; + my_memset(hole_histogram, 0, sizeof(hole_histogram)); + + // Find the lowest address mapping. + size_t curr = 0; + for (size_t i = 1; i < mappings.size(); ++i) { + if (mappings[i]->start_addr < mappings[curr]->start_addr) curr = i; + } + + uintptr_t lo_addr = mappings[curr]->start_addr; + + size_t hole_cnt = 0; + size_t hole_max = 0; + size_t hole_sum = 0; + + while (true) { + // Skip to the end of an adjacent run of mappings. This is an optimization + // for the fact that mappings is mostly sorted. + while (curr != mappings.size() - 1 && + MappingsAreAdjacent(*mappings[curr], *mappings[curr + 1])) { + ++curr; + } + + if (mappings[curr] == stack_mapping) { + // Because we can't determine the top of userspace mappable + // memory we treat the start of the process stack as the top + // of the allocatable address space. Once we reach + // |stack_mapping| we are done scanning for free space regions. + break; + } + + size_t next = NextOrderedMapping(mappings, curr); + if (next == std::numeric_limits::max()) + break; + + uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size; + uintptr_t hole_hi = mappings[next]->start_addr; + + if (hole_hi > hole_lo) { + size_t hole_sz = hole_hi - hole_lo; + hole_sum += hole_sz; + hole_max = std::max(hole_sz, hole_max); + ++hole_cnt; + ++hole_histogram[Log2Floor(hole_sz)]; + } + curr = next; + } + + uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size; + + LogAppend("H "); + LogAppend(lo_addr); + LogAppend(" "); + LogAppend(hi_addr); + LogAppend(" "); + LogAppend(saturated_cast(hole_cnt)); + LogAppend(" "); + LogAppend(hole_max); + LogAppend(" "); + LogAppend(hole_sum); + for (unsigned int i = 0; i < HBITS; ++i) { + if (!hole_histogram[i]) continue; + LogAppend(" "); + LogAppend(saturated_cast(i)); + LogAppend(":"); + LogAppend(saturated_cast(hole_histogram[i])); + } + LogCommitLine(); + } +#endif + + // Write information about the mappings in effect. + void DumpMappings() { + // First write all the mappings from the dumper + for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (mapping.name[0] == 0 || // only want modules with filenames. + !mapping.exec || // only want executable mappings. + mapping.size < 4096 || // too small to get a signature for. + HaveMappingInfo(mapping)) { + continue; + } + + DumpModule(mapping, true, i, NULL); + } + // Next write all the mappings provided by the caller + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + DumpModule(iter->first, false, 0, &iter->second); + } + } + + void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } + + const ucontext_t* const ucontext_; +#if !defined(__ARM_EABI__) && !defined(__mips__) + const google_breakpad::fpstate_t* const float_state_; +#endif + LinuxDumper* dumper_; + const MappingList& mapping_list_; + bool skip_dump_if_principal_mapping_not_referenced_; + uintptr_t address_within_principal_mapping_; + bool sanitize_stack_; + const MicrodumpExtraInfo microdump_extra_info_; + char* log_line_; + + // The local copy of crashed process stack memory, beginning at + // |stack_lower_bound_|. + uint8_t* stack_copy_; + + // The length of crashed process stack copy. + size_t stack_len_; + + // The address of the page containing the stack pointer in the + // crashed process. |stack_lower_bound_| <= |stack_pointer_| + uintptr_t stack_lower_bound_; + + // The stack pointer of the crashed thread. + uintptr_t stack_pointer_; +}; +} // namespace + +namespace google_breakpad { + +bool WriteMicrodump(pid_t crashing_process, + const void* blob, + size_t blob_size, + const MappingList& mappings, + bool skip_dump_if_principal_mapping_not_referenced, + uintptr_t address_within_principal_mapping, + bool sanitize_stack, + const MicrodumpExtraInfo& microdump_extra_info) { + LinuxPtraceDumper dumper(crashing_process); + const ExceptionHandler::CrashContext* context = NULL; + if (blob) { + if (blob_size != sizeof(ExceptionHandler::CrashContext)) + return false; + context = reinterpret_cast(blob); + dumper.SetCrashInfoFromSigInfo(context->siginfo); + dumper.set_crash_thread(context->tid); + } + MicrodumpWriter writer(context, mappings, + skip_dump_if_principal_mapping_not_referenced, + address_within_principal_mapping, sanitize_stack, + microdump_extra_info, &dumper); + if (!writer.Init()) + return false; + writer.Dump(); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.h b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.h new file mode 100644 index 0000000000..63b5463247 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer.h @@ -0,0 +1,68 @@ +// Copyright (c) 2014, 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_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ + +#include +#include + +#include "linux/dump_writer_common/mapping_info.h" + +namespace google_breakpad { + +struct MicrodumpExtraInfo; + +// Writes a microdump (a reduced dump containing only the state of the crashing +// thread) on the console (logcat on Android). These functions do not malloc nor +// use libc functions which may. Thus, it can be used in contexts where the +// state of the heap may be corrupt. +// Args: +// crashing_process: the pid of the crashing process. This must be trusted. +// blob: a blob of data from the crashing process. See exception_handler.h +// blob_size: the length of |blob| in bytes. +// mappings: a list of additional mappings provided by the application. +// build_fingerprint: a (optional) C string which determines the OS +// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys). +// product_info: a (optional) C string which determines the product name and +// version (e.g., WebView:42.0.2311.136). +// +// Returns true iff successful. +bool WriteMicrodump(pid_t crashing_process, + const void* blob, + size_t blob_size, + const MappingList& mappings, + bool skip_dump_if_main_module_not_referenced, + uintptr_t address_within_main_module, + bool sanitize_stack, + const MicrodumpExtraInfo& microdump_extra_info); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer_unittest.cc new file mode 100644 index 0000000000..6b7fb5f6ac --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/microdump_writer/microdump_writer_unittest.cc @@ -0,0 +1,421 @@ +// Copyright (c) 2014 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 +#include +#include +#include +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "linux/handler/exception_handler.h" +#include "linux/handler/microdump_extra_info.h" +#include "linux/microdump_writer/microdump_writer.h" +#include "common/linux/breakpad_getcontext.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/ignore_ret.h" +#include "common/scoped_ptr.h" +#include "common/tests/auto_tempdir.h" +#include "common/using_std_string.h" + +using namespace google_breakpad; + +extern "C" { +extern char __executable_start; +extern char __etext; +} + +namespace { + +typedef testing::Test MicrodumpWriterTest; + +MicrodumpExtraInfo MakeMicrodumpExtraInfo( + const char* build_fingerprint, + const char* product_info, + const char* gpu_fingerprint) { + MicrodumpExtraInfo info; + info.build_fingerprint = build_fingerprint; + info.product_info = product_info; + info.gpu_fingerprint = gpu_fingerprint; + info.process_type = "Browser"; + return info; +} + +bool ContainsMicrodump(const std::string& buf) { + return std::string::npos != buf.find("-----BEGIN BREAKPAD MICRODUMP-----") && + std::string::npos != buf.find("-----END BREAKPAD MICRODUMP-----"); +} + +const char kIdentifiableString[] = "_IDENTIFIABLE_"; +const uintptr_t kCrashAddress = 0xdeaddeadu; + +void CrashAndGetMicrodump(const MappingList& mappings, + const MicrodumpExtraInfo& microdump_extra_info, + std::string* microdump, + bool skip_dump_if_principal_mapping_not_referenced = false, + uintptr_t address_within_principal_mapping = 0, + bool sanitize_stack = false) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + AutoTempDir temp_dir; + string stderr_file = temp_dir.path() + "/stderr.log"; + int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + ASSERT_NE(-1, err_fd); + + char identifiable_string[sizeof(kIdentifiableString)]; + + // This string should not appear in the resulting microdump if it + // has been sanitized. + strcpy(identifiable_string, kIdentifiableString); + // Force the strcpy to not be optimized away. + IGNORE_RET(write(STDOUT_FILENO, identifiable_string, 0)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + // Pretend the current context is the child context (which is + // approximately right) so that we have a valid stack pointer, and + // can fetch child stack data via ptrace. + getcontext(&context.context); + // Set a non-zero tid to avoid tripping asserts. + context.tid = child; + context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED; + context.siginfo.si_addr = reinterpret_cast(kCrashAddress); + + // Redirect temporarily stderr to the stderr.log file. + int save_err = dup(STDERR_FILENO); + ASSERT_NE(-1, save_err); + ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); + + ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, + skip_dump_if_principal_mapping_not_referenced, + address_within_principal_mapping, sanitize_stack, + microdump_extra_info)); + + // Revert stderr back to the console. + dup2(save_err, STDERR_FILENO); + close(save_err); + + // Read back the stderr file and check for the microdump marker. + fsync(err_fd); + lseek(err_fd, 0, SEEK_SET); + + microdump->clear(); + char buf[1024]; + + while (true) { + int bytes_read = IGNORE_EINTR(read(err_fd, buf, 1024)); + if (bytes_read <= 0) break; + microdump->append(buf, buf + bytes_read); + } + close(err_fd); + close(fds[1]); +} + +void ExtractMicrodumpStackContents(const string& microdump_content, + string* result) { + std::istringstream iss(microdump_content); + result->clear(); + for (string line; std::getline(iss, line);) { + if (line.find("S ") == 0) { + std::istringstream stack_data(line); + std::string key; + std::string addr; + std::string data; + stack_data >> key >> addr >> data; + EXPECT_TRUE((data.size() & 1u) == 0u); + result->reserve(result->size() + data.size() / 2); + for (size_t i = 0; i < data.size(); i += 2) { + std::string byte = data.substr(i, 2); + result->push_back(static_cast(strtoul(byte.c_str(), NULL, 16))); + } + } + } +} + +void CheckMicrodumpContents(const string& microdump_content, + const MicrodumpExtraInfo& expected_info) { + std::istringstream iss(microdump_content); + bool did_find_os_info = false; + bool did_find_product_info = false; + bool did_find_process_type = false; + bool did_find_crash_reason = false; + bool did_find_gpu_info = false; + for (string line; std::getline(iss, line);) { + if (line.find("O ") == 0) { + std::istringstream os_info_tokens(line); + string token; + os_info_tokens.ignore(2); // Ignore the "O " preamble. + // Check the OS descriptor char (L=Linux, A=Android). + os_info_tokens >> token; + ASSERT_TRUE(token == "L" || token == "A"); + + os_info_tokens >> token; // HW architecture. + os_info_tokens >> token; // Number of cpus. + for (size_t i = 0; i < token.size(); ++i) + ASSERT_TRUE(isxdigit(token[i])); + os_info_tokens >> token; // SW architecture. + + // Check that the build fingerprint is in the right place. + os_info_tokens >> token; + ASSERT_FALSE(os_info_tokens.fail()); + if (expected_info.build_fingerprint) + ASSERT_EQ(expected_info.build_fingerprint, token); + did_find_os_info = true; + } else if (line.find("P ") == 0) { + if (expected_info.process_type) + ASSERT_EQ(string("P ") + expected_info.process_type, line); + did_find_process_type = true; + } else if (line.find("R ") == 0) { + std::istringstream crash_reason_tokens(line); + string token; + unsigned crash_reason; + string crash_reason_str; + uintptr_t crash_address; + crash_reason_tokens.ignore(2); // Ignore the "R " preamble. + crash_reason_tokens >> std::hex >> crash_reason >> crash_reason_str >> + crash_address; + ASSERT_FALSE(crash_reason_tokens.fail()); + ASSERT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, crash_reason); + ASSERT_EQ("DUMP_REQUESTED", crash_reason_str); + ASSERT_EQ(kCrashAddress, crash_address); + did_find_crash_reason = true; + } else if (line.find("V ") == 0) { + if (expected_info.product_info) + ASSERT_EQ(string("V ") + expected_info.product_info, line); + did_find_product_info = true; + } else if (line.find("G ") == 0) { + if (expected_info.gpu_fingerprint) + ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line); + did_find_gpu_info = true; + } + } + ASSERT_TRUE(did_find_os_info); + ASSERT_TRUE(did_find_product_info); + ASSERT_TRUE(did_find_process_type); + ASSERT_TRUE(did_find_crash_reason); + ASSERT_TRUE(did_find_gpu_info); +} + +bool MicrodumpStackContains(const string& microdump_content, + const string& expected_content) { + string result; + ExtractMicrodumpStackContents(microdump_content, &result); + return result.find(kIdentifiableString) != string::npos; +} + +void CheckMicrodumpContents(const string& microdump_content, + const string& expected_fingerprint, + const string& expected_product_info, + const string& expected_gpu_fingerprint) { + CheckMicrodumpContents( + microdump_content, + MakeMicrodumpExtraInfo(expected_fingerprint.c_str(), + expected_product_info.c_str(), + expected_gpu_fingerprint.c_str())); +} + +TEST(MicrodumpWriterTest, BasicWithMappings) { + // Push some extra mapping to check the MappingList logic. + const uint32_t memory_size = sysconf(_SC_PAGESIZE); + const char* kMemoryName = "libfoo.so"; + const uint8_t kModuleGUID[sizeof(MDGUID)] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + + MappingInfo info; + info.start_addr = memory_size; + info.size = memory_size; + info.offset = 42; + strcpy(info.name, kMemoryName); + + MappingList mappings; + MappingEntry mapping; + mapping.first = info; + mapping.second.assign(std::begin(kModuleGUID), std::end(kModuleGUID)); + mappings.push_back(mapping); + + std::string buf; + CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf); + ASSERT_TRUE(ContainsMicrodump(buf)); + +#ifdef __LP64__ + ASSERT_NE(std::string::npos, + buf.find("M 0000000000001000 000000000000002A 0000000000001000 " + "33221100554477668899AABBCCDDEEFF0 libfoo.so")); +#else + ASSERT_NE(std::string::npos, + buf.find("M 00001000 0000002A 00001000 " + "33221100554477668899AABBCCDDEEFF0 libfoo.so")); +#endif + + // In absence of a product info in the minidump, the writer should just write + // an unknown marker. + ASSERT_NE(std::string::npos, buf.find("V UNKNOWN:0.0.0.0")); +} + +// Ensure that no output occurs if the interest region is set, but +// doesn't overlap anything on the stack. +TEST(MicrodumpWriterTest, NoOutputIfUninteresting) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true, 0); + ASSERT_FALSE(ContainsMicrodump(buf)); +} + +// Ensure that stack content does not contain an identifiable string if the +// stack is sanitized. +TEST(MicrodumpWriterTest, StringRemovedBySanitization) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, true); + ASSERT_TRUE(ContainsMicrodump(buf)); + ASSERT_FALSE(MicrodumpStackContains(buf, kIdentifiableString)); +} + +// Ensure that stack content does contain an identifiable string if the +// stack is not sanitized. +TEST(MicrodumpWriterTest, StringPresentIfNotSanitized) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, false, 0u, false); + ASSERT_TRUE(ContainsMicrodump(buf)); + ASSERT_TRUE(MicrodumpStackContains(buf, kIdentifiableString)); +} + +// Ensure that output occurs if the interest region is set, and +// does overlap something on the stack. +TEST(MicrodumpWriterTest, OutputIfInteresting) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf, true, + reinterpret_cast(CrashAndGetMicrodump)); + ASSERT_TRUE(ContainsMicrodump(buf)); +} + +// Ensure that the product info and build fingerprint metadata show up in the +// final microdump if present. +TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); + ASSERT_TRUE(ContainsMicrodump(buf)); + CheckMicrodumpContents(buf, kMicrodumpExtraInfo); +} + +TEST(MicrodumpWriterTest, NoProductInfo) { + const char kBuildFingerprint[] = "foobar"; + const char kGPUFingerprint[] = "bazqux"; + std::string buf; + MappingList no_mappings; + + const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint)); + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); + ASSERT_TRUE(ContainsMicrodump(buf)); + CheckMicrodumpContents(buf, kBuildFingerprint, "UNKNOWN:0.0.0.0", + kGPUFingerprint); +} + +TEST(MicrodumpWriterTest, NoGPUInfo) { + const char kProductInfo[] = "bazqux"; + const char kBuildFingerprint[] = "foobar"; + std::string buf; + MappingList no_mappings; + + const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL)); + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf); + ASSERT_TRUE(ContainsMicrodump(buf)); + CheckMicrodumpContents(buf, kBuildFingerprint, kProductInfo, "UNKNOWN"); +} +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set.h new file mode 100644 index 0000000000..1cca9aa5a0 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set.h @@ -0,0 +1,144 @@ +// Copyright (c) 2013, 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_LINUX_MINIDUMP_WRITER_CPU_SET_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ + +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// Helper class used to model a set of CPUs, as read from sysfs +// files like /sys/devices/system/cpu/present +// See See http://www.kernel.org/doc/Documentation/cputopology.txt +class CpuSet { +public: + // The maximum number of supported CPUs. + static const size_t kMaxCpus = 1024; + + CpuSet() { + my_memset(mask_, 0, sizeof(mask_)); + } + + // Parse a sysfs file to extract the corresponding CPU set. + bool ParseSysFile(int fd) { + char buffer[512]; + int ret = sys_read(fd, buffer, sizeof(buffer)-1); + if (ret < 0) + return false; + + buffer[ret] = '\0'; + + // Expected format: comma-separated list of items, where each + // item can be a decimal integer, or two decimal integers separated + // by a dash. + // E.g.: + // 0 + // 0,1,2,3 + // 0-3 + // 1,10-23 + const char* p = buffer; + const char* p_end = p + ret; + while (p < p_end) { + // Skip leading space, if any + while (p < p_end && my_isspace(*p)) + p++; + + // Find start and size of current item. + const char* item = p; + size_t item_len = static_cast(p_end - p); + const char* item_next = + static_cast(my_memchr(p, ',', item_len)); + if (item_next != NULL) { + p = item_next + 1; + item_len = static_cast(item_next - item); + } else { + p = p_end; + item_next = p_end; + } + + // Ignore trailing spaces. + while (item_next > item && my_isspace(item_next[-1])) + item_next--; + + // skip empty items. + if (item_next == item) + continue; + + // read first decimal value. + uintptr_t start = 0; + const char* next = my_read_decimal_ptr(&start, item); + uintptr_t end = start; + if (*next == '-') + my_read_decimal_ptr(&end, next+1); + + while (start <= end) + SetBit(start++); + } + return true; + } + + // Intersect this CPU set with another one. + void IntersectWith(const CpuSet& other) { + for (size_t nn = 0; nn < kMaskWordCount; ++nn) + mask_[nn] &= other.mask_[nn]; + } + + // Return the number of CPUs in this set. + int GetCount() { + int result = 0; + for (size_t nn = 0; nn < kMaskWordCount; ++nn) { + result += __builtin_popcount(mask_[nn]); + } + return result; + } + +private: + void SetBit(uintptr_t index) { + size_t nn = static_cast(index); + if (nn < kMaxCpus) + mask_[nn / kMaskWordBits] |= (1U << (nn % kMaskWordBits)); + } + + typedef uint32_t MaskWordType; + static const size_t kMaskWordBits = 8*sizeof(MaskWordType); + static const size_t kMaskWordCount = + (kMaxCpus + kMaskWordBits - 1) / kMaskWordBits; + + MaskWordType mask_[kMaskWordCount]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set_unittest.cc new file mode 100644 index 0000000000..75172e9938 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/cpu_set_unittest.cc @@ -0,0 +1,164 @@ +// Copyright (c) 2013, 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 +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "linux/minidump_writer/cpu_set.h" +#include "common/linux/tests/auto_testfile.h" + +using namespace google_breakpad; + +namespace { + +typedef testing::Test CpuSetTest; + +// Helper class to write test text file to a temporary file and return +// its file descriptor. +class ScopedTestFile : public AutoTestFile { +public: + explicit ScopedTestFile(const char* text) + : AutoTestFile("cpu_set", text) { + } +}; + +} + +TEST(CpuSetTest, EmptyCount) { + CpuSet set; + ASSERT_EQ(0, set.GetCount()); +} + +TEST(CpuSetTest, OneCpu) { + ScopedTestFile file("10"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(1, set.GetCount()); +} + +TEST(CpuSetTest, OneCpuTerminated) { + ScopedTestFile file("10\n"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(1, set.GetCount()); +} + +TEST(CpuSetTest, TwoCpusWithComma) { + ScopedTestFile file("1,10"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(2, set.GetCount()); +} + +TEST(CpuSetTest, TwoCpusWithRange) { + ScopedTestFile file("1-2"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(2, set.GetCount()); +} + +TEST(CpuSetTest, TenCpusWithRange) { + ScopedTestFile file("9-18"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(10, set.GetCount()); +} + +TEST(CpuSetTest, MultiItems) { + ScopedTestFile file("0, 2-4, 128"); + ASSERT_TRUE(file.IsOk()); + + CpuSet set; + ASSERT_TRUE(set.ParseSysFile(file.GetFd())); + ASSERT_EQ(5, set.GetCount()); +} + +TEST(CpuSetTest, IntersectWith) { + ScopedTestFile file1("9-19"); + ASSERT_TRUE(file1.IsOk()); + CpuSet set1; + ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); + ASSERT_EQ(11, set1.GetCount()); + + ScopedTestFile file2("16-24"); + ASSERT_TRUE(file2.IsOk()); + CpuSet set2; + ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); + ASSERT_EQ(9, set2.GetCount()); + + set1.IntersectWith(set2); + ASSERT_EQ(4, set1.GetCount()); + ASSERT_EQ(9, set2.GetCount()); +} + +TEST(CpuSetTest, SelfIntersection) { + ScopedTestFile file1("9-19"); + ASSERT_TRUE(file1.IsOk()); + CpuSet set1; + ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); + ASSERT_EQ(11, set1.GetCount()); + + set1.IntersectWith(set1); + ASSERT_EQ(11, set1.GetCount()); +} + +TEST(CpuSetTest, EmptyIntersection) { + ScopedTestFile file1("0-19"); + ASSERT_TRUE(file1.IsOk()); + CpuSet set1; + ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); + ASSERT_EQ(20, set1.GetCount()); + + ScopedTestFile file2("20-39"); + ASSERT_TRUE(file2.IsOk()); + CpuSet set2; + ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); + ASSERT_EQ(20, set2.GetCount()); + + set1.IntersectWith(set2); + ASSERT_EQ(0, set1.GetCount()); + + ASSERT_EQ(20, set2.GetCount()); +} + diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader.h new file mode 100644 index 0000000000..a4bde18031 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader.h @@ -0,0 +1,106 @@ +// Copyright (c) 2009, 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_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ + +#include +#include +#include +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for enumerating a directory without using diropen/readdir or other +// functions which may allocate memory. +class DirectoryReader { + public: + DirectoryReader(int fd) + : fd_(fd), + buf_used_(0) { + } + + // Return the next entry from the directory + // name: (output) the NUL terminated entry name + // + // Returns true iff successful (false on EOF). + // + // After calling this, one must call |PopEntry| otherwise you'll get the same + // entry over and over. + bool GetNextEntry(const char** name) { + struct kernel_dirent* const dent = + reinterpret_cast(buf_); + + if (buf_used_ == 0) { + // need to read more entries. + const int n = sys_getdents(fd_, dent, sizeof(buf_)); + if (n < 0) { + return false; + } else if (n == 0) { + hit_eof_ = true; + } else { + buf_used_ += n; + } + } + + if (buf_used_ == 0 && hit_eof_) + return false; + + assert(buf_used_ > 0); + + *name = dent->d_name; + return true; + } + + void PopEntry() { + if (!buf_used_) + return; + + const struct kernel_dirent* const dent = + reinterpret_cast(buf_); + + buf_used_ -= dent->d_reclen; + my_memmove(buf_, buf_ + dent->d_reclen, buf_used_); + } + + private: + const int fd_; + bool hit_eof_; + unsigned buf_used_; + uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader_unittest.cc new file mode 100644 index 0000000000..b33507db95 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/directory_reader_unittest.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2009, 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 +#include + +#include +#include +#include + +#include "linux/minidump_writer/directory_reader.h" +#include "common/using_std_string.h" +#include "breakpad_googletest_includes.h" + +using namespace google_breakpad; + +namespace { +typedef testing::Test DirectoryReaderTest; +} + +TEST(DirectoryReaderTest, CompareResults) { + std::set dent_set; + + DIR *const dir = opendir("/proc/self"); + ASSERT_TRUE(dir != NULL); + + struct dirent* dent; + while ((dent = readdir(dir))) + dent_set.insert(dent->d_name); + + closedir(dir); + + const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY); + ASSERT_GE(fd, 0); + + DirectoryReader dir_reader(fd); + unsigned seen = 0; + + const char* name; + while (dir_reader.GetNextEntry(&name)) { + ASSERT_TRUE(dent_set.find(name) != dent_set.end()); + seen++; + dir_reader.PopEntry(); + } + + ASSERT_TRUE(dent_set.find("status") != dent_set.end()); + ASSERT_TRUE(dent_set.find("stat") != dent_set.end()); + ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end()); + + ASSERT_EQ(dent_set.size(), seen); + close(fd); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader.h new file mode 100644 index 0000000000..d8e2dbcc11 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader.h @@ -0,0 +1,131 @@ +// Copyright (c) 2009, 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_LINUX_MINIDUMP_WRITER_LINE_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_ + +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for reading a file, line by line, without using fopen/fgets or other +// functions which may allocate memory. +class LineReader { + public: + LineReader(int fd) + : fd_(fd), + hit_eof_(false), + buf_used_(0) { + } + + // The maximum length of a line. + static const size_t kMaxLineLen = 1024; + + // Return the next line from the file. + // line: (output) a pointer to the start of the line. The line is NUL + // terminated. + // len: (output) the length of the line (not inc the NUL byte) + // + // Returns true iff successful (false on EOF). + // + // One must call |PopLine| after this function, otherwise you'll continue to + // get the same line over and over. + bool GetNextLine(const char **line, unsigned *len) { + for (;;) { + if (buf_used_ == 0 && hit_eof_) + return false; + + for (unsigned i = 0; i < buf_used_; ++i) { + if (buf_[i] == '\n' || buf_[i] == 0) { + buf_[i] = 0; + *len = i; + *line = buf_; + return true; + } + } + + if (buf_used_ == sizeof(buf_)) { + // we scanned the whole buffer and didn't find an end-of-line marker. + // This line is too long to process. + return false; + } + + // We didn't find any end-of-line terminators in the buffer. However, if + // this is the last line in the file it might not have one: + if (hit_eof_) { + assert(buf_used_); + // There's room for the NUL because of the buf_used_ == sizeof(buf_) + // check above. + buf_[buf_used_] = 0; + *len = buf_used_; + buf_used_ += 1; // since we appended the NUL. + *line = buf_; + return true; + } + + // Otherwise, we should pull in more data from the file + const ssize_t n = sys_read(fd_, buf_ + buf_used_, + sizeof(buf_) - buf_used_); + if (n < 0) { + return false; + } else if (n == 0) { + hit_eof_ = true; + } else { + buf_used_ += n; + } + + // At this point, we have either set the hit_eof_ flag, or we have more + // data to process... + } + } + + void PopLine(unsigned len) { + // len doesn't include the NUL byte at the end. + + assert(buf_used_ >= len + 1); + buf_used_ -= len + 1; + my_memmove(buf_, buf_ + len + 1, buf_used_); + } + + private: + const int fd_; + + bool hit_eof_; + unsigned buf_used_; + char buf_[kMaxLineLen]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader_unittest.cc new file mode 100644 index 0000000000..576b8b5cdb --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/line_reader_unittest.cc @@ -0,0 +1,169 @@ +// Copyright (c) 2009, 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 +#include +#include + +#include "linux/minidump_writer/line_reader.h" +#include "breakpad_googletest_includes.h" +#include "common/linux/tests/auto_testfile.h" + +using namespace google_breakpad; + +namespace { + +typedef testing::Test LineReaderTest; + +class ScopedTestFile : public AutoTestFile { +public: + explicit ScopedTestFile(const char* text) + : AutoTestFile("line_reader", text) { + } + + ScopedTestFile(const char* text, size_t text_len) + : AutoTestFile("line_reader", text, text_len) { + } +}; + +} + +TEST(LineReaderTest, EmptyFile) { + ScopedTestFile file(""); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} + +TEST(LineReaderTest, OneLineTerminated) { + ScopedTestFile file("a\n"); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned int len; + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned int)1, len); + ASSERT_EQ('a', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} + +TEST(LineReaderTest, OneLine) { + ScopedTestFile file("a"); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned)1, len); + ASSERT_EQ('a', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} + +TEST(LineReaderTest, TwoLinesTerminated) { + ScopedTestFile file("a\nb\n"); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned)1, len); + ASSERT_EQ('a', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned)1, len); + ASSERT_EQ('b', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} + +TEST(LineReaderTest, TwoLines) { + ScopedTestFile file("a\nb"); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned)1, len); + ASSERT_EQ('a', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ((unsigned)1, len); + ASSERT_EQ('b', line[0]); + ASSERT_EQ('\0', line[1]); + reader.PopLine(len); + + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} + +TEST(LineReaderTest, MaxLength) { + char l[LineReader::kMaxLineLen-1]; + memset(l, 'a', sizeof(l)); + ScopedTestFile file(l, sizeof(l)); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_TRUE(reader.GetNextLine(&line, &len)); + ASSERT_EQ(sizeof(l), len); + ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0); + ASSERT_EQ('\0', line[len]); +} + +TEST(LineReaderTest, TooLong) { + // Note: this writes kMaxLineLen 'a' chars in the test file. + char l[LineReader::kMaxLineLen]; + memset(l, 'a', sizeof(l)); + ScopedTestFile file(l, sizeof(l)); + ASSERT_TRUE(file.IsOk()); + LineReader reader(file.GetFd()); + + const char *line; + unsigned len; + ASSERT_FALSE(reader.GetNextLine(&line, &len)); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc new file mode 100644 index 0000000000..38feb0aaa7 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc @@ -0,0 +1,308 @@ +// Copyright (c) 2012, 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. + +// linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper. +// See linux_core_dumper.h for details. + +#include "linux/minidump_writer/linux_core_dumper.h" + +#include +#include +#include +#include +#include +#include +#if defined(__mips__) && defined(__ANDROID__) +// To get register definitions. +#include +#endif + +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/linux_libc_support.h" + +namespace google_breakpad { + +LinuxCoreDumper::LinuxCoreDumper(pid_t pid, + const char* core_path, + const char* procfs_path, + const char* root_prefix) + : LinuxDumper(pid, root_prefix), + core_path_(core_path), + procfs_path_(procfs_path), + thread_infos_(&allocator_, 8) { + assert(core_path_); +} + +bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid, + const char* node) const { + if (!path || !node) + return false; + + size_t node_len = my_strlen(node); + if (node_len == 0) + return false; + + size_t procfs_path_len = my_strlen(procfs_path_); + size_t total_length = procfs_path_len + 1 + node_len; + if (total_length >= NAME_MAX) + return false; + + memcpy(path, procfs_path_, procfs_path_len); + path[procfs_path_len] = '/'; + memcpy(path + procfs_path_len + 1, node, node_len); + path[total_length] = '\0'; + return true; +} + +bool LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child, + const void* src, size_t length) { + ElfCoreDump::Addr virtual_address = reinterpret_cast(src); + // TODO(benchan): Investigate whether the data to be copied could span + // across multiple segments in the core dump file. ElfCoreDump::CopyData + // and this method do not handle that case yet. + if (!core_.CopyData(dest, virtual_address, length)) { + // If the data segment is not found in the core dump, fill the result + // with marker characters. + memset(dest, 0xab, length); + return false; + } + return true; +} + +bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { + if (index >= thread_infos_.size()) + return false; + + *info = thread_infos_[index]; + const uint8_t* stack_pointer; +#if defined(__i386) + memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); +#elif defined(__x86_64) + memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); +#elif defined(__ARM_EABI__) + memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); +#elif defined(__aarch64__) + memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); +#elif defined(__mips__) + stack_pointer = + reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#else +#error "This code hasn't been ported to your platform yet." +#endif + info->stack_pointer = reinterpret_cast(stack_pointer); + return true; +} + +bool LinuxCoreDumper::GetThreadNameByIndex(size_t index, char* name, + size_t size) { + // Not implemented + return false; +} + +bool LinuxCoreDumper::IsPostMortem() const { + return true; +} + +bool LinuxCoreDumper::ThreadsSuspend() { + return true; +} + +bool LinuxCoreDumper::ThreadsResume() { + return true; +} + +bool LinuxCoreDumper::EnumerateThreads() { + if (!mapped_core_file_.Map(core_path_, 0)) { + fprintf(stderr, "Could not map core dump file into memory\n"); + return false; + } + + core_.SetContent(mapped_core_file_.content()); + if (!core_.IsValid()) { + fprintf(stderr, "Invalid core dump file\n"); + return false; + } + + ElfCoreDump::Note note = core_.GetFirstNote(); + if (!note.IsValid()) { + fprintf(stderr, "PT_NOTE section not found\n"); + return false; + } + + bool first_thread = true; + do { + ElfCoreDump::Word type = note.GetType(); + MemoryRange name = note.GetName(); + MemoryRange description = note.GetDescription(); + + if (type == 0 || name.IsEmpty() || description.IsEmpty()) { + fprintf(stderr, "Could not found a valid PT_NOTE.\n"); + return false; + } + + // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are + // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific): + // Thread Name Type + // ------------------------------------------------------------------- + // 1st thread CORE NT_PRSTATUS + // process-wide CORE NT_PRPSINFO + // process-wide CORE NT_SIGINFO + // process-wide CORE NT_AUXV + // 1st thread CORE NT_FPREGSET + // 1st thread LINUX NT_PRXFPREG + // 1st thread LINUX NT_386_TLS + // + // 2nd thread CORE NT_PRSTATUS + // 2nd thread CORE NT_FPREGSET + // 2nd thread LINUX NT_PRXFPREG + // 2nd thread LINUX NT_386_TLS + // + // 3rd thread CORE NT_PRSTATUS + // 3rd thread CORE NT_FPREGSET + // 3rd thread LINUX NT_PRXFPREG + // 3rd thread LINUX NT_386_TLS + // + // The following code only works if notes are ordered as expected. + switch (type) { + case NT_PRSTATUS: { + if (description.length() != sizeof(elf_prstatus)) { + fprintf(stderr, "Found NT_PRSTATUS descriptor of unexpected size\n"); + return false; + } + + const elf_prstatus* status = + reinterpret_cast(description.data()); + pid_t pid = status->pr_pid; + ThreadInfo info; + memset(&info, 0, sizeof(ThreadInfo)); + info.tgid = status->pr_pgrp; + info.ppid = status->pr_ppid; +#if defined(__mips__) +#if defined(__ANDROID__) + for (int i = EF_R0; i <= EF_R31; i++) + info.mcontext.gregs[i - EF_R0] = status->pr_reg[i]; +#else // __ANDROID__ + for (int i = EF_REG0; i <= EF_REG31; i++) + info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i]; +#endif // __ANDROID__ + info.mcontext.mdlo = status->pr_reg[EF_LO]; + info.mcontext.mdhi = status->pr_reg[EF_HI]; + info.mcontext.pc = status->pr_reg[EF_CP0_EPC]; +#else // __mips__ + memcpy(&info.regs, status->pr_reg, sizeof(info.regs)); +#endif // __mips__ + if (first_thread) { + crash_thread_ = pid; + crash_signal_ = status->pr_info.si_signo; + crash_signal_code_ = status->pr_info.si_code; + } + first_thread = false; + threads_.push_back(pid); + thread_infos_.push_back(info); + break; + } + case NT_SIGINFO: { + if (description.length() != sizeof(siginfo_t)) { + fprintf(stderr, "Found NT_SIGINFO descriptor of unexpected size\n"); + return false; + } + + const siginfo_t* info = + reinterpret_cast(description.data()); + + // Set crash_address when si_addr is valid for the signal. + switch (info->si_signo) { + case MD_EXCEPTION_CODE_LIN_SIGBUS: + case MD_EXCEPTION_CODE_LIN_SIGFPE: + case MD_EXCEPTION_CODE_LIN_SIGILL: + case MD_EXCEPTION_CODE_LIN_SIGSEGV: + case MD_EXCEPTION_CODE_LIN_SIGSYS: + case MD_EXCEPTION_CODE_LIN_SIGTRAP: + crash_address_ = reinterpret_cast(info->si_addr); + break; + } + + // Set crash_exception_info for common signals. Since exception info is + // unsigned, but some of these fields might be signed, we always cast. + switch (info->si_signo) { + case MD_EXCEPTION_CODE_LIN_SIGKILL: + set_crash_exception_info({ + static_cast(info->si_pid), + static_cast(info->si_uid), + }); + break; + case MD_EXCEPTION_CODE_LIN_SIGSYS: +#ifdef si_syscall + set_crash_exception_info({ + static_cast(info->si_syscall), + static_cast(info->si_arch), + }); +#endif + break; + } + break; + } +#if defined(__i386) || defined(__x86_64) + case NT_FPREGSET: { + if (thread_infos_.empty()) + return false; + + ThreadInfo* info = &thread_infos_.back(); + if (description.length() != sizeof(info->fpregs)) { + fprintf(stderr, "Found NT_FPREGSET descriptor of unexpected size\n"); + return false; + } + + memcpy(&info->fpregs, description.data(), sizeof(info->fpregs)); + break; + } +#endif +#if defined(__i386) + case NT_PRXFPREG: { + if (thread_infos_.empty()) + return false; + + ThreadInfo* info = &thread_infos_.back(); + if (description.length() != sizeof(info->fpxregs)) { + fprintf(stderr, "Found NT_PRXFPREG descriptor of unexpected size\n"); + return false; + } + + memcpy(&info->fpxregs, description.data(), sizeof(info->fpxregs)); + break; + } +#endif + } + note = note.GetNextNote(); + } while (note.IsValid()); + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.h new file mode 100644 index 0000000000..7805854a33 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.h @@ -0,0 +1,130 @@ +// Copyright (c) 2012, 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. + +// linux_core_dumper.h: Define the google_breakpad::LinuxCoreDumper +// class, which is derived from google_breakpad::LinuxDumper to extract +// information from a crashed process via its core dump and proc files. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_ + +#include "linux/minidump_writer/linux_dumper.h" +#include "common/linux/elf_core_dump.h" +#include "common/linux/memory_mapped_file.h" + +namespace google_breakpad { + +class LinuxCoreDumper : public LinuxDumper { + public: + // Constructs a dumper for extracting information of a given process + // with a process ID of |pid| via its core dump file at |core_path| and + // its proc files at |procfs_path|. If |procfs_path| is a copy of + // /proc/, it should contain the following files: + // auxv, cmdline, environ, exe, maps, status + // See LinuxDumper for the purpose of |root_prefix|. + LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path, + const char* root_prefix = ""); + + // Implements LinuxDumper::BuildProcPath(). + // Builds a proc path for a certain pid for a node (/proc//). + // |path| is a character array of at least NAME_MAX bytes to return the + // result.|node| is the final node without any slashes. Return true on + // success. + // + // As this dumper performs a post-mortem dump and makes use of a copy + // of the proc files of the crashed process, this derived method does + // not actually make use of |pid| and always returns a subpath of + // |procfs_path_| regardless of whether |pid| corresponds to the main + // process or a thread of the process, i.e. assuming both the main process + // and its threads have the following proc files with the same content: + // auxv, cmdline, environ, exe, maps, status + virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const; + + // Implements LinuxDumper::CopyFromProcess(). + // Copies content of |length| bytes from a given process |child|, + // starting from |src|, into |dest|. This method extracts the content + // the core dump and fills |dest| with a sequence of marker bytes + // if the expected data is not found in the core dump. Returns true if + // the expected data is found in the core dump. + virtual bool CopyFromProcess(void* dest, pid_t child, const void* src, + size_t length); + + // Implements LinuxDumper::GetThreadInfoByIndex(). + // Reads information about the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info); + + // Implements LinuxDumper::GetThreadNameByIndex(). + // Reads the name of the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadNameByIndex(size_t index, char* info, size_t size); + + // Implements LinuxDumper::IsPostMortem(). + // Always returns true to indicate that this dumper performs a + // post-mortem dump of a crashed process via a core dump file. + virtual bool IsPostMortem() const; + + // Implements LinuxDumper::ThreadsSuspend(). + // As the dumper performs a post-mortem dump via a core dump file, + // there is no threads to suspend. This method does nothing and + // always returns true. + virtual bool ThreadsSuspend(); + + // Implements LinuxDumper::ThreadsResume(). + // As the dumper performs a post-mortem dump via a core dump file, + // there is no threads to resume. This method does nothing and + // always returns true. + virtual bool ThreadsResume(); + + protected: + // Implements LinuxDumper::EnumerateThreads(). + // Enumerates all threads of the given process into |threads_|. + virtual bool EnumerateThreads(); + + private: + // Path of the core dump file. + const char* core_path_; + + // Path of the directory containing the proc files of the given process, + // which is usually a copy of /proc/. + const char* procfs_path_; + + // Memory-mapped core dump file at |core_path_|. + MemoryMappedFile mapped_core_file_; + + // Content of the core dump file. + ElfCoreDump core_; + + // Thread info found in the core dump file. + wasteful_vector thread_infos_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_LINUX_CORE_DUMPER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc new file mode 100644 index 0000000000..2e973167fd --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc @@ -0,0 +1,192 @@ +// Copyright (c) 2012, 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. + +// linux_core_dumper_unittest.cc: +// Unit tests for google_breakpad::LinuxCoreDumoer. + +#include + +#include "breakpad_googletest_includes.h" +#include "linux/minidump_writer/linux_core_dumper.h" +#include "common/linux/tests/crash_generator.h" +#include "common/using_std_string.h" + +using namespace google_breakpad; + +TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) { + const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root"); + const MappingInfo mapping = {0, 0, {0, 0}, 0, false, "/usr/lib/libc.so"}; + + char path[PATH_MAX]; + dumper.GetMappingAbsolutePath(mapping, path); + + EXPECT_STREQ("/mnt/root/usr/lib/libc.so", path); +} + +TEST(LinuxCoreDumperTest, BuildProcPath) { + const pid_t pid = getpid(); + const char procfs_path[] = "/procfs_copy"; + LinuxCoreDumper dumper(getpid(), "core_file", procfs_path); + + char maps_path[NAME_MAX] = ""; + char maps_path_expected[NAME_MAX]; + snprintf(maps_path_expected, sizeof(maps_path_expected), + "%s/maps", procfs_path); + EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); + EXPECT_STREQ(maps_path_expected, maps_path); + + EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); + + char long_node[NAME_MAX]; + size_t long_node_len = NAME_MAX - strlen(procfs_path) - 1; + memset(long_node, 'a', long_node_len); + long_node[long_node_len] = '\0'; + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, long_node)); +} + +TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) { + CrashGenerator crash_generator; + if (!crash_generator.HasDefaultCorePattern()) { + fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test " + "is skipped due to non-default core pattern\n"); + return; + } + + const unsigned kNumOfThreads = 3; + const unsigned kCrashThread = 1; + const int kCrashSignal = SIGABRT; + pid_t child_pid; + ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, + kCrashSignal, &child_pid)); + + const string core_file = crash_generator.GetCoreFilePath(); + const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy(); + +#if defined(__ANDROID__) + struct stat st; + if (stat(core_file.c_str(), &st) != 0) { + fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test is " + "skipped due to no core file being generated\n"); + return; + } +#endif + + LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str()); + + EXPECT_TRUE(dumper.Init()); + + EXPECT_TRUE(dumper.IsPostMortem()); + + // These are no-ops and should always return true. + EXPECT_TRUE(dumper.ThreadsSuspend()); + EXPECT_TRUE(dumper.ThreadsResume()); + + // Linux does not set the crash address with SIGABRT, so make sure it always + // sets the crash address to 0. + EXPECT_EQ(0U, dumper.crash_address()); + EXPECT_EQ(kCrashSignal, dumper.crash_signal()); + EXPECT_EQ(crash_generator.GetThreadId(kCrashThread), + dumper.crash_thread()); + +#if defined(THREAD_SANITIZER) + EXPECT_GE(dumper.threads().size(), kNumOfThreads); +#else + EXPECT_EQ(dumper.threads().size(), kNumOfThreads); +#endif + for (unsigned i = 0; i < kNumOfThreads; ++i) { + ThreadInfo info; + EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &info)); + const void* stack; + size_t stack_len; + EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len, info.stack_pointer)); + EXPECT_EQ(getpid(), info.ppid); + } +} + +TEST(LinuxCoreDumperTest, VerifyExceptionDetails) { + CrashGenerator crash_generator; + if (!crash_generator.HasDefaultCorePattern()) { + fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test " + "is skipped due to non-default core pattern\n"); + return; + } + +#ifndef si_syscall + fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test is " + "skipped due to old kernel/C library headers\n"); + return; +#endif + + const unsigned kNumOfThreads = 2; + const unsigned kCrashThread = 1; + const int kCrashSignal = SIGSYS; + pid_t child_pid; + ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, + kCrashSignal, &child_pid)); + + const string core_file = crash_generator.GetCoreFilePath(); + const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy(); + +#if defined(__ANDROID__) + struct stat st; + if (stat(core_file.c_str(), &st) != 0) { + fprintf(stderr, "LinuxCoreDumperTest.VerifyExceptionDetails test is " + "skipped due to no core file being generated\n"); + return; + } +#endif + + LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str()); + + EXPECT_TRUE(dumper.Init()); + + EXPECT_TRUE(dumper.IsPostMortem()); + +#if defined(__ANDROID__) + // TODO: For some reason, Android doesn't seem to pass this. + if (!dumper.crash_address()) { + fprintf(stderr, "LinuxCoreDumperTest.VerifyExceptionDetails test is " + "skipped due to missing signal details on Android\n"); + return; + } +#endif + + // Check the exception details. + EXPECT_NE(0U, dumper.crash_address()); + EXPECT_EQ(kCrashSignal, dumper.crash_signal()); + EXPECT_EQ(crash_generator.GetThreadId(kCrashThread), + dumper.crash_thread()); + + // We check the length, but not the actual fields. We sent SIGSYS ourselves + // instead of the kernel, so the extended fields are garbage. + const std::vector info(dumper.crash_exception_info()); + EXPECT_EQ(2U, info.size()); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.cc new file mode 100644 index 0000000000..3b400ce8ca --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.cc @@ -0,0 +1,999 @@ +// Copyright (c) 2010, 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. + +// linux_dumper.cc: Implement google_breakpad::LinuxDumper. +// See linux_dumper.h for details. + +// This code deals with the mechanics of getting information about a crashed +// process. Since this code may run in a compromised address space, the same +// rules apply as detailed at the top of minidump_writer.h: no libc calls and +// use the alternative allocator. + +#include "linux/minidump_writer/linux_dumper.h" + +#include +#include +#include +#include +#include +#include + +#include "linux/minidump_writer/line_reader.h" +#include "common/linux/elfutils.h" +#include "common/linux/file_id.h" +#include "common/linux/linux_libc_support.h" +#include "common/linux/memory_mapped_file.h" +#include "common/linux/safe_readlink.h" +#include "google_breakpad/common/minidump_exception_linux.h" +#include "third_party/lss/linux_syscall_support.h" + +#if defined(__ANDROID__) + +// Android packed relocations definitions are not yet available from the +// NDK header files, so we have to provide them manually here. +#ifndef DT_LOOS +#define DT_LOOS 0x6000000d +#endif +#ifndef DT_ANDROID_REL +static const int DT_ANDROID_REL = DT_LOOS + 2; +#endif +#ifndef DT_ANDROID_RELA +static const int DT_ANDROID_RELA = DT_LOOS + 4; +#endif + +#endif // __ANDROID __ + +static const char kMappedFileUnsafePrefix[] = "/dev/"; +static const char kDeletedSuffix[] = " (deleted)"; +static const char kReservedFlags[] = " ---p"; +static const char kMozillaIpcPrefix[] = "org.mozilla.ipc."; + +inline static bool IsMappedFileOpenUnsafe( + const google_breakpad::MappingInfo& mapping) { + // It is unsafe to attempt to open a mapped file that lives under /dev, + // because the semantics of the open may be driver-specific so we'd risk + // hanging the crash dumper. And a file in /dev/ almost certainly has no + // ELF file identifier anyways. + return my_strncmp(mapping.name, + kMappedFileUnsafePrefix, + sizeof(kMappedFileUnsafePrefix) - 1) == 0; +} + +namespace google_breakpad { + +namespace { + +bool MappingContainsAddress(const MappingInfo& mapping, uintptr_t address) { + return mapping.system_mapping_info.start_addr <= address && + address < mapping.system_mapping_info.end_addr; +} + +#if defined(__CHROMEOS__) + +// Recover memory mappings before writing dump on ChromeOS +// +// On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from +// addresses. ChromeOS' hugepage implementation replaces some segments with +// anonymous private pages, which is a restriction of current implementation +// in Linux kernel at the time of writing. Thus, breakpad can no longer +// symbolize addresses from those text segments replaced with hugepages. +// +// This postprocess tries to recover the mappings. Because hugepages are always +// inserted in between some .text sections, it tries to infer the names and +// offsets of the segments, by looking at segments immediately precede and +// succeed them. +// +// For example, a text segment before hugepage optimization +// 02001000-03002000 r-xp /opt/google/chrome/chrome +// +// can be broken into +// 02001000-02200000 r-xp /opt/google/chrome/chrome +// 02200000-03000000 r-xp +// 03000000-03002000 r-xp /opt/google/chrome/chrome +// +// For more details, see: +// crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization + +// Copied from CrOS' hugepage implementation, which is unlikely to change. +// The hugepage size is 2M. +const unsigned int kHpageShift = 21; +const size_t kHpageSize = (1 << kHpageShift); +const size_t kHpageMask = (~(kHpageSize - 1)); + +// Find and merge anonymous r-xp segments with surrounding named segments. +// There are two cases: + +// Case 1: curr, next +// curr is anonymous +// curr is r-xp +// curr.size >= 2M +// curr.size is a multiple of 2M. +// next is backed by some file. +// curr and next are contiguous. +// offset(next) == sizeof(curr) +void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) { + // Merged segments are marked with size = 0. + if (curr->size == 0 || next->size == 0) + return; + + if (curr->size >= kHpageSize && + curr->exec && + (curr->size & kHpageMask) == curr->size && + (curr->start_addr & kHpageMask) == curr->start_addr && + curr->name[0] == '\0' && + next->name[0] != '\0' && + curr->start_addr + curr->size == next->start_addr && + curr->size == next->offset) { + + // matched + my_strlcpy(curr->name, next->name, NAME_MAX); + if (next->exec) { + // (curr, next) + curr->size += next->size; + next->size = 0; + } + } +} + +// Case 2: prev, curr, next +// curr is anonymous +// curr is r-xp +// curr.size >= 2M +// curr.size is a multiple of 2M. +// next and prev are backed by the same file. +// prev, curr and next are contiguous. +// offset(next) == offset(prev) + sizeof(prev) + sizeof(curr) +void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr, + MappingInfo *next) { + // Merged segments are marked with size = 0. + if (prev->size == 0 || curr->size == 0 || next->size == 0) + return; + + if (curr->size >= kHpageSize && + curr->exec && + (curr->size & kHpageMask) == curr->size && + (curr->start_addr & kHpageMask) == curr->start_addr && + curr->name[0] == '\0' && + next->name[0] != '\0' && + curr->start_addr + curr->size == next->start_addr && + prev->start_addr + prev->size == curr->start_addr && + my_strncmp(prev->name, next->name, NAME_MAX) == 0 && + next->offset == prev->offset + prev->size + curr->size) { + + // matched + my_strlcpy(curr->name, prev->name, NAME_MAX); + if (prev->exec) { + curr->offset = prev->offset; + curr->start_addr = prev->start_addr; + if (next->exec) { + // (prev, curr, next) + curr->size += prev->size + next->size; + prev->size = 0; + next->size = 0; + } else { + // (prev, curr), next + curr->size += prev->size; + prev->size = 0; + } + } else { + curr->offset = prev->offset + prev->size; + if (next->exec) { + // prev, (curr, next) + curr->size += next->size; + next->size = 0; + } else { + // prev, curr, next + } + } + } +} + +// mappings_ is sorted excepted for the first entry. +// This function tries to merge segemnts into the first entry, +// then check for other sorted entries. +// See LinuxDumper::EnumerateMappings(). +void CrOSPostProcessMappings(wasteful_vector& mappings) { + // Find the candidate "next" to first segment, which is the only one that + // could be out-of-order. + size_t l = 1; + size_t r = mappings.size(); + size_t next = mappings.size(); + while (l < r) { + int m = (l + r) / 2; + if (mappings[m]->start_addr > mappings[0]->start_addr) + r = next = m; + else + l = m + 1; + } + + // Shows the range that contains the entry point is + // [first_start_addr, first_end_addr) + size_t first_start_addr = mappings[0]->start_addr; + size_t first_end_addr = mappings[0]->start_addr + mappings[0]->size; + + // Put the out-of-order segment in order. + std::rotate(mappings.begin(), mappings.begin() + 1, mappings.begin() + next); + + // Iterate through normal, sorted cases. + // Normal case 1. + for (size_t i = 0; i < mappings.size() - 1; i++) + TryRecoverMappings(mappings[i], mappings[i + 1]); + + // Normal case 2. + for (size_t i = 0; i < mappings.size() - 2; i++) + TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]); + + // Collect merged (size == 0) segments. + size_t f, e; + for (f = e = 0; e < mappings.size(); e++) + if (mappings[e]->size > 0) + mappings[f++] = mappings[e]; + mappings.resize(f); + + // The entry point is in the first mapping. We want to find the location + // of the entry point after merging segment. To do this, we want to find + // the mapping that covers the first mapping from the original mapping list. + // If the mapping is not in the beginning, we move it to the begining via + // a right rotate by using reverse iterators. + for (l = 0; l < mappings.size(); l++) { + if (mappings[l]->start_addr <= first_start_addr + && (mappings[l]->start_addr + mappings[l]->size >= first_end_addr)) + break; + } + if (l > 0) { + r = mappings.size(); + std::rotate(mappings.rbegin() + r - l - 1, mappings.rbegin() + r - l, + mappings.rend()); + } +} + +#endif // __CHROMEOS__ + +} // namespace + +// All interesting auvx entry types are below AT_SYSINFO_EHDR +#define AT_MAX AT_SYSINFO_EHDR + +LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix) + : pid_(pid), + root_prefix_(root_prefix), + crash_address_(0), + crash_signal_(0), + crash_signal_code_(0), + crash_thread_(pid), + threads_(&allocator_, 8), + mappings_(&allocator_), + auxv_(&allocator_, AT_MAX + 1) { + assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX); + // The passed-in size to the constructor (above) is only a hint. + // Must call .resize() to do actual initialization of the elements. + auxv_.resize(AT_MAX + 1); +} + +LinuxDumper::~LinuxDumper() { +} + +bool LinuxDumper::Init() { + return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); +} + +bool LinuxDumper::LateInit() { +#if defined(__ANDROID__) + LatePostprocessMappings(); +#endif + +#if defined(__CHROMEOS__) + CrOSPostProcessMappings(mappings_); +#endif + + return true; +} + +bool +LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + wasteful_vector& identifier) { + assert(!member || mapping_id < mappings_.size()); + if (IsMappedFileOpenUnsafe(mapping)) + return false; + + // Special-case linux-gate because it's not a real file. + if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) { + void* linux_gate = NULL; + if (pid_ == sys_getpid()) { + linux_gate = reinterpret_cast(mapping.start_addr); + } else { + linux_gate = allocator_.Alloc(mapping.size); + CopyFromProcess(linux_gate, pid_, + reinterpret_cast(mapping.start_addr), + mapping.size); + } + return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier); + } + + char filename[PATH_MAX]; + if (!GetMappingAbsolutePath(mapping, filename)) + return false; + bool filename_modified = HandleDeletedFileInMapping(filename); + + MemoryMappedFile mapped_file(filename, mapping.offset); + if (!mapped_file.data() || mapped_file.size() < SELFMAG) + return false; + + bool success = + FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); + if (success && member && filename_modified) { + mappings_[mapping_id]->name[my_strlen(mapping.name) - + sizeof(kDeletedSuffix) + 1] = '\0'; + } + + return success; +} + +void LinuxDumper::SetCrashInfoFromSigInfo(const siginfo_t& siginfo) { + set_crash_address(reinterpret_cast(siginfo.si_addr)); + set_crash_signal(siginfo.si_signo); + set_crash_signal_code(siginfo.si_code); +} + +const char* LinuxDumper::GetCrashSignalString() const { + switch (static_cast(crash_signal_)) { + case MD_EXCEPTION_CODE_LIN_SIGHUP: + return "SIGHUP"; + case MD_EXCEPTION_CODE_LIN_SIGINT: + return "SIGINT"; + case MD_EXCEPTION_CODE_LIN_SIGQUIT: + return "SIGQUIT"; + case MD_EXCEPTION_CODE_LIN_SIGILL: + return "SIGILL"; + case MD_EXCEPTION_CODE_LIN_SIGTRAP: + return "SIGTRAP"; + case MD_EXCEPTION_CODE_LIN_SIGABRT: + return "SIGABRT"; + case MD_EXCEPTION_CODE_LIN_SIGBUS: + return "SIGBUS"; + case MD_EXCEPTION_CODE_LIN_SIGFPE: + return "SIGFPE"; + case MD_EXCEPTION_CODE_LIN_SIGKILL: + return "SIGKILL"; + case MD_EXCEPTION_CODE_LIN_SIGUSR1: + return "SIGUSR1"; + case MD_EXCEPTION_CODE_LIN_SIGSEGV: + return "SIGSEGV"; + case MD_EXCEPTION_CODE_LIN_SIGUSR2: + return "SIGUSR2"; + case MD_EXCEPTION_CODE_LIN_SIGPIPE: + return "SIGPIPE"; + case MD_EXCEPTION_CODE_LIN_SIGALRM: + return "SIGALRM"; + case MD_EXCEPTION_CODE_LIN_SIGTERM: + return "SIGTERM"; + case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: + return "SIGSTKFLT"; + case MD_EXCEPTION_CODE_LIN_SIGCHLD: + return "SIGCHLD"; + case MD_EXCEPTION_CODE_LIN_SIGCONT: + return "SIGCONT"; + case MD_EXCEPTION_CODE_LIN_SIGSTOP: + return "SIGSTOP"; + case MD_EXCEPTION_CODE_LIN_SIGTSTP: + return "SIGTSTP"; + case MD_EXCEPTION_CODE_LIN_SIGTTIN: + return "SIGTTIN"; + case MD_EXCEPTION_CODE_LIN_SIGTTOU: + return "SIGTTOU"; + case MD_EXCEPTION_CODE_LIN_SIGURG: + return "SIGURG"; + case MD_EXCEPTION_CODE_LIN_SIGXCPU: + return "SIGXCPU"; + case MD_EXCEPTION_CODE_LIN_SIGXFSZ: + return "SIGXFSZ"; + case MD_EXCEPTION_CODE_LIN_SIGVTALRM: + return "SIGVTALRM"; + case MD_EXCEPTION_CODE_LIN_SIGPROF: + return "SIGPROF"; + case MD_EXCEPTION_CODE_LIN_SIGWINCH: + return "SIGWINCH"; + case MD_EXCEPTION_CODE_LIN_SIGIO: + return "SIGIO"; + case MD_EXCEPTION_CODE_LIN_SIGPWR: + return "SIGPWR"; + case MD_EXCEPTION_CODE_LIN_SIGSYS: + return "SIGSYS"; + case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: + return "DUMP_REQUESTED"; + default: + return "UNKNOWN"; + } +} + +bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping, + char path[PATH_MAX]) const { + return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX && + my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX; +} + +namespace { +// Find the shared object name (SONAME) by examining the ELF information +// for |mapping|. If the SONAME is found copy it into the passed buffer +// |soname| and return true. The size of the buffer is |soname_size|. +// The SONAME will be truncated if it is too long to fit in the buffer. +bool ElfFileSoName(const LinuxDumper& dumper, + const MappingInfo& mapping, char* soname, size_t soname_size) { + if (IsMappedFileOpenUnsafe(mapping)) { + // Not safe + return false; + } + + char filename[PATH_MAX]; + if (!dumper.GetMappingAbsolutePath(mapping, filename)) + return false; + + MemoryMappedFile mapped_file(filename, mapping.offset); + if (!mapped_file.data() || mapped_file.size() < SELFMAG) { + // mmap failed + return false; + } + + return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); +} + +} // namespace + + +void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size) { + my_strlcpy(file_path, mapping.name, file_path_size); + + // Tools such as minidump_stackwalk use the name of the module to look up + // symbols produced by dump_syms. dump_syms will prefer to use a module's + // DT_SONAME as the module name, if one exists, and will fall back to the + // filesystem name of the module. + + // Just use the filesystem name if no SONAME is present. + if (!ElfFileSoName(*this, mapping, file_name, file_name_size)) { + // file_path := /path/to/libname.so + // file_name := libname.so + const char* basename = my_strrchr(file_path, '/'); + basename = basename == NULL ? file_path : (basename + 1); + my_strlcpy(file_name, basename, file_name_size); + return; + } + + if (mapping.exec && mapping.offset != 0) { + // If an executable is mapped from a non-zero offset, this is likely because + // the executable was loaded directly from inside an archive file (e.g., an + // apk on Android). + // In this case, we append the file_name to the mapped archive path: + // file_name := libname.so + // file_path := /path/to/ARCHIVE.APK/libname.so + if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { + my_strlcat(file_path, "/", file_path_size); + my_strlcat(file_path, file_name, file_path_size); + } + } else { + // Otherwise, replace the basename with the SONAME. + char* basename = const_cast(my_strrchr(file_path, '/')); + if (basename) { + my_strlcpy(basename + 1, file_name, + file_path_size - my_strlen(file_path) + + my_strlen(basename + 1)); + } else { + my_strlcpy(file_path, file_name, file_path_size); + } + } +} + +bool LinuxDumper::ReadAuxv() { + char auxv_path[NAME_MAX]; + if (!BuildProcPath(auxv_path, pid_, "auxv")) { + return false; + } + + int fd = sys_open(auxv_path, O_RDONLY, 0); + if (fd < 0) { + return false; + } + + elf_aux_entry one_aux_entry; + bool res = false; + while (sys_read(fd, + &one_aux_entry, + sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) && + one_aux_entry.a_type != AT_NULL) { + if (one_aux_entry.a_type <= AT_MAX) { + auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val; + res = true; + } + } + sys_close(fd); + return res; +} + +bool LinuxDumper::IsIPCSharedMemorySegment(const char* name) { + if (my_strstr(name, kMozillaIpcPrefix) && + my_strstr(name, kDeletedSuffix)) { + return true; + } + + return false; +} + +bool LinuxDumper::EnumerateMappings() { + char maps_path[NAME_MAX]; + if (!BuildProcPath(maps_path, pid_, "maps")) + return false; + + // linux_gate_loc is the beginning of the kernel's mapping of + // linux-gate.so in the process. It doesn't actually show up in the + // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR + // aux vector entry, which gives the information necessary to special + // case its entry when creating the list of mappings. + // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more + // information. + const void* linux_gate_loc = + reinterpret_cast(auxv_[AT_SYSINFO_EHDR]); + // Although the initial executable is usually the first mapping, it's not + // guaranteed (see http://crosbug.com/25355); therefore, try to use the + // actual entry point to find the mapping. + const void* entry_point_loc = reinterpret_cast(auxv_[AT_ENTRY]); + + const int fd = sys_open(maps_path, O_RDONLY, 0); + if (fd < 0) + return false; + LineReader* const line_reader = new(allocator_) LineReader(fd); + + const char* line; + unsigned line_len; + while (line_reader->GetNextLine(&line, &line_len)) { + uintptr_t start_addr, end_addr, offset; + + const char* i1 = my_read_hex_ptr(&start_addr, line); + if (*i1 == '-') { + const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1); + if (*i2 == ' ') { + bool exec = (*(i2 + 3) == 'x'); + const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); + if (*i3 == ' ') { + const char* name = NULL; + // Only copy name if the name is a valid path name, or if + // it's the VDSO image. + if (((name = my_strchr(line, '/')) == NULL) && + linux_gate_loc && + reinterpret_cast(start_addr) == linux_gate_loc) { + name = kLinuxGateLibraryName; + offset = 0; + } + // Skip shared memory segments used for IPC + if (name && IsIPCSharedMemorySegment(name)) { + line_reader->PopLine(line_len); + continue; + } + // Merge adjacent mappings into one module, assuming they're a single + // library mapped by the dynamic linker. + if (name && !mappings_.empty()) { + MappingInfo* module = mappings_.back(); + if ((start_addr == module->start_addr + module->size) && + (my_strlen(name) == my_strlen(module->name)) && + (my_strncmp(name, module->name, my_strlen(name)) == 0)) { + module->system_mapping_info.end_addr = end_addr; + module->size = end_addr - module->start_addr; + module->exec |= exec; + line_reader->PopLine(line_len); + continue; + } + } + // Also merge mappings that result from address ranges that the + // linker reserved but which a loaded library did not use. These + // appear as an anonymous private mapping with no access flags set + // and which directly follow an executable mapping. + if (!name && !mappings_.empty()) { + MappingInfo* module = mappings_.back(); + uintptr_t module_end_addr = module->start_addr + module->size; + if ((start_addr == module_end_addr) && + module->exec && + module->name[0] == '/' && + ((offset == 0) || (offset == module_end_addr)) && + my_strncmp(i2, kReservedFlags, + sizeof(kReservedFlags) - 1) == 0) { + module->size = end_addr - module->start_addr; + line_reader->PopLine(line_len); + continue; + } + } + MappingInfo* const module = new(allocator_) MappingInfo; + mappings_.push_back(module); + my_memset(module, 0, sizeof(MappingInfo)); + module->system_mapping_info.start_addr = start_addr; + module->system_mapping_info.end_addr = end_addr; + module->start_addr = start_addr; + module->size = end_addr - start_addr; + module->offset = offset; + module->exec = exec; + if (name != NULL) { + const unsigned l = my_strlen(name); + if (l < sizeof(module->name)) + my_memcpy(module->name, name, l); + } + } + } + } + line_reader->PopLine(line_len); + } + + if (entry_point_loc) { + for (size_t i = 0; i < mappings_.size(); ++i) { + MappingInfo* module = mappings_[i]; + + // If this module contains the entry-point, and it's not already the first + // one, then we need to make it be first. This is because the minidump + // format assumes the first module is the one that corresponds to the main + // executable (as codified in + // processor/minidump.cc:MinidumpModuleList::GetMainModule()). + if ((entry_point_loc >= reinterpret_cast(module->start_addr)) && + (entry_point_loc < + reinterpret_cast(module->start_addr + module->size))) { + for (size_t j = i; j > 0; j--) + mappings_[j] = mappings_[j - 1]; + mappings_[0] = module; + break; + } + } + } + + sys_close(fd); + + return !mappings_.empty(); +} + +#if defined(__ANDROID__) + +bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) { + CopyFromProcess(ehdr, pid_, + reinterpret_cast(start_addr), + sizeof(*ehdr)); + return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0; +} + +void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, + uintptr_t start_addr, + uintptr_t* min_vaddr_ptr, + uintptr_t* dyn_vaddr_ptr, + size_t* dyn_count_ptr) { + uintptr_t phdr_addr = start_addr + ehdr->e_phoff; + + const uintptr_t max_addr = UINTPTR_MAX; + uintptr_t min_vaddr = max_addr; + uintptr_t dyn_vaddr = 0; + size_t dyn_count = 0; + + for (size_t i = 0; i < ehdr->e_phnum; ++i) { + ElfW(Phdr) phdr; + CopyFromProcess(&phdr, pid_, + reinterpret_cast(phdr_addr), + sizeof(phdr)); + if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) { + min_vaddr = phdr.p_vaddr; + } + if (phdr.p_type == PT_DYNAMIC) { + dyn_vaddr = phdr.p_vaddr; + dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn)); + } + phdr_addr += sizeof(phdr); + } + + *min_vaddr_ptr = min_vaddr; + *dyn_vaddr_ptr = dyn_vaddr; + *dyn_count_ptr = dyn_count; +} + +bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, + uintptr_t dyn_vaddr, + size_t dyn_count) { + uintptr_t dyn_addr = load_bias + dyn_vaddr; + for (size_t i = 0; i < dyn_count; ++i) { + ElfW(Dyn) dyn; + CopyFromProcess(&dyn, pid_, + reinterpret_cast(dyn_addr), + sizeof(dyn)); + if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { + return true; + } + dyn_addr += sizeof(dyn); + } + return false; +} + +uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, + uintptr_t start_addr) { + uintptr_t min_vaddr = 0; + uintptr_t dyn_vaddr = 0; + size_t dyn_count = 0; + ParseLoadedElfProgramHeaders(ehdr, start_addr, + &min_vaddr, &dyn_vaddr, &dyn_count); + // If |min_vaddr| is non-zero and we find Android packed relocation tags, + // return the effective load bias. + if (min_vaddr != 0) { + const uintptr_t load_bias = start_addr - min_vaddr; + if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { + return load_bias; + } + } + // Either |min_vaddr| is zero, or it is non-zero but we did not find the + // expected Android packed relocations tags. + return start_addr; +} + +void LinuxDumper::LatePostprocessMappings() { + for (size_t i = 0; i < mappings_.size(); ++i) { + // Only consider exec mappings that indicate a file path was mapped, and + // where the ELF header indicates a mapped shared library. + MappingInfo* mapping = mappings_[i]; + if (!(mapping->exec && mapping->name[0] == '/')) { + continue; + } + ElfW(Ehdr) ehdr; + if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { + continue; + } + if (ehdr.e_type == ET_DYN) { + // Compute the effective load bias for this mapped library, and update + // the mapping to hold that rather than |start_addr|, at the same time + // adjusting |size| to account for the change in |start_addr|. Where + // the library does not contain Android packed relocations, + // GetEffectiveLoadBias() returns |start_addr| and the mapping entry + // is not changed. + const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr, + mapping->start_addr); + mapping->size += mapping->start_addr - load_bias; + mapping->start_addr = load_bias; + } + } +} + +#endif // __ANDROID__ + +// Get information about the stack, given the stack pointer. We don't try to +// walk the stack since we might not have all the information needed to do +// unwind. So we just grab, up to, 32k of stack. +bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, + uintptr_t int_stack_pointer) { + // Move the stack pointer to the bottom of the page that it's in. + const uintptr_t page_size = getpagesize(); + + uint8_t* const stack_pointer = + reinterpret_cast(int_stack_pointer & ~(page_size - 1)); + + // The number of bytes of stack which we try to capture. + static const ptrdiff_t kStackToCapture = 32 * 1024; + + const MappingInfo* mapping = FindMapping(stack_pointer); + if (!mapping) + return false; + const ptrdiff_t offset = stack_pointer - + reinterpret_cast(mapping->start_addr); + const ptrdiff_t distance_to_end = + static_cast(mapping->size) - offset; + *stack_len = distance_to_end > kStackToCapture ? + kStackToCapture : distance_to_end; + *stack = stack_pointer; + return true; +} + +void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len, + uintptr_t stack_pointer, + uintptr_t sp_offset) { + // We optimize the search for containing mappings in three ways: + // 1) We expect that pointers into the stack mapping will be common, so + // we cache that address range. + // 2) The last referenced mapping is a reasonable predictor for the next + // referenced mapping, so we test that first. + // 3) We precompute a bitfield based upon bits 32:32-n of the start and + // stop addresses, and use that to short circuit any values that can + // not be pointers. (n=11) + const uintptr_t defaced = +#if defined(__LP64__) + 0x0defaced0defaced; +#else + 0x0defaced; +#endif + // the bitfield length is 2^test_bits long. + const unsigned int test_bits = 11; + // byte length of the corresponding array. + const unsigned int array_size = 1 << (test_bits - 3); + const unsigned int array_mask = array_size - 1; + // The amount to right shift pointers by. This captures the top bits + // on 32 bit architectures. On 64 bit architectures this would be + // uninformative so we take the same range of bits. + const unsigned int shift = 32 - 11; + const MappingInfo* last_hit_mapping = nullptr; + const MappingInfo* hit_mapping = nullptr; + const MappingInfo* stack_mapping = FindMappingNoBias(stack_pointer); + // The magnitude below which integers are considered to be to be + // 'small', and not constitute a PII risk. These are included to + // avoid eliding useful register values. + const ssize_t small_int_magnitude = 4096; + + char could_hit_mapping[array_size]; + my_memset(could_hit_mapping, 0, array_size); + + // Initialize the bitfield such that if the (pointer >> shift)'th + // bit, modulo the bitfield size, is not set then there does not + // exist a mapping in mappings_ that would contain that pointer. + for (size_t i = 0; i < mappings_.size(); ++i) { + if (!mappings_[i]->exec) continue; + // For each mapping, work out the (unmodulo'ed) range of bits to + // set. + uintptr_t start = mappings_[i]->start_addr; + uintptr_t end = start + mappings_[i]->size; + start >>= shift; + end >>= shift; + for (size_t bit = start; bit <= end; ++bit) { + // Set each bit in the range, applying the modulus. + could_hit_mapping[(bit >> 3) & array_mask] |= 1 << (bit & 7); + } + } + + // Zero memory that is below the current stack pointer. + const uintptr_t offset = + (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + if (offset) { + my_memset(stack_copy, 0, offset); + } + + // Apply sanitization to each complete pointer-aligned word in the + // stack. + uint8_t* sp; + for (sp = stack_copy + offset; + sp <= stack_copy + stack_len - sizeof(uintptr_t); + sp += sizeof(uintptr_t)) { + uintptr_t addr; + my_memcpy(&addr, sp, sizeof(uintptr_t)); + if (static_cast(addr) <= small_int_magnitude && + static_cast(addr) >= -small_int_magnitude) { + continue; + } + if (stack_mapping && MappingContainsAddress(*stack_mapping, addr)) { + continue; + } + if (last_hit_mapping && MappingContainsAddress(*last_hit_mapping, addr)) { + continue; + } + uintptr_t test = addr >> shift; + if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) && + (hit_mapping = FindMappingNoBias(addr)) != nullptr && + hit_mapping->exec) { + last_hit_mapping = hit_mapping; + continue; + } + my_memcpy(sp, &defaced, sizeof(uintptr_t)); + } + // Zero any partial word at the top of the stack, if alignment is + // such that that is required. + if (sp < stack_copy + stack_len) { + my_memset(sp, 0, stack_copy + stack_len - sp); + } +} + +bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy, + size_t stack_len, + uintptr_t sp_offset, + const MappingInfo& mapping) { + // Loop over all stack words that would have been on the stack in + // the target process (i.e. are word aligned, and at addresses >= + // the stack pointer). Regardless of the alignment of |stack_copy|, + // the memory starting at |stack_copy| + |offset| represents an + // aligned word in the target process. + const uintptr_t low_addr = mapping.system_mapping_info.start_addr; + const uintptr_t high_addr = mapping.system_mapping_info.end_addr; + const uintptr_t offset = + (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + + for (const uint8_t* sp = stack_copy + offset; + sp <= stack_copy + stack_len - sizeof(uintptr_t); + sp += sizeof(uintptr_t)) { + uintptr_t addr; + my_memcpy(&addr, sp, sizeof(uintptr_t)); + if (low_addr <= addr && addr <= high_addr) + return true; + } + return false; +} + +// Find the mapping which the given memory address falls in. +const MappingInfo* LinuxDumper::FindMapping(const void* address) const { + const uintptr_t addr = (uintptr_t) address; + + for (size_t i = 0; i < mappings_.size(); ++i) { + const uintptr_t start = static_cast(mappings_[i]->start_addr); + if (addr >= start && addr - start < mappings_[i]->size) + return mappings_[i]; + } + + return NULL; +} + +// Find the mapping which the given memory address falls in. Uses the +// unadjusted mapping address range from the kernel, rather than the +// biased range. +const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const { + for (size_t i = 0; i < mappings_.size(); ++i) { + if (address >= mappings_[i]->system_mapping_info.start_addr && + address < mappings_[i]->system_mapping_info.end_addr) { + return mappings_[i]; + } + } + return NULL; +} + +bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { + static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1; + + // Check for ' (deleted)' in |path|. + // |path| has to be at least as long as "/x (deleted)". + const size_t path_len = my_strlen(path); + if (path_len < kDeletedSuffixLen + 2) + return false; + if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix, + kDeletedSuffixLen) != 0) { + return false; + } + + // Check |path| against the /proc/pid/exe 'symlink'. + char exe_link[NAME_MAX]; + if (!BuildProcPath(exe_link, pid_, "exe")) + return false; + MappingInfo new_mapping = {0}; + if (!SafeReadLink(exe_link, new_mapping.name)) + return false; + char new_path[PATH_MAX]; + if (!GetMappingAbsolutePath(new_mapping, new_path)) + return false; + if (my_strcmp(path, new_path) != 0) + return false; + + // Check to see if someone actually named their executable 'foo (deleted)'. + struct kernel_stat exe_stat; + struct kernel_stat new_path_stat; + if (sys_stat(exe_link, &exe_stat) == 0 && + sys_stat(new_path, &new_path_stat) == 0 && + exe_stat.st_dev == new_path_stat.st_dev && + exe_stat.st_ino == new_path_stat.st_ino) { + return false; + } + + my_memcpy(path, exe_link, NAME_MAX); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h new file mode 100644 index 0000000000..7155524ffc --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h @@ -0,0 +1,333 @@ +// Copyright (c) 2010, 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. + +// linux_dumper.h: Define the google_breakpad::LinuxDumper class, which +// is a base class for extracting information of a crashed process. It +// was originally a complete implementation using the ptrace API, but +// has been refactored to allow derived implementations supporting both +// ptrace and core dump. A portion of the original implementation is now +// in google_breakpad::LinuxPtraceDumper (see linux_ptrace_dumper.h for +// details). + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_ + +#include +#include +#if defined(__ANDROID__) +#include +#endif +#include +#include +#include +#include + +#include + +#include "linux/dump_writer_common/mapping_info.h" +#include "linux/dump_writer_common/thread_info.h" +#include "common/linux/file_id.h" +#include "common/memory_allocator.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Typedef for our parsing of the auxv variables in /proc/pid/auxv. +#if defined(__i386) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _ABIO32) +typedef Elf32_auxv_t elf_aux_entry; +#elif defined(__x86_64) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM != _ABIO32) +typedef Elf64_auxv_t elf_aux_entry; +#endif + +typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; + +// When we find the VDSO mapping in the process's address space, this +// is the name we use for it when writing it to the minidump. +// This should always be less than NAME_MAX! +const char kLinuxGateLibraryName[] = "linux-gate.so"; + +class LinuxDumper { + public: + // The |root_prefix| is prepended to mapping paths before opening them, which + // is useful if the crash originates from a chroot. + explicit LinuxDumper(pid_t pid, const char* root_prefix = ""); + + virtual ~LinuxDumper(); + + // Parse the data for |threads| and |mappings|. + virtual bool Init(); + + // Take any actions that could not be taken in Init(). LateInit() is + // called after all other caller's initialization is complete, and in + // particular after it has called ThreadsSuspend(), so that ptrace is + // available. + virtual bool LateInit(); + + // Return true if the dumper performs a post-mortem dump. + virtual bool IsPostMortem() const = 0; + + // Suspend/resume all threads in the given process. + virtual bool ThreadsSuspend() = 0; + virtual bool ThreadsResume() = 0; + + // Read information about the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0; + + // Read the name ofthe |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadNameByIndex(size_t index, char* name, size_t size) = 0; + + size_t GetMainThreadIndex() const { + for (size_t i = 0; i < threads_.size(); ++i) { + if (threads_[i] == pid_) return i; + } + return -1u; + } + + // These are only valid after a call to |Init|. + const wasteful_vector &threads() { return threads_; } + const wasteful_vector &mappings() { return mappings_; } + const MappingInfo* FindMapping(const void* address) const; + // Find the mapping which the given memory address falls in. Unlike + // FindMapping, this method uses the unadjusted mapping address + // ranges from the kernel, rather than the ranges that have had the + // load bias applied. + const MappingInfo* FindMappingNoBias(uintptr_t address) const; + const wasteful_vector& auxv() { return auxv_; } + + // Find a block of memory to take as the stack given the top of stack pointer. + // stack: (output) the lowest address in the memory area + // stack_len: (output) the length of the memory area + // stack_top: the current top of the stack + bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top); + + // Sanitize a copy of the stack by overwriting words that are not + // pointers with a sentinel (0x0defaced). + // stack_copy: a copy of the stack to sanitize. |stack_copy| might + // not be word aligned, but it represents word aligned + // data copied from another location. + // stack_len: the length of the allocation pointed to by |stack_copy|. + // stack_pointer: the address of the stack pointer (used to locate + // the stack mapping, as an optimization). + // sp_offset: the offset relative to stack_copy that reflects the + // current value of the stack pointer. + void SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len, + uintptr_t stack_pointer, uintptr_t sp_offset); + + // Test whether |stack_copy| contains a pointer-aligned word that + // could be an address within a given mapping. + // stack_copy: a copy of the stack to check. |stack_copy| might + // not be word aligned, but it represents word aligned + // data copied from another location. + // stack_len: the length of the allocation pointed to by |stack_copy|. + // sp_offset: the offset relative to stack_copy that reflects the + // current value of the stack pointer. + // mapping: the mapping against which to test stack words. + bool StackHasPointerToMapping(const uint8_t* stack_copy, size_t stack_len, + uintptr_t sp_offset, + const MappingInfo& mapping); + + PageAllocator* allocator() { return &allocator_; } + + // Copy content of |length| bytes from a given process |child|, + // starting from |src|, into |dest|. Returns true on success. + virtual bool CopyFromProcess(void* dest, pid_t child, const void* src, + size_t length) = 0; + + // Builds a proc path for a certain pid for a node (/proc//). + // |path| is a character array of at least NAME_MAX bytes to return the + // result.|node| is the final node without any slashes. Returns true on + // success. + virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0; + + // Generate a File ID from the .text section of a mapped entry. + // If not a member, mapping_id is ignored. This method can also manipulate the + // |mapping|.name to truncate "(deleted)" from the file name if necessary. + bool ElfFileIdentifierForMapping(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + wasteful_vector& identifier); + + void SetCrashInfoFromSigInfo(const siginfo_t& siginfo); + + uintptr_t crash_address() const { return crash_address_; } + void set_crash_address(uintptr_t crash_address) { + crash_address_ = crash_address; + } + + int crash_signal() const { return crash_signal_; } + void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; } + const char* GetCrashSignalString() const; + + void set_crash_signal_code(int code) { crash_signal_code_ = code; } + int crash_signal_code() const { return crash_signal_code_; } + + void set_crash_exception_info(const std::vector& exception_info) { + assert(exception_info.size() <= MD_EXCEPTION_MAXIMUM_PARAMETERS); + crash_exception_info_ = exception_info; + } + const std::vector& crash_exception_info() const { + return crash_exception_info_; + } + + pid_t pid() const { return pid_; } + pid_t crash_thread() const { return crash_thread_; } + void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } + + // Concatenates the |root_prefix_| and |mapping| path. Writes into |path| and + // returns true unless the string is too long. + bool GetMappingAbsolutePath(const MappingInfo& mapping, + char path[PATH_MAX]) const; + + // Extracts the effective path and file name of from |mapping|. In most cases + // the effective name/path are just the mapping's path and basename. In some + // other cases, however, a library can be mapped from an archive (e.g., when + // loading .so libs from an apk on Android) and this method is able to + // reconstruct the original file name. + void GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size); + + protected: + bool ReadAuxv(); + + virtual bool EnumerateMappings(); + + virtual bool EnumerateThreads() = 0; + + // For the case where a running program has been deleted, it'll show up in + // /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then + // see if '/path/to/program (deleted)' matches /proc/pid/exe and return + // /proc/pid/exe in |path| so ELF identifier generation works correctly. This + // also checks to see if '/path/to/program (deleted)' exists, so it does not + // get fooled by a poorly named binary. + // For programs that don't end with ' (deleted)', this is a no-op. + // This assumes |path| is a buffer with length NAME_MAX. + // Returns true if |path| is modified. + bool HandleDeletedFileInMapping(char* path) const; + + // ID of the crashed process. + const pid_t pid_; + + // Path of the root directory to which mapping paths are relative. + const char* const root_prefix_; + + // Virtual address at which the process crashed. + uintptr_t crash_address_; + + // Signal that terminated the crashed process. + int crash_signal_; + + // The code associated with |crash_signal_|. + int crash_signal_code_; + + // The additional fields associated with |crash_signal_|. + std::vector crash_exception_info_; + + // ID of the crashed thread. + pid_t crash_thread_; + + mutable PageAllocator allocator_; + + // IDs of all the threads. + wasteful_vector threads_; + + // Info from /proc//maps. + wasteful_vector mappings_; + + // Info from /proc//auxv + wasteful_vector auxv_; + +private: + bool IsIPCSharedMemorySegment(const char* name); + +#if defined(__ANDROID__) + // Android M and later support packed ELF relocations in shared libraries. + // Packing relocations changes the vaddr of the LOAD segments, such that + // the effective load bias is no longer the same as the start address of + // the memory mapping containing the executable parts of the library. The + // packing is applied to the stripped library run on the target, but not to + // any other library, and in particular not to the library used to generate + // breakpad symbols. As a result, we need to adjust the |start_addr| for + // any mapping that results from a shared library that contains Android + // packed relocations, so that it properly represents the effective library + // load bias. The following functions support this adjustment. + + // Check that a given mapping at |start_addr| is for an ELF shared library. + // If it is, place the ELF header in |ehdr| and return true. + // The first LOAD segment in an ELF shared library has offset zero, so the + // ELF file header is at the start of this map entry, and in already mapped + // memory. + bool GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr); + + // For the ELF file mapped at |start_addr|, iterate ELF program headers to + // find the min vaddr of all program header LOAD segments, the vaddr for + // the DYNAMIC segment, and a count of DYNAMIC entries. Return values in + // |min_vaddr_ptr|, |dyn_vaddr_ptr|, and |dyn_count_ptr|. + // The program header table is also in already mapped memory. + void ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, + uintptr_t start_addr, + uintptr_t* min_vaddr_ptr, + uintptr_t* dyn_vaddr_ptr, + size_t* dyn_count_ptr); + + // Search the DYNAMIC tags for the ELF file with the given |load_bias|, and + // return true if the tags indicate that the file contains Android packed + // relocations. Dynamic tags are found at |dyn_vaddr| past the |load_bias|. + bool HasAndroidPackedRelocations(uintptr_t load_bias, + uintptr_t dyn_vaddr, + size_t dyn_count); + + // If the ELF file mapped at |start_addr| contained Android packed + // relocations, return the load bias that the system linker (or Chromium + // crazy linker) will have used. If the file did not contain Android + // packed relocations, returns |start_addr|, indicating that no adjustment + // is necessary. + // The effective load bias is |start_addr| adjusted downwards by the + // min vaddr in the library LOAD segments. + uintptr_t GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, uintptr_t start_addr); + + // Called from LateInit(). Iterates |mappings_| and rewrites the |start_addr| + // field of any that represent ELF shared libraries with Android packed + // relocations, so that |start_addr| is the load bias that the system linker + // (or Chromium crazy linker) used. This value matches the addresses produced + // when the non-relocation-packed library is used for breakpad symbol + // generation. + void LatePostprocessMappings(); +#endif // __ANDROID__ +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper_unittest_helper.cc new file mode 100644 index 0000000000..3ad48e5015 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper_unittest_helper.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2010, 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. +// +// Helper program for the linux_dumper class, which creates a bunch of +// threads. The first word of each thread's stack is set to the thread +// id. + +#include +#include +#include +#include +#include +#include + +#include "common/scoped_ptr.h" +#include "third_party/lss/linux_syscall_support.h" + +#if defined(__ARM_EABI__) +#define TID_PTR_REGISTER "r3" +#elif defined(__aarch64__) +#define TID_PTR_REGISTER "x3" +#elif defined(__i386) +#define TID_PTR_REGISTER "ecx" +#elif defined(__x86_64) +#define TID_PTR_REGISTER "rcx" +#elif defined(__mips__) +#define TID_PTR_REGISTER "$1" +#else +#error This test has not been ported to this platform. +#endif + +void *thread_function(void *data) { + int pipefd = *static_cast(data); + volatile pid_t* thread_id = new pid_t; + *thread_id = syscall(__NR_gettid); + // Signal parent that a thread has started. + uint8_t byte = 1; + if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) { + perror("ERROR: parent notification failed"); + return NULL; + } + register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = thread_id; + while (true) + asm volatile ("" : : "r" (thread_id_ptr)); + return NULL; +} + +int main(int argc, char *argv[]) { + if (argc < 3) { + fprintf(stderr, + "usage: linux_dumper_unittest_helper <# of threads>\n"); + return 1; + } + int pipefd = atoi(argv[1]); + int num_threads = atoi(argv[2]); + if (num_threads < 1) { + fprintf(stderr, "ERROR: number of threads is 0"); + return 1; + } + google_breakpad::scoped_array threads(new pthread_t[num_threads]); + pthread_attr_t thread_attributes; + pthread_attr_init(&thread_attributes); + pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED); + for (int i = 1; i < num_threads; i++) { + pthread_create(&threads[i], &thread_attributes, &thread_function, &pipefd); + } + thread_function(&pipefd); + return 0; +} diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.cc new file mode 100644 index 0000000000..6ed70eeb61 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -0,0 +1,403 @@ +// Copyright (c) 2012, 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. + +// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper. +// See linux_ptrace_dumper.h for detals. +// This class was originally splitted from google_breakpad::LinuxDumper. + +// This code deals with the mechanics of getting information about a crashed +// process. Since this code may run in a compromised address space, the same +// rules apply as detailed at the top of minidump_writer.h: no libc calls and +// use the alternative allocator. + +#include "linux/minidump_writer/linux_ptrace_dumper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__i386) +#include +#endif + +#include "linux/minidump_writer/directory_reader.h" +#include "linux/minidump_writer/line_reader.h" +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +// Suspends a thread by attaching to it. +static bool SuspendThread(pid_t pid) { + // This may fail if the thread has just died or debugged. + errno = 0; + if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 && + errno != 0) { + return false; + } + while (sys_waitpid(pid, NULL, __WALL) < 0) { + if (errno != EINTR) { + sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + return false; + } + } +#if defined(__i386) || defined(__x86_64) + // On x86, the stack pointer is NULL or -1, when executing trusted code in + // the seccomp sandbox. Not only does this cause difficulties down the line + // when trying to dump the thread's stack, it also results in the minidumps + // containing information about the trusted threads. This information is + // generally completely meaningless and just pollutes the minidumps. + // We thus test the stack pointer and exclude any threads that are part of + // the seccomp sandbox's trusted code. + user_regs_struct regs; + if (sys_ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1 || +#if defined(__i386) + !regs.esp +#elif defined(__x86_64) + !regs.rsp +#endif + ) { + sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + return false; + } +#endif + return true; +} + +// Resumes a thread by detaching from it. +static bool ResumeThread(pid_t pid) { + return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; +} + +namespace google_breakpad { + +LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid) + : LinuxDumper(pid), + threads_suspended_(false) { +} + +bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid, + const char* node) const { + if (!path || !node || pid <= 0) + return false; + + size_t node_len = my_strlen(node); + if (node_len == 0) + return false; + + const unsigned pid_len = my_uint_len(pid); + const size_t total_length = 6 + pid_len + 1 + node_len; + if (total_length >= NAME_MAX) + return false; + + my_memcpy(path, "/proc/", 6); + my_uitos(path + 6, pid, pid_len); + path[6 + pid_len] = '/'; + my_memcpy(path + 6 + pid_len + 1, node, node_len); + path[total_length] = '\0'; + return true; +} + +bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child, + const void* src, size_t length) { + unsigned long tmp = 55; + size_t done = 0; + static const size_t word_size = sizeof(tmp); + uint8_t* const local = (uint8_t*) dest; + uint8_t* const remote = (uint8_t*) src; + + while (done < length) { + const size_t l = (length - done > word_size) ? word_size : (length - done); + if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) { + tmp = 0; + } + my_memcpy(local + done, &tmp, l); + done += l; + } + return true; +} + +bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid) +{ +#ifdef PTRACE_GETREGSET + struct iovec io; + info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { + return false; + } + + info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { + return false; + } + return true; +#else + return false; +#endif +} + +bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) { +#ifdef PTRACE_GETREGS + void* gp_addr; + info->GetGeneralPurposeRegisters(&gp_addr, NULL); + if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) { + return false; + } + +#if !(defined(__ANDROID__) && defined(__ARM_EABI__)) + // When running an arm build on an arm64 device, attempting to get the + // floating point registers fails. On Android, the floating point registers + // aren't written to the cpu context anyway, so just don't get them here. + // See http://crbug.com/508324 + void* fp_addr; + info->GetFloatingPointRegisters(&fp_addr, NULL); + if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) { + return false; + } +#endif // !(defined(__ANDROID__) && defined(__ARM_EABI__)) + return true; +#else // PTRACE_GETREGS + return false; +#endif +} + +// Read thread info from /proc/$pid/status. +// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable, +// these members are set to -1. Returns true iff all three members are +// available. +bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { + if (index >= threads_.size()) + return false; + + pid_t tid = threads_[index]; + + assert(info != NULL); + char status_path[NAME_MAX]; + if (!BuildProcPath(status_path, tid, "status")) + return false; + + const int fd = sys_open(status_path, O_RDONLY, 0); + if (fd < 0) + return false; + + LineReader* const line_reader = new(allocator_) LineReader(fd); + const char* line; + unsigned line_len; + + info->ppid = info->tgid = -1; + + while (line_reader->GetNextLine(&line, &line_len)) { + if (my_strncmp("Tgid:\t", line, 6) == 0) { + my_strtoui(&info->tgid, line + 6); + } else if (my_strncmp("PPid:\t", line, 6) == 0) { + my_strtoui(&info->ppid, line + 6); + } + + line_reader->PopLine(line_len); + } + sys_close(fd); + + if (info->ppid == -1 || info->tgid == -1) + return false; + + if (!ReadRegisterSet(info, tid)) { + if (!ReadRegisters(info, tid)) { + return false; + } + } + +#if defined(__i386) +#if !defined(bit_FXSAVE) // e.g. Clang +#define bit_FXSAVE bit_FXSR +#endif + // Detect if the CPU supports the FXSAVE/FXRSTOR instructions + int eax, ebx, ecx, edx; + __cpuid(1, eax, ebx, ecx, edx); + if (edx & bit_FXSAVE) { + if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) { + return false; + } + } else { + memset(&info->fpxregs, 0, sizeof(info->fpxregs)); + } +#endif // defined(__i386) + +#if defined(__i386) || defined(__x86_64) + for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) { + if (sys_ptrace( + PTRACE_PEEKUSER, tid, + reinterpret_cast (offsetof(struct user, + u_debugreg[0]) + i * + sizeof(debugreg_t)), + &info->dregs[i]) == -1) { + return false; + } + } +#endif + +#if defined(__mips__) + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(PC), &info->mcontext.pc); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE), &info->mcontext.hi1); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 1), &info->mcontext.lo1); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 2), &info->mcontext.hi2); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 3), &info->mcontext.lo2); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 4), &info->mcontext.hi3); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 5), &info->mcontext.lo3); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_CONTROL), &info->mcontext.dsp); +#endif + + const uint8_t* stack_pointer; +#if defined(__i386) + my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); +#elif defined(__x86_64) + my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); +#elif defined(__ARM_EABI__) + my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); +#elif defined(__aarch64__) + my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); +#elif defined(__mips__) + stack_pointer = + reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#else +#error "This code hasn't been ported to your platform yet." +#endif + info->stack_pointer = reinterpret_cast(stack_pointer); + + return true; +} + +bool LinuxPtraceDumper::GetThreadNameByIndex(size_t index, char* name, + size_t size) { + if (index >= threads_.size()) + return false; + + pid_t tid = threads_[index]; + + assert(name != NULL); + char path[NAME_MAX]; + + // Read the thread name (aka comm entry in /proc) + if (!BuildProcPath(path, tid, "comm")) + return false; + + const int fd = sys_open(path, O_RDONLY, 0); + if (fd < 0) + return false; + + const int len = sys_read(fd, name, size); + if (len > 0) + name[len - 1] = '\0'; // Get rid of the newline + + sys_close(fd); + + return len > 0; +} + +bool LinuxPtraceDumper::IsPostMortem() const { + return false; +} + +bool LinuxPtraceDumper::ThreadsSuspend() { + if (threads_suspended_) + return true; + for (size_t i = 0; i < threads_.size(); ++i) { + if (!SuspendThread(threads_[i])) { + // If the thread either disappeared before we could attach to it, or if + // it was part of the seccomp sandbox's trusted code, it is OK to + // silently drop it from the minidump. + if (i < threads_.size() - 1) { + my_memmove(&threads_[i], &threads_[i + 1], + (threads_.size() - i - 1) * sizeof(threads_[i])); + } + threads_.resize(threads_.size() - 1); + --i; + } + } + threads_suspended_ = true; + return !threads_.empty(); +} + +bool LinuxPtraceDumper::ThreadsResume() { + if (!threads_suspended_) + return false; + bool good = true; + for (size_t i = 0; i < threads_.size(); ++i) + good &= ResumeThread(threads_[i]); + threads_suspended_ = false; + return good; +} + +// Parse /proc/$pid/task to list all the threads of the process identified by +// pid. +bool LinuxPtraceDumper::EnumerateThreads() { + char task_path[NAME_MAX]; + if (!BuildProcPath(task_path, pid_, "task")) + return false; + + const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0); + if (fd < 0) + return false; + DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd); + + // The directory may contain duplicate entries which we filter by assuming + // that they are consecutive. + int last_tid = -1; + const char* dent_name; + while (dir_reader->GetNextEntry(&dent_name)) { + if (my_strcmp(dent_name, ".") && + my_strcmp(dent_name, "..")) { + int tid = 0; + if (my_strtoui(&tid, dent_name) && + last_tid != tid) { + last_tid = tid; + threads_.push_back(tid); + } + } + dir_reader->PopEntry(); + } + + sys_close(fd); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.h new file mode 100644 index 0000000000..576098c349 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper.h @@ -0,0 +1,106 @@ +// Copyright (c) 2012, 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. + +// linux_ptrace_dumper.h: Define the google_breakpad::LinuxPtraceDumper +// class, which is derived from google_breakpad::LinuxDumper to extract +// information from a crashed process via ptrace. +// This class was originally splitted from google_breakpad::LinuxDumper. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_ + +#include "linux/minidump_writer/linux_dumper.h" + +namespace google_breakpad { + +class LinuxPtraceDumper : public LinuxDumper { + public: + // Constructs a dumper for extracting information of a given process + // with a process ID of |pid|. + explicit LinuxPtraceDumper(pid_t pid); + + // Implements LinuxDumper::BuildProcPath(). + // Builds a proc path for a certain pid for a node (/proc//). + // |path| is a character array of at least NAME_MAX bytes to return the + // result. |node| is the final node without any slashes. Returns true on + // success. + virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const; + + // Implements LinuxDumper::CopyFromProcess(). + // Copies content of |length| bytes from a given process |child|, + // starting from |src|, into |dest|. This method uses ptrace to extract + // the content from the target process. Always returns true. + virtual bool CopyFromProcess(void* dest, pid_t child, const void* src, + size_t length); + + // Implements LinuxDumper::GetThreadInfoByIndex(). + // Reads information about the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info); + + // Implements LinuxDumper::GetThreadNameByIndex(). + // Reads the name of the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadNameByIndex(size_t index, char* name, size_t size); + + // Implements LinuxDumper::IsPostMortem(). + // Always returns false to indicate this dumper performs a dump of + // a crashed process via ptrace. + virtual bool IsPostMortem() const; + + // Implements LinuxDumper::ThreadsSuspend(). + // Suspends all threads in the given process. Returns true on success. + virtual bool ThreadsSuspend(); + + // Implements LinuxDumper::ThreadsResume(). + // Resumes all threads in the given process. Returns true on success. + virtual bool ThreadsResume(); + + protected: + // Implements LinuxDumper::EnumerateThreads(). + // Enumerates all threads of the given process into |threads_|. + virtual bool EnumerateThreads(); + + private: + // Set to true if all threads of the crashed process are suspended. + bool threads_suspended_; + + // Read the tracee's registers on kernel with PTRACE_GETREGSET support. + // Returns false if PTRACE_GETREGSET is not defined. + // Returns true on success. + bool ReadRegisterSet(ThreadInfo* info, pid_t tid); + + // Read the tracee's registers on kernel with PTRACE_GETREGS support. + // Returns true on success. + bool ReadRegisters(ThreadInfo* info, pid_t tid); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_LINUX_PTRACE_DUMPER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc new file mode 100644 index 0000000000..79d26a1e31 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc @@ -0,0 +1,580 @@ +// Copyright (c) 2009, 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. + +// linux_ptrace_dumper_unittest.cc: +// Unit tests for google_breakpad::LinuxPtraceDumper. +// +// This file was renamed from linux_dumper_unittest.cc and modified due +// to LinuxDumper being splitted into two classes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "linux/minidump_writer/linux_ptrace_dumper.h" +#include "linux/minidump_writer/minidump_writer_unittest_utils.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/file_id.h" +#include "common/linux/ignore_ret.h" +#include "common/linux/safe_readlink.h" +#include "common/memory_allocator.h" +#include "common/using_std_string.h" + +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif + +using namespace google_breakpad; + +namespace { + +pid_t SetupChildProcess(int number_of_threads) { + char kNumberOfThreadsArgument[2]; + sprintf(kNumberOfThreadsArgument, "%d", number_of_threads); + + int fds[2]; + EXPECT_NE(-1, pipe(fds)); + + pid_t child_pid = fork(); + if (child_pid == 0) { + // In child process. + close(fds[0]); + + string helper_path(GetHelperBinary()); + if (helper_path.empty()) { + fprintf(stderr, "Couldn't find helper binary\n"); + _exit(1); + } + + // Pass the pipe fd and the number of threads as arguments. + char pipe_fd_string[8]; + sprintf(pipe_fd_string, "%d", fds[1]); + execl(helper_path.c_str(), + "linux_dumper_unittest_helper", + pipe_fd_string, + kNumberOfThreadsArgument, + NULL); + // Kill if we get here. + printf("Errno from exec: %d", errno); + std::string err_str = "Exec of " + helper_path + " failed"; + perror(err_str.c_str()); + _exit(1); + } + close(fds[1]); + + // Wait for all child threads to indicate that they have started + for (int threads = 0; threads < number_of_threads; threads++) { + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fds[0]; + pfd.events = POLLIN | POLLERR; + + const int r = HANDLE_EINTR(poll(&pfd, 1, 1000)); + EXPECT_EQ(1, r); + EXPECT_TRUE(pfd.revents & POLLIN); + uint8_t junk; + EXPECT_EQ(read(fds[0], &junk, sizeof(junk)), + static_cast(sizeof(junk))); + } + close(fds[0]); + + // There is a race here because we may stop a child thread before + // it is actually running the busy loop. Empirically this sleep + // is sufficient to avoid the race. + usleep(100000); + return child_pid; +} + +typedef wasteful_vector id_vector; +typedef testing::Test LinuxPtraceDumperTest; + +/* Fixture for running tests in a child process. */ +class LinuxPtraceDumperChildTest : public testing::Test { + protected: + virtual void SetUp() { + child_pid_ = fork(); +#ifndef __ANDROID__ + prctl(PR_SET_PTRACER, child_pid_); +#endif + } + + /* Gtest is calling TestBody from this class, which sets up a child + * process in which the RealTestBody virtual member is called. + * As such, TestBody is not supposed to be overridden in derived classes. + */ + virtual void TestBody() /* final */ { + if (child_pid_ == 0) { + // child process + RealTestBody(); + _exit(HasFatalFailure() ? kFatalFailure : + (HasNonfatalFailure() ? kNonFatalFailure : 0)); + } + + ASSERT_TRUE(child_pid_ > 0); + int status; + waitpid(child_pid_, &status, 0); + if (WEXITSTATUS(status) == kFatalFailure) { + GTEST_FATAL_FAILURE_("Test failed in child process"); + } else if (WEXITSTATUS(status) == kNonFatalFailure) { + GTEST_NONFATAL_FAILURE_("Test failed in child process"); + } + } + + /* Gtest defines TestBody functions through its macros, but classes + * derived from this one need to define RealTestBody instead. + * This is achieved by defining a TestBody macro further below. + */ + virtual void RealTestBody() = 0; + + id_vector make_vector() { + return id_vector(&allocator, kDefaultBuildIdSize); + } + + private: + static const int kFatalFailure = 1; + static const int kNonFatalFailure = 2; + + pid_t child_pid_; + PageAllocator allocator; +}; + +} // namespace + +/* Replace TestBody declarations within TEST*() with RealTestBody + * declarations */ +#define TestBody RealTestBody + +TEST_F(LinuxPtraceDumperChildTest, Setup) { + LinuxPtraceDumper dumper(getppid()); +} + +TEST_F(LinuxPtraceDumperChildTest, FindMappings) { + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + + ASSERT_TRUE(dumper.FindMapping(reinterpret_cast(getpid))); + ASSERT_TRUE(dumper.FindMapping(reinterpret_cast(printf))); + ASSERT_FALSE(dumper.FindMapping(NULL)); +} + +TEST_F(LinuxPtraceDumperChildTest, ThreadList) { + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + + ASSERT_GE(dumper.threads().size(), (size_t)1); + bool found = false; + for (size_t i = 0; i < dumper.threads().size(); ++i) { + if (dumper.threads()[i] == getppid()) { + ASSERT_FALSE(found); + found = true; + } + } + ASSERT_TRUE(found); +} + +// Helper stack class to close a file descriptor and unmap +// a mmap'ed mapping. +class StackHelper { + public: + StackHelper() + : fd_(-1), mapping_(NULL), size_(0) {} + ~StackHelper() { + if (size_) + munmap(mapping_, size_); + if (fd_ >= 0) + close(fd_); + } + void Init(int fd, char* mapping, size_t size) { + fd_ = fd; + mapping_ = mapping; + size_ = size; + } + + char* mapping() const { return mapping_; } + size_t size() const { return size_; } + + private: + int fd_; + char* mapping_; + size_t size_; +}; + +class LinuxPtraceDumperMappingsTest : public LinuxPtraceDumperChildTest { + protected: + virtual void SetUp(); + + string helper_path_; + size_t page_size_; + StackHelper helper_; +}; + +void LinuxPtraceDumperMappingsTest::SetUp() { + helper_path_ = GetHelperBinary(); + if (helper_path_.empty()) { + FAIL() << "Couldn't find helper binary"; + _exit(1); + } + + // mmap two segments out of the helper binary, one + // enclosed in the other, but with different protections. + page_size_ = sysconf(_SC_PAGESIZE); + const size_t kMappingSize = 3 * page_size_; + int fd = open(helper_path_.c_str(), O_RDONLY); + ASSERT_NE(-1, fd) << "Failed to open file: " << helper_path_ + << ", Error: " << strerror(errno); + char* mapping = + reinterpret_cast(mmap(NULL, + kMappingSize, + PROT_READ, + MAP_SHARED, + fd, + 0)); + ASSERT_TRUE(mapping); + + // Ensure that things get cleaned up. + helper_.Init(fd, mapping, kMappingSize); + + // Carve a page out of the first mapping with different permissions. + char* inside_mapping = reinterpret_cast( + mmap(mapping + 2 * page_size_, + page_size_, + PROT_NONE, + MAP_SHARED | MAP_FIXED, + fd, + // Map a different offset just to + // better test real-world conditions. + page_size_)); + ASSERT_TRUE(inside_mapping); + + LinuxPtraceDumperChildTest::SetUp(); +} + +TEST_F(LinuxPtraceDumperMappingsTest, MergedMappings) { + // Now check that LinuxPtraceDumper interpreted the mappings properly. + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + int mapping_count = 0; + for (unsigned i = 0; i < dumper.mappings().size(); ++i) { + const MappingInfo& mapping = *dumper.mappings()[i]; + if (strcmp(mapping.name, this->helper_path_.c_str()) == 0) { + // This mapping should encompass the entire original mapped + // range. + EXPECT_EQ(reinterpret_cast(this->helper_.mapping()), + mapping.start_addr); + EXPECT_EQ(this->helper_.size(), mapping.size); + EXPECT_EQ(0U, mapping.offset); + mapping_count++; + } + } + EXPECT_EQ(1, mapping_count); +} + +TEST_F(LinuxPtraceDumperChildTest, BuildProcPath) { + const pid_t pid = getppid(); + LinuxPtraceDumper dumper(pid); + + char maps_path[NAME_MAX] = ""; + char maps_path_expected[NAME_MAX]; + snprintf(maps_path_expected, sizeof(maps_path_expected), + "/proc/%d/maps", pid); + EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps")); + EXPECT_STREQ(maps_path_expected, maps_path); + + EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps")); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps")); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, "")); + EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL)); + + char long_node[NAME_MAX]; + size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1; + memset(long_node, 'a', long_node_len); + long_node[long_node_len] = '\0'; + EXPECT_FALSE(dumper.BuildProcPath(maps_path, 123, long_node)); +} + +#if !defined(__ARM_EABI__) && !defined(__mips__) +// Ensure that the linux-gate VDSO is included in the mapping list. +TEST_F(LinuxPtraceDumperChildTest, MappingsIncludeLinuxGate) { + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + + void* linux_gate_loc = + reinterpret_cast(dumper.auxv()[AT_SYSINFO_EHDR]); + ASSERT_TRUE(linux_gate_loc); + bool found_linux_gate = false; + + const wasteful_vector mappings = dumper.mappings(); + const MappingInfo* mapping; + for (unsigned i = 0; i < mappings.size(); ++i) { + mapping = mappings[i]; + if (!strcmp(mapping->name, kLinuxGateLibraryName)) { + found_linux_gate = true; + break; + } + } + EXPECT_TRUE(found_linux_gate); + EXPECT_EQ(linux_gate_loc, reinterpret_cast(mapping->start_addr)); + EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); +} + +// Ensure that the linux-gate VDSO can generate a non-zeroed File ID. +TEST_F(LinuxPtraceDumperChildTest, LinuxGateMappingID) { + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + + bool found_linux_gate = false; + const wasteful_vector mappings = dumper.mappings(); + unsigned index = 0; + for (unsigned i = 0; i < mappings.size(); ++i) { + if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) { + found_linux_gate = true; + index = i; + break; + } + } + ASSERT_TRUE(found_linux_gate); + + // Need to suspend the child so ptrace actually works. + ASSERT_TRUE(dumper.ThreadsSuspend()); + id_vector identifier(make_vector()); + ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index], + true, + index, + identifier)); + + id_vector empty_identifier(make_vector()); + empty_identifier.resize(kDefaultBuildIdSize, 0); + EXPECT_NE(empty_identifier, identifier); + EXPECT_TRUE(dumper.ThreadsResume()); +} +#endif + +TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) { + // Calculate the File ID of our binary using both + // FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping + // and ensure that we get the same result from both. + char exe_name[PATH_MAX]; + ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); + + LinuxPtraceDumper dumper(getppid()); + ASSERT_TRUE(dumper.Init()); + const wasteful_vector mappings = dumper.mappings(); + bool found_exe = false; + unsigned i; + for (i = 0; i < mappings.size(); ++i) { + const MappingInfo* mapping = mappings[i]; + if (!strcmp(mapping->name, exe_name)) { + found_exe = true; + break; + } + } + ASSERT_TRUE(found_exe); + + id_vector identifier1(make_vector()); + id_vector identifier2(make_vector()); + EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[i], true, i, + identifier1)); + FileID fileid(exe_name); + EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2)); + + string identifier_string1 = + FileID::ConvertIdentifierToUUIDString(identifier1); + string identifier_string2 = + FileID::ConvertIdentifierToUUIDString(identifier2); + EXPECT_EQ(identifier_string1, identifier_string2); +} + +/* Get back to normal behavior of TEST*() macros wrt TestBody. */ +#undef TestBody + +TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) { + static const size_t kNumberOfThreadsInHelperProgram = 5; + + pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram); + ASSERT_NE(child_pid, -1); + + // Children are ready now. + LinuxPtraceDumper dumper(child_pid); + ASSERT_TRUE(dumper.Init()); +#if defined(THREAD_SANITIZER) + EXPECT_GE(dumper.threads().size(), (size_t)kNumberOfThreadsInHelperProgram); +#else + EXPECT_EQ(dumper.threads().size(), (size_t)kNumberOfThreadsInHelperProgram); +#endif + EXPECT_TRUE(dumper.ThreadsSuspend()); + + ThreadInfo one_thread; + size_t matching_threads = 0; + for (size_t i = 0; i < dumper.threads().size(); ++i) { + EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &one_thread)); + const void* stack; + size_t stack_len; + EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len, + one_thread.stack_pointer)); + // In the helper program, we stored a pointer to the thread id in a + // specific register. Check that we can recover its value. +#if defined(__ARM_EABI__) + pid_t* process_tid_location = (pid_t*)(one_thread.regs.uregs[3]); +#elif defined(__aarch64__) + pid_t* process_tid_location = (pid_t*)(one_thread.regs.regs[3]); +#elif defined(__i386) + pid_t* process_tid_location = (pid_t*)(one_thread.regs.ecx); +#elif defined(__x86_64) + pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx); +#elif defined(__mips__) + pid_t* process_tid_location = + reinterpret_cast(one_thread.mcontext.gregs[1]); +#else +#error This test has not been ported to this platform. +#endif + pid_t one_thread_id; + dumper.CopyFromProcess(&one_thread_id, + dumper.threads()[i], + process_tid_location, + 4); + matching_threads += (dumper.threads()[i] == one_thread_id) ? 1 : 0; + } + EXPECT_EQ(matching_threads, kNumberOfThreadsInHelperProgram); + EXPECT_TRUE(dumper.ThreadsResume()); + kill(child_pid, SIGKILL); + + // Reap child + int status; + ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0))); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_EQ(SIGKILL, WTERMSIG(status)); +} + +TEST_F(LinuxPtraceDumperTest, SanitizeStackCopy) { + static const size_t kNumberOfThreadsInHelperProgram = 1; + + pid_t child_pid = SetupChildProcess(kNumberOfThreadsInHelperProgram); + ASSERT_NE(child_pid, -1); + + LinuxPtraceDumper dumper(child_pid); + ASSERT_TRUE(dumper.Init()); + EXPECT_TRUE(dumper.ThreadsSuspend()); + + ThreadInfo thread_info; + EXPECT_TRUE(dumper.GetThreadInfoByIndex(0, &thread_info)); + + const uintptr_t defaced = +#if defined(__LP64__) + 0x0defaced0defaced; +#else + 0x0defaced; +#endif + + uintptr_t simulated_stack[2]; + + // Pointers into the stack shouldn't be sanitized. + memset(simulated_stack, 0xff, sizeof(simulated_stack)); + simulated_stack[1] = thread_info.stack_pointer; + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + sizeof(uintptr_t)); + ASSERT_NE(simulated_stack[1], defaced); + + // Memory prior to the stack pointer should be cleared. + ASSERT_EQ(simulated_stack[0], 0u); + + // Small integers should not be sanitized. + for (int i = -4096; i <= 4096; ++i) { + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[0] = static_cast(i); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_NE(simulated_stack[0], defaced); + } + + // The instruction pointer definitely should point into an executable mapping. + const MappingInfo* mapping_info = dumper.FindMappingNoBias( + reinterpret_cast(thread_info.GetInstructionPointer())); + ASSERT_NE(mapping_info, nullptr); + ASSERT_TRUE(mapping_info->exec); + + // Pointers to code shouldn't be sanitized. + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[1] = thread_info.GetInstructionPointer(); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_NE(simulated_stack[0], defaced); + + // String fragments should be sanitized. + memcpy(simulated_stack, "abcdefghijklmnop", sizeof(simulated_stack)); + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_EQ(simulated_stack[0], defaced); + ASSERT_EQ(simulated_stack[1], defaced); + + // Heap pointers should be sanititzed. +#if defined(__ARM_EABI__) + uintptr_t heap_addr = thread_info.regs.uregs[3]; +#elif defined(__aarch64__) + uintptr_t heap_addr = thread_info.regs.regs[3]; +#elif defined(__i386) + uintptr_t heap_addr = thread_info.regs.ecx; +#elif defined(__x86_64) + uintptr_t heap_addr = thread_info.regs.rcx; +#elif defined(__mips__) + uintptr_t heap_addr = thread_info.mcontext.gregs[1]; +#else +#error This test has not been ported to this platform. +#endif + memset(simulated_stack, 0, sizeof(simulated_stack)); + simulated_stack[0] = heap_addr; + dumper.SanitizeStackCopy(reinterpret_cast(&simulated_stack), + sizeof(simulated_stack), thread_info.stack_pointer, + 0u); + ASSERT_EQ(simulated_stack[0], defaced); + + EXPECT_TRUE(dumper.ThreadsResume()); + kill(child_pid, SIGKILL); + + // Reap child. + int status; + ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0))); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_EQ(SIGKILL, WTERMSIG(status)); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc new file mode 100644 index 0000000000..03066e9110 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc @@ -0,0 +1,1562 @@ +// Copyright (c) 2010, 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. + +// This code writes out minidump files: +// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx +// +// Minidumps are a Microsoft format which Breakpad uses for recording crash +// dumps. This code has to run in a compromised environment (the address space +// may have received SIGSEGV), thus the following rules apply: +// * You may not enter the dynamic linker. This means that we cannot call +// any symbols in a shared library (inc libc). Because of this we replace +// libc functions in linux_libc_support.h. +// * You may not call syscalls via the libc wrappers. This rule is a subset +// of the first rule but it bears repeating. We have direct wrappers +// around the system calls in linux_syscall_support.h. +// * You may not malloc. There's an alternative allocator in memory.h and +// a canonical instance in the LinuxDumper object. We use the placement +// new form to allocate objects and we don't delete them. + +#include "linux/handler/minidump_descriptor.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "minidump_file_writer-inl.h" + +#include +#include +#include +#include +#include +#if defined(__ANDROID__) +#include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "linux/dump_writer_common/thread_info.h" +#include "linux/dump_writer_common/ucontext_reader.h" +#include "linux/handler/exception_handler.h" +#include "linux/minidump_writer/cpu_set.h" +#include "linux/minidump_writer/line_reader.h" +#include "linux/minidump_writer/linux_dumper.h" +#include "linux/minidump_writer/linux_ptrace_dumper.h" +#include "linux/minidump_writer/proc_cpuinfo_reader.h" +#include "minidump_file_writer.h" +#include "common/linux/file_id.h" +#include "common/linux/linux_libc_support.h" +#include "common/minidump_type_helper.h" +#include "google_breakpad/common/minidump_format.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace { + +using google_breakpad::AppMemoryList; +using google_breakpad::auto_wasteful_vector; +using google_breakpad::ExceptionHandler; +using google_breakpad::CpuSet; +using google_breakpad::kDefaultBuildIdSize; +using google_breakpad::LineReader; +using google_breakpad::LinuxDumper; +using google_breakpad::LinuxPtraceDumper; +using google_breakpad::MDTypeHelper; +using google_breakpad::MappingEntry; +using google_breakpad::MappingInfo; +using google_breakpad::MappingList; +using google_breakpad::MinidumpFileWriter; +using google_breakpad::PageAllocator; +using google_breakpad::ProcCpuInfoReader; +using google_breakpad::RawContextCPU; +using google_breakpad::ThreadInfo; +using google_breakpad::TypedMDRVA; +using google_breakpad::UContextReader; +using google_breakpad::UntypedMDRVA; +using google_breakpad::wasteful_vector; + +typedef MDTypeHelper::MDRawDebug MDRawDebug; +typedef MDTypeHelper::MDRawLinkMap MDRawLinkMap; + +class MinidumpWriter { + public: + // The following kLimit* constants are for when minidump_size_limit_ is set + // and the minidump size might exceed it. + // + // Estimate for how big each thread's stack will be (in bytes). + static const unsigned kLimitAverageThreadStackLength = 8 * 1024; + // Number of threads whose stack size we don't want to limit. These base + // threads will simply be the first N threads returned by the dumper (although + // the crashing thread will never be limited). Threads beyond this count are + // the extra threads. + static const unsigned kLimitBaseThreadCount = 20; + // Maximum stack size to dump for any extra thread (in bytes). + static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024; + // Make sure this number of additional bytes can fit in the minidump + // (exclude the stack data). + static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024; + + MinidumpWriter(const char* minidump_path, + int minidump_fd, + const ExceptionHandler::CrashContext* context, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks, + LinuxDumper* dumper) + : fd_(minidump_fd), + path_(minidump_path), + ucontext_(context ? &context->context : NULL), +#if !defined(__ARM_EABI__) && !defined(__mips__) + float_state_(context ? &context->float_state : NULL), +#endif + dumper_(dumper), + minidump_size_limit_(-1), + memory_blocks_(dumper_->allocator()), + mapping_list_(mappings), + app_memory_list_(appmem), + skip_stacks_if_mapping_unreferenced_( + skip_stacks_if_mapping_unreferenced), + principal_mapping_address_(principal_mapping_address), + principal_mapping_(nullptr), + sanitize_stacks_(sanitize_stacks) { + // Assert there should be either a valid fd or a valid path, not both. + assert(fd_ != -1 || minidump_path); + assert(fd_ == -1 || !minidump_path); + } + + bool Init() { + if (!dumper_->Init()) + return false; + + if (!dumper_->ThreadsSuspend() || !dumper_->LateInit()) + return false; + + if (skip_stacks_if_mapping_unreferenced_) { + principal_mapping_ = + dumper_->FindMappingNoBias(principal_mapping_address_); + if (!CrashingThreadReferencesPrincipalMapping()) + return false; + } + + if (fd_ != -1) + minidump_writer_.SetFile(fd_); + else if (!minidump_writer_.Open(path_)) + return false; + + return true; + } + + ~MinidumpWriter() { + // Don't close the file descriptor when it's been provided explicitly. + // Callers might still need to use it. + if (fd_ == -1) + minidump_writer_.Close(); + dumper_->ThreadsResume(); + } + + bool CrashingThreadReferencesPrincipalMapping() { + if (!ucontext_ || !principal_mapping_) + return false; + + const uintptr_t low_addr = + principal_mapping_->system_mapping_info.start_addr; + const uintptr_t high_addr = + principal_mapping_->system_mapping_info.end_addr; + + const uintptr_t stack_pointer = UContextReader::GetStackPointer(ucontext_); + const uintptr_t pc = UContextReader::GetInstructionPointer(ucontext_); + + if (pc >= low_addr && pc < high_addr) + return true; + + uint8_t* stack_copy; + const void* stack; + size_t stack_len; + + if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) + return false; + + stack_copy = reinterpret_cast(Alloc(stack_len)); + dumper_->CopyFromProcess(stack_copy, GetCrashThread(), stack, stack_len); + + uintptr_t stack_pointer_offset = + stack_pointer - reinterpret_cast(stack); + + return dumper_->StackHasPointerToMapping( + stack_copy, stack_len, stack_pointer_offset, *principal_mapping_); + } + + bool Dump() { + // A minidump file contains a number of tagged streams. This is the number + // of stream which we write. + unsigned kNumWriters = 14; + + TypedMDRVA dir(&minidump_writer_); + { + // Ensure the header gets flushed, as that happens in the destructor. + // If we crash somewhere below, we should have a mostly-intact dump + TypedMDRVA header(&minidump_writer_); + if (!header.Allocate()) + return false; + + if (!dir.AllocateArray(kNumWriters)) + return false; + + my_memset(header.get(), 0, sizeof(MDRawHeader)); + + header.get()->signature = MD_HEADER_SIGNATURE; + header.get()->version = MD_HEADER_VERSION; + header.get()->time_date_stamp = time(NULL); + header.get()->stream_count = kNumWriters; + header.get()->stream_directory_rva = dir.position(); + } + + unsigned dir_index = 0; + MDRawDirectory dirent; + + if (!WriteThreadListStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteThreadNamesStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteMappings(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteAppMemory()) + return false; + + if (!WriteMemoryListStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteExceptionStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteSystemInfoStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_CPU_INFO; + if (!WriteFile(&dirent.location, "/proc/cpuinfo")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_PROC_STATUS; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "status")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_LSB_RELEASE; + if (!WriteFile(&dirent.location, "/etc/lsb-release") && + !WriteFile(&dirent.location, "/etc/os-release")) { + NullifyDirectoryEntry(&dirent); + } + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_CMD_LINE; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_ENVIRON; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_AUXV; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_MAPS; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_DSO_DEBUG; + if (!WriteDSODebugStream(&dirent)) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + // If you add more directory entries, don't forget to update kNumWriters, + // above. + + dumper_->ThreadsResume(); + return true; + } + + bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, + uintptr_t pc, int max_stack_len, uint8_t** stack_copy) { + *stack_copy = NULL; + const void* stack; + size_t stack_len; + + thread->stack.start_of_memory_range = stack_pointer; + thread->stack.memory.data_size = 0; + thread->stack.memory.rva = minidump_writer_.position(); + + if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { + if (max_stack_len >= 0 && + stack_len > static_cast(max_stack_len)) { + stack_len = max_stack_len; + // Skip empty chunks of length max_stack_len. + uintptr_t int_stack = reinterpret_cast(stack); + if (max_stack_len > 0) { + while (int_stack + max_stack_len < stack_pointer) { + int_stack += max_stack_len; + } + } + stack = reinterpret_cast(int_stack); + } + *stack_copy = reinterpret_cast(Alloc(stack_len)); + dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack, + stack_len); + + uintptr_t stack_pointer_offset = + stack_pointer - reinterpret_cast(stack); + if (skip_stacks_if_mapping_unreferenced_) { + if (!principal_mapping_) { + return true; + } + uintptr_t low_addr = principal_mapping_->system_mapping_info.start_addr; + uintptr_t high_addr = principal_mapping_->system_mapping_info.end_addr; + if ((pc < low_addr || pc > high_addr) && + !dumper_->StackHasPointerToMapping(*stack_copy, stack_len, + stack_pointer_offset, + *principal_mapping_)) { + return true; + } + } + + if (sanitize_stacks_) { + dumper_->SanitizeStackCopy(*stack_copy, stack_len, stack_pointer, + stack_pointer_offset); + } + + UntypedMDRVA memory(&minidump_writer_); + if (!memory.Allocate(stack_len)) + return false; + memory.Copy(*stack_copy, stack_len); + thread->stack.start_of_memory_range = reinterpret_cast(stack); + thread->stack.memory = memory.location(); + memory_blocks_.push_back(thread->stack); + } + return true; + } + + // Write information about the threads. + bool WriteThreadListStream(MDRawDirectory* dirent) { + const unsigned num_threads = dumper_->threads().size(); + + TypedMDRVA list(&minidump_writer_); + if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread))) + return false; + + dirent->stream_type = MD_THREAD_LIST_STREAM; + dirent->location = list.location(); + + *list.get() = num_threads; + + // If there's a minidump size limit, check if it might be exceeded. Since + // most of the space is filled with stack data, just check against that. + // If this expects to exceed the limit, set extra_thread_stack_len such + // that any thread beyond the first kLimitBaseThreadCount threads will + // have only kLimitMaxExtraThreadStackLen bytes dumped. + int extra_thread_stack_len = -1; // default to no maximum + if (minidump_size_limit_ >= 0) { + const unsigned estimated_total_stack_size = num_threads * + kLimitAverageThreadStackLength; + const off_t estimated_minidump_size = minidump_writer_.position() + + estimated_total_stack_size + kLimitMinidumpFudgeFactor; + if (estimated_minidump_size > minidump_size_limit_) + extra_thread_stack_len = kLimitMaxExtraThreadStackLen; + } + + for (unsigned i = 0; i < num_threads; ++i) { + MDRawThread thread; + my_memset(&thread, 0, sizeof(thread)); + thread.thread_id = dumper_->threads()[i]; + + // We have a different source of information for the crashing thread. If + // we used the actual state of the thread we would find it running in the + // signal handler with the alternative stack, which would be deeply + // unhelpful. + if (static_cast(thread.thread_id) == GetCrashThread() && + ucontext_ && + !dumper_->IsPostMortem()) { + uint8_t* stack_copy; + const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); + if (!FillThreadStack(&thread, stack_ptr, + UContextReader::GetInstructionPointer(ucontext_), + -1, &stack_copy)) + return false; + + // Copy 256 bytes around crashing instruction pointer to minidump. + const size_t kIPMemorySize = 256; + uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); + // Bound it to the upper and lower bounds of the memory map + // it's contained within. If it's not in mapped memory, + // don't bother trying to write it. + bool ip_is_mapped = false; + MDMemoryDescriptor ip_memory_d; + for (unsigned j = 0; j < dumper_->mappings().size(); ++j) { + const MappingInfo& mapping = *dumper_->mappings()[j]; + if (ip >= mapping.start_addr && + ip < mapping.start_addr + mapping.size) { + ip_is_mapped = true; + // Try to get 128 bytes before and after the IP, but + // settle for whatever's available. + ip_memory_d.start_of_memory_range = + std::max(mapping.start_addr, + uintptr_t(ip - (kIPMemorySize / 2))); + uintptr_t end_of_range = + std::min(uintptr_t(ip + (kIPMemorySize / 2)), + uintptr_t(mapping.start_addr + mapping.size)); + ip_memory_d.memory.data_size = + end_of_range - ip_memory_d.start_of_memory_range; + break; + } + } + + if (ip_is_mapped) { + UntypedMDRVA ip_memory(&minidump_writer_); + if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) + return false; + uint8_t* memory_copy = + reinterpret_cast(Alloc(ip_memory_d.memory.data_size)); + dumper_->CopyFromProcess( + memory_copy, + thread.thread_id, + reinterpret_cast(ip_memory_d.start_of_memory_range), + ip_memory_d.memory.data_size); + ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size); + ip_memory_d.memory = ip_memory.location(); + memory_blocks_.push_back(ip_memory_d); + } + + TypedMDRVA cpu(&minidump_writer_); + if (!cpu.Allocate()) + return false; + my_memset(cpu.get(), 0, sizeof(RawContextCPU)); +#if !defined(__ARM_EABI__) && !defined(__mips__) + UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); +#else + UContextReader::FillCPUContext(cpu.get(), ucontext_); +#endif + thread.thread_context = cpu.location(); + crashing_thread_context_ = cpu.location(); + } else { + ThreadInfo info; + if (!dumper_->GetThreadInfoByIndex(i, &info)) + return false; + + uint8_t* stack_copy; + int max_stack_len = -1; // default to no maximum for this thread + if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount) + max_stack_len = extra_thread_stack_len; + if (!FillThreadStack(&thread, info.stack_pointer, + info.GetInstructionPointer(), max_stack_len, + &stack_copy)) + return false; + + TypedMDRVA cpu(&minidump_writer_); + if (!cpu.Allocate()) + return false; + my_memset(cpu.get(), 0, sizeof(RawContextCPU)); + info.FillCPUContext(cpu.get()); + thread.thread_context = cpu.location(); + if (dumper_->threads()[i] == GetCrashThread()) { + crashing_thread_context_ = cpu.location(); + if (!dumper_->IsPostMortem()) { + // This is the crashing thread of a live process, but + // no context was provided, so set the crash address + // while the instruction pointer is already here. + dumper_->set_crash_address(info.GetInstructionPointer()); + } + } + } + + list.CopyIndexAfterObject(i, &thread, sizeof(thread)); + } + + return true; + } + + bool WriteThreadName(pid_t tid, char* name, MDRawThreadName *thread_name) { + MDLocationDescriptor string_location; + + if (!minidump_writer_.WriteString(name, 0, &string_location)) + return false; + + thread_name->thread_id = tid; + thread_name->rva_of_thread_name = string_location.rva; + return true; + } + + // Write the threads' names. + bool WriteThreadNamesStream(MDRawDirectory* thread_names_stream) { + TypedMDRVA list(&minidump_writer_); + const unsigned num_threads = dumper_->threads().size(); + + if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThreadName))) { + return false; + } + + thread_names_stream->stream_type = MD_THREAD_NAMES_STREAM; + thread_names_stream->location = list.location(); + list.get()->number_of_thread_names = num_threads; + + MDRawThreadName thread_name; + int thread_idx = 0; + + for (unsigned int i = 0; i < num_threads; ++i) { + const pid_t tid = dumper_->threads()[i]; + // This is a constant from the Linux kernel, documented in man 5 proc. + // The comm entries in /proc are no longer than this. + static const size_t TASK_COMM_LEN = 16; + char name[TASK_COMM_LEN]; + memset(&thread_name, 0, sizeof(MDRawThreadName)); + + if (dumper_->GetThreadNameByIndex(i, name, sizeof(name))) { + if (WriteThreadName(tid, name, &thread_name)) { + list.CopyIndexAfterObject(thread_idx++, &thread_name, + sizeof(MDRawThreadName)); + } + } + } + + return true; + } + + // Write application-provided memory regions. + bool WriteAppMemory() { + for (AppMemoryList::const_iterator iter = app_memory_list_.begin(); + iter != app_memory_list_.end(); + ++iter) { + uint8_t* data_copy = + reinterpret_cast(dumper_->allocator()->Alloc(iter->length)); + dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr, + iter->length); + + UntypedMDRVA memory(&minidump_writer_); + if (!memory.Allocate(iter->length)) { + return false; + } + memory.Copy(data_copy, iter->length); + MDMemoryDescriptor desc; + desc.start_of_memory_range = reinterpret_cast(iter->ptr); + desc.memory = memory.location(); + memory_blocks_.push_back(desc); + } + + return true; + } + + static bool ShouldIncludeMapping(const MappingInfo& mapping) { + if (mapping.name[0] == 0 || // only want modules with filenames. + // Only want to include one mapping per shared lib. + // Avoid filtering executable mappings. + (mapping.offset != 0 && !mapping.exec) || + mapping.size < 4096) { // too small to get a signature for. + return false; + } + + return true; + } + + // If there is caller-provided information about this mapping + // in the mapping_list_ list, return true. Otherwise, return false. + bool HaveMappingInfo(const MappingInfo& mapping) { + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + // Ignore any mappings that are wholly contained within + // mappings in the mapping_info_ list. + if (mapping.start_addr >= iter->first.start_addr && + (mapping.start_addr + mapping.size) <= + (iter->first.start_addr + iter->first.size)) { + return true; + } + } + return false; + } + + // Write information about the mappings in effect. Because we are using the + // minidump format, the information about the mappings is pretty limited. + // Because of this, we also include the full, unparsed, /proc/$x/maps file in + // another stream in the file. + bool WriteMappings(MDRawDirectory* dirent) { + const unsigned num_mappings = dumper_->mappings().size(); + unsigned num_output_mappings = mapping_list_.size(); + + for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping)) + num_output_mappings++; + } + + TypedMDRVA list(&minidump_writer_); + if (num_output_mappings) { + if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE)) + return false; + } else { + // Still create the module list stream, although it will have zero + // modules. + if (!list.Allocate()) + return false; + } + + dirent->stream_type = MD_MODULE_LIST_STREAM; + dirent->location = list.location(); + *list.get() = num_output_mappings; + + // First write all the mappings from the dumper + unsigned int j = 0; + for (unsigned i = 0; i < num_mappings; ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) + continue; + + MDRawModule mod; + if (!FillRawModule(mapping, true, i, &mod, NULL)) + return false; + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } + // Next write all the mappings provided by the caller + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + MDRawModule mod; + if (!FillRawModule(iter->first, false, 0, &mod, &iter->second)) { + return false; + } + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } + + return true; + } + + // Fill the MDRawModule |mod| with information about the provided + // |mapping|. If |identifier| is non-NULL, use it instead of calculating + // a file ID from the mapping. + bool FillRawModule(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + MDRawModule* mod, + const std::vector* identifier) { + my_memset(mod, 0, MD_MODULE_SIZE); + + mod->base_of_image = mapping.start_addr; + mod->size_of_image = mapping.size; + + auto_wasteful_vector identifier_bytes( + dumper_->allocator()); + + if (identifier) { + // GUID was provided by caller. + identifier_bytes.insert(identifier_bytes.end(), + identifier->begin(), + identifier->end()); + } else { + // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. + if (!dumper_->ElfFileIdentifierForMapping(mapping, + member, + mapping_id, + identifier_bytes)) { + identifier_bytes.clear(); + } + } + + if (!identifier_bytes.empty()) { + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size())) + return false; + + const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE; + cv.Copy(&cv_signature, sizeof(cv_signature)); + cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0], + identifier_bytes.size()); + + mod->cv_record = cv.location(); + } + + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + dumper_->GetMappingEffectiveNameAndPath( + mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); + + MDLocationDescriptor ld; + if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) + return false; + mod->module_name_rva = ld.rva; + return true; + } + + bool WriteMemoryListStream(MDRawDirectory* dirent) { + TypedMDRVA list(&minidump_writer_); + if (!memory_blocks_.empty()) { + if (!list.AllocateObjectAndArray(memory_blocks_.size(), + sizeof(MDMemoryDescriptor))) + return false; + } else { + // Still create the memory list stream, although it will have zero + // memory blocks. + if (!list.Allocate()) + return false; + } + + dirent->stream_type = MD_MEMORY_LIST_STREAM; + dirent->location = list.location(); + + *list.get() = memory_blocks_.size(); + + for (size_t i = 0; i < memory_blocks_.size(); ++i) { + list.CopyIndexAfterObject(i, &memory_blocks_[i], + sizeof(MDMemoryDescriptor)); + } + return true; + } + + bool WriteExceptionStream(MDRawDirectory* dirent) { + TypedMDRVA exc(&minidump_writer_); + if (!exc.Allocate()) + return false; + + MDRawExceptionStream* stream = exc.get(); + my_memset(stream, 0, sizeof(MDRawExceptionStream)); + + dirent->stream_type = MD_EXCEPTION_STREAM; + dirent->location = exc.location(); + + stream->thread_id = GetCrashThread(); + stream->exception_record.exception_code = dumper_->crash_signal(); + stream->exception_record.exception_flags = dumper_->crash_signal_code(); + stream->exception_record.exception_address = dumper_->crash_address(); + const std::vector crash_exception_info = + dumper_->crash_exception_info(); + stream->exception_record.number_parameters = crash_exception_info.size(); + memcpy(stream->exception_record.exception_information, + crash_exception_info.data(), + sizeof(uint64_t) * crash_exception_info.size()); + stream->thread_context = crashing_thread_context_; + + return true; + } + + bool WriteSystemInfoStream(MDRawDirectory* dirent) { + TypedMDRVA si(&minidump_writer_); + if (!si.Allocate()) + return false; + my_memset(si.get(), 0, sizeof(MDRawSystemInfo)); + + dirent->stream_type = MD_SYSTEM_INFO_STREAM; + dirent->location = si.location(); + + WriteCPUInformation(si.get()); + WriteOSInformation(si.get()); + + return true; + } + + bool WriteDSODebugStream(MDRawDirectory* dirent) { + ElfW(Phdr)* phdr = reinterpret_cast(dumper_->auxv()[AT_PHDR]); + char* base; + int phnum = dumper_->auxv()[AT_PHNUM]; + if (!phnum || !phdr) + return false; + + // Assume the program base is at the beginning of the same page as the PHDR + base = reinterpret_cast(reinterpret_cast(phdr) & ~0xfff); + + // Search for the program PT_DYNAMIC segment + ElfW(Addr) dyn_addr = 0; + for (; phnum >= 0; phnum--, phdr++) { + ElfW(Phdr) ph; + if (!dumper_->CopyFromProcess(&ph, dumper_->pid(), phdr, sizeof(ph))) + return false; + + // Adjust base address with the virtual address of the PT_LOAD segment + // corresponding to offset 0 + if (ph.p_type == PT_LOAD && ph.p_offset == 0) { + base -= ph.p_vaddr; + } + if (ph.p_type == PT_DYNAMIC) { + dyn_addr = ph.p_vaddr; + } + } + if (!dyn_addr) + return false; + + ElfW(Dyn) *dynamic = reinterpret_cast(dyn_addr + base); + + // The dynamic linker makes information available that helps gdb find all + // DSOs loaded into the program. If this information is indeed available, + // dump it to a MD_LINUX_DSO_DEBUG stream. + struct r_debug* r_debug = NULL; + uint32_t dynamic_length = 0; + + for (int i = 0; ; ++i) { + ElfW(Dyn) dyn; + dynamic_length += sizeof(dyn); + if (!dumper_->CopyFromProcess(&dyn, dumper_->pid(), dynamic + i, sizeof(dyn))) { + return false; + } + +#ifdef __mips__ + const int32_t debug_tag = DT_MIPS_RLD_MAP; +#else + const int32_t debug_tag = DT_DEBUG; +#endif + if (dyn.d_tag == debug_tag) { + r_debug = reinterpret_cast(dyn.d_un.d_ptr); + continue; + } else if (dyn.d_tag == DT_NULL) { + break; + } + } + + // The "r_map" field of that r_debug struct contains a linked list of all + // loaded DSOs. + // Our list of DSOs potentially is different from the ones in the crashing + // process. So, we have to be careful to never dereference pointers + // directly. Instead, we use CopyFromProcess() everywhere. + // See for a more detailed discussion of the how the dynamic + // loader communicates with debuggers. + + // Count the number of loaded DSOs + int dso_count = 0; + struct r_debug debug_entry; + if (!dumper_->CopyFromProcess(&debug_entry, dumper_->pid(), r_debug, + sizeof(debug_entry))) { + return false; + } + for (struct link_map* ptr = debug_entry.r_map; ptr; ) { + struct link_map map; + if (!dumper_->CopyFromProcess(&map, dumper_->pid(), ptr, sizeof(map))) + return false; + + ptr = map.l_next; + dso_count++; + } + + MDRVA linkmap_rva = MinidumpFileWriter::kInvalidMDRVA; + if (dso_count > 0) { + // If we have at least one DSO, create an array of MDRawLinkMap + // entries in the minidump file. + TypedMDRVA linkmap(&minidump_writer_); + if (!linkmap.AllocateArray(dso_count)) + return false; + linkmap_rva = linkmap.location().rva; + int idx = 0; + + // Iterate over DSOs and write their information to mini dump + for (struct link_map* ptr = debug_entry.r_map; ptr; ) { + struct link_map map; + if (!dumper_->CopyFromProcess(&map, dumper_->pid(), ptr, sizeof(map))) + return false; + + ptr = map.l_next; + char filename[257] = { 0 }; + if (map.l_name) { + dumper_->CopyFromProcess(filename, dumper_->pid(), map.l_name, + sizeof(filename) - 1); + } + MDLocationDescriptor location; + if (!minidump_writer_.WriteString(filename, 0, &location)) + return false; + MDRawLinkMap entry; + entry.name = location.rva; + entry.addr = map.l_addr; + entry.ld = reinterpret_cast(map.l_ld); + linkmap.CopyIndex(idx++, &entry); + } + } + + // Write MD_LINUX_DSO_DEBUG record + TypedMDRVA debug(&minidump_writer_); + if (!debug.AllocateObjectAndArray(1, dynamic_length)) + return false; + my_memset(debug.get(), 0, sizeof(MDRawDebug)); + dirent->stream_type = MD_LINUX_DSO_DEBUG; + dirent->location = debug.location(); + + debug.get()->version = debug_entry.r_version; + debug.get()->map = linkmap_rva; + debug.get()->dso_count = dso_count; + debug.get()->brk = debug_entry.r_brk; + debug.get()->ldbase = debug_entry.r_ldbase; + debug.get()->dynamic = reinterpret_cast(dynamic); + + wasteful_vector dso_debug_data(dumper_->allocator(), dynamic_length); + // The passed-in size to the constructor (above) is only a hint. + // Must call .resize() to do actual initialization of the elements. + dso_debug_data.resize(dynamic_length); + dumper_->CopyFromProcess(&dso_debug_data[0], dumper_->pid(), dynamic, + dynamic_length); + debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); + + return true; + } + + void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; } + + private: + void* Alloc(unsigned bytes) { + return dumper_->allocator()->Alloc(bytes); + } + + pid_t GetCrashThread() const { + return dumper_->crash_thread(); + } + + void NullifyDirectoryEntry(MDRawDirectory* dirent) { + dirent->stream_type = 0; + dirent->location.data_size = 0; + dirent->location.rva = 0; + } + +#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; + static const char vendor_id_name[] = "vendor_id"; + + struct CpuInfoEntry { + const char* info_name; + int value; + bool found; + } cpu_info_table[] = { + { "processor", -1, false }, +#if defined(__i386__) || defined(__x86_64__) + { "model", 0, false }, + { "stepping", 0, false }, + { "cpu family", 0, false }, +#endif + }; + + // processor_architecture should always be set, do this first + sys_info->processor_architecture = +#if defined(__mips__) +# if _MIPS_SIM == _ABIO32 + MD_CPU_ARCHITECTURE_MIPS; +# elif _MIPS_SIM == _ABI64 + MD_CPU_ARCHITECTURE_MIPS64; +# else +# error "This mips ABI is currently not supported (n32)" +#endif +#elif defined(__i386__) + MD_CPU_ARCHITECTURE_X86; +#else + MD_CPU_ARCHITECTURE_AMD64; +#endif + + const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); + if (fd < 0) + return false; + + { + PageAllocator allocator; + ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); + const char* field; + while (reader->GetNextField(&field)) { + bool is_first_entry = true; + for (CpuInfoEntry& entry : cpu_info_table) { + if (!is_first_entry && entry.found) { + // except for the 'processor' field, ignore repeated values. + continue; + } + is_first_entry = false; + if (!my_strcmp(field, entry.info_name)) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + if (value_len == 0) + continue; + + uintptr_t val; + if (my_read_decimal_ptr(&val, value) == value) + continue; + + entry.value = static_cast(val); + entry.found = true; + } + } + + // special case for vendor_id + if (!my_strcmp(field, vendor_id_name)) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + if (value_len > 0) + my_strlcpy(vendor_id, value, sizeof(vendor_id)); + } + } + sys_close(fd); + } + + // make sure we got everything we wanted + for (const CpuInfoEntry& entry : cpu_info_table) { + if (!entry.found) { + return false; + } + } + // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, + // assuming this is the highest id, change it to the number of CPUs + // by adding one. + cpu_info_table[0].value++; + + sys_info->number_of_processors = cpu_info_table[0].value; +#if defined(__i386__) || defined(__x86_64__) + sys_info->processor_level = cpu_info_table[3].value; + sys_info->processor_revision = cpu_info_table[1].value << 8 | + cpu_info_table[2].value; +#endif + + if (vendor_id[0] != '\0') { + my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, + sizeof(sys_info->cpu.x86_cpu_info.vendor_id)); + } + return true; + } +#elif defined(__arm__) || defined(__aarch64__) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + // The CPUID value is broken up in several entries in /proc/cpuinfo. + // This table is used to rebuild it from the entries. + const struct CpuIdEntry { + const char* field; + char format; + char bit_lshift; + char bit_length; + } cpu_id_entries[] = { + { "CPU implementer", 'x', 24, 8 }, + { "CPU variant", 'x', 20, 4 }, + { "CPU part", 'x', 4, 12 }, + { "CPU revision", 'd', 0, 4 }, + }; + + // The ELF hwcaps are listed in the "Features" entry as textual tags. + // This table is used to rebuild them. + const struct CpuFeaturesEntry { + const char* tag; + uint32_t hwcaps; + } cpu_features_entries[] = { +#if defined(__arm__) + { "swp", MD_CPU_ARM_ELF_HWCAP_SWP }, + { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, + { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, + { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT }, + { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT }, + { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA }, + { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP }, + { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP }, + { "java", MD_CPU_ARM_ELF_HWCAP_JAVA }, + { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT }, + { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH }, + { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE }, + { "neon", MD_CPU_ARM_ELF_HWCAP_NEON }, + { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 }, + { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 }, + { "tls", MD_CPU_ARM_ELF_HWCAP_TLS }, + { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 }, + { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, + { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, + { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, +#elif defined(__aarch64__) + // No hwcaps on aarch64. +#endif + }; + + // processor_architecture should always be set, do this first + sys_info->processor_architecture = +#if defined(__aarch64__) + MD_CPU_ARCHITECTURE_ARM64_OLD; +#else + MD_CPU_ARCHITECTURE_ARM; +#endif + + // /proc/cpuinfo is not readable under various sandboxed environments + // (e.g. Android services with the android:isolatedProcess attribute) + // prepare for this by setting default values now, which will be + // returned when this happens. + // + // Note: Bogus values are used to distinguish between failures (to + // read /sys and /proc files) and really badly configured kernels. + sys_info->number_of_processors = 0; + sys_info->processor_level = 1U; // There is no ARMv1 + sys_info->processor_revision = 42; + sys_info->cpu.arm_cpu_info.cpuid = 0; + sys_info->cpu.arm_cpu_info.elf_hwcaps = 0; + + // Counting the number of CPUs involves parsing two sysfs files, + // because the content of /proc/cpuinfo will only mirror the number + // of 'online' cores, and thus will vary with time. + // See http://www.kernel.org/doc/Documentation/cputopology.txt + { + CpuSet cpus_present; + CpuSet cpus_possible; + + int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0); + if (fd >= 0) { + cpus_present.ParseSysFile(fd); + sys_close(fd); + + fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0); + if (fd >= 0) { + cpus_possible.ParseSysFile(fd); + sys_close(fd); + + cpus_present.IntersectWith(cpus_possible); + int cpu_count = cpus_present.GetCount(); + if (cpu_count > 255) + cpu_count = 255; + sys_info->number_of_processors = static_cast(cpu_count); + } + } + } + + // Parse /proc/cpuinfo to reconstruct the CPUID value, as well + // as the ELF hwcaps field. For the latter, it would be easier to + // read /proc/self/auxv but unfortunately, this file is not always + // readable from regular Android applications on later versions + // (>= 4.1) of the Android platform. + const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); + if (fd < 0) { + // Do not return false here to allow the minidump generation + // to happen properly. + return true; + } + + { + PageAllocator allocator; + ProcCpuInfoReader* const reader = + new(allocator) ProcCpuInfoReader(fd); + const char* field; + while (reader->GetNextField(&field)) { + for (const CpuIdEntry& entry : cpu_id_entries) { + if (my_strcmp(entry.field, field) != 0) + continue; + uintptr_t result = 0; + const char* value = reader->GetValue(); + const char* p = value; + if (value[0] == '0' && value[1] == 'x') { + p = my_read_hex_ptr(&result, value+2); + } else if (entry.format == 'x') { + p = my_read_hex_ptr(&result, value); + } else { + p = my_read_decimal_ptr(&result, value); + } + if (p == value) + continue; + + result &= (1U << entry.bit_length)-1; + result <<= entry.bit_lshift; + sys_info->cpu.arm_cpu_info.cpuid |= + static_cast(result); + } +#if defined(__arm__) + // Get the architecture version from the "Processor" field. + // Note that it is also available in the "CPU architecture" field, + // however, some existing kernels are misconfigured and will report + // invalid values here (e.g. 6, while the CPU is ARMv7-A based). + // The "Processor" field doesn't have this issue. + if (!my_strcmp(field, "Processor")) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + // Expected format: (v) + // Where is some text like "ARMv7 Processor rev 2" + // and is a decimal corresponding to the ARM + // architecture number. is either 'l' or 'b' + // and corresponds to the endianess, it is ignored here. + while (value_len > 0 && my_isspace(value[value_len-1])) + value_len--; + + size_t nn = value_len; + while (nn > 0 && value[nn-1] != '(') + nn--; + if (nn > 0 && value[nn] == 'v') { + uintptr_t arch_level = 5; + my_read_decimal_ptr(&arch_level, value + nn + 1); + sys_info->processor_level = static_cast(arch_level); + } + } +#elif defined(__aarch64__) + // The aarch64 architecture does not provide the architecture level + // in the Processor field, so we instead check the "CPU architecture" + // field. + if (!my_strcmp(field, "CPU architecture")) { + uintptr_t arch_level = 0; + const char* value = reader->GetValue(); + const char* p = value; + p = my_read_decimal_ptr(&arch_level, value); + if (p == value) + continue; + sys_info->processor_level = static_cast(arch_level); + } +#endif + // Rebuild the ELF hwcaps from the 'Features' field. + if (!my_strcmp(field, "Features")) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + + // Parse each space-separated tag. + while (value_len > 0) { + const char* tag = value; + size_t tag_len = value_len; + const char* p = my_strchr(tag, ' '); + if (p) { + tag_len = static_cast(p - tag); + value += tag_len + 1; + value_len -= tag_len + 1; + } else { + tag_len = strlen(tag); + value_len = 0; + } + for (const CpuFeaturesEntry& entry : cpu_features_entries) { + if (tag_len == strlen(entry.tag) && + !memcmp(tag, entry.tag, tag_len)) { + sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry.hwcaps; + break; + } + } + } + } + } + sys_close(fd); + } + + return true; + } +#else +# error "Unsupported CPU" +#endif + + bool WriteFile(MDLocationDescriptor* result, const char* filename) { + const int fd = sys_open(filename, O_RDONLY, 0); + if (fd < 0) + return false; + + // We can't stat the files because several of the files that we want to + // read are kernel seqfiles, which always have a length of zero. So we have + // to read as much as we can into a buffer. + static const unsigned kBufSize = 1024 - 2*sizeof(void*); + struct Buffers { + Buffers* next; + size_t len; + uint8_t data[kBufSize]; + } *buffers = reinterpret_cast(Alloc(sizeof(Buffers))); + buffers->next = NULL; + buffers->len = 0; + + size_t total = 0; + for (Buffers* bufptr = buffers;;) { + ssize_t r; + do { + r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len); + } while (r == -1 && errno == EINTR); + + if (r < 1) + break; + + total += r; + bufptr->len += r; + if (bufptr->len == kBufSize) { + bufptr->next = reinterpret_cast(Alloc(sizeof(Buffers))); + bufptr = bufptr->next; + bufptr->next = NULL; + bufptr->len = 0; + } + } + sys_close(fd); + + if (!total) + return false; + + UntypedMDRVA memory(&minidump_writer_); + if (!memory.Allocate(total)) + return false; + for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) { + // Check for special case of a zero-length buffer. This should only + // occur if a file's size happens to be a multiple of the buffer's + // size, in which case the final sys_read() will have resulted in + // zero bytes being read after the final buffer was just allocated. + if (buffers->len == 0) { + // This can only occur with final buffer. + assert(buffers->next == NULL); + continue; + } + memory.Copy(pos, &buffers->data, buffers->len); + pos += buffers->len; + } + *result = memory.location(); + return true; + } + + bool WriteOSInformation(MDRawSystemInfo* sys_info) { +#if defined(__ANDROID__) + sys_info->platform_id = MD_OS_ANDROID; +#else + sys_info->platform_id = MD_OS_LINUX; +#endif + + struct utsname uts; + if (uname(&uts)) + return false; + + static const size_t buf_len = 512; + char buf[buf_len] = {0}; + size_t space_left = buf_len - 1; + const char* info_table[] = { + uts.sysname, + uts.release, + uts.version, + uts.machine, + NULL + }; + bool first_item = true; + for (const char** cur_info = info_table; *cur_info; cur_info++) { + static const char separator[] = " "; + size_t separator_len = sizeof(separator) - 1; + size_t info_len = my_strlen(*cur_info); + if (info_len == 0) + continue; + + if (space_left < info_len + (first_item ? 0 : separator_len)) + break; + + if (!first_item) { + my_strlcat(buf, separator, sizeof(buf)); + space_left -= separator_len; + } + + first_item = false; + my_strlcat(buf, *cur_info, sizeof(buf)); + space_left -= info_len; + } + + MDLocationDescriptor location; + if (!minidump_writer_.WriteString(buf, 0, &location)) + return false; + sys_info->csd_version_rva = location.rva; + + return true; + } + + bool WriteProcFile(MDLocationDescriptor* result, pid_t pid, + const char* filename) { + char buf[NAME_MAX]; + if (!dumper_->BuildProcPath(buf, pid, filename)) + return false; + return WriteFile(result, buf); + } + + // Only one of the 2 member variables below should be set to a valid value. + const int fd_; // File descriptor where the minidum should be written. + const char* path_; // Path to the file where the minidum should be written. + + const ucontext_t* const ucontext_; // also from the signal handler +#if !defined(__ARM_EABI__) && !defined(__mips__) + const google_breakpad::fpstate_t* const float_state_; // ditto +#endif + LinuxDumper* dumper_; + MinidumpFileWriter minidump_writer_; + off_t minidump_size_limit_; + MDLocationDescriptor crashing_thread_context_; + // Blocks of memory written to the dump. These are all currently + // written while writing the thread list stream, but saved here + // so a memory list stream can be written afterwards. + wasteful_vector memory_blocks_; + // Additional information about some mappings provided by the caller. + const MappingList& mapping_list_; + // Additional memory regions to be included in the dump, + // provided by the caller. + const AppMemoryList& app_memory_list_; + // If set, skip recording any threads that do not reference the + // mapping containing principal_mapping_address_. + bool skip_stacks_if_mapping_unreferenced_; + uintptr_t principal_mapping_address_; + const MappingInfo* principal_mapping_; + // If true, apply stack sanitization to stored stack data. + bool sanitize_stacks_; +}; + + +bool WriteMinidumpImpl(const char* minidump_path, + int minidump_fd, + off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + LinuxPtraceDumper dumper(crashing_process); + const ExceptionHandler::CrashContext* context = NULL; + if (blob) { + if (blob_size != sizeof(ExceptionHandler::CrashContext)) + return false; + context = reinterpret_cast(blob); + dumper.SetCrashInfoFromSigInfo(context->siginfo); + dumper.set_crash_thread(context->tid); + } + MinidumpWriter writer(minidump_path, minidump_fd, context, mappings, + appmem, skip_stacks_if_mapping_unreferenced, + principal_mapping_address, sanitize_stacks, &dumper); + // Set desired limit for file size of minidump (-1 means no limit). + writer.set_minidump_size_limit(minidump_size_limit); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +} // namespace + +namespace google_breakpad { + +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(minidump_path, -1, -1, + crashing_process, blob, blob_size, + MappingList(), AppMemoryList(), + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(NULL, minidump_fd, -1, + crashing_process, blob, blob_size, + MappingList(), AppMemoryList(), + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(const char* minidump_path, pid_t process, + pid_t process_blamed_thread) { + LinuxPtraceDumper dumper(process); + // MinidumpWriter will set crash address + dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED); + dumper.set_crash_thread(process_blamed_thread); + MappingList mapping_list; + AppMemoryList app_memory_list; + MinidumpWriter writer(minidump_path, -1, NULL, mapping_list, + app_memory_list, false, 0, false, &dumper); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process, + blob, blob_size, + mappings, appmem, + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process, + blob, blob_size, + mappings, appmem, + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit, + crashing_process, blob, blob_size, + mappings, appmem, + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem, + bool skip_stacks_if_mapping_unreferenced, + uintptr_t principal_mapping_address, + bool sanitize_stacks) { + return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit, + crashing_process, blob, blob_size, + mappings, appmem, + skip_stacks_if_mapping_unreferenced, + principal_mapping_address, + sanitize_stacks); +} + +bool WriteMinidump(const char* filename, + const MappingList& mappings, + const AppMemoryList& appmem, + LinuxDumper* dumper) { + MinidumpWriter writer(filename, -1, NULL, mappings, appmem, + false, 0, false, dumper); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.h new file mode 100644 index 0000000000..1d02ec8d7d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.h @@ -0,0 +1,143 @@ +// Copyright (c) 2009, 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_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include "linux/minidump_writer/linux_dumper.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class ExceptionHandler; + +#if defined(__aarch64__) +typedef struct fpsimd_context fpstate_t; +#elif !defined(__ARM_EABI__) && !defined(__mips__) +typedef std::remove_pointer::type fpstate_t; +#endif + +// These entries store a list of memory regions that the client wants included +// in the minidump. +struct AppMemory { + void* ptr; + size_t length; + + bool operator==(const struct AppMemory& other) const { + return ptr == other.ptr; + } + + bool operator==(const void* other) const { + return ptr == other; + } +}; +typedef std::list AppMemoryList; + +// Writes a minidump to the filesystem. These functions do not malloc nor use +// libc functions which may. Thus, it can be used in contexts where the state +// of the heap may be corrupt. +// minidump_path: the path to the file to write to. This is opened O_EXCL and +// fails open fails. +// crashing_process: the pid of the crashing process. This must be trusted. +// blob: a blob of data from the crashing process. See exception_handler.h +// blob_size: the length of |blob|, in bytes +// +// Returns true iff successful. +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); +// Same as above but takes an open file descriptor instead of a path. +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); + +// Alternate form of WriteMinidump() that works with processes that +// are not expected to have crashed. If |process_blamed_thread| is +// meaningful, it will be the one from which a crash signature is +// extracted. It is not expected that this function will be called +// from a compromised context, but it is safe to do so. +bool WriteMinidump(const char* minidump_path, pid_t process, + pid_t process_blamed_thread); + +// These overloads also allow passing a list of known mappings and +// a list of additional memory regions to be included in the minidump. +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); + +// These overloads also allow passing a file size limit for the minidump. +bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); +bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata, + bool skip_stacks_if_mapping_unreferenced = false, + uintptr_t principal_mapping_address = 0, + bool sanitize_stacks = false); + +bool WriteMinidump(const char* filename, + const MappingList& mappings, + const AppMemoryList& appdata, + LinuxDumper* dumper); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest.cc new file mode 100644 index 0000000000..4e49a4e577 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest.cc @@ -0,0 +1,934 @@ +// Copyright (c) 2011 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 +#include +#include +#include +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "linux/handler/exception_handler.h" +#include "linux/minidump_writer/linux_dumper.h" +#include "linux/minidump_writer/minidump_writer.h" +#include "linux/minidump_writer/minidump_writer_unittest_utils.h" +#include "common/linux/breakpad_getcontext.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/file_id.h" +#include "common/linux/ignore_ret.h" +#include "common/linux/safe_readlink.h" +#include "common/scoped_ptr.h" +#include "common/tests/auto_tempdir.h" +#include "common/tests/file_utils.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/minidump.h" + +using namespace google_breakpad; + +namespace { + +typedef testing::Test MinidumpWriterTest; + +const char kMDWriterUnitTestFileName[] = "/minidump-writer-unittest"; + +TEST(MinidumpWriterTest, SetupWithPath) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + // Set a non-zero tid to avoid tripping asserts. + context.tid = child; + ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context))); + struct stat st; + ASSERT_EQ(0, stat(templ.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +TEST(MinidumpWriterTest, SetupWithFD) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + HANDLE_EINTR(read(fds[0], &b, sizeof(b))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU); + // Set a non-zero tid to avoid tripping asserts. + context.tid = child; + ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context))); + struct stat st; + ASSERT_EQ(0, stat(templ.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that mapping info can be specified when writing a minidump, +// and that it ends up in the module list of the minidump. +TEST(MinidumpWriterTest, MappingInfo) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t memory_size = sysconf(_SC_PAGESIZE); + const char* kMemoryName = "a fake module"; + const uint8_t kModuleGUID[sizeof(MDGUID)] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + const string module_identifier = "33221100554477668899AABBCCDDEEFF0"; + + // Get some memory. + char* memory = + reinterpret_cast(mmap(NULL, + memory_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + + // Add information about the mapped memory. + MappingInfo info; + info.start_addr = kMemoryAddress; + info.size = memory_size; + info.offset = 0; + info.exec = false; + strcpy(info.name, kMemoryName); + + MappingList mappings; + AppMemoryList memory_list; + MappingEntry mapping; + mapping.first = info; + mapping.second.assign(std::begin(kModuleGUID), std::end(kModuleGUID)); + mappings.push_back(mapping); + ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context), + mappings, memory_list, false, 0, false)); + + // Read the minidump. Load the module list, and ensure that + // the mmap'ed |memory| is listed with the given module name + // and debug ID. + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* module = + module_list->GetModuleForAddress(kMemoryAddress); + ASSERT_TRUE(module); + + EXPECT_EQ(kMemoryAddress, module->base_address()); + EXPECT_EQ(memory_size, module->size()); + EXPECT_EQ(kMemoryName, module->code_file()); + EXPECT_EQ(module_identifier, module->debug_identifier()); + + uint32_t len; + // These streams are expected to be there + EXPECT_TRUE(minidump.SeekToStreamType(MD_THREAD_LIST_STREAM, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_MEMORY_LIST_STREAM, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_EXCEPTION_STREAM, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_SYSTEM_INFO_STREAM, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CPU_INFO, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_PROC_STATUS, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CMD_LINE, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_ENVIRON, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_AUXV, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_MAPS, &len)); + EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_DSO_DEBUG, &len)); + + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that minidumping is skipped while writing minidumps if principal mapping +// is not referenced. +TEST(MinidumpWriterTest, MinidumpSkippedIfRequested) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + + // pass an invalid principal mapping address, which will force + // WriteMinidump to not write a minidump. + ASSERT_FALSE(WriteMinidump(templ.c_str(), child, &context, sizeof(context), + true, static_cast(0x0102030405060708ull), + false)); + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that minidumping is skipped while writing minidumps if principal mapping +// is not referenced. +TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + + // Create a thread that does not return, and only references libc (not the + // current executable). This thread should not be captured in the minidump. + pthread_t thread; + pthread_attr_t thread_attributes; + pthread_attr_init(&thread_attributes); + pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED); + sigset_t sigset; + sigemptyset(&sigset); + pthread_create(&thread, &thread_attributes, + reinterpret_cast(&sigsuspend), &sigset); + + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + + // Pass an invalid principal mapping address, which will force + // WriteMinidump to not dump any thread stacks. + ASSERT_TRUE(WriteMinidump( + templ.c_str(), child, &context, sizeof(context), true, + reinterpret_cast(google_breakpad::WriteFile), false)); + + // Read the minidump. And ensure that thread memory was dumped only for the + // main thread. + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + MinidumpThreadList *threads = minidump.GetThreadList(); + int threads_with_stacks = 0; + for (unsigned int i = 0; i < threads->thread_count(); ++i) { + MinidumpThread *thread = threads->GetThreadAtIndex(i); + if (thread->GetMemory()) { + ++threads_with_stacks; + } + } +#if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER) + ASSERT_GE(threads_with_stacks, 1); +#else + ASSERT_EQ(threads_with_stacks, 1); +#endif + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that stacks can be sanitized while writing minidumps. +TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + // pass an invalid principal mapping address, which will force + // WriteMinidump to not dump any thread stacks. + ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context), + false, 0, true)); + + // Read the minidump. And ensure that thread memory contains a defaced value. + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + const uintptr_t defaced = +#if defined(__LP64__) + 0x0defaced0defaced; +#else + 0x0defaced; +#endif + MinidumpThreadList *threads = minidump.GetThreadList(); + for (unsigned int i = 0; i < threads->thread_count(); ++i) { + MinidumpThread *thread = threads->GetThreadAtIndex(i); + MinidumpMemoryRegion *mem = thread->GetMemory(); + ASSERT_TRUE(mem != nullptr); + uint32_t sz = mem->GetSize(); + const uint8_t *data = mem->GetMemory(); + ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr); + } + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that a binary with a longer-than-usual build id note +// makes its way all the way through to the minidump unscathed. +// The linux_client_unittest is linked with an explicit --build-id +// in Makefile.am. +TEST(MinidumpWriterTest, BuildIDLong) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + const string dump_path = temp_dir.path() + kMDWriterUnitTestFileName; + + EXPECT_TRUE(WriteMinidump(dump_path.c_str(), + child, &context, sizeof(context))); + close(fds[1]); + + // Read the minidump. Load the module list, and ensure that + // the main module has the correct debug id and code id. + Minidump minidump(dump_path); + ASSERT_TRUE(minidump.Read()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* module = module_list->GetMainModule(); + ASSERT_TRUE(module); + const string module_identifier = "030201000504070608090A0B0C0D0E0F0"; + // This is passed explicitly to the linker in Makefile.am + const string build_id = + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + EXPECT_EQ(module_identifier, module->debug_identifier()); + EXPECT_EQ(build_id, module->code_identifier()); + + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that mapping info can be specified, and that it overrides +// existing mappings that are wholly contained within the specified +// range. +TEST(MinidumpWriterTest, MappingInfoContained) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const int32_t memory_size = sysconf(_SC_PAGESIZE); + const char* kMemoryName = "a fake module"; + const uint8_t kModuleGUID[sizeof(MDGUID)] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + const string module_identifier = "33221100554477668899AABBCCDDEEFF0"; + + // mmap a file + AutoTempDir temp_dir; + string tempfile = temp_dir.path() + "/minidump-writer-unittest-temp"; + int fd = open(tempfile.c_str(), O_RDWR | O_CREAT, 0); + ASSERT_NE(-1, fd); + unlink(tempfile.c_str()); + // fill with zeros + google_breakpad::scoped_array buffer(new char[memory_size]); + memset(buffer.get(), 0, memory_size); + ASSERT_EQ(memory_size, write(fd, buffer.get(), memory_size)); + lseek(fd, 0, SEEK_SET); + + char* memory = + reinterpret_cast(mmap(NULL, + memory_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + fd, + 0)); + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + close(fd); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + context.tid = 1; + + string dumpfile = temp_dir.path() + kMDWriterUnitTestFileName; + + // Add information about the mapped memory. Report it as being larger than + // it actually is. + MappingInfo info; + info.start_addr = kMemoryAddress - memory_size; + info.size = memory_size * 3; + info.offset = 0; + info.exec = false; + strcpy(info.name, kMemoryName); + + MappingList mappings; + AppMemoryList memory_list; + MappingEntry mapping; + mapping.first = info; + mapping.second.assign(std::begin(kModuleGUID), std::end(kModuleGUID)); + mappings.push_back(mapping); + ASSERT_TRUE(WriteMinidump(dumpfile.c_str(), child, &context, sizeof(context), + mappings, memory_list)); + + // Read the minidump. Load the module list, and ensure that + // the mmap'ed |memory| is listed with the given module name + // and debug ID. + Minidump minidump(dumpfile); + ASSERT_TRUE(minidump.Read()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* module = + module_list->GetModuleForAddress(kMemoryAddress); + ASSERT_TRUE(module); + + EXPECT_EQ(info.start_addr, module->base_address()); + EXPECT_EQ(info.size, module->size()); + EXPECT_EQ(kMemoryName, module->code_file()); + EXPECT_EQ(module_identifier, module->debug_identifier()); + + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +TEST(MinidumpWriterTest, DeletedBinary) { + const string kNumberOfThreadsArgument = "1"; + const string helper_path(GetHelperBinary()); + if (helper_path.empty()) { + FAIL() << "Couldn't find helper binary"; + exit(1); + } + + // Copy binary to a temp file. + AutoTempDir temp_dir; + string binpath = temp_dir.path() + "/linux-dumper-unittest-helper"; + ASSERT_TRUE(CopyFile(helper_path.c_str(), binpath.c_str())) + << "Failed to copy " << helper_path << " to " << binpath; + ASSERT_EQ(0, chmod(binpath.c_str(), 0755)); + + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + pid_t child_pid = fork(); + if (child_pid == 0) { + // In child process. + close(fds[0]); + + // Pass the pipe fd and the number of threads as arguments. + char pipe_fd_string[8]; + sprintf(pipe_fd_string, "%d", fds[1]); + execl(binpath.c_str(), + binpath.c_str(), + pipe_fd_string, + kNumberOfThreadsArgument.c_str(), + NULL); + } + close(fds[1]); + // Wait for the child process to signal that it's ready. + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fds[0]; + pfd.events = POLLIN | POLLERR; + + const int r = HANDLE_EINTR(poll(&pfd, 1, 1000)); + ASSERT_EQ(1, r); + ASSERT_TRUE(pfd.revents & POLLIN); + uint8_t junk; + const int nr = HANDLE_EINTR(read(fds[0], &junk, sizeof(junk))); + ASSERT_EQ(static_cast(sizeof(junk)), nr); + close(fds[0]); + + // Child is ready now. + // Unlink the test binary. + unlink(binpath.c_str()); + + ExceptionHandler::CrashContext context; + memset(&context, 0, sizeof(context)); + + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + // Set a non-zero tid to avoid tripping asserts. + context.tid = child_pid; + ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context, + sizeof(context))); + kill(child_pid, SIGKILL); + + struct stat st; + ASSERT_EQ(0, stat(templ.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + // Check that the main module filename is correct. + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* module = module_list->GetMainModule(); + EXPECT_STREQ(binpath.c_str(), module->code_file().c_str()); + // Check that the file ID is correct. + FileID fileid(helper_path.c_str()); + PageAllocator allocator; + wasteful_vector identifier(&allocator, kDefaultBuildIdSize); + EXPECT_TRUE(fileid.ElfFileIdentifier(identifier)); + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + string module_identifier(identifier_string); + // Strip out dashes + size_t pos; + while ((pos = module_identifier.find('-')) != string::npos) { + module_identifier.erase(pos, 1); + } + // And append a zero, because module IDs include an "age" field + // which is always zero on Linux. + module_identifier += "0"; + EXPECT_EQ(module_identifier, module->debug_identifier()); + + IGNORE_EINTR(waitpid(child_pid, nullptr, 0)); +} + +// Test that an additional memory region can be added to the minidump. +TEST(MinidumpWriterTest, AdditionalMemory) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); + + // Get some heap memory. + uint8_t* memory = new uint8_t[kMemorySize]; + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + // Stick some data into the memory so the contents can be verified. + for (uint32_t i = 0; i < kMemorySize; ++i) { + memory[i] = i % 255; + } + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + HANDLE_EINTR(read(fds[0], &b, sizeof(b))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + + // This needs a valid context for minidump writing to work, but getting + // a useful one from the child is too much work, so just use one from + // the parent since the child is just a forked copy anyway. + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + unlink(templ.c_str()); + + MappingList mappings; + AppMemoryList memory_list; + + // Add the memory region to the list of memory to be included. + AppMemory app_memory; + app_memory.ptr = memory; + app_memory.length = kMemorySize; + memory_list.push_back(app_memory); + ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context), + mappings, memory_list)); + + // Read the minidump. Ensure that the memory region is present + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(dump_memory_list); + const MinidumpMemoryRegion* region = + dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemoryAddress, region->GetBase()); + EXPECT_EQ(kMemorySize, region->GetSize()); + + // Verify memory contents. + EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize)); + + delete[] memory; + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that an invalid thread stack pointer still results in a minidump. +TEST(MinidumpWriterTest, InvalidStackPointer) { + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + char b; + HANDLE_EINTR(read(fds[0], &b, sizeof(b))); + close(fds[0]); + syscall(__NR_exit_group); + } + close(fds[0]); + + ExceptionHandler::CrashContext context; + + // This needs a valid context for minidump writing to work, but getting + // a useful one from the child is too much work, so just use one from + // the parent since the child is just a forked copy anyway. + ASSERT_EQ(0, getcontext(&context.context)); + context.tid = child; + + // Fake the child's stack pointer for its crashing thread. NOTE: This must + // be an invalid memory address for the child process (stack or otherwise). + // Try 1MB below the current stack. + uintptr_t invalid_stack_pointer = + reinterpret_cast(&context) - 1024*1024; +#if defined(__i386) + context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer; +#elif defined(__x86_64) + context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer; +#elif defined(__ARM_EABI__) + context.context.uc_mcontext.arm_sp = invalid_stack_pointer; +#elif defined(__aarch64__) + context.context.uc_mcontext.sp = invalid_stack_pointer; +#elif defined(__mips__) + context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] = + invalid_stack_pointer; +#else +# error "This code has not been ported to your platform yet." +#endif + + AutoTempDir temp_dir; + string templ = temp_dir.path() + kMDWriterUnitTestFileName; + // NOTE: In previous versions of Breakpad, WriteMinidump() would fail if + // presented with an invalid stack pointer. + ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context))); + + // Read the minidump. Ensure that the memory region is present + Minidump minidump(templ); + ASSERT_TRUE(minidump.Read()); + + // TODO(ted.mielczarek,mkrebs): Enable this part of the test once + // https://breakpad.appspot.com/413002/ is committed. +#if 0 + // Make sure there's a thread without a stack. NOTE: It's okay if + // GetThreadList() shows the error: "ERROR: MinidumpThread has a memory + // region problem". + MinidumpThreadList* dump_thread_list = minidump.GetThreadList(); + ASSERT_TRUE(dump_thread_list); + bool found_empty_stack = false; + for (int i = 0; i < dump_thread_list->thread_count(); i++) { + MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); + ASSERT_TRUE(thread->thread() != NULL); + // When the stack size is zero bytes, GetMemory() returns NULL. + if (thread->GetMemory() == NULL) { + found_empty_stack = true; + break; + } + } + // NOTE: If you fail this, first make sure that "invalid_stack_pointer" + // above is indeed set to an invalid address. + ASSERT_TRUE(found_empty_stack); +#endif + + close(fds[1]); + IGNORE_EINTR(waitpid(child, nullptr, 0)); +} + +// Test that limiting the size of the minidump works. +TEST(MinidumpWriterTest, MinidumpSizeLimit) { + static const int kNumberOfThreadsInHelperProgram = 40; + + char number_of_threads_arg[3]; + sprintf(number_of_threads_arg, "%d", kNumberOfThreadsInHelperProgram); + + string helper_path(GetHelperBinary()); + if (helper_path.empty()) { + FAIL() << "Couldn't find helper binary"; + exit(1); + } + + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + pid_t child_pid = fork(); + if (child_pid == 0) { + // In child process. + close(fds[0]); + + // Pass the pipe fd and the number of threads as arguments. + char pipe_fd_string[8]; + sprintf(pipe_fd_string, "%d", fds[1]); + execl(helper_path.c_str(), + helper_path.c_str(), + pipe_fd_string, + number_of_threads_arg, + NULL); + } + close(fds[1]); + + // Wait for all child threads to indicate that they have started + for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) { + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fds[0]; + pfd.events = POLLIN | POLLERR; + + const int r = HANDLE_EINTR(poll(&pfd, 1, 1000)); + ASSERT_EQ(1, r); + ASSERT_TRUE(pfd.revents & POLLIN); + uint8_t junk; + ASSERT_EQ(read(fds[0], &junk, sizeof(junk)), + static_cast(sizeof(junk))); + } + close(fds[0]); + + // There is a race here because we may stop a child thread before + // it is actually running the busy loop. Empirically this sleep + // is sufficient to avoid the race. + usleep(100000); + + // Child and its threads are ready now. + + + off_t normal_file_size; + int total_normal_stack_size = 0; + AutoTempDir temp_dir; + + // First, write a minidump with no size limit. + { + string normal_dump = temp_dir.path() + + "/minidump-writer-unittest.dmp"; + ASSERT_TRUE(WriteMinidump(normal_dump.c_str(), -1, + child_pid, NULL, 0, + MappingList(), AppMemoryList())); + struct stat st; + ASSERT_EQ(0, stat(normal_dump.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + normal_file_size = st.st_size; + + Minidump minidump(normal_dump); + ASSERT_TRUE(minidump.Read()); + MinidumpThreadList* dump_thread_list = minidump.GetThreadList(); + ASSERT_TRUE(dump_thread_list); + for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) { + MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); + ASSERT_TRUE(thread->thread() != NULL); + // When the stack size is zero bytes, GetMemory() returns NULL. + MinidumpMemoryRegion* memory = thread->GetMemory(); + ASSERT_TRUE(memory != NULL); + total_normal_stack_size += memory->GetSize(); + } + } + + // Second, write a minidump with a size limit big enough to not trigger + // anything. + { + // Set size limit arbitrarily 1MB larger than the normal file size -- such + // that the limiting code will not kick in. + const off_t minidump_size_limit = normal_file_size + 1024*1024; + + string same_dump = temp_dir.path() + + "/minidump-writer-unittest-same.dmp"; + ASSERT_TRUE(WriteMinidump(same_dump.c_str(), minidump_size_limit, + child_pid, NULL, 0, + MappingList(), AppMemoryList())); + struct stat st; + ASSERT_EQ(0, stat(same_dump.c_str(), &st)); + // Make sure limiting wasn't actually triggered. NOTE: If you fail this, + // first make sure that "minidump_size_limit" above is indeed set to a + // large enough value -- the limit-checking code in minidump_writer.cc + // does just a rough estimate. + ASSERT_EQ(normal_file_size, st.st_size); + } + + // Third, write a minidump with a size limit small enough to be triggered. + { + // Set size limit to some arbitrary amount, such that the limiting code + // will kick in. The equation used to set this value was determined by + // simply reversing the size-limit logic a little bit in order to pick a + // size we know will trigger it. The definition of + // kLimitAverageThreadStackLength here was copied from class + // MinidumpWriter in minidump_writer.cc. + static const unsigned kLimitAverageThreadStackLength = 8 * 1024; + off_t minidump_size_limit = kNumberOfThreadsInHelperProgram * + kLimitAverageThreadStackLength; + // If, in reality, each of the threads' stack is *smaller* than + // kLimitAverageThreadStackLength, the normal file size could very well be + // smaller than the arbitrary limit that was just set. In that case, + // either of these numbers should trigger the size-limiting code, but we + // might as well pick the smallest. + if (normal_file_size < minidump_size_limit) + minidump_size_limit = normal_file_size; + + string limit_dump = temp_dir.path() + + "/minidump-writer-unittest-limit.dmp"; + ASSERT_TRUE(WriteMinidump(limit_dump.c_str(), minidump_size_limit, + child_pid, NULL, 0, + MappingList(), AppMemoryList())); + struct stat st; + ASSERT_EQ(0, stat(limit_dump.c_str(), &st)); + ASSERT_GT(st.st_size, 0); + // Make sure the file size is at least smaller than the original. If this + // fails because it's the same size, then the size-limit logic didn't kick + // in like it was supposed to. + EXPECT_LT(st.st_size, normal_file_size); + + Minidump minidump(limit_dump); + ASSERT_TRUE(minidump.Read()); + MinidumpThreadList* dump_thread_list = minidump.GetThreadList(); + ASSERT_TRUE(dump_thread_list); + int total_limit_stack_size = 0; + for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) { + MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i); + ASSERT_TRUE(thread->thread() != NULL); + // When the stack size is zero bytes, GetMemory() returns NULL. + MinidumpMemoryRegion* memory = thread->GetMemory(); + ASSERT_TRUE(memory != NULL); + total_limit_stack_size += memory->GetSize(); + } + + // Make sure stack size shrunk by at least 1KB per extra thread. The + // definition of kLimitBaseThreadCount here was copied from class + // MinidumpWriter in minidump_writer.cc. + // Note: The 1KB is arbitrary, and assumes that the thread stacks are big + // enough to shrink by that much. For example, if each thread stack was + // originally only 2KB, the current size-limit logic wouldn't actually + // shrink them because that's the size to which it tries to shrink. If + // you fail this part of the test due to something like that, the test + // logic should probably be improved to account for your situation. + const unsigned kLimitBaseThreadCount = 20; + const unsigned kMinPerExtraThreadStackReduction = 1024; + const int min_expected_reduction = (kNumberOfThreadsInHelperProgram - + kLimitBaseThreadCount) * kMinPerExtraThreadStackReduction; + EXPECT_LT(total_limit_stack_size, + total_normal_stack_size - min_expected_reduction); + } + + // Kill the helper program. + kill(child_pid, SIGKILL); + IGNORE_EINTR(waitpid(child_pid, nullptr, 0)); +} + +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.cc new file mode 100644 index 0000000000..3e27be73cc --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 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_writer_unittest_utils.cc: +// Shared routines used by unittests under linux/minidump_writer. + +#include +#include + +#include "linux/minidump_writer/minidump_writer_unittest_utils.h" +#include "common/linux/safe_readlink.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +string GetHelperBinary() { + string helper_path; + char *bindir = getenv("bindir"); + if (bindir) { + helper_path = string(bindir) + "/"; + } else { + // Locate helper binary next to the current binary. + char self_path[PATH_MAX]; + if (!SafeReadLink("/proc/self/exe", self_path)) { + return ""; + } + helper_path = string(self_path); + size_t pos = helper_path.rfind('/'); + if (pos == string::npos) { + return ""; + } + helper_path.erase(pos + 1); + } + + helper_path += "linux_dumper_unittest_helper"; + + return helper_path; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.h new file mode 100644 index 0000000000..bc7b7c83f4 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer_unittest_utils.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012, 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_writer_unittest_utils.h: +// Shared routines used by unittests under linux/minidump_writer. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_ + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// Returns the full path to linux_dumper_unittest_helper. The full path is +// discovered either by using the environment variable "bindir" or by using +// the location of the main module of the currently running process. +string GetHelperBinary(); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader.h b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader.h new file mode 100644 index 0000000000..94a637fc15 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader.h @@ -0,0 +1,130 @@ +// Copyright (c) 2013, 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_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ + +#include +#include +#include + +#include "linux/minidump_writer/line_reader.h" +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for reading /proc/cpuinfo without using fopen/fgets or other +// functions which may allocate memory. +class ProcCpuInfoReader { +public: + ProcCpuInfoReader(int fd) + : line_reader_(fd), pop_count_(-1) { + } + + // Return the next field name, or NULL in case of EOF. + // field: (output) Pointer to zero-terminated field name. + // Returns true on success, or false on EOF or error (line too long). + bool GetNextField(const char** field) { + for (;;) { + const char* line; + unsigned line_len; + + // Try to read next line. + if (pop_count_ >= 0) { + line_reader_.PopLine(pop_count_); + pop_count_ = -1; + } + + if (!line_reader_.GetNextLine(&line, &line_len)) + return false; + + pop_count_ = static_cast(line_len); + + const char* line_end = line + line_len; + + // Expected format: + ':' + // Note that: + // - empty lines happen. + // - can contain spaces. + // - some fields have an empty + char* sep = static_cast(my_memchr(line, ':', line_len)); + if (sep == NULL) + continue; + + // Record the value. Skip leading space after the column to get + // its start. + const char* val = sep+1; + while (val < line_end && my_isspace(*val)) + val++; + + value_ = val; + value_len_ = static_cast(line_end - val); + + // Remove trailing spaces before the column to properly 0-terminate + // the field name. + while (sep > line && my_isspace(sep[-1])) + sep--; + + if (sep == line) + continue; + + // zero-terminate field name. + *sep = '\0'; + + *field = line; + return true; + } + } + + // Return the field value. This must be called after a succesful + // call to GetNextField(). + const char* GetValue() { + assert(value_); + return value_; + } + + // Same as GetValue(), but also returns the length in characters of + // the value. + const char* GetValueAndLen(size_t* length) { + assert(value_); + *length = value_len_; + return value_; + } + +private: + LineReader line_reader_; + int pop_count_; + const char* value_; + size_t value_len_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ diff --git a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc new file mode 100644 index 0000000000..26fe9e3a38 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2013, 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 +#include +#include +#include +#include +#include + +#include "linux/minidump_writer/proc_cpuinfo_reader.h" +#include "breakpad_googletest_includes.h" +#include "common/linux/tests/auto_testfile.h" + +using namespace google_breakpad; + +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + + +namespace { + +typedef testing::Test ProcCpuInfoReaderTest; + +class ScopedTestFile : public AutoTestFile { +public: + explicit ScopedTestFile(const char* text) + : AutoTestFile("proc_cpuinfo_reader", text) { + } +}; + +} + +TEST(ProcCpuInfoReaderTest, EmptyFile) { + ScopedTestFile file(""); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char *field; + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, OneLineTerminated) { + ScopedTestFile file("foo : bar\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char *field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, OneLine) { + ScopedTestFile file("foo : bar"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char *field; + size_t value_len; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValueAndLen(&value_len)); + ASSERT_EQ(3U, value_len); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) { + ScopedTestFile file("foo : bar\nzoo : tut\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("zoo", field); + ASSERT_STREQ("tut", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, SkipMalformedLine) { + ScopedTestFile file("this line should have a column\nfoo : bar\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) { + ScopedTestFile file("\n\nfoo : bar\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, SkipEmptyField) { + ScopedTestFile file(" : bar\nzoo : tut\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("zoo", field); + ASSERT_STREQ("tut", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) { + ScopedTestFile file("foo : bar\n\n\nfoo : bar\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + ASSERT_STREQ("bar", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, FieldWithSpaces) { + ScopedTestFile file("foo bar : zoo\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo bar", field); + ASSERT_STREQ("zoo", reader.GetValue()); + + ASSERT_FALSE(reader.GetNextField(&field)); +} + +TEST(ProcCpuInfoReaderTest, EmptyValue) { + ScopedTestFile file("foo :\n"); + ASSERT_TRUE(file.IsOk()); + ProcCpuInfoReader reader(file.GetFd()); + + const char* field; + ASSERT_TRUE(reader.GetNextField(&field)); + ASSERT_STREQ("foo", field); + size_t value_len; + ASSERT_STREQ("", reader.GetValueAndLen(&value_len)); + ASSERT_EQ(0U, value_len); + + ASSERT_FALSE(reader.GetNextField(&field)); +} diff --git a/toolkit/crashreporter/breakpad-client/linux/moz.build b/toolkit/crashreporter/breakpad-client/linux/moz.build new file mode 100644 index 0000000000..ac4fb1e230 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/linux/moz.build @@ -0,0 +1,47 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'crash_generation/crash_generation_client.cc', + 'crash_generation/crash_generation_server.cc', + 'dump_writer_common/thread_info.cc', + 'dump_writer_common/ucontext_reader.cc', + 'handler/exception_handler.cc', + 'handler/guid_generator.cc', + 'handler/minidump_descriptor.cc', + 'log/log.cc', + 'microdump_writer/microdump_writer.cc', + 'minidump_writer/linux_dumper.cc', + 'minidump_writer/linux_ptrace_dumper.cc', +] + +if CONFIG["CC_TYPE"] == "gcc": + # Workaround for an ICE in the hazard detection GCC plug-in, see + # https://bugzilla.mozilla.org/show_bug.cgi?id=1756505#c7 + SOURCES += ['minidump_writer/minidump_writer.cc'] +else: + UNIFIED_SOURCES += ['minidump_writer/minidump_writer.cc'] + +# On Linux we override the guid_creator.h header and use our own instead +if CONFIG['OS_TARGET'] == 'Linux' or CONFIG['OS_TARGET'] == 'Android': + DEFINES['COMMON_LINUX_GUID_CREATOR_H__'] = 1 + +if CONFIG['OS_TARGET'] == 'Android': + DEFINES['ANDROID_NDK_MAJOR_VERSION'] = CONFIG['ANDROID_NDK_MAJOR_VERSION'] + DEFINES['ANDROID_NDK_MINOR_VERSION'] = CONFIG['ANDROID_NDK_MINOR_VERSION'] + LOCAL_INCLUDES += [ + '/toolkit/crashreporter/google-breakpad/src/common/android/include', + ] + +FINAL_LIBRARY = 'breakpad_client' + +include('/toolkit/crashreporter/crashreporter.mozbuild') + +if CONFIG['MOZ_PHC']: + DEFINES['MOZ_PHC'] = True + +if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CXXFLAGS += ['-Wno-error=stack-protector'] diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/client_info.h b/toolkit/crashreporter/breakpad-client/mac/crash_generation/client_info.h new file mode 100644 index 0000000000..92301036b6 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/client_info.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010 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_MAC_CRASH_GENERATION_CLIENT_INFO_H_ +#define CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_ + +namespace google_breakpad { + +class ClientInfo { + public: + ClientInfo(pid_t pid, task_t task) : pid_(pid), task_(task) {} + + pid_t pid() const { return pid_; } + task_t task() const { return task_; } + + private: + pid_t pid_; + task_t task_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_ diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc new file mode 100644 index 0000000000..bdbf43aaca --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2010 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 "mac/crash_generation/crash_generation_client.h" + +#include "mac/crash_generation/crash_generation_server.h" +#include "common/mac/MachIPC.h" + +namespace google_breakpad { + +bool CrashGenerationClient::RequestDumpForException( + int exception_type, + int exception_code, + int64_t exception_subcode, + mach_port_t crashing_thread, + mach_port_t crashing_task) { + // The server will send a message to this port indicating that it + // has finished its work. + ReceivePort acknowledge_port; + + MachSendMessage message(kDumpRequestMessage); + message.AddDescriptor(crashing_task); // crashing task + message.AddDescriptor(crashing_thread); // crashing thread + message.AddDescriptor(MACH_PORT_NULL); // handler thread + message.AddDescriptor(acknowledge_port.GetPort()); // message receive port + + ExceptionInfo info; + info.exception_type = exception_type; + info.exception_code = exception_code; + info.exception_subcode = exception_subcode; + info.child_pid = getpid(); + + message.SetData(&info, sizeof(info)); + + kern_return_t result = sender_.SendMessage(message, MACH_MSG_TIMEOUT_NONE); + if (result != KERN_SUCCESS) + return false; + + // Give the server slightly longer to reply since it has to + // inspect this task and write the minidump. + MachReceiveMessage acknowledge_message; + result = acknowledge_port.WaitForMessage(&acknowledge_message, + MACH_MSG_TIMEOUT_NONE); + + return result == KERN_SUCCESS; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.h b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.h new file mode 100644 index 0000000000..9bcd79af7f --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.h @@ -0,0 +1,66 @@ +// Copyright (c) 2010 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_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ +#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ + +#include "common/mac/MachIPC.h" + +namespace google_breakpad { + +class CrashGenerationClient { + public: + explicit CrashGenerationClient(const char* mach_port_name) + : sender_(mach_port_name) { + } + + // Request the crash server to generate a dump. + // + // Return true if the dump was successful; false otherwise. + bool RequestDumpForException(int exception_type, + int exception_code, + int64_t exception_subcode, + mach_port_t crashing_thread, + mach_port_t crashing_task); + + bool RequestDump() { + return RequestDumpForException(0, 0, 0, MACH_PORT_NULL, mach_task_self()); + } + + private: + MachPortSender sender_; + + // Prevent copy construction and assignment. + CrashGenerationClient(const CrashGenerationClient&); + CrashGenerationClient& operator=(const CrashGenerationClient&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.cc new file mode 100644 index 0000000000..8cbc012caa --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.cc @@ -0,0 +1,164 @@ +// Copyright (c) 2010 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 "mac/crash_generation/crash_generation_server.h" + +#include + +#include "mac/crash_generation/client_info.h" +#include "mac/handler/minidump_generator.h" +#include "common/mac/scoped_task_suspend-inl.h" + +namespace google_breakpad { + +CrashGenerationServer::CrashGenerationServer( + const char *mach_port_name, + FilterCallback filter, + void *filter_context, + OnClientDumpRequestCallback dump_callback, + void *dump_context, + OnClientExitingCallback exit_callback, + void *exit_context, + bool generate_dumps, + const std::string &dump_path) + : filter_(filter), + filter_context_(filter_context), + dump_callback_(dump_callback), + dump_context_(dump_context), + exit_callback_(exit_callback), + exit_context_(exit_context), + generate_dumps_(generate_dumps), + dump_dir_(dump_path.empty() ? "/tmp" : dump_path), + started_(false), + receive_port_(mach_port_name), + mach_port_name_(mach_port_name) { +} + +CrashGenerationServer::~CrashGenerationServer() { + if (started_) + Stop(); +} + +bool CrashGenerationServer::Start() { + int thread_create_result = pthread_create(&server_thread_, NULL, + &WaitForMessages, this); + started_ = thread_create_result == 0; + return started_; +} + +bool CrashGenerationServer::Stop() { + if (!started_) + return false; + + // Send a quit message to the background thread, and then join it. + MachPortSender sender(mach_port_name_.c_str()); + MachSendMessage quit_message(kQuitMessage); + const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000; + kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs); + if (result == KERN_SUCCESS) { + int thread_join_result = pthread_join(server_thread_, NULL); + started_ = thread_join_result != 0; + } + + return !started_; +} + +// static +void *CrashGenerationServer::WaitForMessages(void *server) { + pthread_setname_np("Breakpad CrashGenerationServer"); + + CrashGenerationServer *self = + reinterpret_cast(server); + while (self->WaitForOneMessage()) {} + return NULL; +} + +bool CrashGenerationServer::WaitForOneMessage() { + MachReceiveMessage message; + kern_return_t result = receive_port_.WaitForMessage(&message, + MACH_MSG_TIMEOUT_NONE); + if (result == KERN_SUCCESS) { + switch (message.GetMessageID()) { + case kDumpRequestMessage: { + ExceptionInfo &info = (ExceptionInfo &)*message.GetData(); + + mach_port_t remote_task = message.GetTranslatedPort(0); + mach_port_t crashing_thread = message.GetTranslatedPort(1); + mach_port_t handler_thread = message.GetTranslatedPort(2); + mach_port_t ack_port = message.GetTranslatedPort(3); + ClientInfo client(info.child_pid, remote_task); + + bool result; + std::string dump_path; + if (generate_dumps_ && (!filter_ || filter_(filter_context_))) { + ScopedTaskSuspend suspend(remote_task); + + MinidumpGenerator generator(remote_task, handler_thread); + dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL); + + if (info.exception_type && info.exception_code) { + generator.SetExceptionInformation(info.exception_type, + info.exception_code, + info.exception_subcode, + crashing_thread); + } + result = generator.Write(dump_path.c_str()); + } else { + result = true; + } + + if (result && dump_callback_) { + dump_callback_(dump_context_, client, dump_path); + } + + // TODO(ted): support a way for the client to send additional data, + // perhaps with a callback so users of the server can read the data + // themselves? + + if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) { + MachPortSender sender(ack_port); + MachSendMessage ack_message(kAcknowledgementMessage); + sender.SendMessage(ack_message, MACH_MSG_TIMEOUT_NONE); + } + + if (result && exit_callback_) { + exit_callback_(exit_context_, client); + } + break; + } + case kQuitMessage: + return false; + } + } else { // result != KERN_SUCCESS + return false; + } + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.h b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.h new file mode 100644 index 0000000000..d0b39f3acf --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_server.h @@ -0,0 +1,151 @@ +// Copyright (c) 2010 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_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ +#define GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ + +#include + +#include + +#include "common/mac/MachIPC.h" + +namespace google_breakpad { + +class ClientInfo; + +// Messages the server can read via its mach port +enum { + kDumpRequestMessage = 1, + kAcknowledgementMessage = 2, + kQuitMessage = 3 +}; + +// Exception details sent by the client when requesting a dump. +struct ExceptionInfo { + int32_t exception_type; + int32_t exception_code; + int64_t exception_subcode; + int32_t child_pid; +}; + +class CrashGenerationServer { + public: + // WARNING: callbacks may be invoked on a different thread + // than that which creates the CrashGenerationServer. They must + // be thread safe. + typedef void (*OnClientDumpRequestCallback)(void *context, + const ClientInfo &client_info, + const std::string &file_path); + + typedef void (*OnClientExitingCallback)(void *context, + const ClientInfo &client_info); + // If a FilterCallback returns false, the dump will not be written. + typedef bool (*FilterCallback)(void *context); + + // Create an instance with the given parameters. + // + // mach_port_name: Named server port to listen on. + // filter: Callback for a client to cancel writing a dump. + // filter_context: Context for the filter callback. + // dump_callback: Callback for a client crash dump request. + // dump_context: Context for client crash dump request callback. + // exit_callback: Callback for client process exit. + // exit_context: Context for client exit callback. + // 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. + // dump_path: Path for generating dumps; required only if true is + // passed for generateDumps parameter; NULL can be passed otherwise. + CrashGenerationServer(const char *mach_port_name, + FilterCallback filter, + void *filter_context, + OnClientDumpRequestCallback dump_callback, + void *dump_context, + OnClientExitingCallback exit_callback, + void *exit_context, + bool generate_dumps, + const std::string &dump_path); + + ~CrashGenerationServer(); + + // Perform initialization steps needed to start listening to clients. + // + // Return true if initialization is successful; false otherwise. + bool Start(); + + // Stop the server. + bool Stop(); + + private: + // Return a unique filename at which a minidump can be written. + bool MakeMinidumpFilename(std::string &outFilename); + + // Loop reading client messages and responding to them until + // a quit message is received. + static void *WaitForMessages(void *server); + + // Wait for a single client message and respond to it. Returns false + // if a quit message was received or if an error occurred. + bool WaitForOneMessage(); + + FilterCallback filter_; + void *filter_context_; + + OnClientDumpRequestCallback dump_callback_; + void *dump_context_; + + OnClientExitingCallback exit_callback_; + void *exit_context_; + + bool generate_dumps_; + + std::string dump_dir_; + + bool started_; + + // The mach port that receives requests to dump from child processes. + ReceivePort receive_port_; + + // The name of the mach port. Stored so the Stop method can message + // the background thread to shut it down. + std::string mach_port_name_; + + // The thread that waits on the receive port. + pthread_t server_thread_; + + // Disable copy constructor and operator=. + CrashGenerationServer(const CrashGenerationServer&); + CrashGenerationServer& operator=(const CrashGenerationServer&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_CLIENT_MAC_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_ diff --git a/toolkit/crashreporter/breakpad-client/mac/crash_generation/moz.build b/toolkit/crashreporter/breakpad-client/mac/crash_generation/moz.build new file mode 100644 index 0000000000..731670a4f1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'crash_generation_client.cc', + 'crash_generation_server.cc', +] + +FINAL_LIBRARY = 'breakpad_client' + +LOCAL_INCLUDES += [ + '/ipc/chromium/src', + '/toolkit/crashreporter/breakpad-client', + '/toolkit/crashreporter/google-breakpad/src', +] diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.cc b/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.cc new file mode 100644 index 0000000000..3492b823da --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.cc @@ -0,0 +1,402 @@ +/* + * 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. + */ + + +/* + * 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. +*/ + +#include "breakpad_nlist_64.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Stuff lifted from and 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) + +// Traits structs for specializing function templates to handle +// 32-bit/64-bit Mach-O files. +template +struct MachBits {}; + +typedef struct nlist nlist32; +typedef struct nlist_64 nlist64; + +template<> +struct MachBits { + typedef mach_header mach_header_type; + typedef uint32_t word_type; + static const uint32_t magic = MH_MAGIC; +}; + +template<> +struct MachBits { + typedef mach_header_64 mach_header_type; + typedef uint64_t word_type; + static const uint32_t magic = MH_MAGIC_64; +}; + +template +int +__breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, + cpu_type_t cpu_type); + +/* + * nlist - retreive attributes from name list (string table version) + */ + +template +int breakpad_nlist_common(const char *name, + nlist_type *list, + const char **symbolNames, + cpu_type_t cpu_type) { + int fd = open(name, O_RDONLY, 0); + if (fd < 0) + return -1; + int n = __breakpad_fdnlist(fd, list, symbolNames, cpu_type); + close(fd); + return n; +} + +int breakpad_nlist(const char *name, + struct nlist *list, + const char **symbolNames, + cpu_type_t cpu_type) { + return breakpad_nlist_common(name, list, symbolNames, cpu_type); +} + +int breakpad_nlist(const char *name, + struct nlist_64 *list, + const char **symbolNames, + cpu_type_t cpu_type) { + return breakpad_nlist_common(name, list, symbolNames, cpu_type); +} + +/* Note: __fdnlist() is called from kvm_nlist in libkvm's kvm.c */ + +template +int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames, + cpu_type_t cpu_type) { + typedef typename MachBits::mach_header_type mach_header_type; + typedef typename MachBits::word_type word_type; + + const uint32_t magic = MachBits::magic; + + int maxlen = 500; + int nreq = 0; + for (nlist_type* q = list; + 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; + } + + struct exec buf; + if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) || + (N_BADMAG(buf) && *((uint32_t *)&buf) != magic && + CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC && + /* The following is the big-endian ppc64 check */ + (*((uint32_t*)&buf)) != FAT_MAGIC)) { + return -1; + } + + /* Deal with fat file if necessary */ + unsigned arch_offset = 0; + if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC || + /* The following is the big-endian ppc64 check */ + *((unsigned int *)&buf) == FAT_MAGIC) { + /* Read in the fat header */ + struct fat_header fh; + if (lseek(fd, 0, SEEK_SET) == -1) { + return -1; + } + if (read(fd, (char *)&fh, sizeof(fh)) != sizeof(fh)) { + return -1; + } + + /* Convert fat_narchs to host byte order */ + fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch); + + /* Read in the fat archs */ + struct fat_arch *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) != + (ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) { + free(fat_archs); + return -1; + } + + /* + * Convert archs to host byte ordering (a constraint of + * cpusubtype_getbestarch() + */ + for (unsigned i = 0; i < fh.nfat_arch; i++) { + fat_archs[i].cputype = + CFSwapInt32BigToHost(fat_archs[i].cputype); + fat_archs[i].cpusubtype = + CFSwapInt32BigToHost(fat_archs[i].cpusubtype); + fat_archs[i].offset = + CFSwapInt32BigToHost(fat_archs[i].offset); + fat_archs[i].size = + CFSwapInt32BigToHost(fat_archs[i].size); + fat_archs[i].align = + CFSwapInt32BigToHost(fat_archs[i].align); + } + + struct fat_arch *fap = NULL; + for (unsigned i = 0; i < fh.nfat_arch; i++) { + if (fat_archs[i].cputype == cpu_type) { + 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 */ + if (lseek(fd, arch_offset, SEEK_SET) == -1) { + return -1; + } + if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf)) { + return -1; + } + } + + off_t sa; /* symbol address */ + off_t ss; /* start of strings */ + register_t n; + if (*((unsigned int *)&buf) == magic) { + if (lseek(fd, arch_offset, SEEK_SET) == -1) { + return -1; + } + mach_header_type mh; + if (read(fd, (char *)&mh, sizeof(mh)) != sizeof(mh)) { + return -1; + } + + struct load_command *load_commands = + (struct load_command *)malloc(mh.sizeofcmds); + if (load_commands == NULL) { + return -1; + } + if (read(fd, (char *)load_commands, mh.sizeofcmds) != + (ssize_t)mh.sizeofcmds) { + free(load_commands); + return -1; + } + struct symtab_command *stp = NULL; + struct load_command *lcp = load_commands; + // iterate through all load commands, looking for + // LC_SYMTAB load command + for (uint32_t i = 0; i < mh.ncmds; i++) { + if (lcp->cmdsize % sizeof(word_type) != 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(nlist_type); + free(load_commands); + } else { + sa = N_SYMOFF(buf) + arch_offset; + ss = sa + buf.a_syms + arch_offset; + n = buf.a_syms; + } + + if (lseek(fd, sa, SEEK_SET) == -1) { + return -1; + } + + // 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) { + nlist_type space[BUFSIZ/sizeof (nlist_type)]; + register_t m = sizeof (space); + + if (n < m) + m = n; + if (read(fd, (char *)space, m) != m) + break; + n -= m; + off_t savpos = lseek(fd, 0, SEEK_CUR); + if (savpos == -1) { + return -1; + } + for (nlist_type* q = space; (m -= sizeof(nlist_type)) >= 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 + if (lseek(fd, ss+q->n_un.n_strx, SEEK_SET) == -1) { + return -1; + } + if (read(fd, nambuf, maxlen+1) == -1) { + return -1; + } + const char *s2 = nambuf; + for (nlist_type *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 + const char *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: ; + } + } + if (lseek(fd, savpos, SEEK_SET) == -1) { + return -1; + } + } + return nreq; +} diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.h b/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.h new file mode 100644 index 0000000000..e8e2e0834e --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/breakpad_nlist_64.h @@ -0,0 +1,48 @@ +// 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__ +#define CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ + +#include + +int breakpad_nlist(const char *name, + struct nlist *list, + const char **symbolNames, + cpu_type_t cpu_type); +int breakpad_nlist(const char *name, + struct nlist_64 *list, + const char **symbolNames, + cpu_type_t cpu_type); + +#endif /* CLIENT_MAC_HANDLER_BREAKPAD_NLIST_H__ */ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.cc b/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.cc new file mode 100644 index 0000000000..855580a071 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.cc @@ -0,0 +1,625 @@ +// 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. + +#include "mac/handler/dynamic_images.h" + +extern "C" { // needed to compile on Leopard + #include + #include + #include +} + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "breakpad_nlist_64.h" + +#if !TARGET_OS_IPHONE +#include +#endif // !TARGET_OS_IPHONE + +namespace google_breakpad { + +using std::string; +using std::vector; + +//============================================================================== +// 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 uint64_t 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(&submap_info); + + kern_return_t result = + mach_vm_region_recurse(target_task, + ®ion_base, + ®ion_size, + &nesting_level, + region_info, + &info_count); + + if (result == KERN_SUCCESS) { + // Get distance from |address| to the end of this region + *size_to_end = region_base + region_size -(mach_vm_address_t)address; + + // If we want to handle strings as long as 4096 characters we may need + // to check if there's a vm region immediately following the first one. + // If so, we need to extend |*size_to_end| to go all the way to the end + // of the second region. + if (*size_to_end < 4096) { + // Second region starts where the first one ends + mach_vm_address_t region_base2 = + (mach_vm_address_t)(region_base + region_size); + mach_vm_size_t region_size2; + + // Get information about the following vm region + result = + mach_vm_region_recurse(target_task, + ®ion_base2, + ®ion_size2, + &nesting_level, + region_info, + &info_count); + + // Extend region_size to go all the way to the end of the 2nd region + if (result == KERN_SUCCESS + && region_base2 == region_base + region_size) { + region_size += region_size2; + } + } + + *size_to_end = region_base + region_size -(mach_vm_address_t)address; + } else { + region_size = 0; + *size_to_end = 0; + } + + return region_size; +} + +#define kMaxStringLength 8192 +//============================================================================== +// Reads a NULL-terminated string from another task. +// +// Warning! This will not read any strings longer than kMaxStringLength-1 +// +string ReadTaskString(task_port_t target_task, + const uint64_t 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; + + vector bytes; + if (ReadTaskMemory(target_task, address, (size_t)size_to_read, bytes) != + KERN_SUCCESS) + return string(); + + return string(reinterpret_cast(&bytes[0])); + } + + return string(); +} + +//============================================================================== +// Reads an address range from another task. The bytes read will be returned +// in bytes, which will be resized as necessary. +kern_return_t ReadTaskMemory(task_port_t target_task, + const uint64_t address, + size_t length, + vector &bytes) { + int systemPageSize = getpagesize(); + + // use the negative of the page size for the mask to find the page address + mach_vm_address_t page_address = address & (-systemPageSize); + + mach_vm_address_t last_page_address = + (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 = mach_vm_read(target_task, + page_address, + page_size, + reinterpret_cast(&local_start), + &local_length); + + if (r != KERN_SUCCESS) + return r; + + bytes.resize(length); + memcpy(&bytes[0], + &local_start[(mach_vm_address_t)address - page_address], + length); + mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length); + return KERN_SUCCESS; +} + +#pragma mark - + +//============================================================================== +// Traits structs for specializing function templates to handle +// 32-bit/64-bit Mach-O files. +struct MachO32 { + typedef mach_header mach_header_type; + typedef segment_command mach_segment_command_type; + typedef dyld_image_info32 dyld_image_info; + typedef dyld_all_image_infos32 dyld_all_image_infos; + typedef section mach_section_type; + typedef struct nlist nlist_type; + static const uint32_t magic = MH_MAGIC; + static const uint32_t segment_load_command = LC_SEGMENT; +}; + +struct MachO64 { + typedef mach_header_64 mach_header_type; + typedef segment_command_64 mach_segment_command_type; + typedef dyld_image_info64 dyld_image_info; + typedef dyld_all_image_infos64 dyld_all_image_infos; + typedef section_64 mach_section_type; + typedef struct nlist_64 nlist_type; + static const uint32_t magic = MH_MAGIC_64; + static const uint32_t segment_load_command = LC_SEGMENT_64; +}; + +template +bool FindTextSection(DynamicImage& image) { + typedef typename MachBits::mach_header_type mach_header_type; + typedef typename MachBits::mach_segment_command_type + mach_segment_command_type; + typedef typename MachBits::mach_section_type mach_section_type; + + const mach_header_type* header = + reinterpret_cast(&image.header_[0]); + + if(header->magic != MachBits::magic) { + return false; + } + + bool is_in_shared_cache = ((header->flags & MH_SHAREDCACHE) != 0); + if (is_in_shared_cache) { + image.slide_ = image.shared_cache_slide_; + } + + const struct load_command *cmd = + reinterpret_cast(header + 1); + + bool retval = false; + + uint32_t num_data_sections = 0; + const mach_section_type *data_sections = NULL; + uint32_t num_data_dirty_sections = 0; + const mach_section_type *data_dirty_sections = NULL; + bool found_text_section = false; + bool found_dylib_id_command = false; + for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) { + if (!data_sections) { + if (cmd->cmd == MachBits::segment_load_command) { + const mach_segment_command_type *seg = + reinterpret_cast(cmd); + + if (!strcmp(seg->segname, "__DATA")) { + num_data_sections = seg->nsects; + data_sections = reinterpret_cast(seg + 1); + } + } + } + + if (!data_dirty_sections) { + if (cmd->cmd == MachBits::segment_load_command) { + const mach_segment_command_type *seg = + reinterpret_cast(cmd); + + if (!strcmp(seg->segname, "__DATA_DIRTY")) { + num_data_dirty_sections = seg->nsects; + data_dirty_sections = + reinterpret_cast(seg + 1); + } + } + } + + if (!found_text_section) { + if (cmd->cmd == MachBits::segment_load_command) { + const mach_segment_command_type *seg = + reinterpret_cast(cmd); + + if (!is_in_shared_cache) { + if (seg->fileoff == 0 && seg->filesize != 0) { + image.slide_ = + (uintptr_t)image.GetLoadAddress() - (uintptr_t)seg->vmaddr; + } + } + + if (!strcmp(seg->segname, "__TEXT")) { + image.vmaddr_ = static_cast(seg->vmaddr); + image.vmsize_ = static_cast(seg->vmsize); + found_text_section = true; + } + } + } + + if (!found_dylib_id_command) { + if (cmd->cmd == LC_ID_DYLIB) { + const struct dylib_command *dc = + reinterpret_cast(cmd); + + image.version_ = dc->dylib.current_version; + found_dylib_id_command = true; + } + } + + if (found_dylib_id_command && found_text_section && + data_sections && data_dirty_sections) { + break; + } + + cmd = reinterpret_cast + (reinterpret_cast(cmd) + cmd->cmdsize); + } + + if (found_dylib_id_command && found_text_section) { + retval = true; + } + + // The __DYLD,__crash_info section may not be accessible in child process + // modules that aren't dyld or in the dyld shared cache. + if (image.GetIsDyld() || is_in_shared_cache) { + for (unsigned int i = 0; i < num_data_sections; ++i) { + if (!strcmp(data_sections[i].sectname, "__crash_info")) { + ReadTaskMemory(image.task_, + data_sections[i].addr + image.slide_, + data_sections[i].size, + image.crash_info_); + return retval; + } + } + // __crash_info might be in the __DATA_DIRTY segment. + for (unsigned int i = 0; i < num_data_dirty_sections; ++i) { + if (!strcmp(data_dirty_sections[i].sectname, "__crash_info")) { + ReadTaskMemory(image.task_, + data_dirty_sections[i].addr + image.slide_, + data_dirty_sections[i].size, + image.crash_info_); + return retval; + } + } + } + + return retval; +} + +//============================================================================== +// Initializes vmaddr_, vmsize_, and slide_ +void DynamicImage::CalculateMemoryAndVersionInfo() { + // unless we can process the header, ensure that calls to + // IsValid() will return false + vmaddr_ = 0; + vmsize_ = 0; + slide_ = 0; + version_ = 0; + + // The function template above does all the real work. + if (Is64Bit()) + FindTextSection(*this); + else + FindTextSection(*this); +} + +//============================================================================== +// The helper function template abstracts the 32/64-bit differences. +template +uint32_t GetFileTypeFromHeader(DynamicImage& image) { + typedef typename MachBits::mach_header_type mach_header_type; + + const mach_header_type* header = + reinterpret_cast(&image.header_[0]); + return header->filetype; +} + +uint32_t DynamicImage::GetFileType() { + if (Is64Bit()) + return GetFileTypeFromHeader(*this); + + return GetFileTypeFromHeader(*this); +} + +#pragma mark - + +//============================================================================== +// Loads information about dynamically loaded code in the given task. +DynamicImages::DynamicImages(mach_port_t task) + : task_(task), + cpu_type_(DetermineTaskCPUType(task)), + image_list_() { + ReadImageInfoForTask(); +} + +template +static uint64_t LookupSymbol(const char* symbol_name, + const char* filename, + cpu_type_t cpu_type) { + typedef typename MachBits::nlist_type nlist_type; + + nlist_type symbol_info[8] = {}; + const char *symbolNames[2] = { symbol_name, "\0" }; + nlist_type &list = symbol_info[0]; + int invalidEntriesCount = breakpad_nlist(filename, + &list, + symbolNames, + cpu_type); + + if(invalidEntriesCount != 0) { + return 0; + } + + assert(list.n_value); + return list.n_value; +} + +uint64_t DynamicImages::GetDyldAllImageInfosPointer() { + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(task_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, + &count) != KERN_SUCCESS) { + return 0; + } + + return (uint64_t)task_dyld_info.all_image_info_addr; +} + +//============================================================================== +// This code was written using dyld_debug.c (from Darwin) as a guide. + +template +void ReadOneImageInfo(DynamicImages& images, uint64_t image_address, + uint64_t file_path_address, uint64_t file_mod_date, + uint64_t shared_cache_slide, bool is_dyld) { + typedef typename MachBits::mach_header_type mach_header_type; + + // First read just the mach_header from the image in the task. + vector mach_header_bytes; + if (ReadTaskMemory(images.task_, + image_address, + sizeof(mach_header_type), + mach_header_bytes) != KERN_SUCCESS) { + return; // bail on this dynamic image + } + + mach_header_type *header = + reinterpret_cast(&mach_header_bytes[0]); + if (header->magic != MachBits::magic) { + return; + } + + cpu_subtype_t cpusubtype = (header->cpusubtype & ~CPU_SUBTYPE_MASK); + + // Now determine the total amount necessary to read the header + // plus all of the load commands. + size_t header_size = sizeof(mach_header_type) + header->sizeofcmds; + + if (ReadTaskMemory(images.task_, + image_address, + header_size, + mach_header_bytes) != KERN_SUCCESS) { + return; + } + + // Read the file name from the task's memory space. + string file_path; + if (file_path_address) { + // 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 = ReadTaskString(images.task_, file_path_address); + } + + // Create an object representing this image and add it to our list. + DynamicImage *new_image; + new_image = new DynamicImage(&mach_header_bytes[0], + header_size, + image_address, + file_path, + static_cast(file_mod_date), + images.task_, + images.cpu_type_, + cpusubtype, + shared_cache_slide, + is_dyld); + + if (new_image->IsValid()) { + images.image_list_.push_back(DynamicImageRef(new_image)); + } else { + delete new_image; + } +} + +template +void ReadImageInfo(DynamicImages& images, + uint64_t image_list_address) { + typedef typename MachBits::dyld_image_info dyld_image_info; + typedef typename MachBits::dyld_all_image_infos dyld_all_image_infos; + + // 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. + vector dyld_all_info_bytes; + if (ReadTaskMemory(images.task_, + image_list_address, + sizeof(dyld_all_image_infos), + dyld_all_info_bytes) != KERN_SUCCESS) { + return; + } + + dyld_all_image_infos *dyldInfo = + reinterpret_cast(&dyld_all_info_bytes[0]); + + // number of loaded images + int count = dyldInfo->infoArrayCount; + + // Read an array of dyld_image_info structures each containing + // information about a loaded image. + vector dyld_info_array_bytes; + if (ReadTaskMemory(images.task_, + dyldInfo->infoArray, + count * sizeof(dyld_image_info), + dyld_info_array_bytes) != KERN_SUCCESS) { + return; + } + + dyld_image_info *infoArray = + reinterpret_cast(&dyld_info_array_bytes[0]); + // Add room for dyld at the end + images.image_list_.reserve(count + 1); + + for (int i = 0; i < count; ++i) { + dyld_image_info &info = infoArray[i]; + ReadOneImageInfo(images, info.load_address_, + info.file_path_, info.file_mod_date_, + dyldInfo->sharedCacheSlide, + /* is_dyld */ false); + } + + // Add an image for dyld itself. It doesn't appear in the standard list of + // modules. + uint64_t dyld_address = (uint64_t) dyldInfo->dyldImageLoadAddress; + if (dyld_address) { + ReadOneImageInfo(images, dyld_address, + (uint64_t) dyldInfo->dyldPath, + /* file_mod_date */ 0, + dyldInfo->sharedCacheSlide, + /* is_dyld */ true); + } + + // sorts based on loading address + sort(images.image_list_.begin(), images.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::iterator it = unique(images.image_list_.begin(), + images.image_list_.end()); + images.image_list_.erase(it, images.image_list_.end()); +} + +void DynamicImages::ReadImageInfoForTask() { + uint64_t imageList = GetDyldAllImageInfosPointer(); + + if (imageList) { + if (Is64Bit()) + ReadImageInfo(*this, imageList); + else + ReadImageInfo(*this, imageList); + } +} + +//============================================================================== +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->GetFileType() == MH_EXECUTE) { + return i; + } + } + + return -1; +} + +//============================================================================== +// static +cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) { + if (task == mach_task_self()) + return GetNativeCPUType(); + + int mib[CTL_MAXNAME]; + size_t mibLen = CTL_MAXNAME; + int err = sysctlnametomib("sysctl.proc_cputype", mib, &mibLen); + if (err == 0) { + assert(mibLen < CTL_MAXNAME); + pid_for_task(task, &mib[mibLen]); + mibLen += 1; + + cpu_type_t cpu_type; + size_t cpuTypeSize = sizeof(cpu_type); + sysctl(mib, static_cast(mibLen), &cpu_type, &cpuTypeSize, 0, 0); + return cpu_type; + } + + return GetNativeCPUType(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.h b/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.h new file mode 100644 index 0000000000..e225c00b88 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/dynamic_images.h @@ -0,0 +1,386 @@ +// 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 +#include +#include +#include + +#include +#include + +#include "mach_vm_compat.h" + +namespace google_breakpad { + +using std::string; +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_info32 { + uint32_t load_address_; // struct mach_header* + uint32_t file_path_; // char* + uint32_t file_mod_date_; +} dyld_image_info32; + +typedef struct dyld_image_info64 { + uint64_t load_address_; // struct mach_header* + uint64_t file_path_; // char* + uint64_t file_mod_date_; +} dyld_image_info64; + +//============================================================================== +// 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_infos32 { + uint32_t version; // == 1 in Mac OS X 10.4 + uint32_t infoArrayCount; + uint32_t infoArray; // const struct dyld_image_info* + uint32_t notification; + bool processDetachedFromSharedRegion; + // Only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later + const struct mach_header* dyldImageLoadAddress; + uint32_t padding[14]; + // Only in version 12 (Mac OS X 10.7, iOS 4.3) and later + uint32_t sharedCacheSlide; + uint32_t padding1[6]; + // Only in version 15 (macOS 10.12, iOS 10.0) and later + const char* dyldPath; +} dyld_all_image_infos32; + +typedef struct dyld_all_image_infos64 { + uint32_t version; // == 1 in Mac OS X 10.4 + uint32_t infoArrayCount; + uint64_t infoArray; // const struct dyld_image_info* + uint64_t notification; + bool processDetachedFromSharedRegion; + // Only in version 2 (Mac OS X 10.6, iPhoneOS 2.0) and later + const struct mach_header_64* dyldImageLoadAddress; + uint64_t padding[14]; + // Only in version 12 (Mac OS X 10.7, iOS 4.3) and later + uint64_t sharedCacheSlide; + uint64_t padding1[4]; + // Only in version 15 (macOS 10.12, iOS 10.0) and later + const char* dyldPath; +} dyld_all_image_infos64; + +// 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 + +// Bit in mach_header.flags that indicates whether or not the image is in the +// dyld shared cache. The dyld shared cache is a single image into which +// commonly used system dylibs and frameworks are incorporated. dyld maps it +// into every process at load time. The component images all have the same +// slide. +#define MH_SHAREDCACHE 0x80000000 + +// Helper functions to deal with 32-bit/64-bit Mach-O differences. +class DynamicImage; +template +bool FindTextSection(DynamicImage& image); + +template +uint32_t GetFileTypeFromHeader(DynamicImage& image); + +//============================================================================== +// Represents a single dynamically loaded mach-o image +class DynamicImage { + public: + DynamicImage(uint8_t *header, // data is copied + size_t header_size, // includes load commands + uint64_t load_address, + string file_path, + uintptr_t image_mod_date, + mach_port_t task, + cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + ptrdiff_t shared_cache_slide, + bool is_dyld) + : header_(header, header + header_size), + header_size_(header_size), + load_address_(load_address), + vmaddr_(0), + vmsize_(0), + slide_(0), + crash_info_(), + version_(0), + file_path_(file_path), + file_mod_date_(image_mod_date), + is_dyld_(is_dyld), + task_(task), + cpu_type_(cpu_type), + cpu_subtype_(cpu_subtype), + shared_cache_slide_(shared_cache_slide) { + CalculateMemoryAndVersionInfo(); + } + + // Size of mach_header plus load commands + size_t GetHeaderSize() const {return header_.size();} + + // Full path to mach-o binary + string GetFilePath() {return file_path_;} + + uint64_t GetModDate() const {return file_mod_date_;} + + // Actual address where the image was loaded + uint64_t GetLoadAddress() const {return load_address_;} + + // Address where the image should be loaded + mach_vm_address_t GetVMAddr() const {return vmaddr_;} + + bool GetInDyldSharedCache() + {return (shared_cache_slide_ && (slide_ == shared_cache_slide_));} + + bool GetIsDyld() {return is_dyld_;} + + // Difference between GetLoadAddress() and GetVMAddr() + ptrdiff_t GetVMAddrSlide() const {return slide_;} + + // Size of the image + mach_vm_size_t GetVMSize() const {return vmsize_;} + + // Returns the address of the locally cached __DATA,__crash_info section. + // The vector will be empty if the image doesn't have a __crash_info + // section. But even if the vector isn't empty, its contents may be "empty" + // of useful data (see definition of crashreporter_annotations_t in + // mach_vm_compat.h). + mach_vm_address_t GetCrashInfo() const { + return reinterpret_cast(&crash_info_[0]); + } + + // Size of the locally cached __DATA,__crash_info section. This will be zero + // if the vector is empty. But even if it's non-zero, the __crash_info + // section of which it's a copy may be empty of useful data. + size_t GetCrashInfoSize() const {return crash_info_.size();} + + // Task owning this loaded image + mach_port_t GetTask() {return task_;} + + // CPU type of the task and the image + cpu_type_t GetCPUType() {return cpu_type_;} + + // CPU subtype of the image + cpu_type_t GetCPUSubtype() {return cpu_subtype_;} + + // filetype from the Mach-O header. + uint32_t GetFileType(); + + // Return true if the task is a 64-bit architecture. + bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } + + uint32_t GetVersion() {return version_;} + // For sorting + bool operator<(const DynamicImage &inInfo) { + return GetLoadAddress() < inInfo.GetLoadAddress(); + } + + // Sanity checking + bool IsValid() {return GetVMSize() != 0;} + + private: + DynamicImage(const DynamicImage &); + DynamicImage &operator=(const DynamicImage &); + + friend class DynamicImages; + template + friend bool FindTextSection(DynamicImage& image); + template + friend uint32_t GetFileTypeFromHeader(DynamicImage& image); + + // Initializes vmaddr_, vmsize_, and slide_ + void CalculateMemoryAndVersionInfo(); + + const vector header_; // our local copy of the header + size_t header_size_; // mach_header plus load commands + uint64_t load_address_; // base address image is mapped into + mach_vm_address_t vmaddr_; + mach_vm_size_t vmsize_; + ptrdiff_t slide_; + vector crash_info_; + uint32_t version_; // Dylib version + string file_path_; // path dyld used to load the image + uintptr_t file_mod_date_; // time_t of image file + bool is_dyld_; // Is image file dyld itself? + + mach_port_t task_; + cpu_type_t cpu_type_; // CPU type of task_ and image + cpu_subtype_t cpu_subtype_; // CPU subtype of image + ptrdiff_t shared_cache_slide_; // Task's shared cache slide +}; + +//============================================================================== +// 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(this)->p) + < (*const_cast(inRef).p); + } + + bool operator==(const DynamicImageRef &inInfo) const { + return (*const_cast(this)->p).GetLoadAddress() == + (*const_cast(inInfo)).GetLoadAddress(); + } + + // Be just like DynamicImage* + DynamicImage *operator->() {return p;} + operator DynamicImage*() {return p;} + + private: + DynamicImage *p; +}; + +// Helper function to deal with 32-bit/64-bit Mach-O differences. +class DynamicImages; +template +void ReadOneImageInfo(DynamicImages& images, uint64_t image_address, + uint64_t file_path_address, uint64_t file_mod_date, + uint64_t shared_cache_slide, bool is_dyld); +template +void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); + +//============================================================================== +// 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 < GetImageCount(); ++i) { + delete image_list_[i]; + } + } + + // Returns the number of dynamically loaded mach-o images. + int GetImageCount() const {return static_cast(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_;} + + // CPU type of the task + cpu_type_t GetCPUType() {return cpu_type_;} + + // Return true if the task is a 64-bit architecture. + bool Is64Bit() { return (GetCPUType() & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; } + + // Determine the CPU type of the task being dumped. + static cpu_type_t DetermineTaskCPUType(task_t task); + + // Get the native CPU type of this task. + static cpu_type_t GetNativeCPUType() { +#if defined(__i386__) + return CPU_TYPE_I386; +#elif defined(__x86_64__) + return CPU_TYPE_X86_64; +#elif defined(__ppc__) + return CPU_TYPE_POWERPC; +#elif defined(__ppc64__) + return CPU_TYPE_POWERPC64; +#elif defined(__arm__) + return CPU_TYPE_ARM; +#elif defined(__aarch64__) + return CPU_TYPE_ARM64; +#else +#error "GetNativeCPUType not implemented for this architecture" +#endif + } + + private: + template + friend void ReadOneImageInfo(DynamicImages& images, uint64_t image_address, + uint64_t file_path_address, uint64_t file_mod_date, + uint64_t shared_cache_slide, bool is_dyld); + template + friend void ReadImageInfo(DynamicImages& images, uint64_t image_list_address); + + bool IsOurTask() {return task_ == mach_task_self();} + + // Initialization + void ReadImageInfoForTask(); + uint64_t GetDyldAllImageInfosPointer(); + + mach_port_t task_; + cpu_type_t cpu_type_; // CPU type of task_ + vector image_list_; +}; + +// Fill bytes with the contents of memory at a particular +// location in another task. +kern_return_t ReadTaskMemory(task_port_t target_task, + const uint64_t address, + size_t length, + vector &bytes); + +std::string ReadTaskString(task_port_t target_task, + const uint64_t address); + +} // namespace google_breakpad + +#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc b/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc new file mode 100644 index 0000000000..75dd722fee --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.cc @@ -0,0 +1,991 @@ +// 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 +#include +#include +#include +#include + +#include + +#include "mac/handler/exception_handler.h" +#include "mac/handler/minidump_generator.h" +#include "common/mac/macho_utilities.h" +#include "common/mac/scoped_task_suspend-inl.h" +#include "google_breakpad/common/minidump_exception_mac.h" +#include "mozilla/Assertions.h" + +#ifdef MOZ_PHC +#include "PHC.h" +#endif + +#ifndef __EXCEPTIONS +// This file uses C++ try/catch (but shouldn't). Duplicate the macros from +// allowing this file to work properly with +// exceptions disabled even when other C++ libraries are used. #undef the try +// and catch macros first in case libstdc++ is in use and has already provided +// its own definitions. +#undef try +#define try if (true) +#undef catch +#define catch(X) if (false) +#endif // __EXCEPTIONS + +#ifndef USE_PROTECTED_ALLOCATIONS +#if TARGET_OS_IPHONE +#define USE_PROTECTED_ALLOCATIONS 1 +#else +#define USE_PROTECTED_ALLOCATIONS 0 +#endif +#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 { + +static union { +#if USE_PROTECTED_ALLOCATIONS +#if defined PAGE_MAX_SIZE + char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE))); +#else + char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); +#endif // defined PAGE_MAX_SIZE +#endif // USE_PROTECTED_ALLOCATIONS + google_breakpad::ExceptionHandler *handler; +} gProtectedData; + +using std::map; + +// These structures and techniques are illustrated in +// Mac OS X Internals, Amit Singh, ch 9.7 +#pragma pack(push, 4) +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; + mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; + char padding[512]; +}; +#pragma pack(pop) + +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]; +}; + +#pragma pack(push, 4) +struct ExceptionReplyMessage { + mach_msg_header_t header; + NDR_record_t ndr; + kern_return_t return_code; +}; +#pragma pack(pop) + +// 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 | +EXC_MASK_CRASH | EXC_MASK_RESOURCE | EXC_MASK_GUARD; + +kern_return_t ForwardException(mach_port_t task, + mach_port_t failed_thread, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t code_count); + +// The contents of mach_exc_server() and mach_exception_raise() are derived +// from /usr/include/mach/mach_exc.defs, as follows: +// +// 1) Run 'mig mach_exc.defs' which creates the following files: +// mach_exc.h +// mach_excServer.c +// mach_excUser.c +// 2) The relevant code for mach_exc_server() comes from the following methods +// in mach_excServer.c: +// mach_exc_server() +// _Xmach_exception_raise() +// 3) The relevant code for mach_exception_raise() comes from the following +// method in mach_excUser.c: +// mach_exception_raise() +boolean_t mach_exc_server(mach_msg_header_t* InHeadP, + mach_msg_header_t* OutHeadP) +{ + OutHeadP->msgh_bits = + MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0); + OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port; + /* Minimal size: mach_exception_raise() will update it if different */ + OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); + OutHeadP->msgh_local_port = MACH_PORT_NULL; + OutHeadP->msgh_id = InHeadP->msgh_id + 100; + OutHeadP->msgh_reserved = 0; + + if (InHeadP->msgh_id != 2405) { + ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record; + ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID; + return FALSE; + } + +#pragma pack(push, 4) + 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; + int64_t code[2]; + mach_msg_trailer_t trailer; + } Request; + + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } Reply; +#pragma pack(pop) + + Request* In0P = (Request*)InHeadP; + Reply* OutP = (Reply*)OutHeadP; + + if (In0P->task.name != mach_task_self()) { + // This exception was not meant for us, we avoid forwarding it (because it + // could cause a loop in the exception handler) and simply ignore it + // instead. + return TRUE; + } + + OutP->RetCode = ForwardException(In0P->task.name, + In0P->thread.name, + In0P->exception, + In0P->code, + In0P->codeCnt); + OutP->NDR = NDR_record; + return TRUE; +} + +kern_return_t mach_exception_raise(mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt) +{ +#pragma pack(push, 4) + 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; + int64_t code[2]; + } Request; + + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_trailer_t trailer; + } Reply; +#pragma pack(pop) + + Request In; + Request *InP = &In; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + + InP->msgh_body.msgh_descriptor_count = 2; + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size = (mach_msg_size_t)(sizeof(Request) - 16) + ((8 * codeCnt)); + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX | + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_remote_port = exception_port; + InP->Head.msgh_local_port = mig_get_reply_port(); + InP->Head.msgh_id = 2405; + InP->Head.msgh_reserved = 0; + + msg_result = mach_msg(&InP->Head, + MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, + msgh_size, + (mach_msg_size_t)sizeof(Reply), + InP->Head.msgh_local_port, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + + if (msg_result != MACH_MSG_SUCCESS) { + fprintf(stderr, "** mach_msg() error forwarding exception!!\n"); + return msg_result; + } + + return KERN_SUCCESS; +} + +ExceptionHandler::ExceptionHandler(const string &dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + bool install_handler, + const char* port_name) + : 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(); +#if !TARGET_OS_IPHONE + if (port_name) + crash_generation_client_.reset(new CrashGenerationClient(port_name)); +#endif + 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(bool write_exception_stream) { + // 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 + bool result = SendMessageToHandlerThread(write_exception_stream ? + kWriteDumpWithExceptionMessage : + kWriteDumpMessage); + if (!result) { + pthread_mutex_unlock(&minidump_write_mutex_); + return false; + } + + // 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, + bool write_exception_stream, + MinidumpCallback callback, + void* callback_context) { + ExceptionHandler handler(dump_path, NULL, callback, callback_context, false, + NULL); + return handler.WriteMinidump(write_exception_stream); +} + +// static +bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, + mach_port_t child_blamed_thread, + const string &dump_path, + MinidumpCallback callback, + void* callback_context) { + ScopedTaskSuspend suspend(child); + + MinidumpGenerator generator(child, MACH_PORT_NULL); + string dump_id; + string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id); + + generator.SetExceptionInformation(EXC_BREAKPOINT, +#if defined(__i386__) || defined(__x86_64__) + EXC_I386_BPT, +#elif defined(__ppc__) || defined(__ppc64__) + EXC_PPC_BREAKPOINT, +#elif defined(__arm__) || defined(__aarch64__) + EXC_ARM_BREAKPOINT, +#else +#error architecture not supported +#endif + 0, + child_blamed_thread); + bool result = generator.Write(dump_filename.c_str()); + + if (callback) { + return callback(dump_path.c_str(), dump_id.c_str(), + callback_context, nullptr, result); + } + return result; +} + +#ifdef MOZ_PHC +static void GetPHCAddrInfo(int exception_type, int64_t exception_subcode, + mozilla::phc::AddrInfo* addr_info) { + // Is this a crash involving a PHC allocation? + if (exception_type == EXC_BAD_ACCESS) { + // `exception_subcode` is only non-zero when it's a bad access, in which + // case it holds the address of the bad access. + char* addr = reinterpret_cast(exception_subcode); + mozilla::phc::IsPHCAllocation(addr, addr_info); + } +} +#endif + +bool ExceptionHandler::WriteMinidumpWithException( + int exception_type, + int64_t exception_code, + int64_t exception_subcode, + breakpad_ucontext_t* task_context, + mach_port_t thread_name, + mach_port_t task_name, + bool exit_after_write, + bool report_current_thread) { + bool result = false; + +#if TARGET_OS_IPHONE + // _exit() should never be called on iOS. + exit_after_write = false; +#endif + + mozilla::phc::AddrInfo* addr_info = nullptr; +#ifdef MOZ_PHC + addr_info = &mozilla::phc::gAddrInfo; + GetPHCAddrInfo(exception_type, exception_subcode, addr_info); +#endif + + if (directCallback_) { + if (directCallback_(callback_context_, + exception_type, + exception_code, + exception_subcode, + thread_name) ) { + if (exit_after_write) + _exit(exception_type); + } +#if !TARGET_OS_IPHONE + } else if (IsOutOfProcess()) { + if (exception_type && exception_code) { + // If this is a real exception, give the filter (if any) a chance to + // decide if this should be sent. + if (filter_ && !filter_(callback_context_)) + return false; + result = crash_generation_client_->RequestDumpForException( + exception_type, + exception_code, + exception_subcode, + thread_name, + task_name); + + if (callback_) { + result = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, + addr_info, result); + } + + if (result && exit_after_write) { + _exit(exception_type); + } + } +#endif + } 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(mach_task_self(), + report_current_thread ? MACH_PORT_NULL : + mach_thread_self()); + md.SetTaskContext(task_context); + if (exception_type && exception_code) { + // If this is a real exception, give the filter (if any) a chance to + // decide if this should be sent. + if (filter_ && !filter_(callback_context_)) + return false; + + md.SetExceptionInformation(exception_type, exception_code, + exception_subcode, thread_name); + } + + result = md.Write(next_minidump_path_c_); + } + + // Call user specified callback (if any) + if (callback_) { + result = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, + addr_info, result); + // 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 (result) { + if (exit_after_write) + _exit(exception_type); + } + } + } + + return result; +} + +kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread, + exception_type_t exception, + mach_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(); + task_get_exception_ports(current_task, + s_exception_mask, + current.masks, + ¤t.count, + current.ports, + current.behaviors, + current.flavors); + + // Find the first exception handler that matches the exception + unsigned int found; + for (found = 0; found < current.count; ++found) { + if (current.masks[found] & (1 << exception)) { + break; + } + } + + // Nothing to forward + if (found == current.count) { + fprintf(stderr, "** No previous ports for forwarding!! \n"); + _exit(KERN_FAILURE); + } + + mach_port_t target_port = current.ports[found]; + exception_behavior_t target_behavior = current.behaviors[found]; + + kern_return_t result; + switch (target_behavior & ~MACH_EXCEPTION_CODES) { + case EXCEPTION_DEFAULT: + result = mach_exception_raise(target_port, failed_thread, task, exception, + code, code_count); + break; + default: + fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior); + result = KERN_FAILURE; + break; + } + + return result; +} + +// static +void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { + pthread_setname_np("Breakpad ExceptionHandler"); + + ExceptionHandler* self = + reinterpret_cast(exception_handler_class); + ExceptionMessage receive; + + // Wait for the exception info + while (1) { + receive.header.msgh_local_port = self->handler_port_; + receive.header.msgh_size = static_cast(sizeof(receive)); + kern_return_t result = mach_msg(&(receive.header), + MACH_RCV_MSG | MACH_RCV_LARGE, 0, + receive.header.msgh_size, + 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) { + // Don't touch self, since this message could have been sent + // from its destructor. + if (receive.header.msgh_id == kShutdownMessage) + return NULL; + + self->SuspendThreads(); + +#if USE_PROTECTED_ALLOCATIONS + if (gBreakpadAllocator) + gBreakpadAllocator->Unprotect(); +#endif + + mach_port_t thread = MACH_PORT_NULL; + int exception_type = 0; + int64_t exception_code = 0; + if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) { + thread = receive.thread.name; + exception_type = EXC_BREAKPOINT; +#if defined(__i386__) || defined(__x86_64__) + exception_code = EXC_I386_BPT; +#elif defined(__ppc__) || defined(__ppc64__) + exception_code = EXC_PPC_BREAKPOINT; +#elif defined(__arm__) || defined(__aarch64__) + exception_code = EXC_ARM_BREAKPOINT; +#else +#error architecture not supported +#endif + } + + // Write out the dump and save the result for later retrieval + self->last_minidump_write_result_ = + self->WriteMinidumpWithException(exception_type, exception_code, + 0, NULL, thread, mach_task_self(), + false, 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 { + bool crash_reported = false; + + // 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 (receive.task.name == mach_task_self()) { + self->SuspendThreads(); + +#if USE_PROTECTED_ALLOCATIONS + if (gBreakpadAllocator) + gBreakpadAllocator->Unprotect(); +#endif + + mach_exception_data_type_t subcode = 0; + if (receive.code_count > 1) { + switch (receive.exception) { + case EXC_BAD_ACCESS: + case EXC_CRASH: + case EXC_RESOURCE: + case EXC_GUARD: + subcode = receive.code[1]; + break; + default: + subcode = 0; + } + } + + // Generate the minidump with the exception data. + crash_reported = + self->WriteMinidumpWithException(receive.exception, receive.code[0], + subcode, NULL, receive.thread.name, + mach_task_self(), true, false); + +#if USE_PROTECTED_ALLOCATIONS + // This may have become protected again within + // WriteMinidumpWithException, but it needs to be unprotected for + // UninstallHandler. + if (gBreakpadAllocator) + gBreakpadAllocator->Unprotect(); +#endif + + self->UninstallHandler(true); + +#if USE_PROTECTED_ALLOCATIONS + if (gBreakpadAllocator) + gBreakpadAllocator->Protect(); +#endif + } + + ExceptionReplyMessage reply; + if (!mach_exc_server(&receive.header, &reply.header)) { + MOZ_CRASH_UNSAFE_PRINTF("Mach message id: %d crash reported = %d", + receive.header.msgh_id, crash_reported); + } + + // Send a reply and exit + mach_msg(&(reply.header), MACH_SEND_MSG, + reply.header.msgh_size, 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + } + } + } + + return NULL; +} + +// static +void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { +#if USE_PROTECTED_ALLOCATIONS + if (gBreakpadAllocator) + gBreakpadAllocator->Unprotect(); +#endif + gProtectedData.handler->WriteMinidumpWithException( + EXC_SOFTWARE, + MD_EXCEPTION_CODE_MAC_ABORT, + 0, + static_cast(uc), + mach_thread_self(), + mach_task_self(), + true, + true); +#if USE_PROTECTED_ALLOCATIONS + if (gBreakpadAllocator) + gBreakpadAllocator->Protect(); +#endif +} + +// static +bool ExceptionHandler::WriteForwardedExceptionMinidump(int exception_type, + int64_t exception_code, + int64_t exception_subcode, + mach_port_t thread, + mach_port_t task) +{ + if (!gProtectedData.handler) { + return false; + } + return gProtectedData.handler->WriteMinidumpWithException(exception_type, exception_code, + exception_subcode, NULL, thread, task, + /* exit_after_write = */ false, + /* report_current_thread = */ true); +} + +bool ExceptionHandler::InstallHandler() { + // If a handler is already installed, something is really wrong. + if (gProtectedData.handler != NULL) { + return false; + } + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGABRT); + sa.sa_sigaction = ExceptionHandler::SignalHandler; + sa.sa_flags = SA_SIGINFO; + + scoped_ptr old(new struct sigaction); + if (sigaction(SIGABRT, &sa, old.get()) == -1) { + return false; + } + old_handler_.swap(old); + gProtectedData.handler = this; +#if USE_PROTECTED_ALLOCATIONS + assert(((size_t)(gProtectedData.protected_buffer) & PAGE_MASK) == 0); + mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ); +#endif + + 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. Such documentation as exists for + // task_set_exception_port() and friends can be found in the source code for + // xnu. Apple's implementation is available at https://opensource.apple.com/. + if (result == KERN_SUCCESS) + result = task_set_exception_ports(current_task, s_exception_mask, + handler_port_, + EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, + 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 (old_handler_.get()) { + sigaction(SIGABRT, old_handler_.get(), NULL); +#if USE_PROTECTED_ALLOCATIONS + mprotect(gProtectedData.protected_buffer, PAGE_SIZE, + PROT_READ | PROT_WRITE); +#endif + // If we're handling an exception, leak the sigaction struct + // because it is unsafe to delete objects while in exception + // handling context. + if (in_exception) { + old_handler_.release(); + } else { + old_handler_.reset(); + } + gProtectedData.handler = NULL; + } + + 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; +} + +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 (SendMessageToHandlerThread(kShutdownMessage)) { + 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_ = MACH_PORT_NULL; + pthread_mutex_destroy(&minidump_write_mutex_); + + return result == KERN_SUCCESS; +} + +bool ExceptionHandler::SendMessageToHandlerThread( + HandlerThreadMessage message_id) { + ExceptionMessage msg; + memset(&msg, 0, sizeof(msg)); + msg.header.msgh_id = message_id; + if (message_id == kWriteDumpMessage || + message_id == kWriteDumpWithExceptionMessage) { + // Include this thread's port. + msg.thread.name = mach_thread_self(); + msg.thread.disposition = MACH_MSG_TYPE_PORT_SEND; + msg.thread.type = MACH_MSG_PORT_DESCRIPTOR; + } + msg.header.msgh_size = sizeof(msg) - sizeof(msg.padding); + msg.header.msgh_remote_port = handler_port_; + msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND_ONCE); + kern_return_t result = mach_msg(&(msg.header), + MACH_SEND_MSG | MACH_SEND_TIMEOUT, + msg.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 diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.h b/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.h new file mode 100644 index 0000000000..24728a8c7c --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/exception_handler.h @@ -0,0 +1,297 @@ +// 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 +#include + +#include + +#include "mac/handler/ucontext_compat.h" +#include "common/scoped_ptr.h" + +#if !TARGET_OS_IPHONE +#include "mac/crash_generation/crash_generation_client.h" +#endif + +#ifdef MOZ_PHC +#include "PHC.h" +#else +namespace mozilla { namespace phc { class AddrInfo {}; } } +#endif + +namespace google_breakpad { + +using std::string; + +struct ExceptionParameters; + +enum HandlerThreadMessage { + // Message ID telling the handler thread to write a dump. + kWriteDumpMessage = 0, + // Message ID telling the handler thread to write a dump and include + // an exception stream. + kWriteDumpWithExceptionMessage = 1, + // Message ID telling the handler thread to quit. + kShutdownMessage = 2 +}; + +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 /.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, + const mozilla::phc::AddrInfo* addr_info, + 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, + int64_t exception_subcode, + 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. + // If port_name is non-NULL, attempt to perform out-of-process dump generation + // If port_name is NULL, in-process dump generation will be used. + ExceptionHandler(const string &dump_path, + FilterCallback filter, MinidumpCallback callback, + void *callback_context, bool install_handler, + const char *port_name); + + // 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() { + return WriteMinidump(false); + } + + bool WriteMinidump(bool write_exception_stream); + + // Convenience form of WriteMinidump which does not require an + // ExceptionHandler instance. + static bool WriteMinidump(const string &dump_path, MinidumpCallback callback, + void *callback_context) { + return WriteMinidump(dump_path, false, callback, callback_context); + } + + static bool WriteMinidump(const string &dump_path, + bool write_exception_stream, + MinidumpCallback callback, + void *callback_context); + + // Write a minidump of child immediately. This can be used to capture + // the execution state of a child process independently of a crash. + static bool WriteMinidumpForChild(mach_port_t child, + mach_port_t child_blamed_thread, + const std::string &dump_path, + MinidumpCallback callback, + void *callback_context); + + // Write a minidump for an exception that was received by another handler. + static bool WriteForwardedExceptionMinidump(int exception_type, + int64_t exception_code, + int64_t exception_subcode, + mach_port_t thread, + mach_port_t task); + + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { +#if TARGET_OS_IPHONE + return false; +#else + return crash_generation_client_.get() != NULL; +#endif + } + + 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 a mach message to the exception handler. Return true on + // success, false otherwise. + bool SendMessageToHandlerThread(HandlerThreadMessage message_id); + + // All minidump writing goes through this one routine. + // |task_context| can be NULL. If not, it will be used to retrieve the + // context of the current thread, instead of using |thread_get_state|. + bool WriteMinidumpWithException(int exception_type, + int64_t exception_code, + int64_t exception_subcode, + breakpad_ucontext_t *task_context, + mach_port_t thread_name, + mach_port_t task_name, + bool exit_after_write, + bool report_current_thread); + + // 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); + + // Signal handler for SIGABRT. + static void SignalHandler(int sig, siginfo_t* info, void* uc); + + // 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_; + + // Old signal handler for SIGABRT. Used to be able to restore it when + // uninstalling. + scoped_ptr old_handler_; + +#if !TARGET_OS_IPHONE + // Client for out-of-process dump generation. + scoped_ptr crash_generation_client_; +#endif +}; + +} // namespace google_breakpad + +#endif // CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/mach_vm_compat.h b/toolkit/crashreporter/breakpad-client/mac/handler/mach_vm_compat.h new file mode 100644 index 0000000000..aef3ad82f5 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/mach_vm_compat.h @@ -0,0 +1,88 @@ +// Copyright (c) 2011, 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_MAC_GENERATOR_MACH_VM_COMPAT_H_ +#define CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_ + +#include + +// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding +// vm_map functions instead. +#if TARGET_OS_IPHONE +#include +#define mach_vm_address_t vm_address_t +#define mach_vm_deallocate vm_deallocate +#define mach_vm_read vm_read +#define mach_vm_region_recurse vm_region_recurse_64 +#define mach_vm_size_t vm_size_t +#else +#include +#endif // TARGET_OS_IPHONE + +// This is the current (as of macOS 11.2.3) raw format of the data in the +// __crash_info section of the __DATA segment. It must be read from memory +// (__crash_info sections in file system modules are always empty of useful +// data). The data (and that of its strings) may be readable from an out-of- +// process image, but generally only if the module is in the dyld shared +// cache. A __crash_info section is considered "empty of useful data" if all +// of its fields besides 'version' are zero. The __crash_info section is only +// present on macOS. Apple may add new fields to this structure in the future, +// as they added 'abort_cause' when 'version' changed from '4' to '5'. +// Breakpad should take this into account, and provide a way for new fields to +// be added to future versions of MDRawMacCrashInfoRecord without breaking +// older code. +typedef struct { // Non-raw format + uint64_t version; // unsigned long + uint64_t message; // char * + uint64_t signature_string; // char * + uint64_t backtrace; // char * + uint64_t message2; // char * + // We can't use uint64_t for 'thread' in non-raw structures: Though uint64_t + // is the same size on all platforms, it's "unsigned long" on some platforms + // (like Android and Linux) and "unsigned long long" on others (like macOS + // and Windows). + uint64_t thread; // uint64_t, but we use unsigned long long + uint64_t dialog_mode; // unsigned int + // There's a string in the OSAnalytics private framework ("Abort Cause %lld") + // which hints that this field's non-raw format is long long. + uint64_t abort_cause; // long long, only present when + // 'version' > 4 +} crashreporter_annotations_t; + +// Defines for calls to getsectdatafromheader_64() or getsectdatafromheader(). +// __LP64__ is true on both amd64 and arm64 (Apple Silicon) hardware. +#ifdef __LP64__ + #define getsectdatafromheader_func getsectdatafromheader_64 + typedef uint64_t getsectdata_size_type; +#else + #define getsectdatafromheader_func getsectdatafromheader + typedef uint32_t getsectdata_size_type; +#endif + +#endif // CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.cc b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.cc new file mode 100644 index 0000000000..e13e4509b0 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.cc @@ -0,0 +1,2135 @@ +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mac/handler/minidump_generator.h" + +#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) +#include +#endif +#ifdef HAS_PPC_SUPPORT +#include +#endif +#ifdef HAS_X86_SUPPORT +#include +#endif + +#include "minidump_file_writer-inl.h" +#include "common/mac/file_id.h" +#include "common/mac/macho_id.h" +#include "common/mac/string_utilities.h" + +using MacStringUtils::ConvertToString; +using MacStringUtils::IntegerValueAtIndex; + +namespace google_breakpad { + +#if defined(__LP64__) && __LP64__ +#define LC_SEGMENT_ARCH LC_SEGMENT_64 +#define MH_MAGIC_ARCH MH_MAGIC_64 +#else +#define LC_SEGMENT_ARCH LC_SEGMENT +#define MH_MAGIC_ARCH MH_MAGIC +#endif + +// constructor when generating from within the crashed process +MinidumpGenerator::MinidumpGenerator() + : writer_(), + exception_type_(0), + exception_code_(0), + exception_subcode_(0), + exception_thread_(0), + crashing_task_(mach_task_self()), + handler_thread_(mach_thread_self()), + cpu_type_(DynamicImages::GetNativeCPUType()), + dyldImageLoadAddress_(NULL), + dyldSlide_(0), + dyldPath_(), + task_context_(NULL), + dynamic_images_(NULL), + memory_blocks_(&allocator_) { + GatherSystemInformation(); + GatherCurrentProcessDyldInformation(); +} + +// constructor when generating from a different process than the +// crashed process +MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, + mach_port_t handler_thread) + : writer_(), + exception_type_(0), + exception_code_(0), + exception_subcode_(0), + exception_thread_(0), + crashing_task_(crashing_task), + handler_thread_(handler_thread), + cpu_type_(DynamicImages::GetNativeCPUType()), + dyldImageLoadAddress_(NULL), + dyldSlide_(0), + dyldPath_(), + task_context_(NULL), + dynamic_images_(NULL), + memory_blocks_(&allocator_) { + if (crashing_task != mach_task_self()) { + dynamic_images_ = new DynamicImages(crashing_task_); + cpu_type_ = dynamic_images_->GetCPUType(); + } else { + dynamic_images_ = NULL; + cpu_type_ = DynamicImages::GetNativeCPUType(); + } + + GatherSystemInformation(); + // This constructor is used when creating a crash server, but the crash + // server may also be the crashing process. + GatherCurrentProcessDyldInformation(); +} + +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); + CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers); + CFRelease(sys_vers); + if (!read_stream) { + return; + } + if (!CFReadStreamOpen(read_stream)) { + CFRelease(read_stream); + return; + } + CFMutableDataRef data = NULL; + while (true) { + // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes. + const CFIndex kMaxBufferLength = 1024; + UInt8 data_bytes[kMaxBufferLength]; + CFIndex num_bytes_read = + CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength); + if (num_bytes_read < 0) { + if (data) { + CFRelease(data); + data = NULL; + } + break; + } else if (num_bytes_read == 0) { + break; + } else if (!data) { + data = CFDataCreateMutable(NULL, 0); + } + CFDataAppendBytes(data, data_bytes, num_bytes_read); + } + CFReadStreamClose(read_stream); + CFRelease(read_stream); + if (!data) { + return; + } + CFDictionaryRef list = + static_cast(CFPropertyListCreateWithData( + NULL, data, kCFPropertyListImmutable, NULL, NULL)); + CFRelease(data); + if (!list) { + return; + } + CFStringRef build_version = static_cast + (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion"))); + CFStringRef product_version = static_cast + (CFDictionaryGetValue(list, CFSTR("ProductVersion"))); + string build_str = ConvertToString(build_version); + string product_str = ConvertToString(product_version); + + CFRelease(list); + + 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); +} + +// static +uint64_t +MinidumpGenerator::GetCurrentProcessModuleSlide(breakpad_mach_header* mh, + uint64_t shared_cache_slide) { + if (!mh || (mh->magic != MH_MAGIC_ARCH)) { + return 0; + } + + if ((mh->flags & MH_SHAREDCACHE) != 0) { + return shared_cache_slide; + } + + uint64_t slide = 0; + + uint32_t num_commands = mh->ncmds; + breakpad_mach_segment_command* cmd = (breakpad_mach_segment_command*) + ((uintptr_t)mh + sizeof(breakpad_mach_header)); + for (uint32_t i = 0; i < num_commands; ++i) { + if (cmd->cmd != LC_SEGMENT_ARCH) { + break; + } + if (!cmd->fileoff && cmd->filesize) { + slide = (uintptr_t)mh - cmd->vmaddr; + break; + } + cmd = (breakpad_mach_segment_command*) ((uintptr_t)cmd + cmd->cmdsize); + } + + return slide; +} + +void MinidumpGenerator::GatherCurrentProcessDyldInformation() { + task_dyld_info_data_t task_dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + if (task_info(mach_task_self(), TASK_DYLD_INFO, + (task_info_t)&task_dyld_info, &count) != KERN_SUCCESS) { + return; + } + + dyld_all_image_infos_self* aii = (dyld_all_image_infos_self*) + task_dyld_info.all_image_info_addr; + breakpad_mach_header* mh = (breakpad_mach_header*) aii->dyldImageLoadAddress; + if (!mh || (mh->magic != MH_MAGIC_ARCH)) { + return; + } + dyldImageLoadAddress_ = mh; + dyldPath_ = string(aii->dyldPath); + dyldSlide_ = GetCurrentProcessModuleSlide(mh, aii->sharedCacheSlide); +} + +void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { + task_context_ = task_context; +} + +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::WriteMemoryListStream, + &MinidumpGenerator::WriteSystemInfoStream, + &MinidumpGenerator::WriteModuleListStream, + &MinidumpGenerator::WriteMiscInfoStream, + &MinidumpGenerator::WriteBreakpadInfoStream, + &MinidumpGenerator::WriteCrashInfoStream, + &MinidumpGenerator::WriteBootargsStream, + &MinidumpGenerator::WriteThreadNamesStream, + // 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 = false; + + // 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 header(&writer_); + TypedMDRVA dir(&writer_); + + if (!header.Allocate()) + return false; + + int writer_count = static_cast(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(&(header_ptr->time_date_stamp))); + header_ptr->stream_count = writer_count; + header_ptr->stream_directory_rva = dir.position(); + + MDRawDirectory local_dir; + result = true; + 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(&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 (result != KERN_SUCCESS || start_addr < stack_region_base) { + // Failure or stack corruption, since mach_vm_region had to go + // higher in the process address space to find a valid region. + return 0; + } + + unsigned int tag = submap_info.user_tag; + + // If the user tag is VM_MEMORY_STACK, look for more readable regions with + // the same tag placed immediately above the computed stack region. Under + // some circumstances, the stack for thread 0 winds up broken up into + // multiple distinct abutting regions. This can happen for several reasons, + // including user code that calls setrlimit(RLIMIT_STACK, ...) or changes + // the access on stack pages by calling mprotect. + if (tag == VM_MEMORY_STACK) { + while (true) { + mach_vm_address_t next_region_base = stack_region_base + + stack_region_size; + mach_vm_address_t proposed_next_region_base = next_region_base; + mach_vm_size_t next_region_size; + nesting_level = 0; + info_count = VM_REGION_SUBMAP_INFO_COUNT_64; + result = mach_vm_region_recurse(crashing_task_, &next_region_base, + &next_region_size, &nesting_level, + region_info, &info_count); + if (result != KERN_SUCCESS || + next_region_base != proposed_next_region_base || + submap_info.user_tag != tag || + (submap_info.protection & VM_PROT_READ) == 0) { + break; + } + + stack_region_size += next_region_size; + } + } + + return stack_region_base + stack_region_size - start_addr; +} + +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_) { + vector stack_memory; + if (ReadTaskMemory(crashing_task_, + start_addr, + size, + stack_memory) != KERN_SUCCESS) { + return false; + } + + result = memory.Copy(&stack_memory[0], size); + } else { + result = memory.Copy(reinterpret_cast(start_addr), size); + } + } + + stack_location->start_of_memory_range = start_addr; + stack_location->memory = memory.location(); + + return result; +} + +bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return WriteStackARM(state, stack_location); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return WriteStackARM64(state, stack_location); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return WriteStackPPC(state, stack_location); + case CPU_TYPE_POWERPC64: + return WriteStackPPC64(state, stack_location); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return WriteStackX86(state, stack_location); + case CPU_TYPE_X86_64: + return WriteStackX86_64(state, stack_location); +#endif + default: + return false; + } +} + +bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return WriteContextARM(state, register_location); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return WriteContextARM64(state, register_location); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return WriteContextPPC(state, register_location); + case CPU_TYPE_POWERPC64: + return WriteContextPPC64(state, register_location); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return WriteContextX86(state, register_location); + case CPU_TYPE_X86_64: + return WriteContextX86_64(state, register_location); +#endif + default: + return false; + } +} + +uint64_t MinidumpGenerator::CurrentPCForStack( + breakpad_thread_state_data_t state) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + return CurrentPCForStackARM(state); +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + return CurrentPCForStackARM64(state); +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + return CurrentPCForStackPPC(state); + case CPU_TYPE_POWERPC64: + return CurrentPCForStackPPC64(state); +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + return CurrentPCForStackX86(state); + case CPU_TYPE_X86_64: + return CurrentPCForStackX86_64(state); +#endif + default: + assert(0 && "Unknown CPU type!"); + return 0; + } +} + +#ifdef HAS_ARM_SUPPORT +bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + arm_thread_state_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) { + arm_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + arm_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextARM *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_ARM_FULL; + +#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a]) + + context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp); + context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr); + context_ptr->iregs[15] = REGISTER_FROM_THREADSTATE(machine_state, pc); + context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); + + 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); +#undef AddGPR + + return true; +} +#endif + +#ifdef HAS_ARM64_SUPPORT +bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) { + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool +MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + arm_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextARM64_Old *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_ARM64_FULL_OLD; + +#define AddGPR(a) \ + context_ptr->iregs[a] = ARRAY_REGISTER_FROM_THREADSTATE(machine_state, x, a) + + context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp); + context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr); + context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp); + context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc); + context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); + + 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); +#undef AddGPR + + return true; +} +#endif + +#ifdef HAS_PCC_SUPPORT +bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) { + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, srr0); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) { + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, srr0); +} + +bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + ppc_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextPPC *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_PPC_BASE; + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ + static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, r ## a) + + 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); + AddReg(mq); +#undef AddReg +#undef AddGPR + + return true; +} + +bool MinidumpGenerator::WriteContextPPC64( + breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + TypedMDRVA context(&writer_); + ppc_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextPPC64 *context_ptr = context.get(); + context_ptr->context_flags = MD_CONTEXT_PPC_BASE; + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ + static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, r ## a) + + 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); +#undef AddReg +#undef AddGPR + + return true; +} + +#endif + +#ifdef HAS_X86_SUPPORT +bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location) { + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + mach_vm_address_t start_addr = static_cast( + REGISTER_FROM_THREADSTATE(machine_state, rsp)); + return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, eip); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) { + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + return REGISTER_FROM_THREADSTATE(machine_state, rip); +} + +bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + i386_thread_state_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextX86 *context_ptr = context.get(); + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(machine_state, a)) + + context_ptr->context_flags = MD_CONTEXT_X86; + 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); +#undef AddReg + + return true; +} + +bool MinidumpGenerator::WriteContextX86_64( + breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + TypedMDRVA context(&writer_); + x86_thread_state64_t *machine_state = + reinterpret_cast(state); + + if (!context.Allocate()) + return false; + + *register_location = context.location(); + MDRawContextAMD64 *context_ptr = context.get(); + +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ + REGISTER_FROM_THREADSTATE(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 = static_cast(REGISTER_FROM_THREADSTATE(machine_state, rflags)); + AddReg(cs); + AddReg(fs); + AddReg(gs); +#undef AddReg + + return true; +} +#endif + +bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, + thread_state_t state, + mach_msg_type_number_t *count) { + if (task_context_ && target_thread == mach_thread_self()) { + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + size_t final_size = + std::min(static_cast(*count), sizeof(arm_thread_state_t)); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: { + size_t final_size = + std::min(static_cast(*count), sizeof(arm_thread_state64_t)); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; + } +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: { + size_t state_size = cpu_type_ == CPU_TYPE_I386 ? + sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); + size_t final_size = + std::min(static_cast(*count), state_size); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = static_cast(final_size); + return true; + } +#endif + } + } + + thread_state_flavor_t flavor; + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + flavor = ARM_THREAD_STATE; + break; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + flavor = ARM_THREAD_STATE64; + break; +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + flavor = PPC_THREAD_STATE; + break; + case CPU_TYPE_POWERPC64: + flavor = PPC_THREAD_STATE64; + break; +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + flavor = i386_THREAD_STATE; + break; + case CPU_TYPE_X86_64: + flavor = x86_THREAD_STATE64; + break; +#endif + default: + return false; + } + return thread_get_state(target_thread, flavor, + state, count) == KERN_SUCCESS; +} + +bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, + MDRawThread *thread) { + breakpad_thread_state_data_t state; + mach_msg_type_number_t state_count + = static_cast(sizeof(state)); + + if (GetThreadState(thread_id, state, &state_count)) { + if (!WriteStack(state, &thread->stack)) + return false; + + memory_blocks_.push_back(thread->stack); + + 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 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 + if (handler_thread_ != MACH_PORT_NULL) + non_generator_thread_count = thread_count - 1; + else + non_generator_thread_count = thread_count; + 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::WriteMemoryListStream( + MDRawDirectory *memory_list_stream) { + TypedMDRVA list(&writer_); + + // If the dump has an exception, include some memory around the + // instruction pointer. + const size_t kIPMemorySize = 256; // bytes + bool have_ip_memory = false; + MDMemoryDescriptor ip_memory_d; + if (exception_thread_ && exception_type_) { + breakpad_thread_state_data_t state; + mach_msg_type_number_t stateCount + = static_cast(sizeof(state)); + + if (GetThreadState(exception_thread_, state, &stateCount)) { + uint64_t ip = CurrentPCForStack(state); + // Bound it to the upper and lower bounds of the region + // it's contained within. If it's not in a known memory region, + // don't bother trying to write it. + mach_vm_address_t addr = static_cast(ip); + mach_vm_size_t size; + natural_t nesting_level = 0; + vm_region_submap_info_64 info; + mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; + vm_region_recurse_info_t recurse_info; + recurse_info = reinterpret_cast(&info); + + kern_return_t ret = + mach_vm_region_recurse(crashing_task_, + &addr, + &size, + &nesting_level, + recurse_info, + &info_count); + if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) { + // Try to get 128 bytes before and after the IP, but + // settle for whatever's available. + ip_memory_d.start_of_memory_range = + std::max(uintptr_t(addr), + uintptr_t(ip - (kIPMemorySize / 2))); + uintptr_t end_of_range = + std::min(uintptr_t(ip + (kIPMemorySize / 2)), + uintptr_t(addr + size)); + uintptr_t range_diff = end_of_range - + static_cast(ip_memory_d.start_of_memory_range); + ip_memory_d.memory.data_size = static_cast(range_diff); + have_ip_memory = true; + // This needs to get appended to the list even though + // the memory bytes aren't filled in yet so the entire + // list can be written first. The memory bytes will get filled + // in after the memory list is written. + memory_blocks_.push_back(ip_memory_d); + } + } + } + + // Now fill in the memory list and write it. + size_t memory_count = memory_blocks_.size(); + if (!list.AllocateObjectAndArray(memory_count, + sizeof(MDMemoryDescriptor))) + return false; + + memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM; + memory_list_stream->location = list.location(); + + list.get()->number_of_memory_ranges = static_cast(memory_count); + + unsigned int i; + for (i = 0; i < memory_count; ++i) { + list.CopyIndexAfterObject(i, &memory_blocks_[i], + sizeof(MDMemoryDescriptor)); + } + + if (have_ip_memory) { + // Now read the memory around the instruction pointer. + UntypedMDRVA ip_memory(&writer_); + if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) + return false; + + if (dynamic_images_) { + // Out-of-process. + vector memory; + if (ReadTaskMemory(crashing_task_, + ip_memory_d.start_of_memory_range, + ip_memory_d.memory.data_size, + memory) != KERN_SUCCESS) { + return false; + } + + ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size); + } else { + // In-process, just copy from local memory. + ip_memory.Copy( + reinterpret_cast(ip_memory_d.start_of_memory_range), + ip_memory_d.memory.data_size); + } + + ip_memory_d.memory = ip_memory.location(); + // Write this again now that the data location is filled in. + list.CopyIndexAfterObject(i - 1, &ip_memory_d, + sizeof(MDMemoryDescriptor)); + } + + return true; +} + +bool +MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { + TypedMDRVA 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_; + + uint64_t u_exception_code = exception_code_; + if (exception_type_ == EXC_CRASH) { + if (!IsValidExcCrash(exception_code_)) { + return false; + } + + [[maybe_unused]] int signal_number; + RecoverExceptionDataFromExcCrash(u_exception_code, signal_number); + } + + // This naming is confusing, but it is the proper translation from + // mach naming to minidump naming. + exception_ptr->exception_record.exception_code = exception_type_; + + uint32_t exception_flags = 0; + if (exception_type_ == EXC_RESOURCE || exception_type_ == EXC_GUARD) { + // For EXC_RESOURCE and EXC_GUARD crashes Crashpad records the uppermost + // 32 bits of the exception code in the exception flags, let's do the same + // here. + exception_flags = u_exception_code >> 32; + } else { + exception_flags = exception_code_; + } + + exception_ptr->exception_record.exception_flags = exception_flags; + + breakpad_thread_state_data_t state; + mach_msg_type_number_t state_count + = static_cast(sizeof(state)); + + if (!GetThreadState(exception_thread_, state, &state_count)) + return false; + + if (!WriteContext(state, &exception_ptr->thread_context)) + return false; + + if (exception_type_ == EXC_BAD_ACCESS) + exception_ptr->exception_record.exception_address = exception_subcode_; + else + exception_ptr->exception_record.exception_address = CurrentPCForStack(state); + + // Crashpad stores the exception type and the optional exception codes in + // the exception information field, so we do the same here. + exception_ptr->exception_record.number_parameters = + (exception_subcode_ != 0) ? 3 : 2; + exception_ptr->exception_record.exception_information[0] = exception_type_; + exception_ptr->exception_record.exception_information[1] = exception_code_; + exception_ptr->exception_record.exception_information[2] = exception_subcode_; + + return true; +} + +bool MinidumpGenerator::WriteSystemInfoStream( + MDRawDirectory *system_info_stream) { + TypedMDRVA 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 number_of_processors; + size_t len = sizeof(number_of_processors); + sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); + MDRawSystemInfo *info_ptr = info.get(); + + switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT + case CPU_TYPE_ARM: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM; + break; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64_OLD; + break; +#endif +#ifdef HAS_PPC_SUPPORT + case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; + break; +#endif +#ifdef HAS_X86_SUPPORT + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: + if (cpu_type_ == CPU_TYPE_I386) + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; + else + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64; +#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)) +#elif defined(__x86_64__) + +#define cpuid(op,eax,ebx,ecx,edx) \ + asm ("cpuid \n\t" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "0" (op)) +#endif + +#if defined(__i386__) || defined(__x86_64__) + 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 = static_cast( + (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | + ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4)); + + // decode extended model info + if (info_ptr->processor_level == 0xF || + info_ptr->processor_level == 0x6) { + info_ptr->processor_revision |= + ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4); + } + + // decode extended family info + if (info_ptr->processor_level == 0xF) { + info_ptr->processor_level += + ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20); + } + +#endif // __i386__ || __x86_64_ + break; +#endif // HAS_X86_SUPPORT + default: + info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; + break; + } + + info_ptr->number_of_processors = static_cast(number_of_processors); +#if TARGET_OS_IPHONE + info_ptr->platform_id = MD_OS_IOS; +#else + info_ptr->platform_id = MD_OS_MAC_OS_X; +#endif // TARGET_OS_IPHONE + + 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; +} + +// If index == INT_MAX, we're being asked to write dyld in the crashed process. +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; + + memset(module, 0, sizeof(MDRawModule)); + + MDLocationDescriptor string_location; + + string name = image->GetFilePath(); + if (!writer_.WriteString(name.c_str(), 0, &string_location)) + return false; + + module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); + module->size_of_image = static_cast(image->GetVMSize()); + module->module_name_rva = string_location.rva; + + // We'll skip the executable module, because they don't have + // LC_ID_DYLIB load commands, and the crash processing server gets + // version information from the Plist file, anyway. + if (index != static_cast(FindExecutableModule())) { + module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE; + module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION; + // 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 + uint32_t modVersion = image->GetVersion(); + module->version_info.file_version_hi = 0; + module->version_info.file_version_hi = modVersion >> 16; + module->version_info.file_version_lo |= (modVersion & 0xff00) << 8; + module->version_info.file_version_lo |= (modVersion & 0xff); + } + + if (!WriteCVRecord(module, image->GetCPUType(), image->GetCPUSubtype(), + name.c_str(), /* in_memory */ false, /* out_of_process */ true, + image->GetIsDyld() || image->GetInDyldSharedCache())) { + return false; + } + } else { + // Getting module info in the crashed process + const breakpad_mach_header *header; + if (index == INT_MAX) { + header = dyldImageLoadAddress_; + } else { + 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; + int cpu_subtype = (header->cpusubtype & ~CPU_SUBTYPE_MASK); + bool dyld_or_in_dyld_shared_cache; + unsigned long slide; + const char* name; + if (index == INT_MAX) { + dyld_or_in_dyld_shared_cache = true; + slide = dyldSlide_; + name = dyldPath_.c_str(); + } else { + dyld_or_in_dyld_shared_cache = + ((header->flags & MH_SHAREDCACHE) != 0); + slide = _dyld_get_image_vmaddr_slide(index); + name = _dyld_get_image_name(index); + } + const struct load_command *cmd = + reinterpret_cast(header + 1); + + memset(module, 0, sizeof(MDRawModule)); + + for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { + if (cmd->cmd == LC_SEGMENT_ARCH) { + + const breakpad_mach_segment_command *seg = + reinterpret_cast(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 = static_cast(seg->vmsize); + module->module_name_rva = string_location.rva; + + bool in_memory = false; +#if TARGET_OS_IPHONE + in_memory = true; +#endif + if (!WriteCVRecord(module, cpu_type, cpu_subtype, name, in_memory, + /* out_of_process */ false, + dyld_or_in_dyld_shared_cache)) { + return false; + } + + return true; + } + } + + cmd = reinterpret_cast((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::IsValidExcCrash(uint64_t exception_code) { + switch ((exception_code >> 20) & 0xf) { + case EXC_CRASH: // EXC_CRASH cannot wrap EXC_CRASH + case EXC_RESOURCE: // EXC_RESOURCE would lose data if wrapped + case EXC_GUARD: // EXC_GUARD would lose data if wrapped + case EXC_CORPSE_NOTIFY: // EXC_CRASH cannot wrap EXC_CORPSE_NOTIFY + return false; + default: + return true; + } +} + +void MinidumpGenerator::RecoverExceptionDataFromExcCrash( + uint64_t exception_code, int& signal_number) +{ + exception_type_ = (exception_code >> 20) & 0xf; + exception_code_ = exception_code & 0xfffff; + signal_number = (exception_code >> 24) & 0xff; +} + +bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, int cpu_subtype, + const char *module_path, bool in_memory, + bool out_of_process, bool dyld_or_in_dyld_shared_cache) { + TypedMDRVA 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 = ""; + + size_t module_name_length = strlen(module_name); + + if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_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 + unsigned char identifier[16]; + bool result = false; + bool in_memory_changed = false; + // As of macOS 11, most system libraries no longer have separate copies in + // the macOS file system. They only exist all lumped together in the "dyld + // shared cache", which gets loaded into each process on startup. If one of + // our system libraries isn't in the file system, we can only get a UUID + // (aka a debug id) for it by looking at a copy of the module loaded into + // the crashing process. Setting 'in_memory' to 'true' makes this happen. + // + // We should be reluctant to change the value of 'in_memory' from 'false' to + // 'true'. But we'll sometimes need to do that to work around the problem + // discussed above. In any case we only do it if all else has failed. This + // resolves https://bugzilla.mozilla.org/show_bug.cgi?id=1662862. + // + // We're always called in the main process. But the crashing process might + // be either the same process or a different one (a child process). If it's + // a child process, the modules we'll be looking at are in that process's + // memory space, to which we generally don't have access. But because dyld + // and the dyld shared cache are loaded into all processes, we do have + // access (in child processes) to dyld and modules in the dyld shared cache. + // So it's fine to look at these modules. But we must prevent ourselves from + // trying to access other child process modules. This resolves + // https://bugzilla.mozilla.org/show_bug.cgi?id=1676102. + while (true) { + if (in_memory) { + if (out_of_process && !dyld_or_in_dyld_shared_cache) { + break; + } + MacFileUtilities::MachoID macho(module_path, + reinterpret_cast(module->base_of_image), + static_cast(module->size_of_image)); + result = macho.UUIDCommand(cpu_type, cpu_subtype, identifier); + if (!result) + result = macho.MD5(cpu_type, cpu_subtype, identifier); + if (result || in_memory_changed) + break; + } + + if (!result) { + FileID file_id(module_path); + result = file_id.MachoIdentifier(cpu_type, cpu_subtype, + identifier); + } + if (result) + break; + + if (!in_memory) { + in_memory = true; + in_memory_changed = true; + } else + break; + } + + if (result) { + cv_ptr->signature.data1 = + static_cast(identifier[0]) << 24 | + static_cast(identifier[1]) << 16 | + static_cast(identifier[2]) << 8 | + static_cast(identifier[3]); + cv_ptr->signature.data2 = + static_cast(identifier[4] << 8) | identifier[5]; + cv_ptr->signature.data3 = + static_cast(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 list(&writer_); + + uint32_t image_count = dynamic_images_ ? + dynamic_images_->GetImageCount() : + _dyld_image_count(); + + // module_count is one higher when we're in the crashed process, to make + // room for dyld, which isn't in the standard list of modules. If + // dynamic_images_ exists (and we're in a different process than the + // crashed process), we've already added dyld to it. + uint32_t module_count = dynamic_images_ ? image_count : image_count + 1; + + if (!list.AllocateObjectAndArray(module_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 = static_cast(module_count); + + // Write out the executable module as the first one + MDRawModule module; + uint32_t executableIndex = FindExecutableModule(); + + if (!WriteModuleStream(static_cast(executableIndex), &module)) { + return false; + } + + list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE); + int destinationIndex = 1; // Write all other modules after this one + + if (!dynamic_images_) { + // If we're in the crashed process we need to write dyld explicitly, + // since it's not included in the standard list. index == INT_MAX signals + // our intentions to WriteModuleStream(). + if (!WriteModuleStream(INT_MAX, &module)) { + return false; + } + + list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); + } + + for (uint32_t i = 0; i < image_count; ++i) { + if (i != executableIndex) { + if (!WriteModuleStream(static_cast(i), &module)) { + return false; + } + + list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); + } + } + + return true; +} + +bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { + TypedMDRVA 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 = static_cast(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 = + static_cast(usage.ru_utime.tv_sec); + info_ptr->process_kernel_time = + static_cast(usage.ru_stime.tv_sec); + } + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, + static_cast(info_ptr->process_id) }; + uint mibsize = static_cast(sizeof(mib) / sizeof(mib[0])); + struct kinfo_proc proc; + size_t size = sizeof(proc); + if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) { + info_ptr->process_create_time = + static_cast(proc.kp_proc.p_starttime.tv_sec); + } + + // Speed + uint64_t speed; + const uint64_t kOneMillion = 1000 * 1000; + size = sizeof(speed); + sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); + info_ptr->processor_max_mhz = static_cast(speed / kOneMillion); + info_ptr->processor_mhz_limit = static_cast(speed / kOneMillion); + size = sizeof(speed); + sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); + info_ptr->processor_current_mhz = static_cast(speed / kOneMillion); + + return true; +} + +bool MinidumpGenerator::WriteBreakpadInfoStream( + MDRawDirectory *breakpad_info_stream) { + TypedMDRVA 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; +} + +bool MinidumpGenerator::WriteCrashInfoRecord(MDLocationDescriptor *location, + const char *module_path, + const char *crash_info, + unsigned long crash_info_size, + bool out_of_process, + bool dyld_or_in_dyld_shared_cache) { + TypedMDRVA info(&writer_); + + // Only write crash info records for modules that actually have + // __DATA,__crash_info sections. + if (!crash_info || !crash_info_size) { + return false; + } + // We generally don't have access to modules in another process's memory + // space if the module isn't dyld and isn't in the dyld shared cache. + if (out_of_process && !dyld_or_in_dyld_shared_cache) { + return false; + } + + // If 'crash_info_size' is larger than we expect, 'crash_info' probably + // contains fields we don't recognize (added by Apple since we last updated + // this code). In that case only copy the fields we do recognize. If it's + // smaller than we expect, we're probably running on an older version of + // macOS, whose __crash_info sections don't contain all the fields we + // recognize. In that case make sure the "missing" fields are zeroed in + // 'raw_crash_info'. + crashreporter_annotations_t raw_crash_info; + bzero(&raw_crash_info, sizeof(raw_crash_info)); + if (crash_info_size > sizeof(raw_crash_info)) { + crash_info_size = sizeof(raw_crash_info); + } + memcpy(&raw_crash_info, crash_info, crash_info_size); + + // Don't write crash info records that are empty of useful data (see + // definition of crashreporter_annotations_t in mach_vm_compat.h). + bool is_empty = true; + if (raw_crash_info.message || + raw_crash_info.signature_string || + raw_crash_info.backtrace || + raw_crash_info.message2 || + raw_crash_info.thread || + raw_crash_info.dialog_mode || + ((raw_crash_info.version > 4) && raw_crash_info.abort_cause)) { + is_empty = false; + } + if (is_empty) { + return false; + } + + string message; + string signature_string; + string backtrace; + string message2; + + const char *message_ptr = NULL; + const char *signature_string_ptr = NULL; + const char *backtrace_ptr = NULL; + const char *message2_ptr = NULL; + + if (out_of_process) { + if (raw_crash_info.message) { + message = ReadTaskString(crashing_task_, raw_crash_info.message); + message_ptr = message.c_str(); + } + if (raw_crash_info.signature_string) { + signature_string = + ReadTaskString(crashing_task_, raw_crash_info.signature_string); + signature_string_ptr = signature_string.c_str(); + } + if (raw_crash_info.backtrace) { + backtrace = ReadTaskString(crashing_task_, raw_crash_info.backtrace); + backtrace_ptr = backtrace.c_str(); + } + if (raw_crash_info.message2) { + message2 = ReadTaskString(crashing_task_, raw_crash_info.message2); + message2_ptr = message2.c_str(); + } + } else { + message_ptr = reinterpret_cast(raw_crash_info.message); + signature_string_ptr = + reinterpret_cast(raw_crash_info.signature_string); + backtrace_ptr = reinterpret_cast(raw_crash_info.backtrace); + message2_ptr = reinterpret_cast(raw_crash_info.message2); + } + + const char* data_strings[] = { module_path, message_ptr, + signature_string_ptr, backtrace_ptr, + message2_ptr }; + + // Compute the total size of the strings we'll be copying to + // (MDRawMacCrashInfoRecord).data, including their terminal nulls. + size_t data_size = 0; + for (auto src : data_strings) { + if (!src) { + src = ""; + } + // Always include the terminal null, even for an empty string. + size_t copy_length = strlen(src) + 1; + // A "string" that's too large is a sign of data corruption. + if (copy_length > MACCRASHINFO_STRING_MAXSIZE) { + return false; + } + data_size += copy_length; + } + + if (!info.AllocateObjectAndArray(data_size, sizeof(uint8_t))) + return false; + + // Now copy 'module_path' and the __crash_info strings in order to + // (MDRawMacCrashInfoRecord).data, including their terminal nulls. + size_t offset = 0; + for (auto src : data_strings) { + if (!src) { + src = ""; + } + // Always include the terminal null, even for an empty string. + size_t copy_length = strlen(src) + 1; + // We can't use CopyIndexAfterObject() here. Calling that method multiple + // times only works for objects in an array (which are all the same size). + if (!info.Copy(info.position() + sizeof(MDRawMacCrashInfoRecord) + offset, + src, copy_length)) { + return false; + } + offset += copy_length; + } + + *location = info.location(); + MDRawMacCrashInfoRecord *info_ptr = info.get(); + info_ptr->stream_type = MOZ_MACOS_CRASH_INFO_STREAM; + info_ptr->version = raw_crash_info.version; + info_ptr->thread = raw_crash_info.thread; + info_ptr->dialog_mode = raw_crash_info.dialog_mode; + info_ptr->abort_cause = raw_crash_info.abort_cause; + + return true; +} + +bool MinidumpGenerator::WriteCrashInfoStream( + MDRawDirectory *crash_info_stream) { + TypedMDRVA list(&writer_); + + if (!list.Allocate()) + return false; + + crash_info_stream->stream_type = MOZ_MACOS_CRASH_INFO_STREAM; + crash_info_stream->location = list.location(); + + MDRawMacCrashInfo *list_ptr = list.get(); + bzero(list_ptr, sizeof(MDRawMacCrashInfo)); + list_ptr->stream_type = MOZ_MACOS_CRASH_INFO_STREAM; + list_ptr->record_start_size = sizeof(MDRawMacCrashInfoRecord); + + uint32_t image_count = dynamic_images_ ? + dynamic_images_->GetImageCount() : + // Leave room for dyld, which isn't among the images + // counted by _dyld_image_count(). + _dyld_image_count() + 1; + uint32_t crash_info_count = 0; + for (uint32_t i = 0; (i < image_count) && + (crash_info_count < MAC_CRASH_INFOS_MAX); ++i) { + if (dynamic_images_) { + // We're in a different process than the crashed process + DynamicImage *image = dynamic_images_->GetImage(i); + if (!image) { + continue; + } + + MDLocationDescriptor location; + string module_path = image->GetFilePath(); + // WriteCrashInfoRecord() fails if a module doesn't contain a + // __DATA,__crash_info section, or if it's empty of useful data. + if (WriteCrashInfoRecord(&location, + module_path.c_str(), + reinterpret_cast + (image->GetCrashInfo()), + image->GetCrashInfoSize(), + /* out_of_process */ true, + image->GetInDyldSharedCache() || + image->GetIsDyld())) { + list_ptr->records[crash_info_count] = location; + ++crash_info_count; + } + } else { + // Getting crash info in the crashed process + const breakpad_mach_header *header; + // dyld isn't in our list of images, so tack it onto the end. + if (i == image_count - 1) { + header = dyldImageLoadAddress_; + } else { + header = (breakpad_mach_header*) _dyld_get_image_header(i); + } + if (!header || (header->magic != MH_MAGIC_ARCH)) { + continue; + } + + unsigned long slide; + const char *module_path; + bool dyld_or_in_dyld_shared_cache; + if (i == image_count - 1) { + slide = dyldSlide_; + module_path = dyldPath_.c_str(); + dyld_or_in_dyld_shared_cache = true; + } else { + slide = _dyld_get_image_vmaddr_slide(i); + module_path = _dyld_get_image_name(i); + dyld_or_in_dyld_shared_cache = + ((header->flags & MH_SHAREDCACHE) != 0); + } + + getsectdata_size_type crash_info_size = 0; + const char *crash_info = + getsectdatafromheader_func(header, "__DATA", "__crash_info", + &crash_info_size); + // __crash_info might be in the __DATA_DIRTY segment. + if (!crash_info) { + crash_info = + getsectdatafromheader_func(header, "__DATA_DIRTY", "__crash_info", + &crash_info_size); + } + if (crash_info) { + crash_info += slide; + } + MDLocationDescriptor location; + // WriteCrashInfoRecord() fails if a module doesn't contain a + // __DATA,__crash_info section, or if it's empty of useful data. + if (WriteCrashInfoRecord(&location, module_path, crash_info, + crash_info_size, /* out_of_process */ false, + dyld_or_in_dyld_shared_cache)) { + list_ptr->records[crash_info_count] = location; + ++crash_info_count; + } + } + } + + list_ptr->record_count = crash_info_count; + + return true; +} + +bool MinidumpGenerator::WriteBootargsStream( + MDRawDirectory *bootargs_stream) { + TypedMDRVA info(&writer_); + if (!info.Allocate()) + return false; + + bootargs_stream->stream_type = MOZ_MACOS_BOOTARGS_STREAM; + bootargs_stream->location = info.location(); + + // We need to write *something* to the stream -- otherwise it will get + // corrupted. So if we fail to get kern.bootargs, or if it's empty, write + // an empty string -- a single terminal null. + size_t size = 0; // Includes terminal null + int rv = sysctlbyname("kern.bootargs", NULL, &size, NULL, 0); + if ((rv != 0) || (size == 0)) + size = 1; + vector bootargs(size); + bootargs[0] = 0; + if (rv == 0) + sysctlbyname("kern.bootargs", &bootargs[0], &size, NULL, 0); + + MDLocationDescriptor bootargs_location; + const char *bootargs_ptr = reinterpret_cast(&bootargs[0]); + if (!writer_.WriteString(bootargs_ptr, 0, &bootargs_location)) + return false; + + MDRawMacBootargs *info_ptr = info.get(); + info_ptr->stream_type = MOZ_MACOS_BOOTARGS_STREAM; + info_ptr->bootargs = bootargs_location.rva; + + return true; +} + +bool MinidumpGenerator::WriteThreadName( + mach_port_t thread_id, + MDRawThreadName *thread_name) { + MDLocationDescriptor string_location; + + thread_extended_info_data_t thread_extended_info; + mach_msg_type_number_t thread_extended_info_count = + THREAD_EXTENDED_INFO_COUNT; + kern_return_t res = thread_info(thread_id, THREAD_EXTENDED_INFO, + (thread_info_t)&thread_extended_info, + &thread_extended_info_count); + + if (res != KERN_SUCCESS) + return false; + + if (!writer_.WriteString(thread_extended_info.pth_name, 0, &string_location)) + return false; + + thread_name->thread_id = thread_id; + thread_name->rva_of_thread_name = string_location.rva; + return true; +} + +bool MinidumpGenerator::WriteThreadNamesStream( + MDRawDirectory *thread_names_stream) { + TypedMDRVA list(&writer_); + thread_act_port_array_t threads_for_task; + mach_msg_type_number_t thread_count; + + if (task_threads(crashing_task_, &threads_for_task, &thread_count)) + return false; + + int non_generator_thread_count; + + // Don't include the generator thread + if (handler_thread_ != MACH_PORT_NULL) + non_generator_thread_count = thread_count - 1; + else + non_generator_thread_count = thread_count; + + if (!list.AllocateObjectAndArray(non_generator_thread_count, + sizeof(MDRawThreadName))) { + return false; + } + + thread_names_stream->stream_type = MD_THREAD_NAMES_STREAM; + thread_names_stream->location = list.location(); + + list.get()->number_of_thread_names = non_generator_thread_count; + + MDRawThreadName thread_name; + int thread_idx = 0; + + for (unsigned int i = 0; i < thread_count; ++i) { + memset(&thread_name, 0, sizeof(MDRawThreadName)); + + if (threads_for_task[i] != handler_thread_) { + if (WriteThreadName(threads_for_task[i], &thread_name)) { + list.CopyIndexAfterObject(thread_idx++, &thread_name, + sizeof(MDRawThreadName)); + } + } + } + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.h b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.h new file mode 100644 index 0000000000..aba067cc04 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_generator.h @@ -0,0 +1,290 @@ +// 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 +#include + +#include + +#include "mac/handler/ucontext_compat.h" +#include "minidump_file_writer.h" +#include "common/memory_allocator.h" +#include "common/mac/macho_utilities.h" +#include "google_breakpad/common/minidump_format.h" + +#include "dynamic_images.h" +#include "mach_vm_compat.h" + +#if defined(__arm__) +#define HAS_ARM_SUPPORT +#elif defined(__aarch64__) +#define HAS_ARM64_SUPPORT +#elif defined(__i386__) || defined(__x86_64__) + #define HAS_X86_SUPPORT +#endif + +namespace google_breakpad { + +using std::string; + +// Use the REGISTER_FROM_THREADSTATE to access a register name from the +// breakpad_thread_state_t structure. +#if __DARWIN_OPAQUE_ARM_THREAD_STATE64 +#define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i) ((a)->__##b[i]) +#define GET_REGISTER_FROM_THREADSTATE_fp(a) \ + (reinterpret_cast((a)->__opaque_fp)) +#define GET_REGISTER_FROM_THREADSTATE_lr(a) \ + (reinterpret_cast((a)->__opaque_lr)) +#define GET_REGISTER_FROM_THREADSTATE_sp(a) \ + (reinterpret_cast((a)->__opaque_sp)) +#define GET_REGISTER_FROM_THREADSTATE_pc(a) \ + (reinterpret_cast((a)->__opaque_pc)) +#define GET_REGISTER_FROM_THREADSTATE_cpsr(a) ((a)->__cpsr) +#define GET_REGISTER_FROM_THREADSTATE_flags(a) ((a)->__opaque_flags) +#define REGISTER_FROM_THREADSTATE(a, b) (GET_REGISTER_FROM_THREADSTATE_##b(a)) +#elif __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64 || TARGET_CPU_ARM +// In The 10.5 SDK Headers Apple prepended __ to the variable names in the +// i386_thread_state_t structure. There's no good way to tell what version of +// the SDK we're compiling against so we just toggle on the same preprocessor +// symbol Apple's headers use. +#define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b) +#define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i) \ + REGISTER_FROM_THREADSTATE(a, b[i]) +#else +#define REGISTER_FROM_THREADSTATE(a, b) (a->b) +#define ARRAY_REGISTER_FROM_THREADSTATE(a, b, i) \ + REGISTER_FROM_THREADSTATE(a, b[i]) +#endif + +// These typedefs only apply to the current process, whether or not it's the +// one that crashed. +#ifdef __LP64__ +typedef dyld_all_image_infos64 dyld_all_image_infos_self; +#else +typedef dyld_all_image_infos32 dyld_all_image_infos_self; +#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); + + virtual ~MinidumpGenerator(); + + // Return /.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, int64_t code, int64_t subcode, + mach_port_t thread_name) { + exception_type_ = type; + exception_code_ = code; + exception_subcode_ = subcode; + exception_thread_ = thread_name; + } + + // Specify the task context. If |task_context| is not NULL, it will be used + // to retrieve the context of the current thread, instead of using + // |thread_get_state|. + void SetTaskContext(breakpad_ucontext_t *task_context); + + // Gather system information. This should be call at least once before using + // the MinidumpGenerator class. + static void GatherSystemInformation(); + + // Get the slide for a module in the current process. + static uint64_t GetCurrentProcessModuleSlide(breakpad_mach_header* mh, + uint64_t shared_cache_slide); + + // Gather information about the dyld module in the current process. This + // information is only relevant if the current process is also the crashing + // process. + void GatherCurrentProcessDyldInformation(); + + protected: + // Overridable Stream writers + virtual bool WriteExceptionStream(MDRawDirectory *exception_stream); + + // Overridable Helper + virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread); + + private: + typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *); + + // Stream writers + bool WriteThreadListStream(MDRawDirectory *thread_list_stream); + bool WriteMemoryListStream(MDRawDirectory *memory_list_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); + bool WriteCrashInfoStream(MDRawDirectory *crash_info_stream); + bool WriteBootargsStream(MDRawDirectory *bootargs_stream); + bool WriteThreadNamesStream(MDRawDirectory *thread_names_stream); + + // Helpers + uint64_t CurrentPCForStack(breakpad_thread_state_data_t state); + bool GetThreadState(thread_act_t target_thread, thread_state_t state, + mach_msg_type_number_t *count); + 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 WriteCVRecord(MDRawModule *module, int cpu_type, int cpu_subtype, + const char *module_path, bool in_memory, + bool out_of_process, bool dyld_or_in_dyld_shared_cache); + bool WriteModuleStream(unsigned int index, MDRawModule *module); + bool WriteCrashInfoRecord(MDLocationDescriptor *location, + const char *module_path, + const char *crash_info, + unsigned long crash_info_size, + bool out_of_process, + bool dyld_or_in_dyld_shared_cache); + bool WriteThreadName(mach_port_t thread_id, + MDRawThreadName *thread_name); + size_t CalculateStackSize(mach_vm_address_t start_addr); + int FindExecutableModule(); + bool IsValidExcCrash(uint64_t exception_code); + void RecoverExceptionDataFromExcCrash(uint64_t exception_code, + int& signal_number); + + // Per-CPU implementations of these methods +#ifdef HAS_ARM_SUPPORT + bool WriteStackARM(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextARM(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state); +#endif +#ifdef HAS_ARM64_SUPPORT + bool WriteStackARM64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextARM64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state); +#endif +#ifdef HAS_PPC_SUPPORT + bool WriteStackPPC(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextPPC(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state); + bool WriteStackPPC64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextPPC64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state); +#endif +#ifdef HAS_X86_SUPPORT + bool WriteStackX86(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextX86(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state); + bool WriteStackX86_64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextX86_64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state); +#endif + + // disallow copy ctor and operator= + explicit MinidumpGenerator(const MinidumpGenerator &); + void operator=(const MinidumpGenerator &); + + protected: + // Use this writer to put the data to disk + MinidumpFileWriter writer_; + + private: + // Exception information + int exception_type_; + int64_t exception_code_; + int64_t exception_subcode_; + mach_port_t exception_thread_; + mach_port_t crashing_task_; + mach_port_t handler_thread_; + + // CPU type of the task being dumped. + cpu_type_t cpu_type_; + + // System information + static char build_string_[16]; + static int os_major_version_; + static int os_minor_version_; + static int os_build_number_; + + // Current process dyld information. It only applies to the crashed process + // if the current process is the one that crashed. It doesn't apply to the + // crashed process if the current process is the crash server and some other + // process has crashed. + breakpad_mach_header* dyldImageLoadAddress_; + ptrdiff_t dyldSlide_; + string dyldPath_; + + // Context of the task to dump. + breakpad_ucontext_t *task_context_; + + // Information about dynamically loaded code + DynamicImages *dynamic_images_; + + // PageAllocator makes it possible to allocate memory + // directly from the system, even while handling an exception. + mutable PageAllocator allocator_; + + protected: + // Blocks of memory written to the dump. These are all currently + // written while writing the thread list stream, but saved here + // so a memory list stream can be written afterwards. + wasteful_vector memory_blocks_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/minidump_test.xcodeproj/project.pbxproj b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_test.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..1924ac4d58 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/minidump_test.xcodeproj/project.pbxproj @@ -0,0 +1,843 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 8BFC813F11FF9A58002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814411FF9A9C002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814511FF9A9D002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814811FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814911FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814A11FF9B13002CB4DC /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */; }; + 8BFC814B11FF9B3F002CB4DC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; }; + 8BFC814C11FF9B3F002CB4DC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; }; + 8BFC81A211FF9C2E002CB4DC /* CPlusTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */; }; + 8BFC81A311FF9C2F002CB4DC /* CPlusTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */; }; + 8BFC81AD11FF9C8A002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; }; + 8BFC81AE11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; }; + 8BFC81AF11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; }; + 8BFC81B011FF9C8D002CB4DC /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; }; + 9B35FF5A0B267D5F008DE8C7 /* convert_UTF.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF560B267D5F008DE8C7 /* convert_UTF.cc */; }; + 9B35FF5B0B267D5F008DE8C7 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */; }; + 9B37CEEC0AF98ECD00FA4BD4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */; }; + 9B7CA7700B12873A00CD3A1D /* minidump_file_writer-inl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BE3C01E0B0CE329009892DF /* minidump_file_writer-inl.h */; }; + 9B7CA8540B12989000CD3A1D /* minidump_file_writer_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B7CA8530B12989000CD3A1D /* minidump_file_writer_unittest.cc */; }; + 9B7CA8550B1298A100CD3A1D /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C230B01344C0055103E /* minidump_file_writer.cc */; }; + 9BC1D2940B336F2300F2A2B4 /* convert_UTF.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF560B267D5F008DE8C7 /* convert_UTF.cc */; }; + 9BC1D2950B336F2500F2A2B4 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */; }; + 9BD82AC10B0029DF0055103E /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */; }; + 9BD82BFF0B01333D0055103E /* exception_handler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82BFD0B01333D0055103E /* exception_handler_test.cc */; }; + 9BD82C020B01333D0055103E /* minidump_generator_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82BFE0B01333D0055103E /* minidump_generator_test.cc */; }; + 9BD82C0D0B0133520055103E /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C090B0133520055103E /* exception_handler.cc */; }; + 9BD82C0E0B0133520055103E /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C0B0B0133520055103E /* minidump_generator.cc */; }; + 9BD82C0F0B0133520055103E /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C090B0133520055103E /* exception_handler.cc */; }; + 9BD82C100B0133520055103E /* exception_handler.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD82C0A0B0133520055103E /* exception_handler.h */; }; + 9BD82C110B0133520055103E /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C0B0B0133520055103E /* minidump_generator.cc */; }; + 9BD82C120B0133520055103E /* minidump_generator.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD82C0C0B0133520055103E /* minidump_generator.h */; }; + 9BD82C250B01344C0055103E /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C230B01344C0055103E /* minidump_file_writer.cc */; }; + 9BD82C260B01344C0055103E /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C230B01344C0055103E /* minidump_file_writer.cc */; }; + 9BD82C270B01344C0055103E /* minidump_file_writer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD82C240B01344C0055103E /* minidump_file_writer.h */; }; + 9BD82C2D0B01345E0055103E /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C2B0B01345E0055103E /* string_utilities.cc */; }; + 9BD82C2E0B01345E0055103E /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BD82C2B0B01345E0055103E /* string_utilities.cc */; }; + 9BD82C2F0B01345E0055103E /* string_utilities.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD82C2C0B01345E0055103E /* string_utilities.h */; }; + D2F651000BEF947200920385 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; }; + D2F651010BEF947200920385 /* file_id.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D2F650FB0BEF947200920385 /* file_id.h */; }; + D2F651020BEF947200920385 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; }; + D2F651030BEF947200920385 /* macho_id.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D2F650FD0BEF947200920385 /* macho_id.h */; }; + D2F651040BEF947200920385 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; }; + D2F651050BEF947200920385 /* macho_utilities.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D2F650FF0BEF947200920385 /* macho_utilities.h */; }; + D2F651090BEF949A00920385 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; }; + D2F6510A0BEF949A00920385 /* dynamic_images.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D2F651080BEF949A00920385 /* dynamic_images.h */; }; + D2F6510E0BEF94EB00920385 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; }; + D2F6510F0BEF94EB00920385 /* macho_walker.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = D2F6510D0BEF94EB00920385 /* macho_walker.h */; }; + D2F651110BEF951700920385 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */; }; + D2F651130BEF951C00920385 /* string_conversion.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FF590B267D5F008DE8C7 /* string_conversion.h */; }; + D2F651150BEF953000920385 /* convert_UTF.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FF560B267D5F008DE8C7 /* convert_UTF.cc */; }; + D2F651160BEF953100920385 /* convert_UTF.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FF570B267D5F008DE8C7 /* convert_UTF.h */; }; + D2F6511B0BEF970E00920385 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; }; + D2F6511D0BEF973500920385 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; }; + D2F6511E0BEF973600920385 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; }; + D2F6511F0BEF973900920385 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; }; + D2F651210BEF975400920385 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; }; + F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F6510C0BEF94EB00920385 /* macho_walker.cc */; }; + F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FC0BEF947200920385 /* macho_id.cc */; }; + F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FE0BEF947200920385 /* macho_utilities.cc */; }; + F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F650FA0BEF947200920385 /* file_id.cc */; }; + F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9721F310E8B07E800D7E813 /* dwarftests.mm */; }; + F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F390E8B0D0D00D7E813 /* dump_syms.cc */; }; + F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; }; + F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; }; + F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; }; + F93A888B0E8B4C9A0026AF89 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721FA80E8B0E4800D7E813 /* md5.cc */; }; + F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; }; + F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; }; + F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */; }; + F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */; }; + F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; }; + F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; }; + F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2F651070BEF949A00920385 /* dynamic_images.cc */; }; + F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F690486A84900D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 9BD82C100B0133520055103E /* exception_handler.h in CopyFiles */, + 9BD82C120B0133520055103E /* minidump_generator.h in CopyFiles */, + 9BD82C270B01344C0055103E /* minidump_file_writer.h in CopyFiles */, + 9BD82C2F0B01345E0055103E /* string_utilities.h in CopyFiles */, + 9B7CA7700B12873A00CD3A1D /* minidump_file_writer-inl.h in CopyFiles */, + D2F651010BEF947200920385 /* file_id.h in CopyFiles */, + D2F651030BEF947200920385 /* macho_id.h in CopyFiles */, + D2F651050BEF947200920385 /* macho_utilities.h in CopyFiles */, + D2F6510A0BEF949A00920385 /* dynamic_images.h in CopyFiles */, + D2F6510F0BEF94EB00920385 /* macho_walker.h in CopyFiles */, + D2F651130BEF951C00920385 /* string_conversion.h in CopyFiles */, + D2F651160BEF953100920385 /* convert_UTF.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 8BFC812011FF99D5002CB4DC /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; + 8BFC815411FF9B7F002CB4DC /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CPlusTest.framework; path = Library/Frameworks/CPlusTest.framework; sourceTree = DEVELOPER_DIR; }; + 8DD76F6C0486A84900D96B5E /* generator_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = generator_test; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B35FF560B267D5F008DE8C7 /* convert_UTF.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = convert_UTF.cc; path = ../../../common/convert_UTF.cc; sourceTree = SOURCE_ROOT; }; + 9B35FF570B267D5F008DE8C7 /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = convert_UTF.h; path = ../../../common/convert_UTF.h; sourceTree = SOURCE_ROOT; }; + 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = string_conversion.cc; path = ../../../common/string_conversion.cc; sourceTree = SOURCE_ROOT; }; + 9B35FF590B267D5F008DE8C7 /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = string_conversion.h; path = ../../../common/string_conversion.h; sourceTree = SOURCE_ROOT; }; + 9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 9B7CA84E0B1297F200CD3A1D /* unit_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unit_test; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B7CA8530B12989000CD3A1D /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer_unittest.cc; path = ../../minidump_file_writer_unittest.cc; sourceTree = ""; }; + 9BD82A9B0B00267E0055103E /* handler_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = handler_test; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BD82BFD0B01333D0055103E /* exception_handler_test.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = exception_handler_test.cc; sourceTree = SOURCE_ROOT; }; + 9BD82BFE0B01333D0055103E /* minidump_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_generator_test.cc; sourceTree = SOURCE_ROOT; }; + 9BD82C090B0133520055103E /* exception_handler.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = exception_handler.cc; sourceTree = SOURCE_ROOT; }; + 9BD82C0A0B0133520055103E /* exception_handler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = exception_handler.h; sourceTree = SOURCE_ROOT; }; + 9BD82C0B0B0133520055103E /* minidump_generator.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_generator.cc; sourceTree = SOURCE_ROOT; }; + 9BD82C0C0B0133520055103E /* minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_generator.h; sourceTree = SOURCE_ROOT; }; + 9BD82C230B01344C0055103E /* minidump_file_writer.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer.cc; path = ../../minidump_file_writer.cc; sourceTree = SOURCE_ROOT; }; + 9BD82C240B01344C0055103E /* minidump_file_writer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = minidump_file_writer.h; path = ../../minidump_file_writer.h; sourceTree = SOURCE_ROOT; }; + 9BD82C2B0B01345E0055103E /* string_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = string_utilities.cc; path = ../../../common/mac/string_utilities.cc; sourceTree = SOURCE_ROOT; }; + 9BD82C2C0B01345E0055103E /* string_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = string_utilities.h; path = ../../../common/mac/string_utilities.h; sourceTree = SOURCE_ROOT; }; + 9BE3C01E0B0CE329009892DF /* minidump_file_writer-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "minidump_file_writer-inl.h"; path = "../../minidump_file_writer-inl.h"; sourceTree = SOURCE_ROOT; }; + D2F650FA0BEF947200920385 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; + D2F650FB0BEF947200920385 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; + D2F650FC0BEF947200920385 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; + D2F650FD0BEF947200920385 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; + D2F650FE0BEF947200920385 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; + D2F650FF0BEF947200920385 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; + D2F651070BEF949A00920385 /* dynamic_images.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = dynamic_images.cc; sourceTree = ""; }; + D2F651080BEF949A00920385 /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = ""; }; + D2F6510C0BEF94EB00920385 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; + D2F6510D0BEF94EB00920385 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; + F917C4F70E03265A00F86017 /* breakpad_exc_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = breakpad_exc_server.c; sourceTree = ""; }; + F917C4F80E03265A00F86017 /* breakpad_exc_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_exc_server.h; sourceTree = ""; }; + F93A88750E8B4C700026AF89 /* octestcases.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = octestcases.octest; sourceTree = BUILT_PRODUCTS_DIR; }; + F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "obj-cTestCases-Info.plist"; sourceTree = ""; }; + F9721F300E8B07E800D7E813 /* dwarftests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dwarftests.h; sourceTree = ""; }; + F9721F310E8B07E800D7E813 /* dwarftests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dwarftests.mm; sourceTree = ""; }; + F9721F380E8B0CFC00D7E813 /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; }; + F9721F390E8B0D0D00D7E813 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; }; + F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + F9721F760E8B0DC700D7E813 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; + F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; + F9721F780E8B0DC700D7E813 /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; }; + F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + F9721FA80E8B0E4800D7E813 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; + F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_test.h; sourceTree = ""; }; + F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_test.cc; sourceTree = ""; }; + F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = ""; }; + F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = ""; }; + F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests32-Info.plist"; sourceTree = ""; }; + F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests64.cptest; sourceTree = BUILT_PRODUCTS_DIR; }; + F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = minidump_tests32.cptest; sourceTree = BUILT_PRODUCTS_DIR; }; + F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "minidump_tests64-Info.plist"; sourceTree = ""; }; + F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicImagesTests.h; sourceTree = ""; }; + F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicImagesTests.cc; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F660486A84900D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9B37CEEC0AF98ECD00FA4BD4 /* CoreFoundation.framework in Frameworks */, + 8BFC813F11FF9A58002CB4DC /* libcrypto.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9B7CA84C0B1297F200CD3A1D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BFC814511FF9A9D002CB4DC /* libcrypto.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD82A990B00267E0055103E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9BD82AC10B0029DF0055103E /* CoreFoundation.framework in Frameworks */, + 8BFC814411FF9A9C002CB4DC /* libcrypto.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F93A88720E8B4C700026AF89 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BFC814A11FF9B13002CB4DC /* libcrypto.dylib in Frameworks */, + 8BFC814B11FF9B3F002CB4DC /* SenTestingKit.framework in Frameworks */, + 8BFC814C11FF9B3F002CB4DC /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE19C00DB04A9500C98454 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8BFC814811FF9B13002CB4DC /* libcrypto.dylib in Frameworks */, + 8BFC81A211FF9C2E002CB4DC /* CPlusTest.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE5B300DBFDBA300505983 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */, + F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */, + 8BFC814911FF9B13002CB4DC /* libcrypto.dylib in Frameworks */, + 8BFC81A311FF9C2F002CB4DC /* CPlusTest.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* MinidumpWriter */ = { + isa = PBXGroup; + children = ( + 8BFC812011FF99D5002CB4DC /* Breakpad.xcconfig */, + 8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */, + 8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */, + F9721FA80E8B0E4800D7E813 /* md5.cc */, + F9721F760E8B0DC700D7E813 /* bytereader.cc */, + F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */, + F9721F780E8B0DC700D7E813 /* functioninfo.cc */, + F9721F390E8B0D0D00D7E813 /* dump_syms.cc */, + F9721F380E8B0CFC00D7E813 /* dump_syms.h */, + F917C4F70E03265A00F86017 /* breakpad_exc_server.c */, + F917C4F80E03265A00F86017 /* breakpad_exc_server.h */, + F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */, + F98208A20DB32CAE0017AECA /* breakpad_nlist_64.h */, + D2F6510C0BEF94EB00920385 /* macho_walker.cc */, + D2F6510D0BEF94EB00920385 /* macho_walker.h */, + D2F651070BEF949A00920385 /* dynamic_images.cc */, + D2F651080BEF949A00920385 /* dynamic_images.h */, + D2F650FA0BEF947200920385 /* file_id.cc */, + D2F650FB0BEF947200920385 /* file_id.h */, + D2F650FC0BEF947200920385 /* macho_id.cc */, + D2F650FD0BEF947200920385 /* macho_id.h */, + D2F650FE0BEF947200920385 /* macho_utilities.cc */, + D2F650FF0BEF947200920385 /* macho_utilities.h */, + F9C5A41F0DB82DB000209C76 /* testcases */, + 9BD82C040B0133420055103E /* Breakpad */, + 08FB7795FE84155DC02AAC07 /* Source */, + 9B37CEEA0AF98EB600FA4BD4 /* Frameworks */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + F9AE19B50DB040E300C98454 /* minidump_tests32-Info.plist */, + F9AE5B340DBFDBA300505983 /* minidump_tests64-Info.plist */, + F93A88760E8B4C700026AF89 /* obj-cTestCases-Info.plist */, + ); + name = MinidumpWriter; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 9BD82BFD0B01333D0055103E /* exception_handler_test.cc */, + 9BD82BFE0B01333D0055103E /* minidump_generator_test.cc */, + 9B7CA8530B12989000CD3A1D /* minidump_file_writer_unittest.cc */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76F6C0486A84900D96B5E /* generator_test */, + 9BD82A9B0B00267E0055103E /* handler_test */, + 9B7CA84E0B1297F200CD3A1D /* unit_test */, + F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */, + F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */, + F93A88750E8B4C700026AF89 /* octestcases.octest */, + ); + name = Products; + sourceTree = ""; + }; + 9B37CEEA0AF98EB600FA4BD4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8BFC813E11FF9A58002CB4DC /* libcrypto.dylib */, + 8BFC815411FF9B7F002CB4DC /* Carbon.framework */, + F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */, + F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */, + 9B37CEEB0AF98ECD00FA4BD4 /* CoreFoundation.framework */, + 8BFC819211FF9C23002CB4DC /* CPlusTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9BD82C040B0133420055103E /* Breakpad */ = { + isa = PBXGroup; + children = ( + 9B35FF560B267D5F008DE8C7 /* convert_UTF.cc */, + 9B35FF570B267D5F008DE8C7 /* convert_UTF.h */, + 9B35FF580B267D5F008DE8C7 /* string_conversion.cc */, + 9B35FF590B267D5F008DE8C7 /* string_conversion.h */, + 9BD82C090B0133520055103E /* exception_handler.cc */, + 9BD82C0A0B0133520055103E /* exception_handler.h */, + 9BD82C0B0B0133520055103E /* minidump_generator.cc */, + 9BD82C0C0B0133520055103E /* minidump_generator.h */, + 9BD82C230B01344C0055103E /* minidump_file_writer.cc */, + 9BE3C01E0B0CE329009892DF /* minidump_file_writer-inl.h */, + 9BD82C240B01344C0055103E /* minidump_file_writer.h */, + 9BD82C2B0B01345E0055103E /* string_utilities.cc */, + 9BD82C2C0B01345E0055103E /* string_utilities.h */, + ); + name = Breakpad; + sourceTree = ""; + }; + F9C5A41F0DB82DB000209C76 /* testcases */ = { + isa = PBXGroup; + children = ( + F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */, + F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */, + F9C5A4200DB82DD800209C76 /* DynamicImagesTests.h */, + F9C5A4210DB82DD800209C76 /* DynamicImagesTests.cc */, + F9721F300E8B07E800D7E813 /* dwarftests.h */, + F9721F310E8B07E800D7E813 /* dwarftests.mm */, + ); + path = testcases; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F620486A84900D96B5E /* generator_test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "generator_test" */; + buildPhases = ( + 8DD76F640486A84900D96B5E /* Sources */, + 8DD76F660486A84900D96B5E /* Frameworks */, + 8DD76F690486A84900D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = generator_test; + productInstallPath = "$(HOME)/bin"; + productName = MinidumpWriter; + productReference = 8DD76F6C0486A84900D96B5E /* generator_test */; + productType = "com.apple.product-type.tool"; + }; + 9B7CA84D0B1297F200CD3A1D /* unit_test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9B7CA8500B12984300CD3A1D /* Build configuration list for PBXNativeTarget "unit_test" */; + buildPhases = ( + 9B7CA84B0B1297F200CD3A1D /* Sources */, + 9B7CA84C0B1297F200CD3A1D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = unit_test; + productName = "filewriter unit test"; + productReference = 9B7CA84E0B1297F200CD3A1D /* unit_test */; + productType = "com.apple.product-type.tool"; + }; + 9BD82A9A0B00267E0055103E /* handler_test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9BD82AA60B0026BF0055103E /* Build configuration list for PBXNativeTarget "handler_test" */; + buildPhases = ( + 9BD82A980B00267E0055103E /* Sources */, + 9BD82A990B00267E0055103E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = handler_test; + productName = ExceptionTester; + productReference = 9BD82A9B0B00267E0055103E /* handler_test */; + productType = "com.apple.product-type.tool"; + }; + F93A88740E8B4C700026AF89 /* obj-c_TestCases */ = { + isa = PBXNativeTarget; + buildConfigurationList = F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */; + buildPhases = ( + F93A88700E8B4C700026AF89 /* Resources */, + F93A88710E8B4C700026AF89 /* Sources */, + F93A88720E8B4C700026AF89 /* Frameworks */, + F93A88730E8B4C700026AF89 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "obj-c_TestCases"; + productName = octestcases; + productReference = F93A88750E8B4C700026AF89 /* octestcases.octest */; + productType = "com.apple.product-type.bundle"; + }; + F9AE19C20DB04A9500C98454 /* minidump_tests64 */ = { + isa = PBXNativeTarget; + buildConfigurationList = F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */; + buildPhases = ( + F9AE19BE0DB04A9500C98454 /* Resources */, + F9AE19BF0DB04A9500C98454 /* Sources */, + F9AE19C00DB04A9500C98454 /* Frameworks */, + F9AE19C10DB04A9500C98454 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = minidump_tests64; + productName = minidump_tests; + productReference = F9AE19C30DB04A9500C98454 /* minidump_tests64.cptest */; + productType = "com.apple.product-type.bundle"; + }; + F9AE5B320DBFDBA300505983 /* minidump_tests32 */ = { + isa = PBXNativeTarget; + buildConfigurationList = F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */; + buildPhases = ( + F9AE5B2E0DBFDBA300505983 /* Resources */, + F9AE5B2F0DBFDBA300505983 /* Sources */, + F9AE5B300DBFDBA300505983 /* Frameworks */, + F9AE5B310DBFDBA300505983 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = minidump_tests32; + productName = Untitled; + productReference = F9AE5B330DBFDBA300505983 /* minidump_tests32.cptest */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "minidump_test" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* MinidumpWriter */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F620486A84900D96B5E /* generator_test */, + 9BD82A9A0B00267E0055103E /* handler_test */, + 9B7CA84D0B1297F200CD3A1D /* unit_test */, + F9AE19C20DB04A9500C98454 /* minidump_tests64 */, + F9AE5B320DBFDBA300505983 /* minidump_tests32 */, + F93A88740E8B4C700026AF89 /* obj-c_TestCases */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F93A88700E8B4C700026AF89 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE19BE0DB04A9500C98454 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE5B2E0DBFDBA300505983 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + F93A88730E8B4C700026AF89 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; + }; + F9AE19C10DB04A9500C98454 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n# Run gcov on the framework getting tested\nif [ \"${CONFIGURATION}\" = 'Coverage' ];\nthen\n FRAMEWORK_NAME=minidump_tests64\n FRAMEWORK_OBJ_DIR=${OBJROOT}/${PROJECT_NAME}.build/${CONFIGURATION}/${FRAMEWORK_NAME}.build/Objects-normal/${NATIVE_ARCH_ACTUAL}\n mkdir -p coverage\n pushd coverage\n echo find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n find ${OBJROOT} -name *.gcda -exec gcov -o ${FRAMEWORK_OBJ_DIR} {} \\;\n popd\nfi "; + }; + F9AE5B310DBFDBA300505983 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F640486A84900D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9BD82C020B01333D0055103E /* minidump_generator_test.cc in Sources */, + 9BD82C0F0B0133520055103E /* exception_handler.cc in Sources */, + 9BD82C110B0133520055103E /* minidump_generator.cc in Sources */, + 9BD82C260B01344C0055103E /* minidump_file_writer.cc in Sources */, + 9BD82C2E0B01345E0055103E /* string_utilities.cc in Sources */, + D2F651000BEF947200920385 /* file_id.cc in Sources */, + D2F651020BEF947200920385 /* macho_id.cc in Sources */, + D2F651040BEF947200920385 /* macho_utilities.cc in Sources */, + D2F651090BEF949A00920385 /* dynamic_images.cc in Sources */, + D2F6510E0BEF94EB00920385 /* macho_walker.cc in Sources */, + D2F651110BEF951700920385 /* string_conversion.cc in Sources */, + D2F651150BEF953000920385 /* convert_UTF.cc in Sources */, + 8BFC81B011FF9C8D002CB4DC /* breakpad_nlist_64.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9B7CA84B0B1297F200CD3A1D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9B7CA8540B12989000CD3A1D /* minidump_file_writer_unittest.cc in Sources */, + 9B7CA8550B1298A100CD3A1D /* minidump_file_writer.cc in Sources */, + 9BC1D2940B336F2300F2A2B4 /* convert_UTF.cc in Sources */, + 9BC1D2950B336F2500F2A2B4 /* string_conversion.cc in Sources */, + 8BFC81AE11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD82A980B00267E0055103E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9BD82BFF0B01333D0055103E /* exception_handler_test.cc in Sources */, + 9BD82C0D0B0133520055103E /* exception_handler.cc in Sources */, + 9BD82C0E0B0133520055103E /* minidump_generator.cc in Sources */, + 9BD82C250B01344C0055103E /* minidump_file_writer.cc in Sources */, + 9BD82C2D0B01345E0055103E /* string_utilities.cc in Sources */, + 9B35FF5A0B267D5F008DE8C7 /* convert_UTF.cc in Sources */, + 9B35FF5B0B267D5F008DE8C7 /* string_conversion.cc in Sources */, + D2F6511B0BEF970E00920385 /* dynamic_images.cc in Sources */, + D2F6511D0BEF973500920385 /* file_id.cc in Sources */, + D2F6511E0BEF973600920385 /* macho_id.cc in Sources */, + D2F6511F0BEF973900920385 /* macho_utilities.cc in Sources */, + D2F651210BEF975400920385 /* macho_walker.cc in Sources */, + 8BFC81AF11FF9C8C002CB4DC /* breakpad_nlist_64.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F93A88710E8B4C700026AF89 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F93A88860E8B4C9A0026AF89 /* dwarftests.mm in Sources */, + F93A88870E8B4C9A0026AF89 /* dump_syms.cc in Sources */, + F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */, + F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */, + F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */, + F93A888B0E8B4C9A0026AF89 /* md5.cc in Sources */, + F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */, + F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */, + F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */, + F93A88800E8B4C8C0026AF89 /* file_id.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE19BF0DB04A9500C98454 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F9B34E870DBC1E1600306484 /* dynamic_images.cc in Sources */, + F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */, + F98208A30DB32CAE0017AECA /* breakpad_nlist_64.cc in Sources */, + F9C5A4220DB82DD800209C76 /* DynamicImagesTests.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F9AE5B2F0DBFDBA300505983 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F9AE5B390DBFDBDB00505983 /* dynamic_images.cc in Sources */, + F9AE5B3A0DBFDBDB00505983 /* DynamicImagesTests.cc in Sources */, + 8BFC81AD11FF9C8A002CB4DC /* breakpad_nlist_64.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB923208733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_FRAMEWORKS_DIR)\"", + ); + PRODUCT_NAME = generator_test; + USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)"; + }; + name = Debug; + }; + 1DEB923308733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(DEVELOPER_FRAMEWORKS_DIR)\"", + ); + PRODUCT_NAME = generator_test; + USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)"; + }; + name = Release; + }; + 1DEB923608733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 1DEB923708733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 9B7CA8510B12984300CD3A1D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = unit_test; + USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)"; + }; + name = Debug; + }; + 9B7CA8520B12984300CD3A1D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = unit_test; + USER_HEADER_SEARCH_PATHS = "../../../** $(inherited)"; + }; + name = Release; + }; + 9BD82AA70B0026BF0055103E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = handler_test; + USER_HEADER_SEARCH_PATHS = "../../.. $(inherited)"; + }; + name = Debug; + }; + 9BD82AA80B0026BF0055103E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = handler_test; + USER_HEADER_SEARCH_PATHS = "../../.. $(inherited)"; + }; + name = Release; + }; + F93A88770E8B4C700026AF89 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "obj-cTestCases-Info.plist"; + PRODUCT_NAME = octestcases; + USER_HEADER_SEARCH_PATHS = "../../../..//**"; + WRAPPER_EXTENSION = octest; + }; + name = Debug; + }; + F93A88780E8B4C700026AF89 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "obj-cTestCases-Info.plist"; + PRODUCT_NAME = octestcases; + USER_HEADER_SEARCH_PATHS = "../../../..//**"; + WRAPPER_EXTENSION = octest; + }; + name = Release; + }; + F9AE19C40DB04A9500C98454 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "minidump_tests64-Info.plist"; + PRODUCT_NAME = minidump_tests64; + USER_HEADER_SEARCH_PATHS = "../../../**"; + WRAPPER_EXTENSION = cptest; + }; + name = Debug; + }; + F9AE19C50DB04A9500C98454 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "minidump_tests64-Info.plist"; + PRODUCT_NAME = minidump_tests64; + USER_HEADER_SEARCH_PATHS = "../../../**"; + WRAPPER_EXTENSION = cptest; + }; + name = Release; + }; + F9AE5B350DBFDBA300505983 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "minidump_tests32-Info.plist"; + PRODUCT_NAME = minidump_tests32; + USER_HEADER_SEARCH_PATHS = "../../../**"; + WRAPPER_EXTENSION = cptest; + }; + name = Debug; + }; + F9AE5B370DBFDBA300505983 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + INFOPLIST_FILE = "minidump_tests32-Info.plist"; + PRODUCT_NAME = minidump_tests32; + USER_HEADER_SEARCH_PATHS = "../../../**"; + WRAPPER_EXTENSION = cptest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "generator_test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923208733DC60010E9CD /* Debug */, + 1DEB923308733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "minidump_test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923608733DC60010E9CD /* Debug */, + 1DEB923708733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9B7CA8500B12984300CD3A1D /* Build configuration list for PBXNativeTarget "unit_test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9B7CA8510B12984300CD3A1D /* Debug */, + 9B7CA8520B12984300CD3A1D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9BD82AA60B0026BF0055103E /* Build configuration list for PBXNativeTarget "handler_test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9BD82AA70B0026BF0055103E /* Debug */, + 9BD82AA80B0026BF0055103E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F93A88790E8B4C700026AF89 /* Build configuration list for PBXNativeTarget "obj-c_TestCases" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F93A88770E8B4C700026AF89 /* Debug */, + F93A88780E8B4C700026AF89 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F9AE19C70DB04AA200C98454 /* Build configuration list for PBXNativeTarget "minidump_tests64" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F9AE19C40DB04A9500C98454 /* Debug */, + F9AE19C50DB04A9500C98454 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F9AE5B380DBFDBA300505983 /* Build configuration list for PBXNativeTarget "minidump_tests32" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F9AE5B350DBFDBA300505983 /* Debug */, + F9AE5B370DBFDBA300505983 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/moz.build b/toolkit/crashreporter/breakpad-client/mac/handler/moz.build new file mode 100644 index 0000000000..7d123a2ef1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'breakpad_nlist_64.cc', + 'dynamic_images.cc', + 'exception_handler.cc', + 'minidump_generator.cc', +] + +FINAL_LIBRARY = 'breakpad_client' + +LOCAL_INCLUDES += [ + '/toolkit/crashreporter/breakpad-client', + '/toolkit/crashreporter/google-breakpad/src', +] + +if CONFIG['MOZ_PHC']: + DEFINES['MOZ_PHC'] = True diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.cc b/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.cc new file mode 100644 index 0000000000..6142ad124a --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.cc @@ -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. +// +// ProtectedMemoryAllocator +// +// See the header file for documentation + +#include "protected_memory_allocator.h" +#include + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ProtectedMemoryAllocator::ProtectedMemoryAllocator(vm_size_t pool_size) + : pool_size_(pool_size), + next_alloc_offset_(0), + valid_(false) { + + kern_return_t result = vm_allocate(mach_task_self(), + &base_address_, + pool_size, + TRUE + ); + + valid_ = (result == KERN_SUCCESS); + assert(valid_); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ProtectedMemoryAllocator::~ProtectedMemoryAllocator() { + vm_deallocate(mach_task_self(), + base_address_, + pool_size_ + ); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) { + if (valid_ && next_alloc_offset_ + bytes <= pool_size_) { + char *p = (char*)base_address_ + next_alloc_offset_; + next_alloc_offset_ += bytes; + return p; + } + + return NULL; // ran out of memory in our allocation block +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +kern_return_t ProtectedMemoryAllocator::Protect() { + kern_return_t result = vm_protect(mach_task_self(), + base_address_, + pool_size_, + FALSE, + VM_PROT_READ); + + return result; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +kern_return_t ProtectedMemoryAllocator::Unprotect() { + kern_return_t result = vm_protect(mach_task_self(), + base_address_, + pool_size_, + FALSE, + VM_PROT_READ | VM_PROT_WRITE); + + return result; +} diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.h b/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.h new file mode 100644 index 0000000000..64ac23c00b --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/protected_memory_allocator.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 + +// +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(vm_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_; + vm_size_t next_alloc_offset_; + bool valid_; +}; + +#endif // PROTECTED_MEMORY_ALLOCATOR_H__ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.cc b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.cc new file mode 100644 index 0000000000..42344ec5d3 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.cc @@ -0,0 +1,79 @@ +// 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. + +// +// DynamicImagesTests.cpp +// minidump_test +// +// Created by Neal Sidhwaney on 4/17/08. +// Copyright 2008 Google Inc. All rights reserved. +// + +#include "mac/handler/testcases/DynamicImagesTests.h" +#include "mac/handler/dynamic_images.h" + +DynamicImagesTests test2(TEST_INVOCATION(DynamicImagesTests, + ReadTaskMemoryTest)); +DynamicImagesTests test3(TEST_INVOCATION(DynamicImagesTests, + ReadLibrariesFromLocalTaskTest)); + +DynamicImagesTests::DynamicImagesTests(TestInvocation *invocation) + : TestCase(invocation) { +} + +DynamicImagesTests::~DynamicImagesTests() { +} + +void DynamicImagesTests::ReadTaskMemoryTest() { + kern_return_t kr; + + // pick test2 as a symbol we know to be valid to read + // anything will work, really + void *addr = reinterpret_cast(&test2); + std::vector buf(getpagesize()); + + fprintf(stderr, "reading 0x%p\n", addr); + kr = google_breakpad::ReadTaskMemory(mach_task_self(), + (uint64_t)addr, + getpagesize(), + buf); + + CPTAssert(kr == KERN_SUCCESS); + + CPTAssert(0 == memcmp(&buf[0], (const void*)addr, getpagesize())); +} + +void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() { + + mach_port_t me = mach_task_self(); + google_breakpad::DynamicImages *d = new google_breakpad::DynamicImages(me); + + fprintf(stderr,"Local task image count: %d\n", d->GetImageCount()); + + CPTAssert(d->GetImageCount() > 0); +} diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.h b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.h new file mode 100644 index 0000000000..e1e79993bb --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/DynamicImagesTests.h @@ -0,0 +1,52 @@ +// 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. + +// +// DynamicImagesTests.h +// minidump_test +// +// Created by Neal Sidhwaney on 4/17/08. +// Copyright 2008 Google Inc. All rights reserved. +// +// + +#ifndef _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__ +#define _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__ + +#include + +class DynamicImagesTests : public TestCase { + public: + explicit DynamicImagesTests(TestInvocation* invocation); + virtual ~DynamicImagesTests(); + + void ReadTaskMemoryTest(); + void ReadLibrariesFromLocalTaskTest(); +}; + +#endif /* _CLIENT_MAC_HANDLER_TESTCASES_DYNAMICIMAGESTESTS_H__ */ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.cc b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.cc new file mode 100644 index 0000000000..ee3248116d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.cc @@ -0,0 +1,106 @@ +// 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_test.cc +// minidump_test +// +// Created by Neal Sidhwaney on 4/13/08. +// Copyright 2008 Google Inc. All rights reserved. +// + +#include "mac/handler/testcases/breakpad_nlist_test.h" +#include +#include "mac/handler/breakpad_nlist_64.h" + +BreakpadNlistTest test1(TEST_INVOCATION(BreakpadNlistTest, CompareToNM)); + +BreakpadNlistTest::BreakpadNlistTest(TestInvocation *invocation) + : TestCase(invocation) { +} + + +BreakpadNlistTest::~BreakpadNlistTest() { +} + +void BreakpadNlistTest::CompareToNM() { +#if TARGET_CPU_X86_64 + system("/usr/bin/nm -arch x86_64 /usr/lib/dyld > /tmp/dyld-namelist.txt"); +#elif TARGET_CPU_PPC64 + system("/usr/bin/nm -arch ppc64 /usr/lib/dyld > /tmp/dyld-namelist.txt"); +#endif + + FILE *fd = fopen("/tmp/dyld-namelist.txt", "rt"); + + char oneNMAddr[30]; + char symbolType; + char symbolName[500]; + while (!feof(fd)) { + fscanf(fd, "%s %c %s", oneNMAddr, &symbolType, symbolName); + breakpad_nlist symbolList[2]; + breakpad_nlist &list = symbolList[0]; + + memset(symbolList, 0, sizeof(breakpad_nlist)*2); + const char *symbolNames[2]; + symbolNames[0] = (const char*)symbolName; + symbolNames[1] = "\0"; + breakpad_nlist_64("/usr/lib/dyld", &list, symbolNames); + uint64_t nmAddr = strtol(oneNMAddr, NULL, 16); + if (!IsSymbolMoreThanOnceInDyld(symbolName)) { + CPTAssert(nmAddr == symbolList[0].n_value); + } + } + + fclose(fd); +} + +bool BreakpadNlistTest::IsSymbolMoreThanOnceInDyld(const char *symbolName) { + // These are the symbols that occur more than once when nm dumps + // the symbol table of /usr/lib/dyld. Our nlist program returns + // the first address because it's doing a search so we need to exclude + // these from causing the test to fail + const char *multipleSymbols[] = { + "__Z41__static_initialization_and_destruction_0ii", + "___tcf_0", + "___tcf_1", + "_read_encoded_value_with_base", + "_read_sleb128", + "_read_uleb128", + "\0"}; + + bool found = false; + + for (int i = 0; multipleSymbols[i][0]; i++) { + if (!strcmp(multipleSymbols[i], symbolName)) { + found = true; + break; + } + } + + return found; +} diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.h b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.h new file mode 100644 index 0000000000..e93657cc90 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/breakpad_nlist_test.h @@ -0,0 +1,62 @@ +// 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_test.h +// minidump_test +// +// Created by Neal Sidhwaney on 4/13/08. +// Copyright 2008 Google Inc. All rights reserved. +// +// + +#ifndef CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__ +#define CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__ + +#include + +class BreakpadNlistTest : public TestCase { + private: + + // nm dumps multiple addresses for the same symbol in + // /usr/lib/dyld. So we track those so we don't report failures + // in mismatches between what our nlist returns and what nm has + // for the duplicate symbols. + bool IsSymbolMoreThanOnceInDyld(const char *symbolName); + + public: + explicit BreakpadNlistTest(TestInvocation* invocation); + virtual ~BreakpadNlistTest(); + + + /* This test case runs nm on /usr/lib/dyld and then compares the + output of every symbol to what our nlist implementation returns */ + void CompareToNM(); +}; + +#endif /* CLIENT_MAC_HANDLER_TESTCASES_BREAKPAD_NLIST_TEST_H__*/ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.h b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.h new file mode 100644 index 0000000000..21ff7a44f0 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.h @@ -0,0 +1,46 @@ +// 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. + +// +// dwarftests.h +// minidump_test +// +// Created by Neal Sidhwaney on 9/24/08. +// Copyright 2008 Google Inc. All rights reserved. +// + +#import + + +@interface dwarftests : SenTestCase { + +} + +- (void) testDWARFSymbolFileGeneration; + +@end diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.mm b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.mm new file mode 100644 index 0000000000..40c69aff25 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/dwarftests.mm @@ -0,0 +1,60 @@ +// 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. + +// +// dwarftests.m +// minidump_test +// +// Created by Neal Sidhwaney on 9/24/08. +// Copyright 2008 Google Inc. All rights reserved. +// + +#import "dwarftests.h" +#import "dump_syms.h" + +@implementation dwarftests +- (void) testDWARFSymbolFileGeneration { + NSString *inputBreakpadSymbolFile = @"testcases/testdata/dump_syms_i386_breakpad.sym"; + NSString *outputBreakpadSymbolFile = @"/tmp/dump_syms_i386.breakpad"; + + DumpSymbols *dump = [[DumpSymbols alloc] initWithContentsOfFile:@"testcases/testdata/dump_syms_dwarf_data"]; + + STAssertNotNil(dump, @"DumpSymbols is nil"); + [dump setArchitecture:@"i386"]; + [dump writeSymbolFile:outputBreakpadSymbolFile]; + + NSData *d = [[NSData alloc] initWithContentsOfFile:inputBreakpadSymbolFile]; + STAssertNotNil(d, @"Input breakpad symbol file not found"); + + NSData *d1 = [[NSData alloc] initWithContentsOfFile:outputBreakpadSymbolFile]; + STAssertNotNil(d1, @"Output breakpad symbol file not found"); + + STAssertTrue([d isEqualToData:d1], + @"Symbol files were not equal!",nil); +} +@end diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_dwarf_data b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_dwarf_data new file mode 100644 index 0000000000..5be17aeedc Binary files /dev/null and b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_dwarf_data differ diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym new file mode 100644 index 0000000000..bca43c1037 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym @@ -0,0 +1,5300 @@ +MODULE mac x86 94BF873C47A73BC07125291390B4C5F10 dump_syms_dwarf_data +FILE 1 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/libkern/i386/OSByteOrder.h +FILE 2 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/architecture/byte_order.h +FILE 3 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/dump_syms.mm +FILE 4 /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSRange.h +FILE 5 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/new +FILE 6 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/hash_fun.h +FILE 7 ../../../common/mac/dwarf/dwarf2reader.h +FILE 8 ../../../common/mac/file_id.h +FILE 9 ../../../common/mac/dwarf/functioninfo.h +FILE 10 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_tree.h +FILE 11 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_iterator.h +FILE 12 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/hashtable.h +FILE 13 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_pair.h +FILE 14 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h +FILE 15 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/allocator.h +FILE 16 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_vector.h +FILE 17 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h +FILE 18 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_iterator_base_funcs.h +FILE 19 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_algo.h +FILE 20 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_map.h +FILE 21 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h +FILE 22 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_function.h +FILE 23 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/hash_map +FILE 24 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/basic_string.h +FILE 25 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_algobase.h +FILE 26 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_list.h +FILE 27 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/list.tcc +FILE 28 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_uninitialized.h +FILE 29 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/vector.tcc +FILE 30 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/dwarf/functioninfo.cc +FILE 31 ../../../common/mac/dwarf/dwarf2reader.h +FILE 32 ../../../common/mac/dwarf/functioninfo.h +FILE 33 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_pair.h +FILE 34 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/hashtable.h +FILE 35 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/memory +FILE 36 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h +FILE 37 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/basic_string.h +FILE 38 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_iterator.h +FILE 39 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_vector.h +FILE 40 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_tree.h +FILE 41 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_function.h +FILE 42 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/hash_map +FILE 43 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h +FILE 44 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_algobase.h +FILE 45 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_map.h +FILE 46 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_uninitialized.h +FILE 47 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/vector.tcc +FILE 48 /g/code/breakpad-staging/src/tools/mac/dump_syms/dump_syms_tool.mm +FILE 49 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/file_id.cc +FILE 50 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/architecture/byte_order.h +FILE 51 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/macho_id.cc +FILE 52 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/libkern/i386/OSByteOrder.h +FILE 53 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/architecture/byte_order.h +FILE 54 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/macho_walker.cc +FILE 55 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/libkern/i386/OSByteOrder.h +FILE 56 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/architecture/byte_order.h +FILE 57 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/macho_utilities.cc +FILE 58 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/dwarf/bytereader.cc +FILE 59 ../../../common/mac/dwarf/bytereader-inl.h +FILE 60 /g/code/breakpad-staging/src/tools/mac/dump_syms/../../../common/mac/dwarf/dwarf2reader.cc +FILE 61 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_algobase.h +FILE 62 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_deque.h +FILE 63 ../../../common/mac/dwarf/bytereader.h +FILE 64 ../../../common/mac/dwarf/bytereader-inl.h +FILE 65 ../../../common/mac/dwarf/line_state_machine.h +FILE 66 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_list.h +FILE 67 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/memory +FILE 68 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/ext/new_allocator.h +FILE 69 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/allocator.h +FILE 70 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_pair.h +FILE 71 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_vector.h +FILE 72 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_iterator.h +FILE 73 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_construct.h +FILE 74 ../../../common/mac/dwarf/dwarf2reader.h +FILE 75 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_stack.h +FILE 76 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/deque.tcc +FILE 77 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/list.tcc +FILE 78 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/vector.tcc +FILE 79 /Developer/SDKs/MacOSX10.4u.sdk/usr/include/c++/4.0.0/bits/stl_uninitialized.h +FILE 80 /var/tmp/gcc/gcc-5484~1/src/gcc/libgcc2.c +FUNC 162a 28 0 _OSSwapInt16 +162a 10 44 55 +163a 16 46 55 +1650 2 47 55 +FUNC 1652 1c 0 _OSSwapInt32 +1652 f 53 55 +1661 8 55 55 +1669 3 56 55 +166c 2 57 55 +FUNC 166e 2b 0 _OSSwapInt64 +166e 12 64 55 +1680 11 69 55 +1691 6 70 55 +1697 2 71 55 +1699 1 71 55 +FUNC 169a 1e 0 NXSwapShort +169a 10 43 56 +16aa c 45 56 +16b6 2 46 56 +FUNC 16b8 19 0 NXSwapInt +16b8 f 52 56 +16c7 8 54 56 +16cf 2 55 56 +16d1 1 55 56 +FUNC 16d2 19 0 NXSwapLong +16d2 f 61 56 +16e1 8 63 56 +16e9 2 64 56 +16eb 1 64 56 +FUNC 16ec 1f 0 NXSwapLongLong +16ec 12 70 56 +16fe b 72 56 +1709 2 73 56 +170b 1 73 56 +FUNC 170c 181 0 -[DumpSymbols convertCPlusPlusSymbols:] +170c 14 128 3 +1720 54 130 3 +1774 f 132 3 +1783 7 133 3 +178a 1a 136 3 +17a4 5 138 3 +17a9 1a 139 3 +17c3 23 140 3 +17e6 7 141 3 +17ed 44 142 3 +1831 1e 145 3 +184f 29 138 3 +1878 b 148 3 +1883 3 150 3 +1886 7 151 3 +188d 1 151 3 +FUNC 188e 323 0 -[DumpSymbols convertSymbols] +188e 14 154 3 +18a2 1f 155 3 +18c1 3e 156 3 +18ff 2b 160 3 +192a c 162 3 +1936 43 164 3 +1979 2a 165 3 +19a3 20 168 3 +19c3 d 169 3 +19d0 1e 171 3 +19ee 11 162 3 +19ff 7 181 3 +1a06 6 182 3 +1a0c 5 184 3 +1a11 15 185 3 +1a26 6 18 4 +1a2c 6 19 4 +1a32 6 20 4 +1a38 6 185 3 +1a3e 28 186 3 +1a66 21 187 3 +1a87 1a 188 3 +1aa1 a 190 3 +1aab c 194 3 +1ab7 43 198 3 +1afa 21 199 3 +1b1b 20 202 3 +1b3b 2e 203 3 +1b69 1e 194 3 +1b87 c 184 3 +1b93 17 207 3 +1baa 7 208 3 +1bb1 1 208 3 +FUNC 1bb2 4a2 0 -[DumpSymbols addFunction:line:address:section:] +1bb2 21 211 3 +1bd3 2f 212 3 +1c02 e 214 3 +1c10 4 219 3 +1c14 2a 221 3 +1c3e 22 223 3 +1c60 6 224 3 +1c66 2a 225 3 +1c90 4 226 3 +1c94 2e 230 3 +1cc2 2e 233 3 +1cf0 2e 236 3 +1d1e a 239 3 +1d28 2b 253 3 +1d53 e 254 3 +1d61 3c 255 3 +1d9d 22 32 4 +1dbf 3 256 3 +1dc2 6 259 3 +1dc8 a 260 3 +1dd2 3c 261 3 +1e0e 25 262 3 +1e33 2a 263 3 +1e5d 22 265 3 +1e7f 26 270 3 +1ea5 6 272 3 +1eab 37 273 3 +1ee2 2a 274 3 +1f0c 17 275 3 +1f23 43 278 3 +1f66 2e 279 3 +1f94 23 282 3 +1fb7 43 285 3 +1ffa 52 287 3 +204c 8 289 3 +FUNC 2054 5a4 0 -[DumpSymbols processSymbolItem:stringTable:] +2054 18 292 3 +206c 8 293 3 +2074 4 294 3 +2078 16 297 3 +208e c 298 3 +209a f 300 3 +20a9 b 301 3 +20b4 16 303 3 +20ca 4d 309 3 +2117 38 311 3 +214f 30 315 3 +217f 60 317 3 +21df d 322 3 +21ec 2b 325 3 +2217 3a 327 3 +2251 f 332 3 +2260 2d 333 3 +228d 1a 334 3 +22a7 32 335 3 +22d9 20 342 3 +22f9 c 343 3 +2305 24 348 3 +2329 a 349 3 +2333 3c 350 3 +236f 2a 352 3 +2399 1c 353 3 +23b5 9 354 3 +23be f 356 3 +23cd 2d 357 3 +23fa 2f 358 3 +2429 20 360 3 +2449 c 361 3 +2455 7 363 3 +245c 21 365 3 +247d 4a 368 3 +24c7 9 370 3 +24d0 1a 371 3 +24ea 4b 372 3 +2535 4 373 3 +2539 5 371 3 +253e 29 374 3 +2567 2d 376 3 +2594 4b 378 3 +25df 4 379 3 +25e3 a 382 3 +25ed b 383 3 +FUNC 25f8 c9 0 -[DumpSymbols loadSymbolInfo:offset:] +25f8 13 391 3 +260b 2b 392 3 +2636 2a 393 3 +2660 2d 395 3 +268d 2e 398 3 +26bb 6 399 3 +26c1 1 399 3 +FUNC 26c2 2be 0 -[DumpSymbols loadSTABSSymbolInfo:offset:] +26c2 16 537 3 +26d8 9 538 3 +26e1 10 539 3 +26f1 2e 540 3 +271f 9 542 3 +2728 22 543 3 +274a 4 544 3 +274e a 546 3 +2758 3c 547 3 +2794 c 549 3 +27a0 e 550 3 +27ae 6 551 3 +27b4 25 552 3 +27d9 25 553 3 +27fe 25 554 3 +2823 c 555 3 +282f c 556 3 +283b c 559 3 +2847 23 562 3 +286a a 563 3 +2874 a 564 3 +287e 2e 565 3 +28ac 39 566 3 +28e5 2e 570 3 +2913 4 571 3 +2917 17 559 3 +292e 25 575 3 +2953 9 576 3 +295c 17 549 3 +2973 4 579 3 +2977 9 580 3 +FUNC 2980 28a 0 -[DumpSymbols loadSymbolInfo64:offset:] +2980 16 583 3 +2996 9 585 3 +299f 10 586 3 +29af 2e 587 3 +29dd 9 589 3 +29e6 22 590 3 +2a08 4 591 3 +2a0c c 593 3 +2a18 e 594 3 +2a26 6 595 3 +2a2c 25 596 3 +2a51 25 597 3 +2a76 25 598 3 +2a9b 9 599 3 +2aa4 c 600 3 +2ab0 c 603 3 +2abc 17 604 3 +2ad3 23 609 3 +2af6 a 610 3 +2b00 a 611 3 +2b0a 2e 612 3 +2b38 37 613 3 +2b6f 2e 615 3 +2b9d 4 616 3 +2ba1 17 603 3 +2bb8 25 620 3 +2bdd 9 621 3 +2be6 17 593 3 +2bfd 4 624 3 +2c01 9 625 3 +FUNC 2c0a 199 0 -[DumpSymbols loadSymbolInfoForArchitecture] +2c0a 13 628 3 +2c1d 41 630 3 +2c5e 2b 631 3 +2c89 1a 632 3 +2ca3 40 634 3 +2ce3 40 635 3 +2d23 5f 637 3 +2d82 17 639 3 +2d99 4 640 3 +2d9d 6 641 3 +2da3 1 641 3 +FUNC 2da4 3e5 0 -[DumpSymbols loadHeader:offset:] +2da4 18 728 3 +2dbc 9 729 3 +2dc5 10 730 3 +2dd5 2e 731 3 +2e03 9 733 3 +2e0c 2b 734 3 +2e37 1e 736 3 +2e55 c 738 3 +2e61 e 739 3 +2e6f 6 740 3 +2e75 50 742 3 +2ec5 2e 743 3 +2ef3 2e 744 3 +2f21 2e 745 3 +2f4f 20 746 3 +2f6f 1b7 755 3 +3126 9 757 3 +312f 25 761 3 +3154 9 762 3 +315d 17 738 3 +3174 a 765 3 +317e b 766 3 +3189 1 766 3 +FUNC 318a 41d 0 -[DumpSymbols loadHeader64:offset:] +318a 18 769 3 +31a2 9 771 3 +31ab 10 772 3 +31bb 2e 773 3 +31e9 9 775 3 +31f2 c 777 3 +31fe 2b 778 3 +3229 e 779 3 +3237 6 780 3 +323d 50 781 3 +328d 49 782 3 +32d6 49 783 3 +331f 2e 784 3 +334d 9 785 3 +3356 29 786 3 +337f 1c5 794 3 +3544 9 795 3 +354d 25 799 3 +3572 9 800 3 +357b 17 777 3 +3592 a 803 3 +359c b 804 3 +35a7 1 804 3 +FUNC 35a8 52a 0 -[DumpSymbols loadModuleInfo] +35a8 14 807 3 +35bc e 808 3 +35ca 41 810 3 +360b 1a 811 3 +3625 6 812 3 +362b 6 814 3 +3631 17 815 3 +3648 c 816 3 +3654 29 820 3 +367d 29 821 3 +36a6 29 822 3 +36cf 35 824 3 +3704 12 826 3 +3716 17 827 3 +372d c 828 3 +3739 3c 832 3 +3775 a 834 3 +377f 9 836 3 +3788 25 837 3 +37ad c 839 3 +37b9 54 840 3 +380d 57 841 3 +3864 57 842 3 +38bb 57 843 3 +3912 57 844 3 +3969 1c 846 3 +3985 4b 847 3 +39d0 49 849 3 +3a19 13 839 3 +3a2c 6 851 3 +3a32 3c 852 3 +3a6e 3a 854 3 +3aa8 17 857 3 +3abf c 858 3 +3acb 7 859 3 +FUNC 3ad2 b6 0 WriteFormat +3ad2 10 862 3 +3ae2 6 867 3 +3ae8 24 868 3 +3b0c 27 869 3 +3b33 40 870 3 +3b73 c 873 3 +3b7f 9 874 3 +FUNC 3b88 35 0 -[DumpSymbols availableArchitectures] +3b88 13 1140 3 +3b9b 1c 1141 3 +3bb7 6 1142 3 +3bbd 1 1142 3 +FUNC 3bbe 1b4 0 -[DumpSymbols setArchitecture:] +3bbe 13 1158 3 +3bd1 1a 1159 3 +3beb 4 1160 3 +3bef 2a 1162 3 +3c19 9 1163 3 +3c22 2a 1165 3 +3c4c 9 1166 3 +3c55 9 1167 3 +3c5e 2a 1169 3 +3c88 6 1170 3 +3c8e 2a 1172 3 +3cb8 6 1173 3 +3cbe 2a 1175 3 +3ce8 4 1176 3 +3cec 6 1179 3 +3cf2 2c 1180 3 +3d1e 9 1181 3 +3d27 1c 1183 3 +3d43 1f 1184 3 +3d62 a 1187 3 +3d6c 6 1188 3 +FUNC 3d72 14 0 -[DumpSymbols architecture] +3d72 c 1191 3 +3d7e 6 1192 3 +3d84 2 1193 3 +FUNC 3d86 e7 0 -[DumpSymbols writeSymbolFile:] +3d86 13 1196 3 +3d99 1a 1197 3 +3db3 48 1200 3 +3dfb 9 1201 3 +3e04 1e 1203 3 +3e22 6 1205 3 +3e28 9 1206 3 +3e31 21 1208 3 +3e52 b 1210 3 +3e5d a 1212 3 +3e67 6 1213 3 +3e6d 1 1213 3 +FUNC 3e6e 65 0 -[MachSection initWithMachSection:andNumber:] +3e6e 13 1219 3 +3e81 37 1220 3 +3eb8 9 1221 3 +3ec1 9 1222 3 +3eca 3 1225 3 +3ecd 6 1226 3 +3ed3 1 1226 3 +FUNC 3ed4 14 0 -[MachSection sectionPointer] +3ed4 c 1228 3 +3ee0 6 1229 3 +3ee6 2 1230 3 +FUNC 3ee8 14 0 -[MachSection sectionNumber] +3ee8 c 1232 3 +3ef4 6 1233 3 +3efa 2 1234 3 +FUNC 3efc 17c 0 -[DumpSymbols processDWARFSourceFileInfo:] +3efc 14 459 3 +3f10 a 460 3 +3f1a 3c 461 3 +3f56 20 463 3 +3f76 5 464 3 +3f7b 3a 465 3 +3fb5 1d 466 3 +3fd2 3a 467 3 +400c 2a 468 3 +4036 3b 464 3 +4071 7 471 3 +FUNC 4078 1d7 0 DumpFunctionMap(std::map, std::allocator > >) +4078 15 82 3 +408d 13 83 3 +40a0 1e 85 3 +40be 42 89 3 +4100 20 90 3 +4120 2b 91 3 +414b 1a 92 3 +4165 23 93 3 +4188 46 96 3 +41ce 46 99 3 +4214 33 83 3 +4247 8 102 3 +424f 1 102 3 +FUNC 4250 3ef 0 -[DumpSymbols processDWARFFunctionInfo:] +4250 15 473 3 +4265 25 474 3 +428a 1e 476 3 +42a8 a 480 3 +42b2 3c 481 3 +42ee 3d 483 3 +432b 23 485 3 +434e 26 487 3 +4374 6 489 3 +437a 37 490 3 +43b1 2a 491 3 +43db 17 492 3 +43f2 30 496 3 +4422 3d 497 3 +445f 2e 498 3 +448d 30 502 3 +44bd 64 504 3 +4521 34 507 3 +4555 9d 509 3 +45f2 45 474 3 +4637 8 513 3 +463f 1 513 3 +FUNC 4640 1f5 0 -[DumpSymbols processDWARFLineNumberInfo:] +4640 15 515 3 +4655 25 516 3 +467a 39 520 3 +46b3 26 521 3 +46d9 6 523 3 +46df 37 524 3 +4716 2a 525 3 +4740 17 526 3 +4757 30 529 3 +4787 61 531 3 +47e8 45 516 3 +482d 8 534 3 +4835 1 534 3 +FUNC 4836 10f 0 -[DumpSymbols dealloc] +4836 13 1145 3 +4849 1c 1146 3 +4865 1c 1147 3 +4881 1c 1148 3 +489d 1c 1149 3 +48b9 1c 1150 3 +48d5 1c 1151 3 +48f1 25 1152 3 +4916 29 1154 3 +493f 6 1155 3 +4945 1 1155 3 +FUNC 4946 512 0 -[DumpSymbols loadDWARFSymbolInfo:offset:] +4946 17 402 3 +495d 9 405 3 +4966 10 406 3 +4976 2b 408 3 +49a1 38 409 3 +49d9 3a 410 3 +4a13 2e 411 3 +4a41 31 416 3 +4a72 e 418 3 +4a80 24 420 3 +4aa4 5 422 3 +4aa9 b 424 3 +4ab4 b 425 3 +4abf e 426 3 +4acd 2b 427 3 +4af8 2b 428 3 +4b23 2c 431 3 +4b4f 52 439 3 +4ba1 34 444 3 +4bd5 1a 446 3 +4bef 21 451 3 +4c10 1e 452 3 +4c2e 21 453 3 +4c4f 40 422 3 +4c8f 6 453 3 +4c95 170 422 3 +4e05 43 456 3 +4e48 10 457 3 +FUNC 4e58 4fd 0 -[DumpSymbols generateSectionDictionary:] +4e58 18 663 3 +4e70 10 665 3 +4e80 2e 666 3 +4eae 9 668 3 +4eb7 2b 669 3 +4ee2 7 670 3 +4ee9 2e 672 3 +4f17 d 676 3 +4f24 32 678 3 +4f56 29 680 3 +4f7f a 684 3 +4f89 3c 685 3 +4fc5 31 688 3 +4ff6 5d 689 3 +5053 26 692 3 +5079 21 694 3 +509a c 698 3 +50a6 e 699 3 +50b4 6 700 3 +50ba 9 701 3 +50c3 2e 702 3 +50f1 c 704 3 +50fd 3c 706 3 +5139 66 709 3 +519f 1c 712 3 +51bb fb 714 3 +52b6 6 717 3 +52bc 5 718 3 +52c1 19 704 3 +52da 25 714 3 +52ff 2e 722 3 +532d 9 723 3 +5336 17 698 3 +534d 8 725 3 +5355 1 725 3 +FUNC 5356 24a 0 -[DumpSymbols getSectionMapForArchitecture:] +5356 14 643 3 +536a 43 645 3 +53ad 1a 648 3 +53c7 1c 645 3 +53e3 18 648 3 +53fb 40 650 3 +543b 20 651 3 +545b 17 652 3 +5472 16 651 3 +5488 cb 652 3 +5553 11 654 3 +5564 32 657 3 +5596 a 658 3 +FUNC 55a0 3fe 0 -[DumpSymbols initWithContentsOfFile:] +55a0 14 1056 3 +55b4 3b 1057 3 +55ef 44 1059 3 +5633 17 1060 3 +564a c 1061 3 +5656 1f 1064 3 +5675 2b 1067 3 +56a0 a 1069 3 +56aa 35 1083 3 +56df 2 1087 3 +56e1 1a 1088 3 +56fb 3d 1087 3 +5738 33 1092 3 +576b 6 1094 3 +5771 e 1095 3 +577f 17 1096 3 +5796 c 1097 3 +57a2 1c 1101 3 +57be 1f 1103 3 +57dd 18 1104 3 +57f5 23 1107 3 +5818 25 1109 3 +583d 1c 1107 3 +5859 17 1110 3 +5870 c 1111 3 +587c 2a 1115 3 +58a6 8 1116 3 +58ae a 1118 3 +58b8 9 1119 3 +58c1 d 1122 3 +58ce 29 1124 3 +58f7 20 1126 3 +5917 20 1128 3 +5937 57 1132 3 +598e 9 1136 3 +5997 7 1137 3 +FUNC 599e d74 0 -[DumpSymbols outputSymbolFile:] +599e 18 877 3 +59b6 2e 879 3 +59e4 30 880 3 +5a14 5d 882 3 +5a71 30 883 3 +5aa1 5d 885 3 +5afe 2e 888 3 +5b2c 38 891 3 +5b64 46 892 3 +5baa 26 893 3 +5bd0 20 895 3 +5bf0 20 904 3 +5c10 30 898 3 +5c40 f 899 3 +5c4f 1e 904 3 +5c6d 17 907 3 +5c84 17 908 3 +5c9b 44 911 3 +5cdf 44 914 3 +5d23 a 917 3 +5d2d 36 921 3 +5d63 30 923 3 +5d93 9 18 4 +5d9c 9 19 4 +5da5 c 20 4 +5db1 56 923 3 +5e07 74 925 3 +5e7b f 927 3 +5e8a 44 932 3 +5ece 20 933 3 +5eee c 934 3 +5efa 4e 935 3 +5f48 41 936 3 +5f89 f 937 3 +5f98 14 934 3 +5fac 7 941 3 +5fb3 14 942 3 +5fc7 14 943 3 +5fdb 1d 946 3 +5ff8 c 948 3 +6004 24 949 3 +6028 29 950 3 +6051 9 953 3 +605a 28 954 3 +6082 2e 955 3 +60b0 1e 957 3 +60ce 7 959 3 +60d5 26 962 3 +60fb 2a 963 3 +6125 2a 964 3 +614f 6 966 3 +6155 2a 967 3 +617f e 971 3 +618d 43 972 3 +61d0 4c 974 3 +621c 8 975 3 +6224 2e 979 3 +6252 2e 982 3 +6280 2e 985 3 +62ae 2e 988 3 +62dc 2e 991 3 +630a 2e 994 3 +6338 2e 997 3 +6366 2e 1000 3 +6394 54 1004 3 +63e8 c 1005 3 +63f4 e 1007 3 +6402 27 1008 3 +6429 8 1009 3 +6431 34 1010 3 +6465 24 1012 3 +6489 2 1013 3 +648b 2a 1017 3 +64b5 a 1019 3 +64bf 14 1020 3 +64d3 1d 1021 3 +64f0 a 1025 3 +64fa 32 1026 3 +652c 33 1028 3 +655f c 1029 3 +656b 55 1034 3 +65c0 f 1036 3 +65cf 16 1040 3 +65e5 61 1041 3 +6646 f 1043 3 +6655 47 1046 3 +669c c 1048 3 +66a8 11 948 3 +66b9 4e 1052 3 +6707 b 1053 3 +FUNC 6712 11 0 operator new(unsigned long, void*) +6712 c 94 5 +671e 5 94 5 +6723 1 94 5 +FUNC 6724 e 0 operator delete(void*, void*) +6724 c 98 5 +6730 2 98 5 +673e 7 76 6 +6745 2 77 6 +6747 1a 78 6 +6761 d 77 6 +676e 3 79 6 +6771 2 80 6 +6773 1 80 6 +6780 d 95 6 +678d 1 95 6 +678e 13 127 74 +67a1 2a 127 74 +67cb 1 127 74 +67cc 13 127 74 +67df 2a 127 74 +6809 1 127 74 +680a 13 127 74 +681d 2a 127 74 +6847 1 127 74 +FUNC 6848 e 0 dwarf2reader::LineInfoHandler::DefineDir(std::string const&, unsigned int) +6848 c 131 7 +6854 2 131 74 +FUNC 6856 26 0 dwarf2reader::LineInfoHandler::DefineFile(std::string const&, int, unsigned int, unsigned long long, unsigned long long) +6856 24 142 7 +687a 2 142 74 +FUNC 687c 1a 0 dwarf2reader::LineInfoHandler::AddLine(unsigned long long, unsigned int, unsigned int, unsigned int) +687c 18 150 7 +6894 2 150 74 +6896 12 299 74 +68a8 12 299 74 +68ba 13 301 74 +68cd 2a 301 74 +68f7 1 301 74 +68f8 13 301 74 +690b 2a 301 74 +6935 1 301 74 +6936 13 301 74 +6949 2a 301 74 +6973 1 301 74 +FUNC 6974 44 0 dwarf2reader::Dwarf2Handler::StartCompilationUnit(unsigned long long, unsigned char, unsigned char, unsigned long long, unsigned char) +6974 39 308 7 +69ad b 308 74 +FUNC 69b8 1f 0 dwarf2reader::Dwarf2Handler::StartDIE(unsigned long long, dwarf2reader::DwarfTag, std::list, std::allocator > > const&) +69b8 18 314 7 +69d0 7 314 74 +69d7 1 314 74 +FUNC 69d8 26 0 dwarf2reader::Dwarf2Handler::ProcessAttributeUnsigned(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, unsigned long long) +69d8 24 323 7 +69fc 2 323 74 +FUNC 69fe 26 0 dwarf2reader::Dwarf2Handler::ProcessAttributeSigned(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, long long) +69fe 24 332 7 +6a22 2 332 74 +FUNC 6a24 26 0 dwarf2reader::Dwarf2Handler::ProcessAttributeBuffer(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, char const*, unsigned long long) +6a24 24 345 7 +6a48 2 345 74 +FUNC 6a4a 1a 0 dwarf2reader::Dwarf2Handler::ProcessAttributeString(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, std::string const&) +6a4a 18 354 7 +6a62 2 354 74 +FUNC 6a64 1a 0 dwarf2reader::Dwarf2Handler::EndDIE(unsigned long long) +6a64 18 360 7 +6a7c 2 360 74 +6a7e c 44 8 +6a8a 2 44 8 +6a8c 13 55 32 +6a9f 35 55 32 +6ad4 13 91 32 +6ae7 73 96 32 +6b5a 13 98 32 +6b6d 35 98 32 +6bae 1a 75 3 +6bc8 2 76 3 +FUNC 6bca 20 0 std::_Rb_tree_const_iterator >::operator!=(std::_Rb_tree_const_iterator > const&) const +6bca c 287 10 +6bd6 14 288 40 +FUNC 6bea 16 0 std::_Rb_tree_const_iterator >::operator->() const +6bea c 249 10 +6bf6 a 250 40 +6c0c 7 614 72 +6c13 1 614 72 +6c14 c 241 40 +6c20 c 242 40 +FUNC 6c2c 16 0 std::_Rb_tree_const_iterator >::operator*() const +6c2c c 245 11 +6c38 a 246 40 +6c42 c 241 40 +6c4e c 242 40 +FUNC 6c5a 20 0 std::_Rb_tree_const_iterator > >::operator!=(std::_Rb_tree_const_iterator > > const&) const +6c5a c 287 11 +6c66 14 288 40 +FUNC 6c7a 16 0 std::_Rb_tree_const_iterator > >::operator->() const +6c7a c 249 11 +6c86 a 250 40 +6c90 c 185 34 +6c9c 18 186 34 +6cc0 14 204 34 +6cd4 c 69 70 +6ce0 d 69 70 +6ced 1 69 70 +6cee c 89 70 +6cfa 20 90 70 +6d1a c 69 70 +6d26 d 69 70 +6d33 1 69 70 +6d34 c 69 70 +6d40 d 69 70 +6d4d 1 69 70 +FUNC 6d4e 25 0 std::_Rb_tree_const_iterator >::operator++() +6d4e c 253 13 +6d5a 14 255 40 +6d6e 5 256 40 +6d73 1 256 40 +FUNC 6d74 25 0 std::_Rb_tree_const_iterator > >::operator++() +6d74 c 253 13 +6d80 14 255 40 +6d94 5 256 40 +6d99 1 256 40 +FUNC 6d9a 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_begin() +6d9a c 461 13 +6da6 8 462 40 +FUNC 6dae 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_begin() +6dae c 461 13 +6dba 8 462 40 +6dc2 c 65 68 +6dce 2 65 68 +6dd0 c 72 68 +6ddc 2 72 68 +6dde c 97 69 +6dea d 97 69 +6df7 1 97 69 +6df8 c 105 69 +6e04 d 105 69 +6e11 1 105 69 +6e12 c 105 69 +6e1e d 105 69 +6e2b 1 105 69 +6e2c c 67 68 +6e38 2 67 68 +6e3a c 99 69 +6e46 14 100 69 +6e5a c 99 69 +6e66 14 100 69 +FUNC 6e7a 2b 0 std::_Vector_base >::get_allocator() const +6e7a 10 93 16 +6e8a 1b 94 71 +6ea5 1 94 71 +6ea6 c 65 68 +6eb2 2 65 68 +6eb4 c 72 68 +6ec0 2 72 68 +6ec2 c 97 69 +6ece d 97 69 +6edb 1 97 69 +6edc c 105 69 +6ee8 d 105 69 +6ef5 1 105 69 +6ef6 c 105 69 +6f02 d 105 69 +6f0f 1 105 69 +6f10 c 67 68 +6f1c 2 67 68 +6f1e c 99 69 +6f2a 14 100 69 +6f3e c 99 69 +6f4a 14 100 69 +FUNC 6f5e 2b 0 std::_Vector_base >::get_allocator() const +6f5e 10 93 16 +6f6e 1b 94 71 +6f89 1 94 71 +6f8a c 603 72 +6f96 c 603 72 +FUNC 6fa2 23 0 std::vector >::begin() +6fa2 c 333 16 +6fae 17 334 71 +6fc5 1 334 71 +FUNC 6fc6 26 0 std::vector >::end() +6fc6 c 351 16 +6fd2 1a 352 71 +6ff8 5 666 72 +6ffd 1 666 72 +6ffe c 608 72 +700a 14 609 72 +702a 5 666 72 +702f 1 666 72 +FUNC 7030 35 0 bool __gnu_cxx::operator!= > >(__gnu_cxx::__normal_iterator > > const&, __gnu_cxx::__normal_iterator > > const&) +7030 d 693 16 +703d 28 694 72 +7065 1 694 72 +7066 c 603 72 +7072 c 603 72 +708a 27 629 72 +70b1 1 629 72 +70b2 c 84 70 +70be 1f 85 70 +70dd 1 85 70 +FUNC 70de 32 0 std::pair, __gnu_cxx::hash, std::equal_to, std::allocator > >*> std::make_pair, __gnu_cxx::hash, std::equal_to, std::allocator > >*>(std::string, __gnu_cxx::hash_map, __gnu_cxx::hash, std::equal_to, std::allocator > >*) +70de 10 144 16 +70ee 22 145 70 +711c a 190 34 +7132 d 194 34 +713f 1 194 34 +7140 c 84 70 +714c 17 85 70 +7163 1 85 70 +FUNC 7164 2d 0 std::pair std::make_pair(char const*, unsigned long) +7164 c 144 16 +7170 21 145 70 +7191 1 145 70 +7192 c 84 70 +719e 1d 85 70 +71bb 1 85 70 +FUNC 71bc 30 0 std::pair > std::make_pair >(char*, std::pair) +71bc 10 144 16 +71cc 20 145 70 +71ec c 89 70 +71f8 20 90 70 +7218 d 89 70 +7225 70 90 70 +7295 1 90 70 +FUNC 7296 12 0 std::iterator_traits::iterator_category std::__iterator_category(unsigned long const* const&) +7296 c 164 17 +72a2 6 165 17 +FUNC 72a8 1d 0 std::iterator_traits::difference_type std::__distance(unsigned long const*, unsigned long const*, std::random_access_iterator_tag) +72a8 c 92 18 +72b4 11 97 18 +72c5 1 97 18 +FUNC 72c6 33 0 std::iterator_traits::difference_type std::distance(unsigned long const*, unsigned long const*) +72c6 c 114 18 +72d2 27 118 18 +72f9 1 118 18 +FUNC 72fa 20 0 void std::__advance(unsigned long const*&, int, std::random_access_iterator_tag) +72fa c 150 18 +7306 14 155 18 +FUNC 731a 33 0 void std::advance(unsigned long const*&, int) +731a c 172 18 +7326 27 175 18 +734d 1 175 18 +FUNC 734e 7a 0 unsigned long const* std::lower_bound(unsigned long const*, unsigned long const*, unsigned long const&) +734e c 2625 19 +735a 15 2642 19 +736f 2 2646 19 +7371 8 2648 19 +7379 6 2649 19 +737f 12 2650 19 +7391 e 2651 19 +739f 6 2653 19 +73a5 4 2654 19 +73a9 e 2655 19 +73b7 6 2658 19 +73bd 6 2646 19 +73c3 5 2660 19 +73db b 227 34 +73e6 e 228 34 +73f4 1c 229 34 +7410 20 230 34 +7430 6 231 34 +7436 c 72 68 +7442 2 72 68 +7444 c 105 69 +7450 d 105 69 +745d 1 105 69 +745e c 105 69 +746a d 105 69 +7477 1 105 69 +7478 c 80 71 +7484 d 80 71 +7491 1 80 71 +7492 c 67 68 +749e 2 67 68 +74a0 c 99 69 +74ac 14 100 69 +FUNC 74c0 2b 0 std::_Vector_base >::get_allocator() const +74c0 10 93 19 +74d0 1b 94 71 +74eb 1 94 71 +74ec c 238 40 +74f8 a 239 40 +FUNC 7502 26 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::begin() const +7502 c 585 19 +750e 1a 588 40 +FUNC 7528 19 0 std::map, std::allocator > >::begin() const +7528 c 243 20 +7534 d 244 45 +7541 1 244 45 +FUNC 7542 26 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::end() const +7542 c 596 20 +754e 1a 597 40 +FUNC 7568 19 0 std::map, std::allocator > >::end() const +7568 c 260 20 +7574 d 261 45 +7581 1 261 45 +7582 c 65 68 +758e 2 65 68 +7590 c 72 68 +759c 2 72 68 +759e c 97 69 +75aa d 97 69 +75b7 1 97 69 +75b8 c 105 69 +75c4 d 105 69 +75d1 1 105 69 +75d2 c 72 68 +75de 2 72 68 +75e0 c 105 69 +75ec d 105 69 +75f9 1 105 69 +75fa c 397 40 +7606 d 397 40 +7613 1 397 40 +7614 c 105 69 +7620 d 105 69 +762d 1 105 69 +FUNC 762e 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_right(std::_Rb_tree_node_base*) +762e c 496 20 +763a 8 497 40 +FUNC 7642 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_left(std::_Rb_tree_node_base*) +7642 c 488 20 +764e 8 489 40 +7656 c 65 68 +7662 2 65 68 +7664 c 72 68 +7670 2 72 68 +7672 c 97 69 +767e d 97 69 +768b 1 97 69 +768c c 105 69 +7698 d 105 69 +76a5 1 105 69 +76a6 c 72 68 +76b2 2 72 68 +76b4 c 105 69 +76c0 d 105 69 +76cd 1 105 69 +76ce c 397 40 +76da d 397 40 +76e7 1 397 40 +76e8 c 105 69 +76f4 d 105 69 +7701 1 105 69 +FUNC 7702 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_right(std::_Rb_tree_node_base*) +7702 c 496 20 +770e 8 497 40 +FUNC 7716 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_left(std::_Rb_tree_node_base*) +7716 c 488 20 +7722 8 489 40 +772a c 84 71 +7736 2f 85 71 +7765 2 86 71 +7767 1 86 71 +7768 c 80 71 +7774 d 80 71 +7781 1 80 71 +7782 c 96 71 +778e 12 97 71 +77a0 2 98 71 +77a2 c 84 71 +77ae 2f 85 71 +77dd 2 86 71 +77df 1 86 71 +77e0 c 80 71 +77ec d 80 71 +77f9 1 80 71 +77fa c 96 71 +7806 12 97 71 +7818 2 98 71 +7826 d 107 68 +7833 1 107 68 +FUNC 7834 2e 0 void std::_Destroy >(std::string*, std::string*, std::allocator) +7834 c 171 21 +7840 2 173 73 +7842 12 174 73 +7854 c 173 73 +7860 2 174 73 +7862 c 167 40 +786e a 168 40 +FUNC 7878 26 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::begin() +7878 c 581 21 +7884 1a 582 40 +FUNC 789e 19 0 std::map, std::allocator > >::begin() +789e c 234 21 +78aa d 235 45 +78b7 1 235 45 +FUNC 78b8 26 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::end() +78b8 c 592 21 +78c4 1a 593 40 +FUNC 78de 19 0 std::map, std::allocator > >::end() +78de c 251 21 +78ea d 252 45 +78f7 1 252 45 +78f8 c 167 40 +7904 a 168 40 +FUNC 790e 26 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::begin() +790e c 581 21 +791a 1a 582 40 +FUNC 7934 19 0 std::map, std::less, std::allocator > > >::begin() +7934 c 234 21 +7940 d 235 45 +794d 1 235 45 +FUNC 794e 26 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::end() +794e c 592 21 +795a 1a 593 40 +FUNC 7974 19 0 std::map, std::less, std::allocator > > >::end() +7974 c 251 21 +7980 d 252 45 +798d 1 252 45 +FUNC 798e 11 0 std::_Select1st, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >::operator()(std::pair, __gnu_cxx::hash, std::equal_to, std::allocator > >*>&) const +798e c 546 22 +799a 5 547 41 +799f 1 547 41 +79a0 c 128 34 +79ac 13 129 34 +79bf 1 129 34 +79cc 22 396 34 +79fa d 199 42 +7a07 1 199 42 +7a08 c 65 68 +7a14 2 65 68 +7a16 c 72 68 +7a22 2 72 68 +7a24 c 97 69 +7a30 d 97 69 +7a3d 1 97 69 +7a3e c 105 69 +7a4a d 105 69 +7a57 1 105 69 +7a58 c 65 68 +7a64 2 65 68 +7a66 c 72 68 +7a72 2 72 68 +7a74 c 105 69 +7a80 d 105 69 +7a8d 1 105 69 +7a8e c 97 69 +7a9a d 97 69 +7aa7 1 97 69 +7aa8 c 72 68 +7ab4 2 72 68 +7ab6 c 105 69 +7ac2 d 105 69 +7acf 1 105 69 +7adc d 94 68 +7ae9 1 94 68 +FUNC 7aea 2f 0 std::_Vector_base >::_M_deallocate(dwarf2reader::CompilationUnit::Abbrev*, unsigned long) +7aea c 120 23 +7af6 6 122 71 +7afc 1d 123 71 +7b19 1 123 71 +7b1a c 108 71 +7b26 43 109 71 +7b69 1 109 71 +7b6a c 65 68 +7b76 2 65 68 +7b78 c 103 69 +7b84 d 103 69 +7b91 1 103 69 +7b92 c 65 68 +7b9e 2 65 68 +7ba0 c 103 69 +7bac d 103 69 +7bb9 1 103 69 +7bc6 d 94 68 +7bd3 1 94 68 +FUNC 7bd4 2f 0 std::_Vector_base >::_M_deallocate(dwarf2reader::SourceFileInfo*, unsigned long) +7bd4 c 120 23 +7be0 6 122 71 +7be6 1d 123 71 +7c03 1 123 71 +7c04 c 108 71 +7c10 43 109 71 +7c53 1 109 71 +7c54 c 188 71 +7c60 12 189 71 +7c72 2 190 71 +7c74 c 35 32 +7c80 d 35 32 +7c8d 1 35 32 +7c9a d 107 68 +7ca7 1 107 68 +FUNC 7ca8 2e 0 void std::_Destroy >(dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo*, std::allocator) +7ca8 c 171 23 +7cb4 2 173 73 +7cb6 12 174 73 +7cc8 c 173 73 +7cd4 2 174 73 +7cd6 d 272 71 +7ce3 8c 273 71 +7d6f 1 273 71 +7d7c d 94 68 +7d89 1 94 68 +FUNC 7d8a 2f 0 std::_Vector_base >::_M_deallocate(std::string*, unsigned long) +7d8a c 120 23 +7d96 6 122 71 +7d9c 1d 123 71 +7db9 1 123 71 +7dba c 108 71 +7dc6 3d 109 71 +7e03 1 109 71 +7e04 c 188 71 +7e10 12 189 71 +7e22 2 190 71 +7e24 d 272 71 +7e31 8c 273 71 +7ebd 1 273 71 +7eca 2b 596 34 +7ef5 1 596 34 +7f02 7 614 72 +7f09 1 614 72 +7f0a c 65 68 +7f16 2 65 68 +7f18 c 72 68 +7f24 2 72 68 +7f26 c 103 69 +7f32 d 103 69 +7f3f 1 103 69 +7f40 c 105 69 +7f4c d 105 69 +7f59 1 105 69 +7f5a c 65 68 +7f66 2 65 68 +7f68 c 72 68 +7f74 2 72 68 +7f76 c 103 69 +7f82 d 103 69 +7f8f 1 103 69 +7f90 c 105 69 +7f9c d 105 69 +7fa9 1 105 69 +7faa c 105 69 +7fb6 d 105 69 +7fc3 1 105 69 +7fd0 d 575 34 +7fdd 1 575 34 +7fea d 575 34 +7ff7 1 575 34 +FUNC 7ff8 11 0 std::_Select1st, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >::operator()(std::pair, __gnu_cxx::hash, std::equal_to, std::allocator > >*> const&) const +7ff8 c 550 23 +8004 5 551 41 +8009 1 551 41 +8016 2f 600 34 +8045 1 600 34 +8046 c 84 70 +8052 1e 85 70 +FUNC 8070 11 0 std::_Select1st > >::operator()(std::pair >&) const +8070 c 546 23 +807c 5 547 41 +8081 1 547 41 +FUNC 8082 11 0 std::_Select1st > >::operator()(std::pair > const&) const +8082 c 550 23 +808e 5 551 41 +8093 1 551 41 +8094 c 128 34 +80a0 13 129 34 +80b3 1 129 34 +80b4 c 84 70 +80c0 1e 85 70 +80de c 65 68 +80ea 2 65 68 +80ec c 103 69 +80f8 d 103 69 +8105 1 103 69 +8106 c 65 68 +8112 2 65 68 +8114 c 72 68 +8120 2 72 68 +8122 c 105 69 +812e d 105 69 +813b 1 105 69 +813c c 103 69 +8148 d 103 69 +8155 1 103 69 +8156 c 105 69 +8162 d 105 69 +816f 1 105 69 +8170 c 80 71 +817c d 80 71 +8189 1 80 71 +818a c 67 68 +8196 2 67 68 +8198 c 99 69 +81a4 14 100 69 +FUNC 81b8 2b 0 std::_Vector_base<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::get_allocator() const +81b8 10 93 23 +81c8 1b 94 71 +81e3 1 94 71 +81e4 c 99 69 +81f0 14 100 69 +8210 2 107 68 +FUNC 8212 2e 0 void std::_Destroy<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>) +8212 c 171 23 +821e 2 173 73 +8220 12 174 73 +8232 c 173 73 +823e 2 174 73 +824c d 107 68 +8259 1 107 68 +825a c 67 68 +8266 2 67 68 +8268 c 99 69 +8274 14 100 69 +8288 c 403 40 +8294 1c 404 40 +82b0 a 406 40 +82ba a 407 40 +82c4 c 408 40 +82d0 e 409 40 +82de c 553 40 +82ea 36 554 40 +8320 2 555 40 +8322 c 103 69 +832e d 103 69 +833b 1 103 69 +FUNC 833c 2b 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::get_allocator() const +833c 10 350 23 +834c 1b 351 40 +8367 1 351 40 +8368 c 69 70 +8374 2 69 70 +8382 d 107 68 +838f 1 107 68 +839c d 94 68 +83a9 1 94 68 +FUNC 83aa 2a 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_put_node(std::_Rb_tree_node >*) +83aa c 359 23 +83b6 1e 360 40 +FUNC 83d4 59 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::destroy_node(std::_Rb_tree_node >*) +83d4 d 387 23 +83e1 35 389 40 +8416 17 390 40 +842d 1 390 40 +FUNC 842e 56 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_erase(std::_Rb_tree_node >*) +842e c 1051 23 +843a 2 1054 40 +843c 1a 1056 40 +8456 e 1057 40 +8464 12 1058 40 +8476 6 1059 40 +847c 6 1054 40 +8482 2 1059 40 +8484 d 569 40 +8491 58 570 40 +84e9 1 570 40 +84ea c 147 45 +84f6 31 148 45 +8527 1 148 45 +8528 c 92 45 +8534 d 92 45 +8541 1 92 45 +8542 c 67 68 +854e 2 67 68 +8550 c 99 69 +855c 14 100 69 +8570 c 403 40 +857c 1c 404 40 +8598 a 406 40 +85a2 a 407 40 +85ac c 408 40 +85b8 e 409 40 +85c6 c 553 40 +85d2 36 554 40 +8608 2 555 40 +860a c 103 69 +8616 d 103 69 +8623 1 103 69 +FUNC 8624 2b 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::get_allocator() const +8624 10 350 23 +8634 1b 351 40 +864f 1 351 40 +8650 c 69 70 +865c d 69 70 +8669 1 69 70 +866a c 69 70 +8676 30 69 70 +86b2 d 107 68 +86bf 1 107 68 +86cc d 94 68 +86d9 1 94 68 +FUNC 86da 2a 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_put_node(std::_Rb_tree_node > >*) +86da c 359 23 +86e6 1e 360 40 +FUNC 8704 59 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::destroy_node(std::_Rb_tree_node > >*) +8704 d 387 23 +8711 35 389 40 +8746 17 390 40 +875d 1 390 40 +FUNC 875e 56 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_erase(std::_Rb_tree_node > >*) +875e c 1051 23 +876a 2 1054 40 +876c 1a 1056 40 +8786 e 1057 40 +8794 12 1058 40 +87a6 6 1059 40 +87ac 6 1054 40 +87b2 2 1059 40 +87b4 d 569 40 +87c1 58 570 40 +8819 1 570 40 +881a c 147 45 +8826 31 148 45 +8857 1 148 45 +8858 c 92 45 +8864 d 92 45 +8871 1 92 45 +8872 c 603 72 +887e c 603 72 +FUNC 888a 23 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::begin() +888a c 333 23 +8896 17 334 71 +88ad 1 334 71 +88ba 2a 654 72 +FUNC 88e4 42 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::operator[](unsigned long) +88e4 c 494 23 +88f0 36 495 71 +FUNC 8926 26 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::end() +8926 c 351 23 +8932 1a 352 71 +FUNC 894c 28 0 bool std::operator==, std::allocator >(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&) +894c c 2115 24 +8958 1c 2116 37 +FUNC 8974 23 0 std::equal_to::operator()(std::string const&, std::string const&) const +8974 c 199 24 +8980 17 200 41 +8997 1 200 41 +8998 c 80 71 +89a4 d 80 71 +89b1 1 80 71 +89b2 c 67 68 +89be 2 67 68 +89c0 c 99 69 +89cc 14 100 69 +FUNC 89e0 2b 0 std::_Vector_base<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::get_allocator() const +89e0 10 93 24 +89f0 1b 94 71 +8a0b 1 94 71 +8a0c c 99 69 +8a18 14 100 69 +8a2c c 84 71 +8a38 2f 85 71 +8a67 2 86 71 +8a69 1 86 71 +8a6a c 96 71 +8a76 12 97 71 +8a88 2 98 71 +8a96 2 107 68 +FUNC 8a98 2e 0 void std::_Destroy<__gnu_cxx::_Hashtable_node > >**, std::allocator<__gnu_cxx::_Hashtable_node > >*> >(__gnu_cxx::_Hashtable_node > >**, __gnu_cxx::_Hashtable_node > >**, std::allocator<__gnu_cxx::_Hashtable_node > >*>) +8a98 c 171 24 +8aa4 2 173 73 +8aa6 12 174 73 +8ab8 c 173 73 +8ac4 2 174 73 +FUNC 8ac6 13 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::max_size() const +8ac6 c 407 24 +8ad2 7 408 71 +8ad9 1 408 71 +8ada c 603 72 +8ae6 c 603 72 +FUNC 8af2 26 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::end() +8af2 c 351 24 +8afe 1a 352 71 +FUNC 8b18 23 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::begin() +8b18 c 333 24 +8b24 17 334 71 +8b3b 1 334 71 +8b48 2a 654 72 +8b7e 7 614 72 +8b85 1 614 72 +FUNC 8b86 42 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::operator[](unsigned long) +8b86 c 494 24 +8b92 36 495 71 +8bd4 d 107 68 +8be1 1 107 68 +FUNC 8be2 28 0 void std::swap<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**>(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**&, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**&) +8be2 c 92 25 +8bee 8 97 61 +8bf6 a 98 61 +8c00 a 99 61 +FUNC 8c0a 50 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::swap(std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >&) +8c0a c 733 25 +8c16 12 735 71 +8c28 18 736 71 +8c40 1a 737 71 +8c66 2b 596 34 +8c91 1 596 34 +8c9e 2f 600 34 +8ccd 1 600 34 +FUNC 8cce 28 0 void std::swap<__gnu_cxx::_Hashtable_node > >**>(__gnu_cxx::_Hashtable_node > >**&, __gnu_cxx::_Hashtable_node > >**&) +8cce c 92 25 +8cda 8 97 61 +8ce2 a 98 61 +8cec a 99 61 +FUNC 8cf6 50 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::swap(std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >&) +8cf6 c 733 25 +8d02 12 735 71 +8d14 18 736 71 +8d2c 1a 737 71 +8d46 c 84 71 +8d52 2f 85 71 +8d81 2 86 71 +8d83 1 86 71 +8d84 c 96 71 +8d90 12 97 71 +8da2 2 98 71 +FUNC 8da4 13 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::max_size() const +8da4 c 407 25 +8db0 7 408 71 +8db7 1 408 71 +8dc4 d 94 68 +8dd1 1 94 68 +FUNC 8dd2 2f 0 std::_Vector_base<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::_M_deallocate(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long) +8dd2 c 120 25 +8dde 6 122 71 +8de4 1d 123 71 +8e01 1 123 71 +8e02 c 108 71 +8e0e 3d 109 71 +8e4b 1 109 71 +8e4c c 272 71 +8e58 4b 273 71 +8ea3 1 273 71 +8ea4 c 188 71 +8eb0 12 189 71 +8ec2 2 190 71 +8ec4 c 603 72 +8ed0 c 603 72 +FUNC 8edc 2b 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::begin() const +8edc c 342 25 +8ee8 1f 343 71 +8f07 1 343 71 +FUNC 8f08 2c 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::end() const +8f08 c 360 25 +8f14 20 361 71 +8f40 5 666 72 +8f45 1 666 72 +8f53 2b 759 72 +FUNC 8f7e 3c 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::size() const +8f7e c 402 25 +8f8a 30 403 71 +8fc6 26 588 34 +8ff8 15 511 34 +900d 79 513 34 +9086 21 517 34 +90a7 1 517 34 +90b4 14 225 42 +90d4 26 592 34 +FUNC 90fa 49 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::capacity() const +90fa c 449 25 +9106 3d 451 71 +9143 1 451 71 +9144 c 103 69 +9150 d 103 69 +915d 1 103 69 +916e 1b 286 34 +9189 1 286 34 +9196 d 94 68 +91a3 1 94 68 +91b0 1e 301 34 +91db 56 622 34 +9231 17 623 34 +9254 9 1080 34 +925d 1a 1082 34 +9277 2 1083 34 +9279 8 1085 34 +9281 12 1086 34 +9293 6 1087 34 +9299 6 1083 34 +929f 1b 1089 34 +92ba 1d 1080 34 +92d7 c 1091 34 +92e3 1 1091 34 +92e4 d 360 34 +92f1 77 361 34 +9368 c 93 42 +9374 d 93 42 +9381 1 93 42 +9382 c 72 68 +938e 2 72 68 +9390 c 105 69 +939c d 105 69 +93a9 1 105 69 +93aa c 301 66 +93b6 d 301 66 +93c3 1 301 66 +93d0 d 94 68 +93dd 1 94 68 +FUNC 93de 2f 0 std::_Vector_base<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::_M_deallocate(__gnu_cxx::_Hashtable_node > >**, unsigned long) +93de c 120 26 +93ea 6 122 71 +93f0 1d 123 71 +940d 1 123 71 +940e c 108 71 +941a 3d 109 71 +9457 1 109 71 +9458 c 188 71 +9464 12 189 71 +9476 2 190 71 +9478 c 272 71 +9484 4b 273 71 +94cf 1 273 71 +94d0 c 603 72 +94dc c 603 72 +FUNC 94e8 2b 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::begin() const +94e8 c 342 26 +94f4 1f 343 71 +9513 1 343 71 +FUNC 9514 2c 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::end() const +9514 c 360 26 +9520 20 361 71 +954c 2d 662 72 +9579 1 662 72 +FUNC 957a 2d 0 unsigned long const& std::max(unsigned long const&, unsigned long const&) +957a c 206 26 +9586 e 211 61 +9594 8 212 61 +959c b 213 61 +95a7 1 213 61 +95b4 19 650 72 +95cd 1 650 72 +95da 5 666 72 +95df 1 666 72 +95ed 2b 759 72 +9624 5 666 72 +9629 1 666 72 +9637 2b 759 72 +FUNC 9662 49 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::capacity() const +9662 c 449 26 +966e 3d 451 71 +96ab 1 451 71 +FUNC 96ac 3c 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::size() const +96ac c 402 26 +96b8 30 403 71 +96f4 26 588 34 +9726 26 592 34 +974c c 103 69 +9758 d 103 69 +9765 1 103 69 +9776 1b 286 34 +9791 1 286 34 +979e d 94 68 +97ab 1 94 68 +97b8 1e 301 34 +97e3 56 622 34 +9839 17 623 34 +985c 9 1080 34 +9865 1a 1082 34 +987f 2 1083 34 +9881 8 1085 34 +9889 12 1086 34 +989b 6 1087 34 +98a1 6 1083 34 +98a7 1b 1089 34 +98c2 1d 1080 34 +98df c 1091 34 +98eb 1 1091 34 +98ec d 360 34 +98f9 77 361 34 +9970 c 69 70 +997c 20 69 70 +99a9 5c 104 68 +9a05 1 104 68 +9a06 c 69 70 +9a12 2c 69 70 +9a4b 5c 104 68 +9aa7 1 104 68 +9ab4 2d 662 72 +9ae1 1 662 72 +9aee 19 650 72 +9b07 1 650 72 +9b14 5 666 72 +9b19 1 666 72 +9b27 2b 759 72 +9b52 c 72 68 +9b5e 2 72 68 +9b60 c 105 69 +9b6c d 105 69 +9b79 1 105 69 +9b7a c 69 70 +9b86 2 69 70 +9b94 d 107 68 +9ba1 1 107 68 +9bae d 94 68 +9bbb 1 94 68 +FUNC 9bbc 2a 0 std::_List_base, std::allocator > >::_M_put_node(std::_List_node >*) +9bbc c 315 26 +9bc8 1e 316 66 +FUNC 9be6 35 0 bool __gnu_cxx::operator!=<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > > const&, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > > const&) +9be6 d 699 26 +9bf3 28 700 72 +9c1b 1 700 72 +9c28 d 623 72 +9c35 5 624 72 +FUNC 9c3a 4b 0 void std::__fill::fill<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::_Hashtable_node > >* const&) +9c3a c 539 61 +9c46 8 541 61 +9c4e 2 542 61 +9c50 12 543 61 +9c62 21 542 61 +9c83 2 543 61 +9c85 1 543 61 +FUNC 9c86 2b 0 void std::fill<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::_Hashtable_node > >* const&) +9c86 c 560 26 +9c92 4 567 61 +9c96 1b 568 61 +9cb1 1 568 61 +FUNC 9cb2 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, std::allocator<__gnu_cxx::_Hashtable_node > >*> >(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, std::allocator<__gnu_cxx::_Hashtable_node > >*>) +9cb2 c 171 26 +9cbe 2 173 73 +9cc0 1a 174 73 +9cda 21 173 73 +9cfb 2 174 73 +9cfd 1 174 73 +9d0a 7 98 68 +9d11 1 98 68 +9d1e 1d 85 68 +9d3b 5 86 68 +9d40 16 88 68 +9d62 1d 297 34 +9d7f 1 297 34 +9d8d e 605 34 +9d9b 9 606 34 +9da4 3c 609 34 +9de0 b 610 34 +9deb 11 609 34 +9dfc b 612 34 +9e07 12 614 34 +9e19 b 615 34 +9e24 13 612 34 +9e37 8 615 34 +9e3f 1 615 34 +9e4d 15 751 34 +9e62 1a 752 34 +9e7c b 754 34 +9e87 49 755 34 +9ed0 3b 756 34 +9f0b 12 754 34 +9f1d 15 758 34 +9f32 8 759 34 +9f3a 1c 760 34 +9f56 f 761 34 +9f65 41 762 34 +9fb2 7 98 68 +9fb9 1 98 68 +9fc6 1d 85 68 +9fe3 5 86 68 +9fe8 17 88 68 +9fff 1 88 68 +a00c 1d 297 34 +a029 1 297 34 +a037 e 605 34 +a045 9 606 34 +a04e 3c 609 34 +a08a b 610 34 +a095 11 609 34 +a0a6 b 612 34 +a0b1 12 614 34 +a0c3 b 615 34 +a0ce 13 612 34 +a0e1 8 615 34 +a0e9 1 615 34 +a0f7 15 751 34 +a10c 1a 752 34 +a126 b 754 34 +a131 49 755 34 +a17a 3b 756 34 +a1b5 12 754 34 +a1c7 15 758 34 +a1dc 8 759 34 +a1e4 1c 760 34 +a200 f 761 34 +a20f 41 762 34 +FUNC a250 35 0 bool __gnu_cxx::operator!=<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > > const&, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > > const&) +a250 d 699 26 +a25d 28 700 72 +a285 1 700 72 +a292 d 623 72 +a29f 5 624 72 +FUNC a2a4 4b 0 void std::__fill::fill<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +a2a4 c 539 61 +a2b0 8 541 61 +a2b8 2 542 61 +a2ba 12 543 61 +a2cc 21 542 61 +a2ed 2 543 61 +a2ef 1 543 61 +FUNC a2f0 2b 0 void std::fill<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +a2f0 c 560 26 +a2fc 4 567 61 +a300 1b 568 61 +a31b 1 568 61 +FUNC a31c 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, __gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>) +a31c c 171 26 +a328 2 173 73 +a32a 1a 174 73 +a344 21 173 73 +a365 2 174 73 +a367 1 174 73 +a368 c 65 68 +a374 2 65 68 +a376 c 103 69 +a382 d 103 69 +a38f 1 103 69 +FUNC a390 2b 0 std::_List_base, std::allocator > >::get_allocator() const +a390 10 322 26 +a3a0 1b 324 66 +a3bb 1 324 66 +FUNC a3bc 7b 0 std::_List_base, std::allocator > >::_M_clear() +a3bc d 69 27 +a3c9 8 72 77 +a3d1 2 73 77 +a3d3 6 75 77 +a3d9 8 76 77 +a3e1 35 77 77 +a416 12 78 77 +a428 a 73 77 +a432 5 78 77 +a437 1 78 77 +a438 c 331 66 +a444 18 332 66 +a45c c 392 66 +a468 d 392 66 +a475 1 392 66 +a476 c 211 74 +a482 10 211 74 +a49e d 107 68 +a4ab 1 107 68 +FUNC a4ac 2e 0 void std::_Destroy >(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, std::allocator) +a4ac c 171 27 +a4b8 2 173 73 +a4ba 12 174 73 +a4cc c 173 73 +a4d8 2 174 73 +a4da c 272 71 +a4e6 4b 273 71 +a531 1 273 71 +a532 13 196 74 +a545 10 196 74 +a555 2f 197 74 +a584 1a 198 74 +a59e 13 196 74 +a5b1 10 196 74 +a5c1 2f 197 74 +a5f0 1a 198 74 +a616 7 98 68 +a61d 1 98 68 +a62a 1d 85 68 +a647 5 86 68 +a64c 10 88 68 +FUNC a65c 2a 0 std::_Vector_base<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::_M_allocate(unsigned long) +a65c c 116 27 +a668 1e 117 71 +a686 d 100 71 +a693 12 101 71 +a6a5 19 103 71 +a6be b 104 71 +a6c9 3a 105 71 +a703 1 105 71 +a710 7 98 68 +a717 1 98 68 +a724 1d 85 68 +a741 5 86 68 +a746 10 88 68 +FUNC a756 2a 0 std::_Vector_base<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::_M_allocate(unsigned long) +a756 c 116 27 +a762 1e 117 71 +a780 d 100 71 +a78d 12 101 71 +a79f 19 103 71 +a7b8 b 104 71 +a7c3 3a 105 71 +a7fd 1 105 71 +a80b 12 424 61 +a81d 2e 425 61 +a84b 13 426 61 +a86a 4 440 61 +a86e 1b 443 61 +a889 1 443 61 +a898 56 482 61 +a8fa 4 514 61 +a8fe 4 515 61 +a902 1b 517 61 +a91d 1 517 61 +a92a 8 616 61 +a932 2 617 61 +a934 8 618 61 +a93c f 617 61 +a94b 5 619 61 +a95c 4 641 61 +a960 1b 642 61 +a97b 1 642 61 +FUNC a97c 27 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&, __true_type) +a97c c 182 28 +a988 1b 183 79 +a9a3 1 183 79 +FUNC a9a4 2f 0 void std::uninitialized_fill_n<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +a9a4 c 214 28 +a9b0 23 218 79 +a9d3 1 218 79 +FUNC a9d4 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>) +a9d4 c 308 28 +a9e0 1b 310 79 +a9fb 1 310 79 +a9fc c 200 71 +aa08 19 201 71 +aa21 42 203 71 +aa63 15 205 71 +aa85 11 992 34 +aa96 c 993 34 +aaa2 15 995 34 +aab7 c 996 34 +aac3 4a 998 34 +ab0d f 1001 34 +ab1c 1c 998 34 +ab38 1a 1003 34 +ab52 5 1004 34 +ab57 1f 1007 34 +ab76 1c 1008 34 +ab92 19 1009 34 +abab 19 1010 34 +abc4 1a 1011 34 +abde a 1004 34 +abe8 11 1001 34 +abf9 15 1014 34 +ac0e 13 1028 34 +ac21 b 1016 34 +ac2c 9 1018 34 +ac35 19 1023 34 +ac4e 23 1024 34 +ac71 19 1025 34 +ac8a 1d 1021 34 +aca7 1a 1018 34 +acc1 b 1028 34 +accc b 1016 34 +acd7 1e 1028 34 +acf5 1 1028 34 +ad06 16 438 34 +ad1c 37 439 34 +ad53 1 439 34 +ad64 37 212 42 +ad9b 1 212 42 +ada8 8 616 61 +adb0 2 617 61 +adb2 8 618 61 +adba f 617 61 +adc9 5 619 61 +adda 4 641 61 +adde 1b 642 61 +adf9 1 642 61 +FUNC adfa 27 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >* const&, __true_type) +adfa c 182 28 +ae06 1b 183 79 +ae21 1 183 79 +FUNC ae22 2f 0 void std::uninitialized_fill_n<__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >* const&) +ae22 c 214 28 +ae2e 23 218 79 +ae51 1 218 79 +FUNC ae52 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >*, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::_Hashtable_node > >**, unsigned long, __gnu_cxx::_Hashtable_node > >* const&, std::allocator<__gnu_cxx::_Hashtable_node > >*>) +ae52 c 308 28 +ae5e 1b 310 79 +ae79 1 310 79 +ae7a c 200 71 +ae86 19 201 71 +ae9f 42 203 71 +aee1 15 205 71 +af03 11 992 34 +af14 c 993 34 +af20 15 995 34 +af35 c 996 34 +af41 4a 998 34 +af8b f 1001 34 +af9a 1c 998 34 +afb6 1a 1003 34 +afd0 5 1004 34 +afd5 1f 1007 34 +aff4 1c 1008 34 +b010 19 1009 34 +b029 19 1010 34 +b042 1a 1011 34 +b05c a 1004 34 +b066 11 1001 34 +b077 15 1014 34 +b08c 13 1028 34 +b09f b 1016 34 +b0aa 9 1018 34 +b0b3 19 1023 34 +b0cc 23 1024 34 +b0ef 19 1025 34 +b108 1d 1021 34 +b125 1a 1018 34 +b13f b 1028 34 +b14a b 1016 34 +b155 1e 1028 34 +b173 1 1028 34 +b184 16 438 34 +b19a 37 439 34 +b1d1 1 439 34 +b1e2 37 212 42 +b219 1 212 42 +b227 12 424 61 +b239 2e 425 61 +b267 13 426 61 +b286 4 440 61 +b28a 1b 443 61 +b2a5 1 443 61 +b2b4 56 482 61 +b316 4 514 61 +b31a 4 515 61 +b31e 1b 517 61 +b339 1 517 61 +b346 8 616 61 +b34e 2 617 61 +b350 12 618 61 +b362 16 617 61 +b378 5 619 61 +b37d 1 619 61 +b38a 4 641 61 +b38e 1b 642 61 +b3a9 1 642 61 +FUNC b3aa 27 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >* const&, __true_type) +b3aa c 182 28 +b3b6 1b 183 79 +b3d1 1 183 79 +FUNC b3d2 2f 0 void std::uninitialized_fill_n<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >* const&) +b3d2 c 214 28 +b3de 23 218 79 +b401 1 218 79 +FUNC b402 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >*, __gnu_cxx::_Hashtable_node > >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >* const&, std::allocator<__gnu_cxx::_Hashtable_node > >*>) +b402 c 308 28 +b40e 1b 310 79 +b429 1 310 79 +b436 8 616 61 +b43e 2 617 61 +b440 12 618 61 +b452 16 617 61 +b468 5 619 61 +b46d 1 619 61 +b47a 4 641 61 +b47e 1b 642 61 +b499 1 642 61 +FUNC b49a 27 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&, __true_type) +b49a c 182 28 +b4a6 1b 183 79 +b4c1 1 183 79 +FUNC b4c2 2f 0 void std::uninitialized_fill_n<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +b4c2 c 214 28 +b4ce 23 218 79 +b4f1 1 218 79 +FUNC b4f2 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*>) +b4f2 c 308 28 +b4fe 1b 310 79 +b519 1 310 79 +b526 22 300 61 +b548 11 301 61 +b559 1 301 61 +b566 4 315 61 +b56a 1b 317 61 +b585 1 317 61 +b592 1b 326 61 +b5ad 1 326 61 +b5ba 4 384 61 +b5be 4 385 61 +b5c2 1b 387 61 +b5dd 1 387 61 +b5ea 1b 74 79 +b605 1 74 79 +b612 23 113 79 +b635 1 113 79 +b642 1b 254 79 +b65d 1 254 79 +b66a 15 763 71 +b67f 40 766 71 +b6bf 3 768 71 +b6c2 2 773 71 +FUNC b6c4 124 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::reserve(unsigned long) +b6c4 13 69 29 +b6d7 15 71 78 +b6ec e 72 78 +b6fa 19 73 78 +b713 e 75 78 +b721 28 78 78 +b749 3e 79 78 +b787 30 81 78 +b7b7 8 84 78 +b7bf 11 85 78 +b7d0 18 86 78 +b7f5 33 335 61 +b834 4 384 61 +b838 4 385 61 +b83c 1b 387 61 +b857 1 387 61 +b864 1b 74 79 +b87f 1 74 79 +b88c 23 113 79 +b8af 1 113 79 +b8bc 1b 254 79 +b8d7 1 254 79 +b8e6 56 354 61 +b948 4 384 61 +b94c 4 385 61 +b950 1b 387 61 +b96b 1 387 61 +b978 1b 74 79 +b993 1 74 79 +b9a0 23 113 79 +b9c3 1 113 79 +b9d0 1b 254 79 +b9eb 1 254 79 +FUNC b9ec 46e 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::_M_fill_insert(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >* const&) +b9ec 14 311 29 +ba00 b 313 78 +ba0b 24 315 78 +ba2f 8 318 78 +ba37 23 319 78 +ba5a 15 320 78 +ba6f c 321 78 +ba7b 51 323 78 +bacc 14 327 78 +bae0 30 328 78 +bb10 35 330 78 +bb45 48 334 78 +bb8d 17 338 78 +bba4 43 339 78 +bbe7 14 342 78 +bbfb 1e 343 78 +bc19 e 348 78 +bc27 1e 349 78 +bc45 e 350 78 +bc53 1d 353 78 +bc70 8 354 78 +bc78 e 355 78 +bc86 27 357 78 +bcad 6 358 78 +bcb3 4d 361 78 +bd00 40 365 78 +bd40 18 367 78 +bd58 4d 368 78 +bda5 3e 379 78 +bde3 30 381 78 +be13 12 384 78 +be25 13 385 78 +be38 22 386 78 +FUNC be5a 2e 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::insert(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node > >**, std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> > >, unsigned long, __gnu_cxx::_Hashtable_node > >* const&) +be5a c 657 29 +be66 22 658 71 +be94 15 580 34 +bea9 15 581 34 +bebe 37 582 34 +bef5 c 583 34 +bf01 1 583 34 +bf02 d 335 34 +bf0f 4e 337 34 +bf5d 4d 338 34 +bfaa d 134 42 +bfb7 65 135 42 +c028 22 300 61 +c04a 11 301 61 +c05b 1 301 61 +c068 4 315 61 +c06c 1b 317 61 +c087 1 317 61 +c094 1b 326 61 +c0af 1 326 61 +c0bc 4 384 61 +c0c0 4 385 61 +c0c4 1b 387 61 +c0df 1 387 61 +c0ec 1b 74 79 +c107 1 74 79 +c114 23 113 79 +c137 1 113 79 +c144 1b 254 79 +c15f 1 254 79 +c16c 15 763 71 +c181 40 766 71 +c1c1 3 768 71 +c1c4 2 773 71 +FUNC c1c6 124 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::reserve(unsigned long) +c1c6 13 69 29 +c1d9 15 71 78 +c1ee e 72 78 +c1fc 19 73 78 +c215 e 75 78 +c223 28 78 78 +c24b 3e 79 78 +c289 30 81 78 +c2b9 8 84 78 +c2c1 11 85 78 +c2d2 18 86 78 +c2f7 33 335 61 +c336 4 384 61 +c33a 4 385 61 +c33e 1b 387 61 +c359 1 387 61 +c366 1b 74 79 +c381 1 74 79 +c38e 23 113 79 +c3b1 1 113 79 +c3be 1b 254 79 +c3d9 1 254 79 +c3e8 56 354 61 +c44a 4 384 61 +c44e 4 385 61 +c452 1b 387 61 +c46d 1 387 61 +c47a 1b 74 79 +c495 1 74 79 +c4a2 23 113 79 +c4c5 1 113 79 +c4d2 1b 254 79 +c4ed 1 254 79 +FUNC c4ee 46e 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::_M_fill_insert(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +c4ee 14 311 29 +c502 b 313 78 +c50d 24 315 78 +c531 8 318 78 +c539 23 319 78 +c55c 15 320 78 +c571 c 321 78 +c57d 51 323 78 +c5ce 14 327 78 +c5e2 30 328 78 +c612 35 330 78 +c647 48 334 78 +c68f 17 338 78 +c6a6 43 339 78 +c6e9 14 342 78 +c6fd 1e 343 78 +c71b e 348 78 +c729 1e 349 78 +c747 e 350 78 +c755 1d 353 78 +c772 8 354 78 +c77a e 355 78 +c788 27 357 78 +c7af 6 358 78 +c7b5 4d 361 78 +c802 40 365 78 +c842 18 367 78 +c85a 4d 368 78 +c8a7 3e 379 78 +c8e5 30 381 78 +c915 12 384 78 +c927 13 385 78 +c93a 22 386 78 +FUNC c95c 2e 0 std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> >::insert(__gnu_cxx::__normal_iterator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >**, std::vector<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*, std::allocator<__gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >*> > >, unsigned long, __gnu_cxx::_Hashtable_node, __gnu_cxx::hash, std::equal_to, std::allocator > >*> >* const&) +c95c c 657 29 +c968 22 658 71 +c996 15 580 34 +c9ab 15 581 34 +c9c0 37 582 34 +c9f7 c 583 34 +ca03 1 583 34 +ca04 d 335 34 +ca11 4e 337 34 +ca5f 4d 338 34 +caac d 134 42 +cab9 65 135 42 +FUNC cb1e 44 0 dwarf2reader::CUFunctionInfoHandler::StartCompilationUnit(unsigned long long, unsigned char, unsigned char, unsigned long long, unsigned char) +cb1e 39 135 42 +cb57 5 102 30 +cb5c 6 103 30 +FUNC cb62 41 0 dwarf2reader::CUFunctionInfoHandler::ProcessAttributeString(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, std::string const&) +cb62 18 136 30 +cb7a 10 137 30 +cb8a 17 138 30 +cba1 2 139 30 +cba3 1 139 30 +FUNC cba4 2a5 0 dwarf2reader::CUFunctionInfoHandler::ProcessAttributeUnsigned(unsigned long long, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm, unsigned long long) +cba4 2d 144 30 +cbd1 a 145 30 +cbdb 58 146 30 +cc33 35 147 30 +cc68 32 146 30 +cc9a 2a 147 30 +ccc4 82 152 30 +cd46 18 153 30 +cd5e 1c 152 30 +cd7a 2f 153 30 +cda9 e 154 30 +cdb7 28 155 30 +cddf 12 157 30 +cdf1 2 158 30 +cdf3 12 160 30 +ce05 2 161 30 +ce07 c 163 30 +ce13 2 164 30 +ce15 2c 166 30 +ce41 8 172 30 +ce49 1 172 30 +FUNC ce4a 19c 0 dwarf2reader::CULineInfoHandler::AddLine(unsigned long long, unsigned int, unsigned int, unsigned int) +ce4a 20 84 30 +ce6a 1c 85 30 +ce86 9c 87 30 +cf22 4f 89 30 +cf71 19 87 30 +cf8a 25 90 30 +cfaf 30 93 30 +cfdf 7 95 30 +FUNC cfe6 9f 0 dwarf2reader::CUFunctionInfoHandler::EndDIE(unsigned long long) +cfe6 19 174 30 +cfff 1c 175 30 +d01b 65 177 30 +d080 5 178 30 +d085 1 178 30 +FUNC d086 164 0 dwarf2reader::CUFunctionInfoHandler::StartDIE(unsigned long long, dwarf2reader::DwarfTag, std::list, std::allocator > > const&) +d086 20 111 30 +d0a6 1c 112 30 +d0c2 c 126 30 +d0ce 23 115 30 +d0f1 26 116 30 +d117 1a 117 30 +d131 d 118 30 +d13e 1b 119 30 +d159 5f 120 30 +d1b8 c 124 30 +d1c4 1c 115 30 +d1e0 3 126 30 +d1e3 7 129 30 +FUNC d1ea 73 0 dwarf2reader::CULineInfoHandler::DefineDir(std::string const&, unsigned int) +d1ea 13 52 30 +d1fd 45 54 30 +d242 15 55 30 +d257 6 56 30 +d25d 1 56 30 +FUNC d25e 23b 0 dwarf2reader::CULineInfoHandler::DefineFile(std::string const&, int, unsigned int, unsigned long long, unsigned long long) +d25e 2c 60 30 +d28a 45 62 30 +d2cf 2f 65 30 +d2fe 24 66 30 +d322 b 68 30 +d32d e 69 30 +d33b 19 71 30 +d354 17 72 30 +d36b 93 74 30 +d3fe 64 77 30 +d462 30 79 30 +d492 7 81 30 +d499 1 81 30 +d49a 14 38 30 +d4ae 36 40 30 +d4e4 41 43 30 +d525 41 44 30 +d566 67 45 30 +d5cd 10 46 30 +d5dd 13 45 30 +d5f0 15 47 30 +d605 e 48 30 +d613 3d 49 30 +d650 20 50 30 +d670 14 38 30 +d684 36 40 30 +d6ba 41 43 30 +d6fb 41 44 30 +d73c 67 45 30 +d7a3 10 46 30 +d7b3 13 45 30 +d7c6 15 47 30 +d7db e 48 30 +d7e9 3d 49 30 +d826 20 50 30 +d846 12 125 74 +d858 12 125 74 +d86a 13 55 32 +d87d 35 55 32 +d8b2 13 98 32 +d8c5 35 98 32 +d8fa c 35 32 +d906 d 35 32 +d913 1 35 32 +d914 d 22 32 +d921 40 22 32 +d961 1 22 32 +d962 c 89 70 +d96e 1e 90 70 +d998 14 208 34 +d9ac c 190 67 +d9b8 a 190 67 +d9c2 c 259 67 +d9ce 21 259 67 +d9ef 1 259 67 +FUNC d9f0 13 0 std::auto_ptr::operator->() const +d9f0 c 283 35 +d9fc 7 286 67 +da03 1 286 67 +da11 5c 104 68 +da6d 1 104 68 +FUNC da6e 28 0 bool std::operator==, std::allocator >(std::basic_string, std::allocator > const&, char const*) +da6e c 2139 37 +da7a 1c 2140 37 +FUNC da96 5d 0 std::basic_string, std::allocator > std::operator+, std::allocator >(std::basic_string, std::allocator > const&, char const*) +da96 d 2081 37 +daa3 12 2083 37 +dab5 1a 2084 37 +dacf 24 2085 37 +daf3 1 2085 37 +FUNC daf4 5d 0 std::basic_string, std::allocator > std::operator+, std::allocator >(std::basic_string, std::allocator > const&, std::basic_string, std::allocator > const&) +daf4 d 2044 37 +db01 12 2046 37 +db13 1a 2047 37 +db2d 24 2048 37 +db51 1 2048 37 +db52 c 84 70 +db5e 17 85 70 +db75 1 85 70 +FUNC db76 2d 0 std::pair std::make_pair(char const*, unsigned int) +db76 c 144 37 +db82 21 145 70 +dba3 1 145 70 +dba4 c 84 70 +dbb0 23 85 70 +dbd3 1 85 70 +FUNC dbd4 3c 0 std::pair > std::make_pair >(unsigned long long, std::pair) +dbd4 1c 144 37 +dbf0 20 145 70 +dc10 d 89 70 +dc1d 64 90 70 +dc81 1 90 70 +dc82 c 89 70 +dc8e 2a 90 70 +dcb8 c 84 70 +dcc4 1d 85 70 +dce1 1 85 70 +FUNC dce2 3c 0 std::pair std::make_pair(unsigned long long, dwarf2reader::FunctionInfo*) +dce2 1c 144 37 +dcfe 20 145 70 +dd2a a 190 34 +dd40 d 194 34 +dd4d 1 194 34 +dd4e c 603 72 +dd5a c 603 72 +FUNC dd66 2b 0 std::vector >::begin() const +dd66 c 342 39 +dd72 1f 343 71 +dd91 1 343 71 +FUNC dd92 2c 0 std::vector >::end() const +dd92 c 360 39 +dd9e 20 361 71 +ddca 5 666 72 +ddcf 1 666 72 +dddd 2b 759 72 +FUNC de08 3c 0 std::vector >::size() const +de08 c 402 39 +de14 30 403 71 +FUNC de44 2b 0 std::vector >::begin() const +de44 c 342 39 +de50 1f 343 71 +de6f 1 343 71 +FUNC de70 2c 0 std::vector >::end() const +de70 c 360 39 +de7c 20 361 71 +dea9 31 759 72 +FUNC deda 3c 0 std::vector >::size() const +deda c 402 39 +dee6 30 403 71 +df16 c 603 72 +df22 c 603 72 +FUNC df2e 26 0 std::vector >::end() +df2e c 351 39 +df3a 1a 352 71 +df60 7 614 72 +df67 1 614 72 +FUNC df68 13 0 std::vector >::max_size() const +df68 c 407 39 +df74 7 408 71 +df7b 1 408 71 +df88 5 666 72 +df8d 1 666 72 +df9a d 623 72 +dfa7 5 624 72 +FUNC dfac 23 0 std::vector >::begin() +dfac c 333 39 +dfb8 17 334 71 +dfcf 1 334 71 +dfd0 c 35 32 +dfdc 26 35 32 +e00f 5c 104 68 +e06b 1 104 68 +e078 7 614 72 +e07f 1 614 72 +FUNC e080 35 0 dwarf2reader::SourceFileInfo::operator=(dwarf2reader::SourceFileInfo const&) +e080 c 35 39 +e08c 29 35 32 +e0b5 1 35 32 +FUNC e0b6 13 0 std::vector >::max_size() const +e0b6 c 407 39 +e0c2 7 408 71 +e0c9 1 408 71 +e0d6 d 623 72 +e0e3 5 624 72 +FUNC e0e8 3c 0 std::vector >::_M_range_check(unsigned long) const +e0e8 13 515 39 +e0fb 15 517 71 +e110 14 518 71 +FUNC e124 3c 0 std::vector >::_M_range_check(unsigned long) const +e124 13 515 39 +e137 15 517 71 +e14c 14 518 71 +e16c 2a 654 72 +FUNC e196 42 0 std::vector >::operator[](unsigned long) +e196 c 494 39 +e1a2 36 495 71 +FUNC e1d8 32 0 std::vector >::at(unsigned long) +e1d8 c 534 39 +e1e4 12 536 71 +e1f6 14 537 71 +e216 32 654 72 +FUNC e248 42 0 std::vector >::operator[](unsigned long) +e248 c 494 39 +e254 36 495 71 +FUNC e28a 32 0 std::vector >::at(unsigned long) +e28a c 534 39 +e296 12 536 71 +e2a8 14 537 71 +FUNC e2bc 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_end() +e2bc c 472 40 +e2c8 8 473 40 +FUNC e2d0 11 0 std::_Select1st > >::operator()(std::pair > const&) const +e2d0 c 550 41 +e2dc 5 551 41 +e2e1 1 551 41 +FUNC e2e2 53 0 std::less::operator()(unsigned long long const&, unsigned long long const&) const +e2e2 c 226 41 +e2ee 47 227 41 +e335 1 227 41 +FUNC e336 20 0 std::_Rb_tree_iterator > >::operator==(std::_Rb_tree_iterator > > const&) const +e336 c 209 41 +e342 14 210 40 +e356 c 84 70 +e362 18 85 70 +FUNC e37a 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_end() +e37a c 472 41 +e386 8 473 40 +FUNC e38e 11 0 std::_Select1st >::operator()(std::pair const&) const +e38e c 550 41 +e39a 5 551 41 +e39f 1 551 41 +FUNC e3a0 20 0 std::_Rb_tree_iterator >::operator==(std::_Rb_tree_iterator > const&) const +e3a0 c 209 41 +e3ac 14 210 40 +e3c0 c 84 70 +e3cc 18 85 70 +e3e4 c 180 34 +e3f0 13 181 34 +e403 1 181 34 +e410 22 409 34 +e43e d 207 42 +e44b 1 207 42 +FUNC e44c 35 0 bool __gnu_cxx::operator!= > >(__gnu_cxx::__normal_iterator > > const&, __gnu_cxx::__normal_iterator > > const&) +e44c d 699 42 +e459 28 700 72 +e481 1 700 72 +FUNC e482 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator > >, std::allocator >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, std::allocator) +e482 c 171 43 +e48e 2 173 73 +e490 1a 174 73 +e4aa 21 173 73 +e4cb 2 174 73 +e4cd 1 174 73 +FUNC e4ce 35 0 bool __gnu_cxx::operator!= > >(__gnu_cxx::__normal_iterator > > const&, __gnu_cxx::__normal_iterator > > const&) +e4ce d 699 43 +e4db 28 700 72 +e503 1 700 72 +FUNC e504 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator > >, std::allocator >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, std::allocator) +e504 c 171 43 +e510 2 173 73 +e512 1a 174 73 +e52c 21 173 73 +e54d 2 174 73 +e54f 1 174 73 +FUNC e550 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_value(std::_Rb_tree_node > > const*) +e550 c 480 43 +e55c 8 481 40 +FUNC e564 28 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_key(std::_Rb_tree_node > > const*) +e564 c 484 43 +e570 1c 485 40 +FUNC e58c 25 0 std::_Rb_tree_iterator >::operator--() +e58c c 194 43 +e598 14 196 40 +e5ac 5 197 40 +e5b1 1 197 40 +FUNC e5b2 25 0 std::_Rb_tree_iterator > >::operator--() +e5b2 c 194 43 +e5be 14 196 40 +e5d2 5 197 40 +e5d7 1 197 40 +FUNC e5d8 14 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_value(std::_Rb_tree_node_base const*) +e5d8 c 504 43 +e5e4 8 505 40 +FUNC e5ec 28 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_S_key(std::_Rb_tree_node_base const*) +e5ec c 508 43 +e5f8 1c 509 40 +FUNC e614 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_value(std::_Rb_tree_node > const*) +e614 c 480 43 +e620 8 481 40 +FUNC e628 28 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_key(std::_Rb_tree_node > const*) +e628 c 484 43 +e634 1c 485 40 +FUNC e650 14 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_value(std::_Rb_tree_node_base const*) +e650 c 504 43 +e65c 8 505 40 +FUNC e664 28 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_S_key(std::_Rb_tree_node_base const*) +e664 c 508 43 +e670 1c 509 40 +e698 7 614 72 +e69f 1 614 72 +e6ac 7 98 68 +e6b3 1 98 68 +e6c0 1d 85 68 +e6dd 5 86 68 +e6e2 10 88 68 +FUNC e6f2 2a 0 std::_Vector_base >::_M_allocate(unsigned long) +e6f2 c 116 43 +e6fe 1e 117 71 +e728 7 98 68 +e72f 1 98 68 +e73c 1d 85 68 +e759 5 86 68 +e75e 16 88 68 +FUNC e774 2a 0 std::_Vector_base >::_M_allocate(unsigned long) +e774 c 116 43 +e780 1e 117 71 +e7aa 3a 104 68 +e7f0 2a 654 72 +FUNC e81a 42 0 std::vector<__gnu_cxx::_Hashtable_node > >*, std::allocator<__gnu_cxx::_Hashtable_node > >*> >::operator[](unsigned long) const +e81a c 509 43 +e826 36 510 71 +FUNC e85c 4e 0 std::string* std::__copy_backward::copy_b(std::string*, std::string*, std::string*) +e85c c 408 61 +e868 14 411 61 +e87c 1e 412 61 +e89a b 411 61 +e8a5 5 413 61 +FUNC e8aa 2b 0 std::string* std::__copy_backward_aux(std::string*, std::string*, std::string*) +e8aa c 432 44 +e8b6 4 440 61 +e8ba 1b 443 61 +e8d5 1 443 61 +e8e4 56 482 61 +e946 4 514 61 +e94a 4 515 61 +e94e 1b 517 61 +e969 1 517 61 +FUNC e96a 69 0 void std::_Construct(std::string*, std::string const&) +e96a d 77 44 +e977 5c 81 73 +e9d3 1 81 73 +FUNC e9d4 54 0 dwarf2reader::SourceFileInfo* std::__copy_backward::copy_b(dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo*) +e9d4 c 408 61 +e9e0 1a 411 61 +e9fa 1e 412 61 +ea18 b 411 61 +ea23 5 413 61 +FUNC ea28 2b 0 dwarf2reader::SourceFileInfo* std::__copy_backward_aux(dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo*) +ea28 c 432 44 +ea34 4 440 61 +ea38 1b 443 61 +ea53 1 443 61 +ea62 56 482 61 +eac4 4 514 61 +eac8 4 515 61 +eacc 1b 517 61 +eae7 1 517 61 +FUNC eae8 69 0 void std::_Construct(dwarf2reader::SourceFileInfo*, dwarf2reader::SourceFileInfo const&) +eae8 d 77 44 +eaf5 5c 81 73 +eb51 1 81 73 +eb52 c 69 70 +eb5e 20 69 70 +eb7e c 69 70 +eb8a 2a 69 70 +ebc1 5c 104 68 +ec1d 1 104 68 +ec2a 15 523 34 +ec3f 79 525 34 +ecb8 21 529 34 +ecd9 1 529 34 +ece6 14 229 42 +ed06 7 98 68 +ed0d 1 98 68 +ed1a 1d 85 68 +ed37 5 86 68 +ed3c 10 88 68 +FUNC ed4c 29 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_get_node() +ed4c c 355 44 +ed58 1d 356 40 +ed75 1 356 40 +FUNC ed76 b6 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_create_node(std::pair > const&) +ed76 d 363 44 +ed83 e 365 40 +ed91 3c 367 40 +edcd b 373 40 +edd8 11 367 40 +ede9 b 368 40 +edf4 12 370 40 +ee06 b 371 40 +ee11 13 368 40 +ee24 8 373 40 +FUNC ee2c cd 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::_M_insert(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::pair > const&) +ee2c d 787 44 +ee39 15 789 40 +ee4e 5d 792 40 +eeab 24 796 40 +eecf f 798 40 +eede 1b 799 40 +eef9 1 799 40 +FUNC eefa 1ef 0 std::_Rb_tree >, std::_Select1st > >, std::less, std::allocator > > >::insert_unique(std::pair > const&) +eefa d 869 44 +ef07 e 871 40 +ef15 e 872 40 +ef23 4 873 40 +ef27 2 874 40 +ef29 6 876 40 +ef2f 35 877 40 +ef64 2a 878 40 +ef8e 6 874 40 +ef94 12 880 40 +efa6 a 881 40 +efb0 24 882 40 +efd4 51 883 40 +f025 b 885 40 +f030 36 886 40 +f066 4e 887 40 +f0b4 35 888 40 +f0e9 1 888 40 +FUNC f0ea 20 0 std::map, std::less, std::allocator > > >::insert(std::pair > const&) +f0ea c 359 45 +f0f6 14 360 45 +f116 7 98 68 +f11d 1 98 68 +f12a 1d 85 68 +f147 5 86 68 +f14c 1d 88 68 +f169 1 88 68 +FUNC f16a 29 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_get_node() +f16a c 355 45 +f176 1d 356 40 +f193 1 356 40 +FUNC f194 5f 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_create_node(std::pair const&) +f194 d 363 45 +f1a1 e 365 40 +f1af 3c 367 40 +f1eb 8 373 40 +f1f3 1 373 40 +FUNC f1f4 cd 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::_M_insert(std::_Rb_tree_node_base*, std::_Rb_tree_node_base*, std::pair const&) +f1f4 d 787 45 +f201 15 789 40 +f216 5d 792 40 +f273 24 796 40 +f297 f 798 40 +f2a6 1b 799 40 +f2c1 1 799 40 +FUNC f2c2 1ef 0 std::_Rb_tree, std::_Select1st >, std::less, std::allocator > >::insert_unique(std::pair const&) +f2c2 d 869 45 +f2cf e 871 40 +f2dd e 872 40 +f2eb 4 873 40 +f2ef 2 874 40 +f2f1 6 876 40 +f2f7 35 877 40 +f32c 2a 878 40 +f356 6 874 40 +f35c 12 880 40 +f36e a 881 40 +f378 24 882 40 +f39c 51 883 40 +f3ed b 885 40 +f3f8 36 886 40 +f42e 4e 887 40 +f47c 35 888 40 +f4b1 1 888 40 +FUNC f4b2 20 0 std::map, std::allocator > >::insert(std::pair const&) +f4b2 c 359 45 +f4be 14 360 45 +FUNC f4d2 19 0 void std::_Destroy(std::string*) +f4d2 c 106 45 +f4de d 107 73 +f4eb 1 107 73 +FUNC f4ec 44 0 void std::__destroy_aux<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, __false_type) +f4ec c 119 45 +f4f8 2 121 73 +f4fa 13 122 73 +f50d 21 121 73 +f52e 2 122 73 +FUNC f530 28 0 void std::_Destroy<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) +f530 c 148 45 +f53c 1c 155 73 +f565 6 82 79 +f56b 2 85 79 +f56d 24 86 79 +f591 2c 85 79 +f5bd b 87 79 +f5c8 b 89 79 +f5d3 12 91 79 +f5e5 b 92 79 +f5f0 13 89 79 +f603 9 92 79 +f618 23 113 79 +f63b 1 113 79 +f648 1b 254 79 +f663 1 254 79 +FUNC f664 430 0 std::vector >::_M_insert_aux(__gnu_cxx::__normal_iterator > >, std::string const&) +f664 14 249 47 +f678 14 251 78 +f68c 22 253 78 +f6ae f 255 78 +f6bd 12 256 78 +f6cf 55 257 78 +f724 4b 260 78 +f76f e 264 78 +f77d 15 265 78 +f792 e 266 78 +f7a0 1d 271 78 +f7bd 8 272 78 +f7c5 e 273 78 +f7d3 27 275 78 +f7fa 6 276 78 +f800 55 279 78 +f855 25 284 78 +f87a b 285 78 +f885 4f 286 78 +f8d4 3 284 78 +f8d7 13 279 78 +f8ea e 286 78 +f8f8 4d 298 78 +f945 30 299 78 +f975 12 302 78 +f987 13 303 78 +f99a 23 304 78 +f9bd 3 298 78 +f9c0 13 286 78 +f9d3 b 292 78 +f9de 39 294 78 +fa17 23 295 78 +fa3a 8 296 78 +fa42 16 294 78 +fa58 3 296 78 +fa5b 19 292 78 +fa74 19 298 78 +fa8d 7 304 78 +FUNC fa94 70 0 std::vector >::push_back(std::string const&) +fa94 c 602 47 +faa0 10 604 71 +fab0 1e 606 71 +face 11 607 71 +fadf 25 610 71 +FUNC fb04 19 0 void std::_Destroy(dwarf2reader::SourceFileInfo*) +fb04 c 106 47 +fb10 d 107 73 +fb1d 1 107 73 +FUNC fb1e 44 0 void std::__destroy_aux<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, __false_type) +fb1e c 119 47 +fb2a 2 121 73 +fb2c 13 122 73 +fb3f 21 121 73 +fb60 2 122 73 +FUNC fb62 28 0 void std::_Destroy<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) +fb62 c 148 47 +fb6e 1c 155 73 +fb97 6 82 79 +fb9d 2 85 79 +fb9f 24 86 79 +fbc3 2c 85 79 +fbef b 87 79 +fbfa b 89 79 +fc05 12 91 79 +fc17 b 92 79 +fc22 13 89 79 +fc35 9 92 79 +fc4a 23 113 79 +fc6d 1 113 79 +fc7a 1b 254 79 +fc95 1 254 79 +FUNC fc96 43d 0 std::vector >::_M_insert_aux(__gnu_cxx::__normal_iterator > >, dwarf2reader::SourceFileInfo const&) +fc96 14 249 47 +fcaa 14 251 78 +fcbe 22 253 78 +fce0 f 255 78 +fcef 12 256 78 +fd01 55 257 78 +fd56 4b 260 78 +fda1 e 264 78 +fdaf 15 265 78 +fdc4 e 266 78 +fdd2 1d 271 78 +fdef 8 272 78 +fdf7 e 273 78 +fe05 27 275 78 +fe2c 6 276 78 +fe32 55 279 78 +fe87 25 284 78 +feac b 285 78 +feb7 4f 286 78 +ff06 3 284 78 +ff09 13 279 78 +ff1c e 286 78 +ff2a 4d 298 78 +ff77 36 299 78 +ffad 12 302 78 +ffbf 13 303 78 +ffd2 2a 304 78 +fffc 3 298 78 +ffff 13 286 78 +10012 b 292 78 +1001d 39 294 78 +10056 23 295 78 +10079 8 296 78 +10081 16 294 78 +10097 3 296 78 +1009a 19 292 78 +100b3 19 298 78 +100cc 7 304 78 +100d3 1 304 78 +FUNC 100d4 70 0 std::vector >::push_back(dwarf2reader::SourceFileInfo const&) +100d4 c 602 47 +100e0 10 604 71 +100f0 1e 606 71 +1010e 11 607 71 +1011f 25 610 71 +FUNC 10144 16c 0 Start +10144 17 610 71 +1015b 40 49 48 +1019b 6 51 48 +101a1 3f 53 48 +101e0 7 54 48 +101e7 5 55 48 +101ec 2a 58 48 +10216 61 61 48 +10277 7 62 48 +1027e 2 63 48 +10280 29 66 48 +102a9 7 67 48 +FUNC 102b0 108 0 Usage +102b0 19 70 48 +102c9 30 71 48 +102f9 29 73 48 +10322 30 74 48 +10352 30 75 48 +10382 30 76 48 +103b2 6 77 48 +FUNC 103b8 3af 0 SetupOptions +103b8 21 80 48 +103d9 8 82 48 +103e1 6 85 48 +103e7 10 86 48 +103f7 2e 88 48 +10425 2f 94 48 +10454 2a 91 48 +1047e 23 95 48 +104a1 3e 97 48 +104df 11 98 48 +104f0 7c 99 48 +1056c c 100 48 +10578 5 99 48 +1057d 3e 101 48 +105bb 11 102 48 +105cc 3e 103 48 +1060a 11 104 48 +1061b 37 106 48 +10652 b 107 48 +1065d c 108 48 +10669 b 113 48 +10674 c 114 48 +10680 14 119 48 +10694 30 120 48 +106c4 b 121 48 +106cf c 122 48 +106db 81 127 48 +1075c b 128 48 +10767 1 128 48 +FUNC 10768 a7 0 main +10768 13 131 48 +1077b 37 132 48 +107b2 1e 135 48 +107d0 e 136 48 +107de 8 137 48 +107e6 17 139 48 +107fd c 141 48 +10809 6 142 48 +1080f 1 142 48 +10810 c 47 49 +1081c 1a 48 49 +10836 2 49 49 +10838 c 47 49 +10844 1a 48 49 +1085e 2 49 49 +FUNC 10860 cb 0 google_breakpad::FileID::FileIdentifier(unsigned char*) +10860 f 51 49 +1086f 16 52 49 +10885 6 53 49 +1088b f 54 49 +1089a b 57 49 +108a5 7 62 49 +108ac 2 63 49 +108ae 1c 64 49 +108ca 32 63 49 +108fc b 67 49 +10907 12 68 49 +10919 10 70 49 +10929 2 71 49 +1092b 1 71 49 +FUNC 1092c f2 0 google_breakpad::FileID::MachoIdentifier(int, unsigned char*) +1092c 10 73 49 +1093c 15 74 49 +10951 20 76 49 +10971 f 77 49 +10980 20 79 49 +109a0 c 80 49 +109ac 69 82 49 +10a15 9 83 49 +FUNC 10a1e fb 0 google_breakpad::FileID::ConvertIdentifierToString(unsigned char const*, char*, int) +10a1e c 87 49 +10a2a 7 88 49 +10a31 c 89 49 +10a3d 15 90 49 +10a52 12 91 49 +10a64 18 93 49 +10a7c e 94 49 +10a8a 2b 96 49 +10ab5 2b 97 49 +10ae0 17 89 49 +10af7 20 101 49 +10b17 2 102 49 +10b19 1 102 49 +FUNC 10b1a 13 0 NXHostByteOrder +10b1a c 144 56 +10b26 5 147 56 +10b2b 2 153 56 +10b2d 1 153 56 +10b2e c 56 51 +10b3a 1a 57 51 +10b54 1e 58 51 +10b72 2 59 51 +10b74 c 56 51 +10b80 1a 57 51 +10b9a 1e 58 51 +10bb8 2 59 51 +10bba c 61 51 +10bc6 e 62 51 +10bd4 11 63 51 +10be5 2 64 51 +10be7 1 64 51 +10be8 c 61 51 +10bf4 e 62 51 +10c02 11 63 51 +10c13 2 64 51 +10c15 1 64 51 +FUNC 10c16 477 0 MacFileUtilities::MachoID::UpdateCRC(unsigned char*, unsigned long) +10c16 c 74 51 +10c22 11 82 51 +10c33 14 83 51 +10c47 5 86 51 +10c4c 9 87 51 +10c55 7 88 51 +10c5c 18b 90 51 +10de7 6 91 51 +10ded 14 89 51 +10e01 23 93 51 +10e24 23 94 51 +10e47 d 86 51 +10e54 f 98 51 +10e63 6 100 51 +10e69 18b 101 51 +10ff4 6 102 51 +10ffa c 99 51 +11006 13 105 51 +11019 8 106 51 +11021 10 104 51 +11031 23 108 51 +11054 23 109 51 +11077 14 110 51 +1108b 2 112 51 +1108d 1 112 51 +FUNC 1108e 2c 0 MacFileUtilities::MachoID::UpdateMD5(unsigned char*, unsigned long) +1108e c 114 51 +1109a 1e 115 51 +110b8 2 116 51 +FUNC 110ba 2c 0 MacFileUtilities::MachoID::UpdateSHA1(unsigned char*, unsigned long) +110ba c 118 51 +110c6 1e 119 51 +110e4 2 120 51 +FUNC 110e6 121 0 MacFileUtilities::MachoID::Update(MacFileUtilities::MachoWalker*, unsigned long, unsigned long) +110e6 f 122 51 +110f5 1b 123 51 +11110 e 129 51 +1111e 5 130 51 +11123 9 131 51 +1112c 7 132 51 +11133 a 133 51 +1113d 6 135 51 +11143 7 136 51 +1114a 35 139 51 +1117f 6c 142 51 +111eb 10 143 51 +111fb a 130 51 +11205 2 145 51 +11207 1 145 51 +FUNC 11208 cf 0 MacFileUtilities::MachoID::UUIDCommand(int, unsigned char*) +11208 14 147 51 +1121c 25 149 51 +11241 7 151 51 +11248 19 152 51 +11261 9 153 51 +1126a 8 157 51 +11272 1f 158 51 +11291 9 159 51 +1129a 36 162 51 +112d0 7 163 51 +112d7 1 163 51 +FUNC 112d8 224 0 MacFileUtilities::MachoID::IDCommand(int, unsigned char*) +112d8 15 165 51 +112ed 25 167 51 +11312 7 169 51 +11319 19 170 51 +11332 c 171 51 +1133e c 175 51 +1134a 6 180 51 +11350 7 181 51 +11357 9 182 51 +11360 9 183 51 +11369 28 185 51 +11391 33 186 51 +113c4 1e 185 51 +113e2 10 189 51 +113f2 10 190 51 +11402 10 191 51 +11412 d 192 51 +1141f 10 193 51 +1142f 10 194 51 +1143f 10 195 51 +1144f d 196 51 +1145c 17 197 51 +11473 17 198 51 +1148a 17 199 51 +114a1 14 200 51 +114b5 9 202 51 +114be 36 205 51 +114f4 8 206 51 +FUNC 114fc d1 0 MacFileUtilities::MachoID::Adler32(int) +114fc 14 208 51 +11510 25 209 51 +11535 27 210 51 +1155c d 211 51 +11569 19 213 51 +11582 9 214 51 +1158b 3b 216 51 +115c6 7 217 51 +115cd 1 217 51 +FUNC 115ce f8 0 MacFileUtilities::MachoID::MD5(int, unsigned char*) +115ce 14 219 51 +115e2 25 220 51 +11607 27 221 51 +1162e 19 223 51 +11647 19 224 51 +11660 9 225 51 +11669 17 227 51 +11680 9 228 51 +11689 36 231 51 +116bf 7 232 51 +FUNC 116c6 f8 0 MacFileUtilities::MachoID::SHA1(int, unsigned char*) +116c6 14 234 51 +116da 25 235 51 +116ff 27 236 51 +11726 19 238 51 +1173f 19 239 51 +11758 9 240 51 +11761 17 242 51 +11778 9 243 51 +11781 36 246 51 +117b7 7 247 51 +FUNC 117be 378 0 MacFileUtilities::MachoID::WalkerCB(MacFileUtilities::MachoWalker*, load_command*, long long, bool, void*) +117be 2b 251 51 +117e9 6 252 51 +117ef e 254 51 +117fd 38 257 51 +11835 f 258 51 +11844 9 260 51 +1184d 17 261 51 +11864 20 266 51 +11884 f 267 51 +11893 d 271 51 +118a0 c 273 51 +118ac 38 274 51 +118e4 f 275 51 +118f3 9 277 51 +118fc 1f 278 51 +1191b 14 282 51 +1192f 2b 283 51 +1195a d 285 51 +11967 19 273 51 +11980 e 287 51 +1198e 38 290 51 +119c6 f 291 51 +119d5 9 293 51 +119de 17 294 51 +119f5 20 299 51 +11a15 f 300 51 +11a24 d 304 51 +11a31 c 306 51 +11a3d 38 307 51 +11a75 f 308 51 +11a84 9 310 51 +11a8d 1f 311 51 +11aac 1a 315 51 +11ac6 39 316 51 +11aff d 318 51 +11b0c 11 306 51 +11b1d 10 323 51 +11b2d 9 324 51 +FUNC 11b36 95 0 MacFileUtilities::MachoID::UUIDWalkerCB(MacFileUtilities::MachoWalker*, load_command*, long long, bool, void*) +11b36 1e 328 51 +11b54 a 329 51 +11b5e 6 331 51 +11b64 2f 333 51 +11b93 9 335 51 +11b9c 6 337 51 +11ba2 14 338 51 +11bb6 9 340 51 +11bbf a 344 51 +11bc9 2 345 51 +11bcb 1 345 51 +FUNC 11bcc 95 0 MacFileUtilities::MachoID::IDWalkerCB(MacFileUtilities::MachoWalker*, load_command*, long long, bool, void*) +11bcc 1e 349 51 +11bea a 350 51 +11bf4 6 351 51 +11bfa 2f 353 51 +11c29 9 354 51 +11c32 6 356 51 +11c38 14 357 51 +11c4c 9 359 51 +11c55 a 363 51 +11c5f 2 364 51 +11c61 1 364 51 +FUNC 11c62 1c 0 _OSSwapInt32 +11c62 f 53 55 +11c71 8 55 55 +11c79 3 56 55 +11c7c 2 57 55 +FUNC 11c7e 19 0 NXSwapInt +11c7e f 52 56 +11c8d 8 54 56 +11c95 2 55 56 +11c97 1 55 56 +FUNC 11c98 13 0 NXHostByteOrder +11c98 c 144 56 +11ca4 5 147 56 +11ca9 2 153 56 +11cab 1 153 56 +11cac c 52 54 +11cb8 12 54 54 +11cca 1a 55 54 +11ce4 2 56 54 +11ce6 c 52 54 +11cf2 12 54 54 +11d04 1a 55 54 +11d1e 2 56 54 +11d20 c 58 54 +11d2c a 59 54 +11d36 d 60 54 +11d43 2 61 54 +11d45 1 61 54 +11d46 c 58 54 +11d52 a 59 54 +11d5c d 60 54 +11d69 2 61 54 +11d6b 1 61 54 +FUNC 11d6c 37 0 MacFileUtilities::MachoWalker::ValidateCPUType(int) +11d6c c 63 54 +11d78 6 66 54 +11d7e 8 67 54 +11d86 6 68 54 +11d8c b 69 54 +11d97 7 74 54 +11d9e 3 80 54 +11da1 2 81 54 +11da3 1 81 54 +FUNC 11da4 50 0 MacFileUtilities::MachoWalker::ReadBytes(void*, unsigned long, long long) +11da4 18 96 54 +11dbc 36 97 54 +11df2 2 98 54 +FUNC 11df4 73 0 MacFileUtilities::MachoWalker::CurrentHeader(mach_header_64*, long long*) +11df4 c 100 54 +11e00 a 101 54 +11e0a 37 102 54 +11e41 11 103 54 +11e52 9 104 54 +11e5b a 107 54 +11e65 2 108 54 +11e67 1 108 54 +FUNC 11e68 2a6 0 MacFileUtilities::MachoWalker::FindHeader(int, long long&) +11e68 c 110 54 +11e74 15 111 54 +11e89 31 114 54 +11eba c 115 54 +11ec6 10 117 54 +11ed6 4 120 54 +11eda 14 121 54 +11eee 4 122 54 +11ef2 11 129 54 +11f03 28 124 54 +11f2b c 126 54 +11f37 31 133 54 +11f68 c 134 54 +11f74 14 136 54 +11f88 b 137 54 +11f93 8 139 54 +11f9b c 140 54 +11fa7 10 142 54 +11fb7 c 143 54 +11fc3 10 146 54 +11fd3 31 148 54 +12004 c 149 54 +12010 f 151 54 +1201f 14 152 54 +12033 16 154 54 +12049 c 158 54 +12055 31 159 54 +12086 9 160 54 +1208f f 162 54 +1209e 1c 163 54 +120ba 8 165 54 +120c2 10 166 54 +120d2 9 167 54 +120db 16 170 54 +120f1 11 158 54 +12102 a 174 54 +1210c 2 175 54 +FUNC 1210e 109 0 MacFileUtilities::MachoWalker::WalkHeaderCore(long long, unsigned int, bool) +1210e 1e 224 54 +1212c c 225 54 +12138 2f 227 54 +12167 c 228 54 +12173 6 230 54 +12179 14 231 54 +1218d 5b 234 54 +121e8 12 237 54 +121fa 11 225 54 +1220b a 240 54 +12215 2 241 54 +12217 1 241 54 +FUNC 12218 10e 0 MacFileUtilities::MachoWalker::WalkHeader64AtOffset(long long) +12218 18 203 54 +12230 2f 205 54 +1225f c 206 54 +1226b e 208 54 +12279 6 209 54 +1227f 14 210 54 +12293 9 212 54 +1229c a 213 54 +122a6 f 214 54 +122b5 15 215 54 +122ca 2b 216 54 +122f5 a 217 54 +122ff a 218 54 +12309 11 219 54 +1231a a 220 54 +12324 2 221 54 +FUNC 12326 143 0 MacFileUtilities::MachoWalker::WalkHeaderAtOffset(long long) +12326 18 177 54 +1233e 2f 179 54 +1236d c 180 54 +12379 e 182 54 +12387 6 183 54 +1238d 14 184 54 +123a1 2e 189 54 +123cf 7 190 54 +123d6 9 192 54 +123df a 193 54 +123e9 f 194 54 +123f8 15 195 54 +1240d 2b 196 54 +12438 a 197 54 +12442 a 198 54 +1244c 11 199 54 +1245d a 200 54 +12467 2 201 54 +12469 1 201 54 +FUNC 1246a 99 0 MacFileUtilities::MachoWalker::WalkHeader(int) +1246a c 83 54 +12476 15 84 54 +1248b 1d 86 54 +124a8 d 87 54 +124b5 21 88 54 +124d6 21 90 54 +124f7 a 93 54 +12501 2 94 54 +12503 1 94 54 +FUNC 12504 1c 0 _OSSwapInt32 +12504 f 53 55 +12513 8 55 55 +1251b 3 56 55 +1251e 2 57 55 +FUNC 12520 2b 0 _OSSwapInt64 +12520 12 64 55 +12532 11 69 55 +12543 6 70 55 +12549 2 71 55 +1254b 1 71 55 +FUNC 1254c 19 0 NXSwapLong +1254c f 61 56 +1255b 8 63 56 +12563 2 64 56 +12565 1 64 56 +FUNC 12566 1f 0 NXSwapLongLong +12566 12 70 56 +12578 b 72 56 +12583 2 73 56 +12585 1 73 56 +FUNC 12586 32 0 breakpad_swap_uuid_command(breakpad_uuid_command*, NXByteOrder) +12586 c 37 57 +12592 11 39 57 +125a3 13 40 57 +125b6 2 41 57 +FUNC 125b8 da 0 breakpad_swap_segment_command_64(segment_command_64*, NXByteOrder) +125b8 c 44 57 +125c4 11 46 57 +125d5 13 47 57 +125e8 17 49 57 +125ff 17 50 57 +12616 17 51 57 +1262d 17 52 57 +12644 13 54 57 +12657 13 55 57 +1266a 13 56 57 +1267d 13 57 57 +12690 2 58 57 +FUNC 12692 a4 0 breakpad_swap_mach_header_64(mach_header_64*, NXByteOrder) +12692 c 61 57 +1269e 11 63 57 +126af 13 64 57 +126c2 13 65 57 +126d5 13 66 57 +126e8 13 67 57 +126fb 13 68 57 +1270e 13 69 57 +12721 13 70 57 +12734 2 71 57 +FUNC 12736 1d1 0 breakpad_swap_section_64(section_64*, unsigned int, NXByteOrder) +12736 d 75 57 +12743 c 77 57 +1274f 33 78 57 +12782 33 79 57 +127b5 2d 81 57 +127e2 2d 82 57 +1280f 2d 83 57 +1283c 2d 84 57 +12869 2d 85 57 +12896 2d 86 57 +128c3 2d 87 57 +128f0 11 77 57 +12901 6 89 57 +12907 1 89 57 +12908 12 9 58 +1291a 4f 11 58 +12969 2 12 58 +1296b 1 12 58 +1296c 12 9 58 +1297e 4f 11 58 +129cd 2 12 58 +129cf 1 12 58 +129d0 13 14 58 +129e3 2a 14 58 +12a0d 1 14 58 +12a0e 13 14 58 +12a21 2a 14 58 +12a4b 1 14 58 +12a4c 13 14 58 +12a5f 2a 14 58 +12a89 1 14 58 +FUNC 12a8a bb 0 dwarf2reader::ByteReader::SetOffsetSize(unsigned char) +12a8a 19 16 58 +12aa3 a 17 58 +12aad 48 18 58 +12af5 6 19 58 +12afb 23 20 58 +12b1e 21 22 58 +12b3f 6 24 58 +12b45 1 24 58 +FUNC 12b46 bb 0 dwarf2reader::ByteReader::SetAddressSize(unsigned char) +12b46 19 26 58 +12b5f a 27 58 +12b69 48 28 58 +12bb1 6 29 58 +12bb7 23 30 58 +12bda 21 32 58 +12bfb 6 34 58 +12c01 1 34 58 +FUNC 12c02 a2 0 dwarf2reader::ByteReader::ReadFourBytes(char const*) const +12c02 c 24 59 +12c0e c 25 64 +12c1a d 26 64 +12c27 f 27 64 +12c36 f 28 64 +12c45 b 29 64 +12c50 27 30 64 +12c77 2b 32 64 +12ca2 2 34 64 +FUNC 12ca4 40e 0 dwarf2reader::ByteReader::ReadEightBytes(char const*) const +12ca4 11 36 59 +12cb5 1a 37 64 +12ccf 1b 38 64 +12cea 1d 39 64 +12d07 1d 40 64 +12d24 1d 41 64 +12d41 1d 42 64 +12d5e 1d 43 64 +12d7b 1d 44 64 +12d98 f 45 64 +12da7 18f 47 64 +12f36 172 50 64 +130a8 a 52 64 +130b2 2 52 64 +FUNC 130b4 a6 0 ReadInitialLength +130b4 15 29 60 +130c9 18 30 60 +130e1 6 31 60 +130e7 d 35 60 +130f4 13 36 60 +13107 9 37 60 +13110 1a 38 60 +1312a 13 40 60 +1313d 9 41 60 +13146 12 43 60 +13158 2 44 60 +1315a 1f 47 60 +13179 65 50 60 +131de 1f 47 60 +131fd 65 50 60 +FUNC 13262 393 0 dwarf2reader::CompilationUnit::SkipAttribute(char const*, dwarf2reader::DwarfForm) +13262 14 133 60 +13276 82 136 60 +132f8 1f 139 60 +13317 a 140 60 +13321 21 141 60 +13342 c 147 60 +1334e e 151 60 +1335c e 155 60 +1336a e 159 60 +13378 27 162 60 +1339f 1c 166 60 +133bb 10 167 60 +133cb 1c 171 60 +133e7 10 172 60 +133f7 1e 175 60 +13415 56 180 60 +1346b d 181 60 +13478 1e 182 60 +13496 11 183 60 +134a7 1e 184 60 +134c5 24 189 60 +134e9 26 192 60 +1350f 23 195 60 +13532 22 198 60 +13554 15 199 60 +13569 1b 203 60 +13584 30 206 60 +135b4 30 208 60 +135e4 a 209 60 +135ee 7 210 60 +135f5 1 210 60 +FUNC 135f6 29b 0 dwarf2reader::CompilationUnit::ReadHeader() +135f6 14 217 60 +1360a 9 218 60 +13613 4e 221 60 +13661 17 223 60 +13678 a 224 60 +13682 f 225 60 +13691 4e 227 60 +136df 1e 228 60 +136fd 6 229 60 +13703 5e 231 60 +13761 1e 232 60 +1377f 18 233 60 +13797 4c 235 60 +137e3 1d 236 60 +13800 1c 237 60 +1381c 5 238 60 +13821 9 240 60 +1382a 60 245 60 +1388a 7 247 60 +13891 1 247 60 +FUNC 13892 a57 0 dwarf2reader::CompilationUnit::ProcessAttribute(unsigned long long, char const*, dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm) +13892 24 299 60 +138b6 8a 302 60 +13940 1f 307 60 +1395f a 308 60 +13969 36 309 60 +1399f 5b 316 60 +139fa c 317 60 +13a06 5b 322 60 +13a61 e 323 60 +13a6f 55 328 60 +13ac4 e 329 60 +13ad2 55 334 60 +13b27 e 335 60 +13b35 6 338 60 +13b3b 9a 340 60 +13bd5 33 341 60 +13c08 25 340 60 +13c2d 5c 348 60 +13c89 10 349 60 +13c99 5c 354 60 +13cf5 10 355 60 +13d05 55 359 60 +13d5a 1e 360 60 +13d78 56 365 60 +13dce d 366 60 +13ddb 55 368 60 +13e30 1e 369 60 +13e4e 11 370 60 +13e5f 55 372 60 +13eb4 1e 373 60 +13ed2 29 378 60 +13efb 4a 380 60 +13f45 f 381 60 +13f54 29 385 60 +13f7d 4c 387 60 +13fc9 11 388 60 +13fda 1b 392 60 +13ff5 4c 394 60 +14041 11 395 60 +14052 22 399 60 +14074 4e 401 60 +140c2 15 402 60 +140d7 3c 406 60 +14113 1b 408 60 +1412e 54 409 60 +14182 f 411 60 +14191 9a 413 60 +1422b 24 414 60 +1424f 25 413 60 +14274 30 418 60 +142a4 30 420 60 +142d4 a 421 60 +142de b 422 60 +142e9 1 422 60 +142ea 1f 489 60 +14309 3a 491 60 +14343 a 492 60 +1434d 6 493 60 +14353 1 493 60 +14354 1f 489 60 +14373 3a 491 60 +143ad a 492 60 +143b7 6 493 60 +143bd 1 493 60 +FUNC 143be b5 0 dwarf2reader::CompilationUnit::ProcessDIE(unsigned long long, char const*, dwarf2reader::CompilationUnit::Abbrev const&) +143be 19 426 60 +143d7 13 427 60 +143ea 46 430 60 +14430 3a 427 60 +1446a 3 432 60 +1446d 6 433 60 +14473 1 433 60 +FUNC 14474 85 0 dwarf2reader::CompilationUnit::SkipDIE(char const*, dwarf2reader::CompilationUnit::Abbrev const&) +14474 c 122 60 +14480 13 123 60 +14493 27 126 60 +144ba 3a 123 60 +144f4 3 128 60 +144f7 2 129 60 +144f9 1 129 60 +FUNC 144fa be4 0 dwarf2reader::LineInfo::ProcessOneOpcode(dwarf2reader::ByteReader*, dwarf2reader::LineInfoHandler*, dwarf2reader::LineInfoHeader const&, char const*, dwarf2reader::LineStateMachine*, unsigned long*, unsigned long, bool*) +144fa 18 593 60 +14512 a 594 60 +1451c 18 596 60 +14534 8 597 60 +1453c 5 598 60 +14541 19 602 60 +1455a f 603 60 +14569 50 605 60 +145b9 46 607 60 +145ff e0 610 60 +146df 6 612 60 +146e5 22 615 60 +14707 22 616 60 +14729 7 617 60 +14730 b 618 60 +1473b f 619 60 +1474a 5a 623 60 +147a4 7 625 60 +147ab b 626 60 +147b6 f 627 60 +147c5 28 631 60 +147ed e 632 60 +147fb 144 635 60 +1493f 6 637 60 +14945 9e 640 60 +149e3 5 642 60 +149e8 22 644 60 +14a0a e 645 60 +14a18 1c 646 60 +14a34 2b 652 60 +14a5f b 653 60 +14a6a 22 658 60 +14a8c e 659 60 +14a9a 8 660 60 +14aa2 5 662 60 +14aa7 22 664 60 +14ac9 e 665 60 +14ad7 9 666 60 +14ae0 5 668 60 +14ae5 12 670 60 +14af7 5 672 60 +14afc 7 674 60 +14b03 5 676 60 +14b08 16 678 60 +14b1e 9 679 60 +14b27 d9 682 60 +14c00 6 684 60 +14c06 1f 687 60 +14c25 5 689 60 +14c2a 40 693 60 +14c6a d6 696 60 +14d40 6 698 60 +14d46 1c 701 60 +14d62 5 703 60 +14d67 1f 706 60 +14d86 d 707 60 +14d93 13 708 60 +14da6 26 710 60 +14dcc 5 711 60 +14dd1 50 713 60 +14e21 7 715 60 +14e28 b 716 60 +14e33 f 717 60 +14e42 18 725 60 +14e5a f 726 60 +14e69 5 728 60 +14e6e 6 730 60 +14e74 28 732 60 +14e9c d 733 60 +14ea9 22 735 60 +14ecb e 736 60 +14ed9 22 739 60 +14efb e 740 60 +14f09 22 743 60 +14f2b e 744 60 +14f39 a 746 60 +14f43 fd 748 60 +15040 a 758 60 +1504a 9 759 60 +15053 1c 761 60 +1506f d 762 60 +1507c e 763 60 +1508a 2e 759 60 +150b8 b 769 60 +150c3 10 770 60 +150d3 b 771 60 +FUNC 150de 14b 0 dwarf2reader::LineInfo::ReadLines() +150de e 773 60 +150ec 9 778 60 +150f5 17 782 60 +1510c 8 783 60 +15114 6 785 60 +1511a 9 787 60 +15123 5 788 60 +15128 19 789 60 +15141 5 790 60 +15146 4a 793 60 +15190 6 794 60 +15196 4a 796 60 +151e0 a 797 60 +151ea f 790 60 +151f9 15 788 60 +1520e 14 801 60 +15222 7 802 60 +15229 1 802 60 +FUNC 1522a 4fd 0 dwarf2reader::CompilationUnit::ReadAbbrevs() +1522a 18 60 60 +15242 e 61 60 +15250 58 65 60 +152a8 38 66 60 +152e0 44 65 60 +15324 2a 66 60 +1534e 45 68 60 +15393 16 69 60 +153a9 1d 75 60 +153c6 6 76 60 +153cc 40 77 60 +1540c b 80 60 +15417 1f 82 60 +15436 e 84 60 +15444 6 77 60 +1544a 1f 68 60 +15469 a 84 60 +15473 1d 79 60 +15490 6 86 60 +15496 a 87 60 +154a0 3d 89 60 +154dd 1f 90 60 +154fc a 91 60 +15506 6 92 60 +1550c 3d 94 60 +15549 1d 95 60 +15566 5 96 60 +1556b 3d 98 60 +155a8 1f 101 60 +155c7 a 102 60 +155d1 3d 104 60 +1560e 1f 105 60 +1562d a 106 60 +15637 c 107 60 +15643 6 111 60 +15649 6 112 60 +1564f 32 113 60 +15681 47 115 60 +156c8 30 116 60 +156f8 24 79 60 +1571c b 118 60 +15727 1 118 60 +FUNC 15728 5dc 0 dwarf2reader::LineInfo::ReadHeader() +15728 18 503 60 +15740 9 504 60 +15749 17 508 60 +15760 a 510 60 +1576a f 511 60 +15779 60 512 60 +157d9 44 516 60 +1581d 1e 518 60 +1583b 6 519 60 +15841 1e 521 60 +1585f 18 522 60 +15877 1d 524 60 +15894 5 525 60 +15899 20 527 60 +158b9 5 528 60 +158be c 530 60 +158ca 5 531 60 +158cf 1d 533 60 +158ec 5 534 60 +158f1 1d 536 60 +1590e 5 537 60 +15913 45 539 60 +15958 1f 540 60 +15977 19 541 60 +15990 15 542 60 +159a5 1f 539 60 +159c4 30 543 60 +159f4 5 544 60 +159f9 14 542 60 +15a0d e 548 60 +15a1b 7 549 60 +15a22 5 550 60 +15a27 6 551 60 +15a2d 8b 552 60 +15ab8 28 553 60 +15ae0 5 554 60 +15ae5 16 550 60 +15afb 25 552 60 +15b20 5 557 60 +15b25 e 560 60 +15b33 7 561 60 +15b3a 5 563 60 +15b3f 6 564 60 +15b45 28 565 60 +15b6d 22 567 60 +15b8f a 568 60 +15b99 22 570 60 +15bbb a 571 60 +15bc5 22 573 60 +15be7 a 574 60 +15bf1 ba 576 60 +15cab 5 577 60 +15cb0 16 563 60 +15cc6 25 576 60 +15ceb 5 580 60 +15cf0 9 582 60 +15cf9 b 583 60 +FUNC 15d04 3d 0 dwarf2reader::LineInfo::Start() +15d04 c 495 60 +15d10 b 496 60 +15d1b b 497 60 +15d26 19 498 60 +15d3f 2 499 60 +15d41 1 499 60 +FUNC 15d42 304 0 dwarf2reader::CompilationUnit::ProcessDIEs() +15d42 11 435 60 +15d53 9 436 60 +15d5c 9 441 60 +15d65 17 445 60 +15d7c 8 446 60 +15d84 6 448 60 +15d8a 6c 453 60 +15df6 8 455 60 +15dfe 16 453 60 +15e14 3 455 60 +15e17 2f 453 60 +15e46 29 458 60 +15e6f 22 460 60 +15e91 a 462 60 +15e9b a 465 60 +15ea5 1e 466 60 +15ec3 13 467 60 +15ed6 2b 468 60 +15f01 18 472 60 +15f19 9 473 60 +15f22 42 474 60 +15f64 1e 475 60 +15f82 2a 477 60 +15fac b 480 60 +15fb7 1e 481 60 +15fd5 26 483 60 +15ffb 1d 455 60 +16018 24 485 60 +1603c a 486 60 +FUNC 16046 35f 0 dwarf2reader::CompilationUnit::Start() +16046 18 249 60 +1605e 58 251 60 +160b6 35 252 60 +160eb 32 251 60 +1611d 2a 252 60 +16147 20 255 60 +16167 37 256 60 +1619e b 259 60 +161a9 f 264 60 +161b8 17 265 60 +161cf c 266 60 +161db a 268 60 +161e5 95 271 60 +1627a 11 276 60 +1628b b 279 60 +16296 58 282 60 +162ee 2f 283 60 +1631d 32 282 60 +1634f 14 284 60 +16363 1a 285 60 +1637d b 289 60 +16388 12 291 60 +1639a b 292 60 +163a5 1 292 60 +FUNC 163a6 3a 0 std::fill(unsigned char*, unsigned char*, unsigned char const&) +163a6 c 573 61 +163b2 9 576 61 +163bb 23 577 61 +163de 2 578 61 +FUNC 163e0 33 0 std::__deque_buf_size(unsigned long) +163e0 c 83 62 +163ec 27 84 62 +16413 1 84 62 +FUNC 16414 18 0 dwarf2reader::ByteReader::OffsetSize() const +16414 c 38 63 +16420 c 38 63 +FUNC 1642c 18 0 dwarf2reader::ByteReader::AddressSize() const +1642c c 41 63 +16438 c 41 63 +FUNC 16444 17 0 dwarf2reader::ByteReader::ReadOneByte(char const*) const +16444 c 10 64 +16450 9 11 64 +16459 2 12 64 +1645b 1 12 64 +FUNC 1645c 63 0 dwarf2reader::ByteReader::ReadTwoBytes(char const*) const +1645c c 14 64 +16468 d 15 64 +16475 e 16 64 +16483 b 17 64 +1648e 17 18 64 +164a5 18 20 64 +164bd 2 22 64 +164bf 1 22 64 +FUNC 164c0 98 0 dwarf2reader::ByteReader::ReadUnsignedLEB128(char const*, unsigned long*) const +164c0 e 59 64 +164ce e 60 64 +164dc 7 61 64 +164e3 7 62 64 +164ea e 66 64 +164f8 5 67 64 +164fd 38 69 64 +16535 6 71 64 +1653b 8 65 64 +16543 8 75 64 +1654b 6 77 64 +16551 7 78 64 +FUNC 16558 ee 0 dwarf2reader::ByteReader::ReadSignedLEB128(char const*, unsigned long*) const +16558 e 84 64 +16566 e 85 64 +16574 7 86 64 +1657b 7 87 64 +16582 e 91 64 +16590 5 92 64 +16595 44 93 64 +165d9 6 94 64 +165df 8 90 64 +165e7 14 97 64 +165fb 36 98 64 +16631 8 99 64 +16639 6 100 64 +1663f 7 101 64 +FUNC 16646 a2 0 dwarf2reader::ByteReader::ReadOffset(char const*) const +16646 13 103 64 +16659 3f 104 64 +16698 4a 105 64 +166e2 6 106 64 +FUNC 166e8 a2 0 dwarf2reader::ByteReader::ReadAddress(char const*) const +166e8 13 108 64 +166fb 3f 109 64 +1673a 4a 110 64 +16784 6 111 64 +FUNC 1678a 61 0 dwarf2reader::LineStateMachine::Reset(bool) +1678a 12 12 65 +1679c 9 13 65 +167a5 11 14 65 +167b6 11 15 65 +167c7 a 16 65 +167d1 a 17 65 +167db 7 18 65 +167e2 7 19 65 +167e9 2 20 65 +167eb 1 20 65 +FUNC 167ec 20 0 std::_List_const_iterator >::operator!=(std::_List_const_iterator > const&) const +167ec c 253 66 +167f8 14 254 66 +FUNC 1680c 25 0 std::_List_const_iterator >::operator++(int) +1680c c 226 66 +16818 8 228 66 +16820 c 229 66 +1682c 5 230 66 +16831 1 230 66 +FUNC 16832 16 0 std::_List_const_iterator >::operator->() const +16832 c 215 66 +1683e a 216 66 +16848 c 190 67 +16854 a 190 67 +FUNC 1685e 13 0 std::auto_ptr > > >::operator->() const +1685e c 283 67 +1686a 7 286 67 +16871 1 286 67 +16872 c 65 68 +1687e 2 65 68 +16880 c 97 69 +1688c d 97 69 +16899 1 97 69 +1689a c 99 69 +168a6 14 100 69 +168ba c 97 69 +168c6 d 97 69 +168d3 1 97 69 +168d4 c 84 70 +168e0 17 85 70 +168f7 1 85 70 +FUNC 168f8 2d 0 std::pair std::make_pair(dwarf2reader::DwarfAttribute, dwarf2reader::DwarfForm) +168f8 c 144 70 +16904 21 145 70 +16925 1 145 70 +16926 c 202 66 +16932 a 203 66 +FUNC 1693c 25 0 std::list, std::allocator > >::begin() const +1693c c 588 70 +16948 19 589 66 +16961 1 589 66 +FUNC 16962 23 0 std::list, std::allocator > >::end() const +16962 c 605 70 +1696e 17 606 66 +16985 1 606 66 +16986 c 65 68 +16992 2 65 68 +16994 c 72 68 +169a0 2 72 68 +169a2 c 97 69 +169ae d 97 69 +169bb 1 97 69 +169bc c 105 69 +169c8 d 105 69 +169d5 1 105 69 +169d6 c 105 69 +169e2 d 105 69 +169ef 1 105 69 +169f0 c 67 68 +169fc 2 67 68 +169fe c 99 69 +16a0a 14 100 69 +16a1e c 99 69 +16a2a 14 100 69 +16a3e c 129 62 +16a4a 30 131 62 +16a7a c 65 68 +16a86 2 65 68 +16a88 c 72 68 +16a94 2 72 68 +16a96 c 97 69 +16aa2 d 97 69 +16aaf 1 97 69 +16ab0 c 105 69 +16abc d 105 69 +16ac9 1 105 69 +16aca c 105 69 +16ad6 d 105 69 +16ae3 1 105 69 +16ae4 c 67 68 +16af0 2 67 68 +16af2 c 99 69 +16afe 14 100 69 +16b12 c 99 69 +16b1e 14 100 69 +FUNC 16b32 2b 0 std::_Vector_base >::get_allocator() const +16b32 10 93 71 +16b42 1b 94 71 +16b5d 1 94 71 +16b6a 7 614 72 +16b71 1 614 72 +16b72 c 80 71 +16b7e d 80 71 +16b8b 1 80 71 +16b98 2 107 68 +FUNC 16b9a 2d 0 void std::_Destroy >(unsigned char*, unsigned char*, std::allocator) +16b9a c 171 73 +16ba6 2 173 73 +16ba8 12 174 73 +16bba b 173 73 +16bc5 2 174 73 +16bc7 1 174 73 +16bc8 c 84 71 +16bd4 2f 85 71 +16c03 2 86 71 +16c05 1 86 71 +16c06 c 96 71 +16c12 12 97 71 +16c24 2 98 71 +FUNC 16c26 1f 0 std::_List_base, std::allocator > >::_M_init() +16c26 c 338 73 +16c32 8 340 66 +16c3a b 341 66 +16c45 1 341 66 +16c46 c 105 69 +16c52 d 105 69 +16c5f 1 105 69 +16c60 c 125 66 +16c6c a 126 66 +FUNC 16c76 25 0 std::list, std::allocator > >::begin() +16c76 c 579 73 +16c82 19 580 66 +16c9b 1 580 66 +FUNC 16c9c 23 0 std::list, std::allocator > >::end() +16c9c c 597 73 +16ca8 17 597 66 +16cbf 1 597 66 +16cc0 c 603 72 +16ccc c 603 72 +FUNC 16cd8 2b 0 std::vector >::begin() const +16cd8 c 342 73 +16ce4 1f 343 71 +16d03 1 343 71 +FUNC 16d04 2c 0 std::vector >::end() const +16d04 c 360 73 +16d10 20 361 71 +16d3c 5 666 72 +16d41 1 666 72 +16d4f 31 759 72 +FUNC 16d80 3c 0 std::vector >::size() const +16d80 c 402 73 +16d8c 30 403 71 +16dbc c 603 72 +16dc8 c 603 72 +FUNC 16dd4 23 0 std::vector >::begin() +16dd4 c 333 73 +16de0 17 334 71 +16df7 1 334 71 +16e04 33 654 72 +16e37 1 654 72 +FUNC 16e38 26 0 std::vector >::end() +16e38 c 351 73 +16e44 1a 352 71 +16e6a 7 614 72 +16e71 1 614 72 +FUNC 16e72 42 0 std::vector >::operator[](unsigned long) +16e72 c 494 73 +16e7e 36 495 71 +FUNC 16eb4 13 0 std::vector >::max_size() const +16eb4 c 407 73 +16ec0 7 408 71 +16ec7 1 408 71 +16ed4 5 666 72 +16ed9 1 666 72 +16ee6 d 623 72 +16ef3 5 624 72 +16ef8 c 382 62 +16f04 d 382 62 +16f11 1 382 62 +FUNC 16f12 2b 0 std::_Deque_base >::get_allocator() const +16f12 10 360 73 +16f22 1b 361 62 +16f3d 1 361 62 +FUNC 16f3e 2d 0 std::deque >::get_allocator() const +16f3e 10 764 73 +16f4e 1d 765 62 +16f6b 1 765 62 +FUNC 16f6c 13 0 std::_Deque_iterator::operator*() const +16f6c c 134 73 +16f78 7 135 62 +16f7f 1 135 62 +16f8c 2 107 68 +16f8e c 129 62 +16f9a 30 131 62 +FUNC 16fca 2c 0 std::deque >::end() const +16fca 10 799 73 +16fda 1c 800 62 +FUNC 16ff6 2c 0 std::deque >::begin() const +16ff6 10 781 73 +17006 1c 782 62 +FUNC 17022 2e 0 std::deque >::end() +17022 10 790 73 +17032 1e 791 62 +FUNC 17050 3c 0 std::vector >::_M_range_check(unsigned long) const +17050 13 515 73 +17063 15 517 71 +17078 14 518 71 +FUNC 1708c 32 0 std::vector >::at(unsigned long) +1708c c 534 73 +17098 12 536 71 +170aa 14 537 71 +170ca 2e 104 68 +170f8 c 84 71 +17104 2f 85 71 +17133 2 86 71 +17135 1 86 71 +17136 c 96 71 +17142 12 97 71 +17154 2 98 71 +17156 c 603 72 +17162 c 603 72 +FUNC 1716e 23 0 std::vector >::begin() +1716e c 333 73 +1717a 17 334 71 +17191 1 334 71 +1719e 27 654 72 +171c5 1 654 72 +FUNC 171c6 42 0 std::vector >::operator[](unsigned long) +171c6 c 494 73 +171d2 36 495 71 +FUNC 17208 26 0 std::vector >::end() +17208 c 351 73 +17214 1a 352 71 +1723a d 94 68 +17247 1 94 68 +FUNC 17248 2f 0 std::_Vector_base >::_M_deallocate(unsigned char*, unsigned long) +17248 c 120 73 +17254 6 122 71 +1725a 1d 123 71 +17277 1 123 71 +17278 c 108 71 +17284 3a 109 71 +172be c 188 71 +172ca 12 189 71 +172dc 2 190 71 +172de c 272 71 +172ea 4b 273 71 +17335 1 273 71 +17336 13 62 74 +17349 10 62 74 +17359 a 63 74 +17363 25 64 74 +17388 1a 66 74 +173a2 13 62 74 +173b5 10 62 74 +173c5 a 63 74 +173cf 25 64 74 +173f4 1a 66 74 +1740e c 188 71 +1741a 12 189 71 +1742c 2 190 71 +1743b 31 759 72 +1746c c 65 68 +17478 2 65 68 +1747a c 103 69 +17486 d 103 69 +17493 1 103 69 +FUNC 17494 2d 0 std::list, std::allocator > >::get_allocator() const +17494 10 570 74 +174a4 1d 571 66 +174c1 1 571 66 +174ce 2e 104 68 +FUNC 174fc 20 0 std::_List_iterator >::operator!=(std::_List_iterator > const&) const +174fc c 172 74 +17508 14 173 66 +FUNC 1751c 1d 0 std::_List_const_iterator >::operator++() +1751c c 219 74 +17528 c 221 66 +17534 5 222 66 +17539 1 222 66 +FUNC 1753a 1d 0 std::_List_iterator >::operator++() +1753a c 138 74 +17546 c 140 66 +17552 5 141 66 +17557 1 141 66 +FUNC 17558 16 0 std::_List_const_iterator >::operator*() const +17558 c 211 74 +17564 a 212 66 +FUNC 1756e 16 0 std::_List_iterator >::operator*() const +1756e c 130 74 +1757a a 131 66 +FUNC 17584 20 0 std::_List_const_iterator >::operator==(std::_List_const_iterator > const&) const +17584 c 249 74 +17590 14 250 66 +FUNC 175a4 35 0 bool __gnu_cxx::operator!= > >(__gnu_cxx::__normal_iterator > > const&, __gnu_cxx::__normal_iterator > > const&) +175a4 d 699 74 +175b1 28 700 72 +175d9 1 700 72 +FUNC 175da 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator > >, std::allocator >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, std::allocator) +175da c 171 74 +175e6 2 173 73 +175e8 1a 174 73 +17602 21 173 73 +17623 2 174 73 +17625 1 174 73 +17626 c 127 62 +17632 29 127 62 +1765b 1 127 62 +1765c c 388 62 +17668 41 389 62 +176a9 2 390 62 +176ab 1 390 62 +176b8 d 94 68 +176c5 1 94 68 +FUNC 176c6 20 0 bool std::operator==(std::_Deque_iterator const&, std::_Deque_iterator const&) +176c6 c 243 74 +176d2 14 244 62 +FUNC 176e6 26 0 bool std::operator!=(std::_Deque_iterator const&, std::_Deque_iterator const&) +176e6 c 256 74 +176f2 1a 257 62 +FUNC 1770c 1a 0 std::_Deque_iterator::_S_buffer_size() +1770c c 106 74 +17718 e 107 62 +FUNC 17726 3e 0 std::_Deque_iterator::_M_set_node(unsigned long long**) +17726 d 229 74 +17733 9 231 62 +1773c b 232 62 +17747 1d 233 62 +FUNC 17764 50 0 std::_Deque_iterator::operator++() +17764 c 142 74 +17770 d 144 62 +1777d f 145 62 +1778c 18 147 62 +177a4 b 148 62 +177af 5 150 62 +FUNC 177b4 4b 0 void std::_Destroy, std::allocator >(std::_Deque_iterator, std::_Deque_iterator, std::allocator) +177b4 c 171 74 +177c0 2 173 73 +177c2 1a 174 73 +177dc 21 173 73 +177fd 2 174 73 +177ff 1 174 73 +FUNC 17800 50 0 std::_Deque_iterator::operator--() +17800 c 162 74 +1780c f 164 62 +1781b 18 166 62 +17833 b 167 62 +1783e d 169 62 +1784b 5 170 62 +FUNC 17850 39 0 std::deque >::back() +17850 c 988 74 +1785c 15 990 62 +17871 b 991 62 +1787c d 992 62 +17889 1 992 62 +FUNC 1788a 19 0 std::stack > >::top() +1788a c 163 75 +17896 d 166 75 +178a3 1 166 75 +FUNC 178a4 66 0 std::_Deque_iterator::difference_type std::operator-(std::_Deque_iterator const&, std::_Deque_iterator const&) +178a4 d 328 75 +178b1 59 333 62 +FUNC 1790a 26 0 std::deque >::size() const +1790a c 840 75 +17916 1a 841 62 +1793c 36 662 72 +1797e 23 650 72 +179a1 1 650 72 +179a2 c 67 68 +179ae 2 67 68 +179b0 c 99 69 +179bc 14 100 69 +179d0 c 303 66 +179dc 12 304 66 +179ee 2 305 66 +179f0 c 326 66 +179fc 2f 327 66 +17a2b d 328 66 +17a38 c 457 66 +17a44 14 458 66 +17a58 c 211 74 +17a64 2d 211 74 +17a91 1 211 74 +17a9e 7 98 68 +17aa5 1 98 68 +17ab2 1d 85 68 +17acf 5 86 68 +17ad4 17 88 68 +17aeb 1 88 68 +FUNC 17aec 2a 0 std::_Vector_base >::_M_allocate(unsigned long) +17aec c 116 75 +17af8 1e 117 71 +17b22 d 94 68 +17b2f 1 94 68 +FUNC 17b30 34 0 std::_Deque_base >::_M_deallocate_node(unsigned long long*) +17b30 c 402 75 +17b3c 28 403 62 +FUNC 17b64 38 0 std::_Deque_base >::_M_destroy_nodes(unsigned long long**, unsigned long long**) +17b64 c 504 75 +17b70 8 506 62 +17b78 14 507 62 +17b8c e 506 62 +17b9a 2 507 62 +FUNC 17b9c 62 0 std::deque >::_M_pop_back_aux() +17b9c c 391 76 +17ba8 15 393 76 +17bbd 1b 394 76 +17bd8 f 395 76 +17be7 17 396 76 +FUNC 17bfe 4f 0 std::deque >::pop_back() +17bfe c 1081 76 +17c0a 10 1083 62 +17c1a f 1086 62 +17c29 17 1087 62 +17c40 d 1090 62 +17c4d 1 1090 62 +FUNC 17c4e 19 0 std::stack > >::pop() +17c4e c 205 76 +17c5a d 208 75 +17c67 1 208 75 +17c68 c 72 68 +17c74 2 72 68 +17c76 c 105 69 +17c82 d 105 69 +17c8f 1 105 69 +17c90 c 603 72 +17c9c c 603 72 +FUNC 17ca8 2b 0 std::vector >::begin() const +17ca8 c 342 76 +17cb4 1f 343 71 +17cd3 1 343 71 +FUNC 17cd4 2c 0 std::vector >::end() const +17cd4 c 360 76 +17ce0 20 361 71 +17d0c 5 666 72 +17d11 1 666 72 +17d1f 28 759 72 +17d47 1 759 72 +FUNC 17d48 3c 0 std::vector >::size() const +17d48 c 402 76 +17d54 30 403 71 +17d90 d 623 72 +17d9d 5 624 72 +17dae 5 666 72 +17db3 1 666 72 +FUNC 17db4 35 0 bool __gnu_cxx::operator!= > >(__gnu_cxx::__normal_iterator > > const&, __gnu_cxx::__normal_iterator > > const&) +17db4 d 699 76 +17dc1 28 700 72 +17de9 1 700 72 +FUNC 17dea 4b 0 void std::_Destroy<__gnu_cxx::__normal_iterator > >, std::allocator >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, std::allocator) +17dea c 171 76 +17df6 2 173 73 +17df8 1a 174 73 +17e12 21 173 73 +17e33 2 174 73 +17e35 1 174 73 +17e43 28 759 72 +17e6b 1 759 72 +17e78 2a 662 72 +FUNC 17ea2 13 0 std::vector >::max_size() const +17ea2 c 407 76 +17eae 7 408 71 +17eb5 1 408 71 +17ec2 16 650 72 +17ee4 7 98 68 +17eeb 1 98 68 +17ef8 1d 85 68 +17f15 5 86 68 +17f1a 10 88 68 +FUNC 17f2a 29 0 std::_List_base, std::allocator > >::_M_get_node() +17f2a c 311 76 +17f36 1d 312 66 +17f53 1 312 66 +FUNC 17f54 5f 0 std::list, std::allocator > >::_M_create_node(std::pair const&) +17f54 d 435 76 +17f61 e 437 66 +17f6f 3c 440 66 +17fab 8 447 66 +17fb3 1 447 66 +FUNC 17fb4 35 0 std::list, std::allocator > >::_M_insert(std::_List_iterator >, std::pair const&) +17fb4 c 1149 76 +17fc0 15 1151 66 +17fd5 14 1152 66 +17fe9 1 1152 66 +FUNC 17fea 52 0 void std::list, std::allocator > >::_M_insert_dispatch > >(std::_List_iterator >, std::_List_const_iterator >, std::_List_const_iterator >, __false_type) +17fea c 1126 66 +17ff6 2 1128 66 +17ff8 21 1129 66 +18019 21 1128 66 +1803a 2 1129 66 +FUNC 1803c 36 0 void std::list, std::allocator > >::insert > >(std::_List_iterator >, std::_List_const_iterator >, std::_List_const_iterator >) +1803c c 838 66 +18048 2a 842 66 +18072 e 491 66 +18080 32 492 66 +180b2 64 493 66 +18116 c 211 74 +18122 3d 211 74 +1815f 1 211 74 +1816d 5c 104 68 +181c9 1 104 68 +FUNC 181ca 31 0 std::list, std::allocator > >::push_back(std::pair const&) +181ca c 772 76 +181d6 25 773 66 +181fb 1 773 66 +FUNC 181fc 69 0 void std::_Construct(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev const&) +181fc d 77 76 +18209 5c 81 73 +18265 1 81 73 +18272 7 98 68 +18279 1 98 68 +18286 1d 85 68 +182a3 5 86 68 +182a8 10 88 68 +182b8 c 65 68 +182c4 2 65 68 +182c6 c 103 69 +182d2 d 103 69 +182df 1 103 69 +FUNC 182e0 4d 0 std::_Deque_base >::_M_get_map_allocator() const +182e0 11 394 76 +182f1 3c 395 62 +1832d 1 395 62 +FUNC 1832e 75 0 std::_Deque_base >::_M_allocate_map(unsigned long) +1832e d 406 76 +1833b 68 407 62 +183a3 1 407 62 +FUNC 183a4 47 0 std::_Deque_base >::_M_deallocate_map(unsigned long long**, unsigned long) +183a4 c 410 76 +183b0 3b 411 62 +183eb 1 411 62 +183ec c 424 62 +183f8 9 426 62 +18401 22 428 62 +18423 2b 430 62 +1844e c 714 62 +1845a 70 715 62 +184ca c 111 75 +184d6 d 111 75 +184e3 1 111 75 +184e4 c 259 67 +184f0 26 259 67 +18522 7 98 68 +18529 1 98 68 +18536 1d 85 68 +18553 5 86 68 +18558 10 88 68 +FUNC 18568 33 0 std::_Deque_base >::_M_allocate_node() +18568 c 398 76 +18574 27 399 62 +1859b 1 399 62 +FUNC 1859c 82 0 std::_Deque_base >::_M_create_nodes(unsigned long long**, unsigned long long**) +1859c d 486 76 +185a9 8 491 62 +185b1 12 492 62 +185c3 13 491 62 +185d6 b 494 62 +185e1 19 496 62 +185fa b 497 62 +18605 13 494 62 +18618 6 497 62 +FUNC 1861e 17b 0 std::_Deque_base >::_M_initialize_map(unsigned long) +1861e d 447 76 +1862b 1e 450 62 +18649 2a 452 62 +18673 1c 454 62 +1868f 19 462 62 +186a8 c 463 62 +186b4 1e 466 62 +186d2 b 467 62 +186dd 1e 469 62 +186fb 9 470 62 +18704 a 471 62 +1870e b 472 62 +18719 13 467 62 +1872c 15 475 62 +18741 18 476 62 +18759 c 477 62 +18765 34 478 62 +18799 1 478 62 +1879a d 366 62 +187a7 12 367 62 +187b9 39 368 62 +187f2 c 645 62 +187fe 1c 646 62 +FUNC 1881a 4d 0 void std::__fill::fill<__gnu_cxx::__normal_iterator > >, unsigned char>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char const&) +1881a c 539 61 +18826 9 541 61 +1882f 2 542 61 +18831 13 543 61 +18844 21 542 61 +18865 2 543 61 +18867 1 543 61 +FUNC 18868 2b 0 void std::fill<__gnu_cxx::__normal_iterator > >, unsigned char>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char const&) +18868 c 560 76 +18874 4 567 61 +18878 1b 568 61 +18893 1 568 61 +FUNC 18894 6a 0 std::list, std::allocator > >::_M_erase(std::_List_iterator >) +18894 d 1157 76 +188a1 b 1159 66 +188ac 6 1160 66 +188b2 35 1161 66 +188e7 17 1162 66 +FUNC 188fe 37 0 std::list, std::allocator > >::erase(std::_List_iterator >) +188fe c 95 77 +1890a 14 97 77 +1891e 12 98 77 +18930 5 99 77 +18935 1 99 77 +FUNC 18936 3e 0 std::list, std::allocator > >::erase(std::_List_iterator >, std::_List_iterator >) +18936 c 883 77 +18942 2 885 66 +18944 15 886 66 +18959 16 885 66 +1896f 5 887 66 +FUNC 18974 129 0 std::list, std::allocator > >::operator=(std::list, std::allocator > > const&) +18974 e 120 77 +18982 c 122 77 +1898e e 124 77 +1899c e 125 77 +189aa e 126 77 +189b8 e 127 77 +189c6 2 128 77 +189c8 20 130 77 +189e8 5a 128 77 +18a42 16 131 77 +18a58 1b 132 77 +18a73 20 134 77 +18a93 a 136 77 +18a9d 1 136 77 +FUNC 18a9e 4c 0 dwarf2reader::CompilationUnit::Abbrev::operator=(dwarf2reader::CompilationUnit::Abbrev const&) +18a9e c 211 77 +18aaa 40 211 74 +FUNC 18aea 52 0 dwarf2reader::CompilationUnit::Abbrev* std::__copy::copy(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +18aea c 280 61 +18af6 1a 283 61 +18b10 12 285 61 +18b22 4 286 61 +18b26 6 287 61 +18b2c b 283 61 +18b37 5 289 61 +FUNC 18b3c 2b 0 dwarf2reader::CompilationUnit::Abbrev* std::__copy_aux(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +18b3c c 307 77 +18b48 4 315 61 +18b4c 1b 317 61 +18b67 1 317 61 +18b76 56 354 61 +18bd8 4 384 61 +18bdc 4 385 61 +18be0 1b 387 61 +18bfb 1 387 61 +FUNC 18bfc ac 0 std::vector >::erase(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) +18bfc d 122 78 +18c09 26 124 78 +18c2f 43 125 78 +18c72 2e 126 78 +18ca0 8 127 78 +FUNC 18ca8 54 0 dwarf2reader::CompilationUnit::Abbrev* std::__copy_backward::copy_b(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +18ca8 c 408 61 +18cb4 1a 411 61 +18cce 1e 412 61 +18cec b 411 61 +18cf7 5 413 61 +FUNC 18cfc 2b 0 dwarf2reader::CompilationUnit::Abbrev* std::__copy_backward_aux(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +18cfc c 432 78 +18d08 4 440 61 +18d0c 1b 443 61 +18d27 1 443 61 +18d36 56 482 61 +18d98 4 514 61 +18d9c 4 515 61 +18da0 1b 517 61 +18dbb 1 517 61 +FUNC 18dbc 4d 0 void std::__fill::fill<__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev const&) +18dbc c 526 61 +18dc8 2 528 61 +18dca 1c 529 61 +18de6 21 528 61 +18e07 2 529 61 +18e09 1 529 61 +FUNC 18e0a 2b 0 void std::fill<__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev const&) +18e0a c 560 78 +18e16 4 567 61 +18e1a 1b 568 61 +18e35 1 568 61 +FUNC 18e36 3f 0 unsigned char* std::__copy::copy(unsigned char const*, unsigned char const*, unsigned char*) +18e36 c 298 61 +18e42 22 300 61 +18e64 11 301 61 +18e75 1 301 61 +FUNC 18e76 2b 0 unsigned char* std::__copy_aux(unsigned char*, unsigned char*, unsigned char*) +18e76 c 307 78 +18e82 4 315 61 +18e86 1b 317 61 +18ea1 1 317 61 +18eb0 56 354 61 +18f12 4 384 61 +18f16 4 385 61 +18f1a 1b 387 61 +18f35 1 387 61 +FUNC 18f36 a0 0 std::vector >::erase(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) +18f36 d 122 78 +18f43 26 124 78 +18f69 43 125 78 +18fac 22 126 78 +18fce 8 127 78 +18fe2 7 98 68 +18fe9 1 98 68 +18ff6 1d 85 68 +19013 5 86 68 +19018 d 88 68 +19025 1 88 68 +FUNC 19026 2a 0 std::_Vector_base >::_M_allocate(unsigned long) +19026 c 116 78 +19032 1e 117 71 +1905c 1b 74 79 +19077 1 74 79 +19084 23 113 79 +190a7 1 113 79 +190b4 1b 254 79 +190cf 1 254 79 +FUNC 190d0 19 0 void std::_Destroy(dwarf2reader::CompilationUnit::Abbrev*) +190d0 c 106 79 +190dc d 107 73 +190e9 1 107 73 +FUNC 190ea 44 0 void std::__destroy_aux<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, __false_type) +190ea c 119 79 +190f6 2 121 73 +190f8 13 122 73 +1910b 21 121 73 +1912c 2 122 73 +FUNC 1912e 28 0 void std::_Destroy<__gnu_cxx::__normal_iterator > > >(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >) +1912e c 148 79 +1913a 1c 155 73 +FUNC 19156 8d 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&, __false_type) +19156 d 188 79 +19163 6 190 79 +19169 2 193 79 +1916b 1c 194 79 +19187 1b 193 79 +191a2 b 196 79 +191ad 12 198 79 +191bf b 199 79 +191ca 13 196 79 +191dd 6 199 79 +191e3 1 199 79 +FUNC 191e4 2f 0 void std::uninitialized_fill_n<__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&) +191e4 c 214 79 +191f0 23 218 79 +19213 1 218 79 +FUNC 19214 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&, std::allocator) +19214 c 308 79 +19220 1b 310 79 +1923b 1 310 79 +19249 6 82 79 +1924f 2 85 79 +19251 24 86 79 +19275 2c 85 79 +192a1 b 87 79 +192ac b 89 79 +192b7 12 91 79 +192c9 b 92 79 +192d4 13 89 79 +192e7 9 92 79 +192fc 23 113 79 +1931f 1 113 79 +1932c 1b 254 79 +19347 1 254 79 +FUNC 19348 409 0 std::vector >::_M_insert_aux(__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev const&) +19348 14 249 79 +1935c 14 251 78 +19370 22 253 78 +19392 f 255 78 +193a1 12 256 78 +193b3 55 257 78 +19408 4b 260 78 +19453 e 264 78 +19461 15 265 78 +19476 e 266 78 +19484 1d 271 78 +194a1 8 272 78 +194a9 e 273 78 +194b7 27 275 78 +194de 6 276 78 +194e4 55 279 78 +19539 25 284 78 +1955e b 285 78 +19569 4f 286 78 +195b8 3 284 78 +195bb 13 279 78 +195ce e 286 78 +195dc 4d 298 78 +19629 36 299 78 +1965f 12 302 78 +19671 13 303 78 +19684 2e 304 78 +196b2 13 286 78 +196c5 b 292 78 +196d0 39 294 78 +19709 23 295 78 +1972c b 296 78 +19737 13 292 78 +1974a 7 304 78 +19751 1 304 78 +FUNC 19752 70 0 std::vector >::push_back(dwarf2reader::CompilationUnit::Abbrev const&) +19752 c 602 79 +1975e 10 604 71 +1976e 1e 606 71 +1978c 11 607 71 +1979d 25 610 71 +FUNC 197c2 50 0 unsigned char* std::__copy_backward::copy_b(unsigned char const*, unsigned char const*, unsigned char*) +197c2 d 422 61 +197cf f 424 61 +197de 24 425 61 +19802 10 426 61 +FUNC 19812 2b 0 unsigned char* std::__copy_backward_aux(unsigned char*, unsigned char*, unsigned char*) +19812 c 432 79 +1981e 4 440 61 +19822 1b 443 61 +1983d 1 443 61 +1984c 56 482 61 +198ae 4 514 61 +198b2 4 515 61 +198b6 1b 517 61 +198d1 1 517 61 +FUNC 198d2 32 0 unsigned char* std::fill_n(unsigned char*, unsigned long, unsigned char const&) +198d2 c 647 79 +198de 1e 649 61 +198fc 8 650 61 +FUNC 19904 27 0 void std::__uninitialized_fill_n_aux(unsigned char*, unsigned long, unsigned char const&, __true_type) +19904 c 182 79 +19910 1b 183 79 +1992b 1 183 79 +FUNC 1992c 2f 0 void std::uninitialized_fill_n(unsigned char*, unsigned long, unsigned char const&) +1992c c 214 79 +19938 23 218 79 +1995b 1 218 79 +FUNC 1995c 27 0 void std::__uninitialized_fill_n_a(unsigned char*, unsigned long, unsigned char const&, std::allocator) +1995c c 308 79 +19968 1b 310 79 +19983 1 310 79 +FUNC 19984 27 0 void std::__destroy_aux(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, __false_type) +19984 c 119 79 +19990 2 121 73 +19992 b 122 73 +1999d c 121 73 +199a9 2 122 73 +199ab 1 122 73 +FUNC 199ac 28 0 void std::_Destroy(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +199ac c 148 79 +199b8 1c 155 73 +FUNC 199d4 88 0 dwarf2reader::CompilationUnit::Abbrev* std::__uninitialized_copy_aux(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, __false_type) +199d4 d 80 79 +199e1 6 82 79 +199e7 2 85 79 +199e9 12 86 79 +199fb 12 85 79 +19a0d b 87 79 +19a18 b 89 79 +19a23 12 91 79 +19a35 b 92 79 +19a40 13 89 79 +19a53 9 92 79 +FUNC 19a5c 2f 0 dwarf2reader::CompilationUnit::Abbrev* std::uninitialized_copy(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*) +19a5c c 108 79 +19a68 23 113 79 +19a8b 1 113 79 +FUNC 19a8c 27 0 dwarf2reader::CompilationUnit::Abbrev* std::__uninitialized_copy_a(dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev*, std::allocator) +19a8c c 252 79 +19a98 1b 254 79 +19ab3 1 254 79 +FUNC 19ab4 7e 0 void std::__uninitialized_fill_n_aux(dwarf2reader::CompilationUnit::Abbrev*, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&, __false_type) +19ab4 d 188 79 +19ac1 6 190 79 +19ac7 2 193 79 +19ac9 12 194 79 +19adb 16 193 79 +19af1 b 196 79 +19afc 12 198 79 +19b0e b 199 79 +19b19 13 196 79 +19b2c 6 199 79 +FUNC 19b32 2f 0 void std::uninitialized_fill_n(dwarf2reader::CompilationUnit::Abbrev*, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&) +19b32 c 214 79 +19b3e 23 218 79 +19b61 1 218 79 +FUNC 19b62 27 0 void std::__uninitialized_fill_n_a(dwarf2reader::CompilationUnit::Abbrev*, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&, std::allocator) +19b62 c 308 79 +19b6e 1b 310 79 +19b89 1 310 79 +FUNC 19b8a a5 0 dwarf2reader::CompilationUnit::Abbrev* std::__uninitialized_copy_aux<__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*, __false_type) +19b8a d 80 79 +19b97 6 82 79 +19b9d 2 85 79 +19b9f 1a 86 79 +19bb9 27 85 79 +19be0 b 87 79 +19beb b 89 79 +19bf6 12 91 79 +19c08 b 92 79 +19c13 13 89 79 +19c26 9 92 79 +19c2f 1 92 79 +FUNC 19c30 2f 0 dwarf2reader::CompilationUnit::Abbrev* std::uninitialized_copy<__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*) +19c30 c 108 79 +19c3c 23 113 79 +19c5f 1 113 79 +FUNC 19c60 27 0 dwarf2reader::CompilationUnit::Abbrev* std::__uninitialized_copy_a<__gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*, dwarf2reader::CompilationUnit::Abbrev>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, dwarf2reader::CompilationUnit::Abbrev*, std::allocator) +19c60 c 252 79 +19c6c 1b 254 79 +19c87 1 254 79 +FUNC 19c88 5f8 0 std::vector >::_M_fill_insert(__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&) +19c88 15 311 79 +19c9d b 313 78 +19ca8 2a 315 78 +19cd2 12 318 78 +19ce4 23 319 78 +19d07 15 320 78 +19d1c c 321 78 +19d28 5a 323 78 +19d82 1c 327 78 +19d9e 35 328 78 +19dd3 16 323 78 +19de9 30 330 78 +19e19 10 343 78 +19e29 48 334 78 +19e71 21 338 78 +19e92 3d 339 78 +19ecf 13 334 78 +19ee2 b 339 78 +19eed 1c 342 78 +19f09 1e 343 78 +19f27 13 339 78 +19f3a 24 343 78 +19f5e e 348 78 +19f6c 1e 349 78 +19f8a e 350 78 +19f98 1d 353 78 +19fb5 8 354 78 +19fbd e 355 78 +19fcb 27 357 78 +19ff2 6 358 78 +19ff8 4d 361 78 +1a045 40 365 78 +1a085 18 367 78 +1a09d 44 368 78 +1a0e1 3 365 78 +1a0e4 19 361 78 +1a0fd 13 365 78 +1a110 e 368 78 +1a11e 3e 379 78 +1a15c 36 381 78 +1a192 12 384 78 +1a1a4 13 385 78 +1a1b7 2e 386 78 +1a1e5 e 368 78 +1a1f3 b 372 78 +1a1fe 39 374 78 +1a237 23 376 78 +1a25a b 377 78 +1a265 13 372 78 +1a278 8 386 78 +FUNC 1a280 2e 0 std::vector >::insert(__gnu_cxx::__normal_iterator > >, unsigned long, dwarf2reader::CompilationUnit::Abbrev const&) +1a280 c 657 79 +1a28c 22 658 71 +FUNC 1a2ae ab 0 std::vector >::resize(unsigned long, dwarf2reader::CompilationUnit::Abbrev const&) +1a2ae d 422 79 +1a2bb 15 424 71 +1a2d0 48 425 71 +1a318 41 427 71 +1a359 1 427 71 +FUNC 1a35a 63 0 std::vector >::resize(unsigned long) +1a35a d 441 79 +1a367 56 442 71 +1a3bd 1 442 71 +FUNC 1a3be 13 0 std::_Deque_iterator::operator*() const +1a3be c 134 79 +1a3ca 7 135 62 +1a3d1 1 135 62 +FUNC 1a3d2 3f 0 unsigned long long** std::__copy::copy(unsigned long long* const*, unsigned long long* const*, unsigned long long**) +1a3d2 c 298 61 +1a3de 22 300 61 +1a400 11 301 61 +1a411 1 301 61 +FUNC 1a412 2b 0 unsigned long long** std::__copy_aux(unsigned long long**, unsigned long long**, unsigned long long**) +1a412 c 307 79 +1a41e 4 315 61 +1a422 1b 317 61 +1a43d 1 317 61 +FUNC 1a43e 27 0 unsigned long long** std::__copy_normal::copy_n(unsigned long long**, unsigned long long**, unsigned long long**) +1a43e c 325 61 +1a44a 1b 326 61 +1a465 1 326 61 +FUNC 1a466 2f 0 unsigned long long** std::copy(unsigned long long**, unsigned long long**, unsigned long long**) +1a466 c 376 79 +1a472 4 384 61 +1a476 4 385 61 +1a47a 1b 387 61 +1a495 1 387 61 +FUNC 1a496 60 0 unsigned long long** std::__copy_backward::copy_b(unsigned long long* const*, unsigned long long* const*, unsigned long long**) +1a496 d 422 61 +1a4a3 12 424 61 +1a4b5 2e 425 61 +1a4e3 13 426 61 +FUNC 1a4f6 2b 0 unsigned long long** std::__copy_backward_aux(unsigned long long**, unsigned long long**, unsigned long long**) +1a4f6 c 432 79 +1a502 4 440 61 +1a506 1b 443 61 +1a521 1 443 61 +FUNC 1a522 27 0 unsigned long long** std::__copy_backward_normal::copy_b_n(unsigned long long**, unsigned long long**, unsigned long long**) +1a522 c 451 61 +1a52e 1b 452 61 +1a549 1 452 61 +FUNC 1a54a 2f 0 unsigned long long** std::copy_backward(unsigned long long**, unsigned long long**, unsigned long long**) +1a54a c 504 79 +1a556 4 514 61 +1a55a 4 515 61 +1a55e 1b 517 61 +1a579 1 517 61 +FUNC 1a57a 1df 0 std::deque >::_M_reallocate_map(unsigned long, bool) +1a57a 13 723 79 +1a58d 1b 726 76 +1a5a8 9 727 76 +1a5b1 13 730 76 +1a5c4 39 732 76 +1a5fd b 735 76 +1a608 27 736 76 +1a62f 2f 740 76 +1a65e 26 748 76 +1a684 15 750 76 +1a699 36 751 76 +1a6cf 22 753 76 +1a6f1 1e 756 76 +1a70f 8 758 76 +1a717 9 759 76 +1a720 15 762 76 +1a735 24 763 76 +1a759 1 763 76 +FUNC 1a75a 59 0 std::deque >::_M_reserve_map_at_back(unsigned long) +1a75a e 1443 79 +1a768 2a 1445 62 +1a792 21 1447 62 +1a7b3 1 1447 62 +FUNC 1a7b4 8c 0 std::deque >::_M_push_back_aux(unsigned long long const&) +1a7b4 c 345 79 +1a7c0 e 347 76 +1a7ce 13 348 76 +1a7e1 18 349 76 +1a7f9 1e 352 76 +1a817 1b 353 76 +1a832 c 355 76 +1a83e 2 360 76 +FUNC 1a840 62 0 std::deque >::push_back(unsigned long long const&) +1a840 c 1039 79 +1a84c 13 1041 62 +1a85f 1e 1044 62 +1a87d 11 1045 62 +1a88e 14 1048 62 +FUNC 1a8a2 20 0 std::stack > >::push(unsigned long long const&) +1a8a2 c 190 79 +1a8ae 14 191 75 +FUNC 1a8c2 27 0 unsigned char* std::__copy_normal::copy_n(unsigned char*, unsigned char*, unsigned char*) +1a8c2 c 325 61 +1a8ce 1b 326 61 +1a8e9 1 326 61 +FUNC 1a8ea 2f 0 unsigned char* std::copy(unsigned char*, unsigned char*, unsigned char*) +1a8ea c 376 79 +1a8f6 4 384 61 +1a8fa 4 385 61 +1a8fe 1b 387 61 +1a919 1 387 61 +FUNC 1a91a 27 0 unsigned char* std::__uninitialized_copy_aux(unsigned char*, unsigned char*, unsigned char*, __true_type) +1a91a c 73 79 +1a926 1b 74 79 +1a941 1 74 79 +FUNC 1a942 2f 0 unsigned char* std::uninitialized_copy(unsigned char*, unsigned char*, unsigned char*) +1a942 c 108 79 +1a94e 23 113 79 +1a971 1 113 79 +FUNC 1a972 27 0 unsigned char* std::__uninitialized_copy_a(unsigned char*, unsigned char*, unsigned char*, std::allocator) +1a972 c 252 79 +1a97e 1b 254 79 +1a999 1 254 79 +FUNC 1a99a 40 0 unsigned char* std::__copy_normal::copy_n<__gnu_cxx::__normal_iterator > >, unsigned char*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char*) +1a99a d 334 61 +1a9a7 33 335 61 +FUNC 1a9da 2f 0 unsigned char* std::copy<__gnu_cxx::__normal_iterator > >, unsigned char*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char*) +1a9da c 376 79 +1a9e6 4 384 61 +1a9ea 4 385 61 +1a9ee 1b 387 61 +1aa09 1 387 61 +FUNC 1aa0a 27 0 unsigned char* std::__uninitialized_copy_aux<__gnu_cxx::__normal_iterator > >, unsigned char*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char*, __true_type) +1aa0a c 73 79 +1aa16 1b 74 79 +1aa31 1 74 79 +FUNC 1aa32 2f 0 unsigned char* std::uninitialized_copy<__gnu_cxx::__normal_iterator > >, unsigned char*>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char*) +1aa32 c 108 79 +1aa3e 23 113 79 +1aa61 1 113 79 +FUNC 1aa62 27 0 unsigned char* std::__uninitialized_copy_a<__gnu_cxx::__normal_iterator > >, unsigned char*, unsigned char>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, unsigned char*, std::allocator) +1aa62 c 252 79 +1aa6e 1b 254 79 +1aa89 1 254 79 +1aa96 9 616 61 +1aa9f 2 617 61 +1aaa1 13 618 61 +1aab4 16 617 61 +1aaca 5 619 61 +1aacf 1 619 61 +1aadc 4 641 61 +1aae0 1b 642 61 +1aafb 1 642 61 +FUNC 1aafc 27 0 void std::__uninitialized_fill_n_aux<__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char>(__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char const&, __true_type) +1aafc c 182 79 +1ab08 1b 183 79 +1ab23 1 183 79 +FUNC 1ab24 2f 0 void std::uninitialized_fill_n<__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char>(__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char const&) +1ab24 c 214 79 +1ab30 23 218 79 +1ab53 1 218 79 +FUNC 1ab54 27 0 void std::__uninitialized_fill_n_a<__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char, unsigned char>(__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char const&, std::allocator) +1ab54 c 308 79 +1ab60 1b 310 79 +1ab7b 1 310 79 +FUNC 1ab7c 45a 0 std::vector >::_M_fill_insert(__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char const&) +1ab7c 14 311 79 +1ab90 b 313 78 +1ab9b 21 315 78 +1abbc 9 318 78 +1abc5 23 319 78 +1abe8 15 320 78 +1abfd c 321 78 +1ac09 4e 323 78 +1ac57 11 327 78 +1ac68 30 328 78 +1ac98 35 330 78 +1accd 48 334 78 +1ad15 14 338 78 +1ad29 43 339 78 +1ad6c 11 342 78 +1ad7d 1e 343 78 +1ad9b e 348 78 +1ada9 1e 349 78 +1adc7 e 350 78 +1add5 1d 353 78 +1adf2 8 354 78 +1adfa e 355 78 +1ae08 27 357 78 +1ae2f 6 358 78 +1ae35 4d 361 78 +1ae82 40 365 78 +1aec2 18 367 78 +1aeda 4d 368 78 +1af27 3e 379 78 +1af65 2d 381 78 +1af92 12 384 78 +1afa4 13 385 78 +1afb7 1f 386 78 +FUNC 1afd6 2e 0 std::vector >::insert(__gnu_cxx::__normal_iterator > >, unsigned long, unsigned char const&) +1afd6 c 657 79 +1afe2 22 658 71 +FUNC 1b004 ab 0 std::vector >::resize(unsigned long, unsigned char const&) +1b004 d 422 79 +1b011 15 424 71 +1b026 48 425 71 +1b06e 41 427 71 +1b0af 1 427 71 +FUNC 1b0b0 2b 0 std::vector >::resize(unsigned long) +1b0b0 c 441 79 +1b0bc 1f 442 71 +1b0db 1 442 71 +FUNC 1b0dc 1a 0 std::_Deque_iterator::_S_buffer_size() +1b0dc c 106 79 +1b0e8 e 107 62 +FUNC 1b0f6 66 0 std::_Deque_iterator::difference_type std::operator-(std::_Deque_iterator const&, std::_Deque_iterator const&) +1b0f6 d 328 79 +1b103 59 333 62 +FUNC 1b15c 3e 0 std::_Deque_iterator::_M_set_node(unsigned long long**) +1b15c d 229 79 +1b169 9 231 62 +1b172 b 232 62 +1b17d 1d 233 62 +FUNC 1b19a 50 0 std::_Deque_iterator::operator++() +1b19a c 142 79 +1b1a6 d 144 62 +1b1b3 f 145 62 +1b1c2 18 147 62 +1b1da b 148 62 +1b1e5 5 150 62 +FUNC 1b1ea 84 0 std::_Deque_iterator std::__copy::copy, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator) +1b1ea e 280 61 +1b1f8 17 283 61 +1b20f 20 285 61 +1b22f b 286 61 +1b23a b 287 61 +1b245 b 283 61 +1b250 1e 289 61 +FUNC 1b26e 7e 0 std::_Deque_iterator std::__copy_aux, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator) +1b26e 11 307 79 +1b27f 4 315 61 +1b283 69 317 61 +FUNC 1b2ec 7a 0 std::_Deque_iterator std::__copy_normal::copy_n, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator) +1b2ec 11 325 61 +1b2fd 69 326 61 +FUNC 1b366 82 0 std::_Deque_iterator std::copy, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator) +1b366 11 376 79 +1b377 4 384 61 +1b37b 4 385 61 +1b37f 69 387 61 +FUNC 1b3e8 7a 0 std::_Deque_iterator std::__uninitialized_copy_aux, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator, __true_type) +1b3e8 11 73 79 +1b3f9 69 74 79 +FUNC 1b462 82 0 std::_Deque_iterator std::uninitialized_copy, std::_Deque_iterator >(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator) +1b462 11 108 79 +1b473 71 113 79 +FUNC 1b4e4 7a 0 std::_Deque_iterator std::__uninitialized_copy_a, std::_Deque_iterator, unsigned long long>(std::_Deque_iterator, std::_Deque_iterator, std::_Deque_iterator, std::allocator) +1b4e4 11 252 79 +1b4f5 69 254 79 +1b55e 10 679 62 +1b56e 64 680 62 +1b5d2 e8 681 62 +1b6ba c 143 75 +1b6c6 14 144 75 +1b6da 6 144 75 +FUNC 1b6e0 4d 0 __eprintf +1b6e0 6 1826 80 +1b6e6 3 1832 80 +1b6e9 c 1826 80 +1b6f5 29 1832 80 +1b71e a 1837 80 +1b728 5 1838 80 +1b72d e8d3 1838 80 diff --git a/toolkit/crashreporter/breakpad-client/mac/handler/ucontext_compat.h b/toolkit/crashreporter/breakpad-client/mac/handler/ucontext_compat.h new file mode 100644 index 0000000000..1e4b752e51 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/handler/ucontext_compat.h @@ -0,0 +1,47 @@ +// Copyright 2013 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_MAC_HANDLER_UCONTEXT_COMPAT_H_ +#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ + +#include + +// The purpose of this file is to work around the fact that ucontext_t's +// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64. +#if defined(__aarch64__) +// doesn't include the below file. +#include +typedef ucontext64_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext64 +#else +typedef ucontext_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext +#endif // defined(__aarch64__) + +#endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/BreakpadFramework_Test.mm b/toolkit/crashreporter/breakpad-client/mac/tests/BreakpadFramework_Test.mm new file mode 100644 index 0000000000..2ea103c694 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/BreakpadFramework_Test.mm @@ -0,0 +1,217 @@ +// Copyright (c) 2009, 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. +// +// BreakpadFramework_Test.mm +// Test case file for Breakpad.h/mm. +// + +#import "GTMSenTestCase.h" +#import "Breakpad.h" + +#include + +@interface BreakpadFramework_Test : GTMTestCase { + @private + int last_exception_code_; + int last_exception_type_; + mach_port_t last_exception_thread_; + // We're not using Obj-C BOOL because we need to interop with + // Breakpad's callback. + bool shouldHandleException_; +} + +// This method is used by a callback used by test cases to determine +// whether to return true or false to Breakpad when handling an +// exception. +- (bool)shouldHandleException; +// This method returns a minimal dictionary that has what +// Breakpad needs to initialize. +- (NSMutableDictionary *)breakpadInitializationDictionary; +// This method is used by the exception handling callback +// to communicate to test cases the properites of the last +// exception. +- (void)setLastExceptionType:(int)type andCode:(int)code + andThread:(mach_port_t)thread; +@end + +// Callback for Breakpad exceptions +bool myBreakpadCallback(int exception_type, + int exception_code, + mach_port_t crashing_thread, + void *context); + +bool myBreakpadCallback(int exception_type, + int exception_code, + mach_port_t crashing_thread, + void *context) { + BreakpadFramework_Test *testCaseClass = + (BreakpadFramework_Test *)context; + [testCaseClass setLastExceptionType:exception_type + andCode:exception_code + andThread:crashing_thread]; + bool shouldHandleException = + [testCaseClass shouldHandleException]; + NSLog(@"Callback returning %d", shouldHandleException); + return shouldHandleException; +} +const int kNoLastExceptionCode = -1; +const int kNoLastExceptionType = -1; +const mach_port_t kNoLastExceptionThread = MACH_PORT_NULL; + +@implementation BreakpadFramework_Test +- (void) initializeExceptionStateVariables { + last_exception_code_ = kNoLastExceptionCode; + last_exception_type_ = kNoLastExceptionType; + last_exception_thread_ = kNoLastExceptionThread; +} + +- (NSMutableDictionary *)breakpadInitializationDictionary { + NSMutableDictionary *breakpadParams = + [NSMutableDictionary dictionaryWithCapacity:3]; + + [breakpadParams setObject:@"UnitTests" forKey:@BREAKPAD_PRODUCT]; + [breakpadParams setObject:@"1.0" forKey:@BREAKPAD_VERSION]; + [breakpadParams setObject:@"http://staging" forKey:@BREAKPAD_URL]; + return breakpadParams; +} + +- (bool)shouldHandleException { + return shouldHandleException_; +} + +- (void)setLastExceptionType:(int)type + andCode:(int)code + andThread:(mach_port_t)thread { + last_exception_type_ = type; + last_exception_code_ = code; + last_exception_thread_ = thread; +} + +// Test that the parameters mark required actually enable Breakpad to +// be initialized. +- (void)testBreakpadInstantiationWithRequiredParameters { + BreakpadRef b = BreakpadCreate([self breakpadInitializationDictionary]); + STAssertNotNULL(b, @"BreakpadCreate failed with required parameters"); + BreakpadRelease(b); +} + +// Test that Breakpad fails to initialize cleanly when required +// parameters are not present. +- (void)testBreakpadInstantiationWithoutRequiredParameters { + NSMutableDictionary *breakpadDictionary = + [self breakpadInitializationDictionary]; + + // Skip setting version, so that BreakpadCreate fails. + [breakpadDictionary removeObjectForKey:@BREAKPAD_VERSION]; + BreakpadRef b = BreakpadCreate(breakpadDictionary); + STAssertNULL(b, @"BreakpadCreate did not fail when missing a required" + " parameter!"); + + breakpadDictionary = [self breakpadInitializationDictionary]; + // Now test with no product + [breakpadDictionary removeObjectForKey:@BREAKPAD_PRODUCT]; + b = BreakpadCreate(breakpadDictionary); + STAssertNULL(b, @"BreakpadCreate did not fail when missing a required" + " parameter!"); + + breakpadDictionary = [self breakpadInitializationDictionary]; + // Now test with no URL + [breakpadDictionary removeObjectForKey:@BREAKPAD_URL]; + b = BreakpadCreate(breakpadDictionary); + STAssertNULL(b, @"BreakpadCreate did not fail when missing a required" + " parameter!"); + BreakpadRelease(b); +} + +// Test to ensure that when we call BreakpadAddUploadParameter, +// it's added to the dictionary correctly(this test depends on +// some internal details of Breakpad, namely, the special prefix +// that it uses to figure out which key/value pairs to upload). +- (void)testAddingBreakpadServerVariable { + NSMutableDictionary *breakpadDictionary = + [self breakpadInitializationDictionary]; + + BreakpadRef b = BreakpadCreate(breakpadDictionary); + STAssertNotNULL(b, @"BreakpadCreate failed with valid dictionary!"); + + BreakpadAddUploadParameter(b, + @"key", + @"value"); + + // Test that it did not add the key/value directly, e.g. without + // prepending the key with the prefix. + STAssertNil(BreakpadKeyValue(b, @"key"), + @"AddUploadParameter added key directly to dictionary" + " instead of prepending it!"); + + NSString *prependedKeyname = + [@BREAKPAD_SERVER_PARAMETER_PREFIX stringByAppendingString:@"key"]; + + STAssertEqualStrings(BreakpadKeyValue(b, prependedKeyname), + @"value", + @"Calling BreakpadAddUploadParameter did not prepend " + "key name"); + BreakpadRelease(b); +} + +// Test that when we do on-demand minidump generation, +// the exception code/type/thread are set properly. +- (void)testFilterCallbackReturnsFalse { + NSMutableDictionary *breakpadDictionary = + [self breakpadInitializationDictionary]; + + BreakpadRef b = BreakpadCreate(breakpadDictionary); + STAssertNotNULL(b, @"BreakpadCreate failed with valid dictionary!"); + BreakpadSetFilterCallback(b, &myBreakpadCallback, self); + + // This causes the callback to return false, meaning + // Breakpad won't take the exception + shouldHandleException_ = false; + + [self initializeExceptionStateVariables]; + STAssertEquals(last_exception_type_, kNoLastExceptionType, + @"Last exception type not initialized correctly."); + STAssertEquals(last_exception_code_, kNoLastExceptionCode, + @"Last exception code not initialized correctly."); + STAssertEquals(last_exception_thread_, kNoLastExceptionThread, + @"Last exception thread is not initialized correctly."); + + // Cause Breakpad's exception handler to be invoked. + BreakpadGenerateAndSendReport(b); + + STAssertEquals(last_exception_type_, 0, + @"Last exception type is not 0 for on demand"); + STAssertEquals(last_exception_code_, 0, + @"Last exception code is not 0 for on demand"); + STAssertEquals(last_exception_thread_, mach_thread_self(), + @"Last exception thread is not mach_thread_self() " + "for on demand"); +} + +@end diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/crash_generation_server_test.cc b/toolkit/crashreporter/breakpad-client/mac/tests/crash_generation_server_test.cc new file mode 100644 index 0000000000..0164f4a298 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/crash_generation_server_test.cc @@ -0,0 +1,398 @@ +// Copyright (c) 2010, 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. +// +// crash_generation_server_test.cc +// Unit tests for CrashGenerationServer + +#include +#include +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "client/mac/crash_generation/client_info.h" +#include "client/mac/crash_generation/crash_generation_client.h" +#include "client/mac/crash_generation/crash_generation_server.h" +#include "client/mac/handler/exception_handler.h" +#include "client/mac/tests/spawn_child_process.h" +#include "common/tests/auto_tempdir.h" +#include "google_breakpad/processor/minidump.h" + +namespace google_breakpad { +// This acts as the log sink for INFO logging from the processor +// logging code. The logging output confuses XCode and makes it think +// there are unit test failures. testlogging.h handles the overriding. +std::ostringstream info_log; +} + +namespace { +using std::string; +using google_breakpad::AutoTempDir; +using google_breakpad::ClientInfo; +using google_breakpad::CrashGenerationClient; +using google_breakpad::CrashGenerationServer; +using google_breakpad::ExceptionHandler; +using google_breakpad::Minidump; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpModule; +using google_breakpad::MinidumpModuleList; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpThread; +using google_breakpad::MinidumpThreadList; +using testing::Test; +using namespace google_breakpad_test; + +class CrashGenerationServerTest : public Test { +public: + // The port name to receive messages on + char mach_port_name[128]; + // Filename of the last dump that was generated + string last_dump_name; + // PID of the child process + pid_t child_pid; + // A temp dir + AutoTempDir temp_dir; + // Counter just to ensure that we don't hit the same port again + static int i; + bool filter_callback_called; + + void SetUp() { + sprintf(mach_port_name, + "com.google.breakpad.ServerTest.%d.%d", getpid(), + CrashGenerationServerTest::i++); + child_pid = (pid_t)-1; + filter_callback_called = false; + } +}; +int CrashGenerationServerTest::i = 0; + +// Test that starting and stopping a server works +TEST_F(CrashGenerationServerTest, testStartStopServer) { + CrashGenerationServer server(mach_port_name, + NULL, // filter callback + NULL, // filter context + NULL, // dump callback + NULL, // dump context + NULL, // exit callback + NULL, // exit context + false, // generate dumps + ""); // dump path + ASSERT_TRUE(server.Start()); + ASSERT_TRUE(server.Stop()); +} + +// Test that requesting a dump via CrashGenerationClient works +// Test without actually dumping +TEST_F(CrashGenerationServerTest, testRequestDumpNoDump) { + CrashGenerationServer server(mach_port_name, + NULL, // filter callback + NULL, // filter context + NULL, // dump callback + NULL, // dump context + NULL, // exit callback + NULL, // exit context + false, // don't generate dumps + temp_dir.path()); // dump path + ASSERT_TRUE(server.Start()); + + pid_t pid = fork(); + ASSERT_NE(-1, pid); + if (pid == 0) { + CrashGenerationClient client(mach_port_name); + bool result = client.RequestDump(); + exit(result ? 0 : 1); + } + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_TRUE(WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + EXPECT_TRUE(server.Stop()); + // check that no minidump was written + string pattern = temp_dir.path() + "/*"; + glob_t dirContents; + ret = glob(pattern.c_str(), GLOB_NOSORT, NULL, &dirContents); + EXPECT_EQ(GLOB_NOMATCH, ret); + if (ret != GLOB_NOMATCH) + globfree(&dirContents); +} + +void dumpCallback(void *context, const ClientInfo &client_info, + const std::string &file_path) { + if (context) { + CrashGenerationServerTest* self = + reinterpret_cast(context); + if (!file_path.empty()) + self->last_dump_name = file_path; + self->child_pid = client_info.pid(); + } +} + +void *RequestDump(void *context) { + CrashGenerationClient client((const char*)context); + bool result = client.RequestDump(); + return (void*)(result ? 0 : 1); +} + +// Test that actually writing a minidump works +TEST_F(CrashGenerationServerTest, testRequestDump) { + CrashGenerationServer server(mach_port_name, + NULL, // filter callback + NULL, // filter context + dumpCallback, // dump callback + this, // dump context + NULL, // exit callback + NULL, // exit context + true, // generate dumps + temp_dir.path()); // dump path + ASSERT_TRUE(server.Start()); + + pid_t pid = fork(); + ASSERT_NE(-1, pid); + if (pid == 0) { + // Have to spawn off a separate thread to request the dump, + // because MinidumpGenerator assumes the handler thread is not + // the only thread + pthread_t thread; + if (pthread_create(&thread, NULL, RequestDump, (void*)mach_port_name) != 0) + exit(1); + void* result; + pthread_join(thread, &result); + exit(reinterpret_cast(result)); + } + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_TRUE(WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + EXPECT_TRUE(server.Stop()); + // check that minidump was written + ASSERT_FALSE(last_dump_name.empty()); + struct stat st; + EXPECT_EQ(0, stat(last_dump_name.c_str(), &st)); + EXPECT_LT(0, st.st_size); + // check client's PID + ASSERT_EQ(pid, child_pid); +} + +static void Crasher() { + int *a = (int*)0x42; + + fprintf(stdout, "Going to crash...\n"); + fprintf(stdout, "A = %d", *a); +} + +// Test that crashing a child process with an OOP ExceptionHandler installed +// results in a minidump being written by the CrashGenerationServer in +// the parent. +TEST_F(CrashGenerationServerTest, testChildProcessCrash) { + CrashGenerationServer server(mach_port_name, + NULL, // filter callback + NULL, // filter context + dumpCallback, // dump callback + this, // dump context + NULL, // exit callback + NULL, // exit context + true, // generate dumps + temp_dir.path()); // dump path + ASSERT_TRUE(server.Start()); + + pid_t pid = fork(); + ASSERT_NE(-1, pid); + if (pid == 0) { + // Instantiate an OOP exception handler. + ExceptionHandler eh("", NULL, NULL, NULL, true, mach_port_name); + Crasher(); + // not reached + exit(0); + } + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_FALSE(WIFEXITED(ret)); + EXPECT_TRUE(server.Stop()); + // check that minidump was written + ASSERT_FALSE(last_dump_name.empty()); + struct stat st; + EXPECT_EQ(0, stat(last_dump_name.c_str(), &st)); + EXPECT_LT(0, st.st_size); + + // Read the minidump, sanity check some data. + Minidump minidump(last_dump_name.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kNativeContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(GetExecutablePath(), main_module->code_file()); +} + +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) && \ + (defined(__x86_64__) || defined(__i386__)) +// Test that crashing a child process of a different architecture +// produces a valid minidump. +TEST_F(CrashGenerationServerTest, testChildProcessCrashCrossArchitecture) { + CrashGenerationServer server(mach_port_name, + NULL, // filter callback + NULL, // filter context + dumpCallback, // dump callback + this, // dump context + NULL, // exit callback + NULL, // exit context + true, // generate dumps + temp_dir.path()); // dump path + ASSERT_TRUE(server.Start()); + + // Spawn a child process + string helper_path = GetHelperPath(); + const char* argv[] = { + helper_path.c_str(), + "crash", + mach_port_name, + NULL + }; + pid_t pid = spawn_child_process(argv); + ASSERT_NE(-1, pid); + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_FALSE(WIFEXITED(ret)); + EXPECT_TRUE(server.Stop()); + // check that minidump was written + ASSERT_FALSE(last_dump_name.empty()); + struct stat st; + EXPECT_EQ(0, stat(last_dump_name.c_str(), &st)); + EXPECT_LT(0, st.st_size); + +const MDCPUArchitecture kExpectedArchitecture = +#if defined(__x86_64__) + MD_CPU_ARCHITECTURE_X86 +#elif defined(__i386__) + MD_CPU_ARCHITECTURE_AMD64 +#endif + ; +const uint32_t kExpectedContext = +#if defined(__i386__) + MD_CONTEXT_AMD64 +#elif defined(__x86_64__) + MD_CONTEXT_X86 +#endif + ; + + // Read the minidump, sanity check some data. + Minidump minidump(last_dump_name.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kExpectedArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kExpectedContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(helper_path, main_module->code_file()); +} +#endif + +bool filter_callback(void* context) { + CrashGenerationServerTest* self = + reinterpret_cast(context); + self->filter_callback_called = true; + // veto dump generation + return false; +} + +// Test that a filter callback can veto minidump writing. +TEST_F(CrashGenerationServerTest, testFilter) { + CrashGenerationServer server(mach_port_name, + filter_callback, // filter callback + this, // filter context + dumpCallback, // dump callback + this, // dump context + NULL, // exit callback + NULL, // exit context + true, // generate dumps + temp_dir.path()); // dump path + ASSERT_TRUE(server.Start()); + + pid_t pid = fork(); + ASSERT_NE(-1, pid); + if (pid == 0) { + // Instantiate an OOP exception handler. + ExceptionHandler eh("", NULL, NULL, NULL, true, mach_port_name); + Crasher(); + // not reached + exit(0); + } + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_FALSE(WIFEXITED(ret)); + EXPECT_TRUE(server.Stop()); + + // check that no minidump was written + EXPECT_TRUE(last_dump_name.empty()); + EXPECT_TRUE(filter_callback_called); +} + +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/exception_handler_test.cc b/toolkit/crashreporter/breakpad-client/mac/tests/exception_handler_test.cc new file mode 100644 index 0000000000..d5b505a1e1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/exception_handler_test.cc @@ -0,0 +1,714 @@ +// Copyright (c) 2010, 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_test.cc: Unit tests for google_breakpad::ExceptionHandler + +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "client/mac/handler/exception_handler.h" +#include "common/linux/ignore_ret.h" +#include "common/mac/MachIPC.h" +#include "common/tests/auto_tempdir.h" +#include "google_breakpad/processor/minidump.h" + +namespace google_breakpad { +// This acts as the log sink for INFO logging from the processor +// logging code. The logging output confuses XCode and makes it think +// there are unit test failures. testlogging.h handles the overriding. +std::ostringstream info_log; +} + +namespace { +using std::string; +using google_breakpad::AutoTempDir; +using google_breakpad::ExceptionHandler; +using google_breakpad::MachPortSender; +using google_breakpad::MachReceiveMessage; +using google_breakpad::MachSendMessage; +using google_breakpad::Minidump; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpMemoryList; +using google_breakpad::MinidumpMemoryRegion; +using google_breakpad::ReceivePort; +using testing::Test; + +class ExceptionHandlerTest : public Test { + public: + void InProcessCrash(bool aborting); + AutoTempDir tempDir; + string lastDumpName; +}; + +static void Crasher() { + int *a = (int*)0x42; + + fprintf(stdout, "Going to crash...\n"); + fprintf(stdout, "A = %d", *a); +} + +static void AbortCrasher() { + fprintf(stdout, "Going to crash...\n"); + abort(); +} + +static void SoonToCrash(void(*crasher)()) { + crasher(); +} + +static bool MDCallback(const char *dump_dir, const char *file_name, + void *context, bool success) { + string path(dump_dir); + path.append("/"); + path.append(file_name); + path.append(".dmp"); + + int fd = *reinterpret_cast(context); + IGNORE_RET(write(fd, path.c_str(), path.length() + 1)); + close(fd); + exit(0); + // not reached + return true; +} + +void ExceptionHandlerTest::InProcessCrash(bool aborting) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + // Fork off a child process so it can crash. + pid_t pid = fork(); + if (pid == 0) { + // In the child process. + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + // crash + SoonToCrash(aborting ? &AbortCrasher : &Crasher); + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + ASSERT_TRUE(exception); + + const MDRawExceptionStream* raw_exception = exception->exception(); + ASSERT_TRUE(raw_exception); + + if (aborting) { + EXPECT_EQ(MD_EXCEPTION_MAC_SOFTWARE, + raw_exception->exception_record.exception_code); + EXPECT_EQ(MD_EXCEPTION_CODE_MAC_ABORT, + raw_exception->exception_record.exception_flags); + } else { + EXPECT_EQ(MD_EXCEPTION_MAC_BAD_ACCESS, + raw_exception->exception_record.exception_code); +#if defined(__x86_64__) + EXPECT_EQ(MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS, + raw_exception->exception_record.exception_flags); +#elif defined(__i386__) + EXPECT_EQ(MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE, + raw_exception->exception_record.exception_flags); +#endif + } + + const MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + // Ideally would like to sanity check that abort() is on the stack + // but that's hard. + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(memory_list); + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + EXPECT_TRUE(region); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); +} + +TEST_F(ExceptionHandlerTest, InProcess) { + InProcessCrash(false); +} + +TEST_F(ExceptionHandlerTest, InProcessAbort) { + InProcessCrash(true); +} + +static bool DumpNameMDCallback(const char *dump_dir, const char *file_name, + void *context, bool success) { + ExceptionHandlerTest *self = reinterpret_cast(context); + if (dump_dir && file_name) { + self->lastDumpName = dump_dir; + self->lastDumpName += "/"; + self->lastDumpName += file_name; + self->lastDumpName += ".dmp"; + } + return true; +} + +TEST_F(ExceptionHandlerTest, WriteMinidump) { + ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true, + NULL); + ASSERT_TRUE(eh.WriteMinidump()); + + // Ensure that minidump file exists and is > 0 bytes. + ASSERT_FALSE(lastDumpName.empty()); + struct stat st; + ASSERT_EQ(0, stat(lastDumpName.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // The minidump should not contain an exception stream. + Minidump minidump(lastDumpName); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + EXPECT_FALSE(exception); +} + +TEST_F(ExceptionHandlerTest, WriteMinidumpWithException) { + ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true, + NULL); + ASSERT_TRUE(eh.WriteMinidump(true)); + + // Ensure that minidump file exists and is > 0 bytes. + ASSERT_FALSE(lastDumpName.empty()); + struct stat st; + ASSERT_EQ(0, stat(lastDumpName.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // The minidump should contain an exception stream. + Minidump minidump(lastDumpName); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + ASSERT_TRUE(exception); + const MDRawExceptionStream* raw_exception = exception->exception(); + ASSERT_TRUE(raw_exception); + + EXPECT_EQ(MD_EXCEPTION_MAC_BREAKPOINT, + raw_exception->exception_record.exception_code); +} + +TEST_F(ExceptionHandlerTest, DumpChildProcess) { + const int kTimeoutMs = 2000; + // Create a mach port to receive the child task on. + char machPortName[128]; + sprintf(machPortName, "ExceptionHandlerTest.%d", getpid()); + ReceivePort parent_recv_port(machPortName); + + // Give the child process a pipe to block on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // Fork off a child process to dump. + pid_t pid = fork(); + if (pid == 0) { + // In the child process + close(fds[1]); + + // Send parent process the task and thread ports. + MachSendMessage child_message(0); + child_message.AddDescriptor(mach_task_self()); + child_message.AddDescriptor(mach_thread_self()); + + MachPortSender child_sender(machPortName); + if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) + exit(1); + + // Wait for the parent process. + uint8_t data; + read(fds[0], &data, 1); + exit(0); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[0]); + + // Read the child's task and thread ports. + MachReceiveMessage child_message; + ASSERT_EQ(KERN_SUCCESS, + parent_recv_port.WaitForMessage(&child_message, kTimeoutMs)); + mach_port_t child_task = child_message.GetTranslatedPort(0); + mach_port_t child_thread = child_message.GetTranslatedPort(1); + ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task); + ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_thread); + + // Write a minidump of the child process. + bool result = ExceptionHandler::WriteMinidumpForChild(child_task, + child_thread, + tempDir.path(), + DumpNameMDCallback, + this); + ASSERT_EQ(true, result); + + // Ensure that minidump file exists and is > 0 bytes. + ASSERT_FALSE(lastDumpName.empty()); + struct stat st; + ASSERT_EQ(0, stat(lastDumpName.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // Unblock child process + uint8_t data = 1; + IGNORE_RET(write(fds[1], &data, 1)); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); +} + +// Test that memory around the instruction pointer is written +// to the dump as a MinidumpMemoryRegion. +TEST_F(ExceptionHandlerTest, InstructionPointerMemory) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = 256; // bytes + const int kOffset = kMemorySize / 2; + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + + pid_t pid = fork(); + if (pid == 0) { + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them in the middle + // of the block of memory, because the minidump should contain 128 + // bytes on either side of the instruction pointer. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[1]); + + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(minidump_file, &st)); + ASSERT_LT(0, st.st_size); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_NE((unsigned int)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + EXPECT_TRUE(region); + + EXPECT_EQ(kMemorySize, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t prefix_bytes[kOffset]; + uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), + suffix_bytes, sizeof(suffix_bytes)) == 0); +} + +// Test that the memory region around the instruction pointer is +// bounded correctly on the low end. +TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + const uint32_t kMemorySize = 256; // bytes + const int kOffset = 0; + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + + pid_t pid = fork(); + if (pid == 0) { + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them at the start + // of the block of memory, to ensure that the memory bounding + // works properly. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[1]); + + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(minidump_file, &st)); + ASSERT_LT(0, st.st_size); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_NE((unsigned int)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + EXPECT_TRUE(region); + + EXPECT_EQ(kMemorySize / 2, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)]; + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), + suffix_bytes, sizeof(suffix_bytes)) == 0); +} + +// Test that the memory region around the instruction pointer is +// bounded correctly on the high end. +TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // These are defined here so the parent can use them to check the + // data from the minidump afterwards. + // Use 4k here because the OS will hand out a single page even + // if a smaller size is requested, and this test wants to + // test the upper bound of the memory range. + const uint32_t kMemorySize = 4096; // bytes + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + const int kOffset = kMemorySize - sizeof(instructions); + + pid_t pid = fork(); + if (pid == 0) { + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + // Get some executable memory. + char* memory = + reinterpret_cast(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + if (!memory) + exit(0); + + // Write some instructions that will crash. Put them at the start + // of the block of memory, to ensure that the memory bounding + // works properly. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + memory_function(); + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[1]); + + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(minidump_file, &st)); + ASSERT_LT(0, st.st_size); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_NE((unsigned int)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + EXPECT_TRUE(region); + + const size_t kPrefixSize = 128; // bytes + EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t prefix_bytes[kPrefixSize]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); + EXPECT_TRUE(memcmp(bytes + kPrefixSize, + instructions, sizeof(instructions)) == 0); +} + +// Ensure that an extra memory block doesn't get added when the +// instruction pointer is not in mapped memory. +TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + pid_t pid = fork(); + if (pid == 0) { + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + // Try calling a NULL pointer. + typedef void (*void_function)(void); + // Volatile markings are needed to keep Clang from generating invalid + // opcodes. See http://crbug.com/498354 for details. + volatile void_function memory_function = + reinterpret_cast(NULL); + memory_function(); + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[1]); + + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(minidump_file, &st)); + ASSERT_LT(0, st.st_size); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is only one memory region + // in the memory list (the thread memory from the single thread). + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_EQ((unsigned int)1, memory_list->region_count()); +} + +static void *Junk(void *) { + sleep(1000000); + return NULL; +} + +// Test that the memory list gets written correctly when multiple +// threads are running. +TEST_F(ExceptionHandlerTest, MemoryListMultipleThreads) { + // Give the child process a pipe to report back on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + pid_t pid = fork(); + if (pid == 0) { + close(fds[0]); + ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL); + + // Run an extra thread so >2 memory regions will be written. + pthread_t junk_thread; + if (pthread_create(&junk_thread, NULL, Junk, NULL) == 0) + pthread_detach(junk_thread); + + // Just crash. + Crasher(); + + // not reached + exit(1); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[1]); + + // Wait for the background process to return the minidump file. + close(fds[1]); + char minidump_file[PATH_MAX]; + ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file)); + ASSERT_NE(0, nbytes); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(minidump_file, &st)); + ASSERT_LT(0, st.st_size); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump, and verify that the memory list can be read. + Minidump minidump(minidump_file); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(memory_list); + // Verify that there are three memory regions: + // one per thread, and one for the instruction pointer memory. + ASSERT_EQ((unsigned int)3, memory_list->region_count()); +} + +} diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test.cc b/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test.cc new file mode 100644 index 0000000000..b1fa5d02a1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2010, 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_test.cc: Unit tests for google_breakpad::MinidumpGenerator + +#include +#ifndef MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_10_6 1060 +#endif +#include +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "client/mac/handler/minidump_generator.h" +#include "client/mac/tests/spawn_child_process.h" +#include "common/linux/ignore_ret.h" +#include "common/mac/MachIPC.h" +#include "common/tests/auto_tempdir.h" +#include "google_breakpad/processor/minidump.h" + +namespace google_breakpad { +// This acts as the log sink for INFO logging from the processor +// logging code. The logging output confuses XCode and makes it think +// there are unit test failures. testlogging.h handles the overriding. +std::ostringstream info_log; +} + +namespace { +using std::string; +using std::vector; +using google_breakpad::AutoTempDir; +using google_breakpad::MinidumpGenerator; +using google_breakpad::MachPortSender; +using google_breakpad::MachReceiveMessage; +using google_breakpad::MachSendMessage; +using google_breakpad::Minidump; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpModule; +using google_breakpad::MinidumpModuleList; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpThread; +using google_breakpad::MinidumpThreadList; +using google_breakpad::ReceivePort; +using testing::Test; +using namespace google_breakpad_test; + +class MinidumpGeneratorTest : public Test { + public: + AutoTempDir tempDir; +}; + +static void *Junk(void* data) { + bool* wait = reinterpret_cast(data); + while (!*wait) { + usleep(10000); + } + return NULL; +} + +TEST_F(MinidumpGeneratorTest, InProcess) { + MinidumpGenerator generator; + string dump_filename = + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + + // Run an extra thread since MinidumpGenerator assumes there + // are 2 or more threads. + pthread_t junk_thread; + bool quit = false; + ASSERT_EQ(0, pthread_create(&junk_thread, NULL, Junk, &quit)); + + ASSERT_TRUE(generator.Write(dump_filename.c_str())); + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(dump_filename.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // join the background thread + quit = true; + pthread_join(junk_thread, NULL); + + // Read the minidump, sanity check some data. + Minidump minidump(dump_filename.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kNativeContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(GetExecutablePath(), main_module->code_file()); +} + +TEST_F(MinidumpGeneratorTest, OutOfProcess) { + const int kTimeoutMs = 2000; + // Create a mach port to receive the child task on. + char machPortName[128]; + sprintf(machPortName, "MinidumpGeneratorTest.OutOfProcess.%d", getpid()); + ReceivePort parent_recv_port(machPortName); + + // Give the child process a pipe to block on. + int fds[2]; + ASSERT_EQ(0, pipe(fds)); + + // Fork off a child process to dump. + pid_t pid = fork(); + if (pid == 0) { + // In the child process + close(fds[1]); + + // Send parent process the task port. + MachSendMessage child_message(0); + child_message.AddDescriptor(mach_task_self()); + + MachPortSender child_sender(machPortName); + if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) { + fprintf(stderr, "Error sending message from child process!\n"); + exit(1); + } + + // Wait for the parent process. + uint8_t data; + read(fds[0], &data, 1); + exit(0); + } + // In the parent process. + ASSERT_NE(-1, pid); + close(fds[0]); + + // Read the child's task port. + MachReceiveMessage child_message; + ASSERT_EQ(KERN_SUCCESS, + parent_recv_port.WaitForMessage(&child_message, kTimeoutMs)); + mach_port_t child_task = child_message.GetTranslatedPort(0); + ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task); + + // Write a minidump of the child process. + MinidumpGenerator generator(child_task, MACH_PORT_NULL); + string dump_filename = + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + ASSERT_TRUE(generator.Write(dump_filename.c_str())); + + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(dump_filename.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // Unblock child process + uint8_t data = 1; + IGNORE_RET(write(fds[1], &data, 1)); + + // Child process should have exited with a zero status. + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + EXPECT_NE(0, WIFEXITED(ret)); + EXPECT_EQ(0, WEXITSTATUS(ret)); + + // Read the minidump, sanity check some data. + Minidump minidump(dump_filename.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kNativeArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kNativeContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(GetExecutablePath(), main_module->code_file()); +} + +// This test fails on 10.5, but I don't have easy access to a 10.5 machine, +// so it's simpler to just limit it to 10.6 for now. +#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) && \ + (defined(__x86_64__) || defined(__i386__)) + +TEST_F(MinidumpGeneratorTest, CrossArchitectureDump) { + const int kTimeoutMs = 5000; + // Create a mach port to receive the child task on. + char machPortName[128]; + sprintf(machPortName, + "MinidumpGeneratorTest.CrossArchitectureDump.%d", getpid()); + + ReceivePort parent_recv_port(machPortName); + + // Spawn a child process to dump. + string helper_path = GetHelperPath(); + const char* argv[] = { + helper_path.c_str(), + machPortName, + NULL + }; + pid_t pid = spawn_child_process(argv); + ASSERT_NE(-1, pid); + + // Read the child's task port. + MachReceiveMessage child_message; + ASSERT_EQ(KERN_SUCCESS, + parent_recv_port.WaitForMessage(&child_message, kTimeoutMs)); + mach_port_t child_task = child_message.GetTranslatedPort(0); + ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task); + + // Write a minidump of the child process. + MinidumpGenerator generator(child_task, MACH_PORT_NULL); + string dump_filename = + MinidumpGenerator::UniqueNameInDirectory(tempDir.path(), NULL); + ASSERT_TRUE(generator.Write(dump_filename.c_str())); + + // Ensure that minidump file exists and is > 0 bytes. + struct stat st; + ASSERT_EQ(0, stat(dump_filename.c_str(), &st)); + ASSERT_LT(0, st.st_size); + + // Kill child process. + kill(pid, SIGKILL); + + int ret; + ASSERT_EQ(pid, waitpid(pid, &ret, 0)); + +const MDCPUArchitecture kExpectedArchitecture = +#if defined(__x86_64__) + MD_CPU_ARCHITECTURE_X86 +#elif defined(__i386__) + MD_CPU_ARCHITECTURE_AMD64 +#endif + ; +const uint32_t kExpectedContext = +#if defined(__i386__) + MD_CONTEXT_AMD64 +#elif defined(__x86_64__) + MD_CONTEXT_X86 +#endif + ; + + // Read the minidump, sanity check some data. + Minidump minidump(dump_filename.c_str()); + ASSERT_TRUE(minidump.Read()); + + MinidumpSystemInfo* system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(system_info); + const MDRawSystemInfo* raw_info = system_info->system_info(); + ASSERT_TRUE(raw_info); + EXPECT_EQ(kExpectedArchitecture, raw_info->processor_architecture); + + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list); + ASSERT_EQ((unsigned int)1, thread_list->thread_count()); + + MinidumpThread* main_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(main_thread); + MinidumpContext* context = main_thread->GetContext(); + ASSERT_TRUE(context); + EXPECT_EQ(kExpectedContext, context->GetContextCPU()); + + MinidumpModuleList* module_list = minidump.GetModuleList(); + ASSERT_TRUE(module_list); + const MinidumpModule* main_module = module_list->GetMainModule(); + ASSERT_TRUE(main_module); + EXPECT_EQ(helper_path, main_module->code_file()); +} +#endif // 10.6 && (x86-64 || i386) + +} diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test_helper.cc b/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test_helper.cc new file mode 100644 index 0000000000..4e8ce3cf00 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/minidump_generator_test_helper.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2010, 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_test_helper.cc: A helper program that +// minidump_generator_test.cc can launch to test certain things +// that require a separate executable. + +#include + +#include "client/mac/handler/exception_handler.h" +#include "common/mac/MachIPC.h" + +using google_breakpad::MachPortSender; +using google_breakpad::MachReceiveMessage; +using google_breakpad::MachSendMessage; +using google_breakpad::ReceivePort; + +int main(int argc, char** argv) { + if (argc < 2) + return 1; + + if (strcmp(argv[1], "crash") != 0) { + const int kTimeoutMs = 2000; + // Send parent process the task and thread ports. + MachSendMessage child_message(0); + child_message.AddDescriptor(mach_task_self()); + child_message.AddDescriptor(mach_thread_self()); + + MachPortSender child_sender(argv[1]); + if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS) { + fprintf(stderr, "Error sending message from child process!\n"); + exit(1); + } + + // Loop forever. + while (true) { + sleep(100); + } + } else if (argc == 3 && strcmp(argv[1], "crash") == 0) { + // Instantiate an OOP exception handler + google_breakpad::ExceptionHandler eh("", NULL, NULL, NULL, true, argv[2]); + // and crash. + int *a = (int*)0x42; + *a = 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/spawn_child_process.h b/toolkit/crashreporter/breakpad-client/mac/tests/spawn_child_process.h new file mode 100644 index 0000000000..1b82c56278 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/spawn_child_process.h @@ -0,0 +1,149 @@ +// Copyright (c) 2010, 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. + +// Utility functions for spawning a helper process using a different +// CPU architecture. + +#ifndef GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS +#define GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS + +#include +#ifndef MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_10_6 1060 +#endif +#include +#include +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 +#include +#endif + +#include +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad_test { + +using std::string; +using std::vector; + +const MDCPUArchitecture kNativeArchitecture = +#if defined(__i386__) + MD_CPU_ARCHITECTURE_X86 +#elif defined(__x86_64__) + MD_CPU_ARCHITECTURE_AMD64 +#elif defined(__ppc__) || defined(__ppc64__) + MD_CPU_ARCHITECTURE_PPC +#else +#error "This file has not been ported to this CPU architecture." +#endif + ; + +const uint32_t kNativeContext = +#if defined(__i386__) + MD_CONTEXT_X86 +#elif defined(__x86_64__) + MD_CONTEXT_AMD64 +#elif defined(__ppc__) || defined(__ppc64__) + MD_CONTEXT_PPC +#else +#error "This file has not been ported to this CPU architecture." +#endif + ; + +string GetExecutablePath() { + char self_path[PATH_MAX]; + uint32_t size = sizeof(self_path); + if (_NSGetExecutablePath(self_path, &size) != 0) + return ""; + return self_path; +} + +string GetHelperPath() { + string helper_path(GetExecutablePath()); + size_t pos = helper_path.rfind('/'); + if (pos == string::npos) + return ""; + + helper_path.erase(pos + 1); + helper_path += "minidump_generator_test_helper"; + return helper_path; +} + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 + +pid_t spawn_child_process(const char** argv) { + posix_spawnattr_t spawnattr; + if (posix_spawnattr_init(&spawnattr) != 0) + return (pid_t)-1; + + cpu_type_t pref_cpu_types[2] = { +#if defined(__x86_64__) + CPU_TYPE_X86, +#elif defined(__i386__) + CPU_TYPE_X86_64, +#endif + CPU_TYPE_ANY + }; + + // Set spawn attributes. + size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]); + size_t attr_ocount = 0; + if (posix_spawnattr_setbinpref_np(&spawnattr, + attr_count, + pref_cpu_types, + &attr_ocount) != 0 || + attr_ocount != attr_count) { + posix_spawnattr_destroy(&spawnattr); + return (pid_t)-1; + } + + // Create an argv array. + vector argv_v; + while (*argv) { + argv_v.push_back(strdup(*argv)); + argv++; + } + argv_v.push_back(NULL); + pid_t new_pid = 0; + int result = posix_spawnp(&new_pid, argv_v[0], NULL, &spawnattr, + &argv_v[0], *_NSGetEnviron()); + posix_spawnattr_destroy(&spawnattr); + + for (unsigned i = 0; i < argv_v.size(); i++) { + free(argv_v[i]); + } + + return result == 0 ? new_pid : -1; +} +#endif + +} // namespace google_breakpad_test + +#endif // GOOGLE_BREAKPAD_CLIENT_MAC_TESTS_SPAWN_CHILD_PROCESS diff --git a/toolkit/crashreporter/breakpad-client/mac/tests/testlogging.h b/toolkit/crashreporter/breakpad-client/mac/tests/testlogging.h new file mode 100644 index 0000000000..c6b6be699b --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/mac/tests/testlogging.h @@ -0,0 +1,9 @@ +// This file exists to override the processor logging for unit tests, +// since it confuses XCode into thinking unit tests have failed. +#include + +namespace google_breakpad { +extern std::ostringstream info_log; +} + +#define BPLOG_INFO_STREAM google_breakpad::info_log diff --git a/toolkit/crashreporter/breakpad-client/minidump_file_writer-inl.h b/toolkit/crashreporter/breakpad-client/minidump_file_writer-inl.h new file mode 100644 index 0000000000..bf63135b85 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/minidump_file_writer-inl.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. + +// 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 + +#include "minidump_file_writer.h" +#include "google_breakpad/common/minidump_size.h" + +namespace google_breakpad { + +template +inline bool TypedMDRVA::Allocate() { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size()); +} + +template +inline bool TypedMDRVA::Allocate(size_t additional) { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size() + additional); +} + +template +inline bool TypedMDRVA::AllocateArray(size_t count) { + assert(count); + allocation_state_ = ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() * count); +} + +template +inline bool TypedMDRVA::AllocateObjectAndArray(size_t count, + size_t length) { + assert(count && length); + allocation_state_ = SINGLE_OBJECT_WITH_ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() + count * length); +} + +template +inline bool TypedMDRVA::CopyIndex(unsigned int index, MDType *item) { + assert(allocation_state_ == ARRAY); + return writer_->Copy( + static_cast(position_ + index * minidump_size::size()), + item, minidump_size::size()); +} + +template +inline bool TypedMDRVA::CopyIndexAfterObject(unsigned int index, + const void *src, + size_t length) { + assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); + return writer_->Copy( + static_cast(position_ + minidump_size::size() + + index * length), + src, length); +} + +template +inline bool TypedMDRVA::Flush() { + return writer_->Copy(position_, &data_, minidump_size::size()); +} + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__ diff --git a/toolkit/crashreporter/breakpad-client/minidump_file_writer.cc b/toolkit/crashreporter/breakpad-client/minidump_file_writer.cc new file mode 100644 index 0000000000..ed9e957d39 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/minidump_file_writer.cc @@ -0,0 +1,402 @@ +// 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.cc: Minidump file writer implementation. +// +// See minidump_file_writer.h for documentation. + +#include +#include +#include +#include +#include + +#include "minidump_file_writer-inl.h" +#include "common/linux/linux_libc_support.h" +#include "common/string_conversion.h" +#if defined(__linux__) && __linux__ +#include "third_party/lss/linux_syscall_support.h" +#endif + +#if defined(__ANDROID__) +#include + +namespace { + +bool g_need_ftruncate_workaround = false; +bool g_checked_need_ftruncate_workaround = false; + +void CheckNeedsFTruncateWorkAround(int file) { + if (g_checked_need_ftruncate_workaround) { + return; + } + g_checked_need_ftruncate_workaround = true; + + // Attempt an idempotent truncate that chops off nothing and see if we + // run into any sort of errors. + off_t offset = sys_lseek(file, 0, SEEK_END); + if (offset == -1) { + // lseek failed. Don't apply work around. It's unlikely that we can write + // to a minidump with either method. + return; + } + + int result = ftruncate(file, offset); + if (result == -1 && errno == EACCES) { + // It very likely that we are running into the kernel bug in M devices. + // We are going to deploy the workaround for writing minidump files + // without uses of ftruncate(). This workaround should be fine even + // for kernels without the bug. + // See http://crbug.com/542840 for more details. + g_need_ftruncate_workaround = true; + } +} + +bool NeedsFTruncateWorkAround() { + return g_need_ftruncate_workaround; +} + +} // namespace +#endif // defined(__ANDROID__) + +namespace google_breakpad { + +const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast(-1); + +MinidumpFileWriter::MinidumpFileWriter() + : file_(-1), + close_file_when_destroyed_(true), + position_(0), + size_(0) { +} + +MinidumpFileWriter::~MinidumpFileWriter() { + if (close_file_when_destroyed_) + Close(); +} + +bool MinidumpFileWriter::Open(const char *path) { + assert(file_ == -1); +#if defined(__linux__) && __linux__ + file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#else + file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + + return file_ != -1; +} + +void MinidumpFileWriter::SetFile(const int file) { + assert(file_ == -1); + file_ = file; + close_file_when_destroyed_ = false; +#if defined(__ANDROID__) + CheckNeedsFTruncateWorkAround(file); +#endif +} + +bool MinidumpFileWriter::Close() { + bool result = true; + + if (file_ != -1) { +#if defined(__ANDROID__) + if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) { + return false; + } +#else + if (ftruncate(file_, position_)) { + return false; + } +#endif +#if defined(__linux__) && __linux__ + result = (sys_close(file_) == 0); +#else + result = (close(file_) == 0); +#endif + file_ = -1; + } + + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + if (sizeof(wchar_t) == sizeof(uint16_t)) { + // Shortcut if wchar_t is the same size as MDString's buffer + result = mdstring->Copy(str, mdstring->get()->length); + } else { + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + UTF32ToUTF16Char(*str, out); + if (!out[0]) + return false; + + // Process one character at a time + --length; + ++str; + + // Append the one or two UTF-16 characters. The first one will be non- + // zero, but the second one may be zero, depending on the conversion from + // UTF-32. + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + } + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const char *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + int conversion_count = UTF8ToUTF16Char(str, length, out); + if (!conversion_count) + return false; + + // Move the pointer along based on the nubmer of converted characters + length -= conversion_count; + str += conversion_count; + + // Append the one or two UTF-16 characters + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + return result; +} + +unsigned int MinidumpFileWriter::CalculateNumOfU16s(const wchar_t *str, unsigned int length) { + if (sizeof(wchar_t) == sizeof(uint16_t)) { + // Shortcut if wchar_t is the same size as MDString's buffer + return length; + } else { + uint16_t out[2]; + unsigned int num_of_u16s = 0; + + // Copy the string character by character + while (length) { + UTF32ToUTF16Char(*str, out); + if (!out[0]) + return false; + + // Process one character at a time + --length; + ++str; + + // Count the number of UTF-16 characters needed for every wchar_t + // and add it to the total. + int out_count = out[1] ? 2 : 1; + num_of_u16s += out_count; + } + + return num_of_u16s; + } +} + +unsigned int MinidumpFileWriter::CalculateNumOfU16s(const char *str, unsigned int length) { + uint16_t out[2]; + unsigned int num_of_u16s = 0; + + while (length) { + int conversion_count = UTF8ToUTF16Char(str, length, out); + if (!conversion_count) { + break; + } + // Move the pointer along based on the number of converted characters + length -= conversion_count; + str += conversion_count; + + // Add one or two to the total + int out_count = out[1] ? 2 : 1; + num_of_u16s += out_count; + } + + return num_of_u16s; +} + + +template +bool MinidumpFileWriter::WriteStringCore(const CharType *str, + unsigned int length, + MDLocationDescriptor *location) { + assert(str); + assert(location); + // Calculate the mdstring length by either limiting to |length| as passed in + // or by finding the location of the NULL character. + unsigned int mdstring_length = 0; + if (!length) + length = INT_MAX; + for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) + ; + + unsigned int num_of_u16s = MinidumpFileWriter::CalculateNumOfU16s(str, mdstring_length); + + // Allocate the string buffer + TypedMDRVA mdstring(this); + if (!mdstring.AllocateObjectAndArray(num_of_u16s + 1, sizeof(uint16_t))) + return false; + + // Set length excluding the NULL and copy the string + mdstring.get()->length = + static_cast(num_of_u16s * sizeof(uint16_t)); + bool result = CopyStringToMDString(str, mdstring_length, &mdstring); + + // NULL terminate + if (result) { + uint16_t ch = 0; + result = mdstring.CopyIndexAfterObject(num_of_u16s, &ch, sizeof(ch)); + + if (result) + *location = mdstring.location(); + } + + return result; +} + +bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, + MDMemoryDescriptor *output) { + assert(src); + assert(output); + UntypedMDRVA mem(this); + + if (!mem.Allocate(size)) + return false; + if (!mem.Copy(src, mem.size())) + return false; + + output->start_of_memory_range = reinterpret_cast(src); + output->memory = mem.location(); + + return true; +} + +MDRVA MinidumpFileWriter::Allocate(size_t size) { + assert(size); + assert(file_ != -1); +#if defined(__ANDROID__) + if (NeedsFTruncateWorkAround()) { + // If ftruncate() is not available. We simply increase the size beyond the + // current file size. sys_write() will expand the file when data is written + // to it. Because we did not over allocate to fit memory pages, we also + // do not need to ftruncate() the file once we are done. + size_ += size; + + // We don't need to seek since the file is unchanged. + MDRVA current_position = position_; + position_ += static_cast(size); + return current_position; + } +#endif + size_t aligned_size = (size + 7) & ~7; // 64-bit alignment + + if (position_ + aligned_size > size_) { + size_t growth = aligned_size; + size_t minimal_growth = getpagesize(); + + // Ensure that the file grows by at least the size of a memory page + if (growth < minimal_growth) + growth = minimal_growth; + + size_t new_size = size_ + growth; + if (ftruncate(file_, new_size) != 0) + return kInvalidMDRVA; + + size_ = new_size; + } + + MDRVA current_position = position_; + position_ += static_cast(aligned_size); + + return current_position; +} + +bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { + assert(src); + assert(size); + assert(file_ != -1); + + // Ensure that the data will fit in the allocated space + if (static_cast(size + position) > size_) + return false; + + // Seek and write the data +#if defined(__linux__) && __linux__ + if (sys_lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (sys_write(file_, src, size) == size) { + return true; + } + } +#else + if (lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (write(file_, src, size) == size) { + return true; + } + } +#endif + return false; +} + +bool UntypedMDRVA::Allocate(size_t size) { + assert(size_ == 0); + size_ = size; + position_ = writer_->Allocate(size_); + return position_ != MinidumpFileWriter::kInvalidMDRVA; +} + +bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { + assert(src); + assert(size); + assert(pos + size <= position_ + size_); + return writer_->Copy(pos, src, size); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/minidump_file_writer.h b/toolkit/crashreporter/breakpad-client/minidump_file_writer.h new file mode 100644 index 0000000000..4d41581027 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/minidump_file_writer.h @@ -0,0 +1,281 @@ +// 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 + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class UntypedMDRVA; +template 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 header(&writer_); +// header.Allocate(); +// header->get()->signature = MD_HEADER_SIGNATURE; +// : +// writer.Close(); +// +// An alternative is to use SetFile and provide a file descriptor: +// MinidumpFileWriter writer; +// writer.SetFile(minidump_fd); +// TypedMDRVA 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. If |path| already + // exists, then Open() will fail. + // Return true on success, or false on failure. + bool Open(const char *path); + + // Sets the file descriptor |file| as the destination of the minidump data. + // Can be used as an alternative to Open() when a file descriptor is + // available. + // Note that |fd| is not closed when the instance of MinidumpFileWriter is + // destroyed. + void SetFile(const int file); + + // Close the current file (that was either created when Open was called, or + // specified with SetFile). + // 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_; + + // Whether |file_| should be closed when the instance is destroyed. + bool close_file_when_destroyed_; + + // 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); + bool CopyStringToMDString(const char *str, unsigned int length, + TypedMDRVA *mdstring); + + // The common templated code for writing a string + template + bool WriteStringCore(const CharType *str, unsigned int length, + MDLocationDescriptor *location); + + + // Calculate the number of uint16_t values required to store a wchar_t string + // when its converted to UTF-16. + static unsigned int CalculateNumOfU16s(const wchar_t *str, unsigned int length); + + // Calculate the number of uint16_t values required to store a UTF-8 string + // when its converted to UTF-16. + static unsigned int CalculateNumOfU16s(const char *str, unsigned int length); +}; + +// 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 = { static_cast(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 +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::size() bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(); + + // Allocates minidump_size::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(size_t 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__ diff --git a/toolkit/crashreporter/breakpad-client/minidump_file_writer_unittest.cc b/toolkit/crashreporter/breakpad-client/minidump_file_writer_unittest.cc new file mode 100644 index 0000000000..256e337127 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/minidump_file_writer_unittest.cc @@ -0,0 +1,179 @@ +// 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. + +// Author: waylonis@google.com (Dan Waylonis) + +/* + g++ -I../ ../common/convert_UTF.cc \ + ../common/string_conversion.cc \ + minidump_file_writer.cc \ + minidump_file_writer_unittest.cc \ + -o minidump_file_writer_unittest + */ + +#include +#include + +#include "minidump_file_writer-inl.h" + +using google_breakpad::MinidumpFileWriter; + +#define ASSERT_TRUE(cond) \ +if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + return false; \ +} + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) +#define ASSERT_NE(e1, e2) ASSERT_TRUE((e1) != (e2)) + +struct StringStructure { + unsigned long integer_value; + MDLocationDescriptor first_string; + MDLocationDescriptor second_string; +}; + +struct ArrayStructure { + unsigned char char_value; + unsigned short short_value; + unsigned long long_value; +}; + +typedef struct { + unsigned long count; + ArrayStructure array[0]; +} ObjectAndArrayStructure; + +static bool WriteFile(const char *path) { + MinidumpFileWriter writer; + if (writer.Open(path)) { + // Test a single structure + google_breakpad::TypedMDRVA strings(&writer); + ASSERT_TRUE(strings.Allocate()); + strings.get()->integer_value = 0xBEEF; + const char *first = "First String"; + ASSERT_TRUE(writer.WriteString(first, 0, &strings.get()->first_string)); + const wchar_t *second = L"Second String"; + ASSERT_TRUE(writer.WriteString(second, 0, &strings.get()->second_string)); + + // Test an array structure + google_breakpad::TypedMDRVA array(&writer); + unsigned int count = 10; + ASSERT_TRUE(array.AllocateArray(count)); + for (unsigned char i = 0; i < count; ++i) { + ArrayStructure local; + local.char_value = i; + local.short_value = i + 1; + local.long_value = i + 2; + ASSERT_TRUE(array.CopyIndex(i, &local)); + } + + // Test an object followed by an array + google_breakpad::TypedMDRVA obj_array(&writer); + ASSERT_TRUE(obj_array.AllocateObjectAndArray(count, + sizeof(ArrayStructure))); + obj_array.get()->count = count; + for (unsigned char i = 0; i < count; ++i) { + ArrayStructure local; + local.char_value = i; + local.short_value = i + 1; + local.long_value = i + 2; + ASSERT_TRUE(obj_array.CopyIndexAfterObject(i, &local, sizeof(local))); + } + } + + return writer.Close(); +} + +static bool CompareFile(const char *path) { + unsigned long expected[] = { +#if defined(__BIG_ENDIAN__) + 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, 0x00000038, 0x00000000, + 0x00000018, 0x00460069, 0x00720073, 0x00740020, 0x00530074, 0x00720069, + 0x006e0067, 0x00000000, 0x0000001a, 0x00530065, 0x0063006f, 0x006e0064, + 0x00200053, 0x00740072, 0x0069006e, 0x00670000, 0x00000001, 0x00000002, + 0x01000002, 0x00000003, 0x02000003, 0x00000004, 0x03000004, 0x00000005, + 0x04000005, 0x00000006, 0x05000006, 0x00000007, 0x06000007, 0x00000008, + 0x07000008, 0x00000009, 0x08000009, 0x0000000a, 0x0900000a, 0x0000000b, + 0x0000000a, 0x00000001, 0x00000002, 0x01000002, 0x00000003, 0x02000003, + 0x00000004, 0x03000004, 0x00000005, 0x04000005, 0x00000006, 0x05000006, + 0x00000007, 0x06000007, 0x00000008, 0x07000008, 0x00000009, 0x08000009, + 0x0000000a, 0x0900000a, 0x0000000b, 0x00000000 +#else + 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, + 0x00000038, 0x00000000, 0x00000018, 0x00690046, + 0x00730072, 0x00200074, 0x00740053, 0x00690072, + 0x0067006e, 0x00000000, 0x0000001a, 0x00650053, + 0x006f0063, 0x0064006e, 0x00530020, 0x00720074, + 0x006e0069, 0x00000067, 0x00011e00, 0x00000002, + 0x00021e01, 0x00000003, 0x00031e02, 0x00000004, + 0x00041e03, 0x00000005, 0x00051e04, 0x00000006, + 0x00061e05, 0x00000007, 0x00071e06, 0x00000008, + 0x00081e07, 0x00000009, 0x00091e08, 0x0000000a, + 0x000a1e09, 0x0000000b, 0x0000000a, 0x00011c00, + 0x00000002, 0x00021c01, 0x00000003, 0x00031c02, + 0x00000004, 0x00041c03, 0x00000005, 0x00051c04, + 0x00000006, 0x00061c05, 0x00000007, 0x00071c06, + 0x00000008, 0x00081c07, 0x00000009, 0x00091c08, + 0x0000000a, 0x000a1c09, 0x0000000b, 0x00000000, +#endif + }; + size_t expected_byte_count = sizeof(expected); + int fd = open(path, O_RDONLY, 0600); + void *buffer = malloc(expected_byte_count); + ASSERT_NE(fd, -1); + ASSERT_TRUE(buffer); + ASSERT_EQ(read(fd, buffer, expected_byte_count), + static_cast(expected_byte_count)); + + char *b1, *b2; + b1 = reinterpret_cast(buffer); + b2 = reinterpret_cast(expected); + while (*b1 == *b2) { + b1++; + b2++; + } + + printf("%p\n", reinterpret_cast(b1 - (char*)buffer)); + + ASSERT_EQ(memcmp(buffer, expected, expected_byte_count), 0); + return true; +} + +static bool RunTests() { + const char *path = "/tmp/minidump_file_writer_unittest.dmp"; + ASSERT_TRUE(WriteFile(path)); + ASSERT_TRUE(CompareFile(path)); + unlink(path); + return true; +} + +extern "C" int main(int argc, const char *argv[]) { + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/breakpad-client/moz.build b/toolkit/crashreporter/breakpad-client/moz.build new file mode 100644 index 0000000000..9ee42e4136 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/moz.build @@ -0,0 +1,33 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + 'minidump_file_writer.cc', +] + +Library('breakpad_client') + +USE_LIBS += [ + 'breakpad_common_s', +] + +if CONFIG['OS_ARCH'] == 'Darwin': + USE_LIBS += [ + 'breakpad_mac_common_s', + ] +elif CONFIG['OS_ARCH'] == 'Linux': + USE_LIBS += [ + 'breakpad_linux_common_s', + ] + +FINAL_LIBRARY = 'xul' + +LOCAL_INCLUDES += [ + '/toolkit/crashreporter/google-breakpad/src', +] + +if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CXXFLAGS += ['-Wno-error=stack-protector'] diff --git a/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h b/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h new file mode 100644 index 0000000000..3fd4b9b7e6 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h @@ -0,0 +1,81 @@ +// 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 + +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), taken_(false) { + assert(cs_); + Acquire(); + } + + // Destructor: leaves the critical section. + ~AutoCriticalSection() { + if (taken_) { + Release(); + } + } + + // Enters the critical section. Recursive Acquire() calls are not allowed. + void Acquire() { + assert(!taken_); + EnterCriticalSection(cs_); + taken_ = true; + } + + // Leaves the critical section. The caller should not call Release() unless + // the critical seciton has been entered already. + void Release() { + assert(taken_); + taken_ = false; + LeaveCriticalSection(cs_); + } + + private: + // Disable copy ctor and operator=. + AutoCriticalSection(const AutoCriticalSection&); + AutoCriticalSection& operator=(const AutoCriticalSection&); + + CRITICAL_SECTION* cs_; + bool taken_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__ diff --git a/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h b/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h new file mode 100644 index 0000000000..c74868198c --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h @@ -0,0 +1,181 @@ +// 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 +#include +#include +#include +#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, + MESSAGE_TAG_UPLOAD_REQUEST = 4 +}; + +struct CustomClientInfo { + const CustomInfoEntry* entries; + size_t count; +}; + +// Message structure for IPC between crash client and crash server. +struct ProtocolMessage { + ProtocolMessage() + : tag(MESSAGE_TAG_NONE), + id(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_id, + 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), + id(arg_id), + 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; + + // The id for this message. This may be either a process id or a crash id + // depending on the type of message. + DWORD id; + + // 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__ diff --git a/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc new file mode 100644 index 0000000000..54d8e25274 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc @@ -0,0 +1,319 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "minidump_callback.h" + +#include + +#include +#include + +namespace google_breakpad { + +static const DWORD sHeapRegionSize= 1024; +static DWORD sPageSize = 0; + +using NtQueryInformationThreadFunc = decltype(::NtQueryInformationThread); +static NtQueryInformationThreadFunc* sNtQueryInformationThread = nullptr; + + +namespace { +enum { + ThreadBasicInformation, +}; + +struct CLIENT_ID { + PVOID UniqueProcess; + PVOID UniqueThread; +}; + +struct THREAD_BASIC_INFORMATION { + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + KAFFINITY AffMask; + DWORD Priority; + DWORD BasePriority; +}; +} + +void InitAppMemoryInternal() +{ + if (!sPageSize) { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + sPageSize = systemInfo.dwPageSize; + } + + if (!sNtQueryInformationThread) { + sNtQueryInformationThread = (NtQueryInformationThreadFunc*) + (::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), + "NtQueryInformationThread")); + } +} + +bool GetAppMemoryFromRegister(HANDLE aProcess, + const NT_TIB* aTib, + RegisterValueType aRegister, + AppMemory* aResult) +{ + static_assert(sizeof(RegisterValueType) == sizeof(void*), + "Size mismatch between DWORD/DWORD64 and void*"); + + if (!sPageSize) { + // GetSystemInfo() should not fail, but bail out just in case it fails. + return false; + } + + RegisterValueType addr = aRegister; + addr &= ~(static_cast(sPageSize) - 1); + + if (aTib) { + if (aRegister >= (RegisterValueType)aTib->StackLimit && + aRegister <= (RegisterValueType)aTib->StackBase) { + // aRegister points to the stack. + return false; + } + } + + MEMORY_BASIC_INFORMATION memInfo; + memset(&memInfo, 0, sizeof(memInfo)); + SIZE_T rv = ::VirtualQueryEx(aProcess, + reinterpret_cast(addr), + &memInfo, + sizeof(memInfo)); + if (!rv) { + // VirtualQuery fails: aAddr is not on heap. + return false; + } + + // Check protection and type of the memory region. Include the region if it's + // 1. read-write: heap, or + // 2. read-executable and private: likely to be JIT code. + if (memInfo.Protect != PAGE_READWRITE && + memInfo.Protect != PAGE_EXECUTE_READ) { + return false; + } + + // Try to include a region of size sHeapRegionSize around aRegister, bounded + // by the [BaseAddress, BaseAddress + RegionSize]. + RegisterValueType lower = + std::max(aRegister - sHeapRegionSize / 2, + reinterpret_cast(memInfo.BaseAddress)); + + RegisterValueType upper = + std::min(lower + sHeapRegionSize, + reinterpret_cast(memInfo.BaseAddress) + + memInfo.RegionSize); + + aResult->ptr = lower; + aResult->length = upper - lower; + + return true; +} + +static AppMemoryList::iterator +FindNextPreallocated(AppMemoryList& aList, AppMemoryList::iterator aBegin) { + auto it = aBegin; + for (auto it = aBegin; it != aList.end(); it++) { + if (it->preallocated) { + return it; + } + } + + assert(it == aList.end()); + return it; +} + +static bool +GetThreadTib(HANDLE aProcess, DWORD aThreadId, NT_TIB* aTib) { + HANDLE threadHandle = ::OpenThread(THREAD_QUERY_INFORMATION, + FALSE, + aThreadId); + if (!threadHandle) { + return false; + } + + if (!sNtQueryInformationThread) { + return false; + } + + THREAD_BASIC_INFORMATION threadInfo; + auto status = (*sNtQueryInformationThread)(threadHandle, + (THREADINFOCLASS)ThreadBasicInformation, + &threadInfo, + sizeof(threadInfo), + NULL); + if (!NT_SUCCESS(status)) { + return false; + } + + auto readSuccess = ::ReadProcessMemory(aProcess, + threadInfo.TebBaseAddress, + aTib, + sizeof(*aTib), + NULL); + if (!readSuccess) { + return false; + } + + ::CloseHandle(threadHandle); + return true; +} + +void IncludeAppMemoryFromExceptionContext(HANDLE aProcess, + DWORD aThreadId, + AppMemoryList& aList, + PCONTEXT aExceptionContext, + bool aInstructionPointerOnly) { + RegisterValueType heapAddrCandidates[kExceptionAppMemoryRegions]; + size_t numElements = 0; + + NT_TIB tib; + memset(&tib, 0, sizeof(tib)); + if (!GetThreadTib(aProcess, aThreadId, &tib)) { + // Fail to query thread stack range: only safe to include the region around + // the instruction pointer. + aInstructionPointerOnly = true; + } + + // Add registers that might have a heap address to heapAddrCandidates. + // Note that older versions of DbgHelp.dll don't correctly put the memory + // around the faulting instruction pointer into the minidump. Include Rip/Eip + // unconditionally ensures it gets included. +#if defined(_M_IX86) + if (!aInstructionPointerOnly) { + heapAddrCandidates[numElements++] = aExceptionContext->Eax; + heapAddrCandidates[numElements++] = aExceptionContext->Ebx; + heapAddrCandidates[numElements++] = aExceptionContext->Ecx; + heapAddrCandidates[numElements++] = aExceptionContext->Edx; + heapAddrCandidates[numElements++] = aExceptionContext->Esi; + heapAddrCandidates[numElements++] = aExceptionContext->Edi; + } + heapAddrCandidates[numElements++] = aExceptionContext->Eip; +#elif defined(_M_AMD64) + if (!aInstructionPointerOnly) { + heapAddrCandidates[numElements++] = aExceptionContext->Rax; + heapAddrCandidates[numElements++] = aExceptionContext->Rbx; + heapAddrCandidates[numElements++] = aExceptionContext->Rcx; + heapAddrCandidates[numElements++] = aExceptionContext->Rdx; + heapAddrCandidates[numElements++] = aExceptionContext->Rsi; + heapAddrCandidates[numElements++] = aExceptionContext->Rdi; + heapAddrCandidates[numElements++] = aExceptionContext->R8; + heapAddrCandidates[numElements++] = aExceptionContext->R9; + heapAddrCandidates[numElements++] = aExceptionContext->R10; + heapAddrCandidates[numElements++] = aExceptionContext->R11; + heapAddrCandidates[numElements++] = aExceptionContext->R12; + heapAddrCandidates[numElements++] = aExceptionContext->R13; + heapAddrCandidates[numElements++] = aExceptionContext->R14; + heapAddrCandidates[numElements++] = aExceptionContext->R15; + } + heapAddrCandidates[numElements++] = aExceptionContext->Rip; +#elif defined(_M_ARM64) + if (!aInstructionPointerOnly) { + for (auto reg : aExceptionContext->X) { + heapAddrCandidates[numElements++] = reg; + } + heapAddrCandidates[numElements++] = aExceptionContext->Sp; + } + heapAddrCandidates[numElements++] = aExceptionContext->Pc; +#endif + + // Inplace sort the candidates for excluding or merging memory regions. + auto begin = &heapAddrCandidates[0], end = &heapAddrCandidates[numElements]; + std::make_heap(begin, end); + std::sort_heap(begin, end); + + auto appMemory = FindNextPreallocated(aList, aList.begin()); + for (size_t i = 0; i < numElements; i++) { + if (appMemory == aList.end()) { + break; + } + + AppMemory tmp{}; + if (!GetAppMemoryFromRegister(aProcess, + aInstructionPointerOnly ? nullptr : &tib, + heapAddrCandidates[i], + &tmp)) { + continue; + } + + if (!(tmp.ptr && tmp.length)) { + // Something unexpected happens. Skip this candidate. + continue; + } + + if (!appMemory->ptr) { + *appMemory = tmp; + continue; + } + + if (appMemory->ptr + appMemory->length > tmp.ptr) { + // The beginning of the next region fall within the range of the previous + // region: merge into one. Note that we don't merge adjacent regions like + // [0, 99] and [100, 199] in case we cross the border of memory allocation + // regions. + appMemory->length = tmp.ptr + tmp.length - appMemory->ptr; + continue; + } + + appMemory = FindNextPreallocated(aList, ++appMemory); + if (appMemory == aList.end()) { + break; + } + + *appMemory = tmp; + } +} + +BOOL CALLBACK MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output) { + switch (callback_input->CallbackType) { + case MemoryCallback: { + MinidumpCallbackContext* callback_context = + reinterpret_cast(context); + + // Skip unused preallocated AppMemory elements. + while (callback_context->iter != callback_context->end && + callback_context->iter->preallocated && + !callback_context->iter->ptr) { + callback_context->iter++; + } + + if (callback_context->iter == callback_context->end) + return FALSE; + + // Include the specified memory region. + callback_output->MemoryBase = callback_context->iter->ptr; + callback_output->MemorySize = callback_context->iter->length; + callback_context->iter++; + return TRUE; + } + + // Include all modules. + case IncludeModuleCallback: + case ModuleCallback: + return TRUE; + + // Include all threads. + case IncludeThreadCallback: + case ThreadCallback: + return TRUE; + + // Stop receiving cancel callbacks. + case CancelCallback: + callback_output->CheckCancel = FALSE; + callback_output->Cancel = FALSE; + return TRUE; + } + // Ignore other callback types. + return FALSE; +} + +} // namespace google_breakpad + diff --git a/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h new file mode 100644 index 0000000000..1306235cfd --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MINIDUMP_CALLBACK_H__ +#define MINIDUMP_CALLBACK_H__ + +#include +#include + +#include + +namespace google_breakpad { + +// These entries store a list of memory regions that the client wants included +// in the minidump. +struct AppMemory { + ULONG64 ptr; + ULONG length; + bool preallocated; + + bool operator==(const struct AppMemory& other) const { + return ptr == other.ptr; + } + + bool operator==(const void* other) const { + return ptr == reinterpret_cast(other); + } + + AppMemory() + : ptr(0) + , length(0) + , preallocated(false) + {} + + AppMemory& operator=(const AppMemory& other) = default; +}; +typedef std::list AppMemoryList; + +// This is passed as the context to the MinidumpWriteDump callback. +typedef struct { + AppMemoryList::const_iterator iter; + AppMemoryList::const_iterator end; +} MinidumpCallbackContext; + +static const size_t kExceptionAppMemoryRegions = 33; + +#if defined(_M_IX86) +using RegisterValueType = DWORD; +#elif defined(_M_AMD64) || defined(_M_ARM64) +using RegisterValueType = DWORD64; +#else +#error Unsupported platform +#endif + +void IncludeAppMemoryFromExceptionContext(HANDLE aProcess, + DWORD aThreadId, + AppMemoryList& aList, + PCONTEXT aExceptionContext, + bool aInsttructionPointerOnly); + +// This function is used as a callback when calling MinidumpWriteDump, +// in order to add additional memory regions to the dump. +BOOL CALLBACK MinidumpWriteDumpCallback( + PVOID context, + const PMINIDUMP_CALLBACK_INPUT callback_input, + PMINIDUMP_CALLBACK_OUTPUT callback_output); + +// Called during startup to initialize system information used by +// IncludeAppMemoryFromExceptionContext(). +void InitAppMemoryInternal(); + +} // namespace google_breakpad + +#endif + diff --git a/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild b/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild new file mode 100644 index 0000000000..ddc1d58d56 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +lobjs_client_common = [ + 'minidump_callback.cc', +] + +subdir = 'toolkit/crashreporter/breakpad-client/windows/common' +objs_client_common = [ + '/%s/%s' % (subdir, s) for s in lobjs_client_common +] diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/ReadMe.txt b/toolkit/crashreporter/breakpad-client/windows/crash_generation/ReadMe.txt new file mode 100644 index 0000000000..b54d0e11b7 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/ReadMe.txt @@ -0,0 +1,58 @@ +========================================================================= + State machine transitions for the Crash Generation Server +========================================================================= + +========================================================================= + | + STATE | ACTIONS + | +========================================================================= + ERROR | Clean up resources used to serve clients. + | Always remain in ERROR state. +------------------------------------------------------------------------- + INITIAL | Connect to the pipe asynchronously. + | If connection is successfully queued up asynchronously, + | go into CONNECTING state. + | If connection is done synchronously, go into CONNECTED + | state. + | For any unexpected problems, go into ERROR state. +------------------------------------------------------------------------- + CONNECTING | Get the result of async connection request. + | If I/O is still incomplete, remain in the CONNECTING + | state. + | If connection is complete, go into CONNECTED state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + CONNECTED | Read from the pipe asynchronously. + | If read request is successfully queued up asynchronously, + | go into READING state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READING | Get the result of async read request. + | If read is done, go into READ_DONE state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READ_DONE | Register the client, prepare the reply and write the + | reply to the pipe asynchronously. + | If write request is successfully queued up asynchronously, + | go into WRITING state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + WRITING | Get the result of the async write request. + | If write is done, go into WRITE_DONE state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + WRITE_DONE | Read from the pipe asynchronously (for an ACK). + | If read request is successfully queued up asynchonously, + | go into READING_ACK state. + | For any unexpected problems, go into DISCONNECTING state. +------------------------------------------------------------------------- + READING_ACK | Get the result of the async read request. + | If read is done, perform action for successful client + | connection. + | Go into DISCONNECTING state. +------------------------------------------------------------------------- + DISCONNECTING | Disconnect from the pipe, reset the event and go into + | INITIAL state and signal the event again. If anything + | fails, go into ERROR state. +========================================================================= diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc new file mode 100644 index 0000000000..5e443241c1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc @@ -0,0 +1,258 @@ +// 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. + +#include + +#include "windows/crash_generation/client_info.h" +#include "windows/common/ipc_protocol.h" + +static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime"; +static const size_t kMaxCustomInfoEntries = 4096; + +namespace google_breakpad { + +ClientInfo::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) + : crash_server_(crash_server), + pid_(pid), + dump_type_(dump_type), + ex_info_(ex_info), + assert_info_(assert_info), + custom_client_info_(custom_client_info), + thread_id_(thread_id), + process_handle_(NULL), + dump_requested_handle_(NULL), + dump_generated_handle_(NULL), + dump_request_wait_handle_(NULL), + process_exit_wait_handle_(NULL), + crash_id_(NULL) { + GetSystemTimeAsFileTime(&start_time_); +} + +bool ClientInfo::Initialize() { + process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_); + if (!process_handle_) { + return false; + } + + // The crash_id will be the low order word of the process creation time. + FILETIME creation_time, exit_time, kernel_time, user_time; + if (GetProcessTimes(process_handle_, &creation_time, &exit_time, + &kernel_time, &user_time)) { + start_time_ = creation_time; + } + crash_id_ = start_time_.dwLowDateTime; + + dump_requested_handle_ = CreateEvent(NULL, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + NULL); // Name. + if (!dump_requested_handle_) { + return false; + } + + dump_generated_handle_ = CreateEvent(NULL, // Security attributes. + TRUE, // Manual reset. + FALSE, // Initial state. + NULL); // Name. + return dump_generated_handle_ != NULL; +} + +void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() { + if (dump_request_wait_handle_) { + // Wait for callbacks that might already be running to finish. + UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE); + dump_request_wait_handle_ = NULL; + } +} + +void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) { + if (process_exit_wait_handle_) { + if (block_until_no_pending) { + // Wait for the callback that might already be running to finish. + UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE); + } else { + UnregisterWait(process_exit_wait_handle_); + } + process_exit_wait_handle_ = NULL; + } +} + +ClientInfo::~ClientInfo() { + // Waiting for the callback to finish here is safe because ClientInfo's are + // never destroyed from the dump request handling callback. + UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // This is a little tricky because ClientInfo's may be destroyed by the same + // callback (OnClientEnd) and waiting for it to finish will cause a deadlock. + // Regardless of this complication, wait for any running callbacks to finish + // so that the common case is properly handled. In order to avoid deadlocks, + // the OnClientEnd callback must call UnregisterProcessExitWait(false) + // before deleting the ClientInfo. + UnregisterProcessExitWait(true); + + if (process_handle_) { + CloseHandle(process_handle_); + } + + if (dump_requested_handle_) { + CloseHandle(dump_requested_handle_); + } + + if (dump_generated_handle_) { + CloseHandle(dump_generated_handle_); + } +} + +bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info_ptr) const { + SIZE_T bytes_count = 0; + + static_assert(sizeof(*ex_info_ptr) == sizeof(void*), + "Expected to read sizeof(void*) bytes."); + if (!ReadProcessMemory(process_handle_, + ex_info_, + ex_info_ptr, + sizeof(*ex_info_ptr), + &bytes_count)) { + return false; + } + + return bytes_count == sizeof(*ex_info_ptr); +} + +bool ClientInfo::PopulateClientExceptionContext(EXCEPTION_POINTERS* ex_info_ptr, + CONTEXT* out_context) const { + SIZE_T bytes_count = 0; + + EXCEPTION_POINTERS ex_info; + if (!ReadProcessMemory(process_handle_, + ex_info_ptr, + &ex_info, + sizeof(ex_info), + &bytes_count)) { + return false; + } + + if (bytes_count != sizeof(ex_info)) { + return false; + } + + static_assert(sizeof(*out_context) == sizeof(CONTEXT), + "Expected to read sizeof(CONTEXT) bytes."); + if (!ReadProcessMemory(process_handle_, + ex_info.ContextRecord, + out_context, + sizeof(*out_context), + &bytes_count)) { + return false; + } + + return bytes_count == sizeof(*out_context); +} + +bool ClientInfo::GetClientThreadId(DWORD* thread_id) const { + SIZE_T bytes_count = 0; + if (!ReadProcessMemory(process_handle_, + thread_id_, + thread_id, + sizeof(*thread_id), + &bytes_count)) { + return false; + } + + return bytes_count == sizeof(*thread_id); +} + +void ClientInfo::SetProcessUptime() { + FILETIME now = {0}; + GetSystemTimeAsFileTime(&now); + + ULARGE_INTEGER time_start; + time_start.HighPart = start_time_.dwHighDateTime; + time_start.LowPart = start_time_.dwLowDateTime; + + ULARGE_INTEGER time_now; + time_now.HighPart = now.dwHighDateTime; + time_now.LowPart = now.dwLowDateTime; + + // Calculate the delay and convert it from 100-nanoseconds to milliseconds. + __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000; + + // Convert it to a string. + wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value; + _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10); +} + +bool ClientInfo::PopulateCustomInfo() { + if (custom_client_info_.count > kMaxCustomInfoEntries) + return false; + + SIZE_T bytes_count = 0; + SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count; + + // If the scoped array for custom info already has an array, it will be + // the same size as what we need. This is because the number of custom info + // entries is always the same. So allocate memory only if scoped array has + // a NULL pointer. + if (!custom_info_entries_.get()) { + // Allocate an extra entry for reporting uptime for the client process. + custom_info_entries_.reset( + new CustomInfoEntry[custom_client_info_.count + 1]); + // Use the last element in the array for uptime. + custom_info_entries_.get()[custom_client_info_.count].set_name( + kCustomInfoProcessUptimeName); + } + + if (!ReadProcessMemory(process_handle_, + custom_client_info_.entries, + custom_info_entries_.get(), + read_count, + &bytes_count)) { + return false; + } + + SetProcessUptime(); + return (bytes_count == read_count); +} + +CustomClientInfo ClientInfo::GetCustomInfo() const { + CustomClientInfo custom_info; + custom_info.entries = custom_info_entries_.get(); + // Add 1 to the count from the client process to account for extra entry for + // process uptime. + custom_info.count = custom_client_info_.count + 1; + return custom_info; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h new file mode 100644 index 0000000000..506099dcdc --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h @@ -0,0 +1,182 @@ +// 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 +#include +#include "windows/common/ipc_protocol.h" +#include "common/scoped_ptr.h" +#include "google_breakpad/common/minidump_format.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_; } + DWORD crash_id() const { return crash_id_; } + const CustomClientInfo& custom_client_info() const { + return custom_client_info_; + } + + void set_dump_request_wait_handle(HANDLE value) { + dump_request_wait_handle_ = value; + } + + void set_process_exit_wait_handle(HANDLE value) { + process_exit_wait_handle_ = value; + } + + // Unregister the dump request wait operation and wait for all callbacks + // that might already be running to complete before returning. + void UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // Unregister the process exit wait operation. If block_until_no_pending is + // true, wait for all callbacks that might already be running to complete + // before returning. + void UnregisterProcessExitWait(bool block_until_no_pending); + + bool Initialize(); + bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info_ptr) const; + + // Reads the content of exception CONTEXT from the client process. + bool PopulateClientExceptionContext(EXCEPTION_POINTERS* ex_info, + CONTEXT* out_context) 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 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_; + + // The crash id which can be used to request an upload. This will be the + // value of the low order dword of the process creation time for the process + // being dumped. + DWORD crash_id_; + + // 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__ diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.cc b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.cc new file mode 100644 index 0000000000..0e524e7854 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.cc @@ -0,0 +1,406 @@ +// 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. + +#include "windows/crash_generation/crash_generation_client.h" +#include +#include +#include "windows/common/ipc_protocol.h" + +namespace google_breakpad { + +const int kPipeBusyWaitTimeoutMs = 2000; + +#ifdef _DEBUG +const DWORD kWaitForServerTimeoutMs = INFINITE; +#else +const DWORD kWaitForServerTimeoutMs = 15000; +#endif + +const int kPipeConnectMaxAttempts = 6; + +const DWORD kPipeDesiredAccess = FILE_READ_DATA | + FILE_WRITE_DATA | + FILE_WRITE_ATTRIBUTES; + +const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION | + SECURITY_SQOS_PRESENT; + +const DWORD kPipeMode = PIPE_READMODE_MESSAGE; + +const size_t kWaitEventCount = 2; + +// This function is orphan for production code. It can be used +// for debugging to help repro some scenarios like the client +// is slow in writing to the pipe after connecting, the client +// is slow in reading from the pipe after writing, etc. The parameter +// overlapped below is not used and it is present to match the signature +// of this function to TransactNamedPipe Win32 API. Uncomment if needed +// for debugging. +/** +static bool TransactNamedPipeDebugHelper(HANDLE pipe, + const void* in_buffer, + DWORD in_size, + void* out_buffer, + DWORD out_size, + DWORD* bytes_count, + LPOVERLAPPED) { + // Uncomment the next sleep to create a gap before writing + // to pipe. + // Sleep(5000); + + if (!WriteFile(pipe, + in_buffer, + in_size, + bytes_count, + NULL)) { + return false; + } + + // Uncomment the next sleep to create a gap between write + // and read. + // Sleep(5000); + + return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE; +} +**/ + +CrashGenerationClient::CrashGenerationClient( + const wchar_t* pipe_name, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info) + : pipe_name_(pipe_name), + pipe_handle_(NULL), + custom_info_(), + dump_type_(dump_type), + crash_event_(NULL), + crash_generated_(NULL), + server_alive_(NULL), + server_process_id_(0), + thread_id_(0), + exception_pointers_(NULL) { + memset(&assert_info_, 0, sizeof(assert_info_)); + if (custom_info) { + custom_info_ = *custom_info; + } +} + +CrashGenerationClient::CrashGenerationClient( + HANDLE pipe_handle, + MINIDUMP_TYPE dump_type, + const CustomClientInfo* custom_info) + : pipe_name_(), + pipe_handle_(pipe_handle), + custom_info_(), + dump_type_(dump_type), + crash_event_(NULL), + crash_generated_(NULL), + server_alive_(NULL), + server_process_id_(0), + thread_id_(0), + exception_pointers_(NULL) { + memset(&assert_info_, 0, sizeof(assert_info_)); + if (custom_info) { + custom_info_ = *custom_info; + } +} + +CrashGenerationClient::~CrashGenerationClient() { + if (crash_event_) { + CloseHandle(crash_event_); + } + + if (crash_generated_) { + CloseHandle(crash_generated_); + } + + if (server_alive_) { + CloseHandle(server_alive_); + } +} + +// Performs the registration step with the server process. +// The registration step involves communicating with the server +// via a named pipe. The client sends the following pieces of +// data to the server: +// +// * Message tag indicating the client is requesting registration. +// * Process id of the client process. +// * Address of a DWORD variable in the client address space +// that will contain the thread id of the client thread that +// caused the crash. +// * Address of a EXCEPTION_POINTERS* variable in the client +// address space that will point to an instance of EXCEPTION_POINTERS +// when the crash happens. +// * Address of an instance of MDRawAssertionInfo that will contain +// relevant information in case of non-exception crashes like assertion +// failures and pure calls. +// +// In return the client expects the following information from the server: +// +// * Message tag indicating successful registration. +// * Server process id. +// * Handle to an object that client can signal to request dump +// generation from the server. +// * Handle to an object that client can wait on after requesting +// dump generation for the server to finish dump generation. +// * Handle to a mutex object that client can wait on to make sure +// server is still alive. +// +// If any step of the expected behavior mentioned above fails, the +// registration step is not considered successful and hence out-of-process +// dump generation service is not available. +// +// Returns true if the registration is successful; false otherwise. +bool CrashGenerationClient::Register() { + if (IsRegistered()) { + return true; + } + + HANDLE pipe = ConnectToServer(); + if (!pipe) { + return false; + } + + bool success = RegisterClient(pipe); + CloseHandle(pipe); + return success; +} + +bool CrashGenerationClient::RequestUpload(DWORD crash_id) { + HANDLE pipe = ConnectToServer(); + if (!pipe) { + return false; + } + + CustomClientInfo custom_info = {NULL, 0}; + ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id, + static_cast(NULL), NULL, NULL, NULL, + custom_info, NULL, NULL, NULL); + DWORD bytes_count = 0; + bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0; + + CloseHandle(pipe); + return success; +} + +HANDLE CrashGenerationClient::ConnectToServer() { + HANDLE pipe = ConnectToPipe(pipe_name_.c_str(), + kPipeDesiredAccess, + kPipeFlagsAndAttributes); + if (!pipe) { + return NULL; + } + + DWORD mode = kPipeMode; + if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) { + CloseHandle(pipe); + pipe = NULL; + } + + return pipe; +} + +bool CrashGenerationClient::RegisterClient(HANDLE pipe) { + ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST, + GetCurrentProcessId(), + dump_type_, + &thread_id_, + &exception_pointers_, + &assert_info_, + custom_info_, + NULL, + NULL, + NULL); + ProtocolMessage reply; + DWORD bytes_count = 0; + // The call to TransactNamedPipe below can be changed to a call + // to TransactNamedPipeDebugHelper to help repro some scenarios. + // For details see comments for TransactNamedPipeDebugHelper. + if (!TransactNamedPipe(pipe, + &msg, + sizeof(msg), + &reply, + sizeof(ProtocolMessage), + &bytes_count, + NULL)) { + return false; + } + + if (!ValidateResponse(reply)) { + return false; + } + + ProtocolMessage ack_msg; + ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK; + + if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) { + return false; + } + crash_event_ = reply.dump_request_handle; + crash_generated_ = reply.dump_generated_handle; + server_alive_ = reply.server_alive_handle; + server_process_id_ = reply.id; + + return true; +} + +HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name, + DWORD pipe_access, + DWORD flags_attrs) { + if (pipe_handle_) { + HANDLE t = pipe_handle_; + pipe_handle_ = NULL; + return t; + } + + for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { + HANDLE pipe = CreateFile(pipe_name, + pipe_access, + 0, + NULL, + OPEN_EXISTING, + flags_attrs, + NULL); + if (pipe != INVALID_HANDLE_VALUE) { + return pipe; + } + + // Cannot continue retrying if error is something other than + // ERROR_PIPE_BUSY. + if (GetLastError() != ERROR_PIPE_BUSY) { + break; + } + + // Cannot continue retrying if wait on pipe fails. + if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) { + break; + } + } + + fprintf(stderr, "ConnectToPipe() failure: GetLastError()=%08lx\n", GetLastError()); + return NULL; +} + +bool CrashGenerationClient::ValidateResponse( + const ProtocolMessage& msg) const { + return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) && + (msg.id != 0) && + (msg.dump_request_handle != NULL) && + (msg.dump_generated_handle != NULL) && + (msg.server_alive_handle != NULL); +} + +bool CrashGenerationClient::IsRegistered() const { + return crash_event_ != NULL; +} + +bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info, + MDRawAssertionInfo* assert_info) { + if (!IsRegistered()) { + return false; + } + + exception_pointers_ = ex_info; + thread_id_ = GetCurrentThreadId(); + + if (assert_info) { + memcpy(&assert_info_, assert_info, sizeof(assert_info_)); + } else { + memset(&assert_info_, 0, sizeof(assert_info_)); + } + + return SignalCrashEventAndWait(); +} + +bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) { + return RequestDump(ex_info, NULL); +} + +bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) { + return RequestDump(NULL, assert_info); +} + +bool CrashGenerationClient::SignalCrashEventAndWait() { + assert(crash_event_); + assert(crash_generated_); + assert(server_alive_); + + // Reset the dump generated event before signaling the crash + // event so that the server can set the dump generated event + // once it is done generating the event. + if (!ResetEvent(crash_generated_)) { + return false; + } + + if (!SetEvent(crash_event_)) { + return false; + } + + HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_}; + + DWORD result = WaitForMultipleObjects(kWaitEventCount, + wait_handles, + FALSE, + kWaitForServerTimeoutMs); + + // Crash dump was successfully generated only if the server + // signaled the crash generated event. + return result == WAIT_OBJECT_0; +} + +HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const wchar_t* pipe_name, + HANDLE hProcess) { + for (int i = 0; i < kPipeConnectMaxAttempts; ++i) { + HANDLE local_pipe = CreateFile(pipe_name, kPipeDesiredAccess, + 0, NULL, OPEN_EXISTING, + kPipeFlagsAndAttributes, NULL); + if (local_pipe != INVALID_HANDLE_VALUE) { + HANDLE remotePipe = INVALID_HANDLE_VALUE; + if (DuplicateHandle(GetCurrentProcess(), local_pipe, + hProcess, &remotePipe, 0, FALSE, + DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { + return remotePipe; + } else { + return INVALID_HANDLE_VALUE; + } + } + + // Cannot continue retrying if the error wasn't a busy pipe. + if (GetLastError() != ERROR_PIPE_BUSY) { + return INVALID_HANDLE_VALUE; + } + + if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) { + return INVALID_HANDLE_VALUE; + } + } + return INVALID_HANDLE_VALUE; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.h b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.h new file mode 100644 index 0000000000..0bfcdb3731 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_client.h @@ -0,0 +1,182 @@ +// 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 +#include +#include +#include +#include "windows/common/ipc_protocol.h" +#include "common/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(HANDLE pipe_handle, + 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 upload a previous dump with the + // given crash id. + bool RequestUpload(DWORD crash_id); + + bool RequestDump(EXCEPTION_POINTERS* ex_info, + MDRawAssertionInfo* assert_info); + + // 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); + + // If the crash generation client is running in a sandbox that prevents it + // from opening the named pipe directly, the server process may open the + // handle and duplicate it into the client process with this helper method. + // Returns INVALID_HANDLE_VALUE on failure. The process must have been opened + // with the PROCESS_DUP_HANDLE access right. + static HANDLE DuplicatePipeToClientProcess(const wchar_t* pipe_name, + HANDLE hProcess); + + 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_; + + // Pipe handle duplicated from server process. Only valid before + // Register is called. + HANDLE pipe_handle_; + + // 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_ diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc new file mode 100644 index 0000000000..dfa6d5161f --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc @@ -0,0 +1,996 @@ +// 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. + +#include "windows/crash_generation/crash_generation_server.h" +#include +#include +#include +#include "windows/common/auto_critical_section.h" +#include "common/scoped_ptr.h" + +#include "windows/crash_generation/client_info.h" + +namespace google_breakpad { + +// Output buffer size. +static const size_t kOutBufferSize = 64; + +// Input buffer size. +static const size_t kInBufferSize = 64; + +// Access flags for the client on the dump request event. +static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE; + +// Access flags for the client on the dump generated event. +static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE | + SYNCHRONIZE; + +// Access flags for the client on the mutex. +static const DWORD kMutexAccess = SYNCHRONIZE; + +// Attribute flags for the pipe. +static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE | + PIPE_ACCESS_DUPLEX | + FILE_FLAG_OVERLAPPED; + +// Mode for the pipe. +static const DWORD kPipeMode = PIPE_TYPE_MESSAGE | + PIPE_READMODE_MESSAGE | + PIPE_WAIT; + +// For pipe I/O, execute the callback in the wait thread itself, +// since the callback does very little work. The callback executes +// the code for one of the states of the server state machine and +// the code for all of the states perform async I/O and hence +// finish very quickly. +static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD; + +// Dump request threads will, most likely, generate dumps. That may +// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag. +static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD | + WT_EXECUTELONGFUNCTION; + +static bool IsClientRequestValid(const ProtocolMessage& msg) { + return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST || + (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST && + msg.id != 0 && + msg.thread_id != NULL && + msg.exception_pointers != NULL && + msg.assert_info != NULL); +} + +#ifndef NDEBUG +static bool CheckForIOIncomplete(bool success) { + // We should never get an I/O incomplete since we should not execute this + // unless the operation has finished and the overlapped event is signaled. If + // we do get INCOMPLETE, we have a bug in our code. + return success ? false : (GetLastError() == ERROR_IO_INCOMPLETE); +} +#endif + +CrashGenerationServer::CrashGenerationServer( + const std::wstring& pipe_name, + SECURITY_ATTRIBUTES* pipe_sec_attrs, + OnClientConnectedCallback connect_callback, + void* connect_context, + OnClientDumpRequestCallback dump_callback, + void* dump_context, + OnClientDumpWrittenCallback written_callback, + OnClientExitedCallback exit_callback, + void* exit_context, + OnClientUploadRequestCallback upload_request_callback, + void* upload_context, + bool generate_dumps, + const std::wstring* dump_path) + : pipe_name_(pipe_name), + pipe_sec_attrs_(pipe_sec_attrs), + pipe_(NULL), + pipe_wait_handle_(NULL), + server_alive_handle_(NULL), + connect_callback_(connect_callback), + connect_context_(connect_context), + dump_callback_(dump_callback), + dump_context_(dump_context), + written_callback_(written_callback), + exit_callback_(exit_callback), + exit_context_(exit_context), + upload_request_callback_(upload_request_callback), + upload_context_(upload_context), + generate_dumps_(generate_dumps), + pre_fetch_custom_info_(true), + dump_path_(dump_path ? *dump_path : L""), + server_state_(IPC_SERVER_STATE_UNINITIALIZED), + shutting_down_(false), + overlapped_(), + client_info_(NULL), + include_context_heap_(false) { + InitializeCriticalSection(&sync_); +} + +// This should never be called from the OnPipeConnected callback. +// Otherwise the UnregisterWaitEx call below will cause a deadlock. +CrashGenerationServer::~CrashGenerationServer() { + // New scope to release the lock automatically. + { + // Make sure no clients are added or removed beyond this point. + // Before adding or removing any clients, the critical section + // must be entered and the shutting_down_ flag checked. The + // critical section is then exited only after the clients_ list + // modifications are done and the list is in a consistent state. + AutoCriticalSection lock(&sync_); + + // Indicate to existing threads that server is shutting down. + shutting_down_ = true; + } + // No one will modify the clients_ list beyond this point - + // not even from another thread. + + // Even if there are no current worker threads running, it is possible that + // an I/O request is pending on the pipe right now but not yet done. + // In fact, it's very likely this is the case unless we are in an ERROR + // state. If we don't wait for the pending I/O to be done, then when the I/O + // completes, it may write to invalid memory. AppVerifier will flag this + // problem too. So we disconnect from the pipe and then wait for the server + // to get into error state so that the pending I/O will fail and get + // cleared. + DisconnectNamedPipe(pipe_); + int num_tries = 100; + while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) { + Sleep(10); + } + + // Unregister wait on the pipe. + if (pipe_wait_handle_) { + // Wait for already executing callbacks to finish. + UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE); + } + + // Close the pipe to avoid further client connections. + if (pipe_) { + CloseHandle(pipe_); + } + + // Request all ClientInfo objects to unregister all waits. + // No need to enter the critical section because no one is allowed to modify + // the clients_ list once the shutting_down_ flag is set. + std::list::iterator iter; + for (iter = clients_.begin(); iter != clients_.end(); ++iter) { + ClientInfo* client_info = *iter; + // Unregister waits. Wait for already executing callbacks to finish. + // Unregister the client process exit wait first and only then unregister + // the dump request wait. The reason is that the OnClientExit callback + // also unregisters the dump request wait and such a race (doing the same + // unregistration from two threads) is undesirable. + client_info->UnregisterProcessExitWait(true); + client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + // Destroying the ClientInfo here is safe because all wait operations for + // this ClientInfo were unregistered and no pending or running callbacks + // for this ClientInfo can possible exist (block_until_no_pending option + // was used). + delete client_info; + } + + if (server_alive_handle_) { + // Release the mutex before closing the handle so that clients requesting + // dumps wait for a long time for the server to generate a dump. + ReleaseMutex(server_alive_handle_); + CloseHandle(server_alive_handle_); + } + + if (overlapped_.hEvent) { + CloseHandle(overlapped_.hEvent); + } + + DeleteCriticalSection(&sync_); +} + +bool CrashGenerationServer::Start() { + if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) { + return false; + } + + server_state_ = IPC_SERVER_STATE_INITIAL; + + server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); + if (!server_alive_handle_) { + return false; + } + + // Event to signal the client connection and pipe reads and writes. + overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. + TRUE, // Manual reset. + FALSE, // Initially nonsignaled. + NULL); // Name. + if (!overlapped_.hEvent) { + return false; + } + + // Register a callback with the thread pool for the client connection. + if (!RegisterWaitForSingleObject(&pipe_wait_handle_, + overlapped_.hEvent, + OnPipeConnected, + this, + INFINITE, + kPipeIOThreadFlags)) { + return false; + } + + pipe_ = CreateNamedPipe(pipe_name_.c_str(), + kPipeAttr, + kPipeMode, + 1, + kOutBufferSize, + kInBufferSize, + 0, + pipe_sec_attrs_); + if (pipe_ == INVALID_HANDLE_VALUE) { + return false; + } + + // Kick-start the state machine. This will initiate an asynchronous wait + // for client connections. + if (!SetEvent(overlapped_.hEvent)) { + server_state_ = IPC_SERVER_STATE_ERROR; + return false; + } + + // If we are in error state, it's because we failed to start listening. + return true; +} + +// If the server thread serving clients ever gets into the +// ERROR state, reset the event, close the pipe and remain +// in the error state forever. Error state means something +// that we didn't account for has happened, and it's dangerous +// to do anything unknowingly. +void CrashGenerationServer::HandleErrorState() { + assert(server_state_ == IPC_SERVER_STATE_ERROR); + + // If the server is shutting down anyway, don't clean up + // here since shut down process will clean up. + if (shutting_down_) { + return; + } + + if (pipe_wait_handle_) { + UnregisterWait(pipe_wait_handle_); + pipe_wait_handle_ = NULL; + } + + if (pipe_) { + CloseHandle(pipe_); + pipe_ = NULL; + } + + if (overlapped_.hEvent) { + CloseHandle(overlapped_.hEvent); + overlapped_.hEvent = NULL; + } +} + +// When the server thread serving clients is in the INITIAL state, +// try to connect to the pipe asynchronously. If the connection +// finishes synchronously, directly go into the CONNECTED state; +// otherwise go into the CONNECTING state. For any problems, go +// into the ERROR state. +void CrashGenerationServer::HandleInitialState() { + assert(server_state_ == IPC_SERVER_STATE_INITIAL); + + if (!ResetEvent(overlapped_.hEvent)) { + EnterErrorState(); + return; + } + + bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + // From MSDN, it is not clear that when ConnectNamedPipe is used + // in an overlapped mode, will it ever return non-zero value, and + // if so, in what cases. + assert(!success); + + switch (error_code) { + case ERROR_IO_PENDING: + EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING); + break; + + case ERROR_PIPE_CONNECTED: + EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); + break; + + default: + EnterErrorState(); + break; + } +} + +// When the server thread serving the clients is in the CONNECTING state, +// try to get the result of the asynchronous connection request using +// the OVERLAPPED object. If the result indicates the connection is done, +// go into the CONNECTED state. If the result indicates I/O is still +// INCOMPLETE, remain in the CONNECTING state. For any problems, +// go into the DISCONNECTING state. +void CrashGenerationServer::HandleConnectingState() { + assert(server_state_ == IPC_SERVER_STATE_CONNECTING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_CONNECTED); + } else if (error_code != ERROR_IO_INCOMPLETE) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } else { + // remain in CONNECTING state + } +} + +// When the server thread serving the clients is in the CONNECTED state, +// try to issue an asynchronous read from the pipe. If read completes +// synchronously or if I/O is pending then go into the READING state. +// For any problems, go into the DISCONNECTING state. +void CrashGenerationServer::HandleConnectedState() { + assert(server_state_ == IPC_SERVER_STATE_CONNECTED); + + DWORD bytes_count = 0; + memset(&msg_, 0, sizeof(msg_)); + bool success = ReadFile(pipe_, + &msg_, + sizeof(msg_), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + // Note that the asynchronous read issued above can finish before the + // code below executes. But, it is okay to change state after issuing + // the asynchronous read. This is because even if the asynchronous read + // is done, the callback for it would not be executed until the current + // thread finishes its execution. + if (success || error_code == ERROR_IO_PENDING) { + EnterStateWhenSignaled(IPC_SERVER_STATE_READING); + } else { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } +} + +// When the server thread serving the clients is in the READING state, +// try to get the result of the async read. If async read is done, +// go into the READ_DONE state. For any problems, go into the +// DISCONNECTING state. +void CrashGenerationServer::HandleReadingState() { + assert(server_state_ == IPC_SERVER_STATE_READING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + if (success && bytes_count == sizeof(ProtocolMessage)) { + EnterStateImmediately(IPC_SERVER_STATE_READ_DONE); + return; + } + + assert(!CheckForIOIncomplete(success)); + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); +} + +// When the server thread serving the client is in the READ_DONE state, +// validate the client's request message, register the client by +// creating appropriate objects and prepare the response. Then try to +// write the response to the pipe asynchronously. If that succeeds, +// go into the WRITING state. For any problems, go into the DISCONNECTING +// state. +void CrashGenerationServer::HandleReadDoneState() { + assert(server_state_ == IPC_SERVER_STATE_READ_DONE); + + if (!IsClientRequestValid(msg_)) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) { + if (upload_request_callback_) + upload_request_callback_(upload_context_, msg_.id); + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + scoped_ptr client_info( + new ClientInfo(this, + msg_.id, + msg_.dump_type, + msg_.thread_id, + msg_.exception_pointers, + msg_.assert_info, + msg_.custom_client_info)); + + if (!client_info->Initialize()) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + // Issues an asynchronous WriteFile call if successful. + // Iff successful, assigns ownership of the client_info pointer to the server + // instance, in which case we must be sure not to free it in this function. + if (!RespondToClient(client_info.get())) { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + return; + } + + // This is only valid as long as it can be found in the clients_ list + client_info_ = client_info.release(); + + // Note that the asynchronous write issued by RespondToClient function + // can finish before the code below executes. But it is okay to change + // state after issuing the asynchronous write. This is because even if + // the asynchronous write is done, the callback for it would not be + // executed until the current thread finishes its execution. + EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING); +} + +// When the server thread serving the clients is in the WRITING state, +// try to get the result of the async write. If the async write is done, +// go into the WRITE_DONE state. For any problems, go into the +// DISONNECTING state. +void CrashGenerationServer::HandleWritingState() { + assert(server_state_ == IPC_SERVER_STATE_WRITING); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE); + return; + } + + assert(!CheckForIOIncomplete(success)); + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); +} + +// When the server thread serving the clients is in the WRITE_DONE state, +// try to issue an async read on the pipe. If the read completes synchronously +// or if I/O is still pending then go into the READING_ACK state. For any +// issues, go into the DISCONNECTING state. +void CrashGenerationServer::HandleWriteDoneState() { + assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE); + + DWORD bytes_count = 0; + bool success = ReadFile(pipe_, + &msg_, + sizeof(msg_), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (success) { + EnterStateImmediately(IPC_SERVER_STATE_READING_ACK); + } else if (error_code == ERROR_IO_PENDING) { + EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK); + } else { + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); + } +} + +// When the server thread serving the clients is in the READING_ACK state, +// try to get result of async read. Go into the DISCONNECTING state. +void CrashGenerationServer::HandleReadingAckState() { + assert(server_state_ == IPC_SERVER_STATE_READING_ACK); + + DWORD bytes_count = 0; + bool success = GetOverlappedResult(pipe_, + &overlapped_, + &bytes_count, + FALSE) != FALSE; + if (success) { + // The connection handshake with the client is now complete; perform + // the callback. + if (connect_callback_) { + // Note that there is only a single copy of the ClientInfo of the + // currently connected client. However it is being referenced from + // two different places: + // - the client_info_ member + // - the clients_ list + // The lifetime of this ClientInfo depends on the lifetime of the + // client process - basically it can go away at any time. + // However, as long as it is referenced by the clients_ list it + // is guaranteed to be valid. Enter the critical section and check + // to see whether the client_info_ can be found in the list. + // If found, execute the callback and only then leave the critical + // section. + AutoCriticalSection lock(&sync_); + + bool client_is_still_alive = false; + std::list::iterator iter; + for (iter = clients_.begin(); iter != clients_.end(); ++iter) { + if (client_info_ == *iter) { + client_is_still_alive = true; + break; + } + } + + if (client_is_still_alive) { + connect_callback_(connect_context_, client_info_); + } + } + } else { + assert(!CheckForIOIncomplete(success)); + } + + EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING); +} + +// When the server thread serving the client is in the DISCONNECTING state, +// disconnect from the pipe and reset the event. If anything fails, go into +// the ERROR state. If it goes well, go into the INITIAL state and set the +// event to start all over again. +void CrashGenerationServer::HandleDisconnectingState() { + assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); + + // Done serving the client. + client_info_ = NULL; + + overlapped_.Internal = NULL; + overlapped_.InternalHigh = NULL; + overlapped_.Offset = 0; + overlapped_.OffsetHigh = 0; + overlapped_.Pointer = NULL; + + if (!ResetEvent(overlapped_.hEvent)) { + EnterErrorState(); + return; + } + + if (!DisconnectNamedPipe(pipe_)) { + EnterErrorState(); + return; + } + + // If the server is shutting down do not connect to the + // next client. + if (shutting_down_) { + return; + } + + EnterStateImmediately(IPC_SERVER_STATE_INITIAL); +} + +void CrashGenerationServer::EnterErrorState() { + SetEvent(overlapped_.hEvent); + server_state_ = IPC_SERVER_STATE_ERROR; +} + +void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) { + server_state_ = state; +} + +void CrashGenerationServer::EnterStateImmediately(IPCServerState state) { + server_state_ = state; + + if (!SetEvent(overlapped_.hEvent)) { + server_state_ = IPC_SERVER_STATE_ERROR; + } +} + +bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, + ProtocolMessage* reply) const { + reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE; + reply->id = GetCurrentProcessId(); + + if (CreateClientHandles(client_info, reply)) { + return true; + } + + // Closing of remote handles (belonging to a different process) can + // only be done through DuplicateHandle. + if (reply->dump_request_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->dump_request_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->dump_request_handle = NULL; + } + + if (reply->dump_generated_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->dump_generated_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->dump_generated_handle = NULL; + } + + if (reply->server_alive_handle) { + DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle + reply->server_alive_handle, // hSourceHandle + NULL, // hTargetProcessHandle + 0, // lpTargetHandle + 0, // dwDesiredAccess + FALSE, // bInheritHandle + DUPLICATE_CLOSE_SOURCE); // dwOptions + reply->server_alive_handle = NULL; + } + + return false; +} + +bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info, + ProtocolMessage* reply) const { + HANDLE current_process = GetCurrentProcess(); + if (!DuplicateHandle(current_process, + client_info.dump_requested_handle(), + client_info.process_handle(), + &reply->dump_request_handle, + kDumpRequestEventAccess, + FALSE, + 0)) { + return false; + } + + if (!DuplicateHandle(current_process, + client_info.dump_generated_handle(), + client_info.process_handle(), + &reply->dump_generated_handle, + kDumpGeneratedEventAccess, + FALSE, + 0)) { + return false; + } + + if (!DuplicateHandle(current_process, + server_alive_handle_, + client_info.process_handle(), + &reply->server_alive_handle, + kMutexAccess, + FALSE, + 0)) { + return false; + } + + return true; +} + +bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) { + ProtocolMessage reply; + if (!PrepareReply(*client_info, &reply)) { + return false; + } + + DWORD bytes_count = 0; + bool success = WriteFile(pipe_, + &reply, + sizeof(reply), + &bytes_count, + &overlapped_) != FALSE; + DWORD error_code = success ? ERROR_SUCCESS : GetLastError(); + + if (!success && error_code != ERROR_IO_PENDING) { + return false; + } + + // Takes over ownership of client_info. We MUST return true if AddClient + // succeeds. + return AddClient(client_info); +} + +// The server thread servicing the clients runs this method. The method +// implements the state machine described in ReadMe.txt along with the +// helper methods HandleXXXState. +void CrashGenerationServer::HandleConnectionRequest() { + // If the server is shutting down, get into ERROR state, reset the event so + // more workers don't run and return immediately. + if (shutting_down_) { + server_state_ = IPC_SERVER_STATE_ERROR; + ResetEvent(overlapped_.hEvent); + return; + } + + switch (server_state_) { + case IPC_SERVER_STATE_ERROR: + HandleErrorState(); + break; + + case IPC_SERVER_STATE_INITIAL: + HandleInitialState(); + break; + + case IPC_SERVER_STATE_CONNECTING: + HandleConnectingState(); + break; + + case IPC_SERVER_STATE_CONNECTED: + HandleConnectedState(); + break; + + case IPC_SERVER_STATE_READING: + HandleReadingState(); + break; + + case IPC_SERVER_STATE_READ_DONE: + HandleReadDoneState(); + break; + + case IPC_SERVER_STATE_WRITING: + HandleWritingState(); + break; + + case IPC_SERVER_STATE_WRITE_DONE: + HandleWriteDoneState(); + break; + + case IPC_SERVER_STATE_READING_ACK: + HandleReadingAckState(); + break; + + case IPC_SERVER_STATE_DISCONNECTING: + HandleDisconnectingState(); + break; + + default: + assert(false); + // This indicates that we added one more state without + // adding handling code. + server_state_ = IPC_SERVER_STATE_ERROR; + break; + } +} + +bool CrashGenerationServer::AddClient(ClientInfo* client_info) { + HANDLE request_wait_handle = NULL; + if (!RegisterWaitForSingleObject(&request_wait_handle, + client_info->dump_requested_handle(), + OnDumpRequest, + client_info, + INFINITE, + kDumpRequestThreadFlags)) { + return false; + } + + client_info->set_dump_request_wait_handle(request_wait_handle); + + // New scope to hold the lock for the shortest time. + { + AutoCriticalSection lock(&sync_); + + // OnClientEnd will be called when the client process terminates. + HANDLE process_wait_handle = NULL; + if (!RegisterWaitForSingleObject(&process_wait_handle, + client_info->process_handle(), + OnClientEnd, + client_info, + INFINITE, + WT_EXECUTEONLYONCE)) { + return false; + } + + client_info->set_process_exit_wait_handle(process_wait_handle); + + if (shutting_down_) { + // If server is shutting down, don't add new clients + return false; + } + clients_.push_back(client_info); + } + + return true; +} + +// static +void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { + assert(context); + + CrashGenerationServer* obj = + reinterpret_cast(context); + obj->HandleConnectionRequest(); +} + +// static +void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { + assert(context); + ClientInfo* client_info = reinterpret_cast(context); + + CrashGenerationServer* crash_server = client_info->crash_server(); + assert(crash_server); + if (crash_server->pre_fetch_custom_info_) { + client_info->PopulateCustomInfo(); + } + crash_server->HandleDumpRequest(*client_info); + + ResetEvent(client_info->dump_requested_handle()); +} + +// static +void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) { + assert(context); + ClientInfo* client_info = reinterpret_cast(context); + + CrashGenerationServer* crash_server = client_info->crash_server(); + assert(crash_server); + + crash_server->HandleClientProcessExit(client_info); +} + +void CrashGenerationServer::HandleClientProcessExit(ClientInfo* client_info) { + assert(client_info); + + // Must unregister the dump request wait operation and wait for any + // dump requests that might be pending to finish before proceeding + // with the client_info cleanup. + client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending(); + + if (exit_callback_) { + exit_callback_(exit_context_, *client_info); + } + + // Start a new scope to release lock automatically. + { + AutoCriticalSection lock(&sync_); + if (shutting_down_) { + // The crash generation server is shutting down and as part of the + // shutdown process it will delete all clients from the clients_ list. + return; + } + clients_.remove(client_info); + } + + AutoCriticalSection lock(&sync_); + + // Explicitly unregister the process exit wait using the non-blocking method. + // Otherwise, the destructor will attempt to unregister it using the blocking + // method which will lead to a deadlock because it is being called from the + // callback of the same wait operation + client_info->UnregisterProcessExitWait(false); + + delete client_info; +} + +void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) { + bool execute_callback = true; + // Generate the dump only if it's explicitly requested by the + // server application; otherwise the server might want to generate + // dump in the callback. + std::wstring dump_path; + if (generate_dumps_) { + if (!GenerateDump(client_info, &dump_path)) { + // client proccess terminated or some other error + execute_callback = false; + } + } + + if (dump_callback_ && execute_callback) { + dump_callback_(dump_context_, client_info, dump_path); + } + + SetEvent(client_info.dump_generated_handle()); + + if (written_callback_ && execute_callback) { + written_callback_(dump_context_, client_info); + } +} + +void CrashGenerationServer::set_include_context_heap(bool enabled) { + include_context_heap_ = enabled; +} + +bool CrashGenerationServer::GenerateDump(const ClientInfo& client, + std::wstring* dump_path) { + assert(client.pid() != 0); + assert(client.process_handle()); + + DWORD client_thread_id = 0; + if (!client.GetClientThreadId(&client_thread_id)) { + return false; + } + + // We have to get the address of EXCEPTION_INFORMATION from + // the client process address space. + EXCEPTION_POINTERS* client_ex_info = NULL; + + // Only needs to read the value of a remote pointer in client_ex_info. + if (!client.GetClientExceptionInfo(&client_ex_info)) { + return false; + } + + if (include_context_heap_) { + CONTEXT context_content; + + // Needs to read the content of CONTEXT from the client. + if (!client.PopulateClientExceptionContext(client_ex_info, + &context_content)) { + include_context_heap_ = false; + } + + // Allocate AppMemory instances for exception context. + for (size_t i = 0; i < kExceptionAppMemoryRegions; i++) { + AppMemory app_memory; + app_memory.ptr = reinterpret_cast(nullptr); + app_memory.length = 0; + app_memory.preallocated = true; + app_memory_info_.push_back(app_memory); + } + + IncludeAppMemoryFromExceptionContext(client.process_handle(), + client_thread_id, + app_memory_info_, + &context_content, + !include_context_heap_); + } + + MinidumpGenerator dump_generator(dump_path_, + client.process_handle(), + client.pid(), + client_thread_id, + GetCurrentThreadId(), + client_ex_info, + client.assert_info(), + client.dump_type(), + true); + + MinidumpCallbackContext callback_context; + MINIDUMP_CALLBACK_INFORMATION callback; + if (include_context_heap_) { + // Set memory callback to include heap regions. + callback_context.iter = app_memory_info_.cbegin(); + callback_context.end = app_memory_info_.cend(); + + callback.CallbackRoutine = MinidumpWriteDumpCallback; + callback.CallbackParam = &callback_context; + + dump_generator.SetCallback(&callback); + } + + if (!dump_generator.GenerateDumpFile(dump_path)) { + return false; + } + + // If the client requests a full memory dump, we will write a normal mini + // dump and a full memory dump. Both dump files use the same uuid as file + // name prefix. + if (client.dump_type() & MiniDumpWithFullMemory) { + std::wstring full_dump_path; + if (!dump_generator.GenerateFullDumpFile(&full_dump_path)) { + return false; + } + } + + return dump_generator.WriteMinidump(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h new file mode 100644 index 0000000000..cc1912cf3c --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h @@ -0,0 +1,318 @@ +// 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 +#include +#include "windows/common/minidump_callback.h" +#include "windows/common/ipc_protocol.h" +#include "windows/crash_generation/minidump_generator.h" +#include "common/scoped_ptr.h" + +namespace google_breakpad { +class ClientInfo; + +// 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 (*OnClientDumpWrittenCallback)(void* context, + const ClientInfo& client_info); + + typedef void (*OnClientExitedCallback)(void* context, + const ClientInfo& client_info); + + typedef void (*OnClientUploadRequestCallback)(void* context, + const DWORD crash_id); + + // 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 dump_callback: Callback for a client crash dump request. + // Parameter dump_context: Context for client crash dump request callback. + // Parameter written_callback: Callback called after a crash dump was written. + // 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, + OnClientDumpWrittenCallback written_callback, + OnClientExitedCallback exit_callback, + void* exit_context, + OnClientUploadRequestCallback upload_request_callback, + void* upload_context, + bool generate_dumps, + const std::wstring* dump_path); + + ~CrashGenerationServer(); + + // Performs initialization steps needed to start listening to clients. Upon + // successful return clients may connect to this server's pipe. + // + // Returns true if initialization is successful; false otherwise. + bool Start(); + + void pre_fetch_custom_info(bool do_pre_fetch) { + pre_fetch_custom_info_ = do_pre_fetch; + } + + // Calling set_include_context_heap(true) causes heap regions to be included + // in the minidump when a crash happens. The heap regions are from the + // register values of the client crashing context. + void set_include_context_heap(bool enabled); + + private: + // Various states the client can be in during the handshake with + // the server. + enum IPCServerState { + // Server starts in this state. + IPC_SERVER_STATE_UNINITIALIZED, + + // 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); + + // Handles client process exit. + void HandleClientProcessExit(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); + + // Puts the server in a permanent error state and sets a signal such that + // the state will be immediately entered after the current state transition + // is complete. + void EnterErrorState(); + + // Puts the server in the specified state and sets a signal such that the + // state is immediately entered after the current state transition is + // complete. + void EnterStateImmediately(IPCServerState state); + + // Puts the server in the specified state. No signal will be set, so the state + // transition will only occur when signaled manually or by completion of an + // asynchronous IO operation. + void EnterStateWhenSignaled(IPCServerState state); + + // Sync object for thread-safe access to the shared list of clients. + CRITICAL_SECTION sync_; + + // List of clients. + std::list 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 a client dump written. + OnClientDumpWrittenCallback written_callback_; + + // Callback for client process exit. + OnClientExitedCallback exit_callback_; + + // Context for client process exit callback. + void* exit_context_; + + // Callback for upload request. + OnClientUploadRequestCallback upload_request_callback_; + + // Context for upload request callback. + void* upload_context_; + + // Whether to generate dumps. + bool generate_dumps_; + + // Wether to populate custom information up-front. + bool pre_fetch_custom_info_; + + // The dump path for the server. + const std::wstring dump_path_; + + // 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. + IPCServerState server_state_; + + // Whether the server is shutting down. + 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_; + + // Whether to include heap regions of the crashing context. + bool include_context_heap_; + + AppMemoryList app_memory_info_; + + // 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__ diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.cc b/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.cc new file mode 100644 index 0000000000..0e0643c5a1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.cc @@ -0,0 +1,581 @@ +// 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. + +#include "windows/crash_generation/minidump_generator.h" + +#include +#include + +#include +#include +#include +#include + +#include "windows/common/auto_critical_section.h" +#include "common/scoped_ptr.h" +#include "common/windows/guid_string.h" + +using std::wstring; + +namespace { + +// A helper class used to collect handle operations data. Unlike +// |MiniDumpWithHandleData| it records the operations for a single handle value +// only, making it possible to include this information to a minidump. +class HandleTraceData { + public: + HandleTraceData(); + ~HandleTraceData(); + + // Collects the handle operations data and formats a user stream to be added + // to the minidump. + bool CollectHandleData(HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers); + + // Fills the user dump entry with a pointer to the collected handle operations + // data. Returns |true| if the entry was initialized successfully, or |false| + // if no trace data is available. + bool GetUserStream(MINIDUMP_USER_STREAM* user_stream); + + private: + // Reads the exception code from the client process's address space. + // This routine assumes that the client process's pointer width matches ours. + static bool ReadExceptionCode(HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers, + DWORD* exception_code); + + // Stores handle operations retrieved by VerifierEnumerateResource(). + static ULONG CALLBACK RecordHandleOperations(void* resource_description, + void* enumeration_context, + ULONG* enumeration_level); + + // Function pointer type for VerifierEnumerateResource, which is looked up + // dynamically. + typedef BOOL (WINAPI* VerifierEnumerateResourceType)( + HANDLE Process, + ULONG Flags, + ULONG ResourceType, + AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback, + PVOID EnumerationContext); + + // Handle to dynamically loaded verifier.dll. + HMODULE verifier_module_; + + // Pointer to the VerifierEnumerateResource function. + VerifierEnumerateResourceType enumerate_resource_; + + // Handle value to look for. + ULONG64 handle_; + + // List of handle operations for |handle_|. + std::list operations_; + + // Minidump stream data. + std::vector stream_; +}; + +HandleTraceData::HandleTraceData() + : verifier_module_(NULL), + enumerate_resource_(NULL), + handle_(NULL) { +} + +HandleTraceData::~HandleTraceData() { + if (verifier_module_) { + FreeLibrary(verifier_module_); + } +} + +bool HandleTraceData::CollectHandleData( + HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers) { + DWORD exception_code; + if (!ReadExceptionCode(process_handle, exception_pointers, &exception_code)) { + return false; + } + + // Verify whether the execption is STATUS_INVALID_HANDLE. Do not record any + // handle information if it is a different exception to keep the minidump + // small. + if (exception_code != STATUS_INVALID_HANDLE) { + return true; + } + + // Load verifier!VerifierEnumerateResource() dynamically. + verifier_module_ = LoadLibrary(TEXT("verifier.dll")); + if (!verifier_module_) { + return false; + } + + enumerate_resource_ = reinterpret_cast( + GetProcAddress(verifier_module_, "VerifierEnumerateResource")); + if (!enumerate_resource_) { + return false; + } + + // STATUS_INVALID_HANDLE does not provide the offending handle value in + // the exception parameters so we have to guess. At the moment we scan + // the handle operations trace looking for the last invalid handle operation + // and record only the operations for that handle value. + if (enumerate_resource_(process_handle, + 0, + AvrfResourceHandleTrace, + &RecordHandleOperations, + this) != ERROR_SUCCESS) { + // The handle tracing must have not been enabled. + return true; + } + + // Now that |handle_| is initialized, purge all irrelevant operations. + std::list::iterator i = operations_.begin(); + std::list::iterator i_end = operations_.end(); + while (i != i_end) { + if (i->Handle == handle_) { + ++i; + } else { + i = operations_.erase(i); + } + } + + // Convert the list of recorded operations to a minidump stream. + stream_.resize(sizeof(MINIDUMP_HANDLE_OPERATION_LIST) + + sizeof(AVRF_HANDLE_OPERATION) * operations_.size()); + + MINIDUMP_HANDLE_OPERATION_LIST* stream_data = + reinterpret_cast( + &stream_.front()); + stream_data->SizeOfHeader = sizeof(MINIDUMP_HANDLE_OPERATION_LIST); + stream_data->SizeOfEntry = sizeof(AVRF_HANDLE_OPERATION); + stream_data->NumberOfEntries = static_cast(operations_.size()); + stream_data->Reserved = 0; + std::copy(operations_.begin(), + operations_.end(), +#if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) + stdext::checked_array_iterator( + reinterpret_cast(stream_data + 1), + operations_.size()) +#else + reinterpret_cast(stream_data + 1) +#endif + ); + + return true; +} + +bool HandleTraceData::GetUserStream(MINIDUMP_USER_STREAM* user_stream) { + if (stream_.empty()) { + return false; + } else { + user_stream->Type = HandleOperationListStream; + user_stream->BufferSize = static_cast(stream_.size()); + user_stream->Buffer = &stream_.front(); + return true; + } +} + +bool HandleTraceData::ReadExceptionCode( + HANDLE process_handle, + EXCEPTION_POINTERS* exception_pointers, + DWORD* exception_code) { + EXCEPTION_POINTERS pointers; + if (!ReadProcessMemory(process_handle, + exception_pointers, + &pointers, + sizeof(pointers), + NULL)) { + return false; + } + + if (!ReadProcessMemory(process_handle, + pointers.ExceptionRecord, + exception_code, + sizeof(*exception_code), + NULL)) { + return false; + } + + return true; +} + +ULONG CALLBACK HandleTraceData::RecordHandleOperations( + void* resource_description, + void* enumeration_context, + ULONG* enumeration_level) { + AVRF_HANDLE_OPERATION* description = + reinterpret_cast(resource_description); + HandleTraceData* self = + reinterpret_cast(enumeration_context); + + // Remember the last invalid handle operation. + if (description->OperationType == OperationDbBADREF) { + self->handle_ = description->Handle; + } + + // Record all handle operations. + self->operations_.push_back(*description); + + *enumeration_level = HeapEnumerationEverything; + return ERROR_SUCCESS; +} + +} // namespace + +namespace google_breakpad { + +MinidumpGenerator::MinidumpGenerator( + const std::wstring& dump_path, + const HANDLE process_handle, + const DWORD process_id, + const DWORD thread_id, + const DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + const MINIDUMP_TYPE dump_type, + const bool is_client_pointers) + : dbghelp_module_(NULL), + write_dump_(NULL), + rpcrt4_module_(NULL), + create_uuid_(NULL), + process_handle_(process_handle), + process_id_(process_id), + thread_id_(thread_id), + requesting_thread_id_(requesting_thread_id), + exception_pointers_(exception_pointers), + assert_info_(assert_info), + dump_type_(dump_type), + is_client_pointers_(is_client_pointers), + dump_path_(dump_path), + uuid_generated_(false), + dump_file_(INVALID_HANDLE_VALUE), + full_dump_file_(INVALID_HANDLE_VALUE), + dump_file_is_internal_(false), + full_dump_file_is_internal_(false), + additional_streams_(NULL), + callback_info_(NULL) { + uuid_ = {0}; + InitializeCriticalSection(&module_load_sync_); + InitializeCriticalSection(&get_proc_address_sync_); +} + +MinidumpGenerator::~MinidumpGenerator() { + if (dump_file_is_internal_ && dump_file_ != INVALID_HANDLE_VALUE) { + CloseHandle(dump_file_); + } + + if (full_dump_file_is_internal_ && full_dump_file_ != INVALID_HANDLE_VALUE) { + CloseHandle(full_dump_file_); + } + + if (dbghelp_module_) { + FreeLibrary(dbghelp_module_); + } + + if (rpcrt4_module_) { + FreeLibrary(rpcrt4_module_); + } + + DeleteCriticalSection(&get_proc_address_sync_); + DeleteCriticalSection(&module_load_sync_); +} + +bool MinidumpGenerator::WriteMinidump() { + bool full_memory_dump = (dump_type_ & MiniDumpWithFullMemory) != 0; + if (dump_file_ == INVALID_HANDLE_VALUE || + (full_memory_dump && full_dump_file_ == INVALID_HANDLE_VALUE)) { + return false; + } + + MiniDumpWriteDumpType write_dump = GetWriteDump(); + if (!write_dump) { + return false; + } + + MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; + + // Setup the exception information object only if it's a dump + // due to an exception. + if (exception_pointers_) { + dump_exception_info.ThreadId = thread_id_; + dump_exception_info.ExceptionPointers = exception_pointers_; + dump_exception_info.ClientPointers = is_client_pointers_; + } + + // Add an MDRawBreakpadInfo stream to the minidump, to provide additional + // information about the exception handler to the Breakpad processor. + // The information will help the processor determine which threads are + // relevant. The Breakpad processor does not require this information but + // can function better with Breakpad-generated dumps when it is present. + // The native debugger is not harmed by the presence of this information. + MDRawBreakpadInfo breakpad_info = {0}; + if (!is_client_pointers_) { + // Set the dump thread id and requesting thread id only in case of + // in-process dump generation. + breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + breakpad_info.dump_thread_id = thread_id_; + breakpad_info.requesting_thread_id = requesting_thread_id_; + } + + int additional_streams_count = additional_streams_ ? + additional_streams_->UserStreamCount : 0; + scoped_array user_stream_array( + new MINIDUMP_USER_STREAM[3 + additional_streams_count]); + user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; + user_stream_array[0].BufferSize = sizeof(breakpad_info); + user_stream_array[0].Buffer = &breakpad_info; + + MINIDUMP_USER_STREAM_INFORMATION user_streams; + user_streams.UserStreamCount = 1; + user_streams.UserStreamArray = user_stream_array.get(); + + MDRawAssertionInfo* actual_assert_info = assert_info_; + MDRawAssertionInfo client_assert_info = {{0}}; + + if (assert_info_) { + // If the assertion info object lives in the client process, + // read the memory of the client process. + if (is_client_pointers_) { + SIZE_T bytes_read = 0; + if (!ReadProcessMemory(process_handle_, + assert_info_, + &client_assert_info, + sizeof(client_assert_info), + &bytes_read)) { + if (dump_file_is_internal_) + CloseHandle(dump_file_); + if (full_dump_file_is_internal_ && + full_dump_file_ != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file_); + return false; + } + + if (bytes_read != sizeof(client_assert_info)) { + if (dump_file_is_internal_) + CloseHandle(dump_file_); + if (full_dump_file_is_internal_ && + full_dump_file_ != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file_); + return false; + } + + actual_assert_info = &client_assert_info; + } + + user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; + user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); + user_stream_array[1].Buffer = actual_assert_info; + ++user_streams.UserStreamCount; + } + + if (additional_streams_) { + for (size_t i = 0; + i < additional_streams_->UserStreamCount; + i++, user_streams.UserStreamCount++) { + user_stream_array[user_streams.UserStreamCount].Type = + additional_streams_->UserStreamArray[i].Type; + user_stream_array[user_streams.UserStreamCount].BufferSize = + additional_streams_->UserStreamArray[i].BufferSize; + user_stream_array[user_streams.UserStreamCount].Buffer = + additional_streams_->UserStreamArray[i].Buffer; + } + } + + // If the process is terminated by STATUS_INVALID_HANDLE exception store + // the trace of operations for the offending handle value. Do nothing special + // if the client already requested the handle trace to be stored in the dump. + HandleTraceData handle_trace_data; + if (exception_pointers_ && (dump_type_ & MiniDumpWithHandleData) == 0) { + if (!handle_trace_data.CollectHandleData(process_handle_, + exception_pointers_)) { + if (dump_file_is_internal_) + CloseHandle(dump_file_); + if (full_dump_file_is_internal_ && + full_dump_file_ != INVALID_HANDLE_VALUE) + CloseHandle(full_dump_file_); + return false; + } + } + + bool result_full_memory = true; + if (full_memory_dump) { + result_full_memory = write_dump( + process_handle_, + process_id_, + full_dump_file_, + static_cast((dump_type_ & (~MiniDumpNormal)) + | MiniDumpWithHandleData), + exception_pointers_ ? &dump_exception_info : NULL, + &user_streams, + NULL) != FALSE; + } + + // Add handle operations trace stream to the minidump if it was collected. + if (handle_trace_data.GetUserStream( + &user_stream_array[user_streams.UserStreamCount])) { + ++user_streams.UserStreamCount; + } + + bool result_minidump = write_dump( + process_handle_, + process_id_, + dump_file_, + static_cast((dump_type_ & (~MiniDumpWithFullMemory)) + | MiniDumpNormal), + exception_pointers_ ? &dump_exception_info : NULL, + &user_streams, + callback_info_) != FALSE; + + return result_minidump && result_full_memory; +} + +bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) { + // The dump file was already set by handle or this function was previously + // called. + if (dump_file_ != INVALID_HANDLE_VALUE) { + return false; + } + + wstring dump_file_path; + if (!GenerateDumpFilePath(&dump_file_path)) { + return false; + } + + dump_file_ = CreateFile(dump_file_path.c_str(), + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (dump_file_ == INVALID_HANDLE_VALUE) { + return false; + } + + dump_file_is_internal_ = true; + *dump_path = dump_file_path; + return true; +} + +bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) { + // A full minidump was not requested. + if ((dump_type_ & MiniDumpWithFullMemory) == 0) { + return false; + } + + // The dump file was already set by handle or this function was previously + // called. + if (full_dump_file_ != INVALID_HANDLE_VALUE) { + return false; + } + + wstring full_dump_file_path; + if (!GenerateDumpFilePath(&full_dump_file_path)) { + return false; + } + full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp + full_dump_file_path.append(TEXT("-full.dmp")); + + full_dump_file_ = CreateFile(full_dump_file_path.c_str(), + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (full_dump_file_ == INVALID_HANDLE_VALUE) { + return false; + } + + full_dump_file_is_internal_ = true; + *full_dump_path = full_dump_file_path; + return true; +} + +HMODULE MinidumpGenerator::GetDbghelpModule() { + AutoCriticalSection lock(&module_load_sync_); + if (!dbghelp_module_) { + dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll")); + } + + return dbghelp_module_; +} + +MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() { + AutoCriticalSection lock(&get_proc_address_sync_); + if (!write_dump_) { + HMODULE module = GetDbghelpModule(); + if (module) { + FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump"); + write_dump_ = reinterpret_cast(proc); + } + } + + return write_dump_; +} + +HMODULE MinidumpGenerator::GetRpcrt4Module() { + AutoCriticalSection lock(&module_load_sync_); + if (!rpcrt4_module_) { + rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll")); + } + + return rpcrt4_module_; +} + +MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() { + AutoCriticalSection lock(&module_load_sync_); + if (!create_uuid_) { + HMODULE module = GetRpcrt4Module(); + if (module) { + FARPROC proc = GetProcAddress(module, "UuidCreate"); + create_uuid_ = reinterpret_cast(proc); + } + } + + return create_uuid_; +} + +bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) { + if (!uuid_generated_) { + UuidCreateType create_uuid = GetCreateUuid(); + if (!create_uuid) { + return false; + } + + create_uuid(&uuid_); + uuid_generated_ = true; + } + + wstring id_str = GUIDString::GUIDToWString(&uuid_); + + *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp"); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.h b/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.h new file mode 100644 index 0000000000..a707c0bb1d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/minidump_generator.h @@ -0,0 +1,203 @@ +// 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_GENERATOR_H_ +#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_ + +#include +#include +#include +#include +#include +#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 parameters. + // is_client_pointers specifies whether the exception_pointers and + // assert_info point into the process that is being dumped. + // Before calling WriteMinidump on the returned instance a dump file muct be + // specified by a call to either SetDumpFile() or GenerateDumpFile(). + // If a full dump file will be requested via a subsequent call to either + // SetFullDumpFile or GenerateFullDumpFile() dump_type must include + // MiniDumpWithFullMemory. + MinidumpGenerator(const std::wstring& dump_path, + const HANDLE process_handle, + const DWORD process_id, + const DWORD thread_id, + const DWORD requesting_thread_id, + EXCEPTION_POINTERS* exception_pointers, + MDRawAssertionInfo* assert_info, + const MINIDUMP_TYPE dump_type, + const bool is_client_pointers); + + ~MinidumpGenerator(); + + void SetDumpFile(const HANDLE dump_file) { dump_file_ = dump_file; } + void SetFullDumpFile(const HANDLE full_dump_file) { + full_dump_file_ = full_dump_file; + } + + // Generate the name for the dump file that will be written to once + // WriteMinidump() is called. Can only be called once and cannot be called + // if the dump file is set via SetDumpFile(). + bool GenerateDumpFile(std::wstring* dump_path); + + // Generate the name for the full dump file that will be written to once + // WriteMinidump() is called. Cannot be called unless the minidump type + // includes MiniDumpWithFullMemory. Can only be called once and cannot be + // called if the dump file is set via SetFullDumpFile(). + bool GenerateFullDumpFile(std::wstring* full_dump_path); + + void SetAdditionalStreams( + MINIDUMP_USER_STREAM_INFORMATION* additional_streams) { + additional_streams_ = additional_streams; + } + + void SetCallback(MINIDUMP_CALLBACK_INFORMATION* callback_info) { + callback_info_ = callback_info; + } + + // Writes the minidump with the given parameters. Stores the + // dump file path in the dump_path parameter if dump generation + // succeeds. + bool WriteMinidump(); + + 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_; + + // Handle for the process to dump. + HANDLE process_handle_; + + // Process ID for the process to dump. + DWORD process_id_; + + // The crashing thread ID. + DWORD thread_id_; + + // The thread ID which is requesting the dump. + DWORD requesting_thread_id_; + + // Pointer to the exception information for the crash. This may point to an + // address in the crashing process so it should not be dereferenced. + EXCEPTION_POINTERS* exception_pointers_; + + // Assertion info for the report. + MDRawAssertionInfo* assert_info_; + + // Type of minidump to generate. + MINIDUMP_TYPE dump_type_; + + // Specifies whether the exception_pointers_ reference memory in the crashing + // process. + bool is_client_pointers_; + + // Folder path to store dump files. + std::wstring dump_path_; + + // UUID used to make dump file names. + UUID uuid_; + bool uuid_generated_; + + // The file where the dump will be written. + HANDLE dump_file_; + + // The file where the full dump will be written. + HANDLE full_dump_file_; + + // Tracks whether the dump file handle is managed externally. + bool dump_file_is_internal_; + + // Tracks whether the full dump file handle is managed externally. + bool full_dump_file_is_internal_; + + // Additional streams to be written to the dump. + MINIDUMP_USER_STREAM_INFORMATION* additional_streams_; + + // The user defined callback for the various stages of the dump process. + MINIDUMP_CALLBACK_INFORMATION* callback_info_; + + // 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_GENERATOR_H_ diff --git a/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild b/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild new file mode 100644 index 0000000000..c964936f1d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +lobjs_crash_generation = [ + 'client_info.cc', + 'crash_generation_client.cc', + 'crash_generation_server.cc', + 'minidump_generator.cc', +] + +subdir = 'toolkit/crashreporter/breakpad-client/windows/crash_generation' +objs_crash_generation = [ + '/%s/%s' % (subdir, s) for s in lobjs_crash_generation +] diff --git a/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.cc b/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.cc new file mode 100644 index 0000000000..f87adba34b --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.cc @@ -0,0 +1,1121 @@ +// 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 + +#include +#include +#include + +#include "common/windows/string_utils-inl.h" + +#include "windows/common/ipc_protocol.h" +#include "windows/handler/exception_handler.h" +#include "common/windows/guid_string.h" + +#ifdef MOZ_PHC +#include "PHC.h" +#endif + +namespace google_breakpad { + +// This define is new to Windows 10. +#ifndef DBG_PRINTEXCEPTION_WIDE_C +#define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A) +#endif + +vector* ExceptionHandler::handler_stack_ = NULL; +LONG ExceptionHandler::handler_stack_index_ = 0; +CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; +volatile LONG ExceptionHandler::instance_count_ = 0; + +ExceptionHandler::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) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + dump_type, + pipe_name, + NULL, // pipe_handle + NULL, // crash_generation_client + custom_info); +} + +ExceptionHandler::ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + HANDLE pipe_handle, + const CustomClientInfo* custom_info) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + dump_type, + NULL, // pipe_name + pipe_handle, + NULL, // crash_generation_client + custom_info); +} + +ExceptionHandler::ExceptionHandler( + const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + CrashGenerationClient* crash_generation_client) { + // The dump_type, pipe_name and custom_info that are passed in to Initialize() + // are not used. The ones set in crash_generation_client are used instead. + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + MiniDumpNormal, // dump_type - not used + NULL, // pipe_name - not used + NULL, // pipe_handle + crash_generation_client, + NULL); // custom_info - not used +} + +ExceptionHandler::ExceptionHandler(const wstring &dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + MiniDumpNormal, + NULL, // pipe_name + NULL, // pipe_handle + NULL, // crash_generation_client + NULL); // custom_info +} + +void ExceptionHandler::Initialize( + const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + HANDLE pipe_handle, + CrashGenerationClient* crash_generation_client, + const CustomClientInfo* custom_info) { + LONG instance_count = InterlockedIncrement(&instance_count_); + filter_ = filter; + callback_ = callback; + callback_context_ = callback_context; + dump_path_c_ = NULL; + next_minidump_id_c_ = NULL; + next_minidump_path_c_ = NULL; + dbghelp_module_ = NULL; + minidump_write_dump_ = NULL; + dump_type_ = dump_type; + rpcrt4_module_ = NULL; + uuid_create_ = NULL; + handler_types_ = handler_types; + previous_filter_ = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + previous_iph_ = NULL; +#endif // _MSC_VER >= 1400 + previous_pch_ = NULL; + heap_corruption_veh_ = NULL; + handler_thread_ = NULL; + is_shutdown_ = false; + handler_start_semaphore_ = NULL; + handler_finish_semaphore_ = NULL; + requesting_thread_id_ = 0; + exception_info_ = NULL; + assertion_ = NULL; + handler_return_value_ = MinidumpResult::Failure; + handle_debug_exceptions_ = false; + consume_invalid_handle_exceptions_ = false; + + // Attempt to use out-of-process if user has specified a pipe or a + // crash generation client. + scoped_ptr client; + if (crash_generation_client) { + client.reset(crash_generation_client); + } else if (pipe_name) { + client.reset( + new CrashGenerationClient(pipe_name, dump_type_, custom_info)); + } else if (pipe_handle) { + client.reset( + new CrashGenerationClient(pipe_handle, dump_type_, custom_info)); + } + + if (client.get() != NULL) { + // If successful in registering with the monitoring process, + // there is no need to setup in-process crash generation. + if (client->Register()) { + crash_generation_client_.reset(client.release()); + } + } + + if (!IsOutOfProcess()) { + // Either client did not ask for out-of-process crash generation + // or registration with the server process failed. In either case, + // setup to do in-process crash generation. + + // Set synchronization primitives and the handler thread. Each + // ExceptionHandler object gets its own handler thread because that's the + // only way to reliably guarantee sufficient stack space in an exception, + // and it allows an easy way to get a snapshot of the requesting thread's + // context outside of an exception. + InitializeCriticalSection(&handler_critical_section_); + handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_start_semaphore_ != NULL); + + handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + assert(handler_finish_semaphore_ != NULL); + + // Don't attempt to create the thread if we could not create the semaphores. + if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { + DWORD thread_id; + const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; + handler_thread_ = CreateThread(NULL, // lpThreadAttributes + kExceptionHandlerThreadInitialStackSize, + ExceptionHandlerThreadMain, + this, // lpParameter + 0, // dwCreationFlags + &thread_id); + assert(handler_thread_ != NULL); + } + + dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); + if (dbghelp_module_) { + minidump_write_dump_ = reinterpret_cast( + GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); + } + + // Load this library dynamically to not affect existing projects. Most + // projects don't link against this directly, it's usually dynamically + // loaded by dependent code. + rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll"); + if (rpcrt4_module_) { + uuid_create_ = reinterpret_cast( + GetProcAddress(rpcrt4_module_, "UuidCreate")); + } + + // set_dump_path calls UpdateNextID. This sets up all of the path and id + // strings, and their equivalent c_str pointers. + set_dump_path(dump_path); + } + + // Reserve one element for the instruction memory + AppMemory instruction_memory; + instruction_memory.ptr = NULL; + instruction_memory.length = 0; + instruction_memory.preallocated = true; + app_memory_info_.push_back(instruction_memory); + + // There is a race condition here. If the first instance has not yet + // initialized the critical section, the second (and later) instances may + // try to use uninitialized critical section object. The feature of multiple + // instances in one module is not used much, so leave it as is for now. + // One way to solve this in the current design (that is, keeping the static + // handler stack) is to use spin locks with volatile bools to synchronize + // the handler stack. This works only if the compiler guarantees to generate + // cache coherent code for volatile. + // TODO(munjal): Fix this in a better way by changing the design if possible. + + // Lazy initialization of the handler_stack_critical_section_ + if (instance_count == 1) { + InitializeCriticalSection(&handler_stack_critical_section_); + } + + if (handler_types != HANDLER_NONE) { + EnterCriticalSection(&handler_stack_critical_section_); + + // The first time an ExceptionHandler that installs a handler is + // created, set up the handler stack. + if (!handler_stack_) { + handler_stack_ = new vector(); + } + handler_stack_->push_back(this); + + if (handler_types & HANDLER_EXCEPTION) + previous_filter_ = SetUnhandledExceptionFilter(HandleException); + +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (handler_types & HANDLER_INVALID_PARAMETER) + previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter); +#endif // _MSC_VER >= 1400 + + if (handler_types & HANDLER_PURECALL) + previous_pch_ = _set_purecall_handler(HandlePureVirtualCall); + + if (handler_types & HANDLER_HEAP_CORRUPTION) { + // Under ASan we need to let the ASan runtime's ShadowExceptionHandler stay + // in the first handler position. +#ifdef MOZ_ASAN + const bool first = false; +#else + const bool first = true; +#endif // MOZ_ASAN + heap_corruption_veh_ = + AddVectoredExceptionHandler(first, HandleHeapCorruption); + } + + LeaveCriticalSection(&handler_stack_critical_section_); + } + + include_context_heap_ = false; +} + +ExceptionHandler::~ExceptionHandler() { + if (handler_types_ != HANDLER_NONE) { + EnterCriticalSection(&handler_stack_critical_section_); + + if (handler_types_ & HANDLER_EXCEPTION) + SetUnhandledExceptionFilter(previous_filter_); + +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (handler_types_ & HANDLER_INVALID_PARAMETER) + _set_invalid_parameter_handler(previous_iph_); +#endif // _MSC_VER >= 1400 + + if (handler_types_ & HANDLER_PURECALL) + _set_purecall_handler(previous_pch_); + + if (handler_types_ & HANDLER_HEAP_CORRUPTION) + RemoveVectoredExceptionHandler(heap_corruption_veh_); + + if (handler_stack_->back() == this) { + handler_stack_->pop_back(); + } else { + // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the + // system's application event log. + fprintf(stderr, "warning: removing Breakpad handler out of order\n"); + vector::iterator iterator = handler_stack_->begin(); + while (iterator != handler_stack_->end()) { + if (*iterator == this) { + iterator = handler_stack_->erase(iterator); + } else { + ++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; + } + + LeaveCriticalSection(&handler_stack_critical_section_); + } + + // Some of the objects were only initialized if out of process + // registration was not done. + if (!IsOutOfProcess()) { +#ifdef BREAKPAD_NO_TERMINATE_THREAD + // Clean up the handler thread and synchronization primitives. The handler + // thread is either waiting on the semaphore to handle a crash or it is + // handling a crash. Coming out of the wait is fast but wait more in the + // eventuality a crash is handled. This compilation option results in a + // deadlock if the exception handler is destroyed while executing code + // inside DllMain. + is_shutdown_ = true; + ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + const int kWaitForHandlerThreadMs = 60000; + WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs); +#else + TerminateThread(handler_thread_, 1); +#endif // BREAKPAD_NO_TERMINATE_THREAD + + CloseHandle(handler_thread_); + handler_thread_ = NULL; + DeleteCriticalSection(&handler_critical_section_); + CloseHandle(handler_start_semaphore_); + CloseHandle(handler_finish_semaphore_); + } + + // There is a race condition in the code below: if this instance is + // deleting the static critical section and a new instance of the class + // is created, then there is a possibility that the critical section be + // initialized while the same critical section is being deleted. Given the + // usage pattern for the code, this race condition is unlikely to hit, but it + // is a race condition nonetheless. + if (InterlockedDecrement(&instance_count_) == 0) { + DeleteCriticalSection(&handler_stack_critical_section_); + } + + // The exception handler is not set anymore and the handler thread which + // could call MiniDumpWriteDump() has been shut down; it is now safe to + // unload these modules. + if (dbghelp_module_) { + FreeLibrary(dbghelp_module_); + } + + if (rpcrt4_module_) { + FreeLibrary(rpcrt4_module_); + } +} + +bool ExceptionHandler::RequestUpload(DWORD crash_id) { + return crash_generation_client_->RequestUpload(crash_id); +} + +// The SetThreadDescription API was brought in version 1607 of Windows 10. +typedef HRESULT(WINAPI* SetThreadDescriptionPtr)(HANDLE hThread, + PCWSTR lpThreadDescription); + +// static +DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { + HMODULE handle = ::GetModuleHandle(L"Kernel32.dll"); + if (handle) { + if (FARPROC address = ::GetProcAddress(handle, "SetThreadDescription")) { + auto SetThreadDescriptionFunc = + reinterpret_cast(address); + SetThreadDescriptionFunc(::GetCurrentThread(), + L"Breakpad ExceptionHandler"); + } + } + + ExceptionHandler* self = reinterpret_cast(lpParameter); + assert(self); + assert(self->handler_start_semaphore_ != NULL); + assert(self->handler_finish_semaphore_ != NULL); + + for (;;) { + if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == + WAIT_OBJECT_0) { + // Perform the requested action. + if (self->is_shutdown_) { + // The instance of the exception handler is being destroyed. + break; + } else { + self->handler_return_value_ = + self->WriteMinidumpWithException(self->requesting_thread_id_, + self->exception_info_, + self->assertion_); + } + + // Allow the requesting thread to proceed. + ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL); + } + } + + // This statement is not reached when the thread is unconditionally + // terminated by the ExceptionHandler destructor. + return 0; +} + +// HandleException and HandleInvalidParameter must create an +// AutoExceptionHandler object to maintain static state and to determine which +// ExceptionHandler instance to use. The constructor locates the correct +// instance, and makes it available through get_handler(). The destructor +// restores the state in effect prior to allocating the AutoExceptionHandler. +class AutoExceptionHandler { + public: + AutoExceptionHandler() { + // Increment handler_stack_index_ so that if another Breakpad handler is + // registered using this same HandleException function, and it needs to be + // called while this handler is running (either because this handler + // declines to handle the exception, or an exception occurs during + // handling), HandleException will find the appropriate ExceptionHandler + // object in handler_stack_ to deliver the exception to. + // + // Because handler_stack_ is addressed in reverse (as |size - index|), + // preincrementing handler_stack_index_ avoids needing to subtract 1 from + // the argument to |at|. + // + // The index is maintained instead of popping elements off of the handler + // stack and pushing them at the end of this method. This avoids ruining + // the order of elements in the stack in the event that some other thread + // decides to manipulate the handler stack (such as creating a new + // ExceptionHandler object) while an exception is being handled. + EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_); + handler_ = ExceptionHandler::handler_stack_->at( + ExceptionHandler::handler_stack_->size() - + ++ExceptionHandler::handler_stack_index_); + + // In case another exception occurs while this handler is doing its thing, + // it should be delivered to the previous filter. + SetUnhandledExceptionFilter(handler_->previous_filter_); +#if _MSC_VER >= 1400 // MSVC 2005/8 + _set_invalid_parameter_handler(handler_->previous_iph_); +#endif // _MSC_VER >= 1400 + _set_purecall_handler(handler_->previous_pch_); + } + + ~AutoExceptionHandler() { + // Put things back the way they were before entering this handler. + SetUnhandledExceptionFilter(ExceptionHandler::HandleException); +#if _MSC_VER >= 1400 // MSVC 2005/8 + _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter); +#endif // _MSC_VER >= 1400 + _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall); + + --ExceptionHandler::handler_stack_index_; + LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_); + } + + ExceptionHandler* get_handler() const { return handler_; } + + private: + ExceptionHandler* handler_; +}; + +// static +LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions. This + // logic will short-circuit before calling WriteMinidumpOnHandlerThread, + // allowing something else to handle the breakpoint without incurring the + // overhead transitioning to and from the handler thread. This behavior + // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions. + DWORD code = exinfo->ExceptionRecord->ExceptionCode; + LONG action; + bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) || + (code == EXCEPTION_SINGLE_STEP) || + (code == DBG_PRINTEXCEPTION_C) || + (code == DBG_PRINTEXCEPTION_WIDE_C); + + if (code == EXCEPTION_INVALID_HANDLE && + current_handler->consume_invalid_handle_exceptions_) { + return EXCEPTION_CONTINUE_EXECUTION; + } + + MinidumpResult result = MinidumpResult::Failure; + + if (!is_debug_exception || + current_handler->get_handle_debug_exceptions()) { + // If out-of-proc crash handler client is available, we have to use that + // to generate dump and we cannot fall back on in-proc dump generation + // because we never prepared for an in-proc dump generation + + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + result = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + exinfo, + NULL); + } else { + result = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL) + ? MinidumpResult::Success : MinidumpResult::Failure; + } + } + + // The handler fully handled the exception. Returning + // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually + // results in the application being terminated. + // + // Note: If the application was launched from within the Cygwin + // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the + // application to be restarted. + if ((result == MinidumpResult::Success) || + (result == MinidumpResult::Ignored)) { + action = EXCEPTION_EXECUTE_HANDLER; + } else { + // There was an exception, it was a breakpoint or something else ignored + // above, or it was passed to the handler, which decided not to handle it. + // This could be because the filter callback didn't want it, because + // minidump writing failed for some reason, or because the post-minidump + // callback function indicated failure. Give the previous handler a + // chance to do something with the exception. If there is no previous + // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger + // or native "crashed" dialog to handle the exception. + if (current_handler->previous_filter_) { + action = current_handler->previous_filter_(exinfo); + } else { + action = EXCEPTION_CONTINUE_SEARCH; + } + } + + return action; +} + +#if _MSC_VER >= 1400 // MSVC 2005/8 +// static +void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, + unsigned int line, + uintptr_t reserved) { + // This is an invalid parameter, not an exception. It's safe to play with + // sprintf here. + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + MDRawAssertionInfo assertion; + memset(&assertion, 0, sizeof(assertion)); + _snwprintf_s(reinterpret_cast(assertion.expression), + sizeof(assertion.expression) / sizeof(assertion.expression[0]), + _TRUNCATE, L"%s", expression); + _snwprintf_s(reinterpret_cast(assertion.function), + sizeof(assertion.function) / sizeof(assertion.function[0]), + _TRUNCATE, L"%s", function); + _snwprintf_s(reinterpret_cast(assertion.file), + sizeof(assertion.file) / sizeof(assertion.file[0]), + _TRUNCATE, L"%s", file); + assertion.line = line; + assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER; + + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + + exception_record.ExceptionCode = STATUS_INVALID_PARAMETER; + + // We store pointers to the the expression and function strings, + // and the line as exception parameters to make them easy to + // access by the developer on the far side. + exception_record.NumberParameters = 3; + exception_record.ExceptionInformation[0] = + reinterpret_cast(&assertion.expression); + exception_record.ExceptionInformation[1] = + reinterpret_cast(&assertion.file); + exception_record.ExceptionInformation[2] = assertion.line; + + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + &exception_ptrs, + &assertion) == MinidumpResult::Success; + } else { + success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, + &assertion); + } + + if (!success) { + if (current_handler->previous_iph_) { + // The handler didn't fully handle the exception. Give it to the + // previous invalid parameter handler. + current_handler->previous_iph_(expression, + function, + file, + line, + reserved); + } else { + // If there's no previous handler, pass the exception back in to the + // invalid parameter handler's core. That's the routine that called this + // function, but now, since this function is no longer registered (and in + // fact, no function at all is registered), this will result in the + // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson. + // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes + // more information through. In non-debug builds, it is not available, + // so fall back to using _invalid_parameter_noinfo. See invarg.c in the + // CRT source. +#ifdef _DEBUG + _invalid_parameter(expression, function, file, line, reserved); +#else // _DEBUG + _invalid_parameter_noinfo(); +#endif // _DEBUG + } + } + + // The handler either took care of the invalid parameter problem itself, + // or passed it on to another handler. "Swallow" it by exiting, paralleling + // the behavior of "swallowing" exceptions. + exit(0); +} +#endif // _MSC_VER >= 1400 + +// static +void ExceptionHandler::HandlePureVirtualCall() { + // This is an pure virtual function call, not an exception. It's safe to + // play with sprintf here. + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + MDRawAssertionInfo assertion; + memset(&assertion, 0, sizeof(assertion)); + assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL; + + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + + exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; + + // We store pointers to the the expression and function strings, + // and the line as exception parameters to make them easy to + // access by the developer on the far side. + exception_record.NumberParameters = 3; + exception_record.ExceptionInformation[0] = + reinterpret_cast(&assertion.expression); + exception_record.ExceptionInformation[1] = + reinterpret_cast(&assertion.file); + exception_record.ExceptionInformation[2] = assertion.line; + + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + &exception_ptrs, + &assertion) == MinidumpResult::Success; + } else { + success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, + &assertion); + } + + if (!success) { + if (current_handler->previous_pch_) { + // The handler didn't fully handle the exception. Give it to the + // previous purecall handler. + current_handler->previous_pch_(); + } else { + // If there's no previous handler, return and let _purecall handle it. + // This will just put up an assertion dialog. + return; + } + } + + // The handler either took care of the invalid parameter problem itself, + // or passed it on to another handler. "Swallow" it by exiting, paralleling + // the behavior of "swallowing" exceptions. + exit(0); +} + +// static +LONG ExceptionHandler::HandleHeapCorruption(EXCEPTION_POINTERS* exinfo) { + if (exinfo->ExceptionRecord->ExceptionCode != STATUS_HEAP_CORRUPTION) { + return EXCEPTION_CONTINUE_SEARCH; + } + + AutoExceptionHandler auto_exception_handler; + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); + + bool result = false; + + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + result = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), exinfo, NULL) == MinidumpResult::Success; + } else { + result = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL); + } + + return result ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} + +bool ExceptionHandler::WriteMinidumpOnHandlerThread( + EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { + EnterCriticalSection(&handler_critical_section_); + + // There isn't much we can do if the handler thread + // was not successfully created. + if (handler_thread_ == NULL) { + LeaveCriticalSection(&handler_critical_section_); + return false; + } + + // The handler thread should only be created when the semaphores are valid. + assert(handler_start_semaphore_ != NULL); + assert(handler_finish_semaphore_ != NULL); + + // Set up data to be passed in to the handler thread. + requesting_thread_id_ = GetCurrentThreadId(); + exception_info_ = exinfo; + assertion_ = assertion; + + // This causes the handler thread to call WriteMinidumpWithException. + ReleaseSemaphore(handler_start_semaphore_, 1, NULL); + + // Wait until WriteMinidumpWithException is done and collect its return value. + WaitForSingleObject(handler_finish_semaphore_, INFINITE); + bool status = (handler_return_value_ == MinidumpResult::Success); + + // Clean up. + requesting_thread_id_ = 0; + exception_info_ = NULL; + assertion_ = NULL; + + LeaveCriticalSection(&handler_critical_section_); + + return status; +} + +bool ExceptionHandler::WriteMinidump() { + // Make up an exception record for the current thread and CPU context + // to make it possible for the crash processor to classify these + // as do regular crashes, and to make it humane for developers to + // analyze them. + EXCEPTION_RECORD exception_record = {}; + CONTEXT exception_context = {}; + EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; + + ::RtlCaptureContext(&exception_context); + exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; + + return WriteMinidumpForException(&exception_ptrs); +} + +bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (IsOutOfProcess()) { + return WriteMinidumpWithException(GetCurrentThreadId(), + exinfo, + NULL) == MinidumpResult::Success; + } + + bool success = WriteMinidumpOnHandlerThread(exinfo, NULL); + UpdateNextID(); + return success; +} + +// static +bool ExceptionHandler::WriteMinidump(const wstring &dump_path, + MinidumpCallback callback, + void* callback_context, + MINIDUMP_TYPE dump_type) { + ExceptionHandler handler(dump_path, NULL, callback, callback_context, + HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); + return handler.WriteMinidump(); +} + +// static +bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, + DWORD child_blamed_thread, + const wstring& dump_path, + MinidumpCallback callback, + void* callback_context, + MINIDUMP_TYPE dump_type) { + EXCEPTION_RECORD ex; + CONTEXT ctx; + EXCEPTION_POINTERS exinfo = { NULL, NULL }; + // As documented on MSDN, on failure SuspendThread returns (DWORD) -1 + const DWORD kFailedToSuspendThread = static_cast(-1); + DWORD last_suspend_count = kFailedToSuspendThread; + HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT | + THREAD_QUERY_INFORMATION | + THREAD_SUSPEND_RESUME, + FALSE, + child_blamed_thread); + // This thread may have died already, so not opening the handle is a + // non-fatal error. + if (child_thread_handle != NULL) { + last_suspend_count = SuspendThread(child_thread_handle); + if (last_suspend_count != kFailedToSuspendThread) { + ctx.ContextFlags = CONTEXT_ALL; + if (GetThreadContext(child_thread_handle, &ctx)) { + memset(&ex, 0, sizeof(ex)); + ex.ExceptionCode = EXCEPTION_BREAKPOINT; +#if defined(_M_IX86) + ex.ExceptionAddress = reinterpret_cast(ctx.Eip); +#elif defined(_M_X64) + ex.ExceptionAddress = reinterpret_cast(ctx.Rip); +#endif + exinfo.ExceptionRecord = &ex; + exinfo.ContextRecord = &ctx; + } + } + } + + ExceptionHandler handler(dump_path, NULL, callback, callback_context, + HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); + bool success = handler.WriteMinidumpWithExceptionForProcess( + child_blamed_thread, + exinfo.ExceptionRecord ? &exinfo : NULL, + NULL, child, false); + + if (last_suspend_count != kFailedToSuspendThread) { + ResumeThread(child_thread_handle); + } + + CloseHandle(child_thread_handle); + + if (callback) { + // nullptr here for phc::AddrInfo* is ok because this is not a crash. + success = callback(handler.dump_path_c_, handler.next_minidump_id_c_, + callback_context, NULL, NULL, nullptr, success); + } + + return success; +} + +#ifdef MOZ_PHC +static void GetPHCAddrInfo(EXCEPTION_POINTERS* exinfo, + mozilla::phc::AddrInfo* addr_info) { + // Is this a crash involving a PHC allocation? + PEXCEPTION_RECORD rec = exinfo->ExceptionRecord; + if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + // rec->ExceptionInformation[0] contains a value indicating what type of + // operation it what, and rec->ExceptionInformation[1] contains the + // virtual address of the inaccessible data. + char* crashAddr = reinterpret_cast(rec->ExceptionInformation[1]); + mozilla::phc::IsPHCAllocation(crashAddr, addr_info); + } +} +#endif + +ExceptionHandler::MinidumpResult ExceptionHandler::WriteMinidumpWithException( + DWORD requesting_thread_id, EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion) { + mozilla::phc::AddrInfo* addr_info = nullptr; +#ifdef MOZ_PHC + addr_info = &mozilla::phc::gAddrInfo; + GetPHCAddrInfo(exinfo, addr_info); +#endif + + // Give user code a chance to approve or prevent writing a minidump. If the + // filter returns Failure or Ignored , don't handle the exception and return + // the result for further handling downstream. If this method was called as a + // result of an exception, returning Failure will cause HandleException to + // call any previous handler or return EXCEPTION_CONTINUE_SEARCH on the + // exception thread, allowing it to appear as though this handler were not + // present at all. + if (filter_) { + switch (filter_(callback_context_, exinfo, assertion)) { + case FilterResult::HandleException: break; + case FilterResult::AbortWithoutMinidump: return MinidumpResult::Ignored; + case FilterResult::ContinueSearch: return MinidumpResult::Failure; + } + } + + bool success = false; + if (IsOutOfProcess()) { + success = crash_generation_client_->RequestDump(exinfo, assertion); + } else { + success = WriteMinidumpWithExceptionForProcess(requesting_thread_id, + exinfo, + assertion, + GetCurrentProcess(), + true); + } + + if (callback_) { + // TODO(munjal): In case of out-of-process dump generation, both + // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process + // scenario, the server process ends up creating the dump path and dump + // id so they are not known to the client. + success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, + exinfo, assertion, addr_info, success); + } + + return success ? MinidumpResult::Success : MinidumpResult::Failure; +} + +// static +bool ExceptionHandler::WriteMinidumpWithExceptionForProcess( + DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + HANDLE process, + bool write_requester_stream) { + bool success = false; + if (minidump_write_dump_) { + HANDLE dump_file = CreateFile(next_minidump_path_c_, + GENERIC_WRITE, + 0, // no sharing + NULL, + CREATE_NEW, // fail if exists + FILE_ATTRIBUTE_NORMAL, + NULL); + if (dump_file != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION except_info; + except_info.ThreadId = requesting_thread_id; + except_info.ExceptionPointers = exinfo; + except_info.ClientPointers = FALSE; + + // Leave room in user_stream_array for possible breakpad and + // assertion info streams. + MINIDUMP_USER_STREAM user_stream_array[2]; + MINIDUMP_USER_STREAM_INFORMATION user_streams; + user_streams.UserStreamCount = 0; + user_streams.UserStreamArray = user_stream_array; + + if (write_requester_stream) { + // Add an MDRawBreakpadInfo stream to the minidump, to provide + // additional information about the exception handler to the Breakpad + // processor. The information will help the processor determine which + // threads are relevant. The Breakpad processor does not require this + // information but can function better with Breakpad-generated dumps + // when it is present. The native debugger is not harmed by the + // presence of this information. + MDRawBreakpadInfo breakpad_info; + breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + breakpad_info.dump_thread_id = GetCurrentThreadId(); + breakpad_info.requesting_thread_id = requesting_thread_id; + + int index = user_streams.UserStreamCount; + user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM; + user_stream_array[index].BufferSize = sizeof(breakpad_info); + user_stream_array[index].Buffer = &breakpad_info; + ++user_streams.UserStreamCount; + } + + if (assertion) { + int index = user_streams.UserStreamCount; + user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM; + user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo); + user_stream_array[index].Buffer = assertion; + ++user_streams.UserStreamCount; + } + + MinidumpCallbackContext context; + context.iter = app_memory_info_.begin(); + context.end = app_memory_info_.end(); + + if (exinfo) { + IncludeAppMemoryFromExceptionContext(process, + requesting_thread_id, + app_memory_info_, + exinfo->ContextRecord, + !include_context_heap_); + } + + // Skip the reserved element if there was no instruction memory + if (context.iter->ptr == 0) { + context.iter++; + } + + MINIDUMP_CALLBACK_INFORMATION callback; + callback.CallbackRoutine = MinidumpWriteDumpCallback; + callback.CallbackParam = reinterpret_cast(&context); + + // The explicit comparison to TRUE avoids a warning (C4800). + success = (minidump_write_dump_(process, + GetProcessId(process), + dump_file, + dump_type_, + exinfo ? &except_info : NULL, + &user_streams, + &callback) == TRUE); + + CloseHandle(dump_file); + } + } + + return success; +} + +void ExceptionHandler::UpdateNextID() { + assert(uuid_create_); + UUID id = {0}; + if (uuid_create_) { + uuid_create_(&id); + } + next_minidump_id_ = GUIDString::GUIDToWString(&id); + next_minidump_id_c_ = next_minidump_id_.c_str(); + + wchar_t minidump_path[MAX_PATH]; + swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp", + dump_path_c_, next_minidump_id_c_); + + // remove when VC++7.1 is no longer supported + minidump_path[MAX_PATH - 1] = L'\0'; + + next_minidump_path_ = minidump_path; + next_minidump_path_c_ = next_minidump_path_.c_str(); +} + +void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { + AppMemoryList::iterator iter = + std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); + if (iter != app_memory_info_.end()) { + // Don't allow registering the same pointer twice. + return; + } + + AppMemory app_memory; + app_memory.ptr = reinterpret_cast(ptr); + app_memory.length = static_cast(length); + app_memory.preallocated = false; + app_memory_info_.push_back(app_memory); +} + +void ExceptionHandler::UnregisterAppMemory(void* ptr) { + AppMemoryList::iterator iter = + std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); + if (iter != app_memory_info_.end()) { + app_memory_info_.erase(iter); + } +} + +void ExceptionHandler::set_include_context_heap(bool enabled) { + if (enabled && !include_context_heap_) { + // Initialize system info used in including context heap regions. + InitAppMemoryInternal(); + + // Preallocate AppMemory instances for exception context if necessary. + auto predicate = [] (const AppMemory& appMemory) -> bool { + return appMemory.preallocated; + }; + + int preallocatedCount = + std::count_if(app_memory_info_.begin(), app_memory_info_.end(), predicate); + + for (size_t i = 0; i < kExceptionAppMemoryRegions - preallocatedCount; i++) { + AppMemory app_memory; + app_memory.ptr = reinterpret_cast(nullptr); + app_memory.length = 0; + app_memory.preallocated = true; + app_memory_info_.push_back(app_memory); + } + } + + include_context_heap_ = enabled; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.h b/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.h new file mode 100644 index 0000000000..18c8f5821a --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/handler/exception_handler.h @@ -0,0 +1,547 @@ +// 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 +#include +#include +#include + +#pragma warning(push) +// Disable exception handler warnings. +#pragma warning(disable:4530) + +#include +#include +#include + +#include "windows/common/minidump_callback.h" +#include "windows/common/ipc_protocol.h" +#include "windows/crash_generation/crash_generation_client.h" +#include "common/scoped_ptr.h" +#include "google_breakpad/common/minidump_format.h" + +#ifdef MOZ_PHC +#include "PHC.h" +#else +namespace mozilla { namespace phc { class AddrInfo {}; } } +#endif + +namespace google_breakpad { + +using std::vector; +using std::wstring; + +class ExceptionHandler { + public: + // The result value for the filter callback, see below. + enum class FilterResult { + HandleException, + AbortWithoutMinidump, + ContinueSearch + }; + + // 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 HandleException, Breakpad will attempt to + // write a minidump. If a FilterCallback returns ContinueSearch Breakpad + // will immediately report the exception as unhandled without writing a + // minidump, allowing another handler the opportunity to handle it. + // If a FilterCallback returns AbortWithoutMinidump, Breakpad will report the + // exception as handled but will not write a minidump, letting the process + // terminate itself instead. + typedef FilterResult (*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 \.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, + const mozilla::phc::AddrInfo* addr_info, + 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_HEAP_CORRUPTION = 1 << 4, // AddVectoredExceptionHandler + HANDLER_ALL = HANDLER_EXCEPTION | HANDLER_INVALID_PARAMETER | + HANDLER_PURECALL | HANDLER_HEAP_CORRUPTION + }; + + // 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 ExceptionHandler 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); + + // As above, creates a new ExceptionHandler instance to perform + // out-of-process dump generation if the given pipe_handle is not NULL. + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + HANDLE pipe_handle, + const CustomClientInfo* custom_info); + + // ExceptionHandler that ENSURES out-of-process dump generation. Expects a + // crash generation client that is already registered with a crash generation + // server. Takes ownership of the passed-in crash_generation_client. + // + // Usage example: + // crash_generation_client = new CrashGenerationClient(..); + // if (crash_generation_client->Register()) { + // // Registration with the crash generation server succeeded. + // // Out-of-process dump generation is guaranteed. + // g_handler = new ExceptionHandler(.., crash_generation_client, ..); + // return true; + // } + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + CrashGenerationClient* crash_generation_client); + + ~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_. + } + + // Requests that a previously reported crash be uploaded. + bool RequestUpload(DWORD crash_id); + + // 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, + MINIDUMP_TYPE dump_type = MiniDumpNormal); + + // Write a minidump of |child| immediately. This can be used to + // capture the execution state of |child| independently of a crash. + // Pass a meaningful |child_blamed_thread| to make that thread in + // the child process the one from which a crash signature is + // extracted. + static bool WriteMinidumpForChild(HANDLE child, + DWORD child_blamed_thread, + const wstring& dump_path, + MinidumpCallback callback, + void* callback_context, + MINIDUMP_TYPE dump_type = MiniDumpNormal); + + // 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; + } + + // Controls behavior of EXCEPTION_INVALID_HANDLE. + bool get_consume_invalid_handle_exceptions() const { + return consume_invalid_handle_exceptions_; + } + void set_consume_invalid_handle_exceptions( + bool consume_invalid_handle_exceptions) { + consume_invalid_handle_exceptions_ = consume_invalid_handle_exceptions; + } + + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } + + // Calling RegisterAppMemory(p, len) causes len bytes starting + // at address p to be copied to the minidump when a crash happens. + void RegisterAppMemory(void* ptr, size_t length); + void UnregisterAppMemory(void* ptr); + + // Calling set_include_context_heap(true) causes heap regions to be included + // in the minidump when a crash happens. The heap regions are from the + // register values of the crashing context. + void set_include_context_heap(bool enabled); + + 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, + HANDLE pipe_handle, + CrashGenerationClient* crash_generation_client, + 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 function will be called by the vectored exception handler and will + // generate a minidump only for exceptions of type STATUS_HEAP_CORRUPTION. + static LONG WINAPI HandleHeapCorruption(EXCEPTION_POINTERS* exinfo); + + // 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); + + // The return value for WriteMinidumpWithException(), see below. + enum class MinidumpResult { + Success, + Failure, + Ignored + }; + + // This function is called on the handler thread. It calls into + // WriteMinidumpWithExceptionForProcess() with a handle to the + // current process. 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. It will return Success in case the minidump has been written + // successfully, Failure if we couldn't write out the minidump because of an + // error and Ignored if we didn't even try to write the minidump because the + // filter callback indicated that we should ignore this exception and abort. + // The latter condition is only relevent for a top-level exception handler, + // other callers should equate it to a failure. + MinidumpResult WriteMinidumpWithException(DWORD requesting_thread_id, + 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 that information is + // meaningful. If the dump is requested as a result of an + // exception, exinfo contains exception information, otherwise, it + // is NULL. process is the one that will be dumped. If + // requesting_thread_id is meaningful and should be added to the + // minidump, write_requester_stream is |true|. + bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + HANDLE process, + bool write_requester_stream); + + // 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 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_; + + // Vectored exception handler used for catching STATUS_HEAP_CORRUPTION + // exceptions + PVOID heap_corruption_veh_; + + // 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. + MinidumpResult 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_; + + // If true, the handler will consume any EXCEPTION_INVALID_HANDLE exceptions. + // Leave this false (the default) to handle these exceptions as normal. + bool consume_invalid_handle_exceptions_; + + // Callers can request additional memory regions to be included in + // the dump. + AppMemoryList app_memory_info_; + + // 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* 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. + static volatile LONG instance_count_; + + bool include_context_heap_; + + // 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__ diff --git a/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild b/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild new file mode 100644 index 0000000000..22dc0d27dd --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +lobjs_handler = [ + 'exception_handler.cc', +] + +subdir = 'toolkit/crashreporter/breakpad-client/windows/handler' +objs_handler = [ + '/%s/%s' % (subdir, s) for s in lobjs_handler +] + +if CONFIG['MOZ_PHC']: + DEFINES['MOZ_PHC'] = True diff --git a/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.cc b/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.cc new file mode 100644 index 0000000000..bf8ea5ea7a --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.cc @@ -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. + +// Disable exception handler warnings. +#pragma warning(disable : 4530) + +#include + +#include "windows/sender/crash_report_sender.h" +#include "common/windows/http_upload.h" + +#if _MSC_VER < 1400 // MSVC 2005/8 +// Older MSVC doesn't have fscanf_s, but they are compatible as long as +// we don't use the string conversions (%s/%c/%S/%C). +# define fscanf_s fscanf +#endif + +namespace google_breakpad { + +static const char kCheckpointSignature[] = "GBP1\n"; + +CrashReportSender::CrashReportSender(const wstring& checkpoint_file) + : checkpoint_file_(checkpoint_file), + max_reports_per_day_(-1), + last_sent_date_(-1), + reports_sent_(0) { + FILE* fd; + if (OpenCheckpointFile(L"r", &fd) == 0) { + ReadCheckpoint(fd); + fclose(fd); + } +} + +ReportResult CrashReportSender::SendCrashReport( + const wstring& url, const string& parameters, + const map& files, wstring* report_code) { + int today = GetCurrentDate(); + if (today == last_sent_date_ && max_reports_per_day_ != -1 && + reports_sent_ >= max_reports_per_day_) { + return RESULT_THROTTLED; + } + + int http_response = 0; + bool result = HTTPUpload::SendMultipartPostRequest( + url, parameters, files, NULL, report_code, + &http_response); + + if (result) { + ReportSent(today); + return RESULT_SUCCEEDED; + } else if (http_response >= 400 && http_response < 500) { + return RESULT_REJECTED; + } else { + return RESULT_FAILED; + } +} + +void CrashReportSender::ReadCheckpoint(FILE* fd) { + char buf[128]; + if (!fgets(buf, sizeof(buf), fd) || strcmp(buf, kCheckpointSignature) != 0) { + return; + } + + if (fscanf_s(fd, "%d\n", &last_sent_date_) != 1) { + last_sent_date_ = -1; + return; + } + if (fscanf_s(fd, "%d\n", &reports_sent_) != 1) { + reports_sent_ = 0; + return; + } +} + +void CrashReportSender::ReportSent(int today) { + // Update the report stats + if (today != last_sent_date_) { + last_sent_date_ = today; + reports_sent_ = 0; + } + ++reports_sent_; + + // Update the checkpoint file + FILE* fd; + if (OpenCheckpointFile(L"w", &fd) == 0) { + fputs(kCheckpointSignature, fd); + fprintf(fd, "%d\n", last_sent_date_); + fprintf(fd, "%d\n", reports_sent_); + fclose(fd); + } +} + +int CrashReportSender::GetCurrentDate() const { + SYSTEMTIME system_time; + GetSystemTime(&system_time); + return (system_time.wYear * 10000) + (system_time.wMonth * 100) + + system_time.wDay; +} + +int CrashReportSender::OpenCheckpointFile(const wchar_t* mode, FILE** fd) { + if (checkpoint_file_.empty()) { + return ENOENT; + } +#if _MSC_VER >= 1400 // MSVC 2005/8 + return _wfopen_s(fd, checkpoint_file_.c_str(), mode); +#else + *fd = _wfopen(checkpoint_file_.c_str(), mode); + if (*fd == NULL) { + return errno; + } + return 0; +#endif +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.h b/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.h new file mode 100644 index 0000000000..02b5f4fe49 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/sender/crash_report_sender.h @@ -0,0 +1,122 @@ +// 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 +#include + +namespace google_breakpad { + +using std::map; +using std::string; +using std::wstring; + +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 files, along with the map of + // name value pairs, as a multipart POST request to the given URL. + // Parameters are specified as a JSON-encoded string in |parameters|. + // 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 string& parameters, + const map& files, + 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__ diff --git a/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild b/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild new file mode 100644 index 0000000000..3084bb92e6 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +lobjs_sender = [ + 'crash_report_sender.cc', +] + +subdir = 'toolkit/crashreporter/breakpad-client/windows/sender' +objs_sender = [ + '/%s/%s' % (subdir, s) for s in lobjs_sender +] diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/crash_generation_server_test.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/crash_generation_server_test.cc new file mode 100644 index 0000000000..09f2dd200d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/crash_generation_server_test.cc @@ -0,0 +1,303 @@ +// Copyright 2010, 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 "breakpad_googletest_includes.h" +#include "client/windows/crash_generation/crash_generation_server.h" +#include "client/windows/common/ipc_protocol.h" + +using testing::_; + +namespace { + +const wchar_t kPipeName[] = + L"\\\\.\\pipe\\CrashGenerationServerTest\\TestCaseServer"; + +const DWORD kPipeDesiredAccess = FILE_READ_DATA | + FILE_WRITE_DATA | + FILE_WRITE_ATTRIBUTES; + +const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION | + SECURITY_SQOS_PRESENT; + +const DWORD kPipeMode = PIPE_READMODE_MESSAGE; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) +const google_breakpad::CustomInfoEntry kCustomInfoEntries[] = { + google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"), + google_breakpad::CustomInfoEntry(L"ver", L"1.0"), +}; + +class CrashGenerationServerTest : public ::testing::Test { + public: + CrashGenerationServerTest() + : crash_generation_server_(kPipeName, + NULL, + CallOnClientConnected, &mock_callbacks_, + CallOnClientDumpRequested, &mock_callbacks_, + CallOnClientExited, &mock_callbacks_, + CallOnClientUploadRequested, &mock_callbacks_, + false, + NULL), + thread_id_(0), + exception_pointers_(NULL) { + memset(&assert_info_, 0, sizeof(assert_info_)); + } + + protected: + class MockCrashGenerationServerCallbacks { + public: + MOCK_METHOD1(OnClientConnected, + void(const google_breakpad::ClientInfo* client_info)); + MOCK_METHOD2(OnClientDumpRequested, + void(const google_breakpad::ClientInfo* client_info, + const std::wstring* file_path)); + MOCK_METHOD1(OnClientExited, + void(const google_breakpad::ClientInfo* client_info)); + MOCK_METHOD1(OnClientUploadRequested, + void(const DWORD crash_id)); + }; + + enum ClientFault { + NO_FAULT, + CLOSE_AFTER_CONNECT, + SEND_INVALID_REGISTRATION, + TRUNCATE_REGISTRATION, + CLOSE_AFTER_REGISTRATION, + RESPONSE_BUFFER_TOO_SMALL, + CLOSE_AFTER_RESPONSE, + SEND_INVALID_ACK + }; + + void SetUp() { + ASSERT_TRUE(crash_generation_server_.Start()); + } + + void FaultyClient(ClientFault fault_type) { + HANDLE pipe = CreateFile(kPipeName, + kPipeDesiredAccess, + 0, + NULL, + OPEN_EXISTING, + kPipeFlagsAndAttributes, + NULL); + + if (pipe == INVALID_HANDLE_VALUE) { + ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError()); + + // Cannot continue retrying if wait on pipe fails. + ASSERT_TRUE(WaitNamedPipe(kPipeName, 500)); + + pipe = CreateFile(kPipeName, + kPipeDesiredAccess, + 0, + NULL, + OPEN_EXISTING, + kPipeFlagsAndAttributes, + NULL); + } + + ASSERT_NE(pipe, INVALID_HANDLE_VALUE); + + DWORD mode = kPipeMode; + ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL)); + + DoFaultyClient(fault_type, pipe); + + CloseHandle(pipe); + } + + void DoTestFault(ClientFault fault) { + EXPECT_CALL(mock_callbacks_, OnClientConnected(_)).Times(0); + ASSERT_NO_FATAL_FAILURE(FaultyClient(fault)); + ASSERT_NO_FATAL_FAILURE(FaultyClient(fault)); + ASSERT_NO_FATAL_FAILURE(FaultyClient(fault)); + + EXPECT_CALL(mock_callbacks_, OnClientConnected(_)); + + ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT)); + + // Slight hack. The OnClientConnected is only invoked after the ack is + // received by the server. At that point, the FaultyClient call has already + // returned. The best way to wait until the server is done handling that is + // to send one more ping, whose processing will be blocked by delivery of + // the OnClientConnected message. + ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT)); + } + + MockCrashGenerationServerCallbacks mock_callbacks_; + + private: + // Depends on the caller to successfully open the pipe before invocation and + // to close it immediately afterwards. + void DoFaultyClient(ClientFault fault_type, HANDLE pipe) { + if (fault_type == CLOSE_AFTER_CONNECT) { + return; + } + + google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries, + arraysize(kCustomInfoEntries)}; + + google_breakpad::ProtocolMessage msg( + fault_type == SEND_INVALID_REGISTRATION ? + google_breakpad::MESSAGE_TAG_NONE : + google_breakpad::MESSAGE_TAG_REGISTRATION_REQUEST, + GetCurrentProcessId(), + MiniDumpNormal, + &thread_id_, + &exception_pointers_, + &assert_info_, + custom_info, + NULL, + NULL, + NULL); + + DWORD bytes_count = 0; + + ASSERT_TRUE(WriteFile(pipe, + &msg, + fault_type == TRUNCATE_REGISTRATION ? + sizeof(msg) / 2 : sizeof(msg), + &bytes_count, + NULL)); + + if (fault_type == CLOSE_AFTER_REGISTRATION) { + return; + } + + google_breakpad::ProtocolMessage reply; + + if (!ReadFile(pipe, + &reply, + fault_type == RESPONSE_BUFFER_TOO_SMALL ? + sizeof(google_breakpad::ProtocolMessage) / 2 : + sizeof(google_breakpad::ProtocolMessage), + &bytes_count, + NULL)) { + switch (fault_type) { + case TRUNCATE_REGISTRATION: + case RESPONSE_BUFFER_TOO_SMALL: + case SEND_INVALID_REGISTRATION: + return; + + default: + FAIL() << "Unexpectedly failed to register."; + } + } + + if (fault_type == CLOSE_AFTER_RESPONSE) { + return; + } + + google_breakpad::ProtocolMessage ack_msg; + ack_msg.tag = google_breakpad::MESSAGE_TAG_REGISTRATION_ACK; + + ASSERT_TRUE(WriteFile(pipe, + &ack_msg, + SEND_INVALID_ACK ? + sizeof(ack_msg) : sizeof(ack_msg) / 2, + &bytes_count, + NULL)); + + return; + } + + static void CallOnClientConnected( + void* context, const google_breakpad::ClientInfo* client_info) { + static_cast(context)-> + OnClientConnected(client_info); + } + + static void CallOnClientDumpRequested( + void* context, + const google_breakpad::ClientInfo* client_info, + const std::wstring* file_path) { + static_cast(context)-> + OnClientDumpRequested(client_info, file_path); + } + + static void CallOnClientExited( + void* context, const google_breakpad::ClientInfo* client_info) { + static_cast(context)-> + OnClientExited(client_info); + } + + static void CallOnClientUploadRequested(void* context, const DWORD crash_id) { + static_cast(context)-> + OnClientUploadRequested(crash_id); + } + + DWORD thread_id_; + EXCEPTION_POINTERS* exception_pointers_; + MDRawAssertionInfo assert_info_; + + google_breakpad::CrashGenerationServer crash_generation_server_; +}; + +TEST_F(CrashGenerationServerTest, PingServerTest) { + DoTestFault(CLOSE_AFTER_CONNECT); +} + +TEST_F(CrashGenerationServerTest, InvalidRegistration) { + DoTestFault(SEND_INVALID_REGISTRATION); +} + +TEST_F(CrashGenerationServerTest, TruncateRegistration) { + DoTestFault(TRUNCATE_REGISTRATION); +} + +TEST_F(CrashGenerationServerTest, CloseAfterRegistration) { + DoTestFault(CLOSE_AFTER_REGISTRATION); +} + +TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) { + DoTestFault(RESPONSE_BUFFER_TOO_SMALL); +} + +TEST_F(CrashGenerationServerTest, CloseAfterResponse) { + DoTestFault(CLOSE_AFTER_RESPONSE); +} + +// It turns out that, as long as you send one byte, the ACK is accepted and +// registration succeeds. +TEST_F(CrashGenerationServerTest, SendInvalidAck) { + EXPECT_CALL(mock_callbacks_, OnClientConnected(_)); + ASSERT_NO_FATAL_FAILURE(FaultyClient(SEND_INVALID_ACK)); + + // See DoTestFault for an explanation of this line + ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT)); + + EXPECT_CALL(mock_callbacks_, OnClientConnected(_)); + ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT)); + + // See DoTestFault for an explanation of this line + ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT)); +} + +} // anonymous namespace diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.cc new file mode 100644 index 0000000000..53d4ddbde9 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.cc @@ -0,0 +1,184 @@ +// Copyright (c) 2010, 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 +#include +#include + +#include "breakpad_googletest_includes.h" +#include "client/windows/unittests/dump_analysis.h" // NOLINT + +DumpAnalysis::~DumpAnalysis() { + if (dump_file_view_ != NULL) { + EXPECT_TRUE(::UnmapViewOfFile(dump_file_view_)); + ::CloseHandle(dump_file_mapping_); + dump_file_mapping_ = NULL; + } + + if (dump_file_handle_ != NULL) { + ::CloseHandle(dump_file_handle_); + dump_file_handle_ = NULL; + } +} + +void DumpAnalysis::EnsureDumpMapped() { + if (dump_file_view_ == NULL) { + dump_file_handle_ = ::CreateFile(dump_file_.c_str(), + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + 0, + NULL); + ASSERT_TRUE(dump_file_handle_ != NULL); + ASSERT_TRUE(dump_file_mapping_ == NULL); + + dump_file_mapping_ = ::CreateFileMapping(dump_file_handle_, + NULL, + PAGE_READONLY, + 0, + 0, + NULL); + ASSERT_TRUE(dump_file_mapping_ != NULL); + + dump_file_view_ = ::MapViewOfFile(dump_file_mapping_, + FILE_MAP_READ, + 0, + 0, + 0); + ASSERT_TRUE(dump_file_view_ != NULL); + } +} + +bool DumpAnalysis::HasTebs() const { + MINIDUMP_THREAD_LIST* thread_list = NULL; + size_t thread_list_size = GetStream(ThreadListStream, &thread_list); + + if (thread_list_size > 0 && thread_list != NULL) { + for (ULONG i = 0; i < thread_list->NumberOfThreads; ++i) { + if (!HasMemory(thread_list->Threads[i].Teb)) + return false; + } + + return true; + } + + // No thread list, no TEB info. + return false; +} + +bool DumpAnalysis::HasPeb() const { + MINIDUMP_THREAD_LIST* thread_list = NULL; + size_t thread_list_size = GetStream(ThreadListStream, &thread_list); + + if (thread_list_size > 0 && thread_list != NULL && + thread_list->NumberOfThreads > 0) { + FakeTEB* teb = NULL; + if (!HasMemory(thread_list->Threads[0].Teb, &teb)) + return false; + + return HasMemory(teb->peb); + } + + return false; +} + +bool DumpAnalysis::HasStream(ULONG stream_number) const { + void* stream = NULL; + size_t stream_size = GetStreamImpl(stream_number, &stream); + return stream_size > 0 && stream != NULL; +} + +size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const { + MINIDUMP_DIRECTORY* directory = NULL; + ULONG memory_list_size = 0; + BOOL ret = ::MiniDumpReadDumpStream(dump_file_view_, + stream_number, + &directory, + stream, + &memory_list_size); + + return ret ? memory_list_size : 0; +} + +bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize, + void **structure) const { + uintptr_t address = reinterpret_cast(addr_in); + MINIDUMP_MEMORY_LIST* memory_list = NULL; + size_t memory_list_size = GetStream(MemoryListStream, &memory_list); + if (memory_list_size > 0 && memory_list != NULL) { + for (ULONG i = 0; i < memory_list->NumberOfMemoryRanges; ++i) { + MINIDUMP_MEMORY_DESCRIPTOR& descr = memory_list->MemoryRanges[i]; + const uintptr_t range_start = + static_cast(descr.StartOfMemoryRange); + uintptr_t range_end = range_start + descr.Memory.DataSize; + + if (address >= range_start && + address + structuresize < range_end) { + // The start address falls in the range, and the end address is + // in bounds, return a pointer to the structure if requested. + if (structure != NULL) + *structure = RVA_TO_ADDR(dump_file_view_, descr.Memory.Rva); + + return true; + } + } + } + + // We didn't find the range in a MINIDUMP_MEMORY_LIST, so maybe this + // is a full dump using MINIDUMP_MEMORY64_LIST with all the memory at the + // end of the dump file. + MINIDUMP_MEMORY64_LIST* memory64_list = NULL; + memory_list_size = GetStream(Memory64ListStream, &memory64_list); + if (memory_list_size > 0 && memory64_list != NULL) { + // Keep track of where the current descriptor maps to. + RVA64 curr_rva = memory64_list->BaseRva; + for (ULONG i = 0; i < memory64_list->NumberOfMemoryRanges; ++i) { + MINIDUMP_MEMORY_DESCRIPTOR64& descr = memory64_list->MemoryRanges[i]; + uintptr_t range_start = + static_cast(descr.StartOfMemoryRange); + uintptr_t range_end = range_start + static_cast(descr.DataSize); + + if (address >= range_start && + address + structuresize < range_end) { + // The start address falls in the range, and the end address is + // in bounds, return a pointer to the structure if requested. + if (structure != NULL) + *structure = RVA_TO_ADDR(dump_file_view_, curr_rva); + + return true; + } + + // Advance the current RVA. + curr_rva += descr.DataSize; + } + } + + return false; +} diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.h b/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.h new file mode 100644 index 0000000000..6cef48d814 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/dump_analysis.h @@ -0,0 +1,102 @@ +// Copyright (c) 2010, 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_UNITTESTS_DUMP_ANALYSIS_H_ +#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_ + +#include "client/windows/crash_generation/minidump_generator.h" + +// Convenience to get to the PEB pointer in a TEB. +struct FakeTEB { + char dummy[0x30]; + void* peb; +}; + +class DumpAnalysis { + public: + explicit DumpAnalysis(const std::wstring& file_path) + : dump_file_(file_path), dump_file_view_(NULL), dump_file_mapping_(NULL), + dump_file_handle_(NULL) { + EnsureDumpMapped(); + } + ~DumpAnalysis(); + + bool HasStream(ULONG stream_number) const; + + // This is template to keep type safety in the front, but we end up casting + // to void** inside the implementation to pass the pointer to Win32. So + // casting here is considered safe. + template + size_t GetStream(ULONG stream_number, StreamType** stream) const { + return GetStreamImpl(stream_number, reinterpret_cast(stream)); + } + + bool HasTebs() const; + bool HasPeb() const; + bool HasMemory(ULONG64 address) const { + return HasMemory(address, NULL); + } + + bool HasMemory(const void* address) const { + return HasMemory(address, NULL); + } + + template + bool HasMemory(ULONG64 address, StructureType** structure = NULL) const { + // We can't cope with 64 bit addresses for now. + if (address > 0xFFFFFFFFUL) + return false; + + return HasMemory(reinterpret_cast(address), structure); + } + + template + bool HasMemory(const void* addr_in, StructureType** structure = NULL) const { + return HasMemoryImpl(addr_in, sizeof(StructureType), + reinterpret_cast(structure)); + } + + protected: + void EnsureDumpMapped(); + + HANDLE dump_file_mapping_; + HANDLE dump_file_handle_; + void* dump_file_view_; + std::wstring dump_file_; + + private: + // This is the implementation of GetStream<>. + size_t GetStreamImpl(ULONG stream_number, void** stream) const; + + // This is the implementation of HasMemory<>. + bool HasMemoryImpl(const void* addr_in, size_t pointersize, + void** structure) const; +}; + +#endif // CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_ diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_death_test.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_death_test.cc new file mode 100644 index 0000000000..5ef9e64d1d --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_death_test.cc @@ -0,0 +1,587 @@ +// Copyright 2009, 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 +#include +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "client/windows/crash_generation/crash_generation_server.h" +#include "client/windows/handler/exception_handler.h" +#include "client/windows/unittests/exception_handler_test.h" +#include "common/windows/string_utils-inl.h" +#include "google_breakpad/processor/minidump.h" + +namespace { + +using std::wstring; +using namespace google_breakpad; + +const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer"; +const char kSuccessIndicator[] = "success"; +const char kFailureIndicator[] = "failure"; + +// Utility function to test for a path's existence. +BOOL DoesPathExist(const TCHAR *path_name); + +enum OutOfProcGuarantee { + OUT_OF_PROC_GUARANTEED, + OUT_OF_PROC_BEST_EFFORT, +}; + +class ExceptionHandlerDeathTest : public ::testing::Test { + protected: + // Member variable for each test that they can use + // for temporary storage. + TCHAR temp_path_[MAX_PATH]; + // Actually constructs a temp path name. + virtual void SetUp(); + // A helper method that tests can use to crash. + void DoCrashAccessViolation(const OutOfProcGuarantee out_of_proc_guarantee); + void DoCrashPureVirtualCall(); +}; + +void ExceptionHandlerDeathTest::SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + TCHAR temp_path[MAX_PATH] = { '\0' }; + TCHAR test_name_wide[MAX_PATH] = { '\0' }; + // We want the temporary directory to be what the OS returns + // to us, + the test case name. + GetTempPath(MAX_PATH, temp_path); + // The test case name is exposed as a c-style string, + // convert it to a wchar_t string. + int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(), + static_cast(strlen(test_info->name())), + test_name_wide, + MAX_PATH); + if (!dwRet) { + assert(false); + } + StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); + CreateDirectory(temp_path_, NULL); +} + +BOOL DoesPathExist(const TCHAR *path_name) { + DWORD flags = GetFileAttributes(path_name); + if (flags == INVALID_FILE_ATTRIBUTES) { + return FALSE; + } + return TRUE; +} + +bool MinidumpWrittenCallback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) { + if (succeeded && DoesPathExist(dump_path)) { + fprintf(stderr, kSuccessIndicator); + } else { + fprintf(stderr, kFailureIndicator); + } + // If we don't flush, the output doesn't get sent before + // this process dies. + fflush(stderr); + return succeeded; +} + +TEST_F(ExceptionHandlerDeathTest, InProcTest) { + // For the in-proc test, we just need to instantiate an exception + // handler in in-proc mode, and crash. Since the entire test is + // reexecuted in the child process, we don't have to worry about + // the semantics of the exception handler being inherited/not + // inherited across CreateProcess(). + ASSERT_TRUE(DoesPathExist(temp_path_)); + scoped_ptr exc( + new google_breakpad::ExceptionHandler( + temp_path_, + NULL, + &MinidumpWrittenCallback, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL)); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + int *i = NULL; + ASSERT_DEATH((*i)++, kSuccessIndicator); +} + +static bool gDumpCallbackCalled = false; + +void clientDumpCallback(void *dump_context, + const google_breakpad::ClientInfo *client_info, + const std::wstring *dump_path) { + gDumpCallbackCalled = true; +} + +void ExceptionHandlerDeathTest::DoCrashAccessViolation( + const OutOfProcGuarantee out_of_proc_guarantee) { + scoped_ptr exc; + + if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) { + google_breakpad::CrashGenerationClient *client = + new google_breakpad::CrashGenerationClient(kPipeName, + MiniDumpNormal, + NULL); // custom_info + ASSERT_TRUE(client->Register()); + exc.reset(new google_breakpad::ExceptionHandler( + temp_path_, + NULL, // filter + NULL, // callback + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_ALL, + client)); + } else { + ASSERT_TRUE(out_of_proc_guarantee == OUT_OF_PROC_BEST_EFFORT); + exc.reset(new google_breakpad::ExceptionHandler( + temp_path_, + NULL, // filter + NULL, // callback + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, + kPipeName, + NULL)); // custom_info + } + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + // Although this is executing in the child process of the death test, + // if it's not true we'll still get an error rather than the crash + // being expected. + ASSERT_TRUE(exc->IsOutOfProcess()); + int *i = NULL; + printf("%d\n", (*i)++); +} + +TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) { + // We can take advantage of a detail of google test here to save some + // complexity in testing: when you do a death test, it actually forks. + // So we can make the main test harness the crash generation server, + // and call ASSERT_DEATH on a NULL dereference, it to expecting test + // the out of process scenario, since it's happening in a different + // process! This is different from the above because, above, we pass + // a NULL pipe name, and we also don't start a crash generation server. + + ASSERT_TRUE(DoesPathExist(temp_path_)); + std::wstring dump_path(temp_path_); + google_breakpad::CrashGenerationServer server( + kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL, + NULL, true, &dump_path); + + // This HAS to be EXPECT_, because when this test case is executed in the + // child process, the server registration will fail due to the named pipe + // being the same. + EXPECT_TRUE(server.Start()); + gDumpCallbackCalled = false; + ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_BEST_EFFORT), ""); + EXPECT_TRUE(gDumpCallbackCalled); +} + +TEST_F(ExceptionHandlerDeathTest, OutOfProcGuaranteedTest) { + // This is similar to the previous test (OutOfProcTest). The only difference + // is that in this test, the crash generation client is created and registered + // with the crash generation server outside of the ExceptionHandler + // constructor which allows breakpad users to opt out of the default + // in-process dump generation when the registration with the crash generation + // server fails. + + ASSERT_TRUE(DoesPathExist(temp_path_)); + std::wstring dump_path(temp_path_); + google_breakpad::CrashGenerationServer server( + kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL, + NULL, true, &dump_path); + + // This HAS to be EXPECT_, because when this test case is executed in the + // child process, the server registration will fail due to the named pipe + // being the same. + EXPECT_TRUE(server.Start()); + gDumpCallbackCalled = false; + ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_GUARANTEED), ""); + EXPECT_TRUE(gDumpCallbackCalled); +} + +TEST_F(ExceptionHandlerDeathTest, InvalidParameterTest) { + using google_breakpad::ExceptionHandler; + + ASSERT_TRUE(DoesPathExist(temp_path_)); + ExceptionHandler handler(temp_path_, NULL, NULL, NULL, + ExceptionHandler::HANDLER_INVALID_PARAMETER); + + // Disable the message box for assertions + _CrtSetReportMode(_CRT_ASSERT, 0); + + // Call with a bad argument. The invalid parameter will be swallowed + // and a dump will be generated, the process will exit(0). + ASSERT_EXIT(printf(NULL), ::testing::ExitedWithCode(0), ""); +} + + +struct PureVirtualCallBase { + PureVirtualCallBase() { + // We have to reinterpret so the linker doesn't get confused because the + // method isn't defined. + reinterpret_cast(this)->PureFunction(); + } + virtual ~PureVirtualCallBase() {} + virtual void PureFunction() const = 0; +}; +struct PureVirtualCall : public PureVirtualCallBase { + PureVirtualCall() { PureFunction(); } + virtual void PureFunction() const {} +}; + +void ExceptionHandlerDeathTest::DoCrashPureVirtualCall() { + PureVirtualCall instance; +} + +TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) { + using google_breakpad::ExceptionHandler; + + ASSERT_TRUE(DoesPathExist(temp_path_)); + ExceptionHandler handler(temp_path_, NULL, NULL, NULL, + ExceptionHandler::HANDLER_PURECALL); + + // Disable the message box for assertions + _CrtSetReportMode(_CRT_ASSERT, 0); + + // Calls a pure virtual function. + EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), ""); +} + +wstring find_minidump_in_directory(const wstring &directory) { + wstring search_path = directory + L"\\*"; + WIN32_FIND_DATA find_data; + HANDLE find_handle = FindFirstFileW(search_path.c_str(), &find_data); + if (find_handle == INVALID_HANDLE_VALUE) + return wstring(); + + wstring filename; + do { + const wchar_t extension[] = L".dmp"; + const size_t extension_length = sizeof(extension) / sizeof(extension[0]) - 1; + const size_t filename_length = wcslen(find_data.cFileName); + if (filename_length > extension_length && + wcsncmp(extension, + find_data.cFileName + filename_length - extension_length, + extension_length) == 0) { + filename = directory + L"\\" + find_data.cFileName; + break; + } + } while (FindNextFile(find_handle, &find_data)); + FindClose(find_handle); + return filename; +} + +#ifndef ADDRESS_SANITIZER + +TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) { + ASSERT_TRUE(DoesPathExist(temp_path_)); + scoped_ptr exc( + new google_breakpad::ExceptionHandler( + temp_path_, + NULL, + NULL, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL)); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + // Get some executable memory. + const uint32_t kMemorySize = 256; // bytes + const int kOffset = kMemorySize / 2; + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + char* memory = reinterpret_cast(VirtualAlloc(NULL, + kMemorySize, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE)); + ASSERT_TRUE(memory); + + // Write some instructions that will crash. Put them + // in the middle of the block of memory, because the + // minidump should contain 128 bytes on either side of the + // instruction pointer. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + ASSERT_DEATH(memory_function(), ""); + + // free the memory. + VirtualFree(memory, 0, MEM_RELEASE); + + // Verify that the resulting minidump contains the memory around the IP + wstring minidump_filename_wide = find_minidump_in_directory(temp_path_); + ASSERT_FALSE(minidump_filename_wide.empty()); + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide, + &minidump_filename)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers at least 128 bytes on either + // side of the instruction pointer from the exception record. + { + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT((unsigned)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + EXPECT_LE(kMemorySize, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint64_t ip_offset = instruction_pointer - region->GetBase(); + EXPECT_GE(region->GetSize() - kOffset, ip_offset); + EXPECT_LE(kOffset, ip_offset); + + uint8_t prefix_bytes[kOffset]; + uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_EQ(0, memcmp(bytes + ip_offset - kOffset, prefix_bytes, + sizeof(prefix_bytes))); + EXPECT_EQ(0, memcmp(bytes + ip_offset, instructions, sizeof(instructions))); + EXPECT_EQ(0, memcmp(bytes + ip_offset + sizeof(instructions), suffix_bytes, + sizeof(suffix_bytes))); + } + + DeleteFileW(minidump_filename_wide.c_str()); +} + +TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) { + ASSERT_TRUE(DoesPathExist(temp_path_)); + scoped_ptr exc( + new google_breakpad::ExceptionHandler( + temp_path_, + NULL, + NULL, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL)); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + SYSTEM_INFO sSysInfo; // Useful information about the system + GetSystemInfo(&sSysInfo); // Initialize the structure. + + const uint32_t kMemorySize = 256; // bytes + const DWORD kPageSize = sSysInfo.dwPageSize; + const int kOffset = 0; + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + // Get some executable memory. Specifically, reserve two pages, + // but only commit the second. + char* all_memory = reinterpret_cast(VirtualAlloc(NULL, + kPageSize * 2, + MEM_RESERVE, + PAGE_NOACCESS)); + ASSERT_TRUE(all_memory); + char* memory = all_memory + kPageSize; + ASSERT_TRUE(VirtualAlloc(memory, kPageSize, + MEM_COMMIT, PAGE_EXECUTE_READWRITE)); + + // Write some instructions that will crash. Put them + // in the middle of the block of memory, because the + // minidump should contain 128 bytes on either side of the + // instruction pointer. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + ASSERT_DEATH(memory_function(), ""); + + // free the memory. + VirtualFree(memory, 0, MEM_RELEASE); + + // Verify that the resulting minidump contains the memory around the IP + wstring minidump_filename_wide = find_minidump_in_directory(temp_path_); + ASSERT_FALSE(minidump_filename_wide.empty()); + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide, + &minidump_filename)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + { + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT((unsigned)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemorySize / 2, region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)]; + memset(suffix_bytes, 0, sizeof(suffix_bytes)); + EXPECT_TRUE(memcmp(bytes + kOffset, + instructions, sizeof(instructions)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), + suffix_bytes, sizeof(suffix_bytes)) == 0); + } + + DeleteFileW(minidump_filename_wide.c_str()); +} + +TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMaxBound) { + ASSERT_TRUE(DoesPathExist(temp_path_)); + scoped_ptr exc( + new google_breakpad::ExceptionHandler( + temp_path_, + NULL, + NULL, + NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL)); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + SYSTEM_INFO sSysInfo; // Useful information about the system + GetSystemInfo(&sSysInfo); // Initialize the structure. + + const DWORD kPageSize = sSysInfo.dwPageSize; + // This crashes with SIGILL on x86/x86-64/arm. + const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; + const int kOffset = kPageSize - sizeof(instructions); + // Get some executable memory. Specifically, reserve two pages, + // but only commit the first. + char* memory = reinterpret_cast(VirtualAlloc(NULL, + kPageSize * 2, + MEM_RESERVE, + PAGE_NOACCESS)); + ASSERT_TRUE(memory); + ASSERT_TRUE(VirtualAlloc(memory, kPageSize, + MEM_COMMIT, PAGE_EXECUTE_READWRITE)); + + // Write some instructions that will crash. + memcpy(memory + kOffset, instructions, sizeof(instructions)); + + // Now execute the instructions, which should crash. + typedef void (*void_function)(void); + void_function memory_function = + reinterpret_cast(memory + kOffset); + ASSERT_DEATH(memory_function(), ""); + + // free the memory. + VirtualFree(memory, 0, MEM_RELEASE); + + // Verify that the resulting minidump contains the memory around the IP + wstring minidump_filename_wide = find_minidump_in_directory(temp_path_); + ASSERT_FALSE(minidump_filename_wide.empty()); + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(minidump_filename_wide, + &minidump_filename)); + + // Read the minidump. Locate the exception record and the + // memory list, and then ensure that there is a memory region + // in the memory list that covers the instruction pointer from + // the exception record. + { + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(exception); + ASSERT_TRUE(memory_list); + ASSERT_LT((unsigned)0, memory_list->region_count()); + + MinidumpContext* context = exception->GetContext(); + ASSERT_TRUE(context); + + uint64_t instruction_pointer; + ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + ASSERT_TRUE(region); + + const size_t kPrefixSize = 128; // bytes + EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize()); + const uint8_t* bytes = region->GetMemory(); + ASSERT_TRUE(bytes); + + uint8_t prefix_bytes[kPrefixSize]; + memset(prefix_bytes, 0, sizeof(prefix_bytes)); + EXPECT_EQ(0, memcmp(bytes, prefix_bytes, sizeof(prefix_bytes))); + EXPECT_EQ(0, memcmp(bytes + kPrefixSize, + instructions, sizeof(instructions))); + } + + DeleteFileW(minidump_filename_wide.c_str()); +} + +#endif // !ADDRESS_SANITIZER + +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_nesting_test.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_nesting_test.cc new file mode 100644 index 0000000000..3ae1d7cd05 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_nesting_test.cc @@ -0,0 +1,327 @@ +// Copyright 2012, 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 + +#include + +#include "breakpad_googletest_includes.h" +#include "client/windows/handler/exception_handler.h" +#include "client/windows/unittests/exception_handler_test.h" + +namespace { + +const char kFoo[] = "foo"; +const char kBar[] = "bar"; + +const char kStartOfLine[] = "^"; +const char kEndOfLine[] = "$"; + +const char kFilterReturnsTrue[] = "filter_returns_true"; +const char kFilterReturnsFalse[] = "filter_returns_false"; + +const char kCallbackReturnsTrue[] = "callback_returns_true"; +const char kCallbackReturnsFalse[] = "callback_returns_false"; + +bool DoesPathExist(const wchar_t *path_name) { + DWORD flags = GetFileAttributes(path_name); + if (flags == INVALID_FILE_ATTRIBUTES) { + return false; + } + return true; +} + +// 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. +template +bool CrashHandlerFilter(void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion) { + if (filter_return_value) { + fprintf(stderr, kFilterReturnsTrue); + } else { + fprintf(stderr, kFilterReturnsFalse); + } + fflush(stderr); + + return filter_return_value; +} + +// 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 \.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. +template +bool MinidumpWrittenCallback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) { + bool rv = false; + if (callback_return_value && + succeeded && + DoesPathExist(dump_path)) { + rv = true; + fprintf(stderr, kCallbackReturnsTrue); + } else { + fprintf(stderr, kCallbackReturnsFalse); + } + fflush(stderr); + + return rv; +} + + +void DoCrash(const char *message) { + if (message) { + fprintf(stderr, "%s", message); + fflush(stderr); + } + int *i = NULL; + (*i)++; + + ASSERT_TRUE(false); +} + +void InstallExceptionHandlerAndCrash(bool install_filter, + bool filter_return_value, + bool install_callback, + bool callback_return_value) { + wchar_t temp_path[MAX_PATH] = { '\0' }; + GetTempPath(MAX_PATH, temp_path); + + ASSERT_TRUE(DoesPathExist(temp_path)); + google_breakpad::ExceptionHandler exc( + temp_path, + install_filter ? + (filter_return_value ? + &CrashHandlerFilter : + &CrashHandlerFilter) : + NULL, + install_callback ? + (callback_return_value ? + &MinidumpWrittenCallback : + &MinidumpWrittenCallback) : + NULL, + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + DoCrash(NULL); +} + +TEST(AssertDeathSanity, Simple) { + ASSERT_DEATH(DoCrash(NULL), ""); +} + +TEST(AssertDeathSanity, Regex) { + ASSERT_DEATH(DoCrash(kFoo), + std::string(kStartOfLine) + + std::string(kFoo) + + std::string(kEndOfLine)); + + ASSERT_DEATH(DoCrash(kBar), + std::string(kStartOfLine) + + std::string(kBar) + + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerCallbacks, FilterTrue_No_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + true, // filter_return_value + false, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsTrue) + + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerCallbacks, FilterTrue_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + true, // filter_return_value + true, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsTrue) + + std::string(kCallbackReturnsFalse) + + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerCallbacks, FilterFalse_No_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + false, // filter_return_value + false, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsFalse) + + std::string(kEndOfLine)); +} + +// Callback shouldn't be executed when filter returns false +TEST(ExceptionHandlerCallbacks, FilterFalse_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + false, // filter_return_value + true, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsFalse) + + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerCallbacks, No_Filter_No_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(false, // install_filter + true, // filter_return_value + false, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerCallbacks, No_Filter_Callback) { + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(false, // install_filter + true, // filter_return_value + true, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kCallbackReturnsFalse) + + std::string(kEndOfLine)); +} + + +TEST(ExceptionHandlerNesting, Skip_From_Inner_Filter) { + wchar_t temp_path[MAX_PATH] = { '\0' }; + GetTempPath(MAX_PATH, temp_path); + + ASSERT_TRUE(DoesPathExist(temp_path)); + google_breakpad::ExceptionHandler exc( + temp_path, + &CrashHandlerFilter, + &MinidumpWrittenCallback, + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); + + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + false, // filter_return_value + true, // install_callback + true), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsFalse) + // inner filter + std::string(kFilterReturnsTrue) + // outer filter + std::string(kCallbackReturnsFalse) + // outer callback + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerNesting, Skip_From_Inner_Callback) { + wchar_t temp_path[MAX_PATH] = { '\0' }; + GetTempPath(MAX_PATH, temp_path); + + ASSERT_TRUE(DoesPathExist(temp_path)); + google_breakpad::ExceptionHandler exc( + temp_path, + &CrashHandlerFilter, + &MinidumpWrittenCallback, + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); + + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + true, // filter_return_value + true, // install_callback + false), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsTrue) + // inner filter + std::string(kCallbackReturnsFalse) + // inner callback + std::string(kFilterReturnsTrue) + // outer filter + std::string(kCallbackReturnsFalse) + // outer callback + std::string(kEndOfLine)); +} + +TEST(ExceptionHandlerNesting, Handled_By_Inner_Handler) { + wchar_t temp_path[MAX_PATH] = { '\0' }; + GetTempPath(MAX_PATH, temp_path); + + ASSERT_TRUE(DoesPathExist(temp_path)); + google_breakpad::ExceptionHandler exc( + temp_path, + &CrashHandlerFilter, + &MinidumpWrittenCallback, + NULL, // callback_context + google_breakpad::ExceptionHandler::HANDLER_EXCEPTION); + + ASSERT_DEATH( + InstallExceptionHandlerAndCrash(true, // install_filter + true, // filter_return_value + true, // install_callback + true), // callback_return_value + std::string(kStartOfLine) + + std::string(kFilterReturnsTrue) + // inner filter + std::string(kCallbackReturnsTrue) + // inner callback + std::string(kEndOfLine)); +} + +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.cc new file mode 100644 index 0000000000..a4ce12a8aa --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.cc @@ -0,0 +1,503 @@ +// Copyright 2009, 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 "client/windows/unittests/exception_handler_test.h" + +#include +#include +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "client/windows/crash_generation/crash_generation_server.h" +#include "client/windows/handler/exception_handler.h" +#include "client/windows/unittests/dump_analysis.h" // NOLINT +#include "common/windows/string_utils-inl.h" +#include "google_breakpad/processor/minidump.h" + +namespace testing { + +DisableExceptionHandlerInScope::DisableExceptionHandlerInScope() { + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + GTEST_FLAG(catch_exceptions) = false; +} + +DisableExceptionHandlerInScope::~DisableExceptionHandlerInScope() { + GTEST_FLAG(catch_exceptions) = catch_exceptions_; +} + +} // namespace testing + +namespace { + +using std::wstring; +using namespace google_breakpad; + +const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer"; +const char kSuccessIndicator[] = "success"; +const char kFailureIndicator[] = "failure"; + +const MINIDUMP_TYPE kFullDumpType = static_cast( + MiniDumpWithFullMemory | // Full memory from process. + MiniDumpWithProcessThreadData | // Get PEB and TEB. + MiniDumpWithHandleData); // Get all handle information. + +class ExceptionHandlerTest : public ::testing::Test { + protected: + // Member variable for each test that they can use + // for temporary storage. + TCHAR temp_path_[MAX_PATH]; + + // Actually constructs a temp path name. + virtual void SetUp(); + + // Deletes temporary files. + virtual void TearDown(); + + void DoCrashInvalidParameter(); + void DoCrashPureVirtualCall(); + + // Utility function to test for a path's existence. + static BOOL DoesPathExist(const TCHAR *path_name); + + // Client callback. + static void ClientDumpCallback( + void *dump_context, + const google_breakpad::ClientInfo *client_info, + const std::wstring *dump_path); + + static bool DumpCallback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded); + + static std::wstring dump_file; + static std::wstring full_dump_file; +}; + +std::wstring ExceptionHandlerTest::dump_file; +std::wstring ExceptionHandlerTest::full_dump_file; + +void ExceptionHandlerTest::SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + TCHAR temp_path[MAX_PATH] = { '\0' }; + TCHAR test_name_wide[MAX_PATH] = { '\0' }; + // We want the temporary directory to be what the OS returns + // to us, + the test case name. + GetTempPath(MAX_PATH, temp_path); + // THe test case name is exposed to use as a c-style string, + // But we might be working in UNICODE here on Windows. + int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(), + static_cast(strlen(test_info->name())), + test_name_wide, + MAX_PATH); + if (!dwRet) { + assert(false); + } + StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); + CreateDirectory(temp_path_, NULL); +} + +void ExceptionHandlerTest::TearDown() { + if (!dump_file.empty()) { + ::DeleteFile(dump_file.c_str()); + dump_file = L""; + } + if (!full_dump_file.empty()) { + ::DeleteFile(full_dump_file.c_str()); + full_dump_file = L""; + } +} + +BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) { + DWORD flags = GetFileAttributes(path_name); + if (flags == INVALID_FILE_ATTRIBUTES) { + return FALSE; + } + return TRUE; +} + +// static +void ExceptionHandlerTest::ClientDumpCallback( + void *dump_context, + const google_breakpad::ClientInfo *client_info, + const wstring *dump_path) { + dump_file = *dump_path; + // Create the full dump file name from the dump path. + full_dump_file = dump_file.substr(0, dump_file.length() - 4) + L"-full.dmp"; +} + +// static +bool ExceptionHandlerTest::DumpCallback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) { + dump_file = dump_path; + dump_file += L"\\"; + dump_file += minidump_id; + dump_file += L".dmp"; + return succeeded; +} + +void ExceptionHandlerTest::DoCrashInvalidParameter() { + google_breakpad::ExceptionHandler *exc = + new google_breakpad::ExceptionHandler( + temp_path_, NULL, NULL, NULL, + google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER, + kFullDumpType, kPipeName, NULL); + + // Disable the message box for assertions + _CrtSetReportMode(_CRT_ASSERT, 0); + + // Although this is executing in the child process of the death test, + // if it's not true we'll still get an error rather than the crash + // being expected. + ASSERT_TRUE(exc->IsOutOfProcess()); + printf(NULL); +} + + +struct PureVirtualCallBase { + PureVirtualCallBase() { + // We have to reinterpret so the linker doesn't get confused because the + // method isn't defined. + reinterpret_cast(this)->PureFunction(); + } + virtual ~PureVirtualCallBase() {} + virtual void PureFunction() const = 0; +}; +struct PureVirtualCall : public PureVirtualCallBase { + PureVirtualCall() { PureFunction(); } + virtual void PureFunction() const {} +}; + +void ExceptionHandlerTest::DoCrashPureVirtualCall() { + google_breakpad::ExceptionHandler *exc = + new google_breakpad::ExceptionHandler( + temp_path_, NULL, NULL, NULL, + google_breakpad::ExceptionHandler::HANDLER_PURECALL, + kFullDumpType, kPipeName, NULL); + + // Disable the message box for assertions + _CrtSetReportMode(_CRT_ASSERT, 0); + + // Although this is executing in the child process of the death test, + // if it's not true we'll still get an error rather than the crash + // being expected. + ASSERT_TRUE(exc->IsOutOfProcess()); + + // Create a new frame to ensure PureVirtualCall is not optimized to some + // other line in this function. + { + PureVirtualCall instance; + } +} + +// This test validates that the minidump is written correctly. +TEST_F(ExceptionHandlerTest, InvalidParameterMiniDumpTest) { + ASSERT_TRUE(DoesPathExist(temp_path_)); + + // Call with a bad argument + ASSERT_TRUE(DoesPathExist(temp_path_)); + wstring dump_path(temp_path_); + google_breakpad::CrashGenerationServer server( + kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, NULL, + NULL, true, &dump_path); + + ASSERT_TRUE(dump_file.empty() && full_dump_file.empty()); + + // This HAS to be EXPECT_, because when this test case is executed in the + // child process, the server registration will fail due to the named pipe + // being the same. + EXPECT_TRUE(server.Start()); + EXPECT_EXIT(DoCrashInvalidParameter(), ::testing::ExitedWithCode(0), ""); + ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty()); + ASSERT_TRUE(DoesPathExist(dump_file.c_str())); + ASSERT_TRUE(DoesPathExist(full_dump_file.c_str())); + + // Verify the dump for infos. + DumpAnalysis mini(dump_file); + DumpAnalysis full(full_dump_file); + + // The dump should have all of these streams. + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(full.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(full.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(full.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(full.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + EXPECT_TRUE(full.HasStream(MiscInfoStream)); + EXPECT_TRUE(mini.HasStream(HandleDataStream)); + EXPECT_TRUE(full.HasStream(HandleDataStream)); + + // We expect PEB and TEBs in this dump. + EXPECT_TRUE(mini.HasTebs() || full.HasTebs()); + EXPECT_TRUE(mini.HasPeb() || full.HasPeb()); + + // Minidump should have a memory listing, but no 64-bit memory. + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + + EXPECT_FALSE(full.HasStream(MemoryListStream)); + EXPECT_TRUE(full.HasStream(Memory64ListStream)); + + // This is the only place we don't use OR because we want both not + // to have the streams. + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(full.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(full.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(full.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(full.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(full.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(full.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(full.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); + EXPECT_FALSE(full.HasStream(TokenStream)); +} + + +// This test validates that the minidump is written correctly. +TEST_F(ExceptionHandlerTest, PureVirtualCallMiniDumpTest) { + ASSERT_TRUE(DoesPathExist(temp_path_)); + + // Call with a bad argument + ASSERT_TRUE(DoesPathExist(temp_path_)); + wstring dump_path(temp_path_); + google_breakpad::CrashGenerationServer server( + kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, NULL, + NULL, true, &dump_path); + + ASSERT_TRUE(dump_file.empty() && full_dump_file.empty()); + + // This HAS to be EXPECT_, because when this test case is executed in the + // child process, the server registration will fail due to the named pipe + // being the same. + EXPECT_TRUE(server.Start()); + EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), ""); + ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty()); + ASSERT_TRUE(DoesPathExist(dump_file.c_str())); + ASSERT_TRUE(DoesPathExist(full_dump_file.c_str())); + + // Verify the dump for infos. + DumpAnalysis mini(dump_file); + DumpAnalysis full(full_dump_file); + + // The dump should have all of these streams. + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(full.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(full.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(full.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(full.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + EXPECT_TRUE(full.HasStream(MiscInfoStream)); + EXPECT_TRUE(mini.HasStream(HandleDataStream)); + EXPECT_TRUE(full.HasStream(HandleDataStream)); + + // We expect PEB and TEBs in this dump. + EXPECT_TRUE(mini.HasTebs() || full.HasTebs()); + EXPECT_TRUE(mini.HasPeb() || full.HasPeb()); + + // Minidump should have a memory listing, but no 64-bit memory. + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + + EXPECT_FALSE(full.HasStream(MemoryListStream)); + EXPECT_TRUE(full.HasStream(Memory64ListStream)); + + // This is the only place we don't use OR because we want both not + // to have the streams. + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(full.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(full.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(full.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(full.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(full.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(full.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(full.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); + EXPECT_FALSE(full.HasStream(TokenStream)); +} + +// Test that writing a minidump produces a valid minidump containing +// some expected structures. +TEST_F(ExceptionHandlerTest, WriteMinidumpTest) { + ExceptionHandler handler(temp_path_, + NULL, + DumpCallback, + NULL, + ExceptionHandler::HANDLER_ALL); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + ASSERT_TRUE(handler.WriteMinidump()); + ASSERT_FALSE(dump_file.empty()); + + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(dump_file, + &minidump_filename)); + + // Read the minidump and verify some info. + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + // TODO(ted): more comprehensive tests... +} + +// Test that an additional memory region can be included in the minidump. +TEST_F(ExceptionHandlerTest, AdditionalMemory) { + SYSTEM_INFO si; + GetSystemInfo(&si); + const uint32_t kMemorySize = si.dwPageSize; + + // Get some heap memory. + uint8_t* memory = new uint8_t[kMemorySize]; + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + // Stick some data into the memory so the contents can be verified. + for (uint32_t i = 0; i < kMemorySize; ++i) { + memory[i] = i % 255; + } + + ExceptionHandler handler(temp_path_, + NULL, + DumpCallback, + NULL, + ExceptionHandler::HANDLER_ALL); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + // Add the memory region to the list of memory to be included. + handler.RegisterAppMemory(memory, kMemorySize); + ASSERT_TRUE(handler.WriteMinidump()); + ASSERT_FALSE(dump_file.empty()); + + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(dump_file, + &minidump_filename)); + + // Read the minidump. Ensure that the memory region is present + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(dump_memory_list); + const MinidumpMemoryRegion* region = + dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); + ASSERT_TRUE(region); + + EXPECT_EQ(kMemoryAddress, region->GetBase()); + EXPECT_EQ(kMemorySize, region->GetSize()); + + // Verify memory contents. + EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize)); + + delete[] memory; +} + +// Test that a memory region that was previously registered +// can be unregistered. +TEST_F(ExceptionHandlerTest, AdditionalMemoryRemove) { + SYSTEM_INFO si; + GetSystemInfo(&si); + const uint32_t kMemorySize = si.dwPageSize; + + // Get some heap memory. + uint8_t* memory = new uint8_t[kMemorySize]; + const uintptr_t kMemoryAddress = reinterpret_cast(memory); + ASSERT_TRUE(memory); + + // Stick some data into the memory so the contents can be verified. + for (uint32_t i = 0; i < kMemorySize; ++i) { + memory[i] = i % 255; + } + + ExceptionHandler handler(temp_path_, + NULL, + DumpCallback, + NULL, + ExceptionHandler::HANDLER_ALL); + + // Disable GTest SEH handler + testing::DisableExceptionHandlerInScope disable_exception_handler; + + // Add the memory region to the list of memory to be included. + handler.RegisterAppMemory(memory, kMemorySize); + + // ...and then remove it + handler.UnregisterAppMemory(memory); + + ASSERT_TRUE(handler.WriteMinidump()); + ASSERT_FALSE(dump_file.empty()); + + string minidump_filename; + ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(dump_file, + &minidump_filename)); + + // Read the minidump. Ensure that the memory region is not present. + Minidump minidump(minidump_filename); + ASSERT_TRUE(minidump.Read()); + + MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(dump_memory_list); + const MinidumpMemoryRegion* region = + dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); + EXPECT_FALSE(region); + + delete[] memory; +} + +} // namespace diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.h b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.h new file mode 100644 index 0000000000..ef973e5392 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/exception_handler_test.h @@ -0,0 +1,61 @@ +// Copyright 2012, 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_UNITTESTS_EXCEPTION_HANDLER_TEST_H_ +#define CLIENT_WINDOWS_UNITTESTS_EXCEPTION_HANDLER_TEST_H_ + +namespace testing { + +// By default, GTest (on Windows) installs a SEH filter (and a handler) before +// starting to run all the tests in order to avoid test interruptions is some +// of the tests are crashing. Unfortunately, this functionality prevents the +// execution to reach the UnhandledExceptionFilter installed by Google-Breakpad +// ExceptionHandler so in order to test the Google-Breakpad exception handling +// code the exception handling done by GTest must be disabled. +// Usage: +// +// google_breakpad::ExceptionHandler exc(...); +// +// // Disable GTest SEH handler +// testing::DisableExceptionHandlerInScope disable_exception_handler; +// ... +// ASSERT_DEATH( ... some crash ...); +// +class DisableExceptionHandlerInScope { + public: + DisableExceptionHandlerInScope(); + ~DisableExceptionHandlerInScope(); + + private: + bool catch_exceptions_; +}; + +} // namespace testing + +#endif // CLIENT_WINDOWS_UNITTESTS_EXCEPTION_HANDLER_TEST_H_ diff --git a/toolkit/crashreporter/breakpad-client/windows/unittests/minidump_test.cc b/toolkit/crashreporter/breakpad-client/windows/unittests/minidump_test.cc new file mode 100644 index 0000000000..82641125c1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-client/windows/unittests/minidump_test.cc @@ -0,0 +1,332 @@ +// Copyright (c) 2010, 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 +#include +#include + +#include "breakpad_googletest_includes.h" +#include "client/windows/crash_generation/minidump_generator.h" +#include "client/windows/unittests/dump_analysis.h" // NOLINT + +namespace { + +// Minidump with stacks, PEB, TEB, and unloaded module list. +const MINIDUMP_TYPE kSmallDumpType = static_cast( + MiniDumpWithProcessThreadData | // Get PEB and TEB. + MiniDumpWithUnloadedModules); // Get unloaded modules when available. + +// Minidump with all of the above, plus memory referenced from stack. +const MINIDUMP_TYPE kLargerDumpType = static_cast( + MiniDumpWithProcessThreadData | // Get PEB and TEB. + MiniDumpWithUnloadedModules | // Get unloaded modules when available. + MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. + +// Large dump with all process memory. +const MINIDUMP_TYPE kFullDumpType = static_cast( + MiniDumpWithFullMemory | // Full memory from process. + MiniDumpWithProcessThreadData | // Get PEB and TEB. + MiniDumpWithHandleData | // Get all handle information. + MiniDumpWithUnloadedModules); // Get unloaded modules when available. + +class MinidumpTest: public testing::Test { + public: + MinidumpTest() { + wchar_t temp_dir_path[ MAX_PATH ] = {0}; + ::GetTempPath(MAX_PATH, temp_dir_path); + dump_path_ = temp_dir_path; + } + + virtual void SetUp() { + // Make sure URLMon isn't loaded into our process. + ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll")); + + // Then load and unload it to ensure we have something to + // stock the unloaded module list with. + HMODULE urlmon = ::LoadLibrary(L"urlmon.dll"); + ASSERT_TRUE(urlmon != NULL); + ASSERT_TRUE(::FreeLibrary(urlmon)); + } + + virtual void TearDown() { + if (!dump_file_.empty()) { + ::DeleteFile(dump_file_.c_str()); + dump_file_ = L""; + } + if (!full_dump_file_.empty()) { + ::DeleteFile(full_dump_file_.c_str()); + full_dump_file_ = L""; + } + } + + bool WriteDump(ULONG flags) { + using google_breakpad::MinidumpGenerator; + + // Fake exception is access violation on write to this. + EXCEPTION_RECORD ex_record = { + STATUS_ACCESS_VIOLATION, // ExceptionCode + 0, // ExceptionFlags + NULL, // ExceptionRecord; + reinterpret_cast(static_cast(0xCAFEBABE)), // ExceptionAddress; + 2, // NumberParameters; + { EXCEPTION_WRITE_FAULT, reinterpret_cast(this) } + }; + CONTEXT ctx_record = {}; + EXCEPTION_POINTERS ex_ptrs = { + &ex_record, + &ctx_record, + }; + + MinidumpGenerator generator(dump_path_, + ::GetCurrentProcess(), + ::GetCurrentProcessId(), + ::GetCurrentThreadId(), + ::GetCurrentThreadId(), + &ex_ptrs, + NULL, + static_cast(flags), + TRUE); + generator.GenerateDumpFile(&dump_file_); + generator.GenerateFullDumpFile(&full_dump_file_); + // And write a dump + bool result = generator.WriteMinidump(); + return result == TRUE; + } + + protected: + std::wstring dump_file_; + std::wstring full_dump_file_; + + std::wstring dump_path_; +}; + +// We need to be able to get file information from Windows +bool HasFileInfo(const std::wstring& file_path) { + DWORD dummy; + const wchar_t* path = file_path.c_str(); + DWORD length = ::GetFileVersionInfoSize(path, &dummy); + if (length == 0) + return NULL; + + void* data = calloc(length, 1); + if (!data) + return false; + + if (!::GetFileVersionInfo(path, dummy, length, data)) { + free(data); + return false; + } + + void* translate = NULL; + UINT page_count; + BOOL query_result = VerQueryValue( + data, + L"\\VarFileInfo\\Translation", + static_cast(&translate), + &page_count); + + free(data); + if (query_result && translate) { + return true; + } else { + return false; + } +} + +TEST_F(MinidumpTest, Version) { + // Loads DbgHelp.dll in process + ImagehlpApiVersion(); + + HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll"); + ASSERT_TRUE(dbg_help != NULL); + + wchar_t dbg_help_file[1024] = {}; + ASSERT_TRUE(::GetModuleFileName(dbg_help, + dbg_help_file, + sizeof(dbg_help_file) / + sizeof(*dbg_help_file))); + ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL); + +// LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version(); +} + +TEST_F(MinidumpTest, Normal) { + EXPECT_TRUE(WriteDump(MiniDumpNormal)); + DumpAnalysis mini(dump_file_); + + // We expect threads, modules and some memory. + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(HandleDataStream)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); + + // We expect no PEB nor TEBs in this dump. + EXPECT_FALSE(mini.HasTebs()); + EXPECT_FALSE(mini.HasPeb()); + + // We expect no off-stack memory in this dump. + EXPECT_FALSE(mini.HasMemory(this)); +} + +TEST_F(MinidumpTest, SmallDump) { + ASSERT_TRUE(WriteDump(kSmallDumpType)); + DumpAnalysis mini(dump_file_); + + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + + // We expect PEB and TEBs in this dump. + EXPECT_TRUE(mini.HasTebs()); + EXPECT_TRUE(mini.HasPeb()); + + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(HandleDataStream)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); + + // We expect no off-stack memory in this dump. + EXPECT_FALSE(mini.HasMemory(this)); +} + +TEST_F(MinidumpTest, LargerDump) { + ASSERT_TRUE(WriteDump(kLargerDumpType)); + DumpAnalysis mini(dump_file_); + + // The dump should have all of these streams. + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + + // We expect memory referenced by stack in this dump. + EXPECT_TRUE(mini.HasMemory(this)); + + // We expect PEB and TEBs in this dump. + EXPECT_TRUE(mini.HasTebs()); + EXPECT_TRUE(mini.HasPeb()); + + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(HandleDataStream)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); +} + +TEST_F(MinidumpTest, FullDump) { + ASSERT_TRUE(WriteDump(kFullDumpType)); + ASSERT_TRUE(dump_file_ != L""); + ASSERT_TRUE(full_dump_file_ != L""); + DumpAnalysis mini(dump_file_); + DumpAnalysis full(full_dump_file_); + + // Either dumps can contain part of the information. + + // The dump should have all of these streams. + EXPECT_TRUE(mini.HasStream(ThreadListStream)); + EXPECT_TRUE(full.HasStream(ThreadListStream)); + EXPECT_TRUE(mini.HasStream(ModuleListStream)); + EXPECT_TRUE(full.HasStream(ModuleListStream)); + EXPECT_TRUE(mini.HasStream(ExceptionStream)); + EXPECT_TRUE(full.HasStream(ExceptionStream)); + EXPECT_TRUE(mini.HasStream(SystemInfoStream)); + EXPECT_TRUE(full.HasStream(SystemInfoStream)); + EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream)); + EXPECT_TRUE(full.HasStream(UnloadedModuleListStream)); + EXPECT_TRUE(mini.HasStream(MiscInfoStream)); + EXPECT_TRUE(full.HasStream(MiscInfoStream)); + EXPECT_TRUE(mini.HasStream(HandleDataStream)); + EXPECT_TRUE(full.HasStream(HandleDataStream)); + + // We expect memory referenced by stack in this dump. + EXPECT_FALSE(mini.HasMemory(this)); + EXPECT_TRUE(full.HasMemory(this)); + + // We expect PEB and TEBs in this dump. + EXPECT_TRUE(mini.HasTebs() || full.HasTebs()); + EXPECT_TRUE(mini.HasPeb() || full.HasPeb()); + + EXPECT_TRUE(mini.HasStream(MemoryListStream)); + EXPECT_TRUE(full.HasStream(Memory64ListStream)); + EXPECT_FALSE(mini.HasStream(Memory64ListStream)); + EXPECT_FALSE(full.HasStream(MemoryListStream)); + + // This is the only place we don't use OR because we want both not + // to have the streams. + EXPECT_FALSE(mini.HasStream(ThreadExListStream)); + EXPECT_FALSE(full.HasStream(ThreadExListStream)); + EXPECT_FALSE(mini.HasStream(CommentStreamA)); + EXPECT_FALSE(full.HasStream(CommentStreamA)); + EXPECT_FALSE(mini.HasStream(CommentStreamW)); + EXPECT_FALSE(full.HasStream(CommentStreamW)); + EXPECT_FALSE(mini.HasStream(FunctionTableStream)); + EXPECT_FALSE(full.HasStream(FunctionTableStream)); + EXPECT_FALSE(mini.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(full.HasStream(MemoryInfoListStream)); + EXPECT_FALSE(mini.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(full.HasStream(ThreadInfoListStream)); + EXPECT_FALSE(mini.HasStream(HandleOperationListStream)); + EXPECT_FALSE(full.HasStream(HandleOperationListStream)); + EXPECT_FALSE(mini.HasStream(TokenStream)); + EXPECT_FALSE(full.HasStream(TokenStream)); +} + +} // namespace diff --git a/toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch b/toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch new file mode 100644 index 0000000000..33ae81f3df --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/00-arm-exidx-rollup.patch @@ -0,0 +1,1352 @@ +diff --git a/Makefile.am b/Makefile.am +index 9a25d9d4..07206601 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -571,6 +571,8 @@ src_tools_linux_core2md_core2md_LDADD = \ + src/client/linux/libbreakpad_client.a + + src_tools_linux_dump_syms_dump_syms_SOURCES = \ ++ src/common/arm_ex_reader.cc \ ++ src/common/arm_ex_to_module.cc \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ +@@ -660,6 +662,8 @@ src_tools_mac_dump_syms_dump_syms_mac_LDADD= \ + $(RUST_DEMANGLE_LIBS) + + src_common_dumper_unittest_SOURCES = \ ++ src/common/arm_ex_reader.cc \ ++ src/common/arm_ex_to_module.cc \ + src/common/byte_cursor_unittest.cc \ + src/common/convert_UTF.cc \ + src/common/dwarf_cfi_to_module.cc \ +@@ -1348,6 +1352,10 @@ EXTRA_DIST = \ + src/client/windows/sender/crash_report_sender.cc \ + src/client/windows/sender/crash_report_sender.h \ + src/client/windows/sender/crash_report_sender.gyp \ ++ src/common/arm_ex_reader.cc \ ++ src/common/arm_ex_reader.h \ ++ src/common/arm_ex_to_module.cc \ ++ src/common/arm_ex_to_module.h \ + src/common/dwarf/dwarf2diehandler.h \ + src/common/dwarf/dwarf2enums.h \ + src/common/dwarf/line_state_machine.h \ +diff --git a/src/common/arm_ex_reader.cc b/src/common/arm_ex_reader.cc +new file mode 100644 +index 00000000..2d1ed983 +--- /dev/null ++++ b/src/common/arm_ex_reader.cc +@@ -0,0 +1,487 @@ ++ ++/* libunwind - a platform-independent unwind library ++ Copyright 2011 Linaro Limited ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++// Copyright (c) 2010 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. ++ ++ ++// Derived from libunwind, with extensive modifications. ++ ++ ++#include "common/arm_ex_reader.h" ++ ++#include ++#include ++ ++// This file, in conjunction with arm_ex_to_module.cc, translates ++// EXIDX unwind information into the same format that Breakpad uses ++// for CFI information. Hence Breakpad's CFI unwinding abilities ++// also become usable for EXIDX. ++// ++// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A ++// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf ++ ++// EXIDX data is presented in two parts: ++// ++// * an index table. This contains two words per routine, ++// the first of which identifies the routine, and the second ++// of which is a reference to the unwind bytecode. If the ++// bytecode is very compact -- 3 bytes or less -- it can be ++// stored directly in the second word. ++// ++// * an area containing the unwind bytecodes. ++ ++// General flow is: ExceptionTableInfo::Start iterates over all ++// of the index table entries (pairs). For each entry, it: ++// ++// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode ++// out into an intermediate buffer. ++ ++// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate ++// buffer. Each bytecode instruction is bundled into a ++// arm_ex_to_module::extab_data structure, and handed to .. ++// ++// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to ++// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI ++// records that Breakpad stores. ++ ++#define ARM_EXIDX_CANT_UNWIND 0x00000001 ++#define ARM_EXIDX_COMPACT 0x80000000 ++#define ARM_EXTBL_OP_FINISH 0xb0 ++#define ARM_EXIDX_TABLE_LIMIT (255*4) ++ ++namespace arm_ex_reader { ++ ++using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; ++using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; ++using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; ++using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; ++using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; ++using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; ++using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; ++using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; ++using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; ++using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; ++using arm_ex_to_module::exidx_entry; ++using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; ++using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; ++using google_breakpad::MemoryRange; ++ ++ ++static void* Prel31ToAddr(const void* addr) { ++ uint32_t offset32 = *reinterpret_cast(addr); ++ // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions ++ // 63:31 inclusive. ++ uint64_t offset64 = offset32; ++ if (offset64 & (1ULL << 30)) ++ offset64 |= 0xFFFFFFFF80000000ULL; ++ else ++ offset64 &= 0x000000007FFFFFFFULL; ++ return ((char*)addr) + (uintptr_t)offset64; ++} ++ ++ ++// Extract unwind bytecode for the function denoted by |entry| into |buf|, ++// and return the number of bytes of |buf| written, along with a code ++// indicating the outcome. ++ ++ExceptionTableInfo::ExExtractResult ExceptionTableInfo::ExtabEntryExtract( ++ const struct exidx_entry* entry, ++ uint8_t* buf, size_t buf_size, ++ size_t* buf_used) { ++ MemoryRange mr_out(buf, buf_size); ++ ++ *buf_used = 0; ++ ++# define PUT_BUF_U8(_byte) \ ++ do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ ++ buf[(*buf_used)++] = (_byte); } while (0) ++ ++# define GET_EX_U32(_lval, _addr, _sec_mr) \ ++ do { if (!(_sec_mr).Covers(reinterpret_cast(_addr) \ ++ - (_sec_mr).data(), 4)) \ ++ return ExInBufOverflow; \ ++ (_lval) = *(reinterpret_cast(_addr)); } while (0) ++ ++# define GET_EXIDX_U32(_lval, _addr) \ ++ GET_EX_U32(_lval, _addr, mr_exidx_) ++# define GET_EXTAB_U32(_lval, _addr) \ ++ GET_EX_U32(_lval, _addr, mr_extab_) ++ ++ uint32_t data; ++ GET_EXIDX_U32(data, &entry->data); ++ ++ // A function can be marked CANT_UNWIND if (eg) it is known to be ++ // at the bottom of the stack. ++ if (data == ARM_EXIDX_CANT_UNWIND) ++ return ExCantUnwind; ++ ++ uint32_t pers; // personality number ++ uint32_t extra; // number of extra data words required ++ uint32_t extra_allowed; // number of extra data words allowed ++ uint32_t* extbl_data; // the handler entry, if not inlined ++ ++ if (data & ARM_EXIDX_COMPACT) { ++ // The handler table entry has been inlined into the index table entry. ++ // In this case it can only be an ARM-defined compact model, since ++ // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the ++ // ARM compact model, but 1 and 2 are "Long format" and may require ++ // extra data words. Hence the allowable personalities here are: ++ // personality 0, in which case 'extra' has no meaning ++ // personality 1, with zero extra words ++ // personality 2, with zero extra words ++ extbl_data = NULL; ++ pers = (data >> 24) & 0x0F; ++ extra = (data >> 16) & 0xFF; ++ extra_allowed = 0; ++ } ++ else { ++ // The index table entry is a pointer to the handler entry. Note ++ // that Prel31ToAddr will read the given address, but we already ++ // range-checked above. ++ extbl_data = reinterpret_cast(Prel31ToAddr(&entry->data)); ++ GET_EXTAB_U32(data, extbl_data); ++ if (!(data & ARM_EXIDX_COMPACT)) { ++ // This denotes a "generic model" handler. That will involve ++ // executing arbitary machine code, which is something we ++ // can't represent here; hence reject it. ++ return ExCantRepresent; ++ } ++ // So we have a compact model representation. Again, 3 possible ++ // personalities, but this time up to 255 allowable extra words. ++ pers = (data >> 24) & 0x0F; ++ extra = (data >> 16) & 0xFF; ++ extra_allowed = 255; ++ extbl_data++; ++ } ++ ++ // Now look at the the handler table entry. The first word is ++ // |data| and subsequent words start at |*extbl_data|. The number ++ // of extra words to use is |extra|, provided that the personality ++ // allows extra words. Even if it does, none may be available -- ++ // extra_allowed is the maximum number of extra words allowed. */ ++ if (pers == 0) { ++ // "Su16" in the documentation -- 3 unwinding insn bytes ++ // |extra| has no meaning here; instead that byte is an unwind-info byte ++ PUT_BUF_U8(data >> 16); ++ PUT_BUF_U8(data >> 8); ++ PUT_BUF_U8(data); ++ } ++ else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { ++ // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, ++ // and up to 255 extra words. ++ PUT_BUF_U8(data >> 8); ++ PUT_BUF_U8(data); ++ for (uint32_t j = 0; j < extra; j++) { ++ GET_EXTAB_U32(data, extbl_data); ++ extbl_data++; ++ PUT_BUF_U8(data >> 24); ++ PUT_BUF_U8(data >> 16); ++ PUT_BUF_U8(data >> 8); ++ PUT_BUF_U8(data >> 0); ++ } ++ } ++ else { ++ // The entry is invalid. ++ return ExInvalid; ++ } ++ ++ // Make sure the entry is terminated with "FINISH" ++ if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) ++ PUT_BUF_U8(ARM_EXTBL_OP_FINISH); ++ ++ return ExSuccess; ++ ++# undef GET_EXTAB_U32 ++# undef GET_EXIDX_U32 ++# undef GET_U32 ++# undef PUT_BUF_U8 ++} ++ ++ ++// Take the unwind information extracted by ExtabEntryExtract ++// and parse it into frame-unwind instructions. These are as ++// specified in "Table 4, ARM-defined frame-unwinding instructions" ++// in the specification document detailed in comments at the top ++// of this file. ++// ++// This reads from |buf[0, +data_size)|. It checks for overruns of ++// the input buffer and returns a negative value if that happens, or ++// for any other failure cases. It returns zero in case of success. ++int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) { ++ if (buf == NULL || buf_size == 0) ++ return -1; ++ ++ MemoryRange mr_in(buf, buf_size); ++ const uint8_t* buf_initially = buf; ++ ++# define GET_BUF_U8(_lval) \ ++ do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ ++ (_lval) = *(buf++); } while (0) ++ ++ const uint8_t* end = buf + buf_size; ++ ++ while (buf < end) { ++ struct arm_ex_to_module::extab_data edata; ++ memset(&edata, 0, sizeof(edata)); ++ ++ uint8_t op; ++ GET_BUF_U8(op); ++ if ((op & 0xc0) == 0x00) { ++ // vsp = vsp + (xxxxxx << 2) + 4 ++ edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; ++ edata.data = (((int)op & 0x3f) << 2) + 4; ++ } else if ((op & 0xc0) == 0x40) { ++ // vsp = vsp - (xxxxxx << 2) - 4 ++ edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; ++ edata.data = (((int)op & 0x3f) << 2) + 4; ++ } else if ((op & 0xf0) == 0x80) { ++ uint8_t op2; ++ GET_BUF_U8(op2); ++ if (op == 0x80 && op2 == 0x00) { ++ // Refuse to unwind ++ edata.cmd = ARM_EXIDX_CMD_REFUSED; ++ } else { ++ // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} ++ edata.cmd = ARM_EXIDX_CMD_REG_POP; ++ edata.data = ((op & 0xf) << 8) | op2; ++ edata.data = edata.data << 4; ++ } ++ } else if ((op & 0xf0) == 0x90) { ++ if (op == 0x9d || op == 0x9f) { ++ // 9d: Reserved as prefix for ARM register to register moves ++ // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves ++ edata.cmd = ARM_EXIDX_CMD_RESERVED; ++ } else { ++ // Set vsp = r[nnnn] ++ edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; ++ edata.data = op & 0x0f; ++ } ++ } else if ((op & 0xf0) == 0xa0) { ++ // Pop r4 to r[4+nnn], or ++ // Pop r4 to r[4+nnn] and r14 or ++ unsigned end = (op & 0x07); ++ edata.data = (1 << (end + 1)) - 1; ++ edata.data = edata.data << 4; ++ if (op & 0x08) edata.data |= 1 << 14; ++ edata.cmd = ARM_EXIDX_CMD_REG_POP; ++ } else if (op == ARM_EXTBL_OP_FINISH) { ++ // Finish ++ edata.cmd = ARM_EXIDX_CMD_FINISH; ++ buf = end; ++ } else if (op == 0xb1) { ++ uint8_t op2; ++ GET_BUF_U8(op2); ++ if (op2 == 0 || (op2 & 0xf0)) { ++ // Spare ++ edata.cmd = ARM_EXIDX_CMD_RESERVED; ++ } else { ++ // Pop integer registers under mask {r3,r2,r1,r0} ++ edata.cmd = ARM_EXIDX_CMD_REG_POP; ++ edata.data = op2 & 0x0f; ++ } ++ } else if (op == 0xb2) { ++ // vsp = vsp + 0x204 + (uleb128 << 2) ++ uint64_t offset = 0; ++ uint8_t byte, shift = 0; ++ do { ++ GET_BUF_U8(byte); ++ offset |= (byte & 0x7f) << shift; ++ shift += 7; ++ } while ((byte & 0x80) && buf < end); ++ edata.data = offset * 4 + 0x204; ++ edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; ++ } else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { ++ // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly ++ // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly ++ // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly ++ edata.cmd = ARM_EXIDX_CMD_VFP_POP; ++ GET_BUF_U8(edata.data); ++ if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; ++ if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; ++ } else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { ++ // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly ++ // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly ++ edata.cmd = ARM_EXIDX_CMD_VFP_POP; ++ edata.data = 0x80 | (op & 0x07); ++ if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; ++ } else if (op >= 0xc0 && op <= 0xc5) { ++ // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 ++ edata.cmd = ARM_EXIDX_CMD_WREG_POP; ++ edata.data = 0xa0 | (op & 0x07); ++ } else if (op == 0xc6) { ++ // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] ++ edata.cmd = ARM_EXIDX_CMD_WREG_POP; ++ GET_BUF_U8(edata.data); ++ } else if (op == 0xc7) { ++ uint8_t op2; ++ GET_BUF_U8(op2); ++ if (op2 == 0 || (op2 & 0xf0)) { ++ // Spare ++ edata.cmd = ARM_EXIDX_CMD_RESERVED; ++ } else { ++ // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} ++ edata.cmd = ARM_EXIDX_CMD_WCGR_POP; ++ edata.data = op2 & 0x0f; ++ } ++ } else { ++ // Spare ++ edata.cmd = ARM_EXIDX_CMD_RESERVED; ++ } ++ ++ int ret = handler_->ImproveStackFrame(&edata); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++ ++# undef GET_BUF_U8 ++} ++ ++void ExceptionTableInfo::Start() { ++ const struct exidx_entry* start ++ = reinterpret_cast(mr_exidx_.data()); ++ const struct exidx_entry* end ++ = reinterpret_cast(mr_exidx_.data() ++ + mr_exidx_.length()); ++ ++ // Iterate over each of the EXIDX entries (pairs of 32-bit words). ++ // These occupy the entire .exidx section. ++ for (const struct exidx_entry* entry = start; entry < end; ++entry) { ++ // Figure out the code address range that this table entry is ++ // associated with. ++ uint32_t addr = (reinterpret_cast(Prel31ToAddr(&entry->addr)) ++ - mapping_addr_ + loading_addr_) & 0x7fffffff; ++ uint32_t next_addr; ++ if (entry < end - 1) { ++ next_addr = (reinterpret_cast(Prel31ToAddr(&((entry + 1)->addr))) ++ - mapping_addr_ + loading_addr_) & 0x7fffffff; ++ } else { ++ // This is the last EXIDX entry in the sequence, so we don't ++ // have an address for the start of the next function, to limit ++ // this one. Instead use the address of the last byte of the ++ // text section associated with this .exidx section, that we ++ // have been given. So as to avoid junking up the CFI unwind ++ // tables with absurdly large address ranges in the case where ++ // text_last_svma_ is wrong, only use the value if it is nonzero ++ // and within one page of |addr|. Otherwise assume a length of 1. ++ // ++ // In some cases, gcc has been observed to finish the exidx ++ // section with an entry of length 1 marked CANT_UNWIND, ++ // presumably exactly for the purpose of giving a definite ++ // length for the last real entry, without having to look at ++ // text segment boundaries. ++ bool plausible = false; ++ next_addr = addr + 1; ++ if (text_last_svma_ != 0) { ++ uint32_t maybe_next_addr = text_last_svma_ + 1; ++ if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { ++ next_addr = maybe_next_addr; ++ plausible = true; ++ } ++ } ++ if (!plausible) { ++ fprintf(stderr, "ExceptionTableInfo: implausible EXIDX last entry size " ++ "%d, using 1 instead.", (int32_t)(text_last_svma_ - addr)); ++ } ++ } ++ ++ // Extract the unwind info into |buf|. This might fail for ++ // various reasons. It involves reading both the .exidx and ++ // .extab sections. All accesses to those sections are ++ // bounds-checked. ++ uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; ++ size_t buf_used = 0; ++ ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); ++ if (res != ExSuccess) { ++ // Couldn't extract the unwind info, for some reason. Move on. ++ switch (res) { ++ case ExInBufOverflow: ++ fprintf(stderr, "ExtabEntryExtract: .exidx/.extab section overrun"); ++ break; ++ case ExOutBufOverflow: ++ fprintf(stderr, "ExtabEntryExtract: bytecode buffer overflow"); ++ break; ++ case ExCantUnwind: ++ fprintf(stderr, "ExtabEntryExtract: function is marked CANT_UNWIND"); ++ break; ++ case ExCantRepresent: ++ fprintf(stderr, "ExtabEntryExtract: bytecode can't be represented"); ++ break; ++ case ExInvalid: ++ fprintf(stderr, "ExtabEntryExtract: index table entry is invalid"); ++ break; ++ default: ++ fprintf(stderr, "ExtabEntryExtract: unknown error: %d", (int)res); ++ break; ++ } ++ continue; ++ } ++ ++ // Finally, work through the unwind instructions in |buf| and ++ // create CFI entries that Breakpad can use. This can also fail. ++ // First, add a new stack frame entry, into which ExtabEntryDecode ++ // will write the CFI entries. ++ if (!handler_->HasStackFrame(addr, next_addr - addr)) { ++ handler_->AddStackFrame(addr, next_addr - addr); ++ int ret = ExtabEntryDecode(buf, buf_used); ++ if (ret < 0) { ++ handler_->DeleteStackFrame(); ++ fprintf(stderr, "ExtabEntryDecode: failed with error code: %d", ret); ++ continue; ++ } ++ handler_->SubmitStackFrame(); ++ } ++ ++ } /* iterating over .exidx */ ++} ++ ++} // namespace arm_ex_reader +diff --git a/src/common/arm_ex_reader.h b/src/common/arm_ex_reader.h +new file mode 100644 +index 00000000..9b54e8a0 +--- /dev/null ++++ b/src/common/arm_ex_reader.h +@@ -0,0 +1,114 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright 2011 Linaro Limited ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++// Copyright (c) 2010 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. ++ ++ ++// Derived from libunwind, with extensive modifications. ++ ++#ifndef COMMON_ARM_EX_READER_H__ ++#define COMMON_ARM_EX_READER_H__ ++ ++#include "common/arm_ex_to_module.h" ++#include "common/memory_range.h" ++ ++namespace arm_ex_reader { ++ ++// This class is a reader for ARM unwind information ++// from .ARM.exidx and .ARM.extab sections. ++class ExceptionTableInfo { ++ public: ++ ExceptionTableInfo(const char* exidx, size_t exidx_size, ++ const char* extab, size_t extab_size, ++ uint32_t text_last_svma, ++ arm_ex_to_module::ARMExToModule* handler, ++ const char* mapping_addr, ++ uint32_t loading_addr) ++ : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)), ++ mr_extab_(google_breakpad::MemoryRange(extab, extab_size)), ++ text_last_svma_(text_last_svma), ++ handler_(handler), mapping_addr_(mapping_addr), ++ loading_addr_(loading_addr) { } ++ ++ ~ExceptionTableInfo() { } ++ ++ // Parses the entries in .ARM.exidx and possibly ++ // in .ARM.extab tables, reports what we find to ++ // arm_ex_to_module::ARMExToModule. ++ void Start(); ++ ++ private: ++ google_breakpad::MemoryRange mr_exidx_; ++ google_breakpad::MemoryRange mr_extab_; ++ uint32_t text_last_svma_; ++ arm_ex_to_module::ARMExToModule* handler_; ++ const char* mapping_addr_; ++ uint32_t loading_addr_; ++ ++ enum ExExtractResult { ++ ExSuccess, // success ++ ExInBufOverflow, // out-of-range while reading .exidx ++ ExOutBufOverflow, // output buffer is too small ++ ExCantUnwind, // this function is marked CANT_UNWIND ++ ExCantRepresent, // entry valid, but we can't represent it ++ ExInvalid // entry is invalid ++ }; ++ ExExtractResult ++ ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry, ++ uint8_t* buf, size_t buf_size, ++ size_t* buf_used); ++ ++ int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); ++}; ++ ++} // namespace arm_ex_reader ++ ++#endif // COMMON_ARM_EX_READER_H__ +diff --git a/src/common/arm_ex_to_module.cc b/src/common/arm_ex_to_module.cc +new file mode 100644 +index 00000000..c326744f +--- /dev/null ++++ b/src/common/arm_ex_to_module.cc +@@ -0,0 +1,209 @@ ++ ++/* libunwind - a platform-independent unwind library ++ Copyright 2011 Linaro Limited ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++// Copyright (c) 2010 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. ++ ++ ++// Derived from libunwind, with extensive modifications. ++ ++#include "common/arm_ex_to_module.h" ++ ++#include ++#include ++ ++// For big-picture comments on how the EXIDX reader works, ++// see arm_ex_reader.cc. ++ ++#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) ++#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) ++#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) ++ ++using google_breakpad::Module; ++ ++namespace arm_ex_to_module { ++ ++static const char* const regnames[] = { ++ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", ++ "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", ++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", ++ "fps", "cpsr" ++}; ++ ++// Translate command from extab_data to command for Module. ++int ARMExToModule::TranslateCmd(const struct extab_data* edata, ++ Module::StackFrameEntry* entry, string& vsp) { ++ int ret = 0; ++ switch (edata->cmd) { ++ case ARM_EXIDX_CMD_FINISH: ++ /* Copy LR to PC if there isn't currently a rule for PC in force. */ ++ if (entry->initial_rules.find("pc") ++ == entry->initial_rules.end()) { ++ if (entry->initial_rules.find("lr") ++ == entry->initial_rules.end()) { ++ entry->initial_rules["pc"] = "lr"; ++ } else { ++ entry->initial_rules["pc"] = entry->initial_rules["lr"]; ++ } ++ } ++ break; ++ case ARM_EXIDX_CMD_SUB_FROM_VSP: ++ { ++ char c[16]; ++ sprintf(c, " %d -", edata->data); ++ vsp += c; ++ } ++ break; ++ case ARM_EXIDX_CMD_ADD_TO_VSP: ++ { ++ char c[16]; ++ sprintf(c, " %d +", edata->data); ++ vsp += c; ++ } ++ break; ++ case ARM_EXIDX_CMD_REG_POP: ++ for (unsigned int i = 0; i < 16; i++) { ++ if (edata->data & (1 << i)) { ++ entry->initial_rules[regnames[i]] ++ = vsp + " ^"; ++ vsp += " 4 +"; ++ } ++ } ++ /* Set cfa in case the SP got popped. */ ++ if (edata->data & (1 << 13)) { ++ vsp = entry->initial_rules["sp"]; ++ } ++ break; ++ case ARM_EXIDX_CMD_REG_TO_SP: { ++ assert (edata->data < 16); ++ const char* const regname = regnames[edata->data]; ++ if (entry->initial_rules.find(regname) == entry->initial_rules.end()) { ++ entry->initial_rules["sp"] = regname; ++ } else { ++ entry->initial_rules["sp"] = entry->initial_rules[regname]; ++ } ++ vsp = entry->initial_rules["sp"]; ++ break; ++ } ++ case ARM_EXIDX_CMD_VFP_POP: ++ /* Don't recover VFP registers, but be sure to adjust the stack ++ pointer. */ ++ for (unsigned int i = ARM_EXBUF_START(edata->data); ++ i <= ARM_EXBUF_END(edata->data); i++) { ++ vsp += " 8 +"; ++ } ++ if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { ++ vsp += " 4 +"; ++ } ++ break; ++ case ARM_EXIDX_CMD_WREG_POP: ++ for (unsigned int i = ARM_EXBUF_START(edata->data); ++ i <= ARM_EXBUF_END(edata->data); i++) { ++ vsp += " 8 +"; ++ } ++ break; ++ case ARM_EXIDX_CMD_WCGR_POP: ++ // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" ++ for (unsigned int i = 0; i < 4; i++) { ++ if (edata->data & (1 << i)) { ++ vsp += " 4 +"; ++ } ++ } ++ break; ++ case ARM_EXIDX_CMD_REFUSED: ++ case ARM_EXIDX_CMD_RESERVED: ++ ret = -1; ++ break; ++ } ++ return ret; ++} ++ ++bool ARMExToModule::HasStackFrame(uintptr_t addr, size_t size) { ++ // Invariant: the range [addr,covered) is covered by existing stack ++ // frame entries. ++ uintptr_t covered = addr; ++ while (covered < addr + size) { ++ const Module::StackFrameEntry *old_entry = ++ module_->FindStackFrameEntryByAddress(covered); ++ if (!old_entry) { ++ return false; ++ } ++ covered = old_entry->address + old_entry->size; ++ } ++ return true; ++} ++ ++void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { ++ stack_frame_entry_ = new Module::StackFrameEntry; ++ stack_frame_entry_->address = addr; ++ stack_frame_entry_->size = size; ++ stack_frame_entry_->initial_rules[".cfa"] = "sp"; ++ vsp_ = "sp"; ++} ++ ++int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { ++ return TranslateCmd(edata, stack_frame_entry_, vsp_) ; ++} ++ ++void ARMExToModule::DeleteStackFrame() { ++ delete stack_frame_entry_; ++} ++ ++void ARMExToModule::SubmitStackFrame() { ++ // return address always winds up in pc ++ stack_frame_entry_->initial_rules[".ra"] ++ = stack_frame_entry_->initial_rules["pc"]; ++ // the final value of vsp is the new value of sp ++ stack_frame_entry_->initial_rules["sp"] = vsp_; ++ module_->AddStackFrameEntry(stack_frame_entry_); ++} ++ ++} // namespace arm_ex_to_module +diff --git a/src/common/arm_ex_to_module.h b/src/common/arm_ex_to_module.h +new file mode 100644 +index 00000000..f413a16a +--- /dev/null ++++ b/src/common/arm_ex_to_module.h +@@ -0,0 +1,119 @@ ++/* libunwind - a platform-independent unwind library ++ Copyright 2011 Linaro Limited ++ ++This file is part of libunwind. ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++ ++// Copyright (c) 2010 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. ++ ++ ++// Derived from libunwind, with extensive modifications. ++ ++#ifndef COMMON_ARM_EX_TO_MODULE__ ++#define COMMON_ARM_EX_TO_MODULE__ ++ ++#include "common/module.h" ++ ++#include ++ ++namespace arm_ex_to_module { ++ ++using google_breakpad::Module; ++ ++typedef enum extab_cmd { ++ ARM_EXIDX_CMD_FINISH, ++ ARM_EXIDX_CMD_SUB_FROM_VSP, ++ ARM_EXIDX_CMD_ADD_TO_VSP, ++ ARM_EXIDX_CMD_REG_POP, ++ ARM_EXIDX_CMD_REG_TO_SP, ++ ARM_EXIDX_CMD_VFP_POP, ++ ARM_EXIDX_CMD_WREG_POP, ++ ARM_EXIDX_CMD_WCGR_POP, ++ ARM_EXIDX_CMD_RESERVED, ++ ARM_EXIDX_CMD_REFUSED, ++} extab_cmd_t; ++ ++struct exidx_entry { ++ uint32_t addr; ++ uint32_t data; ++}; ++ ++struct extab_data { ++ extab_cmd_t cmd; ++ uint32_t data; ++}; ++ ++enum extab_cmd_flags { ++ ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, ++ ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX ++}; ++ ++// Receives information from arm_ex_reader::ExceptionTableInfo ++// and adds it to the Module object ++class ARMExToModule { ++ public: ++ ARMExToModule(Module* module) ++ : module_(module) { } ++ ~ARMExToModule() { } ++ bool HasStackFrame(uintptr_t addr, size_t size); ++ void AddStackFrame(uintptr_t addr, size_t size); ++ int ImproveStackFrame(const struct extab_data* edata); ++ void DeleteStackFrame(); ++ void SubmitStackFrame(); ++ private: ++ Module* module_; ++ Module::StackFrameEntry* stack_frame_entry_; ++ string vsp_; ++ int TranslateCmd(const struct extab_data* edata, ++ Module::StackFrameEntry* entry, ++ string& vsp); ++}; ++ ++} // namespace arm_ex_to_module ++ ++#endif // COMMON_ARM_EX_TO_MODULE__ +diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc +index 0eea2b54..e398f7b3 100644 +--- a/src/common/linux/dump_symbols.cc ++++ b/src/common/linux/dump_symbols.cc +@@ -54,6 +54,7 @@ + #include + #include + ++#include "common/arm_ex_reader.h" + #include "common/dwarf/bytereader-inl.h" + #include "common/dwarf/dwarf2diehandler.h" + #include "common/dwarf_cfi_to_module.h" +@@ -76,6 +77,11 @@ + #endif + #include "common/using_std_string.h" + ++#ifndef SHT_ARM_EXIDX ++// bionic and older glibc don't define this ++# define SHT_ARM_EXIDX (SHT_LOPROC + 1) ++#endif ++ + // This namespace contains helper functions. + namespace { + +@@ -429,6 +435,52 @@ bool LoadDwarfCFI(const string& dwarf_filename, + return true; + } + ++template ++bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header, ++ const typename ElfClass::Shdr* exidx_section, ++ const typename ElfClass::Shdr* extab_section, ++ uint32_t loading_addr, ++ Module* module) { ++ // To do this properly we need to know: ++ // * the bounds of the .ARM.exidx section in the mapped image ++ // * the bounds of the .ARM.extab section in the mapped image ++ // * the vma of the last byte in the text section associated with the .exidx ++ // The first two are easy. The third is a bit tricky. If we can't ++ // figure out what it is, just pass in zero. ++ const char *exidx_img ++ = GetOffset(elf_header, exidx_section->sh_offset); ++ size_t exidx_size = exidx_section->sh_size; ++ const char *extab_img ++ = GetOffset(elf_header, extab_section->sh_offset); ++ size_t extab_size = extab_section->sh_size; ++ ++ // The sh_link field of the exidx section gives the section number ++ // for the associated text section. ++ uint32_t exidx_text_last_svma = 0; ++ int exidx_text_sno = exidx_section->sh_link; ++ typedef typename ElfClass::Shdr Shdr; ++ // |sections| points to the section header table ++ const Shdr* sections ++ = GetOffset(elf_header, elf_header->e_shoff); ++ const int num_sections = elf_header->e_shnum; ++ if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) { ++ const Shdr* exidx_text_shdr = §ions[exidx_text_sno]; ++ if (exidx_text_shdr->sh_size > 0) { ++ exidx_text_last_svma ++ = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1; ++ } ++ } ++ ++ arm_ex_to_module::ARMExToModule handler(module); ++ arm_ex_reader::ExceptionTableInfo ++ parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma, ++ &handler, ++ reinterpret_cast(elf_header), ++ loading_addr); ++ parser.Start(); ++ return true; ++} ++ + bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, + void** elf_header) { + int obj_fd = open(obj_file.c_str(), O_RDONLY); +@@ -846,6 +898,29 @@ bool LoadSymbols(const string& obj_file, + } + } + ++ // ARM has special unwind tables that can be used. ++ const Shdr* arm_exidx_section = ++ FindElfSectionByName(".ARM.exidx", SHT_ARM_EXIDX, ++ sections, names, names_end, ++ elf_header->e_shnum); ++ const Shdr* arm_extab_section = ++ FindElfSectionByName(".ARM.extab", SHT_PROGBITS, ++ sections, names, names_end, ++ elf_header->e_shnum); ++ // Load information from these sections even if there is ++ // .debug_info, because some functions (e.g., hand-written or ++ // script-generated assembly) could have exidx entries but no DWARF. ++ // (For functions with both, the DWARF info that has already been ++ // parsed will take precedence.) ++ if (arm_exidx_section && arm_extab_section && options.symbol_data != NO_CFI) { ++ info->LoadedSection(".ARM.exidx"); ++ info->LoadedSection(".ARM.extab"); ++ bool result = LoadARMexidx(elf_header, ++ arm_exidx_section, arm_extab_section, ++ loading_addr, module); ++ found_usable_info = found_usable_info || result; ++ } ++ + if (!found_debug_info_section) { + fprintf(stderr, "%s: file contains no debugging information" + " (no \".stab\" or \".debug_info\" sections)\n", +diff --git a/src/common/module.cc b/src/common/module.cc +index aff22127..a3544029 100644 +--- a/src/common/module.cc ++++ b/src/common/module.cc +@@ -64,7 +64,7 @@ Module::~Module() { + it != functions_.end(); ++it) { + delete *it; + } +- for (vector::iterator it = stack_frame_entries_.begin(); ++ for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); + it != stack_frame_entries_.end(); ++it) { + delete *it; + } +@@ -130,12 +130,18 @@ void Module::AddFunctions(vector::iterator begin, + AddFunction(*it); + } + +-void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) { ++void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { + if (!AddressIsInModule(stack_frame_entry->address)) { + return; + } + +- stack_frame_entries_.push_back(stack_frame_entry); ++ std::pair ret = ++ stack_frame_entries_.insert(stack_frame_entry); ++ if (!ret.second) { ++ // Free the duplicate that was not inserted because this Module ++ // now owns it. ++ delete stack_frame_entry; ++ } + } + + void Module::AddExtern(Extern *ext) { +@@ -199,8 +205,25 @@ void Module::GetFiles(vector *vec) { + vec->push_back(it->second); + } + +-void Module::GetStackFrameEntries(vector *vec) const { +- *vec = stack_frame_entries_; ++void Module::GetStackFrameEntries(vector* vec) const { ++ vec->clear(); ++ vec->insert(vec->begin(), stack_frame_entries_.begin(), ++ stack_frame_entries_.end()); ++} ++ ++Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { ++ StackFrameEntry search; ++ search.address = address; ++ StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); ++ ++ if (it == stack_frame_entries_.begin()) ++ return NULL; ++ ++ it--; ++ if ((*it)->address <= address && address < (*it)->address + (*it)->size) ++ return *it; ++ ++ return NULL; + } + + void Module::AssignSourceIds() { +@@ -331,7 +354,7 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) { + + if (symbol_data != NO_CFI) { + // Write out 'STACK CFI INIT' and 'STACK CFI' records. +- vector::const_iterator frame_it; ++ StackFrameEntrySet::const_iterator frame_it; + for (frame_it = stack_frame_entries_.begin(); + frame_it != stack_frame_entries_.end(); ++frame_it) { + StackFrameEntry *entry = *frame_it; +diff --git a/src/common/module.h b/src/common/module.h +index 7309cedd..37758605 100644 +--- a/src/common/module.h ++++ b/src/common/module.h +@@ -185,6 +185,13 @@ class Module { + } + }; + ++ struct StackFrameEntryCompare { ++ bool operator() (const StackFrameEntry* lhs, ++ const StackFrameEntry* rhs) const { ++ return lhs->address < rhs->address; ++ } ++ }; ++ + // Create a new module with the given name, operating system, + // architecture, and ID string. + Module(const string &name, const string &os, const string &architecture, +@@ -273,6 +280,10 @@ class Module { + // a more appropriate interface.) + void GetStackFrameEntries(vector *vec) const; + ++ // If this module has a StackFrameEntry whose address range covers ++ // ADDRESS, return it. Otherwise return NULL. ++ StackFrameEntry* FindStackFrameEntryByAddress(Address address); ++ + // Find those files in this module that are actually referred to by + // functions' line number data, and assign them source id numbers. + // Set the source id numbers for all other files --- unused by the +@@ -342,6 +353,9 @@ class Module { + // A set containing Extern structures, sorted by address. + typedef set ExternSet; + ++ // A set containing StackFrameEntry structures, sorted by address. ++ typedef set StackFrameEntrySet; ++ + // The module owns all the files and functions that have been added + // to it; destroying the module frees the Files and Functions these + // point to. +@@ -350,7 +364,7 @@ class Module { + + // The module owns all the call frame info entries that have been + // added to it. +- vector stack_frame_entries_; ++ StackFrameEntrySet stack_frame_entries_; + + // The module owns all the externs that have been added to it; + // destroying the module frees the Externs these point to. +diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc +index 37fee5dd..b855f186 100644 +--- a/src/common/module_unittest.cc ++++ b/src/common/module_unittest.cc +@@ -344,11 +344,6 @@ TEST(Construct, AddFrames) { + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" +- "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" +- "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" +- " .cfa: I think that I shall never see" +- " cannoli: a tree whose hungry mouth is prest" +- " stromboli: a poem lovely as a tree\n" + "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" + " .cfa: Whose woods are these\n" + "STACK CFI 36682fad3763ffff" +@@ -356,7 +351,12 @@ TEST(Construct, AddFrames) { + " stromboli: his house is in\n" + "STACK CFI 47ceb0f63c269d7f" + " calzone: the village though" +- " cannoli: he will not see me stopping here\n", ++ " cannoli: he will not see me stopping here\n" ++ "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" ++ " .cfa: I think that I shall never see" ++ " cannoli: a tree whose hungry mouth is prest" ++ " stromboli: a poem lovely as a tree\n" ++ "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", + contents.c_str()); + + // Check that GetStackFrameEntries works. +@@ -364,10 +364,18 @@ TEST(Construct, AddFrames) { + m.GetStackFrameEntries(&entries); + ASSERT_EQ(3U, entries.size()); + // Check first entry. +- EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address); +- EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size); +- ASSERT_EQ(0U, entries[0]->initial_rules.size()); +- ASSERT_EQ(0U, entries[0]->rule_changes.size()); ++ EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); ++ EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); ++ Module::RuleMap entry1_initial; ++ entry1_initial[".cfa"] = "Whose woods are these"; ++ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); ++ Module::RuleChangeMap entry1_changes; ++ entry1_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; ++ entry1_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; ++ entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; ++ entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = ++ "he will not see me stopping here"; ++ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); + // Check second entry. + EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); + EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); +@@ -379,18 +387,10 @@ TEST(Construct, AddFrames) { + EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); + ASSERT_EQ(0U, entries[1]->rule_changes.size()); + // Check third entry. +- EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address); +- EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size); +- Module::RuleMap entry3_initial; +- entry3_initial[".cfa"] = "Whose woods are these"; +- EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial)); +- Module::RuleChangeMap entry3_changes; +- entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; +- entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; +- entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; +- entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] = +- "he will not see me stopping here"; +- EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes)); ++ EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); ++ EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); ++ ASSERT_EQ(0U, entries[2]->initial_rules.size()); ++ ASSERT_EQ(0U, entries[2]->rule_changes.size()); + } + + TEST(Construct, UniqueFiles) { +@@ -612,5 +612,63 @@ TEST(Write, OutOfRangeAddresses) { + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "STACK CFI INIT 2000 100 \n", + s.str().c_str()); ++} ++ ++TEST(Lookup, StackFrameEntries) { ++ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); ++ ++ // First STACK CFI entry, with no initial rules or deltas. ++ Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); ++ entry1->address = 0x2000; ++ entry1->size = 0x900; ++ m.AddStackFrameEntry(entry1); ++ ++ // Second STACK CFI entry, with initial rules but no deltas. ++ Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); ++ entry2->address = 0x3000; ++ entry2->size = 0x900; ++ entry2->initial_rules[".cfa"] = "I think that I shall never see"; ++ entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; ++ entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; ++ m.AddStackFrameEntry(entry2); ++ ++ // Third STACK CFI entry, with initial rules and deltas. ++ Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); ++ entry3->address = 0x1000; ++ entry3->size = 0x900; ++ entry3->initial_rules[".cfa"] = "Whose woods are these"; ++ entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = ++ "the village though"; ++ entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = ++ "he will not see me stopping here"; ++ entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = ++ "his house is in"; ++ entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = ++ "I think I know"; ++ m.AddStackFrameEntry(entry3); + ++ Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); ++ EXPECT_EQ(entry3, s); ++ s = m.FindStackFrameEntryByAddress(0x18FF); ++ EXPECT_EQ(entry3, s); ++ ++ s = m.FindStackFrameEntryByAddress(0x1900); ++ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); ++ s = m.FindStackFrameEntryByAddress(0x1A00); ++ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); ++ ++ s = m.FindStackFrameEntryByAddress(0x2000); ++ EXPECT_EQ(entry1, s); ++ s = m.FindStackFrameEntryByAddress(0x28FF); ++ EXPECT_EQ(entry1, s); ++ ++ s = m.FindStackFrameEntryByAddress(0x3000); ++ EXPECT_EQ(entry2, s); ++ s = m.FindStackFrameEntryByAddress(0x38FF); ++ EXPECT_EQ(entry2, s); ++ ++ s = m.FindStackFrameEntryByAddress(0x3900); ++ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); ++ s = m.FindStackFrameEntryByAddress(0x3A00); ++ EXPECT_EQ((Module::StackFrameEntry*)NULL, s); + } diff --git a/toolkit/crashreporter/breakpad-patches/02-define-print-mach-result.patch b/toolkit/crashreporter/breakpad-patches/02-define-print-mach-result.patch new file mode 100644 index 0000000000..933659120d --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/02-define-print-mach-result.patch @@ -0,0 +1,24 @@ +diff --git a/src/common/mac/MachIPC.h b/src/common/mac/MachIPC.h +--- a/src/common/mac/MachIPC.h ++++ b/src/common/mac/MachIPC.h +@@ -90,18 +90,20 @@ + // + // char messageString[] = "Hello server!\n"; + // message.SetData(messageString, strlen(messageString)+1); + // + // kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms + // + + namespace google_breakpad { ++#ifndef PRINT_MACH_RESULT + #define PRINT_MACH_RESULT(result_, message_) \ + printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); ++#endif + + //============================================================================== + // A wrapper class for mach_msg_port_descriptor_t (with same memory layout) + // with convenient constructors and accessors + class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { + public: + // General-purpose constructor + MachMsgPortDescriptor(mach_port_t in_name, diff --git a/toolkit/crashreporter/breakpad-patches/03-strstr-libc-replacement.patch b/toolkit/crashreporter/breakpad-patches/03-strstr-libc-replacement.patch new file mode 100644 index 0000000000..17006a91d9 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/03-strstr-libc-replacement.patch @@ -0,0 +1,54 @@ +diff --git a/src/common/linux/linux_libc_support.cc b/src/common/linux/linux_libc_support.cc +--- a/src/common/linux/linux_libc_support.cc ++++ b/src/common/linux/linux_libc_support.cc +@@ -133,16 +133,27 @@ const char* my_strrchr(const char* hayst + while (*haystack) { + if (*haystack == needle) + ret = haystack; + haystack++; + } + return ret; + } + ++const char* my_strstr(const char* haystack, const char* needle) { ++ while (*haystack != 0) { ++ if((*haystack == *needle) && ++ (my_strncmp(haystack, needle, my_strlen(needle)) == 0)) { ++ return haystack; ++ } ++ haystack++; ++ } ++ return nullptr; ++} ++ + void* my_memchr(const void* src, int needle, size_t src_len) { + const unsigned char* p = (const unsigned char*)src; + const unsigned char* p_end = p + src_len; + for (; p < p_end; ++p) { + if (*p == needle) + return (void*)p; + } + return NULL; +diff --git a/src/common/linux/linux_libc_support.h b/src/common/linux/linux_libc_support.h +--- a/src/common/linux/linux_libc_support.h ++++ b/src/common/linux/linux_libc_support.h +@@ -62,16 +62,18 @@ extern unsigned my_uint_len(uintmax_t i) + // i: the unsigned integer to serialise. + // i_len: the length of the integer in base 10 (see |my_uint_len|). + extern void my_uitos(char* output, uintmax_t i, unsigned i_len); + + extern const char* my_strchr(const char* haystack, char needle); + + extern const char* my_strrchr(const char* haystack, char needle); + ++extern const char *my_strstr(const char *haystack, const char *needle); ++ + // Read a hex value + // result: (output) the resulting value + // s: a string + // Returns a pointer to the first invalid charactor. + extern const char* my_read_hex_ptr(uintptr_t* result, const char* s); + + extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s); + + diff --git a/toolkit/crashreporter/breakpad-patches/04-update-headers.patch b/toolkit/crashreporter/breakpad-patches/04-update-headers.patch new file mode 100644 index 0000000000..4baa27be90 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/04-update-headers.patch @@ -0,0 +1,6039 @@ +diff --git a/src/third_party/curl/COPYING b/src/third_party/curl/COPYING +--- a/src/third_party/curl/COPYING ++++ b/src/third_party/curl/COPYING +@@ -1,11 +1,12 @@ + COPYRIGHT AND PERMISSION NOTICE + +-Copyright (c) 1996 - 2011, Daniel Stenberg, . ++Copyright (c) 1996 - 2019, Daniel Stenberg, , and many ++contributors, see the THANKS file. + + All rights reserved. + + Permission to use, copy, modify, and distribute this software for any purpose + with or without fee is hereby granted, provided that the above copyright + notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +@@ -14,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE AND NON + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE + OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of a copyright holder shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization of the copyright holder. +- +diff --git a/src/third_party/curl/curl.h b/src/third_party/curl/curl.h +--- a/src/third_party/curl/curl.h ++++ b/src/third_party/curl/curl.h +@@ -2,234 +2,402 @@ + #define __CURL_CURL_H + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * +- * $Id: curl.h,v 1.396 2009-10-16 13:30:31 yangtse Exp $ + ***************************************************************************/ + + /* + * If you have libcurl problems, all docs and details are found here: +- * http://curl.haxx.se/libcurl/ ++ * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: +- * http://cool.haxx.se/mailman/listinfo/curl-library/ ++ * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +-/* +- * Leading 'curl' path on the 'curlbuild.h' include statement is +- * required to properly allow building outside of the source tree, +- * due to the fact that in this case 'curlbuild.h' is generated in +- * a subdirectory of the build tree while 'curl.h actually remains +- * in a subdirectory of the source tree. +- */ +- +-#include "third_party/curl/curlver.h" /* libcurl version defines */ +-#include "third_party/curl/curlbuild.h" /* libcurl build definitions */ +-#include "third_party/curl/curlrules.h" /* libcurl rules enforcement */ ++#ifdef CURL_NO_OLDIES ++#define CURL_STRICTER ++#endif ++ ++#include "curlver.h" /* libcurl version defines */ ++#include "system.h" /* determine things run-time */ + + /* + * Define WIN32 when build target is Win32 API + */ + + #if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) + #define WIN32 + #endif + + #include + #include + ++#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) ++/* Needed for __FreeBSD_version symbol definition */ ++#include ++#endif ++ + /* The include stuff here below is mainly for time_t! */ + #include + #include + +-#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ +- !defined(__CYGWIN__) || defined(__MINGW32__) +-#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) ++#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) ++#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ ++ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) + /* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ + #include + #include + #endif +-#else ++#endif + + /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish +- libc5-based Linux systems. Only include it on system that are known to ++ libc5-based Linux systems. Only include it on systems that are known to + require it! */ + #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ +- defined(__ANDROID__) ++ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ ++ defined(__CYGWIN__) || \ ++ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) + #include + #endif + +-#ifndef _WIN32_WCE ++#if !defined(WIN32) && !defined(_WIN32_WCE) + #include + #endif ++ + #if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) + #include + #endif +-#include +-#endif + + #ifdef __BEOS__ + #include + #endif + ++/* Compatibility for non-Clang compilers */ ++#ifndef __has_declspec_attribute ++# define __has_declspec_attribute(x) 0 ++#endif ++ + #ifdef __cplusplus + extern "C" { + #endif + ++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) ++typedef struct Curl_easy CURL; ++typedef struct Curl_share CURLSH; ++#else + typedef void CURL; ++typedef void CURLSH; ++#endif + + /* +- * Decorate exportable functions for Win32 and Symbian OS DLL linking. +- * This avoids using a .def file for building libcurl.dll. ++ * libcurl external API function linkage decorations. + */ +-#if (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) && \ +- !defined(CURL_STATICLIB) +-#if defined(BUILDING_LIBCURL) +-#define CURL_EXTERN __declspec(dllexport) +-#else +-#define CURL_EXTERN __declspec(dllimport) +-#endif ++ ++#ifdef CURL_STATICLIB ++# define CURL_EXTERN ++#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) || \ ++ (__has_declspec_attribute(dllexport) && \ ++ __has_declspec_attribute(dllimport)) ++# if defined(BUILDING_LIBCURL) ++# define CURL_EXTERN __declspec(dllexport) ++# else ++# define CURL_EXTERN __declspec(dllimport) ++# endif ++#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) ++# define CURL_EXTERN CURL_EXTERN_SYMBOL + #else +- +-#ifdef CURL_HIDDEN_SYMBOLS +-/* +- * This definition is used to make external definitions visible in the +- * shared library when symbols are hidden by default. It makes no +- * difference when compiling applications whether this is set or not, +- * only when compiling the library. +- */ +-#define CURL_EXTERN CURL_EXTERN_SYMBOL +-#else +-#define CURL_EXTERN +-#endif ++# define CURL_EXTERN + #endif + + #ifndef curl_socket_typedef + /* socket typedef */ +-#ifdef WIN32 ++#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) + typedef SOCKET curl_socket_t; + #define CURL_SOCKET_BAD INVALID_SOCKET + #else + typedef int curl_socket_t; + #define CURL_SOCKET_BAD -1 + #endif + #define curl_socket_typedef + #endif /* curl_socket_typedef */ + ++/* enum for the different supported SSL backends */ ++typedef enum { ++ CURLSSLBACKEND_NONE = 0, ++ CURLSSLBACKEND_OPENSSL = 1, ++ CURLSSLBACKEND_GNUTLS = 2, ++ CURLSSLBACKEND_NSS = 3, ++ CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ ++ CURLSSLBACKEND_GSKIT = 5, ++ CURLSSLBACKEND_POLARSSL = 6, ++ CURLSSLBACKEND_WOLFSSL = 7, ++ CURLSSLBACKEND_SCHANNEL = 8, ++ CURLSSLBACKEND_SECURETRANSPORT = 9, ++ CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ ++ CURLSSLBACKEND_MBEDTLS = 11, ++ CURLSSLBACKEND_MESALINK = 12 ++} curl_sslbackend; ++ ++/* aliases for library clones and renames */ ++#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL ++#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL ++ ++/* deprecated names: */ ++#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL ++#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT ++ + struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ +- long contentslength; /* length of contents field */ ++ long contentslength; /* length of contents field, see also ++ CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ +- struct curl_slist* contentheader; /* list of extra headers for this form */ ++ struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ +-#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ +-#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ +-#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer +- do not free in formfree */ +-#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer +- do not free in formfree */ +-#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ +-#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ +-#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the +- regular read callback to get the data +- and pass the given pointer as custom +- pointer */ ++ ++/* specified content is a file name */ ++#define CURL_HTTPPOST_FILENAME (1<<0) ++/* specified content is a file name */ ++#define CURL_HTTPPOST_READFILE (1<<1) ++/* name is only stored pointer do not free in formfree */ ++#define CURL_HTTPPOST_PTRNAME (1<<2) ++/* contents is only stored pointer do not free in formfree */ ++#define CURL_HTTPPOST_PTRCONTENTS (1<<3) ++/* upload file from buffer */ ++#define CURL_HTTPPOST_BUFFER (1<<4) ++/* upload file from pointer contents */ ++#define CURL_HTTPPOST_PTRBUFFER (1<<5) ++/* upload file contents by using the regular read callback to get the data and ++ pass the given pointer as custom pointer */ ++#define CURL_HTTPPOST_CALLBACK (1<<6) ++/* use size in 'contentlen', added in 7.46.0 */ ++#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ ++ curl_off_t contentlen; /* alternative length of contents ++ field. Used if CURL_HTTPPOST_LARGE is ++ set. Added in 7.46.0 */ + }; + ++/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered ++ deprecated but was the only choice up until 7.31.0 */ + typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + ++/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in ++ 7.32.0, it avoids floating point and provides more detailed information. */ ++typedef int (*curl_xferinfo_callback)(void *clientp, ++ curl_off_t dltotal, ++ curl_off_t dlnow, ++ curl_off_t ultotal, ++ curl_off_t ulnow); ++ ++#ifndef CURL_MAX_READ_SIZE ++ /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ ++#define CURL_MAX_READ_SIZE 524288 ++#endif ++ + #ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build +- time for those who feel adventurous. */ ++ time for those who feel adventurous. The practical minimum is about ++ 400 bytes since libcurl uses a buffer of this size as a scratch area ++ (unrelated to network send operations). */ + #define CURL_MAX_WRITE_SIZE 16384 + #endif + + #ifndef CURL_MAX_HTTP_HEADER + /* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ + #define CURL_MAX_HTTP_HEADER (100*1024) + #endif + +- + /* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ + #define CURL_WRITEFUNC_PAUSE 0x10000001 ++ + typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + ++/* This callback will be called when a new resolver request is made */ ++typedef int (*curl_resolver_start_callback)(void *resolver_state, ++ void *reserved, void *userdata); ++ ++/* enumeration of file types */ ++typedef enum { ++ CURLFILETYPE_FILE = 0, ++ CURLFILETYPE_DIRECTORY, ++ CURLFILETYPE_SYMLINK, ++ CURLFILETYPE_DEVICE_BLOCK, ++ CURLFILETYPE_DEVICE_CHAR, ++ CURLFILETYPE_NAMEDPIPE, ++ CURLFILETYPE_SOCKET, ++ CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ ++ ++ CURLFILETYPE_UNKNOWN /* should never occur */ ++} curlfiletype; ++ ++#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) ++#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) ++#define CURLFINFOFLAG_KNOWN_TIME (1<<2) ++#define CURLFINFOFLAG_KNOWN_PERM (1<<3) ++#define CURLFINFOFLAG_KNOWN_UID (1<<4) ++#define CURLFINFOFLAG_KNOWN_GID (1<<5) ++#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) ++#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) ++ ++/* Content of this structure depends on information which is known and is ++ achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man ++ page for callbacks returning this structure -- some fields are mandatory, ++ some others are optional. The FLAG field has special meaning. */ ++struct curl_fileinfo { ++ char *filename; ++ curlfiletype filetype; ++ time_t time; ++ unsigned int perm; ++ int uid; ++ int gid; ++ curl_off_t size; ++ long int hardlinks; ++ ++ struct { ++ /* If some of these fields is not NULL, it is a pointer to b_data. */ ++ char *time; ++ char *perm; ++ char *user; ++ char *group; ++ char *target; /* pointer to the target filename of a symlink */ ++ } strings; ++ ++ unsigned int flags; ++ ++ /* used internally */ ++ char *b_data; ++ size_t b_size; ++ size_t b_used; ++}; ++ ++/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ ++#define CURL_CHUNK_BGN_FUNC_OK 0 ++#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ ++#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ ++ ++/* if splitting of data transfer is enabled, this callback is called before ++ download of an individual chunk started. Note that parameter "remains" works ++ only for FTP wildcard downloading (for now), otherwise is not used */ ++typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, ++ void *ptr, ++ int remains); ++ ++/* return codes for CURLOPT_CHUNK_END_FUNCTION */ ++#define CURL_CHUNK_END_FUNC_OK 0 ++#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ ++ ++/* If splitting of data transfer is enabled this callback is called after ++ download of an individual chunk finished. ++ Note! After this callback was set then it have to be called FOR ALL chunks. ++ Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. ++ This is the reason why we don't need "transfer_info" parameter in this ++ callback and we are not interested in "remains" parameter too. */ ++typedef long (*curl_chunk_end_callback)(void *ptr); ++ ++/* return codes for FNMATCHFUNCTION */ ++#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ ++#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ ++#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ ++ ++/* callback type for wildcard downloading pattern matching. If the ++ string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ ++typedef int (*curl_fnmatch_callback)(void *ptr, ++ const char *pattern, ++ const char *string); ++ + /* These are the return codes for the seek callbacks */ + #define CURL_SEEKFUNC_OK 0 + #define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ + #define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ + typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + + /* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ + #define CURL_READFUNC_ABORT 0x10000000 + /* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ + #define CURL_READFUNC_PAUSE 0x10000001 + ++/* Return code for when the trailing headers' callback has terminated ++ without any errors*/ ++#define CURL_TRAILERFUNC_OK 0 ++/* Return code for when was an error in the trailing header's list and we ++ want to abort the request */ ++#define CURL_TRAILERFUNC_ABORT 1 ++ + typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +-typedef enum { +- CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ +- CURLSOCKTYPE_LAST /* never use */ ++typedef int (*curl_trailer_callback)(struct curl_slist **list, ++ void *userdata); ++ ++typedef enum { ++ CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ ++ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ ++ CURLSOCKTYPE_LAST /* never use */ + } curlsocktype; + ++/* The return code from the sockopt_callback can signal information back ++ to libcurl: */ ++#define CURL_SOCKOPT_OK 0 ++#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return ++ CURLE_ABORTED_BY_CALLBACK */ ++#define CURL_SOCKOPT_ALREADY_CONNECTED 2 ++ + typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + + struct curl_sockaddr { + int family; + int socktype; + int protocol; +@@ -239,53 +407,52 @@ struct curl_sockaddr { + struct sockaddr addr; + }; + + typedef curl_socket_t + (*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +-#ifndef CURL_NO_OLDIES +- /* not used since 7.10.8, will be removed in a future release */ +-typedef int (*curl_passwd_callback)(void *clientp, +- const char *prompt, +- char *buffer, +- int buflen); +-#endif ++typedef int ++(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + + typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ + } curlioerr; + +-typedef enum { ++typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ + } curliocmd; + + typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + ++#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS + /* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ + typedef void *(*curl_malloc_callback)(size_t size); + typedef void (*curl_free_callback)(void *ptr); + typedef void *(*curl_realloc_callback)(void *ptr, size_t size); + typedef char *(*curl_strdup_callback)(const char *str); + typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + ++#define CURL_DID_MEMORY_FUNC_TYPEDEFS ++#endif ++ + /* the kind of data that is passed to information_callback*/ + typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ +@@ -307,31 +474,37 @@ typedef int (*curl_debug_callback) + codes must remain the same! + */ + + typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ +- CURLE_OBSOLETE4, /* 4 - NOT USED */ ++ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for ++ 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ +- CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ ++ CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ +- CURLE_OBSOLETE10, /* 10 - NOT USED */ ++ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for ++ 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ +- CURLE_OBSOLETE12, /* 12 - NOT USED */ ++ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server ++ [was obsoleted in August 2007 for 7.17.0, ++ reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ +- CURLE_OBSOLETE16, /* 16 - NOT USED */ ++ CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. ++ [was obsoleted in August 2007 for 7.17.0, ++ reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ +@@ -350,39 +523,39 @@ typedef enum { + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ +- CURLE_FUNCTION_NOT_FOUND, /* 41 */ ++ CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ +- CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ +- CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */ +- CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ ++ CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ ++ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ ++ CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ +- CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint +- wasn't verified fine */ ++ CURLE_OBSOLETE51, /* 51 - NOT USED */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ +- CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ +- CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */ ++ CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint ++ wasn't verified fine */ ++ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ +@@ -410,43 +583,72 @@ typedef enum { + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ ++ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ ++ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ ++ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ ++ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ ++ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ ++ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the ++ session will be queued */ ++ CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not ++ match */ ++ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ ++ CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer ++ */ ++ CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from ++ inside a callback */ + CURL_LAST /* never use! */ + } CURLcode; + + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +-/* Backwards compatibility with older names */ ++/* Previously obsolete error code re-used in 7.38.0 */ ++#define CURLE_OBSOLETE16 CURLE_HTTP2 ++ ++/* Previously obsolete error codes re-used in 7.24.0 */ ++#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED ++#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT ++ ++/* compatibility with older names */ ++#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING ++#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY ++ ++/* The following were added in 7.62.0 */ ++#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION ++ ++/* The following were added in 7.21.5, April 2011 */ ++#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + + /* The following were added in 7.17.1 */ + /* These are scheduled to disappear by 2009 */ + #define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + + /* The following were added in 7.17.0 */ + /* These are scheduled to disappear by 2009 */ +-#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* noone should be using this! */ ++#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ + #define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 + #define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 + #define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 + #define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 + #define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 + #define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 + #define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 + #define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 + #define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 + #define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 + #define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +-#define CURLE_URL_MALFORMAT_USER CURLE_OBSOLETE4 ++#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + + #define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED + #define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE + #define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR + #define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL + #define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS + #define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR + #define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED +@@ -462,69 +664,115 @@ typedef enum { + #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE + #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + + /* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ + #define CURLE_ALREADY_COMPLETE 99999 + ++/* Provide defines for really old option names */ ++#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ ++#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ ++#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA ++ ++/* Since long deprecated options with no code in the lib that does anything ++ with them. */ ++#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 ++#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 ++ + #endif /*!CURL_NO_OLDIES*/ + + /* This prototype applies to all conversion callbacks */ + typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + + typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + + typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ ++ CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ + } curl_proxytype; /* this enum was added in 7.10 */ + +-#define CURLAUTH_NONE 0 /* nothing */ +-#define CURLAUTH_BASIC (1<<0) /* Basic (default) */ +-#define CURLAUTH_DIGEST (1<<1) /* Digest */ +-#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ +-#define CURLAUTH_NTLM (1<<3) /* NTLM */ +-#define CURLAUTH_DIGEST_IE (1<<4) /* Digest with IE flavour */ +-#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) /* all fine types set */ +-#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) ++/* ++ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: ++ * ++ * CURLAUTH_NONE - No HTTP authentication ++ * CURLAUTH_BASIC - HTTP Basic authentication (default) ++ * CURLAUTH_DIGEST - HTTP Digest authentication ++ * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication ++ * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) ++ * CURLAUTH_NTLM - HTTP NTLM authentication ++ * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour ++ * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper ++ * CURLAUTH_BEARER - HTTP Bearer token authentication ++ * CURLAUTH_ONLY - Use together with a single other type to force no ++ * authentication or just that single type ++ * CURLAUTH_ANY - All fine types set ++ * CURLAUTH_ANYSAFE - All fine types except Basic ++ */ ++ ++#define CURLAUTH_NONE ((unsigned long)0) ++#define CURLAUTH_BASIC (((unsigned long)1)<<0) ++#define CURLAUTH_DIGEST (((unsigned long)1)<<1) ++#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) ++/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ ++#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE ++/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ ++#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE ++#define CURLAUTH_NTLM (((unsigned long)1)<<3) ++#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) ++#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) ++#define CURLAUTH_BEARER (((unsigned long)1)<<6) ++#define CURLAUTH_ONLY (((unsigned long)1)<<31) ++#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) ++#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + + #define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ + #define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ + #define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ + #define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ + #define CURLSSH_AUTH_HOST (1<<2) /* host key files */ + #define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ ++#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ ++#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ + #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + ++#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ ++#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ ++#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ ++ + #define CURL_ERROR_SIZE 256 + ++enum curl_khtype { ++ CURLKHTYPE_UNKNOWN, ++ CURLKHTYPE_RSA1, ++ CURLKHTYPE_RSA, ++ CURLKHTYPE_DSS, ++ CURLKHTYPE_ECDSA, ++ CURLKHTYPE_ED25519 ++}; ++ + struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; +- enum type { +- CURLKHTYPE_UNKNOWN, +- CURLKHTYPE_RSA1, +- CURLKHTYPE_RSA, +- CURLKHTYPE_DSS +- } keytype; ++ enum curl_khtype keytype; + }; + + /* this is the set of return values expected from the curl_sshkeycallback + callback */ + enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ +@@ -553,16 +801,37 @@ typedef int + typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ + } curl_usessl; + ++/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ ++ ++/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the ++ name of improving interoperability with older servers. Some SSL libraries ++ have introduced work-arounds for this flaw but those work-arounds sometimes ++ make the SSL communication fail. To regain functionality with those broken ++ servers, a user can this way allow the vulnerability back. */ ++#define CURLSSLOPT_ALLOW_BEAST (1<<0) ++ ++/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those ++ SSL backends where such behavior is present. */ ++#define CURLSSLOPT_NO_REVOKE (1<<1) ++ ++/* The default connection attempt delay in milliseconds for happy eyeballs. ++ CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document ++ this value, keep them in sync. */ ++#define CURL_HET_DEFAULT 200L ++ ++/* The default connection upkeep interval in milliseconds. */ ++#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L ++ + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + + /* Backwards compatibility with older names */ + /* These are scheduled to disappear by 2009 */ + + #define CURLFTPSSL_NONE CURLUSESSL_NONE + #define CURLFTPSSL_TRY CURLUSESSL_TRY +@@ -603,91 +872,124 @@ typedef enum { + typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ + } curl_ftpmethod; + ++/* bitmask defines for CURLOPT_HEADEROPT */ ++#define CURLHEADER_UNIFIED 0 ++#define CURLHEADER_SEPARATE (1<<0) ++ ++/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ ++#define CURLALTSVC_IMMEDIATELY (1<<0) ++#define CURLALTSVC_ALTUSED (1<<1) ++#define CURLALTSVC_READONLYFILE (1<<2) ++#define CURLALTSVC_H1 (1<<3) ++#define CURLALTSVC_H2 (1<<4) ++#define CURLALTSVC_H3 (1<<5) ++ + /* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ + #define CURLPROTO_HTTP (1<<0) + #define CURLPROTO_HTTPS (1<<1) + #define CURLPROTO_FTP (1<<2) + #define CURLPROTO_FTPS (1<<3) + #define CURLPROTO_SCP (1<<4) + #define CURLPROTO_SFTP (1<<5) + #define CURLPROTO_TELNET (1<<6) + #define CURLPROTO_LDAP (1<<7) + #define CURLPROTO_LDAPS (1<<8) + #define CURLPROTO_DICT (1<<9) + #define CURLPROTO_FILE (1<<10) + #define CURLPROTO_TFTP (1<<11) ++#define CURLPROTO_IMAP (1<<12) ++#define CURLPROTO_IMAPS (1<<13) ++#define CURLPROTO_POP3 (1<<14) ++#define CURLPROTO_POP3S (1<<15) ++#define CURLPROTO_SMTP (1<<16) ++#define CURLPROTO_SMTPS (1<<17) ++#define CURLPROTO_RTSP (1<<18) ++#define CURLPROTO_RTMP (1<<19) ++#define CURLPROTO_RTMPT (1<<20) ++#define CURLPROTO_RTMPE (1<<21) ++#define CURLPROTO_RTMPTE (1<<22) ++#define CURLPROTO_RTMPS (1<<23) ++#define CURLPROTO_RTMPTS (1<<24) ++#define CURLPROTO_GOPHER (1<<25) ++#define CURLPROTO_SMB (1<<26) ++#define CURLPROTO_SMBS (1<<27) + #define CURLPROTO_ALL (~0) /* enable everything */ + + /* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ + #define CURLOPTTYPE_LONG 0 + #define CURLOPTTYPE_OBJECTPOINT 10000 ++#define CURLOPTTYPE_STRINGPOINT 10000 + #define CURLOPTTYPE_FUNCTIONPOINT 20000 + #define CURLOPTTYPE_OFF_T 30000 + ++/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the ++ string options from the header file */ ++ + /* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ + #ifdef CINIT + #undef CINIT + #endif + + #ifdef CURL_ISOCPP +-#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number ++#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu + #else + /* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ + #define LONG CURLOPTTYPE_LONG + #define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT ++#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT + #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT + #define OFF_T CURLOPTTYPE_OFF_T + #define CINIT(name,type,number) CURLOPT_/**/name = type + number + #endif + + /* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + + typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ +- CINIT(FILE, OBJECTPOINT, 1), ++ CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ +- CINIT(URL, OBJECTPOINT, 2), ++ CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ +- CINIT(PROXY, OBJECTPOINT, 4), +- +- /* "name:password" to use when fetching. */ +- CINIT(USERPWD, OBJECTPOINT, 5), +- +- /* "name:password" to use with proxy. */ +- CINIT(PROXYUSERPWD, OBJECTPOINT, 6), ++ CINIT(PROXY, STRINGPOINT, 4), ++ ++ /* "user:password;options" to use when fetching. */ ++ CINIT(USERPWD, STRINGPOINT, 5), ++ ++ /* "user:password" to use with proxy. */ ++ CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ +- CINIT(RANGE, OBJECTPOINT, 7), ++ CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ +- CINIT(INFILE, OBJECTPOINT, 9), ++ CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE +- * bytes big. If this is not used, error messages go to stderr instead: */ ++ * bytes big. */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ +@@ -706,24 +1008,24 @@ typedef enum { + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ +- CINIT(REFERER, OBJECTPOINT, 16), ++ CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ +- CINIT(FTPPORT, OBJECTPOINT, 17), ++ CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ +- CINIT(USERAGENT, OBJECTPOINT, 18), ++ CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ +@@ -736,43 +1038,44 @@ typedef enum { + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ +- CINIT(COOKIE, OBJECTPOINT, 22), +- +- /* This points to a linked list of headers, struct curl_slist kind */ ++ CINIT(COOKIE, STRINGPOINT, 22), ++ ++ /* This points to a linked list of headers, struct curl_slist kind. This ++ list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ +- CINIT(SSLCERT, OBJECTPOINT, 25), ++ CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ +- CINIT(KEYPASSWD, OBJECTPOINT, 26), ++ CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ +- CINIT(WRITEHEADER, OBJECTPOINT, 29), ++ CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ +- CINIT(COOKIEFILE, OBJECTPOINT, 31), ++ CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + +@@ -781,87 +1084,88 @@ typedef enum { + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ +- CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), +- +- /* HTTP request, for odd commands like DELETE, TRACE and others */ ++ CINIT(CUSTOMREQUEST, STRINGPOINT, 36), ++ ++ /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + +- /* Pass a pointer to string of the output using full variable-replacement +- as described elsewhere. */ +- CINIT(WRITEINFO, OBJECTPOINT, 40), ++ CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ +- CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ ++ CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ +- CINIT(DIRLISTONLY, LONG, 48), /* return bare names when listing directories */ ++ CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + +- /* Function that will be called instead of the internal progress display ++ /* DEPRECATED ++ * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + +- /* Data passed to the progress callback */ ++ /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION ++ callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), ++#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ +- CINIT(INTERFACE, OBJECTPOINT, 62), ++ CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ +- CINIT(KRBLEVEL, OBJECTPOINT, 63), ++ CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ +- CINIT(CAINFO, OBJECTPOINT, 65), ++ CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if +@@ -869,42 +1173,39 @@ typedef enum { + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + +- /* What policy to use when closing connections when the cache is filled +- up */ +- CINIT(CLOSEPOLICY, LONG, 72), ++ CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ +- CINIT(RANDOM_FILE, OBJECTPOINT, 76), ++ CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ +- CINIT(EGDSOCKET, OBJECTPOINT, 77), +- +- /* Time-out connect operations after this amount of seconds, if connects +- are OK within this time, then fine... This only aborts the connect +- phase. [Only works on unix-style/SIGALRM operating systems] */ ++ CINIT(EGDSOCKET, STRINGPOINT, 77), ++ ++ /* Time-out connect operations after this amount of seconds, if connects are ++ OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. +@@ -913,49 +1214,49 @@ typedef enum { + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ +- CINIT(COOKIEJAR, OBJECTPOINT, 82), ++ CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ +- CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), ++ CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ +- CINIT(SSLCERTTYPE, OBJECTPOINT, 86), ++ CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ +- CINIT(SSLKEY, OBJECTPOINT, 87), ++ CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ +- CINIT(SSLKEYTYPE, OBJECTPOINT, 88), ++ CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ +- CINIT(SSLENGINE, OBJECTPOINT, 89), ++ CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ +- CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */ ++ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ +@@ -964,50 +1265,52 @@ typedef enum { + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ +- CINIT(CAPATH, OBJECTPOINT, 97), ++ CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), +- CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ ++ CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and ++ CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like +- the response to be compressed. */ +- CINIT(ENCODING, OBJECTPOINT, 102), ++ the response to be compressed. Before 7.21.6, this was known as ++ CURLOPT_ENCODING */ ++ CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + +- /* Specifically switch on or off the FTP engine's use of the EPRT command ( it +- also disables the LPRT attempt). By default, those ones will always be ++ /* Specifically switch on or off the FTP engine's use of the EPRT command ( ++ it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + +@@ -1031,16 +1334,17 @@ typedef enum { + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), ++#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. +@@ -1063,22 +1367,22 @@ typedef enum { + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ +- CINIT(NETRC_FILE, OBJECTPOINT, 118), ++ CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: +- CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise +- CURLFTPSSL_CONTROL - SSL for the control connection or fail +- CURLFTPSSL_ALL - SSL for all communication or fail ++ CURLUSESSL_TRY - try using SSL, proceed anyway otherwise ++ CURLUSESSL_CONTROL - SSL for the control connection or fail ++ CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), +@@ -1106,20 +1410,20 @@ typedef enum { + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ +- CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), +- +- /* feed cookies into cookie engine */ +- CINIT(COOKIELIST, OBJECTPOINT, 135), ++ CINIT(FTP_ACCOUNT, STRINGPOINT, 134), ++ ++ /* feed cookie into cookie engine */ ++ CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ +@@ -1155,32 +1459,32 @@ typedef enum { + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ +- CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), ++ CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ +- CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), +- CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), ++ CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), ++ CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + +@@ -1194,17 +1498,17 @@ typedef enum { + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ +- CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), ++ CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + +@@ -1214,51 +1518,50 @@ typedef enum { + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ +- CINIT(CRLFILE, OBJECTPOINT, 169), ++ CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ +- CINIT(ISSUERCERT, OBJECTPOINT, 170), ++ CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with +- CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only +- working with OpenSSL-powered builds. */ ++ CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ +- CINIT(USERNAME, OBJECTPOINT, 173), +- CINIT(PASSWORD, OBJECTPOINT, 174), ++ CINIT(USERNAME, STRINGPOINT, 173), ++ CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ +- CINIT(PROXYUSERNAME, OBJECTPOINT, 175), +- CINIT(PROXYPASSWORD, OBJECTPOINT, 176), ++ CINIT(PROXYUSERNAME, STRINGPOINT, 175), ++ CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ +- CINIT(NOPROXY, OBJECTPOINT, 177), ++ CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ +- CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179), ++ CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ +@@ -1266,25 +1569,360 @@ typedef enum { + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ +- CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183), ++ CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + ++ /* set the SMTP mail originator */ ++ CINIT(MAIL_FROM, STRINGPOINT, 186), ++ ++ /* set the list of SMTP mail receiver(s) */ ++ CINIT(MAIL_RCPT, OBJECTPOINT, 187), ++ ++ /* FTP: send PRET before PASV */ ++ CINIT(FTP_USE_PRET, LONG, 188), ++ ++ /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ ++ CINIT(RTSP_REQUEST, LONG, 189), ++ ++ /* The RTSP session identifier */ ++ CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), ++ ++ /* The RTSP stream URI */ ++ CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), ++ ++ /* The Transport: header to use in RTSP requests */ ++ CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), ++ ++ /* Manually initialize the client RTSP CSeq for this handle */ ++ CINIT(RTSP_CLIENT_CSEQ, LONG, 193), ++ ++ /* Manually initialize the server RTSP CSeq for this handle */ ++ CINIT(RTSP_SERVER_CSEQ, LONG, 194), ++ ++ /* The stream to pass to INTERLEAVEFUNCTION. */ ++ CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), ++ ++ /* Let the application define a custom write method for RTP data */ ++ CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), ++ ++ /* Turn on wildcard matching */ ++ CINIT(WILDCARDMATCH, LONG, 197), ++ ++ /* Directory matching callback called before downloading of an ++ individual file (chunk) started */ ++ CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), ++ ++ /* Directory matching callback called after the file (chunk) ++ was downloaded, or skipped */ ++ CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), ++ ++ /* Change match (fnmatch-like) callback for wildcard matching */ ++ CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), ++ ++ /* Let the application define custom chunk data pointer */ ++ CINIT(CHUNK_DATA, OBJECTPOINT, 201), ++ ++ /* FNMATCH_FUNCTION user pointer */ ++ CINIT(FNMATCH_DATA, OBJECTPOINT, 202), ++ ++ /* send linked-list of name:port:address sets */ ++ CINIT(RESOLVE, OBJECTPOINT, 203), ++ ++ /* Set a username for authenticated TLS */ ++ CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), ++ ++ /* Set a password for authenticated TLS */ ++ CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), ++ ++ /* Set authentication type for authenticated TLS */ ++ CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), ++ ++ /* Set to 1 to enable the "TE:" header in HTTP requests to ask for ++ compressed transfer-encoded responses. Set to 0 to disable the use of TE: ++ in outgoing requests. The current default is 0, but it might change in a ++ future libcurl release. ++ ++ libcurl will ask for the compressed methods it knows of, and if that ++ isn't any, it will not ask for transfer-encoding at all even if this ++ option is set to 1. ++ ++ */ ++ CINIT(TRANSFER_ENCODING, LONG, 207), ++ ++ /* Callback function for closing socket (instead of close(2)). The callback ++ should have type curl_closesocket_callback */ ++ CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), ++ CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), ++ ++ /* allow GSSAPI credential delegation */ ++ CINIT(GSSAPI_DELEGATION, LONG, 210), ++ ++ /* Set the name servers to use for DNS resolution */ ++ CINIT(DNS_SERVERS, STRINGPOINT, 211), ++ ++ /* Time-out accept operations (currently for FTP only) after this amount ++ of milliseconds. */ ++ CINIT(ACCEPTTIMEOUT_MS, LONG, 212), ++ ++ /* Set TCP keepalive */ ++ CINIT(TCP_KEEPALIVE, LONG, 213), ++ ++ /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ ++ CINIT(TCP_KEEPIDLE, LONG, 214), ++ CINIT(TCP_KEEPINTVL, LONG, 215), ++ ++ /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ ++ CINIT(SSL_OPTIONS, LONG, 216), ++ ++ /* Set the SMTP auth originator */ ++ CINIT(MAIL_AUTH, STRINGPOINT, 217), ++ ++ /* Enable/disable SASL initial response */ ++ CINIT(SASL_IR, LONG, 218), ++ ++ /* Function that will be called instead of the internal progress display ++ * function. This function should be defined as the curl_xferinfo_callback ++ * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ ++ CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), ++ ++ /* The XOAUTH2 bearer token */ ++ CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), ++ ++ /* Set the interface string to use as outgoing network ++ * interface for DNS requests. ++ * Only supported by the c-ares DNS backend */ ++ CINIT(DNS_INTERFACE, STRINGPOINT, 221), ++ ++ /* Set the local IPv4 address to use for outgoing DNS requests. ++ * Only supported by the c-ares DNS backend */ ++ CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), ++ ++ /* Set the local IPv6 address to use for outgoing DNS requests. ++ * Only supported by the c-ares DNS backend */ ++ CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), ++ ++ /* Set authentication options directly */ ++ CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), ++ ++ /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ ++ CINIT(SSL_ENABLE_NPN, LONG, 225), ++ ++ /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ ++ CINIT(SSL_ENABLE_ALPN, LONG, 226), ++ ++ /* Time to wait for a response to a HTTP request containing an ++ * Expect: 100-continue header before sending the data anyway. */ ++ CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), ++ ++ /* This points to a linked list of headers used for proxy requests only, ++ struct curl_slist kind */ ++ CINIT(PROXYHEADER, OBJECTPOINT, 228), ++ ++ /* Pass in a bitmask of "header options" */ ++ CINIT(HEADEROPT, LONG, 229), ++ ++ /* The public key in DER form used to validate the peer public key ++ this option is used only if SSL_VERIFYPEER is true */ ++ CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), ++ ++ /* Path to Unix domain socket */ ++ CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), ++ ++ /* Set if we should verify the certificate status. */ ++ CINIT(SSL_VERIFYSTATUS, LONG, 232), ++ ++ /* Set if we should enable TLS false start. */ ++ CINIT(SSL_FALSESTART, LONG, 233), ++ ++ /* Do not squash dot-dot sequences */ ++ CINIT(PATH_AS_IS, LONG, 234), ++ ++ /* Proxy Service Name */ ++ CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), ++ ++ /* Service Name */ ++ CINIT(SERVICE_NAME, STRINGPOINT, 236), ++ ++ /* Wait/don't wait for pipe/mutex to clarify */ ++ CINIT(PIPEWAIT, LONG, 237), ++ ++ /* Set the protocol used when curl is given a URL without a protocol */ ++ CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), ++ ++ /* Set stream weight, 1 - 256 (default is 16) */ ++ CINIT(STREAM_WEIGHT, LONG, 239), ++ ++ /* Set stream dependency on another CURL handle */ ++ CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), ++ ++ /* Set E-xclusive stream dependency on another CURL handle */ ++ CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), ++ ++ /* Do not send any tftp option requests to the server */ ++ CINIT(TFTP_NO_OPTIONS, LONG, 242), ++ ++ /* Linked-list of host:port:connect-to-host:connect-to-port, ++ overrides the URL's host:port (only for the network layer) */ ++ CINIT(CONNECT_TO, OBJECTPOINT, 243), ++ ++ /* Set TCP Fast Open */ ++ CINIT(TCP_FASTOPEN, LONG, 244), ++ ++ /* Continue to send data if the server responds early with an ++ * HTTP status code >= 300 */ ++ CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), ++ ++ /* The CApath or CAfile used to validate the proxy certificate ++ this option is used only if PROXY_SSL_VERIFYPEER is true */ ++ CINIT(PROXY_CAINFO, STRINGPOINT, 246), ++ ++ /* The CApath directory used to validate the proxy certificate ++ this option is used only if PROXY_SSL_VERIFYPEER is true */ ++ CINIT(PROXY_CAPATH, STRINGPOINT, 247), ++ ++ /* Set if we should verify the proxy in ssl handshake, ++ set 1 to verify. */ ++ CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), ++ ++ /* Set if we should verify the Common name from the proxy certificate in ssl ++ * handshake, set 1 to check existence, 2 to ensure that it matches ++ * the provided hostname. */ ++ CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), ++ ++ /* What version to specifically try to use for proxy. ++ See CURL_SSLVERSION defines below. */ ++ CINIT(PROXY_SSLVERSION, LONG, 250), ++ ++ /* Set a username for authenticated TLS for proxy */ ++ CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), ++ ++ /* Set a password for authenticated TLS for proxy */ ++ CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), ++ ++ /* Set authentication type for authenticated TLS for proxy */ ++ CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), ++ ++ /* name of the file keeping your private SSL-certificate for proxy */ ++ CINIT(PROXY_SSLCERT, STRINGPOINT, 254), ++ ++ /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for ++ proxy */ ++ CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), ++ ++ /* name of the file keeping your private SSL-key for proxy */ ++ CINIT(PROXY_SSLKEY, STRINGPOINT, 256), ++ ++ /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for ++ proxy */ ++ CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), ++ ++ /* password for the SSL private key for proxy */ ++ CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), ++ ++ /* Specify which SSL ciphers to use for proxy */ ++ CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), ++ ++ /* CRL file for proxy */ ++ CINIT(PROXY_CRLFILE, STRINGPOINT, 260), ++ ++ /* Enable/disable specific SSL features with a bitmask for proxy, see ++ CURLSSLOPT_* */ ++ CINIT(PROXY_SSL_OPTIONS, LONG, 261), ++ ++ /* Name of pre proxy to use. */ ++ CINIT(PRE_PROXY, STRINGPOINT, 262), ++ ++ /* The public key in DER form used to validate the proxy public key ++ this option is used only if PROXY_SSL_VERIFYPEER is true */ ++ CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), ++ ++ /* Path to an abstract Unix domain socket */ ++ CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), ++ ++ /* Suppress proxy CONNECT response headers from user callbacks */ ++ CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), ++ ++ /* The request target, instead of extracted from the URL */ ++ CINIT(REQUEST_TARGET, STRINGPOINT, 266), ++ ++ /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ ++ CINIT(SOCKS5_AUTH, LONG, 267), ++ ++ /* Enable/disable SSH compression */ ++ CINIT(SSH_COMPRESSION, LONG, 268), ++ ++ /* Post MIME data. */ ++ CINIT(MIMEPOST, OBJECTPOINT, 269), ++ ++ /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of ++ seconds since 1 Jan 1970. */ ++ CINIT(TIMEVALUE_LARGE, OFF_T, 270), ++ ++ /* Head start in milliseconds to give happy eyeballs. */ ++ CINIT(HAPPY_EYEBALLS_TIMEOUT_MS, LONG, 271), ++ ++ /* Function that will be called before a resolver request is made */ ++ CINIT(RESOLVER_START_FUNCTION, FUNCTIONPOINT, 272), ++ ++ /* User data to pass to the resolver start callback. */ ++ CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273), ++ ++ /* send HAProxy PROXY protocol header? */ ++ CINIT(HAPROXYPROTOCOL, LONG, 274), ++ ++ /* shuffle addresses before use when DNS returns multiple */ ++ CINIT(DNS_SHUFFLE_ADDRESSES, LONG, 275), ++ ++ /* Specify which TLS 1.3 ciphers suites to use */ ++ CINIT(TLS13_CIPHERS, STRINGPOINT, 276), ++ CINIT(PROXY_TLS13_CIPHERS, STRINGPOINT, 277), ++ ++ /* Disallow specifying username/login in URL. */ ++ CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278), ++ ++ /* DNS-over-HTTPS URL */ ++ CINIT(DOH_URL, STRINGPOINT, 279), ++ ++ /* Preferred buffer size to use for uploads */ ++ CINIT(UPLOAD_BUFFERSIZE, LONG, 280), ++ ++ /* Time in ms between connection upkeep calls for long-lived connections. */ ++ CINIT(UPKEEP_INTERVAL_MS, LONG, 281), ++ ++ /* Specify URL using CURL URL API. */ ++ CINIT(CURLU, OBJECTPOINT, 282), ++ ++ /* add trailing data just after no more data is available */ ++ CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 283), ++ ++ /* pointer to be passed to HTTP_TRAILER_FUNCTION */ ++ CINIT(TRAILERDATA, OBJECTPOINT, 284), ++ ++ /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ ++ CINIT(HTTP09_ALLOWED, LONG, 285), ++ ++ /* alt-svc control bitmask */ ++ CINIT(ALTSVC_CTRL, LONG, 286), ++ ++ /* alt-svc cache file name to possibly read from/write to */ ++ CINIT(ALTSVC, STRINGPOINT, 287), ++ + CURLOPT_LASTENTRY /* the last unused */ + } CURLoption; + + #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + + /* Backwards compatibility with older names */ + /* These are scheduled to disappear by 2011 */ +@@ -1311,81 +1949,260 @@ typedef enum { + #endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ + #define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +-#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ +-#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ ++#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ ++#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +-#define CURLOPT_WRITEDATA CURLOPT_FILE +-#define CURLOPT_READDATA CURLOPT_INFILE +-#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER ++#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ + enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ ++ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ ++ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ ++ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 ++ Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ + }; + ++/* Convenience definition simple because the name of the version is HTTP/2 and ++ not 2.0. The 2_0 version of the enum name was set while the version was ++ still planned to be 2.0 and we stick to it for compatibility. */ ++#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 ++ ++/* ++ * Public API enums for RTSP requests ++ */ ++enum { ++ CURL_RTSPREQ_NONE, /* first in list */ ++ CURL_RTSPREQ_OPTIONS, ++ CURL_RTSPREQ_DESCRIBE, ++ CURL_RTSPREQ_ANNOUNCE, ++ CURL_RTSPREQ_SETUP, ++ CURL_RTSPREQ_PLAY, ++ CURL_RTSPREQ_PAUSE, ++ CURL_RTSPREQ_TEARDOWN, ++ CURL_RTSPREQ_GET_PARAMETER, ++ CURL_RTSPREQ_SET_PARAMETER, ++ CURL_RTSPREQ_RECORD, ++ CURL_RTSPREQ_RECEIVE, ++ CURL_RTSPREQ_LAST /* last in list */ ++}; ++ + /* These enums are for use with the CURLOPT_NETRC option. */ + enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST + }; + + enum { + CURL_SSLVERSION_DEFAULT, +- CURL_SSLVERSION_TLSv1, ++ CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, ++ CURL_SSLVERSION_TLSv1_0, ++ CURL_SSLVERSION_TLSv1_1, ++ CURL_SSLVERSION_TLSv1_2, ++ CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ + }; + ++enum { ++ CURL_SSLVERSION_MAX_NONE = 0, ++ CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), ++ CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), ++ CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), ++ CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), ++ CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), ++ ++ /* never use, keep last */ ++ CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) ++}; ++ ++enum CURL_TLSAUTH { ++ CURL_TLSAUTH_NONE, ++ CURL_TLSAUTH_SRP, ++ CURL_TLSAUTH_LAST /* never use, keep last */ ++}; ++ + /* symbols to use with CURLOPT_POSTREDIR. +- CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that +- CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */ ++ CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 ++ can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 ++ | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + + #define CURL_REDIR_GET_ALL 0 + #define CURL_REDIR_POST_301 1 + #define CURL_REDIR_POST_302 2 +-#define CURL_REDIR_POST_ALL (CURL_REDIR_POST_301|CURL_REDIR_POST_302) ++#define CURL_REDIR_POST_303 4 ++#define CURL_REDIR_POST_ALL \ ++ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + + typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST + } curl_TimeCond; + ++/* Special size_t value signaling a zero-terminated string. */ ++#define CURL_ZERO_TERMINATED ((size_t) -1) + + /* curl_strequal() and curl_strnequal() are subject for removal in a future +- libcurl, see lib/README.curlx for details */ +-CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +-CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); +- ++ release */ ++CURL_EXTERN int curl_strequal(const char *s1, const char *s2); ++CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); ++ ++/* Mime/form handling support. */ ++typedef struct curl_mime_s curl_mime; /* Mime context. */ ++typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ ++ ++/* ++ * NAME curl_mime_init() ++ * ++ * DESCRIPTION ++ * ++ * Create a mime context and return its handle. The easy parameter is the ++ * target handle. ++ */ ++CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); ++ ++/* ++ * NAME curl_mime_free() ++ * ++ * DESCRIPTION ++ * ++ * release a mime handle and its substructures. ++ */ ++CURL_EXTERN void curl_mime_free(curl_mime *mime); ++ ++/* ++ * NAME curl_mime_addpart() ++ * ++ * DESCRIPTION ++ * ++ * Append a new empty part to the given mime context and return a handle to ++ * the created part. ++ */ ++CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); ++ ++/* ++ * NAME curl_mime_name() ++ * ++ * DESCRIPTION ++ * ++ * Set mime/form part name. ++ */ ++CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); ++ ++/* ++ * NAME curl_mime_filename() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part remote file name. ++ */ ++CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, ++ const char *filename); ++ ++/* ++ * NAME curl_mime_type() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part type. ++ */ ++CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); ++ ++/* ++ * NAME curl_mime_encoder() ++ * ++ * DESCRIPTION ++ * ++ * Set mime data transfer encoder. ++ */ ++CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, ++ const char *encoding); ++ ++/* ++ * NAME curl_mime_data() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part data source from memory data, ++ */ ++CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, ++ const char *data, size_t datasize); ++ ++/* ++ * NAME curl_mime_filedata() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part data source from named file. ++ */ ++CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, ++ const char *filename); ++ ++/* ++ * NAME curl_mime_data_cb() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part data source from callback function. ++ */ ++CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, ++ curl_off_t datasize, ++ curl_read_callback readfunc, ++ curl_seek_callback seekfunc, ++ curl_free_callback freefunc, ++ void *arg); ++ ++/* ++ * NAME curl_mime_subparts() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part data source from subparts. ++ */ ++CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, ++ curl_mime *subparts); ++/* ++ * NAME curl_mime_headers() ++ * ++ * DESCRIPTION ++ * ++ * Set mime part headers. ++ */ ++CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, ++ struct curl_slist *headers, ++ int take_ownership); ++ ++/* Old form API. */ + /* name is uppercase CURLFORM_ */ + #ifdef CFINIT + #undef CFINIT + #endif + + #ifdef CURL_ISOCPP + #define CFINIT(name) CURLFORM_ ## name + #else +@@ -1414,16 +2231,17 @@ typedef enum { + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), ++ CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ + } CURLformoption; + + #undef CFINIT /* done */ + + /* structure to be used as parameter for CURLFORM_ARRAY */ + struct curl_forms { +@@ -1477,17 +2295,18 @@ CURL_EXTERN CURLFORMcode curl_formadd(st + /* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +-typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); ++typedef size_t (*curl_formget_callback)(void *arg, const char *buf, ++ size_t len); + + /* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to +@@ -1616,16 +2435,57 @@ CURL_EXTERN void curl_global_cleanup(voi + + /* linked-list structure for the CURLOPT_QUOTE option (and other) */ + struct curl_slist { + char *data; + struct curl_slist *next; + }; + + /* ++ * NAME curl_global_sslset() ++ * ++ * DESCRIPTION ++ * ++ * When built with multiple SSL backends, curl_global_sslset() allows to ++ * choose one. This function can only be called once, and it must be called ++ * *before* curl_global_init(). ++ * ++ * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The ++ * backend can also be specified via the name parameter (passing -1 as id). ++ * If both id and name are specified, the name will be ignored. If neither id ++ * nor name are specified, the function will fail with ++ * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the ++ * NULL-terminated list of available backends. ++ * ++ * Upon success, the function returns CURLSSLSET_OK. ++ * ++ * If the specified SSL backend is not available, the function returns ++ * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated ++ * list of available SSL backends. ++ * ++ * The SSL backend can be set only once. If it has already been set, a ++ * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. ++ */ ++ ++typedef struct { ++ curl_sslbackend id; ++ const char *name; ++} curl_ssl_backend; ++ ++typedef enum { ++ CURLSSLSET_OK = 0, ++ CURLSSLSET_UNKNOWN_BACKEND, ++ CURLSSLSET_TOO_LATE, ++ CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ ++} CURLsslset; ++ ++CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, ++ const curl_ssl_backend ***avail); ++ ++/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ + CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, +@@ -1655,41 +2515,59 @@ CURL_EXTERN time_t curl_getdate(const ch + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ + struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ + }; + ++/* Information about the SSL library used and the respective internal SSL ++ handle, which can be used to obtain further information regarding the ++ connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ ++struct curl_tlssessioninfo { ++ curl_sslbackend backend; ++ void *internals; ++}; ++ + #define CURLINFO_STRING 0x100000 + #define CURLINFO_LONG 0x200000 + #define CURLINFO_DOUBLE 0x300000 + #define CURLINFO_SLIST 0x400000 ++#define CURLINFO_PTR 0x400000 /* same as SLIST */ ++#define CURLINFO_SOCKET 0x500000 ++#define CURLINFO_OFF_T 0x600000 + #define CURLINFO_MASK 0x0fffff + #define CURLINFO_TYPEMASK 0xf00000 + + typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, ++ CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, ++ CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, ++ CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, ++ CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, ++ CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, ++ CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, ++ CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, +@@ -1697,21 +2575,45 @@ typedef enum { + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, +- CURLINFO_CERTINFO = CURLINFO_SLIST + 34, ++ CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, ++ CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, ++ CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, ++ CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, ++ CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, ++ CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, ++ CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, ++ CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, ++ CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, ++ CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, ++ CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, ++ CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, ++ CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, ++ CURLINFO_PROTOCOL = CURLINFO_LONG + 48, ++ CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + +- CURLINFO_LASTONE = 35 ++ /* Preferably these would be defined conditionally based on the ++ sizeof curl_off_t being 64-bits */ ++ CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, ++ CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, ++ CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, ++ CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, ++ CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, ++ CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, ++ CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, ++ ++ CURLINFO_LASTONE = 56 + } CURLINFO; + + /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ + #define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + + typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ +@@ -1720,21 +2622,22 @@ typedef enum { + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ + } curl_closepolicy; + +-#define CURL_GLOBAL_SSL (1<<0) ++#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ + #define CURL_GLOBAL_WIN32 (1<<1) + #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) + #define CURL_GLOBAL_NOTHING 0 + #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL ++#define CURL_GLOBAL_ACK_EINTR (1<<2) + + + /***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + + /* Different data locks for a single share */ + typedef enum { +@@ -1743,16 +2646,17 @@ typedef enum { + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, ++ CURL_LOCK_DATA_PSL, + CURL_LOCK_DATA_LAST + } curl_lock_data; + + /* Different lock access types */ + typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ +@@ -1762,25 +2666,25 @@ typedef enum { + typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); + typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +-typedef void CURLSH; + + typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ +- CURLSHE_NOMEM, /* out of memory */ +- CURLSHE_LAST /* never use */ ++ CURLSHE_NOMEM, /* 4 out of memory */ ++ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ ++ CURLSHE_LAST /* never use */ + } CURLSHcode; + + typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ +@@ -1797,25 +2701,26 @@ CURL_EXTERN CURLSHcode curl_share_cleanu + * Structures for querying information about the curl library at runtime. + */ + + typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, ++ CURLVERSION_FIFTH, + CURLVERSION_LAST /* never actually use this */ + } CURLversion; + + /* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +-#define CURLVERSION_NOW CURLVERSION_FOURTH ++#define CURLVERSION_NOW CURLVERSION_FIFTH + + typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ +@@ -1833,34 +2738,56 @@ typedef struct { + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + ++ /* These fields were added in CURLVERSION_FIFTH */ ++ ++ unsigned int brotli_ver_num; /* Numeric Brotli version ++ (MAJOR << 24) | (MINOR << 12) | PATCH */ ++ const char *brotli_version; /* human readable string. */ ++ + } curl_version_info_data; + +-#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +-#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ +-#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +-#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +-#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +-#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ +-#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ +-#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ +-#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ +-#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ +-#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ +-#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ +-#define CURL_VERSION_CONV (1<<12) /* character conversions supported */ +-#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ +- +-/* ++#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ ++#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported ++ (deprecated) */ ++#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ ++#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ ++#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ ++#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported ++ (deprecated) */ ++#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ ++#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ ++#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ ++#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ ++#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are ++ supported */ ++#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ ++#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ ++#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ ++#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ ++#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper ++ is supported */ ++#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ ++#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ ++#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ ++#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ ++#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used ++ for cookie domain verification */ ++#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ ++#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ ++#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ ++#define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ ++ ++ /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ + CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); +@@ -1910,16 +2837,17 @@ CURL_EXTERN CURLcode curl_easy_pause(CUR + #ifdef __cplusplus + } + #endif + + /* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ + #include "easy.h" /* nothing in curl is fun without the easy stuff */ + #include "multi.h" ++#include "urlapi.h" + + /* the typechecker doesn't work in C++ (yet) */ + #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) + #include "typecheck-gcc.h" + #else + #if defined(__STDC__) && (__STDC__ >= 1) +diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h +deleted file mode 100644 +--- a/src/third_party/curl/curlbuild.h ++++ /dev/null +@@ -1,203 +0,0 @@ +-/* include/curl/curlbuild.h. Generated from curlbuild.h.in by configure. */ +-#ifndef __CURL_CURLBUILD_H +-#define __CURL_CURLBUILD_H +-/*************************************************************************** +- * _ _ ____ _ +- * Project ___| | | | _ \| | +- * / __| | | | |_) | | +- * | (__| |_| | _ <| |___ +- * \___|\___/|_| \_\_____| +- * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. +- * +- * This software is licensed as described in the file COPYING, which +- * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. +- * +- * You may opt to use, copy, modify, merge, publish, distribute and/or sell +- * copies of the Software, and permit persons to whom the Software is +- * furnished to do so, under the terms of the COPYING file. +- * +- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +- * KIND, either express or implied. +- * +- * $Id: curlbuild.h.in,v 1.8 2009-04-29 15:15:38 yangtse Exp $ +- ***************************************************************************/ +- +-/* ================================================================ */ +-/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +-/* ================================================================ */ +- +-/* +- * NOTE 1: +- * ------- +- * +- * Nothing in this file is intended to be modified or adjusted by the +- * curl library user nor by the curl library builder. +- * +- * If you think that something actually needs to be changed, adjusted +- * or fixed in this file, then, report it on the libcurl development +- * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ +- * +- * This header file shall only export symbols which are 'curl' or 'CURL' +- * prefixed, otherwise public name space would be polluted. +- * +- * NOTE 2: +- * ------- +- * +- * Right now you might be staring at file include/curl/curlbuild.h.in or +- * at file include/curl/curlbuild.h, this is due to the following reason: +- * +- * On systems capable of running the configure script, the configure process +- * will overwrite the distributed include/curl/curlbuild.h file with one that +- * is suitable and specific to the library being configured and built, which +- * is generated from the include/curl/curlbuild.h.in template file. +- * +- */ +- +-/* ================================================================ */ +-/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +-/* ================================================================ */ +- +-#ifdef CURL_SIZEOF_LONG +-# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +-#endif +- +-#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +-# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +-#endif +- +-#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +-# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +-#endif +- +-#ifdef CURL_TYPEOF_CURL_OFF_T +-# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +-#endif +- +-#ifdef CURL_FORMAT_CURL_OFF_T +-# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +-#endif +- +-#ifdef CURL_FORMAT_CURL_OFF_TU +-# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +-#endif +- +-#ifdef CURL_FORMAT_OFF_T +-# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +-#endif +- +-#ifdef CURL_SIZEOF_CURL_OFF_T +-# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +-#endif +- +-#ifdef CURL_SUFFIX_CURL_OFF_T +-# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +-#endif +- +-#ifdef CURL_SUFFIX_CURL_OFF_TU +-# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" +- Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +-#endif +- +-/* ================================================================ */ +-/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +-/* ================================================================ */ +- +-/* Configure process defines this to 1 when it finds out that system */ +-/* header file ws2tcpip.h must be included by the external interface. */ +-/* #undef CURL_PULL_WS2TCPIP_H */ +-#ifdef CURL_PULL_WS2TCPIP_H +-# ifndef WIN32_LEAN_AND_MEAN +-# define WIN32_LEAN_AND_MEAN +-# endif +-# include +-# include +-# include +-#endif +- +-/* Configure process defines this to 1 when it finds out that system */ +-/* header file sys/types.h must be included by the external interface. */ +-#define CURL_PULL_SYS_TYPES_H 1 +-#ifdef CURL_PULL_SYS_TYPES_H +-# include +-#endif +- +-/* Configure process defines this to 1 when it finds out that system */ +-/* header file stdint.h must be included by the external interface. */ +-/* #undef CURL_PULL_STDINT_H */ +-#ifdef CURL_PULL_STDINT_H +-# include +-#endif +- +-/* Configure process defines this to 1 when it finds out that system */ +-/* header file inttypes.h must be included by the external interface. */ +-/* #undef CURL_PULL_INTTYPES_H */ +-#ifdef CURL_PULL_INTTYPES_H +-# include +-#endif +- +-/* Configure process defines this to 1 when it finds out that system */ +-/* header file sys/socket.h must be included by the external interface. */ +-#define CURL_PULL_SYS_SOCKET_H 1 +-#ifdef CURL_PULL_SYS_SOCKET_H +-# include +-#endif +- +-/* The size of `long', as computed by sizeof. */ +-#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ +- defined(__aarch64__) || (defined(__mips__) && _MIPS_SIM == _ABI64) || \ +- defined(__powerpc64__) || defined(__s390x__) || defined(__LP64__) +-#define CURL_SIZEOF_LONG 8 +-#else +-#define CURL_SIZEOF_LONG 4 +-#endif +- +-/* Integral data type used for curl_socklen_t. */ +-#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +- +-/* The size of `curl_socklen_t', as computed by sizeof. */ +-#define CURL_SIZEOF_CURL_SOCKLEN_T 4 +- +-/* Data type definition of curl_socklen_t. */ +-typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +- +-/* Signed integral data type used for curl_off_t. */ +-#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ +- defined(__aarch64__) +-#define CURL_TYPEOF_CURL_OFF_T long +-#else +-#define CURL_TYPEOF_CURL_OFF_T int64_t +-#endif +- +-/* Data type definition of curl_off_t. */ +-typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +- +-/* curl_off_t formatting string directive without "%" conversion specifier. */ +-#define CURL_FORMAT_CURL_OFF_T "ld" +- +-/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +-#define CURL_FORMAT_CURL_OFF_TU "lu" +- +-/* curl_off_t formatting string directive with "%" conversion specifier. */ +-#define CURL_FORMAT_OFF_T "%ld" +- +-/* The size of `curl_off_t', as computed by sizeof. */ +-#define CURL_SIZEOF_CURL_OFF_T 8 +- +-/* curl_off_t constant suffix. */ +-#define CURL_SUFFIX_CURL_OFF_T L +- +-/* unsigned curl_off_t constant suffix. */ +-#define CURL_SUFFIX_CURL_OFF_TU UL +- +-#endif /* __CURL_CURLBUILD_H */ +diff --git a/src/third_party/curl/curlrules.h b/src/third_party/curl/curlrules.h +deleted file mode 100644 +--- a/src/third_party/curl/curlrules.h ++++ /dev/null +@@ -1,249 +0,0 @@ +-#ifndef __CURL_CURLRULES_H +-#define __CURL_CURLRULES_H +-/*************************************************************************** +- * _ _ ____ _ +- * Project ___| | | | _ \| | +- * / __| | | | |_) | | +- * | (__| |_| | _ <| |___ +- * \___|\___/|_| \_\_____| +- * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. +- * +- * This software is licensed as described in the file COPYING, which +- * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. +- * +- * You may opt to use, copy, modify, merge, publish, distribute and/or sell +- * copies of the Software, and permit persons to whom the Software is +- * furnished to do so, under the terms of the COPYING file. +- * +- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +- * KIND, either express or implied. +- * +- * $Id: curlrules.h,v 1.7 2009-10-27 16:56:20 yangtse Exp $ +- ***************************************************************************/ +- +-/* ================================================================ */ +-/* COMPILE TIME SANITY CHECKS */ +-/* ================================================================ */ +- +-/* +- * NOTE 1: +- * ------- +- * +- * All checks done in this file are intentionally placed in a public +- * header file which is pulled by curl/curl.h when an application is +- * being built using an already built libcurl library. Additionally +- * this file is also included and used when building the library. +- * +- * If compilation fails on this file it is certainly sure that the +- * problem is elsewhere. It could be a problem in the curlbuild.h +- * header file, or simply that you are using different compilation +- * settings than those used to build the library. +- * +- * Nothing in this file is intended to be modified or adjusted by the +- * curl library user nor by the curl library builder. +- * +- * Do not deactivate any check, these are done to make sure that the +- * library is properly built and used. +- * +- * You can find further help on the libcurl development mailing list: +- * http://cool.haxx.se/mailman/listinfo/curl-library/ +- * +- * NOTE 2 +- * ------ +- * +- * Some of the following compile time checks are based on the fact +- * that the dimension of a constant array can not be a negative one. +- * In this way if the compile time verification fails, the compilation +- * will fail issuing an error. The error description wording is compiler +- * dependent but it will be quite similar to one of the following: +- * +- * "negative subscript or subscript is too large" +- * "array must have at least one element" +- * "-1 is an illegal array size" +- * "size of array is negative" +- * +- * If you are building an application which tries to use an already +- * built libcurl library and you are getting this kind of errors on +- * this file, it is a clear indication that there is a mismatch between +- * how the library was built and how you are trying to use it for your +- * application. Your already compiled or binary library provider is the +- * only one who can give you the details you need to properly use it. +- */ +- +-/* +- * Verify that some macros are actually defined. +- */ +- +-#ifndef CURL_SIZEOF_LONG +-# error "CURL_SIZEOF_LONG definition is missing!" +- Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +-#endif +- +-#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +-# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" +- Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +-#endif +- +-#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +-# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" +- Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +-#endif +- +-#ifndef CURL_TYPEOF_CURL_OFF_T +-# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" +- Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +-#endif +- +-#ifndef CURL_FORMAT_CURL_OFF_T +-# error "CURL_FORMAT_CURL_OFF_T definition is missing!" +- Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +-#endif +- +-#ifndef CURL_FORMAT_CURL_OFF_TU +-# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" +- Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +-#endif +- +-#ifndef CURL_FORMAT_OFF_T +-# error "CURL_FORMAT_OFF_T definition is missing!" +- Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +-#endif +- +-#ifndef CURL_SIZEOF_CURL_OFF_T +-# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" +- Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +-#endif +- +-#ifndef CURL_SUFFIX_CURL_OFF_T +-# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" +- Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +-#endif +- +-#ifndef CURL_SUFFIX_CURL_OFF_TU +-# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" +- Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +-#endif +- +-/* +- * Macros private to this header file. +- */ +- +-#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 +- +-#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 +- +-/* +- * Verify that the size previously defined and expected for long +- * is the same as the one reported by sizeof() at compile time. +- */ +- +-typedef char +- __curl_rule_01__ +- [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; +- +-/* +- * Verify that the size previously defined and expected for +- * curl_off_t is actually the the same as the one reported +- * by sizeof() at compile time. +- */ +- +-typedef char +- __curl_rule_02__ +- [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; +- +-/* +- * Verify at compile time that the size of curl_off_t as reported +- * by sizeof() is greater or equal than the one reported for long +- * for the current compilation. +- */ +- +-typedef char +- __curl_rule_03__ +- [CurlchkszGE(curl_off_t, long)]; +- +-/* +- * Verify that the size previously defined and expected for +- * curl_socklen_t is actually the the same as the one reported +- * by sizeof() at compile time. +- */ +- +-typedef char +- __curl_rule_04__ +- [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; +- +-/* +- * Verify at compile time that the size of curl_socklen_t as reported +- * by sizeof() is greater or equal than the one reported for int for +- * the current compilation. +- */ +- +-typedef char +- __curl_rule_05__ +- [CurlchkszGE(curl_socklen_t, int)]; +- +-/* ================================================================ */ +-/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +-/* ================================================================ */ +- +-/* +- * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow +- * these to be visible and exported by the external libcurl interface API, +- * while also making them visible to the library internals, simply including +- * setup.h, without actually needing to include curl.h internally. +- * If some day this section would grow big enough, all this should be moved +- * to its own header file. +- */ +- +-/* +- * Figure out if we can use the ## preprocessor operator, which is supported +- * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ +- * or __cplusplus so we need to carefully check for them too. +- */ +- +-#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ +- defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ +- defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ +- defined(__ILEC400__) +- /* This compiler is believed to have an ISO compatible preprocessor */ +-#define CURL_ISOCPP +-#else +- /* This compiler is believed NOT to have an ISO compatible preprocessor */ +-#undef CURL_ISOCPP +-#endif +- +-/* +- * Macros for minimum-width signed and unsigned curl_off_t integer constants. +- */ +- +-#ifdef CURL_ISOCPP +-# define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val ## Suffix +-#else +-# define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val/**/Suffix +-#endif +-#define __CURL_OFF_T_C_HELPER1(Val,Suffix) __CURL_OFF_T_C_HELPER2(Val,Suffix) +-#define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_T) +-#define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_TU) +- +-/* +- * Get rid of macros private to this header file. +- */ +- +-#undef CurlchkszEQ +-#undef CurlchkszGE +- +-/* +- * Get rid of macros not intended to exist beyond this point. +- */ +- +-#undef CURL_PULL_WS2TCPIP_H +-#undef CURL_PULL_SYS_TYPES_H +-#undef CURL_PULL_SYS_SOCKET_H +-#undef CURL_PULL_STDINT_H +-#undef CURL_PULL_INTTYPES_H +- +-#undef CURL_TYPEOF_CURL_SOCKLEN_T +-#undef CURL_TYPEOF_CURL_OFF_T +- +-#endif /* __CURL_CURLRULES_H */ +diff --git a/src/third_party/curl/curlver.h b/src/third_party/curl/curlver.h +--- a/src/third_party/curl/curlver.h ++++ b/src/third_party/curl/curlver.h +@@ -2,69 +2,76 @@ + #define __CURL_CURLVER_H + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * +- * $Id: curlver.h,v 1.48 2009-08-12 11:24:52 bagder Exp $ + ***************************************************************************/ + + /* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + + /* This is the global package copyright */ +-#define LIBCURL_COPYRIGHT "1996 - 2009 Daniel Stenberg, ." ++#define LIBCURL_COPYRIGHT "1996 - 2019 Daniel Stenberg, ." + + /* This is the version number of the libcurl package from which this header + file origins: */ +-#define LIBCURL_VERSION "7.19.7" ++#define LIBCURL_VERSION "7.64.1-DEV" + + /* The numeric version number is also available "in parts" by using these + defines: */ + #define LIBCURL_VERSION_MAJOR 7 +-#define LIBCURL_VERSION_MINOR 19 +-#define LIBCURL_VERSION_PATCH 7 ++#define LIBCURL_VERSION_MINOR 64 ++#define LIBCURL_VERSION_PATCH 1 + + /* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. ++ ++ Note: This define is the full hex number and _does not_ use the ++ CURL_VERSION_BITS() macro since curl's own configure script greps for it ++ and needs it to contain the full number. + */ +-#define LIBCURL_VERSION_NUM 0x071307 ++#define LIBCURL_VERSION_NUM 0x074001 + + /* + * This is the date and time when the full source package was created. The +- * timestamp is not stored in CVS, as the timestamp is properly set in the ++ * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * +- * The format of the date should follow this template: ++ * The format of the date follows this template: + * +- * "Mon Feb 12 11:35:33 UTC 2007" ++ * "2007-11-23" + */ +-#define LIBCURL_TIMESTAMP "Wed Nov 4 12:34:59 UTC 2009" ++#define LIBCURL_TIMESTAMP "[unreleased]" ++ ++#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) ++#define CURL_AT_LEAST_VERSION(x,y,z) \ ++ (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + + #endif /* __CURL_CURLVER_H */ +diff --git a/src/third_party/curl/easy.h b/src/third_party/curl/easy.h +--- a/src/third_party/curl/easy.h ++++ b/src/third_party/curl/easy.h +@@ -2,30 +2,29 @@ + #define __CURL_EASY_H + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * +- * $Id: easy.h,v 1.14 2008-05-12 21:43:28 bagder Exp $ + ***************************************************************************/ + #ifdef __cplusplus + extern "C" { + #endif + + CURL_EXTERN CURL *curl_easy_init(void); + CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); + CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +@@ -49,22 +48,22 @@ CURL_EXTERN CURLcode curl_easy_getinfo(C + + /* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and +- * options, internal state info and things like persistant connections cannot +- * be transfered. It is useful in multithreaded applications when you can run ++ * options, internal state info and things like persistent connections cannot ++ * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +-CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); ++CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + + /* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. +@@ -91,13 +90,23 @@ CURL_EXTERN CURLcode curl_easy_recv(CURL + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ + CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + ++ ++/* ++ * NAME curl_easy_upkeep() ++ * ++ * DESCRIPTION ++ * ++ * Performs connection upkeep for the given session handle. ++ */ ++CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); ++ + #ifdef __cplusplus + } + #endif + + #endif +diff --git a/src/third_party/curl/mprintf.h b/src/third_party/curl/mprintf.h +deleted file mode 100644 +--- a/src/third_party/curl/mprintf.h ++++ /dev/null +@@ -1,82 +0,0 @@ +-#ifndef __CURL_MPRINTF_H +-#define __CURL_MPRINTF_H +-/*************************************************************************** +- * _ _ ____ _ +- * Project ___| | | | _ \| | +- * / __| | | | |_) | | +- * | (__| |_| | _ <| |___ +- * \___|\___/|_| \_\_____| +- * +- * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. +- * +- * This software is licensed as described in the file COPYING, which +- * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. +- * +- * You may opt to use, copy, modify, merge, publish, distribute and/or sell +- * copies of the Software, and permit persons to whom the Software is +- * furnished to do so, under the terms of the COPYING file. +- * +- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +- * KIND, either express or implied. +- * +- * $Id: mprintf.h,v 1.16 2008-05-20 10:21:50 patrickm Exp $ +- ***************************************************************************/ +- +-#include +-#include /* needed for FILE */ +- +-#include "curl.h" +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-CURL_EXTERN int curl_mprintf(const char *format, ...); +-CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +-CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +-CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, +- const char *format, ...); +-CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +-CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +-CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +-CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, +- const char *format, va_list args); +-CURL_EXTERN char *curl_maprintf(const char *format, ...); +-CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); +- +-#ifdef _MPRINTF_REPLACE +-# undef printf +-# undef fprintf +-# undef sprintf +-# undef vsprintf +-# undef snprintf +-# undef vprintf +-# undef vfprintf +-# undef vsnprintf +-# undef aprintf +-# undef vaprintf +-# define printf curl_mprintf +-# define fprintf curl_mfprintf +-#ifdef CURLDEBUG +-/* When built with CURLDEBUG we define away the sprintf() functions since we +- don't want internal code to be using them */ +-# define sprintf sprintf_was_used +-# define vsprintf vsprintf_was_used +-#else +-# define sprintf curl_msprintf +-# define vsprintf curl_mvsprintf +-#endif +-# define snprintf curl_msnprintf +-# define vprintf curl_mvprintf +-# define vfprintf curl_mvfprintf +-# define vsnprintf curl_mvsnprintf +-# define aprintf curl_maprintf +-# define vaprintf curl_mvaprintf +-#endif +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /* __CURL_MPRINTF_H */ +diff --git a/src/third_party/curl/multi.h b/src/third_party/curl/multi.h +--- a/src/third_party/curl/multi.h ++++ b/src/third_party/curl/multi.h +@@ -2,30 +2,29 @@ + #define __CURL_MULTI_H + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * +- * $Id: multi.h,v 1.45 2008-05-20 10:21:50 patrickm Exp $ + ***************************************************************************/ + /* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. +@@ -48,36 +47,49 @@ + * but with this warning attached. + */ + #include "curl.h" + + #ifdef __cplusplus + extern "C" { + #endif + ++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) ++typedef struct Curl_multi CURLM; ++#else + typedef void CURLM; ++#endif + + typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ ++ CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was ++ attempted to get added - again */ ++ CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a ++ callback */ + CURLM_LAST + } CURLMcode; + + /* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ + #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + ++/* bitmask bits for CURLMOPT_PIPELINING */ ++#define CURLPIPE_NOTHING 0L ++#define CURLPIPE_HTTP1 1L ++#define CURLPIPE_MULTIPLEX 2L ++ + typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ + } CURLMSG; + + struct CURLMsg { +@@ -85,16 +97,29 @@ struct CURLMsg { + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; + }; + typedef struct CURLMsg CURLMsg; + ++/* Based on poll(2) structure and values. ++ * We don't use pollfd and POLL* constants explicitly ++ * to cover platforms without poll(). */ ++#define CURL_WAIT_POLLIN 0x0001 ++#define CURL_WAIT_POLLPRI 0x0002 ++#define CURL_WAIT_POLLOUT 0x0004 ++ ++struct curl_waitfd { ++ curl_socket_t fd; ++ short events; ++ short revents; /* not supported yet */ ++}; ++ + /* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ + CURL_EXTERN CURLM *curl_multi_init(void); +@@ -129,31 +154,45 @@ CURL_EXTERN CURLMcode curl_multi_remove_ + * Returns: CURLMcode type, general multi error code. + */ + CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + ++/* ++ * Name: curl_multi_wait() ++ * ++ * Desc: Poll on all fds within a CURLM set as well as any ++ * additional fds passed to the function. ++ * ++ * Returns: CURLMcode type, general multi error code. ++ */ ++CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, ++ struct curl_waitfd extra_fds[], ++ unsigned int extra_nfds, ++ int timeout_ms, ++ int *ret); ++ + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might +- * still have occurred problems on invidual transfers even when this +- * returns OK. ++ * still have occurred problems on individual transfers even when ++ * this returns OK. + */ + CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or +@@ -176,17 +215,17 @@ CURL_EXTERN CURLMcode curl_multi_cleanup + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain +- * very basic informations. If more involved information is wanted, ++ * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the +@@ -307,16 +346,47 @@ typedef enum { + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + ++ /* maximum number of (pipelining) connections to one host */ ++ CINIT(MAX_HOST_CONNECTIONS, LONG, 7), ++ ++ /* maximum number of requests in a pipeline */ ++ CINIT(MAX_PIPELINE_LENGTH, LONG, 8), ++ ++ /* a connection with a content-length longer than this ++ will not be considered for pipelining */ ++ CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), ++ ++ /* a connection with a chunk length longer than this ++ will not be considered for pipelining */ ++ CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), ++ ++ /* a list of site names(+port) that are blacklisted from ++ pipelining */ ++ CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), ++ ++ /* a list of server types that are blacklisted from ++ pipelining */ ++ CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), ++ ++ /* maximum number of open connections in total */ ++ CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), ++ ++ /* This is the server push callback function pointer */ ++ CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), ++ ++ /* This is the argument passed to the server push callback */ ++ CINIT(PUSHDATA, OBJECTPOINT, 15), ++ + CURLMOPT_LASTENTRY /* the last unused */ + } CURLMoption; + + + /* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. +@@ -334,13 +404,38 @@ CURL_EXTERN CURLMcode curl_multi_setopt( + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ + CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + ++ ++/* ++ * Name: curl_push_callback ++ * ++ * Desc: This callback gets called when a new stream is being pushed by the ++ * server. It approves or denies the new stream. ++ * ++ * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. ++ */ ++#define CURL_PUSH_OK 0 ++#define CURL_PUSH_DENY 1 ++ ++struct curl_pushheaders; /* forward declaration only */ ++ ++CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, ++ size_t num); ++CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, ++ const char *name); ++ ++typedef int (*curl_push_callback)(CURL *parent, ++ CURL *easy, ++ size_t num_headers, ++ struct curl_pushheaders *headers, ++ void *userp); ++ + #ifdef __cplusplus + } /* end of extern "C" */ + #endif + + #endif +diff --git a/src/third_party/curl/stdcheaders.h b/src/third_party/curl/stdcheaders.h +deleted file mode 100644 +--- a/src/third_party/curl/stdcheaders.h ++++ /dev/null +@@ -1,34 +0,0 @@ +-#ifndef __STDC_HEADERS_H +-#define __STDC_HEADERS_H +-/*************************************************************************** +- * _ _ ____ _ +- * Project ___| | | | _ \| | +- * / __| | | | |_) | | +- * | (__| |_| | _ <| |___ +- * \___|\___/|_| \_\_____| +- * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. +- * +- * This software is licensed as described in the file COPYING, which +- * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. +- * +- * You may opt to use, copy, modify, merge, publish, distribute and/or sell +- * copies of the Software, and permit persons to whom the Software is +- * furnished to do so, under the terms of the COPYING file. +- * +- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +- * KIND, either express or implied. +- * +- * $Id: stdcheaders.h,v 1.9 2009-05-18 12:25:45 yangtse Exp $ +- ***************************************************************************/ +- +-#include +- +-size_t fread (void *, size_t, size_t, FILE *); +-size_t fwrite (const void *, size_t, size_t, FILE *); +- +-int strcasecmp(const char *, const char *); +-int strncasecmp(const char *, const char *, size_t); +- +-#endif +diff --git a/src/third_party/curl/system.h b/src/third_party/curl/system.h +new file mode 100644 +--- /dev/null ++++ b/src/third_party/curl/system.h +@@ -0,0 +1,493 @@ ++#ifndef __CURL_SYSTEM_H ++#define __CURL_SYSTEM_H ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.haxx.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ ***************************************************************************/ ++ ++/* ++ * Try to keep one section per platform, compiler and architecture, otherwise, ++ * if an existing section is reused for a different one and later on the ++ * original is adjusted, probably the piggybacking one can be adversely ++ * changed. ++ * ++ * In order to differentiate between platforms/compilers/architectures use ++ * only compiler built in predefined preprocessor symbols. ++ * ++ * curl_off_t ++ * ---------- ++ * ++ * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit ++ * wide signed integral data type. The width of this data type must remain ++ * constant and independent of any possible large file support settings. ++ * ++ * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit ++ * wide signed integral data type if there is no 64-bit type. ++ * ++ * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall ++ * only be violated if off_t is the only 64-bit data type available and the ++ * size of off_t is independent of large file support settings. Keep your ++ * build on the safe side avoiding an off_t gating. If you have a 64-bit ++ * off_t then take for sure that another 64-bit data type exists, dig deeper ++ * and you will find it. ++ * ++ */ ++ ++#if defined(__DJGPP__) || defined(__GO32__) ++# if defined(__DJGPP__) && (__DJGPP__ > 1) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__SALFORDC__) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__BORLANDC__) ++# if (__BORLANDC__ < 0x520) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# else ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T i64 ++# define CURL_SUFFIX_CURL_OFF_TU ui64 ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__TURBOC__) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__WATCOMC__) ++# if defined(__386__) ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T i64 ++# define CURL_SUFFIX_CURL_OFF_TU ui64 ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__POCC__) ++# if (__POCC__ < 280) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# elif defined(_MSC_VER) ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T i64 ++# define CURL_SUFFIX_CURL_OFF_TU ui64 ++# else ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__LCC__) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__SYMBIAN32__) ++# if defined(__EABI__) /* Treat all ARM compilers equally */ ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(__CW32__) ++# pragma longlong on ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(__VC32__) ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int ++ ++#elif defined(__MWERKS__) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(_WIN32_WCE) ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T i64 ++# define CURL_SUFFIX_CURL_OFF_TU ui64 ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__MINGW32__) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_WS2TCPIP_H 1 ++ ++#elif defined(__VMS) ++# if defined(__VAX) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# else ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int ++ ++#elif defined(__OS400__) ++# if defined(__ILEC400__) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++# endif ++ ++#elif defined(__MVS__) ++# if defined(__IBMC__) || defined(__IBMCPP__) ++# if defined(_ILP32) ++# elif defined(_LP64) ++# endif ++# if defined(_LONG_LONG) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(_LP64) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++# endif ++ ++#elif defined(__370__) ++# if defined(__IBMC__) || defined(__IBMCPP__) ++# if defined(_ILP32) ++# elif defined(_LP64) ++# endif ++# if defined(_LONG_LONG) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(_LP64) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++# endif ++ ++#elif defined(TPF) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++#elif defined(__TINYC__) /* also known as tcc */ ++ ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++ ++#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ ++# if !defined(__LP64) && (defined(__ILP32) || \ ++ defined(__i386) || \ ++ defined(__sparcv8) || \ ++ defined(__sparcv8plus)) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(__LP64) || \ ++ defined(__amd64) || defined(__sparcv9) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++ ++#elif defined(__xlc__) /* IBM xlc compiler */ ++# if !defined(_LP64) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++ ++/* ===================================== */ ++/* KEEP MSVC THE PENULTIMATE ENTRY */ ++/* ===================================== */ ++ ++#elif defined(_MSC_VER) ++# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) ++# define CURL_TYPEOF_CURL_OFF_T __int64 ++# define CURL_FORMAT_CURL_OFF_T "I64d" ++# define CURL_FORMAT_CURL_OFF_TU "I64u" ++# define CURL_SUFFIX_CURL_OFF_T i64 ++# define CURL_SUFFIX_CURL_OFF_TU ui64 ++# else ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++ ++/* ===================================== */ ++/* KEEP GENERIC GCC THE LAST ENTRY */ ++/* ===================================== */ ++ ++#elif defined(__GNUC__) && !defined(_SCO_DS) ++# if !defined(__LP64__) && \ ++ (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ ++ defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ ++ defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ ++ defined(__XTENSA__) || \ ++ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ ++ (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) ++# define CURL_TYPEOF_CURL_OFF_T long long ++# define CURL_FORMAT_CURL_OFF_T "lld" ++# define CURL_FORMAT_CURL_OFF_TU "llu" ++# define CURL_SUFFIX_CURL_OFF_T LL ++# define CURL_SUFFIX_CURL_OFF_TU ULL ++# elif defined(__LP64__) || \ ++ defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ ++ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ ++ (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# endif ++# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t ++# define CURL_PULL_SYS_TYPES_H 1 ++# define CURL_PULL_SYS_SOCKET_H 1 ++ ++#else ++/* generic "safe guess" on old 32 bit style */ ++# define CURL_TYPEOF_CURL_OFF_T long ++# define CURL_FORMAT_CURL_OFF_T "ld" ++# define CURL_FORMAT_CURL_OFF_TU "lu" ++# define CURL_SUFFIX_CURL_OFF_T L ++# define CURL_SUFFIX_CURL_OFF_TU UL ++# define CURL_TYPEOF_CURL_SOCKLEN_T int ++#endif ++ ++#ifdef _AIX ++/* AIX needs */ ++#define CURL_PULL_SYS_POLL_H ++#endif ++ ++ ++/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ ++/* ws2tcpip.h is required here to properly make type definitions below. */ ++#ifdef CURL_PULL_WS2TCPIP_H ++# include ++# include ++# include ++#endif ++ ++/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ ++/* sys/types.h is required here to properly make type definitions below. */ ++#ifdef CURL_PULL_SYS_TYPES_H ++# include ++#endif ++ ++/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ ++/* sys/socket.h is required here to properly make type definitions below. */ ++#ifdef CURL_PULL_SYS_SOCKET_H ++# include ++#endif ++ ++/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ ++/* sys/poll.h is required here to properly make type definitions below. */ ++#ifdef CURL_PULL_SYS_POLL_H ++# include ++#endif ++ ++/* Data type definition of curl_socklen_t. */ ++#ifdef CURL_TYPEOF_CURL_SOCKLEN_T ++ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; ++#endif ++ ++/* Data type definition of curl_off_t. */ ++ ++#ifdef CURL_TYPEOF_CURL_OFF_T ++ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; ++#endif ++ ++/* ++ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow ++ * these to be visible and exported by the external libcurl interface API, ++ * while also making them visible to the library internals, simply including ++ * curl_setup.h, without actually needing to include curl.h internally. ++ * If some day this section would grow big enough, all this should be moved ++ * to its own header file. ++ */ ++ ++/* ++ * Figure out if we can use the ## preprocessor operator, which is supported ++ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ ++ * or __cplusplus so we need to carefully check for them too. ++ */ ++ ++#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ ++ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ ++ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ ++ defined(__ILEC400__) ++ /* This compiler is believed to have an ISO compatible preprocessor */ ++#define CURL_ISOCPP ++#else ++ /* This compiler is believed NOT to have an ISO compatible preprocessor */ ++#undef CURL_ISOCPP ++#endif ++ ++/* ++ * Macros for minimum-width signed and unsigned curl_off_t integer constants. ++ */ ++ ++#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) ++# define __CURL_OFF_T_C_HLPR2(x) x ++# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) ++# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ ++ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) ++# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ ++ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) ++#else ++# ifdef CURL_ISOCPP ++# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix ++# else ++# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix ++# endif ++# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) ++# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) ++# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) ++#endif ++ ++#endif /* __CURL_SYSTEM_H */ +diff --git a/src/third_party/curl/typecheck-gcc.h b/src/third_party/curl/typecheck-gcc.h +--- a/src/third_party/curl/typecheck-gcc.h ++++ b/src/third_party/curl/typecheck-gcc.h +@@ -2,111 +2,151 @@ + #define __CURL_TYPECHECK_GCC_H + /*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms +- * are also available at http://curl.haxx.se/docs/copyright.html. ++ * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * +- * $Id: typecheck-gcc.h,v 1.9 2009-01-25 23:26:31 bagder Exp $ + ***************************************************************************/ + + /* wraps curl_easy_setopt() with typechecking */ + + /* To add a new kind of warning, add an +- * if(_curl_is_sometype_option(_curl_opt) && ! _curl_is_sometype(value)) +- * _curl_easy_setopt_err_sometype(); ++ * if(_curl_is_sometype_option(_curl_opt)) ++ * if(!_curl_is_sometype(value)) ++ * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * ++ * NOTE: We use two nested 'if' statements here instead of the && operator, in ++ * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x ++ * when compiling with -Wlogical-op. ++ * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ + #define curl_easy_setopt(handle, option, value) \ + __extension__ ({ \ +- __typeof__ (option) _curl_opt = option; \ +- if (__builtin_constant_p(_curl_opt)) { \ +- if (_curl_is_long_option(_curl_opt) && !_curl_is_long(value)) \ +- _curl_easy_setopt_err_long(); \ +- if (_curl_is_off_t_option(_curl_opt) && !_curl_is_off_t(value)) \ +- _curl_easy_setopt_err_curl_off_t(); \ +- if (_curl_is_string_option(_curl_opt) && !_curl_is_string(value)) \ +- _curl_easy_setopt_err_string(); \ +- if (_curl_is_write_cb_option(_curl_opt) && !_curl_is_write_cb(value)) \ +- _curl_easy_setopt_err_write_callback(); \ +- if ((_curl_opt) == CURLOPT_READFUNCTION && !_curl_is_read_cb(value)) \ +- _curl_easy_setopt_err_read_cb(); \ +- if ((_curl_opt) == CURLOPT_IOCTLFUNCTION && !_curl_is_ioctl_cb(value)) \ +- _curl_easy_setopt_err_ioctl_cb(); \ +- if ((_curl_opt) == CURLOPT_SOCKOPTFUNCTION && !_curl_is_sockopt_cb(value))\ +- _curl_easy_setopt_err_sockopt_cb(); \ +- if ((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION && \ +- !_curl_is_opensocket_cb(value)) \ +- _curl_easy_setopt_err_opensocket_cb(); \ +- if ((_curl_opt) == CURLOPT_PROGRESSFUNCTION && \ +- !_curl_is_progress_cb(value)) \ +- _curl_easy_setopt_err_progress_cb(); \ +- if ((_curl_opt) == CURLOPT_DEBUGFUNCTION && !_curl_is_debug_cb(value)) \ +- _curl_easy_setopt_err_debug_cb(); \ +- if ((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION && \ +- !_curl_is_ssl_ctx_cb(value)) \ +- _curl_easy_setopt_err_ssl_ctx_cb(); \ +- if (_curl_is_conv_cb_option(_curl_opt) && !_curl_is_conv_cb(value)) \ +- _curl_easy_setopt_err_conv_cb(); \ +- if ((_curl_opt) == CURLOPT_SEEKFUNCTION && !_curl_is_seek_cb(value)) \ +- _curl_easy_setopt_err_seek_cb(); \ +- if (_curl_is_cb_data_option(_curl_opt) && !_curl_is_cb_data(value)) \ +- _curl_easy_setopt_err_cb_data(); \ +- if ((_curl_opt) == CURLOPT_ERRORBUFFER && !_curl_is_error_buffer(value)) \ +- _curl_easy_setopt_err_error_buffer(); \ +- if ((_curl_opt) == CURLOPT_STDERR && !_curl_is_FILE(value)) \ +- _curl_easy_setopt_err_FILE(); \ +- if (_curl_is_postfields_option(_curl_opt) && !_curl_is_postfields(value)) \ +- _curl_easy_setopt_err_postfields(); \ +- if ((_curl_opt) == CURLOPT_HTTPPOST && \ +- !_curl_is_arr((value), struct curl_httppost)) \ +- _curl_easy_setopt_err_curl_httpost(); \ +- if (_curl_is_slist_option(_curl_opt) && \ +- !_curl_is_arr((value), struct curl_slist)) \ +- _curl_easy_setopt_err_curl_slist(); \ +- if ((_curl_opt) == CURLOPT_SHARE && !_curl_is_ptr((value), CURLSH)) \ +- _curl_easy_setopt_err_CURLSH(); \ ++ __typeof__(option) _curl_opt = option; \ ++ if(__builtin_constant_p(_curl_opt)) { \ ++ if(_curl_is_long_option(_curl_opt)) \ ++ if(!_curl_is_long(value)) \ ++ _curl_easy_setopt_err_long(); \ ++ if(_curl_is_off_t_option(_curl_opt)) \ ++ if(!_curl_is_off_t(value)) \ ++ _curl_easy_setopt_err_curl_off_t(); \ ++ if(_curl_is_string_option(_curl_opt)) \ ++ if(!_curl_is_string(value)) \ ++ _curl_easy_setopt_err_string(); \ ++ if(_curl_is_write_cb_option(_curl_opt)) \ ++ if(!_curl_is_write_cb(value)) \ ++ _curl_easy_setopt_err_write_callback(); \ ++ if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ ++ if(!_curl_is_resolver_start_callback(value)) \ ++ _curl_easy_setopt_err_resolver_start_callback(); \ ++ if((_curl_opt) == CURLOPT_READFUNCTION) \ ++ if(!_curl_is_read_cb(value)) \ ++ _curl_easy_setopt_err_read_cb(); \ ++ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ ++ if(!_curl_is_ioctl_cb(value)) \ ++ _curl_easy_setopt_err_ioctl_cb(); \ ++ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ ++ if(!_curl_is_sockopt_cb(value)) \ ++ _curl_easy_setopt_err_sockopt_cb(); \ ++ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ ++ if(!_curl_is_opensocket_cb(value)) \ ++ _curl_easy_setopt_err_opensocket_cb(); \ ++ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ ++ if(!_curl_is_progress_cb(value)) \ ++ _curl_easy_setopt_err_progress_cb(); \ ++ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ ++ if(!_curl_is_debug_cb(value)) \ ++ _curl_easy_setopt_err_debug_cb(); \ ++ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ ++ if(!_curl_is_ssl_ctx_cb(value)) \ ++ _curl_easy_setopt_err_ssl_ctx_cb(); \ ++ if(_curl_is_conv_cb_option(_curl_opt)) \ ++ if(!_curl_is_conv_cb(value)) \ ++ _curl_easy_setopt_err_conv_cb(); \ ++ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ ++ if(!_curl_is_seek_cb(value)) \ ++ _curl_easy_setopt_err_seek_cb(); \ ++ if(_curl_is_cb_data_option(_curl_opt)) \ ++ if(!_curl_is_cb_data(value)) \ ++ _curl_easy_setopt_err_cb_data(); \ ++ if((_curl_opt) == CURLOPT_ERRORBUFFER) \ ++ if(!_curl_is_error_buffer(value)) \ ++ _curl_easy_setopt_err_error_buffer(); \ ++ if((_curl_opt) == CURLOPT_STDERR) \ ++ if(!_curl_is_FILE(value)) \ ++ _curl_easy_setopt_err_FILE(); \ ++ if(_curl_is_postfields_option(_curl_opt)) \ ++ if(!_curl_is_postfields(value)) \ ++ _curl_easy_setopt_err_postfields(); \ ++ if((_curl_opt) == CURLOPT_HTTPPOST) \ ++ if(!_curl_is_arr((value), struct curl_httppost)) \ ++ _curl_easy_setopt_err_curl_httpost(); \ ++ if((_curl_opt) == CURLOPT_MIMEPOST) \ ++ if(!_curl_is_ptr((value), curl_mime)) \ ++ _curl_easy_setopt_err_curl_mimepost(); \ ++ if(_curl_is_slist_option(_curl_opt)) \ ++ if(!_curl_is_arr((value), struct curl_slist)) \ ++ _curl_easy_setopt_err_curl_slist(); \ ++ if((_curl_opt) == CURLOPT_SHARE) \ ++ if(!_curl_is_ptr((value), CURLSH)) \ ++ _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ + }) + + /* wraps curl_easy_getinfo() with typechecking */ + /* FIXME: don't allow const pointers */ + #define curl_easy_getinfo(handle, info, arg) \ + __extension__ ({ \ +- __typeof__ (info) _curl_info = info; \ +- if (__builtin_constant_p(_curl_info)) { \ +- if (_curl_is_string_info(_curl_info) && !_curl_is_arr((arg), char *)) \ +- _curl_easy_getinfo_err_string(); \ +- if (_curl_is_long_info(_curl_info) && !_curl_is_arr((arg), long)) \ +- _curl_easy_getinfo_err_long(); \ +- if (_curl_is_double_info(_curl_info) && !_curl_is_arr((arg), double)) \ +- _curl_easy_getinfo_err_double(); \ +- if (_curl_is_slist_info(_curl_info) && \ +- !_curl_is_arr((arg), struct curl_slist *)) \ +- _curl_easy_getinfo_err_curl_slist(); \ ++ __typeof__(info) _curl_info = info; \ ++ if(__builtin_constant_p(_curl_info)) { \ ++ if(_curl_is_string_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), char *)) \ ++ _curl_easy_getinfo_err_string(); \ ++ if(_curl_is_long_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), long)) \ ++ _curl_easy_getinfo_err_long(); \ ++ if(_curl_is_double_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), double)) \ ++ _curl_easy_getinfo_err_double(); \ ++ if(_curl_is_slist_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), struct curl_slist *)) \ ++ _curl_easy_getinfo_err_curl_slist(); \ ++ if(_curl_is_tlssessioninfo_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ ++ _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ ++ if(_curl_is_certinfo_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), struct curl_certinfo *)) \ ++ _curl_easy_getinfo_err_curl_certinfo(); \ ++ if(_curl_is_socket_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), curl_socket_t)) \ ++ _curl_easy_getinfo_err_curl_socket(); \ ++ if(_curl_is_off_t_info(_curl_info)) \ ++ if(!_curl_is_arr((arg), curl_off_t)) \ ++ _curl_easy_getinfo_err_curl_off_t(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ + }) + + /* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +@@ -114,70 +154,93 @@ + #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + + /* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + + /* To define a new warning, use _CURL_WARNING(identifier, "message") */ + #define _CURL_WARNING(id, message) \ +- static void __attribute__((warning(message))) __attribute__((unused)) \ +- __attribute__((noinline)) id(void) { __asm__(""); } ++ static void __attribute__((__warning__(message))) \ ++ __attribute__((__unused__)) __attribute__((__noinline__)) \ ++ id(void) { __asm__(""); } + + _CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_string, +- "curl_easy_setopt expects a string (char* or char[]) argument for this option" ++ "curl_easy_setopt expects a " ++ "string ('char *' or char[]) argument for this option" + ) + _CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") ++_CURL_WARNING(_curl_easy_setopt_err_resolver_start_callback, ++ "curl_easy_setopt expects a " ++ "curl_resolver_start_callback argument for this option" ++ ) + _CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, +- "curl_easy_setopt expects a curl_opensocket_callback argument for this option" ++ "curl_easy_setopt expects a " ++ "curl_opensocket_callback argument for this option" + ) + _CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_cb_data, +- "curl_easy_setopt expects a private data pointer as argument for this option") ++ "curl_easy_setopt expects a " ++ "private data pointer as argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_error_buffer, +- "curl_easy_setopt expects a char buffer of CURL_ERROR_SIZE as argument for this option") ++ "curl_easy_setopt expects a " ++ "char buffer of CURL_ERROR_SIZE as argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_FILE, +- "curl_easy_setopt expects a FILE* argument for this option") ++ "curl_easy_setopt expects a 'FILE *' argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_postfields, +- "curl_easy_setopt expects a void* or char* argument for this option") ++ "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_curl_httpost, +- "curl_easy_setopt expects a struct curl_httppost* argument for this option") ++ "curl_easy_setopt expects a 'struct curl_httppost *' " ++ "argument for this option") ++_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, ++ "curl_easy_setopt expects a 'curl_mime *' " ++ "argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_curl_slist, +- "curl_easy_setopt expects a struct curl_slist* argument for this option") ++ "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") + _CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + + _CURL_WARNING(_curl_easy_getinfo_err_string, +- "curl_easy_getinfo expects a pointer to char * for this info") ++ "curl_easy_getinfo expects a pointer to 'char *' for this info") + _CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") + _CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") + _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, +- "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") ++ "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") ++_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, ++ "curl_easy_getinfo expects a pointer to " ++ "'struct curl_tlssessioninfo *' for this info") ++_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, ++ "curl_easy_getinfo expects a pointer to " ++ "'struct curl_certinfo *' for this info") ++_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, ++ "curl_easy_getinfo expects a pointer to curl_socket_t for this info") ++_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, ++ "curl_easy_getinfo expects a pointer to curl_off_t for this info") + + /* groups of curl_easy_setops options that take the same type of argument */ + + /* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ +@@ -186,97 +249,145 @@ + #define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + + #define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + + /* evaluates to true if option takes a char* argument */ + #define _curl_is_string_option(option) \ +- ((option) == CURLOPT_URL || \ +- (option) == CURLOPT_PROXY || \ +- (option) == CURLOPT_INTERFACE || \ +- (option) == CURLOPT_NETRC_FILE || \ +- (option) == CURLOPT_USERPWD || \ +- (option) == CURLOPT_USERNAME || \ +- (option) == CURLOPT_PASSWORD || \ +- (option) == CURLOPT_PROXYUSERPWD || \ +- (option) == CURLOPT_PROXYUSERNAME || \ +- (option) == CURLOPT_PROXYPASSWORD || \ +- (option) == CURLOPT_NOPROXY || \ +- (option) == CURLOPT_ENCODING || \ +- (option) == CURLOPT_REFERER || \ +- (option) == CURLOPT_USERAGENT || \ ++ ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ ++ (option) == CURLOPT_ACCEPT_ENCODING || \ ++ (option) == CURLOPT_ALTSVC || \ ++ (option) == CURLOPT_CAINFO || \ ++ (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ ++ (option) == CURLOPT_CRLFILE || \ ++ (option) == CURLOPT_CUSTOMREQUEST || \ ++ (option) == CURLOPT_DEFAULT_PROTOCOL || \ ++ (option) == CURLOPT_DNS_INTERFACE || \ ++ (option) == CURLOPT_DNS_LOCAL_IP4 || \ ++ (option) == CURLOPT_DNS_LOCAL_IP6 || \ ++ (option) == CURLOPT_DNS_SERVERS || \ ++ (option) == CURLOPT_DOH_URL || \ ++ (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ +- (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_FTP_ACCOUNT || \ ++ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ ++ (option) == CURLOPT_INTERFACE || \ ++ (option) == CURLOPT_ISSUERCERT || \ ++ (option) == CURLOPT_KEYPASSWD || \ ++ (option) == CURLOPT_KRBLEVEL || \ ++ (option) == CURLOPT_LOGIN_OPTIONS || \ ++ (option) == CURLOPT_MAIL_AUTH || \ ++ (option) == CURLOPT_MAIL_FROM || \ ++ (option) == CURLOPT_NETRC_FILE || \ ++ (option) == CURLOPT_NOPROXY || \ ++ (option) == CURLOPT_PASSWORD || \ ++ (option) == CURLOPT_PINNEDPUBLICKEY || \ ++ (option) == CURLOPT_PRE_PROXY || \ ++ (option) == CURLOPT_PROXY || \ ++ (option) == CURLOPT_PROXYPASSWORD || \ ++ (option) == CURLOPT_PROXYUSERNAME || \ ++ (option) == CURLOPT_PROXYUSERPWD || \ ++ (option) == CURLOPT_PROXY_CAINFO || \ ++ (option) == CURLOPT_PROXY_CAPATH || \ ++ (option) == CURLOPT_PROXY_CRLFILE || \ ++ (option) == CURLOPT_PROXY_KEYPASSWD || \ ++ (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ ++ (option) == CURLOPT_PROXY_SERVICE_NAME || \ ++ (option) == CURLOPT_PROXY_SSLCERT || \ ++ (option) == CURLOPT_PROXY_SSLCERTTYPE || \ ++ (option) == CURLOPT_PROXY_SSLKEY || \ ++ (option) == CURLOPT_PROXY_SSLKEYTYPE || \ ++ (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ ++ (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ ++ (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ ++ (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ ++ (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ +- (option) == CURLOPT_CUSTOMREQUEST || \ ++ (option) == CURLOPT_REFERER || \ ++ (option) == CURLOPT_RTSP_SESSION_ID || \ ++ (option) == CURLOPT_RTSP_STREAM_URI || \ ++ (option) == CURLOPT_RTSP_TRANSPORT || \ ++ (option) == CURLOPT_SERVICE_NAME || \ ++ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ ++ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ ++ (option) == CURLOPT_SSH_KNOWNHOSTS || \ ++ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ ++ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ ++ (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ +- (option) == CURLOPT_KEYPASSWD || \ +- (option) == CURLOPT_SSLENGINE || \ +- (option) == CURLOPT_CAINFO || \ +- (option) == CURLOPT_CAPATH || \ +- (option) == CURLOPT_RANDOM_FILE || \ +- (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ +- (option) == CURLOPT_KRBLEVEL || \ +- (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ +- (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ +- (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ +- (option) == CURLOPT_CRLFILE || \ +- (option) == CURLOPT_ISSUERCERT || \ ++ (option) == CURLOPT_TLSAUTH_PASSWORD || \ ++ (option) == CURLOPT_TLSAUTH_TYPE || \ ++ (option) == CURLOPT_TLSAUTH_USERNAME || \ ++ (option) == CURLOPT_UNIX_SOCKET_PATH || \ ++ (option) == CURLOPT_URL || \ ++ (option) == CURLOPT_USERAGENT || \ ++ (option) == CURLOPT_USERNAME || \ ++ (option) == CURLOPT_USERPWD || \ ++ (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + + /* evaluates to true if option takes a curl_write_callback argument */ + #define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + + /* evaluates to true if option takes a curl_conv_callback argument */ + #define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + + /* evaluates to true if option takes a data argument to pass to a callback */ + #define _curl_is_cb_data_option(option) \ +- ((option) == CURLOPT_WRITEDATA || \ +- (option) == CURLOPT_READDATA || \ ++ ((option) == CURLOPT_CHUNK_DATA || \ ++ (option) == CURLOPT_CLOSESOCKETDATA || \ ++ (option) == CURLOPT_DEBUGDATA || \ ++ (option) == CURLOPT_FNMATCH_DATA || \ ++ (option) == CURLOPT_HEADERDATA || \ ++ (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ +- (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ ++ (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ +- (option) == CURLOPT_WRITEHEADER || \ +- (option) == CURLOPT_DEBUGDATA || \ ++ (option) == CURLOPT_READDATA || \ ++ (option) == CURLOPT_SEEKDATA || \ ++ (option) == CURLOPT_SOCKOPTDATA || \ ++ (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ +- (option) == CURLOPT_SEEKDATA || \ +- (option) == CURLOPT_PRIVATE || \ ++ (option) == CURLOPT_WRITEDATA || \ ++ (option) == CURLOPT_RESOLVER_START_DATA || \ ++ (option) == CURLOPT_CURLU || \ + 0) + + /* evaluates to true if option takes a POST data argument (void* or char*) */ + #define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + + /* evaluates to true if option takes a struct curl_slist * argument */ + #define _curl_is_slist_option(option) \ +- ((option) == CURLOPT_HTTPHEADER || \ +- (option) == CURLOPT_HTTP200ALIASES || \ +- (option) == CURLOPT_QUOTE || \ ++ ((option) == CURLOPT_HTTP200ALIASES || \ ++ (option) == CURLOPT_HTTPHEADER || \ ++ (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ ++ (option) == CURLOPT_PROXYHEADER || \ ++ (option) == CURLOPT_QUOTE || \ ++ (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + + /* groups of curl_easy_getinfo infos that take the same type of argument */ + + /* evaluates to true if info expects a pointer to char * argument */ + #define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) +@@ -285,34 +396,49 @@ + #define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + + /* evaluates to true if info expects a pointer to double argument */ + #define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + + /* true if info expects a pointer to struct curl_slist * argument */ +-#define _curl_is_slist_info(info) \ +- (CURLINFO_SLIST < (info)) ++#define _curl_is_slist_info(info) \ ++ (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) ++ ++/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ ++#define _curl_is_tlssessioninfo_info(info) \ ++ (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) ++ ++/* true if info expects a pointer to struct curl_certinfo * argument */ ++#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) ++ ++/* true if info expects a pointer to struct curl_socket_t argument */ ++#define _curl_is_socket_info(info) \ ++ (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) ++ ++/* true if info expects a pointer to curl_off_t argument */ ++#define _curl_is_off_t_info(info) \ ++ (CURLINFO_OFF_T < (info)) + + + /* typecheck helpers -- check whether given expression has requested type*/ + + /* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +-/* XXX: should evaluate to true iff expr is a pointer */ ++/* XXX: should evaluate to true if expr is a pointer */ + #define _curl_is_any_ptr(expr) \ +- (sizeof(expr) == sizeof(void*)) ++ (sizeof(expr) == sizeof(void *)) + + /* evaluates to true if expr is NULL */ + /* XXX: must not evaluate expr, so this check is not accurate */ + #define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + + /* evaluates to true if expr is type*, const type* or NULL */ + #define _curl_is_ptr(expr, type) \ +@@ -350,202 +476,225 @@ + + /* evaluates to true if expr is of type curl_off_t */ + #define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + + /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ + /* XXX: also check size of an char[] array? */ + #define _curl_is_error_buffer(expr) \ +- (__builtin_types_compatible_p(__typeof__(expr), char *) || \ ++ (_curl_is_NULL(expr) || \ ++ __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + + /* evaluates to true if expr is of type (const) void* or (const) FILE* */ + #if 0 + #define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) + #else /* be less strict */ + #define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) + #endif + + /* evaluates to true if expr is of type FILE* */ +-#define _curl_is_FILE(expr) \ +- (__builtin_types_compatible_p(__typeof__(expr), FILE *)) ++#define _curl_is_FILE(expr) \ ++ (_curl_is_NULL(expr) || \ ++ (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + + /* evaluates to true if expr can be passed as POST data (void* or char*) */ + #define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ +- _curl_is_arr((expr), char)) ++ _curl_is_arr((expr), char) || \ ++ _curl_is_arr((expr), unsigned char)) + + /* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ + /* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ + #define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ +- __builtin_types_compatible_p(__typeof__(func), type*)) ++ __builtin_types_compatible_p(__typeof__(func) *, type)) ++ ++/* evaluates to true if expr is of type curl_resolver_start_callback */ ++#define _curl_is_resolver_start_callback(expr) \ ++ (_curl_is_NULL(expr) || \ ++ _curl_callback_compatible((expr), curl_resolver_start_callback)) + + /* evaluates to true if expr is of type curl_read_callback or "similar" */ + #define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ ++ _curl_callback_compatible((expr), __typeof__(fread) *) || \ ++ _curl_callback_compatible((expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +-typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); +-typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); +-typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); +-typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); +-typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); +-typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); ++typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); ++typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); ++typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); ++typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); ++typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); ++typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + + /* evaluates to true if expr is of type curl_write_callback or "similar" */ + #define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ ++ _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ ++ _curl_callback_compatible((expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +-typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +-typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, +- const void*); +-typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); +-typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); +-typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, +- const void*); +-typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); ++typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); ++typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, ++ const void *); ++typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); ++typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); ++typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, ++ const void *); ++typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + + /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ + #define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ ++ _curl_callback_compatible((expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +-typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); +-typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); +-typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); +-typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); ++typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); ++typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); ++typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); ++typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + + /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ + #define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ ++ _curl_callback_compatible((expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +-typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +-typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, ++typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); ++typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +-/* evaluates to true if expr is of type curl_opensocket_callback or "similar" */ ++/* evaluates to true if expr is of type curl_opensocket_callback or ++ "similar" */ + #define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ ++ _curl_callback_compatible((expr), curl_opensocket_callback) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +-typedef curl_socket_t (_curl_opensocket_callback1) ++typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +-typedef curl_socket_t (_curl_opensocket_callback2) ++typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +-typedef curl_socket_t (_curl_opensocket_callback3) ++typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +-typedef curl_socket_t (_curl_opensocket_callback4) ++typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + + /* evaluates to true if expr is of type curl_progress_callback or "similar" */ + #define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ ++ _curl_callback_compatible((expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +-typedef int (_curl_progress_callback1)(void *, ++typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +-typedef int (_curl_progress_callback2)(const void *, ++typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + + /* evaluates to true if expr is of type curl_debug_callback or "similar" */ + #define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ ++ _curl_callback_compatible((expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ +- _curl_callback_compatible((expr), _curl_debug_callback4)) +-typedef int (_curl_debug_callback1) (CURL *, ++ _curl_callback_compatible((expr), _curl_debug_callback4) || \ ++ _curl_callback_compatible((expr), _curl_debug_callback5) || \ ++ _curl_callback_compatible((expr), _curl_debug_callback6) || \ ++ _curl_callback_compatible((expr), _curl_debug_callback7) || \ ++ _curl_callback_compatible((expr), _curl_debug_callback8)) ++typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +-typedef int (_curl_debug_callback2) (CURL *, ++typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +-typedef int (_curl_debug_callback3) (CURL *, ++typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +-typedef int (_curl_debug_callback4) (CURL *, ++typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); ++typedef int (*_curl_debug_callback5) (CURL *, ++ curl_infotype, unsigned char *, size_t, void *); ++typedef int (*_curl_debug_callback6) (CURL *, ++ curl_infotype, unsigned char *, size_t, const void *); ++typedef int (*_curl_debug_callback7) (CURL *, ++ curl_infotype, const unsigned char *, size_t, void *); ++typedef int (*_curl_debug_callback8) (CURL *, ++ curl_infotype, const unsigned char *, size_t, const void *); + + /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ + /* this is getting even messier... */ + #define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ ++ _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +-typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +-typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +-typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +-typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); ++typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); ++typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); ++typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); ++typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, ++ const void *); + #ifdef HEADER_SSL_H + /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +-typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +-typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +-typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +-typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, const void *); ++typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); ++typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); ++typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); ++typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, ++ const void *); + #else + typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; + typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; + typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; + typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; + #endif + + /* evaluates to true if expr is of type curl_conv_callback or "similar" */ + #define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ ++ _curl_callback_compatible((expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) + typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); + typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); + typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); + typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + + /* evaluates to true if expr is of type curl_seek_callback or "similar" */ + #define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ +- __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ ++ _curl_callback_compatible((expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) + typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); + typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + + #endif /* __CURL_TYPECHECK_GCC_H */ +diff --git a/src/third_party/curl/types.h b/src/third_party/curl/types.h +deleted file mode 100644 +--- a/src/third_party/curl/types.h ++++ /dev/null +@@ -1,1 +0,0 @@ +-/* not used */ +diff --git a/src/third_party/curl/urlapi.h b/src/third_party/curl/urlapi.h +new file mode 100644 +--- /dev/null ++++ b/src/third_party/curl/urlapi.h +@@ -0,0 +1,122 @@ ++#ifndef __CURL_URLAPI_H ++#define __CURL_URLAPI_H ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.haxx.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ ***************************************************************************/ ++ ++#include "curl.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* the error codes for the URL API */ ++typedef enum { ++ CURLUE_OK, ++ CURLUE_BAD_HANDLE, /* 1 */ ++ CURLUE_BAD_PARTPOINTER, /* 2 */ ++ CURLUE_MALFORMED_INPUT, /* 3 */ ++ CURLUE_BAD_PORT_NUMBER, /* 4 */ ++ CURLUE_UNSUPPORTED_SCHEME, /* 5 */ ++ CURLUE_URLDECODE, /* 6 */ ++ CURLUE_OUT_OF_MEMORY, /* 7 */ ++ CURLUE_USER_NOT_ALLOWED, /* 8 */ ++ CURLUE_UNKNOWN_PART, /* 9 */ ++ CURLUE_NO_SCHEME, /* 10 */ ++ CURLUE_NO_USER, /* 11 */ ++ CURLUE_NO_PASSWORD, /* 12 */ ++ CURLUE_NO_OPTIONS, /* 13 */ ++ CURLUE_NO_HOST, /* 14 */ ++ CURLUE_NO_PORT, /* 15 */ ++ CURLUE_NO_QUERY, /* 16 */ ++ CURLUE_NO_FRAGMENT /* 17 */ ++} CURLUcode; ++ ++typedef enum { ++ CURLUPART_URL, ++ CURLUPART_SCHEME, ++ CURLUPART_USER, ++ CURLUPART_PASSWORD, ++ CURLUPART_OPTIONS, ++ CURLUPART_HOST, ++ CURLUPART_PORT, ++ CURLUPART_PATH, ++ CURLUPART_QUERY, ++ CURLUPART_FRAGMENT ++} CURLUPart; ++ ++#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ ++#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, ++ if the port number matches the ++ default for the scheme */ ++#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if ++ missing */ ++#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ ++#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ ++#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ ++#define CURLU_URLDECODE (1<<6) /* URL decode on get */ ++#define CURLU_URLENCODE (1<<7) /* URL encode on set */ ++#define CURLU_APPENDQUERY (1<<8) /* append a form style part */ ++#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ ++ ++typedef struct Curl_URL CURLU; ++ ++/* ++ * curl_url() creates a new CURLU handle and returns a pointer to it. ++ * Must be freed with curl_url_cleanup(). ++ */ ++CURL_EXTERN CURLU *curl_url(void); ++ ++/* ++ * curl_url_cleanup() frees the CURLU handle and related resources used for ++ * the URL parsing. It will not free strings previously returned with the URL ++ * API. ++ */ ++CURL_EXTERN void curl_url_cleanup(CURLU *handle); ++ ++/* ++ * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new ++ * handle must also be freed with curl_url_cleanup(). ++ */ ++CURL_EXTERN CURLU *curl_url_dup(CURLU *in); ++ ++/* ++ * curl_url_get() extracts a specific part of the URL from a CURLU ++ * handle. Returns error code. The returned pointer MUST be freed with ++ * curl_free() afterwards. ++ */ ++CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, ++ char **part, unsigned int flags); ++ ++/* ++ * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns ++ * error code. The passed in string will be copied. Passing a NULL instead of ++ * a part string, clears that part. ++ */ ++CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, ++ const char *part, unsigned int flags); ++ ++ ++#ifdef __cplusplus ++} /* end of extern "C" */ ++#endif ++ ++#endif +diff --git a/src/third_party/musl/include/elf.h b/src/third_party/musl/include/elf.h +--- a/src/third_party/musl/include/elf.h ++++ b/src/third_party/musl/include/elf.h +@@ -205,23 +205,123 @@ typedef struct { + #define EM_D10V 85 + #define EM_D30V 86 + #define EM_V850 87 + #define EM_M32R 88 + #define EM_MN10300 89 + #define EM_MN10200 90 + #define EM_PJ 91 + #define EM_OR1K 92 ++#define EM_OPENRISC 92 + #define EM_ARC_A5 93 ++#define EM_ARC_COMPACT 93 + #define EM_XTENSA 94 ++#define EM_VIDEOCORE 95 ++#define EM_TMM_GPP 96 ++#define EM_NS32K 97 ++#define EM_TPC 98 ++#define EM_SNP1K 99 ++#define EM_ST200 100 ++#define EM_IP2K 101 ++#define EM_MAX 102 ++#define EM_CR 103 ++#define EM_F2MC16 104 ++#define EM_MSP430 105 ++#define EM_BLACKFIN 106 ++#define EM_SE_C33 107 ++#define EM_SEP 108 ++#define EM_ARCA 109 ++#define EM_UNICORE 110 ++#define EM_EXCESS 111 ++#define EM_DXP 112 ++#define EM_ALTERA_NIOS2 113 ++#define EM_CRX 114 ++#define EM_XGATE 115 ++#define EM_C166 116 ++#define EM_M16C 117 ++#define EM_DSPIC30F 118 ++#define EM_CE 119 ++#define EM_M32C 120 ++#define EM_TSK3000 131 ++#define EM_RS08 132 ++#define EM_SHARC 133 ++#define EM_ECOG2 134 ++#define EM_SCORE7 135 ++#define EM_DSP24 136 ++#define EM_VIDEOCORE3 137 ++#define EM_LATTICEMICO32 138 ++#define EM_SE_C17 139 ++#define EM_TI_C6000 140 ++#define EM_TI_C2000 141 ++#define EM_TI_C5500 142 ++#define EM_TI_ARP32 143 ++#define EM_TI_PRU 144 ++#define EM_MMDSP_PLUS 160 ++#define EM_CYPRESS_M8C 161 ++#define EM_R32C 162 ++#define EM_TRIMEDIA 163 ++#define EM_QDSP6 164 ++#define EM_8051 165 ++#define EM_STXP7X 166 ++#define EM_NDS32 167 ++#define EM_ECOG1X 168 ++#define EM_MAXQ30 169 ++#define EM_XIMO16 170 ++#define EM_MANIK 171 ++#define EM_CRAYNV2 172 ++#define EM_RX 173 ++#define EM_METAG 174 ++#define EM_MCST_ELBRUS 175 ++#define EM_ECOG16 176 ++#define EM_CR16 177 ++#define EM_ETPU 178 ++#define EM_SLE9X 179 ++#define EM_L10M 180 ++#define EM_K10M 181 + #define EM_AARCH64 183 ++#define EM_AVR32 185 ++#define EM_STM8 186 ++#define EM_TILE64 187 + #define EM_TILEPRO 188 + #define EM_MICROBLAZE 189 ++#define EM_CUDA 190 + #define EM_TILEGX 191 +-#define EM_NUM 192 ++#define EM_CLOUDSHIELD 192 ++#define EM_COREA_1ST 193 ++#define EM_COREA_2ND 194 ++#define EM_ARC_COMPACT2 195 ++#define EM_OPEN8 196 ++#define EM_RL78 197 ++#define EM_VIDEOCORE5 198 ++#define EM_78KOR 199 ++#define EM_56800EX 200 ++#define EM_BA1 201 ++#define EM_BA2 202 ++#define EM_XCORE 203 ++#define EM_MCHP_PIC 204 ++#define EM_KM32 210 ++#define EM_KMX32 211 ++#define EM_EMX16 212 ++#define EM_EMX8 213 ++#define EM_KVARC 214 ++#define EM_CDP 215 ++#define EM_COGE 216 ++#define EM_COOL 217 ++#define EM_NORC 218 ++#define EM_CSR_KALIMBA 219 ++#define EM_Z80 220 ++#define EM_VISIUM 221 ++#define EM_FT32 222 ++#define EM_MOXIE 223 ++#define EM_AMDGPU 224 ++#define EM_RISCV 243 ++#define EM_BPF 247 ++#define EM_CSKY 252 ++#define EM_NUM 253 ++ + #define EM_ALPHA 0x9026 + + #define EV_NONE 0 + #define EV_CURRENT 1 + #define EV_NUM 2 + + typedef struct { + Elf32_Word sh_name; +@@ -311,21 +411,42 @@ typedef struct { + #define SHF_MERGE (1 << 4) + #define SHF_STRINGS (1 << 5) + #define SHF_INFO_LINK (1 << 6) + #define SHF_LINK_ORDER (1 << 7) + #define SHF_OS_NONCONFORMING (1 << 8) + + #define SHF_GROUP (1 << 9) + #define SHF_TLS (1 << 10) ++#define SHF_COMPRESSED (1 << 11) + #define SHF_MASKOS 0x0ff00000 + #define SHF_MASKPROC 0xf0000000 + #define SHF_ORDERED (1 << 30) + #define SHF_EXCLUDE (1U << 31) + ++typedef struct { ++ Elf32_Word ch_type; ++ Elf32_Word ch_size; ++ Elf32_Word ch_addralign; ++} Elf32_Chdr; ++ ++typedef struct { ++ Elf64_Word ch_type; ++ Elf64_Word ch_reserved; ++ Elf64_Xword ch_size; ++ Elf64_Xword ch_addralign; ++} Elf64_Chdr; ++ ++#define ELFCOMPRESS_ZLIB 1 ++#define ELFCOMPRESS_LOOS 0x60000000 ++#define ELFCOMPRESS_HIOS 0x6fffffff ++#define ELFCOMPRESS_LOPROC 0x70000000 ++#define ELFCOMPRESS_HIPROC 0x7fffffff ++ ++ + #define GRP_COMDAT 0x1 + + typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; +@@ -404,18 +525,17 @@ typedef struct { + #define STV_DEFAULT 0 + #define STV_INTERNAL 1 + #define STV_HIDDEN 2 + #define STV_PROTECTED 3 + + + + +-typedef struct +-{ ++typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + } Elf32_Rel; + + typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + } Elf64_Rel; +@@ -499,16 +619,17 @@ typedef struct { + #define PF_W (1 << 1) + #define PF_R (1 << 2) + #define PF_MASKOS 0x0ff00000 + #define PF_MASKPROC 0xf0000000 + + + + #define NT_PRSTATUS 1 ++#define NT_PRFPREG 2 + #define NT_FPREGSET 2 + #define NT_PRPSINFO 3 + #define NT_PRXREG 4 + #define NT_TASKSTRUCT 4 + #define NT_PLATFORM 5 + #define NT_AUXV 6 + #define NT_GWINDOWS 7 + #define NT_ASRS 8 +@@ -520,35 +641,61 @@ typedef struct { + #define NT_LWPSINFO 17 + #define NT_PRFPXREG 20 + #define NT_SIGINFO 0x53494749 + #define NT_FILE 0x46494c45 + #define NT_PRXFPREG 0x46e62b7f + #define NT_PPC_VMX 0x100 + #define NT_PPC_SPE 0x101 + #define NT_PPC_VSX 0x102 ++#define NT_PPC_TAR 0x103 ++#define NT_PPC_PPR 0x104 ++#define NT_PPC_DSCR 0x105 ++#define NT_PPC_EBB 0x106 ++#define NT_PPC_PMU 0x107 ++#define NT_PPC_TM_CGPR 0x108 ++#define NT_PPC_TM_CFPR 0x109 ++#define NT_PPC_TM_CVMX 0x10a ++#define NT_PPC_TM_CVSX 0x10b ++#define NT_PPC_TM_SPR 0x10c ++#define NT_PPC_TM_CTAR 0x10d ++#define NT_PPC_TM_CPPR 0x10e ++#define NT_PPC_TM_CDSCR 0x10f + #define NT_386_TLS 0x200 + #define NT_386_IOPERM 0x201 + #define NT_X86_XSTATE 0x202 + #define NT_S390_HIGH_GPRS 0x300 + #define NT_S390_TIMER 0x301 + #define NT_S390_TODCMP 0x302 + #define NT_S390_TODPREG 0x303 + #define NT_S390_CTRS 0x304 + #define NT_S390_PREFIX 0x305 + #define NT_S390_LAST_BREAK 0x306 + #define NT_S390_SYSTEM_CALL 0x307 + #define NT_S390_TDB 0x308 ++#define NT_S390_VXRS_LOW 0x309 ++#define NT_S390_VXRS_HIGH 0x30a ++#define NT_S390_GS_CB 0x30b ++#define NT_S390_GS_BC 0x30c ++#define NT_S390_RI_CB 0x30d + #define NT_ARM_VFP 0x400 + #define NT_ARM_TLS 0x401 + #define NT_ARM_HW_BREAK 0x402 + #define NT_ARM_HW_WATCH 0x403 ++#define NT_ARM_SYSTEM_CALL 0x404 ++#define NT_ARM_SVE 0x405 ++#define NT_ARM_PAC_MASK 0x406 + #define NT_METAG_CBUF 0x500 + #define NT_METAG_RPIPE 0x501 + #define NT_METAG_TLS 0x502 ++#define NT_ARC_V2 0x600 ++#define NT_VMCOREDD 0x700 ++#define NT_MIPS_DSP 0x800 ++#define NT_MIPS_FP_MODE 0x801 ++#define NT_MIPS_MSA 0x802 + #define NT_VERSION 1 + + + + + typedef struct { + Elf32_Sword d_tag; + union { +@@ -596,17 +743,18 @@ typedef struct { + #define DT_FINI_ARRAY 26 + #define DT_INIT_ARRAYSZ 27 + #define DT_FINI_ARRAYSZ 28 + #define DT_RUNPATH 29 + #define DT_FLAGS 30 + #define DT_ENCODING 32 + #define DT_PREINIT_ARRAY 32 + #define DT_PREINIT_ARRAYSZ 33 +-#define DT_NUM 34 ++#define DT_SYMTAB_SHNDX 34 ++#define DT_NUM 35 + #define DT_LOOS 0x6000000d + #define DT_HIOS 0x6ffff000 + #define DT_LOPROC 0x70000000 + #define DT_HIPROC 0x7fffffff + #define DT_PROCNUM DT_MIPS_NUM + + #define DT_VALRNGLO 0x6ffffd00 + #define DT_GNU_PRELINKED 0x6ffffdf5 +@@ -696,16 +844,18 @@ typedef struct { + #define DF_1_IGNMULDEF 0x00040000 + #define DF_1_NOKSYMS 0x00080000 + #define DF_1_NOHDR 0x00100000 + #define DF_1_EDITED 0x00200000 + #define DF_1_NORELOC 0x00400000 + #define DF_1_SYMINTPOSE 0x00800000 + #define DF_1_GLOBAUDIT 0x01000000 + #define DF_1_SINGLETON 0x02000000 ++#define DF_1_STUB 0x04000000 ++#define DF_1_PIE 0x08000000 + + #define DTF_1_PARINIT 0x00000001 + #define DTF_1_CONFEXP 0x00000002 + + + #define DF_P1_LAZYLOAD 0x00000001 + #define DF_P1_GROUPPERM 0x00000002 + +@@ -877,17 +1027,26 @@ typedef struct { + + + + #define AT_L1I_CACHESHAPE 34 + #define AT_L1D_CACHESHAPE 35 + #define AT_L2_CACHESHAPE 36 + #define AT_L3_CACHESHAPE 37 + +- ++#define AT_L1I_CACHESIZE 40 ++#define AT_L1I_CACHEGEOMETRY 41 ++#define AT_L1D_CACHESIZE 42 ++#define AT_L1D_CACHEGEOMETRY 43 ++#define AT_L2_CACHESIZE 44 ++#define AT_L2_CACHEGEOMETRY 45 ++#define AT_L3_CACHESIZE 46 ++#define AT_L3_CACHEGEOMETRY 47 ++ ++#define AT_MINSIGSTKSZ 51 + + + typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; + } Elf32_Nhdr; + +@@ -972,17 +1131,35 @@ typedef struct { + #define R_68K_PLT8 15 + #define R_68K_PLT32O 16 + #define R_68K_PLT16O 17 + #define R_68K_PLT8O 18 + #define R_68K_COPY 19 + #define R_68K_GLOB_DAT 20 + #define R_68K_JMP_SLOT 21 + #define R_68K_RELATIVE 22 +-#define R_68K_NUM 23 ++#define R_68K_TLS_GD32 25 ++#define R_68K_TLS_GD16 26 ++#define R_68K_TLS_GD8 27 ++#define R_68K_TLS_LDM32 28 ++#define R_68K_TLS_LDM16 29 ++#define R_68K_TLS_LDM8 30 ++#define R_68K_TLS_LDO32 31 ++#define R_68K_TLS_LDO16 32 ++#define R_68K_TLS_LDO8 33 ++#define R_68K_TLS_IE32 34 ++#define R_68K_TLS_IE16 35 ++#define R_68K_TLS_IE8 36 ++#define R_68K_TLS_LE32 37 ++#define R_68K_TLS_LE16 38 ++#define R_68K_TLS_LE8 39 ++#define R_68K_TLS_DTPMOD32 40 ++#define R_68K_TLS_DTPREL32 41 ++#define R_68K_TLS_TPREL32 42 ++#define R_68K_NUM 43 + + #define R_386_NONE 0 + #define R_386_32 1 + #define R_386_PC32 2 + #define R_386_GOT32 3 + #define R_386_PLT32 4 + #define R_386_COPY 5 + #define R_386_GLOB_DAT 6 +@@ -1015,17 +1192,18 @@ typedef struct { + #define R_386_TLS_DTPMOD32 35 + #define R_386_TLS_DTPOFF32 36 + #define R_386_TLS_TPOFF32 37 + #define R_386_SIZE32 38 + #define R_386_TLS_GOTDESC 39 + #define R_386_TLS_DESC_CALL 40 + #define R_386_TLS_DESC 41 + #define R_386_IRELATIVE 42 +-#define R_386_NUM 43 ++#define R_386_GOT32X 43 ++#define R_386_NUM 44 + + + + + + #define STT_SPARC_REGISTER 13 + + +@@ -1148,16 +1326,17 @@ typedef struct { + + #define EF_MIPS_NOREORDER 1 + #define EF_MIPS_PIC 2 + #define EF_MIPS_CPIC 4 + #define EF_MIPS_XGOT 8 + #define EF_MIPS_64BIT_WHIRL 16 + #define EF_MIPS_ABI2 32 + #define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_FP64 512 + #define EF_MIPS_NAN2008 1024 + #define EF_MIPS_ARCH 0xf0000000 + + + + #define EF_MIPS_ARCH_1 0x00000000 + #define EF_MIPS_ARCH_2 0x10000000 + #define EF_MIPS_ARCH_3 0x20000000 +@@ -1392,16 +1571,17 @@ typedef struct { + + #define R_MIPS_NUM 128 + + + + #define PT_MIPS_REGINFO 0x70000000 + #define PT_MIPS_RTPROC 0x70000001 + #define PT_MIPS_OPTIONS 0x70000002 ++#define PT_MIPS_ABIFLAGS 0x70000003 + + + + #define PF_MIPS_LOCAL 0x10000000 + + + + #define DT_MIPS_RLD_VERSION 0x70000001 +@@ -1455,17 +1635,18 @@ typedef struct { + + #define DT_MIPS_COMPACT_SIZE 0x7000002f + #define DT_MIPS_GP_VALUE 0x70000030 + #define DT_MIPS_AUX_DYNAMIC 0x70000031 + + #define DT_MIPS_PLTGOT 0x70000032 + + #define DT_MIPS_RWPLT 0x70000034 +-#define DT_MIPS_NUM 0x35 ++#define DT_MIPS_RLD_MAP_REL 0x70000035 ++#define DT_MIPS_NUM 0x36 + + + + #define RHF_NONE 0 + #define RHF_QUICKSTART (1 << 0) + #define RHF_NOTPOT (1 << 1) + #define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) + #define RHF_NO_MOVE (1 << 3) +@@ -1478,27 +1659,25 @@ typedef struct { + #define RHF_REQUICKSTART (1 << 10) + #define RHF_REQUICKSTARTED (1 << 11) + #define RHF_CORD (1 << 12) + #define RHF_NO_UNRES_UNDEF (1 << 13) + #define RHF_RLD_ORDER_SAFE (1 << 14) + + + +-typedef struct +-{ ++typedef struct { + Elf32_Word l_name; + Elf32_Word l_time_stamp; + Elf32_Word l_checksum; + Elf32_Word l_version; + Elf32_Word l_flags; + } Elf32_Lib; + +-typedef struct +-{ ++typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; + } Elf64_Lib; + + +@@ -1511,17 +1690,83 @@ typedef struct + #define LL_EXPORTS (1 << 3) + #define LL_DELAY_LOAD (1 << 4) + #define LL_DELTA (1 << 5) + + + + typedef Elf32_Addr Elf32_Conflict; + +- ++typedef struct { ++ Elf32_Half version; ++ unsigned char isa_level; ++ unsigned char isa_rev; ++ unsigned char gpr_size; ++ unsigned char cpr1_size; ++ unsigned char cpr2_size; ++ unsigned char fp_abi; ++ Elf32_Word isa_ext; ++ Elf32_Word ases; ++ Elf32_Word flags1; ++ Elf32_Word flags2; ++} Elf_MIPS_ABIFlags_v0; ++ ++#define MIPS_AFL_REG_NONE 0x00 ++#define MIPS_AFL_REG_32 0x01 ++#define MIPS_AFL_REG_64 0x02 ++#define MIPS_AFL_REG_128 0x03 ++ ++#define MIPS_AFL_ASE_DSP 0x00000001 ++#define MIPS_AFL_ASE_DSPR2 0x00000002 ++#define MIPS_AFL_ASE_EVA 0x00000004 ++#define MIPS_AFL_ASE_MCU 0x00000008 ++#define MIPS_AFL_ASE_MDMX 0x00000010 ++#define MIPS_AFL_ASE_MIPS3D 0x00000020 ++#define MIPS_AFL_ASE_MT 0x00000040 ++#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 ++#define MIPS_AFL_ASE_VIRT 0x00000100 ++#define MIPS_AFL_ASE_MSA 0x00000200 ++#define MIPS_AFL_ASE_MIPS16 0x00000400 ++#define MIPS_AFL_ASE_MICROMIPS 0x00000800 ++#define MIPS_AFL_ASE_XPA 0x00001000 ++#define MIPS_AFL_ASE_MASK 0x00001fff ++ ++#define MIPS_AFL_EXT_XLR 1 ++#define MIPS_AFL_EXT_OCTEON2 2 ++#define MIPS_AFL_EXT_OCTEONP 3 ++#define MIPS_AFL_EXT_LOONGSON_3A 4 ++#define MIPS_AFL_EXT_OCTEON 5 ++#define MIPS_AFL_EXT_5900 6 ++#define MIPS_AFL_EXT_4650 7 ++#define MIPS_AFL_EXT_4010 8 ++#define MIPS_AFL_EXT_4100 9 ++#define MIPS_AFL_EXT_3900 10 ++#define MIPS_AFL_EXT_10000 11 ++#define MIPS_AFL_EXT_SB1 12 ++#define MIPS_AFL_EXT_4111 13 ++#define MIPS_AFL_EXT_4120 14 ++#define MIPS_AFL_EXT_5400 15 ++#define MIPS_AFL_EXT_5500 16 ++#define MIPS_AFL_EXT_LOONGSON_2E 17 ++#define MIPS_AFL_EXT_LOONGSON_2F 18 ++ ++#define MIPS_AFL_FLAGS1_ODDSPREG 1 ++ ++enum ++{ ++ Val_GNU_MIPS_ABI_FP_ANY = 0, ++ Val_GNU_MIPS_ABI_FP_DOUBLE = 1, ++ Val_GNU_MIPS_ABI_FP_SINGLE = 2, ++ Val_GNU_MIPS_ABI_FP_SOFT = 3, ++ Val_GNU_MIPS_ABI_FP_OLD_64 = 4, ++ Val_GNU_MIPS_ABI_FP_XX = 5, ++ Val_GNU_MIPS_ABI_FP_64 = 6, ++ Val_GNU_MIPS_ABI_FP_64A = 7, ++ Val_GNU_MIPS_ABI_FP_MAX = 7 ++}; + + + + + #define EF_PARISC_TRAPNIL 0x00010000 + #define EF_PARISC_EXT 0x00020000 + #define EF_PARISC_LSB 0x00040000 + #define EF_PARISC_WIDE 0x00080000 +@@ -1852,17 +2097,18 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_PPC_GOT_TPREL16 87 + #define R_PPC_GOT_TPREL16_LO 88 + #define R_PPC_GOT_TPREL16_HI 89 + #define R_PPC_GOT_TPREL16_HA 90 + #define R_PPC_GOT_DTPREL16 91 + #define R_PPC_GOT_DTPREL16_LO 92 + #define R_PPC_GOT_DTPREL16_HI 93 + #define R_PPC_GOT_DTPREL16_HA 94 +- ++#define R_PPC_TLSGD 95 ++#define R_PPC_TLSLD 96 + + + #define R_PPC_EMB_NADDR32 101 + #define R_PPC_EMB_NADDR16 102 + #define R_PPC_EMB_NADDR16_LO 103 + #define R_PPC_EMB_NADDR16_HI 104 + #define R_PPC_EMB_NADDR16_HA 105 + #define R_PPC_EMB_SDAI16 106 +@@ -1895,17 +2141,20 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_PPC_REL16_HA 252 + + + + #define R_PPC_TOC16 255 + + + #define DT_PPC_GOT (DT_LOPROC + 0) +-#define DT_PPC_NUM 1 ++#define DT_PPC_OPT (DT_LOPROC + 1) ++#define DT_PPC_NUM 2 ++ ++#define PPC_OPT_TLS 1 + + + #define R_PPC64_NONE R_PPC_NONE + #define R_PPC64_ADDR32 R_PPC_ADDR32 + #define R_PPC64_ADDR24 R_PPC_ADDR24 + #define R_PPC64_ADDR16 R_PPC_ADDR16 + #define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO + #define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI +@@ -2008,33 +2257,49 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_PPC64_TPREL16_HIGHEST 99 + #define R_PPC64_TPREL16_HIGHESTA 100 + #define R_PPC64_DTPREL16_DS 101 + #define R_PPC64_DTPREL16_LO_DS 102 + #define R_PPC64_DTPREL16_HIGHER 103 + #define R_PPC64_DTPREL16_HIGHERA 104 + #define R_PPC64_DTPREL16_HIGHEST 105 + #define R_PPC64_DTPREL16_HIGHESTA 106 ++#define R_PPC64_TLSGD 107 ++#define R_PPC64_TLSLD 108 ++#define R_PPC64_TOCSAVE 109 ++#define R_PPC64_ADDR16_HIGH 110 ++#define R_PPC64_ADDR16_HIGHA 111 ++#define R_PPC64_TPREL16_HIGH 112 ++#define R_PPC64_TPREL16_HIGHA 113 ++#define R_PPC64_DTPREL16_HIGH 114 ++#define R_PPC64_DTPREL16_HIGHA 115 + + + #define R_PPC64_JMP_IREL 247 + #define R_PPC64_IRELATIVE 248 + #define R_PPC64_REL16 249 + #define R_PPC64_REL16_LO 250 + #define R_PPC64_REL16_HI 251 + #define R_PPC64_REL16_HA 252 + ++#define EF_PPC64_ABI 3 + + #define DT_PPC64_GLINK (DT_LOPROC + 0) + #define DT_PPC64_OPD (DT_LOPROC + 1) + #define DT_PPC64_OPDSZ (DT_LOPROC + 2) +-#define DT_PPC64_NUM 3 +- +- +- ++#define DT_PPC64_OPT (DT_LOPROC + 3) ++#define DT_PPC64_NUM 4 ++ ++#define PPC64_OPT_TLS 1 ++#define PPC64_OPT_MULTI_TOC 2 ++#define PPC64_OPT_LOCALENTRY 4 ++ ++#define STO_PPC64_LOCAL_BIT 5 ++#define STO_PPC64_LOCAL_MASK 0xe0 ++#define PPC64_LOCAL_ENTRY_OFFSET(x) (1 << (((x)&0xe0)>>5) & 0xfc) + + + #define EF_ARM_RELEXEC 0x01 + #define EF_ARM_HASENTRY 0x02 + #define EF_ARM_INTERWORK 0x04 + #define EF_ARM_APCS_26 0x08 + #define EF_ARM_APCS_FLOAT 0x10 + #define EF_ARM_PIC 0x20 +@@ -2084,18 +2349,27 @@ typedef Elf32_Addr Elf32_Conflict; + + #define PT_ARM_EXIDX (PT_LOPROC + 1) + + + #define SHT_ARM_EXIDX (SHT_LOPROC + 1) + #define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) + #define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) + +- + #define R_AARCH64_NONE 0 ++#define R_AARCH64_P32_ABS32 1 ++#define R_AARCH64_P32_COPY 180 ++#define R_AARCH64_P32_GLOB_DAT 181 ++#define R_AARCH64_P32_JUMP_SLOT 182 ++#define R_AARCH64_P32_RELATIVE 183 ++#define R_AARCH64_P32_TLS_DTPMOD 184 ++#define R_AARCH64_P32_TLS_DTPREL 185 ++#define R_AARCH64_P32_TLS_TPREL 186 ++#define R_AARCH64_P32_TLSDESC 187 ++#define R_AARCH64_P32_IRELATIVE 188 + #define R_AARCH64_ABS64 257 + #define R_AARCH64_ABS32 258 + #define R_AARCH64_ABS16 259 + #define R_AARCH64_PREL64 260 + #define R_AARCH64_PREL32 261 + #define R_AARCH64_PREL16 262 + #define R_AARCH64_MOVW_UABS_G0 263 + #define R_AARCH64_MOVW_UABS_G0_NC 264 +@@ -2203,18 +2477,21 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 + #define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 + #define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 + #define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 + #define R_AARCH64_COPY 1024 + #define R_AARCH64_GLOB_DAT 1025 + #define R_AARCH64_JUMP_SLOT 1026 + #define R_AARCH64_RELATIVE 1027 ++#define R_AARCH64_TLS_DTPMOD 1028 + #define R_AARCH64_TLS_DTPMOD64 1028 ++#define R_AARCH64_TLS_DTPREL 1029 + #define R_AARCH64_TLS_DTPREL64 1029 ++#define R_AARCH64_TLS_TPREL 1030 + #define R_AARCH64_TLS_TPREL64 1030 + #define R_AARCH64_TLSDESC 1031 + + + #define R_ARM_NONE 0 + #define R_ARM_PC24 1 + #define R_ARM_ABS32 2 + #define R_ARM_REL32 3 +@@ -2342,16 +2619,71 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_ARM_RREL32 252 + #define R_ARM_RABS22 253 + #define R_ARM_RPC24 254 + #define R_ARM_RBASE 255 + + #define R_ARM_NUM 256 + + ++#define R_CKCORE_NONE 0 ++#define R_CKCORE_ADDR32 1 ++#define R_CKCORE_PCRELIMM8BY4 2 ++#define R_CKCORE_PCRELIMM11BY2 3 ++#define R_CKCORE_PCREL32 5 ++#define R_CKCORE_PCRELJSR_IMM11BY2 6 ++#define R_CKCORE_RELATIVE 9 ++#define R_CKCORE_COPY 10 ++#define R_CKCORE_GLOB_DAT 11 ++#define R_CKCORE_JUMP_SLOT 12 ++#define R_CKCORE_GOTOFF 13 ++#define R_CKCORE_GOTPC 14 ++#define R_CKCORE_GOT32 15 ++#define R_CKCORE_PLT32 16 ++#define R_CKCORE_ADDRGOT 17 ++#define R_CKCORE_ADDRPLT 18 ++#define R_CKCORE_PCREL_IMM26BY2 19 ++#define R_CKCORE_PCREL_IMM16BY2 20 ++#define R_CKCORE_PCREL_IMM16BY4 21 ++#define R_CKCORE_PCREL_IMM10BY2 22 ++#define R_CKCORE_PCREL_IMM10BY4 23 ++#define R_CKCORE_ADDR_HI16 24 ++#define R_CKCORE_ADDR_LO16 25 ++#define R_CKCORE_GOTPC_HI16 26 ++#define R_CKCORE_GOTPC_LO16 27 ++#define R_CKCORE_GOTOFF_HI16 28 ++#define R_CKCORE_GOTOFF_LO16 29 ++#define R_CKCORE_GOT12 30 ++#define R_CKCORE_GOT_HI16 31 ++#define R_CKCORE_GOT_LO16 32 ++#define R_CKCORE_PLT12 33 ++#define R_CKCORE_PLT_HI16 34 ++#define R_CKCORE_PLT_LO16 35 ++#define R_CKCORE_ADDRGOT_HI16 36 ++#define R_CKCORE_ADDRGOT_LO16 37 ++#define R_CKCORE_ADDRPLT_HI16 38 ++#define R_CKCORE_ADDRPLT_LO16 39 ++#define R_CKCORE_PCREL_JSR_IMM26BY2 40 ++#define R_CKCORE_TOFFSET_LO16 41 ++#define R_CKCORE_DOFFSET_LO16 42 ++#define R_CKCORE_PCREL_IMM18BY2 43 ++#define R_CKCORE_DOFFSET_IMM18 44 ++#define R_CKCORE_DOFFSET_IMM18BY2 45 ++#define R_CKCORE_DOFFSET_IMM18BY4 46 ++#define R_CKCORE_GOT_IMM18BY4 48 ++#define R_CKCORE_PLT_IMM18BY4 49 ++#define R_CKCORE_PCREL_IMM7BY4 50 ++#define R_CKCORE_TLS_LE32 51 ++#define R_CKCORE_TLS_IE32 52 ++#define R_CKCORE_TLS_GD32 53 ++#define R_CKCORE_TLS_LDM32 54 ++#define R_CKCORE_TLS_LDO32 55 ++#define R_CKCORE_TLS_DTPMOD32 56 ++#define R_CKCORE_TLS_DTPOFF32 57 ++#define R_CKCORE_TLS_TPOFF32 58 + + + #define EF_IA_64_MASKOS 0x0000000f + #define EF_IA_64_ABI64 0x00000010 + #define EF_IA_64_ARCH 0xff000000 + + + #define PT_IA_64_ARCHEXT (PT_LOPROC + 0) +@@ -2454,17 +2786,38 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_IA64_DTPREL64I 0xb3 + #define R_IA64_DTPREL32MSB 0xb4 + #define R_IA64_DTPREL32LSB 0xb5 + #define R_IA64_DTPREL64MSB 0xb6 + #define R_IA64_DTPREL64LSB 0xb7 + #define R_IA64_LTOFF_DTPREL22 0xba + + +- ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 + + #define R_SH_NONE 0 + #define R_SH_DIR32 1 + #define R_SH_REL32 2 + #define R_SH_DIR8WPN 3 + #define R_SH_IND12W 4 + #define R_SH_DIR8WPL 5 + #define R_SH_DIR8WPZ 6 +@@ -2660,17 +3013,19 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_X86_64_SIZE64 33 + + #define R_X86_64_GOTPC32_TLSDESC 34 + #define R_X86_64_TLSDESC_CALL 35 + + #define R_X86_64_TLSDESC 36 + #define R_X86_64_IRELATIVE 37 + #define R_X86_64_RELATIVE64 38 +-#define R_X86_64_NUM 39 ++#define R_X86_64_GOTPCRELX 41 ++#define R_X86_64_REX_GOTPCRELX 42 ++#define R_X86_64_NUM 43 + + + + #define R_MN10300_NONE 0 + #define R_MN10300_32 1 + #define R_MN10300_16 2 + #define R_MN10300_8 3 + #define R_MN10300_PCREL32 4 +@@ -2778,16 +3133,65 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_MICROBLAZE_TLSGD 23 + #define R_MICROBLAZE_TLSLD 24 + #define R_MICROBLAZE_TLSDTPMOD32 25 + #define R_MICROBLAZE_TLSDTPREL32 26 + #define R_MICROBLAZE_TLSDTPREL64 27 + #define R_MICROBLAZE_TLSGOTTPREL32 28 + #define R_MICROBLAZE_TLSTPREL32 29 + ++#define DT_NIOS2_GP 0x70000002 ++ ++#define R_NIOS2_NONE 0 ++#define R_NIOS2_S16 1 ++#define R_NIOS2_U16 2 ++#define R_NIOS2_PCREL16 3 ++#define R_NIOS2_CALL26 4 ++#define R_NIOS2_IMM5 5 ++#define R_NIOS2_CACHE_OPX 6 ++#define R_NIOS2_IMM6 7 ++#define R_NIOS2_IMM8 8 ++#define R_NIOS2_HI16 9 ++#define R_NIOS2_LO16 10 ++#define R_NIOS2_HIADJ16 11 ++#define R_NIOS2_BFD_RELOC_32 12 ++#define R_NIOS2_BFD_RELOC_16 13 ++#define R_NIOS2_BFD_RELOC_8 14 ++#define R_NIOS2_GPREL 15 ++#define R_NIOS2_GNU_VTINHERIT 16 ++#define R_NIOS2_GNU_VTENTRY 17 ++#define R_NIOS2_UJMP 18 ++#define R_NIOS2_CJMP 19 ++#define R_NIOS2_CALLR 20 ++#define R_NIOS2_ALIGN 21 ++#define R_NIOS2_GOT16 22 ++#define R_NIOS2_CALL16 23 ++#define R_NIOS2_GOTOFF_LO 24 ++#define R_NIOS2_GOTOFF_HA 25 ++#define R_NIOS2_PCREL_LO 26 ++#define R_NIOS2_PCREL_HA 27 ++#define R_NIOS2_TLS_GD16 28 ++#define R_NIOS2_TLS_LDM16 29 ++#define R_NIOS2_TLS_LDO16 30 ++#define R_NIOS2_TLS_IE16 31 ++#define R_NIOS2_TLS_LE16 32 ++#define R_NIOS2_TLS_DTPMOD 33 ++#define R_NIOS2_TLS_DTPREL 34 ++#define R_NIOS2_TLS_TPREL 35 ++#define R_NIOS2_COPY 36 ++#define R_NIOS2_GLOB_DAT 37 ++#define R_NIOS2_JUMP_SLOT 38 ++#define R_NIOS2_RELATIVE 39 ++#define R_NIOS2_GOTOFF 40 ++#define R_NIOS2_CALL26_NOAT 41 ++#define R_NIOS2_GOT_LO 42 ++#define R_NIOS2_GOT_HA 43 ++#define R_NIOS2_CALL_LO 44 ++#define R_NIOS2_CALL_HA 45 ++ + #define R_OR1K_NONE 0 + #define R_OR1K_32 1 + #define R_OR1K_16 2 + #define R_OR1K_8 3 + #define R_OR1K_LO_16_IN_INSN 4 + #define R_OR1K_HI_16_IN_INSN 5 + #define R_OR1K_INSN_REL_26 6 + #define R_OR1K_GNU_VTENTRY 7 +@@ -2814,14 +3218,17 @@ typedef Elf32_Addr Elf32_Conflict; + #define R_OR1K_TLS_IE_HI16 28 + #define R_OR1K_TLS_IE_LO16 29 + #define R_OR1K_TLS_LE_HI16 30 + #define R_OR1K_TLS_LE_LO16 31 + #define R_OR1K_TLS_TPOFF 32 + #define R_OR1K_TLS_DTPOFF 33 + #define R_OR1K_TLS_DTPMOD 34 + ++#define R_BPF_NONE 0 ++#define R_BPF_MAP_FD 1 ++ + #ifdef __cplusplus + } + #endif + + + #endif + diff --git a/toolkit/crashreporter/breakpad-patches/09-json-upload.patch b/toolkit/crashreporter/breakpad-patches/09-json-upload.patch new file mode 100644 index 0000000000..8ad73bc681 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/09-json-upload.patch @@ -0,0 +1,333 @@ +diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc +index 702526af..0a1019dd 100644 +--- a/src/common/linux/http_upload.cc ++++ b/src/common/linux/http_upload.cc +@@ -55,7 +55,7 @@ static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; + + // static + bool HTTPUpload::SendRequest(const string &url, +- const map ¶meters, ++ const string ¶meters, + const map &files, + const string &proxy, + const string &proxy_user_pwd, +@@ -66,9 +66,6 @@ bool HTTPUpload::SendRequest(const string &url, + if (response_code != NULL) + *response_code = 0; + +- if (!CheckParameters(parameters)) +- return false; +- + // We may have been linked statically; if curl_easy_init is in the + // current binary, no need to search for a dynamic version. + void* curl_lib = dlopen(NULL, RTLD_NOW); +@@ -133,14 +130,14 @@ bool HTTPUpload::SendRequest(const string &url, + // Add form data. + CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...); + *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); +- map::const_iterator iter = parameters.begin(); +- for (; iter != parameters.end(); ++iter) +- (*curl_formadd)(&formpost, &lastptr, +- CURLFORM_COPYNAME, iter->first.c_str(), +- CURLFORM_COPYCONTENTS, iter->second.c_str(), +- CURLFORM_END); ++ (*curl_formadd)(&formpost, &lastptr, CURLFORM_COPYNAME, "extra", ++ CURLFORM_BUFFER, "extra.json", CURLFORM_BUFFERPTR, ++ parameters.c_str(), CURLFORM_BUFFERLENGTH, ++ parameters.length(), CURLFORM_CONTENTTYPE, "application/json", ++ CURLFORM_END); + + // Add form files. ++ map::const_iterator iter = files.begin(); + for (iter = files.begin(); iter != files.end(); ++iter) { + (*curl_formadd)(&formpost, &lastptr, + CURLFORM_COPYNAME, iter->first.c_str(), +@@ -210,21 +207,4 @@ bool HTTPUpload::CheckCurlLib(void* curl_lib) { + dlsym(curl_lib, "curl_easy_setopt"); + } + +-// static +-bool HTTPUpload::CheckParameters(const map ¶meters) { +- for (map::const_iterator pos = parameters.begin(); +- pos != parameters.end(); ++pos) { +- const string &str = pos->first; +- if (str.size() == 0) +- return false; // disallow empty parameter names +- for (unsigned int i = 0; i < str.size(); ++i) { +- int c = str[i]; +- if (c < 32 || c == '"' || c > 127) { +- return false; +- } +- } +- } +- return true; +-} +- + } // namespace google_breakpad +diff --git a/src/common/linux/http_upload.h b/src/common/linux/http_upload.h +index bc1d5d57..95dedebc 100644 +--- a/src/common/linux/http_upload.h ++++ b/src/common/linux/http_upload.h +@@ -29,7 +29,7 @@ + + // HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST + // request using libcurl. It currently supports requests that contain +-// a set of string parameters (key/value pairs), and a file to upload. ++// parameters encoded in a JSON string, and a file to upload. + + #ifndef COMMON_LINUX_HTTP_UPLOAD_H__ + #define COMMON_LINUX_HTTP_UPLOAD_H__ +@@ -49,8 +49,7 @@ class HTTPUpload { + // request to the given URL. + // Each key in |files| is the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an . +- // Parameter names must contain only printable ASCII characters, +- // and may not contain a quote (") character. ++ // Parameters are specified as a JSON-encoded string in |parameters|. + // 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. +@@ -59,7 +58,7 @@ class HTTPUpload { + // If the send fails, a description of the error will be + // returned in error_description. + static bool SendRequest(const string &url, +- const map ¶meters, ++ const string ¶meters, + const map &files, + const string &proxy, + const string &proxy_user_pwd, +@@ -69,11 +68,6 @@ class HTTPUpload { + string *error_description); + + private: +- // 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 ¶meters); +- + // Checks the curl_lib parameter points to a valid curl lib. + static bool CheckCurlLib(void* curl_lib); + +diff --git a/src/common/mac/HTTPMultipartUpload.h b/src/common/mac/HTTPMultipartUpload.h +index 42e8fed3..0cea733e 100644 +--- a/src/common/mac/HTTPMultipartUpload.h ++++ b/src/common/mac/HTTPMultipartUpload.h +@@ -37,7 +37,7 @@ + @interface HTTPMultipartUpload : NSObject { + @protected + NSURL *url_; // The destination URL (STRONG) +- NSDictionary *parameters_; // The key/value pairs for sending data (STRONG) ++ NSMutableString *parameters_; // The JSON payload for sending data (STRONG) + NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG) + NSString *boundary_; // The boundary string (STRONG) + NSHTTPURLResponse *response_; // The response from the send (STRONG) +@@ -47,8 +47,8 @@ + + - (NSURL *)URL; + +-- (void)setParameters:(NSDictionary *)parameters; +-- (NSDictionary *)parameters; ++- (void)setParameters:(NSMutableString *)parameters; ++- (NSMutableString *)parameters; + + - (void)addFileAtPath:(NSString *)path name:(NSString *)name; + - (void)addFileContents:(NSData *)data name:(NSString *)name; +diff --git a/src/common/mac/HTTPMultipartUpload.m b/src/common/mac/HTTPMultipartUpload.m +index a3677f25..d2480493 100644 +--- a/src/common/mac/HTTPMultipartUpload.m ++++ b/src/common/mac/HTTPMultipartUpload.m +@@ -93,7 +93,7 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, + - (NSString *)multipartBoundary; + // Each of the following methods will append the starting multipart boundary, + // but not the ending one. +-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value; ++- (NSData *)formDataForJSON:(NSString *)json; + - (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name; + - (NSData *)formDataForFile:(NSString *)file name:(NSString *)name; + @end +@@ -110,13 +110,16 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, + } + + //============================================================================= +-- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value { +- NSString *escaped = PercentEncodeNSString(key); +- NSString *fmt = +- @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; +- NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value]; ++- (NSData *)formDataForJSON:(NSString *)json { ++ NSMutableData *data = [NSMutableData data]; ++ NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"extra\"; " ++ "filename=\"extra.json\"\r\nContent-Type: application/json\r\n\r\n"; ++ NSString *form = [NSString stringWithFormat:fmt, boundary_]; ++ ++ [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]]; ++ [data appendData:[json dataUsingEncoding:NSUTF8StringEncoding]]; + +- return [form dataUsingEncoding:NSUTF8StringEncoding]; ++ return data; + } + + //============================================================================= +@@ -171,15 +174,15 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, + } + + //============================================================================= +-- (void)setParameters:(NSDictionary *)parameters { ++- (void)setParameters:(NSMutableString *)parameters { + if (parameters != parameters_) { + [parameters_ release]; +- parameters_ = [parameters copy]; ++ parameters_ = [parameters mutableCopy]; + } + } + + //============================================================================= +-- (NSDictionary *)parameters { ++- (NSMutableString *)parameters { + return parameters_; + } + +@@ -210,16 +213,8 @@ static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, + [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", + boundary_] forHTTPHeaderField:@"Content-type"]; + +- // Add any parameters to the message +- NSArray *parameterKeys = [parameters_ allKeys]; +- NSString *key; +- +- NSInteger count = [parameterKeys count]; +- for (NSInteger i = 0; i < count; ++i) { +- key = [parameterKeys objectAtIndex:i]; +- [postBody appendData:[self formDataForKey:key +- value:[parameters_ objectForKey:key]]]; +- } ++ // Add JSON parameters to the message ++ [postBody appendData:[self formDataForJSON:parameters_]]; + + // Add any files to the message + NSArray *fileNames = [files_ allKeys]; +diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc +index b0cc9078..5df17e1a 100644 +--- a/src/common/windows/http_upload.cc ++++ b/src/common/windows/http_upload.cc +@@ -141,23 +141,6 @@ namespace { + return rv; + } + +- bool CheckParameters(const map ¶meters) { +- for (map::const_iterator pos = parameters.begin(); +- pos != parameters.end(); ++pos) { +- const wstring &str = pos->first; +- if (str.size() == 0) { +- return false; // disallow empty parameter names +- } +- for (unsigned int i = 0; i < str.size(); ++i) { +- wchar_t c = str[i]; +- if (c < 32 || c == '"' || c > 127) { +- return false; +- } +- } +- } +- return true; +- } +- + // Converts a UTF16 string to UTF8. + string WideToUTF8(const wstring &wide) { + return WideToMBCP(wide, CP_UTF8); +@@ -390,7 +373,7 @@ namespace { + return true; + } + +- bool GenerateRequestBody(const map ¶meters, ++ bool GenerateRequestBody(const string ¶meters, + const map &files, + const wstring &boundary, + string *request_body) { +@@ -401,14 +384,19 @@ namespace { + + request_body->clear(); + +- // Append each of the parameter pairs as a form-data part +- for (map::const_iterator pos = parameters.begin(); +- pos != parameters.end(); ++pos) { +- request_body->append("--" + boundary_str + "\r\n"); +- request_body->append("Content-Disposition: form-data; name=\"" + +- WideToUTF8(pos->first) + "\"\r\n\r\n" + +- WideToUTF8(pos->second) + "\r\n"); ++ // Append the extra data as a single JSON form entry ++ request_body->append("--" + boundary_str + "\r\n"); ++ request_body->append( ++ "Content-Disposition: form-data; " ++ "name=\"extra\"; " ++ "filename=\"extra.json\"\r\n"); ++ request_body->append("Content-Type: application/json\r\n"); ++ request_body->append("\r\n"); ++ ++ if (!parameters.empty()) { ++ request_body->append(parameters); + } ++ request_body->append("\r\n"); + + // Now append each upload file as a binary (octet-stream) part + for (map::const_iterator pos = files.begin(); +@@ -463,16 +451,11 @@ namespace google_breakpad { + + bool HTTPUpload::SendMultipartPostRequest( + const wstring& url, +- const map& parameters, ++ const string& parameters, + const map& files, + int* timeout_ms, + wstring* response_body, + int* response_code) { +- // TODO(bryner): support non-ASCII parameter names +- if (!CheckParameters(parameters)) { +- return false; +- } +- + wstring boundary = GenerateMultipartBoundary(); + wstring content_type_header = GenerateMultipartPostRequestHeader(boundary); + +diff --git a/src/common/windows/http_upload.h b/src/common/windows/http_upload.h +index 57e526e3..1e47f582 100644 +--- a/src/common/windows/http_upload.h ++++ b/src/common/windows/http_upload.h +@@ -29,7 +29,7 @@ + + // 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. ++// parameters encoded in a JSON string, and a file to upload. + + #ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_ + #define COMMON_WINDOWS_HTTP_UPLOAD_H_ +@@ -45,9 +45,9 @@ + + namespace google_breakpad { + ++using std::map; + using std::string; + using std::wstring; +-using std::map; + + class HTTPUpload { + public: +@@ -81,8 +81,7 @@ class HTTPUpload { + // request to the given URL. + // Each key in |files| is the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an . +- // Parameter names must contain only printable ASCII characters, +- // and may not contain a quote (") character. ++ // Parameters are specified as a JSON-encoded string in |parameters|. + // 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. +@@ -90,7 +89,7 @@ class HTTPUpload { + // received (or 0 if the request failed before getting an HTTP response). + static bool SendMultipartPostRequest( + const wstring& url, +- const map& parameters, ++ const string& parameters, + const map& files, + int *timeout_ms, + wstring *response_body, diff --git a/toolkit/crashreporter/breakpad-patches/10-macho-cpu-subtype.patch b/toolkit/crashreporter/breakpad-patches/10-macho-cpu-subtype.patch new file mode 100644 index 0000000000..be743f9fe7 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/10-macho-cpu-subtype.patch @@ -0,0 +1,47 @@ +changeset: 571402:0c63dcd7a1c6 +user: Steven Michaud +date: Tue Nov 19 21:42:37 2019 +0000 +summary: Bug 1371390 - Pay attention to macho images' cpusubtype when creating minidumps (revised). r=gsvelto + +diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc +--- a/src/common/mac/macho_walker.cc ++++ b/src/common/mac/macho_walker.cc +@@ -151,16 +151,18 @@ bool MachoWalker::FindHeader(cpu_type_t + // header + struct mach_header header; + if (!ReadBytes(&header, sizeof(header), 0)) + return false; + + if (magic == MH_CIGAM || magic == MH_CIGAM_64) + breakpad_swap_mach_header(&header); + ++ header.cpusubtype &= ~CPU_SUBTYPE_MASK; ++ + if (cpu_type != header.cputype || + (cpu_subtype != CPU_SUBTYPE_MULTIPLE && + cpu_subtype != header.cpusubtype)) { + return false; + } + + offset = 0; + return true; +@@ -180,16 +182,18 @@ bool MachoWalker::FindHeader(cpu_type_t + struct fat_arch arch; + for (uint32_t i = 0; i < fat.nfat_arch; ++i) { + if (!ReadBytes(&arch, sizeof(arch), offset)) + return false; + + if (NXHostByteOrder() != NX_BigEndian) + breakpad_swap_fat_arch(&arch, 1); + ++ arch.cpusubtype &= ~CPU_SUBTYPE_MASK; ++ + if (arch.cputype == cpu_type && + (cpu_subtype == CPU_SUBTYPE_MULTIPLE || + arch.cpusubtype == cpu_subtype)) { + offset = arch.offset; + return true; + } + + offset += sizeof(arch); + diff --git a/toolkit/crashreporter/breakpad-patches/12-macho-cpu-subtype-fix.patch b/toolkit/crashreporter/breakpad-patches/12-macho-cpu-subtype-fix.patch new file mode 100644 index 0000000000..6fad2d4d58 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/12-macho-cpu-subtype-fix.patch @@ -0,0 +1,22 @@ +commit 65b01bb302ba1eb7b0240753c22dce39c5ed836b +Author: Nathan Froyd +Date: Tue Jul 14 16:50:20 2020 -0400 + + mask off cpusubtype bits before determining Mach-O identifiers; r=gsvelto + + If we don't do this, we run into problems when walking over the Mach-O load + commands, where we *do* mask off cpusubtype bits. + +diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc +index 4ad0e2b..1c9a067 100644 +--- a/src/common/mac/dump_syms.cc ++++ b/src/common/mac/dump_syms.cc +@@ -286,7 +286,7 @@ string DumpSymbols::Identifier() { + FileID file_id(object_filename_.c_str()); + unsigned char identifier_bytes[16]; + cpu_type_t cpu_type = selected_object_file_->cputype; +- cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; ++ cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype & ~CPU_SUBTYPE_MASK; + if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { + fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", + object_filename_.c_str()); diff --git a/toolkit/crashreporter/breakpad-patches/13-improve-arm64-stack-walking.patch b/toolkit/crashreporter/breakpad-patches/13-improve-arm64-stack-walking.patch new file mode 100644 index 0000000000..b9c6f82799 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/13-improve-arm64-stack-walking.patch @@ -0,0 +1,79 @@ +diff --git a/src/processor/stackwalker_arm64.cc b/src/processor/stackwalker_arm64.cc +--- a/src/processor/stackwalker_arm64.cc ++++ b/src/processor/stackwalker_arm64.cc +@@ -282,16 +282,27 @@ void StackwalkerARM64::CorrectRegLRByFra + << std::hex << (last_last_fp + 8); + return; + } + last_lr = PtrauthStrip(last_lr); + + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = last_lr; + } + ++bool StackwalkerARM64::ValidInstructionPointerInFrame(const StackFrameARM64& frame) { ++ const uint64_t ip = frame.context.iregs[MD_CONTEXT_ARM64_REG_PC]; ++ ++ if ((ip < 0x1000) || (ip > 0x000fffffffffffff)) { ++ // The IP points into the first page or above the user space threshold ++ return false; ++ } ++ ++ return true; ++} ++ + StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector &frames = *stack->frames(); +@@ -300,21 +311,22 @@ StackFrame* StackwalkerARM64::GetCallerF + + // See if there is DWARF call frame information covering this address. + scoped_ptr cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If CFI failed, or there wasn't CFI available, fall back to frame pointer. +- if (!frame.get()) ++ if (!frame.get() || !ValidInstructionPointerInFrame(*frame)) + frame.reset(GetCallerByFramePointer(frames)); + + // If everything failed, fall back to stack scanning. +- if (stack_scan_allowed && !frame.get()) ++ if (stack_scan_allowed && ++ (!frame.get() || !ValidInstructionPointerInFrame(*frame))) + frame.reset(GetCallerByStackScan(frames)); + + // If nothing worked, tell the caller. + if (!frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC], +diff --git a/src/processor/stackwalker_arm64.h b/src/processor/stackwalker_arm64.h +--- a/src/processor/stackwalker_arm64.h ++++ b/src/processor/stackwalker_arm64.h +@@ -92,16 +92,19 @@ class StackwalkerARM64 : public Stackwal + + // GetCallerByFramePointer() depends on the previous frame having recovered + // x30($LR) which may not have been done when using CFI. + // This function recovers $LR in the previous frame by using the frame-pointer + // two frames back to read it from the stack. + void CorrectRegLRByFramePointer(const vector& frames, + StackFrameARM64* last_frame); + ++ // Return true if the instruction pointer points into the first 4KiB of memory ++ bool ValidInstructionPointerInFrame(const StackFrameARM64& frame); ++ + // Stores the CPU context corresponding to the youngest stack frame, to + // be returned by GetContextFrame. + const MDRawContextARM64* context_; + + // Validity mask for youngest stack frame. This is always + // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of + // unit tests. + uint64_t context_frame_validity_; diff --git a/toolkit/crashreporter/breakpad-patches/14-handle-non-fixed-size-amd64-and-x86-contexts.patch b/toolkit/crashreporter/breakpad-patches/14-handle-non-fixed-size-amd64-and-x86-contexts.patch new file mode 100644 index 0000000000..b9544281c2 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/14-handle-non-fixed-size-amd64-and-x86-contexts.patch @@ -0,0 +1,344 @@ +diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc +index 1f479558..aa63fe47 100644 +--- a/src/processor/minidump.cc ++++ b/src/processor/minidump.cc +@@ -444,140 +444,30 @@ MinidumpContext::MinidumpContext(Minidump* minidump) + + MinidumpContext::~MinidumpContext() { + } + + bool MinidumpContext::Read(uint32_t expected_size) { + valid_ = false; + + // Certain raw context types are currently assumed to have unique sizes. +- if (!IsContextSizeUnique(sizeof(MDRawContextAMD64))) { +- BPLOG(ERROR) << "sizeof(MDRawContextAMD64) cannot match the size of any " +- << "other raw context"; +- return false; +- } + if (!IsContextSizeUnique(sizeof(MDRawContextPPC64))) { + BPLOG(ERROR) << "sizeof(MDRawContextPPC64) cannot match the size of any " + << "other raw context"; + return false; + } + if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) { + BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any " + << "other raw context"; + return false; + } + + FreeContext(); + +- // First, figure out what type of CPU this context structure is for. +- // For some reason, the AMD64 Context doesn't have context_flags +- // at the beginning of the structure, so special case it here. +- if (expected_size == sizeof(MDRawContextAMD64)) { +- BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; +- +- scoped_ptr context_amd64(new MDRawContextAMD64()); +- if (!minidump_->ReadBytes(context_amd64.get(), +- sizeof(MDRawContextAMD64))) { +- BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; +- return false; +- } +- +- if (minidump_->swap()) +- Swap(&context_amd64->context_flags); +- +- uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK; +- if (cpu_type == 0) { +- if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { +- context_amd64->context_flags |= cpu_type; +- } else { +- BPLOG(ERROR) << "Failed to preserve the current stream position"; +- return false; +- } +- } +- +- if (cpu_type != MD_CONTEXT_AMD64) { +- // TODO: Fall through to switch below. +- // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 +- BPLOG(ERROR) << "MinidumpContext not actually amd64 context"; +- return false; +- } +- +- // Do this after reading the entire MDRawContext structure because +- // GetSystemInfo may seek minidump to a new position. +- if (!CheckAgainstSystemInfo(cpu_type)) { +- BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; +- return false; +- } +- +- // Normalize the 128-bit types in the dump. +- // Since this is AMD64, by definition, the values are little-endian. +- for (unsigned int vr_index = 0; +- vr_index < MD_CONTEXT_AMD64_VR_COUNT; +- ++vr_index) +- Normalize128(&context_amd64->vector_register[vr_index], false); +- +- if (minidump_->swap()) { +- Swap(&context_amd64->p1_home); +- Swap(&context_amd64->p2_home); +- Swap(&context_amd64->p3_home); +- Swap(&context_amd64->p4_home); +- Swap(&context_amd64->p5_home); +- Swap(&context_amd64->p6_home); +- // context_flags is already swapped +- Swap(&context_amd64->mx_csr); +- Swap(&context_amd64->cs); +- Swap(&context_amd64->ds); +- Swap(&context_amd64->es); +- Swap(&context_amd64->fs); +- Swap(&context_amd64->ss); +- Swap(&context_amd64->eflags); +- Swap(&context_amd64->dr0); +- Swap(&context_amd64->dr1); +- Swap(&context_amd64->dr2); +- Swap(&context_amd64->dr3); +- Swap(&context_amd64->dr6); +- Swap(&context_amd64->dr7); +- Swap(&context_amd64->rax); +- Swap(&context_amd64->rcx); +- Swap(&context_amd64->rdx); +- Swap(&context_amd64->rbx); +- Swap(&context_amd64->rsp); +- Swap(&context_amd64->rbp); +- Swap(&context_amd64->rsi); +- Swap(&context_amd64->rdi); +- Swap(&context_amd64->r8); +- Swap(&context_amd64->r9); +- Swap(&context_amd64->r10); +- Swap(&context_amd64->r11); +- Swap(&context_amd64->r12); +- Swap(&context_amd64->r13); +- Swap(&context_amd64->r14); +- Swap(&context_amd64->r15); +- Swap(&context_amd64->rip); +- // FIXME: I'm not sure what actually determines +- // which member of the union {flt_save, sse_registers} +- // is valid. We're not currently using either, +- // but it would be good to have them swapped properly. +- +- for (unsigned int vr_index = 0; +- vr_index < MD_CONTEXT_AMD64_VR_COUNT; +- ++vr_index) +- Swap(&context_amd64->vector_register[vr_index]); +- Swap(&context_amd64->vector_control); +- Swap(&context_amd64->debug_control); +- Swap(&context_amd64->last_branch_to_rip); +- Swap(&context_amd64->last_branch_from_rip); +- Swap(&context_amd64->last_exception_to_rip); +- Swap(&context_amd64->last_exception_from_rip); +- } +- +- SetContextFlags(context_amd64->context_flags); +- +- SetContextAMD64(context_amd64.release()); +- } else if (expected_size == sizeof(MDRawContextPPC64)) { ++ if (expected_size == sizeof(MDRawContextPPC64)) { + // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext + // in the else case have 32 bits |context_flags|, so special case it here. + uint64_t context_flags; + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; + } + if (minidump_->swap()) +@@ -739,56 +629,152 @@ bool MinidumpContext::Read(uint32_t expected_size) { + } + } + + scoped_ptr new_context(new MDRawContextARM64()); + ConvertOldARM64Context(*context_arm64.get(), new_context.get()); + SetContextFlags(new_context->context_flags); + SetContextARM64(new_context.release()); + } else { +- uint32_t context_flags; +- if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { +- BPLOG(ERROR) << "MinidumpContext could not read context flags"; ++ uint32_t cpu_type = 0; ++ if (!minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { ++ BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } +- if (minidump_->swap()) +- Swap(&context_flags); + +- uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; +- if (cpu_type == 0) { +- // Unfortunately the flag for MD_CONTEXT_ARM that was taken +- // from a Windows CE SDK header conflicts in practice with +- // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, +- // but handle dumps with the legacy value gracefully here. +- if (context_flags & MD_CONTEXT_ARM_OLD) { +- context_flags |= MD_CONTEXT_ARM; +- context_flags &= ~MD_CONTEXT_ARM_OLD; +- cpu_type = MD_CONTEXT_ARM; ++ uint32_t context_flags = 0; ++ if ((cpu_type == 0) || cpu_type != MD_CONTEXT_AMD64) { ++ if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { ++ BPLOG(ERROR) << "MinidumpContext could not read context flags"; ++ return false; + } +- } + +- if (cpu_type == 0) { +- if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { +- context_flags |= cpu_type; ++ if (minidump_->swap()) ++ Swap(&context_flags); ++ ++ if ((context_flags & MD_CONTEXT_CPU_MASK) == 0) { ++ // Unfortunately the flag for MD_CONTEXT_ARM that was taken ++ // from a Windows CE SDK header conflicts in practice with ++ // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, ++ // but handle dumps with the legacy value gracefully here. ++ if (context_flags & MD_CONTEXT_ARM_OLD) { ++ context_flags |= MD_CONTEXT_ARM; ++ context_flags &= ~MD_CONTEXT_ARM_OLD; ++ cpu_type = MD_CONTEXT_ARM; ++ } else { ++ context_flags |= cpu_type; ++ } + } else { +- BPLOG(ERROR) << "Failed to preserve the current stream position"; +- return false; ++ cpu_type = context_flags & MD_CONTEXT_CPU_MASK; + } + } + + // Allocate the context structure for the correct CPU and fill it. The + // casts are slightly unorthodox, but it seems better to do that than to + // maintain a separate pointer for each type of CPU context structure + // when only one of them will be used. + switch (cpu_type) { ++ case MD_CONTEXT_AMD64: { ++ if (expected_size != sizeof(MDRawContextAMD64)) { ++ BPLOG(INFO) << "MinidumpContext AMD64 size mismatch, " << ++ expected_size << " != " << sizeof(MDRawContextAMD64); ++ } ++ BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; ++ ++ scoped_ptr context_amd64(new MDRawContextAMD64()); ++ if (!minidump_->ReadBytes(context_amd64.get(), ++ sizeof(MDRawContextAMD64))) { ++ BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; ++ return false; ++ } ++ ++ if (minidump_->swap()) ++ Swap(&context_amd64->context_flags); ++ ++ // Update context_flags since we haven't done it yet ++ context_flags = context_amd64->context_flags; ++ ++ if (cpu_type != (context_flags & MD_CONTEXT_CPU_MASK)) { ++ BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; ++ return false; ++ } ++ ++ // Normalize the 128-bit types in the dump. ++ // Since this is AMD64, by definition, the values are little-endian. ++ for (unsigned int vr_index = 0; ++ vr_index < MD_CONTEXT_AMD64_VR_COUNT; ++ ++vr_index) ++ Normalize128(&context_amd64->vector_register[vr_index], false); ++ ++ if (minidump_->swap()) { ++ Swap(&context_amd64->p1_home); ++ Swap(&context_amd64->p2_home); ++ Swap(&context_amd64->p3_home); ++ Swap(&context_amd64->p4_home); ++ Swap(&context_amd64->p5_home); ++ Swap(&context_amd64->p6_home); ++ // context_flags is already swapped ++ Swap(&context_amd64->mx_csr); ++ Swap(&context_amd64->cs); ++ Swap(&context_amd64->ds); ++ Swap(&context_amd64->es); ++ Swap(&context_amd64->fs); ++ Swap(&context_amd64->ss); ++ Swap(&context_amd64->eflags); ++ Swap(&context_amd64->dr0); ++ Swap(&context_amd64->dr1); ++ Swap(&context_amd64->dr2); ++ Swap(&context_amd64->dr3); ++ Swap(&context_amd64->dr6); ++ Swap(&context_amd64->dr7); ++ Swap(&context_amd64->rax); ++ Swap(&context_amd64->rcx); ++ Swap(&context_amd64->rdx); ++ Swap(&context_amd64->rbx); ++ Swap(&context_amd64->rsp); ++ Swap(&context_amd64->rbp); ++ Swap(&context_amd64->rsi); ++ Swap(&context_amd64->rdi); ++ Swap(&context_amd64->r8); ++ Swap(&context_amd64->r9); ++ Swap(&context_amd64->r10); ++ Swap(&context_amd64->r11); ++ Swap(&context_amd64->r12); ++ Swap(&context_amd64->r13); ++ Swap(&context_amd64->r14); ++ Swap(&context_amd64->r15); ++ Swap(&context_amd64->rip); ++ // FIXME: I'm not sure what actually determines ++ // which member of the union {flt_save, sse_registers} ++ // is valid. We're not currently using either, ++ // but it would be good to have them swapped properly. ++ ++ for (unsigned int vr_index = 0; ++ vr_index < MD_CONTEXT_AMD64_VR_COUNT; ++ ++vr_index) ++ Swap(&context_amd64->vector_register[vr_index]); ++ Swap(&context_amd64->vector_control); ++ Swap(&context_amd64->debug_control); ++ Swap(&context_amd64->last_branch_to_rip); ++ Swap(&context_amd64->last_branch_from_rip); ++ Swap(&context_amd64->last_exception_to_rip); ++ Swap(&context_amd64->last_exception_from_rip); ++ } ++ ++ SetContextFlags(context_amd64->context_flags); ++ ++ SetContextAMD64(context_amd64.release()); ++ minidump_->SeekSet( ++ (minidump_->Tell() - sizeof(MDRawContextAMD64)) + expected_size); ++ break; ++ } + case MD_CONTEXT_X86: { + if (expected_size != sizeof(MDRawContextX86)) { +- BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " << ++ BPLOG(INFO) << "MinidumpContext x86 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextX86); +- return false; + } + + scoped_ptr context_x86(new MDRawContextX86()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_x86->context_flags = context_flags; +@@ -843,16 +829,18 @@ bool MinidumpContext::Read(uint32_t expected_size) { + Swap(&context_x86->eflags); + Swap(&context_x86->esp); + Swap(&context_x86->ss); + // context_x86->extended_registers[] contains 8-bit quantities and + // does not need to be swapped. + } + + SetContextX86(context_x86.release()); ++ minidump_->SeekSet( ++ (minidump_->Tell() - sizeof(MDRawContextX86)) + expected_size); + + break; + } + + case MD_CONTEXT_PPC: { + if (expected_size != sizeof(MDRawContextPPC)) { + BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " << + expected_size << " != " << sizeof(MDRawContextPPC); +-- +2.26.2 + diff --git a/toolkit/crashreporter/breakpad-patches/15-freebsd-profiler-support.patch b/toolkit/crashreporter/breakpad-patches/15-freebsd-profiler-support.patch new file mode 100644 index 0000000000..812d554865 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/15-freebsd-profiler-support.patch @@ -0,0 +1,107 @@ +changeset: 599606:74707e8ecf38 +user: Greg V +date: Wed May 06 17:44:19 2020 +0000 +summary: Bug 1634205 - Support Gecko Profiler and Base Profiler on FreeBSD r=mstange + +diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc +--- a/src/common/dwarf/elf_reader.cc ++++ b/src/common/dwarf/elf_reader.cc +@@ -52,17 +52,17 @@ + + // EM_AARCH64 is not defined by elf.h of GRTE v3 on x86. + // TODO(dougkwan): Remove this when v17 is retired. + #if !defined(EM_AARCH64) + #define EM_AARCH64 183 /* ARM AARCH64 */ + #endif + + // Map Linux macros to their Apple equivalents. +-#if __APPLE__ ++#if __APPLE__ || __FreeBSD__ + #ifndef __LITTLE_ENDIAN + #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ + #endif // __LITTLE_ENDIAN + #ifndef __BIG_ENDIAN + #define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ + #endif // __BIG_ENDIAN + #ifndef __BYTE_ORDER + #define __BYTE_ORDER __BYTE_ORDER__ +diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc +--- a/src/common/linux/elfutils.cc ++++ b/src/common/linux/elfutils.cc +@@ -30,16 +30,20 @@ + #include "common/linux/elfutils.h" + + #include + #include + + #include "common/linux/linux_libc_support.h" + #include "common/linux/elfutils-inl.h" + ++#if defined(__FreeBSD__) ++# define ElfW(type) Elf_##type ++#endif ++ + namespace google_breakpad { + + namespace { + + template + void FindElfClassSection(const char *elf_base, + const char *section_name, + typename ElfClass::Word section_type, +diff --git a/src/common/memory_allocator.h b/src/common/memory_allocator.h +--- a/src/common/memory_allocator.h ++++ b/src/common/memory_allocator.h +@@ -37,17 +37,17 @@ + + #include + #include + + #if defined(MEMORY_SANITIZER) + #include + #endif + +-#ifdef __APPLE__ ++#if defined(__APPLE__) || defined(__FreeBSD__) + #define sys_mmap mmap + #define sys_munmap munmap + #define MAP_ANONYMOUS MAP_ANON + #else + #include "third_party/lss/linux_syscall_support.h" + #endif + + namespace google_breakpad { +diff --git a/src/third_party/lss/linux_syscall_support.h b/src/third_party/lss/linux_syscall_support.h +--- a/src/third_party/lss/linux_syscall_support.h ++++ b/src/third_party/lss/linux_syscall_support.h +@@ -4527,10 +4527,27 @@ struct kernel_statfs { + #pragma pop_macro("pread64") + #pragma pop_macro("pwrite64") + #pragma pop_macro("getdents64") + + #if defined(__cplusplus) && !defined(SYS_CPLUSPLUS) + } + #endif + +-#endif +-#endif ++#elif defined(__FreeBSD__) ++ ++#include ++#include ++ ++#define sys_readlink readlink ++ ++#define sys_open open ++#define sys_close close ++#define sys_fstat fstat ++#define sys_fstat64 fstat ++#define kernel_stat stat ++#define kernel_stat64 stat ++#define sys_mmap mmap ++#define sys_munmap munmap ++ ++#endif ++ ++#endif + diff --git a/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch b/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch new file mode 100644 index 0000000000..96bebbe503 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch @@ -0,0 +1,181 @@ +diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h +--- a/src/google_breakpad/processor/call_stack.h ++++ b/src/google_breakpad/processor/call_stack.h +@@ -62,26 +62,30 @@ class CallStack { + + // Resets the CallStack to its initial empty state + void Clear(); + + const vector* frames() const { return &frames_; } + + // Set the TID associated with this call stack. + void set_tid(uint32_t tid) { tid_ = tid; } ++ void set_last_error(uint32_t last_error) { last_error_ = last_error; } + + uint32_t tid() const { return tid_; } ++ uint32_t last_error() const { return last_error_; } + + private: + // Stackwalker is responsible for building the frames_ vector. + friend class Stackwalker; + + // Storage for pushed frames. + vector frames_; + + // The TID associated with this call stack. Default to 0 if it's not + // available. + uint32_t tid_; ++ // The last error the OS set for this thread (win32's GetLastError()) ++ uint32_t last_error_; + }; + + } // namespace google_breakpad + + #endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__ +diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h +--- a/src/google_breakpad/processor/minidump.h ++++ b/src/google_breakpad/processor/minidump.h +@@ -279,16 +279,26 @@ class MinidumpMemoryRegion : public Mini + class MinidumpThread : public MinidumpObject { + public: + virtual ~MinidumpThread(); + + const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } + // GetMemory may return NULL even if the MinidumpThread is valid, + // if the thread memory cannot be read. + virtual MinidumpMemoryRegion* GetMemory(); ++ // Corresponds to win32's GetLastError function, which records the last ++ // error value set by the OS for this thread. A more useful error message ++ // can be produced by passing this value to FormatMessage: ++ // ++ // https://docs.microsoft.com/windows/win32/debug/retrieving-the-last-error-code ++ // ++ // The value may also be looked up in Microsoft's System Error Codes listing: ++ // ++ // https://docs.microsoft.com/windows/win32/debug/system-error-codes ++ virtual uint32_t GetLastError(); + // GetContext may return NULL even if the MinidumpThread is valid. + virtual 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. + virtual bool GetThreadID(uint32_t *thread_id) const; +diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc +--- a/src/processor/call_stack.cc ++++ b/src/processor/call_stack.cc +@@ -44,11 +44,12 @@ CallStack::~CallStack() { + + void CallStack::Clear() { + for (vector::const_iterator iterator = frames_.begin(); + iterator != frames_.end(); + ++iterator) { + delete *iterator; + } + tid_ = 0; ++ last_error_ = 0; + } + + } // namespace google_breakpad +diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc +--- a/src/processor/minidump.cc ++++ b/src/processor/minidump.cc +@@ -1567,16 +1567,76 @@ MinidumpMemoryRegion* MinidumpThread::Ge + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory"; + return NULL; + } + + return memory_; + } + ++uint32_t MinidumpThread::GetLastError() { ++ if (!valid_) { ++ BPLOG(ERROR) << "Cannot retrieve GetLastError() from an invalid thread"; ++ return 0; ++ } ++ ++ if (!thread_.teb) { ++ BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid TEB pointer"; ++ return 0; ++ } ++ ++ auto memory = minidump_->GetMemoryList(); ++ if (!memory) { ++ BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid memory list"; ++ return 0; ++ } ++ ++ auto context = GetContext(); ++ if (!context) { ++ BPLOG(ERROR) << "Cannot retrieve GetLastError()'s without a valid context"; ++ return 0; ++ } ++ ++ uint64_t pointer_width = 0; ++ switch (context_->GetContextCPU()) { ++ case MD_CONTEXT_X86: ++ pointer_width = 4; ++ break; ++ case MD_CONTEXT_AMD64: ++ case MD_CONTEXT_ARM64: ++ pointer_width = 8; ++ break; ++ default: ++ BPLOG(ERROR) << "GetLastError() isn't implemented for this CPU type yet"; ++ return 0; ++ } ++ ++ auto region = memory->GetMemoryRegionForAddress(thread_.teb); ++ if (!region) { ++ BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump"; ++ return 0; ++ } ++ ++ // The TEB is opaque but we know the value we want lives at this offset ++ // from reverse engineering. ++ uint64_t offset = pointer_width * 13; ++ uint32_t error = 0; ++ if (!region->GetMemoryAtAddress(thread_.teb + offset, &error)) { ++ BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump"; ++ return 0; ++ } ++ ++ if (minidump_->swap()) { ++ Swap(&error); ++ } ++ ++ return error; ++} ++ ++ + + MinidumpContext* MinidumpThread::GetContext() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThread for GetContext"; + return NULL; + } + + if (!context_) { +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -301,16 +301,17 @@ ProcessResult MinidumpProcessor::Process + } + } else { + // Threads with missing CPU contexts will hit this, but + // don't abort processing the rest of the dump just for + // one bad thread. + BPLOG(ERROR) << "No stackwalker for " << thread_string; + } + stack->set_tid(thread_id); ++ stack->set_last_error(thread->GetLastError()); + process_state->threads_.push_back(stack.release()); + process_state->thread_memory_regions_.push_back(thread_memory); + } + + if (interrupted) { + BPLOG(INFO) << "Processing interrupted for " << dump->path(); + return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; + } diff --git a/toolkit/crashreporter/breakpad-patches/17-unloaded-modules.patch b/toolkit/crashreporter/breakpad-patches/17-unloaded-modules.patch new file mode 100644 index 0000000000..c413e4eff4 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/17-unloaded-modules.patch @@ -0,0 +1,251 @@ +changeset: 649910:59994b59eb51 +tag: tip +parent: 649905:058997a8167d +user: Gabriele Svelto +date: Wed Mar 31 16:25:34 2021 +0200 +summary: Bug 1702043 - Print out the list of unloaded modules when processing a minidump + +diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h +--- a/src/google_breakpad/processor/minidump.h ++++ b/src/google_breakpad/processor/minidump.h +@@ -792,16 +792,19 @@ class MinidumpUnloadedModule : public Mi + string debug_file() const override; + string debug_identifier() const override; + string version() const override; + CodeModule* Copy() const override; + bool is_unloaded() const override { return true; } + uint64_t shrink_down_delta() const override; + void SetShrinkDownDelta(uint64_t shrink_down_delta) override; + ++ // Print a human-readable representation of the object to stdout. ++ void Print(); ++ + protected: + explicit MinidumpUnloadedModule(Minidump* minidump); + + private: + // These objects are managed by MinidumpUnloadedModuleList + friend class MinidumpUnloadedModuleList; + + // This works like MinidumpStream::Read, but is driven by +@@ -850,16 +853,19 @@ class MinidumpUnloadedModuleList : publi + const MinidumpUnloadedModule* GetMainModule() const override; + const MinidumpUnloadedModule* + GetModuleAtSequence(unsigned int sequence) const override; + const MinidumpUnloadedModule* + GetModuleAtIndex(unsigned int index) const override; + const CodeModules* Copy() const override; + vector> GetShrunkRangeModules() const override; + ++ // Print a human-readable representation of the object to stdout. ++ void Print(); ++ + protected: + explicit MinidumpUnloadedModuleList(Minidump* minidump_); + + private: + friend class Minidump; + + typedef vector MinidumpUnloadedModules; + +diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc +--- a/src/processor/minidump.cc ++++ b/src/processor/minidump.cc +@@ -3727,16 +3727,46 @@ MinidumpUnloadedModule::MinidumpUnloaded + name_(NULL) { + + } + + MinidumpUnloadedModule::~MinidumpUnloadedModule() { + delete name_; + } + ++void MinidumpUnloadedModule::Print() { ++ if (!valid_) { ++ BPLOG(ERROR) << "MinidumpUnloadedModule cannot print invalid data"; ++ return; ++ } ++ ++ printf("MDRawUnloadedModule\n"); ++ printf(" base_of_image = 0x%" PRIx64 "\n", ++ unloaded_module_.base_of_image); ++ printf(" size_of_image = 0x%x\n", ++ unloaded_module_.size_of_image); ++ printf(" checksum = 0x%x\n", ++ unloaded_module_.checksum); ++ printf(" time_date_stamp = 0x%x %s\n", ++ unloaded_module_.time_date_stamp, ++ TimeTToUTCString(unloaded_module_.time_date_stamp).c_str()); ++ printf(" module_name_rva = 0x%x\n", ++ unloaded_module_.module_name_rva); ++ ++ printf(" (code_file) = \"%s\"\n", code_file().c_str()); ++ printf(" (code_identifier) = \"%s\"\n", ++ code_identifier().c_str()); ++ ++ printf(" (debug_file) = \"%s\"\n", debug_file().c_str()); ++ printf(" (debug_identifier) = \"%s\"\n", ++ debug_identifier().c_str()); ++ printf(" (version) = \"%s\"\n", version().c_str()); ++ printf("\n"); ++} ++ + string MinidumpUnloadedModule::code_file() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file"; + return ""; + } + + return *name_; + } +@@ -3911,16 +3941,34 @@ MinidumpUnloadedModuleList::MinidumpUnlo + range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + } + + MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() { + delete range_map_; + delete unloaded_modules_; + } + ++void MinidumpUnloadedModuleList::Print() { ++ if (!valid_) { ++ BPLOG(ERROR) << "MinidumpUnloadedModuleList cannot print invalid data"; ++ return; ++ } ++ ++ printf("MinidumpUnloadedModuleList\n"); ++ printf(" module_count = %d\n", module_count_); ++ printf("\n"); ++ ++ for (unsigned int module_index = 0; ++ module_index < module_count_; ++ ++module_index) { ++ printf("module[%d]\n", module_index); ++ ++ (*unloaded_modules_)[module_index].Print(); ++ } ++} + + bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) { + range_map_->Clear(); + delete unloaded_modules_; + unloaded_modules_ = NULL; + module_count_ = 0; + + valid_ = false; +diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc +--- a/src/processor/minidump_dump.cc ++++ b/src/processor/minidump_dump.cc +@@ -40,16 +40,17 @@ + #include "google_breakpad/processor/minidump.h" + #include "processor/logging.h" + + namespace { + + using google_breakpad::Minidump; + using google_breakpad::MinidumpThreadList; + using google_breakpad::MinidumpModuleList; ++using google_breakpad::MinidumpUnloadedModuleList; + using google_breakpad::MinidumpMemoryInfoList; + using google_breakpad::MinidumpMemoryList; + using google_breakpad::MinidumpException; + using google_breakpad::MinidumpAssertion; + using google_breakpad::MinidumpSystemInfo; + using google_breakpad::MinidumpMiscInfo; + using google_breakpad::MinidumpBreakpadInfo; + using google_breakpad::MinidumpCrashpadInfo; +@@ -127,16 +128,25 @@ static bool PrintMinidumpDump(const Opti + MinidumpModuleList *module_list = minidump.GetModuleList(); + if (!module_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetModuleList() failed"; + } else { + module_list->Print(); + } + ++ MinidumpUnloadedModuleList::set_max_modules(UINT32_MAX); ++ MinidumpUnloadedModuleList *unloaded_module_list = minidump.GetUnloadedModuleList(); ++ if (!unloaded_module_list) { ++ ++errors; ++ BPLOG(ERROR) << "minidump.GetUnloadedModuleList() failed"; ++ } else { ++ unloaded_module_list->Print(); ++ } ++ + MinidumpMemoryList *memory_list = minidump.GetMemoryList(); + if (!memory_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetMemoryList() failed"; + } else { + memory_list->Print(); + } + +diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc +--- a/src/processor/stackwalk_common.cc ++++ b/src/processor/stackwalk_common.cc +@@ -777,16 +777,46 @@ static void PrintModulesMachineReadable( + StripSeparator(module->debug_identifier()).c_str(), + kOutputSeparator, base_address, + kOutputSeparator, base_address + module->size() - 1, + kOutputSeparator, + main_module != NULL && base_address == main_address ? 1 : 0); + } + } + ++// PrintUnloadedModulesMachineReadable outputs a list of loaded modules, ++// one per line, in the following machine-readable pipe-delimited ++// text format: ++// UnloadedModule|{Module Filename}|{Base Address}|{Max Address}|{Main} ++static void PrintUnloadedModulesMachineReadable(const CodeModules* modules) { ++ if (!modules) ++ return; ++ ++ uint64_t main_address = 0; ++ const CodeModule* main_module = modules->GetMainModule(); ++ if (main_module) { ++ main_address = main_module->base_address(); ++ } ++ ++ unsigned int module_count = modules->module_count(); ++ for (unsigned int module_sequence = 0; ++ module_sequence < module_count; ++ ++module_sequence) { ++ const CodeModule* module = modules->GetModuleAtSequence(module_sequence); ++ uint64_t base_address = module->base_address(); ++ printf("UnloadedModule%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n", ++ kOutputSeparator, ++ StripSeparator(PathnameStripper::File(module->code_file())).c_str(), ++ kOutputSeparator, base_address, ++ kOutputSeparator, base_address + module->size() - 1, ++ kOutputSeparator, ++ main_module != NULL && base_address == main_address ? 1 : 0); ++ } ++} ++ + } // namespace + + void PrintProcessState(const ProcessState& process_state, + bool output_stack_contents, + SourceLineResolverInterface* resolver) { + // Print OS and CPU information. + string cpu = process_state.system_info()->cpu; + string cpu_info = process_state.system_info()->cpu_info; +@@ -921,16 +951,17 @@ void PrintProcessStateMachineReadable(co + + if (requesting_thread != -1) { + printf("%d\n", requesting_thread); + } else { + printf("\n"); + } + + PrintModulesMachineReadable(process_state.modules()); ++ PrintUnloadedModulesMachineReadable(process_state.unloaded_modules()); + + // blank line to indicate start of threads + printf("\n"); + + // If the thread that requested the dump is known, print it first. + if (requesting_thread != -1) { + PrintStackMachineReadable(requesting_thread, + process_state.threads()->at(requesting_thread)); + diff --git a/toolkit/crashreporter/breakpad-patches/18-fastfail-codes.patch b/toolkit/crashreporter/breakpad-patches/18-fastfail-codes.patch new file mode 100644 index 0000000000..543f320c46 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/18-fastfail-codes.patch @@ -0,0 +1,359 @@ +changeset: 651272:ff2582aceafe +parent: 651260:b740f950e497 +user: Gabriele Svelto +date: Thu Apr 08 12:01:43 2021 +0200 +summary: fastfail + +diff --git a/src/google_breakpad/common/minidump_exception_win32.h b/src/google_breakpad/common/minidump_exception_win32.h +--- a/src/google_breakpad/common/minidump_exception_win32.h ++++ b/src/google_breakpad/common/minidump_exception_win32.h +@@ -2261,9 +2261,84 @@ typedef enum { + // These constants are defined in the MSDN documentation of + // the EXCEPTION_RECORD structure. + typedef enum { + MD_IN_PAGE_ERROR_WIN_READ = 0, + MD_IN_PAGE_ERROR_WIN_WRITE = 1, + MD_IN_PAGE_ERROR_WIN_EXEC = 8 + } MDInPageErrorTypeWin; + ++/* For (MDException).exception_information[0], when (MDException).exception_code ++ * is MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN. This describes the underlying ++ * reason for the crash. These values come from winnt.h. ++ * ++ * The content of this enum was created from winnt.h in the 10 SDK ++ * (version 10.0.19041.0) with ++ * ++ * egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h ++ * | tr -d '\r' ++ * | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' ++ * | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_FAST_FAIL_WIN_\2 = \1,@' */ ++typedef enum { ++ MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION = 0, ++ MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE = 1, ++ MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE = 2, ++ MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY = 3, ++ MD_FAST_FAIL_WIN_INCORRECT_STACK = 4, ++ MD_FAST_FAIL_WIN_INVALID_ARG = 5, ++ MD_FAST_FAIL_WIN_GS_COOKIE_INIT = 6, ++ MD_FAST_FAIL_WIN_FATAL_APP_EXIT = 7, ++ MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE = 8, ++ MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS = 9, ++ MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE = 10, ++ MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE = 11, ++ MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH = 12, ++ MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT = 13, ++ MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT = 14, ++ MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER = 18, ++ MD_FAST_FAIL_WIN_MRDATA_MODIFIED = 19, ++ MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE = 20, ++ MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN = 21, ++ MD_FAST_FAIL_WIN_CRYPTO_LIBRARY = 22, ++ MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT = 23, ++ MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE = 24, ++ MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE = 25, ++ MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL = 26, ++ MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED = 27, ++ MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS = 28, ++ MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE = 29, ++ MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD = 30, ++ MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED = 31, ++ MD_FAST_FAIL_WIN_APCS_DISABLED = 32, ++ MD_FAST_FAIL_WIN_INVALID_IDLE_STATE = 33, ++ MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE = 34, ++ MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION = 35, ++ MD_FAST_FAIL_WIN_INVALID_LOCK_STATE = 36, ++ MD_FAST_FAIL_WIN_GUARD_JUMPTABLE = 37, ++ MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET = 38, ++ MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT = 39, ++ MD_FAST_FAIL_WIN_INVALID_THREAD = 40, ++ MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER = 41, ++ MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION = 42, ++ MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED = 43, ++ MD_FAST_FAIL_WIN_GUARD_SS_FAILURE = 44, ++ MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE = 45, ++ MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE = 46, ++ MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK = 47, ++ MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED = 48, ++ MD_FAST_FAIL_WIN_INVALID_IAT = 49, ++ MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION = 50, ++ MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION = 51, ++ MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED = 52, ++ MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE = 53, ++ MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON = 54, ++ MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED = 55, ++ MD_FAST_FAIL_WIN_UNEXPECTED_CALL = 56, ++ MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS = 57, ++ MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR = 58, ++ MD_FAST_FAIL_WIN_FLAGS_CORRUPTION = 59, ++ MD_FAST_FAIL_WIN_VEH_CORRUPTION = 60, ++ MD_FAST_FAIL_WIN_ETW_CORRUPTION = 61, ++ MD_FAST_FAIL_WIN_RIO_ABORT = 62, ++ MD_FAST_FAIL_WIN_INVALID_PFN = 63, ++} MDFastFailWin; ++ + #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1288,16 +1288,24 @@ string MinidumpProcessor::GetCrashReason + case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE: + reason = "EXCEPTION_BAD_FUNCTION_TABLE"; + break; + case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: + reason = "EXCEPTION_POSSIBLE_DEADLOCK"; + break; + case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: + reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; ++ if (raw_exception->exception_record.number_parameters > 0) { ++ uint32_t fast_fail_code = ++ static_cast ++ (raw_exception->exception_record.exception_information[0]); ++ reason.append(" / "); ++ reason.append(FastFailToString(fast_fail_code)); ++ } ++ + break; + case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: + reason = "EXCEPTION_HEAP_CORRUPTION"; + break; + case MD_EXCEPTION_OUT_OF_MEMORY: + reason = "Out of Memory"; + break; + case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: +diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc +--- a/src/processor/symbolic_constants_win.cc ++++ b/src/processor/symbolic_constants_win.cc +@@ -6409,9 +6409,214 @@ string NTStatusToString(uint32_t ntstatu + snprintf(reason_string, sizeof(reason_string), "0x%08x", ntstatus); + reason = reason_string; + break; + } + } + return reason; + } + ++string FastFailToString(uint32_t fast_fail_code) { ++ string code_string; ++ // The content of this switch was created from winnt.h in the 10 SDK ++ // (version 10.0.19041.0) with ++ // ++ // egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h ++ // | tr -d '\r' ++ // | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' ++ // | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ case MD_FAST_FAIL_WIN_\2:\n code_string = "FAST_FAIL_\2";\n break;@' ++ // ++ // and then the default case added. ++ switch (fast_fail_code) { ++ case MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION: ++ code_string = "FAST_FAIL_LEGACY_GS_VIOLATION"; ++ break; ++ case MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE: ++ code_string = "FAST_FAIL_VTGUARD_CHECK_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE: ++ code_string = "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY: ++ code_string = "FAST_FAIL_CORRUPT_LIST_ENTRY"; ++ break; ++ case MD_FAST_FAIL_WIN_INCORRECT_STACK: ++ code_string = "FAST_FAIL_INCORRECT_STACK"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_ARG: ++ code_string = "FAST_FAIL_INVALID_ARG"; ++ break; ++ case MD_FAST_FAIL_WIN_GS_COOKIE_INIT: ++ code_string = "FAST_FAIL_GS_COOKIE_INIT"; ++ break; ++ case MD_FAST_FAIL_WIN_FATAL_APP_EXIT: ++ code_string = "FAST_FAIL_FATAL_APP_EXIT"; ++ break; ++ case MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE: ++ code_string = "FAST_FAIL_RANGE_CHECK_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS: ++ code_string = "FAST_FAIL_UNSAFE_REGISTRY_ACCESS"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE: ++ code_string = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE: ++ code_string = "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH: ++ code_string = "FAST_FAIL_INVALID_FIBER_SWITCH"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT: ++ code_string = "FAST_FAIL_INVALID_SET_OF_CONTEXT"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT: ++ code_string = "FAST_FAIL_INVALID_REFERENCE_COUNT"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER: ++ code_string = "FAST_FAIL_INVALID_JUMP_BUFFER"; ++ break; ++ case MD_FAST_FAIL_WIN_MRDATA_MODIFIED: ++ code_string = "FAST_FAIL_MRDATA_MODIFIED"; ++ break; ++ case MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE: ++ code_string = "FAST_FAIL_CERTIFICATION_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN: ++ code_string = "FAST_FAIL_INVALID_EXCEPTION_CHAIN"; ++ break; ++ case MD_FAST_FAIL_WIN_CRYPTO_LIBRARY: ++ code_string = "FAST_FAIL_CRYPTO_LIBRARY"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT: ++ code_string = "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE: ++ code_string = "FAST_FAIL_INVALID_IMAGE_BASE"; ++ break; ++ case MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE: ++ code_string = "FAST_FAIL_DLOAD_PROTECTION_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL: ++ code_string = "FAST_FAIL_UNSAFE_EXTENSION_CALL"; ++ break; ++ case MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED: ++ code_string = "FAST_FAIL_DEPRECATED_SERVICE_INVOKED"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS: ++ code_string = "FAST_FAIL_INVALID_BUFFER_ACCESS"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE: ++ code_string = "FAST_FAIL_INVALID_BALANCED_TREE"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD: ++ code_string = "FAST_FAIL_INVALID_NEXT_THREAD"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED: ++ code_string = "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED"; ++ break; ++ case MD_FAST_FAIL_WIN_APCS_DISABLED: ++ code_string = "FAST_FAIL_APCS_DISABLED"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_IDLE_STATE: ++ code_string = "FAST_FAIL_INVALID_IDLE_STATE"; ++ break; ++ case MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE: ++ code_string = "FAST_FAIL_MRDATA_PROTECTION_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION: ++ code_string = "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_LOCK_STATE: ++ code_string = "FAST_FAIL_INVALID_LOCK_STATE"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_JUMPTABLE: ++ code_string = "FAST_FAIL_GUARD_JUMPTABLE"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET: ++ code_string = "FAST_FAIL_INVALID_LONGJUMP_TARGET"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT: ++ code_string = "FAST_FAIL_INVALID_DISPATCH_CONTEXT"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_THREAD: ++ code_string = "FAST_FAIL_INVALID_THREAD"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER: ++ code_string = "FAST_FAIL_INVALID_SYSCALL_NUMBER"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION: ++ code_string = "FAST_FAIL_INVALID_FILE_OPERATION"; ++ break; ++ case MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED: ++ code_string = "FAST_FAIL_LPAC_ACCESS_DENIED"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_SS_FAILURE: ++ code_string = "FAST_FAIL_GUARD_SS_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE: ++ code_string = "FAST_FAIL_LOADER_CONTINUITY_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE: ++ code_string = "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK: ++ code_string = "FAST_FAIL_INVALID_CONTROL_STACK"; ++ break; ++ case MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED: ++ code_string = "FAST_FAIL_SET_CONTEXT_DENIED"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_IAT: ++ code_string = "FAST_FAIL_INVALID_IAT"; ++ break; ++ case MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION: ++ code_string = "FAST_FAIL_HEAP_METADATA_CORRUPTION"; ++ break; ++ case MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION: ++ code_string = "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION"; ++ break; ++ case MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED: ++ code_string = "FAST_FAIL_LOW_LABEL_ACCESS_DENIED"; ++ break; ++ case MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE: ++ code_string = "FAST_FAIL_ENCLAVE_CALL_FAILURE"; ++ break; ++ case MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON: ++ code_string = "FAST_FAIL_UNHANDLED_LSS_EXCEPTON"; ++ break; ++ case MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED: ++ code_string = "FAST_FAIL_ADMINLESS_ACCESS_DENIED"; ++ break; ++ case MD_FAST_FAIL_WIN_UNEXPECTED_CALL: ++ code_string = "FAST_FAIL_UNEXPECTED_CALL"; ++ break; ++ case MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS: ++ code_string = "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS"; ++ break; ++ case MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR: ++ code_string = "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR"; ++ break; ++ case MD_FAST_FAIL_WIN_FLAGS_CORRUPTION: ++ code_string = "FAST_FAIL_FLAGS_CORRUPTION"; ++ break; ++ case MD_FAST_FAIL_WIN_VEH_CORRUPTION: ++ code_string = "FAST_FAIL_VEH_CORRUPTION"; ++ break; ++ case MD_FAST_FAIL_WIN_ETW_CORRUPTION: ++ code_string = "FAST_FAIL_ETW_CORRUPTION"; ++ break; ++ case MD_FAST_FAIL_WIN_RIO_ABORT: ++ code_string = "FAST_FAIL_RIO_ABORT"; ++ break; ++ case MD_FAST_FAIL_WIN_INVALID_PFN: ++ code_string = "FAST_FAIL_INVALID_PFN"; ++ break; ++ default: { ++ char buffer[11]; ++ snprintf(buffer, sizeof(buffer), "%u", fast_fail_code); ++ code_string = buffer; ++ break; ++ } ++ } ++ return code_string; ++} ++ + } // namespace google_breakpad +diff --git a/src/processor/symbolic_constants_win.h b/src/processor/symbolic_constants_win.h +--- a/src/processor/symbolic_constants_win.h ++++ b/src/processor/symbolic_constants_win.h +@@ -41,11 +41,14 @@ + #include "common/using_std_string.h" + #include "google_breakpad/common/breakpad_types.h" + + namespace google_breakpad { + + /* Converts a NTSTATUS code to a reason string. */ + string NTStatusToString(uint32_t ntstatus); + ++/* Converts a FAST_FAIL code to a reason string. */ ++string FastFailToString(uint32_t fast_fail_code); ++ + } // namespace google_breakpad + + #endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ + diff --git a/toolkit/crashreporter/breakpad-patches/19-updated-ntstatus.patch b/toolkit/crashreporter/breakpad-patches/19-updated-ntstatus.patch new file mode 100644 index 0000000000..13c6597435 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/19-updated-ntstatus.patch @@ -0,0 +1,3500 @@ +changeset: 651287:a6a1b6cc572e +tag: tip +parent: 651282:232ec0fbbaaa +user: Gabriele Svelto +date: Thu Apr 08 11:13:10 2021 +0200 +summary: Updated ntstatus.h definitions in Breakpad + +diff --git a/src/google_breakpad/common/minidump_exception_win32.h b/src/google_breakpad/common/minidump_exception_win32.h +--- a/src/google_breakpad/common/minidump_exception_win32.h ++++ b/src/google_breakpad/common/minidump_exception_win32.h +@@ -39,22 +39,18 @@ + #ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ + #define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ + + #include + + #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). */ ++/* For (MDException).exception_code. These values come from WinBase.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 */ +@@ -93,51 +89,291 @@ typedef enum { + MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096, + /* EXCEPTION_PRIV_INSTRUCTION */ + MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd, + /* EXCEPTION_STACK_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE = 0xc00000ff, + /* EXCEPTION_BAD_FUNCTION_TABLE */ + MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194, + /* EXCEPTION_POSSIBLE_DEADLOCK */ +- MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409, +- /* STATUS_STACK_BUFFER_OVERRUN */ +- MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374, +- /* STATUS_HEAP_CORRUPTION */ + MD_EXCEPTION_OUT_OF_MEMORY = 0xe0000008, + /* Exception thrown by Chromium allocators to indicate OOM. + See base/process/memory.h in Chromium for rationale. */ + MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363, + /* Per http://support.microsoft.com/kb/185294, + generated by Visual C++ compiler */ + MD_EXCEPTION_CODE_WIN_SIMULATED = 0x0517a7ed + /* Fake exception code used by Crashpad's + CrashpadClient::DumpWithoutCrash. */ + } MDExceptionCodeWin; + + + /* For (MDException).exception_information[2], when (MDException).exception_code + * is MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR. This describes the underlying reason + * for the error. These values come from ntstatus.h. + * +- * The content of this enum was created from ntstatus.h in the 8.1 SDK with ++ * The content of this enum was created from ntstatus.h in the 10 SDK ++ * (version 10.0.19041.0) with + * +- * egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0xC[0-9A-F]+L\)' ntstatus.h ++ * egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h + * | tr -d '\r' +- * | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0xC[0-9A-F]+)L\).*@\2 \1@' ++ * | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' + * | sort +- * | sed -r 's@(0xC[0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2 = \1,@' ++ * | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2 = \1,@' + * + * With easy copy to clipboard with + * | xclip -selection c # on linux + * | clip # on windows +- * | pbcopy # on mac +- * +- * and then the last comma manually removed. */ ++ * | pbcopy # on mac */ + typedef enum { ++ MD_NTSTATUS_WIN_STATUS_SUCCESS = 0x00000000, ++ MD_NTSTATUS_WIN_STATUS_WAIT_0 = 0x00000000, ++ MD_NTSTATUS_WIN_STATUS_WAIT_1 = 0x00000001, ++ MD_NTSTATUS_WIN_STATUS_WAIT_2 = 0x00000002, ++ MD_NTSTATUS_WIN_STATUS_WAIT_3 = 0x00000003, ++ MD_NTSTATUS_WIN_STATUS_WAIT_63 = 0x0000003F, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED = 0x00000080, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_0 = 0x00000080, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63 = 0x000000BF, ++ MD_NTSTATUS_WIN_STATUS_USER_APC = 0x000000C0, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE = 0x000000FF, ++ MD_NTSTATUS_WIN_STATUS_KERNEL_APC = 0x00000100, ++ MD_NTSTATUS_WIN_STATUS_ALERTED = 0x00000101, ++ MD_NTSTATUS_WIN_STATUS_TIMEOUT = 0x00000102, ++ MD_NTSTATUS_WIN_STATUS_PENDING = 0x00000103, ++ MD_NTSTATUS_WIN_STATUS_REPARSE = 0x00000104, ++ MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES = 0x00000105, ++ MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED = 0x00000106, ++ MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED = 0x00000107, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS = 0x00000108, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED = 0x00000109, ++ MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED = 0x0000010A, ++ MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP = 0x0000010B, ++ MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR = 0x0000010C, ++ MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT = 0x0000010D, ++ MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED = 0x0000010E, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION = 0x00000110, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO = 0x00000111, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE = 0x00000112, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE = 0x00000113, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE = 0x00000114, ++ MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED = 0x00000115, ++ MD_NTSTATUS_WIN_STATUS_CRASH_DUMP = 0x00000116, ++ MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS = 0x00000117, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT = 0x00000118, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED = 0x00000119, ++ MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE = 0x00000120, ++ MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY = 0x00000121, ++ MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE = 0x00000122, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB = 0x00000123, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB = 0x00000124, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY = 0x00000125, ++ MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY = 0x00000126, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED = 0x00000127, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED = 0x00000128, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED = 0x00000129, ++ MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS = 0x0000012A, ++ MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS = 0x0000012B, ++ MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH = 0x0000012C, ++ MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH = 0x0000012D, ++ MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH = 0x0000012E, ++ MD_NTSTATUS_WIN_STATUS_GHOSTED = 0x0000012F, ++ MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN = 0x00000130, ++ MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY = 0x00000202, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY = 0x00000210, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL = 0x00000211, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA = 0x00000212, ++ MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY = 0x00000213, ++ MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT = 0x00000214, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE = 0x00000215, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED = 0x00000216, ++ MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK = 0x00000367, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL = 0x00000368, ++ MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED = 0x00010001, ++ MD_NTSTATUS_WIN_DBG_CONTINUE = 0x00010002, ++ MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE = 0x001C0001, ++ MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE = 0x00293000, ++ MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE = 0x00293001, ++ MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS = 0x00350059, ++ MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED = 0x00E70000, ++ MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE = 0x00E70001, ++ MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE = 0x00E70002, ++ MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT = 0x00E70003, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS = 0x40000000, ++ MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED = 0x40000001, ++ MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE = 0x40000002, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE = 0x40000003, ++ MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED = 0x40000004, ++ MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION = 0x40000005, ++ MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY = 0x40000006, ++ MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY = 0x40000007, ++ MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES = 0x40000008, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED = 0x40000009, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP = 0x4000000A, ++ MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY = 0x4000000B, ++ MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT = 0x4000000C, ++ MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD = 0x4000000D, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH = 0x4000000E, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL = 0x4000000F, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED = 0x40000010, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED = 0x40000011, ++ MD_NTSTATUS_WIN_STATUS_EVENT_DONE = 0x40000012, ++ MD_NTSTATUS_WIN_STATUS_EVENT_PENDING = 0x40000013, ++ MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM = 0x40000014, ++ MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT = 0x40000015, ++ MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE = 0x40000016, ++ MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED = 0x40000017, ++ MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION = 0x40000018, ++ MD_NTSTATUS_WIN_STATUS_WAS_LOCKED = 0x40000019, ++ MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR = 0x4000001A, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32 = 0x4000001B, ++ MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE = 0x4000001C, ++ MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE = 0x4000001D, ++ MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP = 0x4000001E, ++ MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT = 0x4000001F, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE = 0x40000020, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE = 0x40000021, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN = 0x40000022, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE = 0x40000023, ++ MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED = 0x40000024, ++ MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED = 0x40000025, ++ MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED = 0x40000026, ++ MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED = 0x40000027, ++ MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB = 0x40000028, ++ MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH = 0x40000029, ++ MD_NTSTATUS_WIN_STATUS_HIBERNATED = 0x4000002A, ++ MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION = 0x4000002B, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED = 0x4000002C, ++ MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES = 0x4000002D, ++ MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED = 0x4000002E, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION = 0x4000002F, ++ MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST = 0x40000030, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 0x40000031, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY = 0x40000032, ++ MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE = 0x40000033, ++ MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED = 0x40000034, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY = 0x40000035, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE = 0x40000036, ++ MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED = 0x40000037, ++ MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM = 0x40000294, ++ MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN = 0x40000370, ++ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED = 0x40000807, ++ MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART = 0x4000A144, ++ MD_NTSTATUS_WIN_DBG_REPLY_LATER = 0x40010001, ++ MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE = 0x40010002, ++ MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD = 0x40010003, ++ MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS = 0x40010004, ++ MD_NTSTATUS_WIN_DBG_CONTROL_C = 0x40010005, ++ MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C = 0x40010006, ++ MD_NTSTATUS_WIN_DBG_RIPEXCEPTION = 0x40010007, ++ MD_NTSTATUS_WIN_DBG_CONTROL_BREAK = 0x40010008, ++ MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION = 0x40010009, ++ MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C = 0x4001000A, ++ MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY = 0x40020056, ++ MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE = 0x400200AF, ++ MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT = 0x400A0004, ++ MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT = 0x400A0005, ++ MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT = 0x4015000D, ++ MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE = 0x40190001, ++ MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED = 0x40190034, ++ MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED = 0x40190035, ++ MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART = 0x401A000C, ++ MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST = 0x401B00EC, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED = 0x401E000A, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION = 0x401E0201, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED = 0x401E0307, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE = 0x401E031E, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY = 0x401E034B, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET = 0x401E034C, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED = 0x401E0351, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS = 0x401E042F, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED = 0x401E0437, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY = 0x401E0439, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED = 0x401E043A, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS = 0x401E043C, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED = 0x40230001, ++ MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT = 0x40292023, ++ MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION = 0x80000001, ++ MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT = 0x80000002, ++ MD_NTSTATUS_WIN_STATUS_BREAKPOINT = 0x80000003, ++ MD_NTSTATUS_WIN_STATUS_SINGLE_STEP = 0x80000004, ++ MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW = 0x80000005, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES = 0x80000006, ++ MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER = 0x80000007, ++ MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED = 0x8000000A, ++ MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE = 0x8000000B, ++ MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE = 0x8000000C, ++ MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY = 0x8000000D, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY = 0x8000000E, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF = 0x8000000F, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE = 0x80000010, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY = 0x80000011, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS = 0x80000012, ++ MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME = 0x80000013, ++ MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT = 0x80000014, ++ MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG = 0x80000015, ++ MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED = 0x80000016, ++ MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION = 0x80000017, ++ MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY = 0x80000018, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES = 0x8000001A, ++ MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED = 0x8000001B, ++ MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED = 0x8000001C, ++ MD_NTSTATUS_WIN_STATUS_BUS_RESET = 0x8000001D, ++ MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA = 0x8000001E, ++ MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA = 0x8000001F, ++ MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK = 0x80000020, ++ MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED = 0x80000021, ++ MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED = 0x80000022, ++ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES = 0x80000023, ++ MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES = 0x80000024, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED = 0x80000025, ++ MD_NTSTATUS_WIN_STATUS_LONGJUMP = 0x80000026, ++ MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED = 0x80000027, ++ MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED = 0x80000028, ++ MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE = 0x80000029, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED = 0x8000002A, ++ MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE = 0x8000002B, ++ MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE = 0x8000002C, ++ MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK = 0x8000002D, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK = 0x8000002E, ++ MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION = 0x8000002F, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS = 0x80000030, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED = 0x80000031, ++ MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE = 0x80000032, ++ MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT = 0x80000033, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING = 0x80000288, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN = 0x80000289, ++ MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR = 0x80000803, ++ MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED = 0x8000A127, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH = 0x8000CF00, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE = 0x8000CF04, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS = 0x8000CF05, ++ MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED = 0x80010001, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP = 0x80130001, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN = 0x80130002, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE = 0x80130003, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE = 0x80130004, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER = 0x80130005, ++ MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG = 0x80190009, ++ MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA = 0x80190029, ++ MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN = 0x80190031, ++ MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT = 0x80190041, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 0x80190042, ++ MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED = 0x801B00EB, ++ MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL = 0x801C0001, ++ MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA = 0x80210001, ++ MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE = 0x80210002, ++ MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED = 0x80370001, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION = 0x80380001, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION = 0x80380002, ++ MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED = 0x80390001, ++ MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED = 0x80390003, ++ MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR = 0x803A0001, ++ MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK = 0x803F0001, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED = 0x80430006, + MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL = 0xC0000001, + MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED = 0xC0000002, + MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS = 0xC0000003, + MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH = 0xC0000004, + MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION = 0xC0000005, + MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR = 0xC0000006, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA = 0xC0000007, + MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE = 0xC0000008, +@@ -181,16 +417,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES = 0xC000002E, + MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG = 0xC000002F, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX = 0xC0000030, + MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER = 0xC0000031, + MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR = 0xC0000032, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID = 0xC0000033, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION = 0xC0000035, ++ MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB = 0xC0000036, + MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED = 0xC0000037, + MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED = 0xC0000038, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID = 0xC0000039, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B, + MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN = 0xC000003C, + MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR = 0xC000003D, + MD_NTSTATUS_WIN_STATUS_DATA_ERROR = 0xC000003E, +@@ -549,16 +786,24 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3, + MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4, + MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER = 0xC00001A5, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES = 0xC00001A6, + MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE = 0xC00001A7, + MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED = 0xC00001A8, + MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED = 0xC00001A9, + MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE = 0xC00001AA, ++ MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS = 0xC00001AB, ++ MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT = 0xC00001AC, ++ MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION = 0xC00001AD, ++ MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB = 0xC00001AE, ++ MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID = 0xC00001AF, ++ MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA = 0xC00001B0, ++ MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE = 0xC00001B1, ++ MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION = 0xC00001B2, + MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION = 0xC0000201, + MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY = 0xC0000202, + MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED = 0xC0000203, + MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND = 0xC0000204, + MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, + MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE = 0xC0000206, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT = 0xC0000207, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD = 0xC0000208, +@@ -664,16 +909,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES = 0xC0000273, + MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT = 0xC0000275, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID = 0xC0000276, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH = 0xC0000277, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID = 0xC0000278, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG = 0xC000027A, + MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION = 0xC000027B, ++ MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION = 0xC000027C, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED = 0xC0000280, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281, + MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT = 0xC0000282, + MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY = 0xC0000283, + MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL = 0xC0000284, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS = 0xC0000285, + MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT = 0xC0000286, + MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED = 0xC0000287, +@@ -796,16 +1042,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE = 0xC0000305, + MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE = 0xC0000306, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT = 0xC0000307, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED = 0xC0000308, + MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR = 0xC0000309, + MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH = 0xC000030A, + MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED = 0xC000030B, + MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED = 0xC000030C, ++ MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION = 0xC000030D, + MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE = 0xC0000320, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321, + MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY = 0xC0000322, + MD_NTSTATUS_WIN_STATUS_HOST_DOWN = 0xC0000350, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH = 0xC0000351, + MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG = 0xC0000352, + MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET = 0xC0000353, + MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE = 0xC0000354, +@@ -928,16 +1175,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE = 0xC0000467, + MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES = 0xC0000468, + MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING = 0xC0000469, + MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY = 0xC000046A, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE = 0xC000046B, + MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED = 0xC000046C, + MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED = 0xC000046D, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 0xC000046E, ++ MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL = 0xC000046F, + MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR = 0xC0000470, + MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION = 0xC0000471, + MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED = 0xC0000472, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS = 0xC0000473, + MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT = 0xC0000474, + MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST = 0xC0000475, + MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS = 0xC0000476, + MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH = 0xC0000477, +@@ -948,26 +1196,101 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED = 0xC000047C, + MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT = 0xC000047D, + MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION = 0xC000047E, + MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN = 0xC000047F, + MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE = 0xC0000480, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED = 0xC0000481, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT = 0xC0000482, + MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR = 0xC0000483, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID = 0xC0000484, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID = 0xC0000485, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH = 0xC0000486, ++ MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE = 0xC0000487, ++ MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS = 0xC0000488, ++ MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION = 0xC0000489, ++ MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY = 0xC000048A, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE = 0xC000048B, ++ MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES = 0xC000048C, ++ MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES = 0xC000048D, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP = 0xC000048E, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE = 0xC000048F, ++ MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS = 0xC0000490, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND = 0xC0000491, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND = 0xC0000492, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE = 0xC0000493, ++ MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED = 0xC0000494, ++ MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING = 0xC0000495, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL = 0xC0000496, ++ MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE = 0xC0000497, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE = 0xC0000499, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX = 0xC000049A, ++ MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED = 0xC000049B, ++ MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS = 0xC000049C, ++ MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED = 0xC000049D, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE = 0xC000049E, ++ MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED = 0xC000049F, ++ MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING = 0xC00004A0, ++ MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED = 0xC00004A1, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION = 0xC00004A2, ++ MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL = 0xC00004A3, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED = 0xC00004A4, ++ MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND = 0xC00004A5, ++ MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED = 0xC00004A6, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED = 0xC00004A7, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET = 0xC00004A8, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE = 0xC00004A9, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER = 0xC00004AA, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE = 0xC00004AB, ++ MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT = 0xC00004AC, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID = 0xC00004AD, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST = 0xC00004AE, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS = 0xC00004AF, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY = 0xC00004B0, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME = 0xC00004B1, ++ MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE = 0xC00004B2, ++ MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR = 0xC00004B3, ++ MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED = 0xC00004B4, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT = 0xC00004B5, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED = 0xC00004B6, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED = 0xC00004B7, ++ MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG = 0xC00004B8, ++ MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES = 0xC00004B9, ++ MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH = 0xC00004BA, ++ MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES = 0xC00004BD, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME = 0xC0000500, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX = 0xC0000501, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK = 0xC0000502, + MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS = 0xC0000503, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE = 0xC0000504, + MD_NTSTATUS_WIN_STATUS_INVALID_CAP = 0xC0000505, + MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS = 0xC0000506, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG = 0xC0000507, ++ MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED = 0xC0000508, ++ MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER = 0xC0000509, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE = 0xC000050A, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B, ++ MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT = 0xC000050C, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME = 0xC000050D, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID = 0xC000050E, ++ MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY = 0xC000050F, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED = 0xC0000510, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED = 0xC0000511, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING = 0xC0000512, ++ MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE = 0xC0000513, ++ MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED = 0xC0000514, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPTED = 0xC0000515, ++ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING = 0xC0000516, + MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION = 0xC0000602, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED = 0xC0000603, + MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED = 0xC0000604, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED = 0xC0000605, ++ MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION = 0xC0000606, ++ MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED = 0xC000060A, ++ MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION = 0xC000060B, + MD_NTSTATUS_WIN_STATUS_PORT_CLOSED = 0xC0000700, + MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST = 0xC0000701, + MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE = 0xC0000702, + MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED = 0xC0000703, + MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH = 0xC0000704, + MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705, + MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE = 0xC0000706, + MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED = 0xC0000707, +@@ -992,16 +1315,21 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B, + MD_NTSTATUS_WIN_STATUS_INVALID_THREAD = 0xC000071C, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION = 0xC000071D, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK = 0xC000071E, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG = 0xC000071F, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK = 0xC0000720, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721, ++ MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED = 0xC0000722, ++ MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE = 0xC0000723, ++ MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE = 0xC0000724, ++ MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE = 0xC0000725, ++ MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE = 0xC0000726, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED = 0xC0000800, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801, + MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED = 0xC0000802, + MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED = 0xC0000804, + MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS = 0xC0000805, + MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY = 0xC0000806, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL = 0xC0000808, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL = 0xC0000809, +@@ -1028,16 +1356,19 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED = 0xC0000910, + MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION = 0xC0009898, + MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE = 0xC000A000, + MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED = 0xC000A001, + MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH = 0xC000A002, + MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION = 0xC000A003, + MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION = 0xC000A004, + MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION = 0xC000A005, ++ MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED = 0xC000A006, ++ MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE = 0xC000A007, ++ MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN = 0xC000A008, + MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW = 0xC000A010, + MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW = 0xC000A011, + MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED = 0xC000A012, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED = 0xC000A013, + MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED = 0xC000A014, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082, +@@ -1059,25 +1390,72 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL = 0xC000A141, + MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING = 0xC000A142, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT = 0xC000A143, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 0xC000A145, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS = 0xC000A146, + MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER = 0xC000A200, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER = 0xC000A201, + MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH = 0xC000A202, ++ MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED = 0xC000A203, ++ MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED = 0xC000A204, + MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND = 0xC000A281, + MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED = 0xC000A282, + MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT = 0xC000A283, + MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED = 0xC000A284, + MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED = 0xC000A285, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4, ++ MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT = 0xC000A2A5, ++ MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT = 0xC000A2A6, ++ MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT = 0xC000A2A7, ++ MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT = 0xC000C001, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE = 0xC000CE01, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT = 0xC000CE02, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY = 0xC000CE03, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN = 0xC000CE04, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION = 0xC000CE05, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT = 0xC000CF00, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING = 0xC000CF01, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT = 0xC000CF02, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE = 0xC000CF03, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED = 0xC000CF06, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE = 0xC000CF07, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC = 0xC000CF08, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED = 0xC000CF09, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED = 0xC000CF0A, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST = 0xC000CF0B, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME = 0xC000CF0C, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY = 0xC000CF0D, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED = 0xC000CF0E, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED = 0xC000CF0F, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES = 0xC000CF10, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE = 0xC000CF11, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL = 0xC000CF12, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT = 0xC000CF13, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE = 0xC000CF14, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED = 0xC000CF15, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED = 0xC000CF16, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT = 0xC000CF17, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED = 0xC000CF18, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS = 0xC000CF19, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT = 0xC000CF1A, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED = 0xC000CF1B, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED = 0xC000CF1D, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT = 0xC000CF1E, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT = 0xC000CF1F, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED = 0xC000CF20, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS = 0xC000F500, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED = 0xC000F501, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED = 0xC000F502, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED = 0xC000F503, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR = 0xC000F504, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER = 0xC000F505, + MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE = 0xC0010001, + MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE = 0xC0010002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING = 0xC0020001, + MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING = 0xC0020003, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004, + MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID = 0xC0020006, +@@ -1263,16 +1641,21 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL = 0xC0130019, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS = 0xC0130020, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR = 0xC0130021, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED = 0xC0130022, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED = 0xC0130023, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING = 0xC0130024, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS = 0xC0130025, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL = 0xC0130026, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS = 0xC0130027, ++ MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT = 0xC0130028, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE = 0xC0130029, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR = 0xC0130030, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED = 0xC0130031, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE = 0xC0140001, + MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW = 0xC0140002, + MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED = 0xC0140003, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX = 0xC0140004, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT = 0xC0140005, + MD_NTSTATUS_WIN_STATUS_ACPI_FATAL = 0xC0140006, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME = 0xC0140007, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE = 0xC0140008, +@@ -1504,16 +1887,21 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED = 0xC01E0007, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH = 0xC01E0009, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE = 0xC01E000D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED = 0xC01E000E, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW = 0xC01E000F, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND = 0xC01E0010, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED = 0xC01E0011, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN = 0xC01E0012, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED = 0xC01E0013, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY = 0xC01E0102, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID = 0xC01E0106, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107, +@@ -1725,16 +2113,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED = 0xC0210038, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED = 0xC0210039, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE = 0xC021003A, + MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT = 0xC021003B, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT = 0xC021003C, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME = 0xC021003D, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED = 0xC021003E, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED = 0xC021003F, ++ MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED = 0xC0210040, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND = 0xC0220001, + MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND = 0xC0220002, + MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND = 0xC0220003, + MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND = 0xC0220004, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND = 0xC0220005, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006, + MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND = 0xC0220007, + MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND = 0xC0220008, +@@ -1832,25 +2221,32 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS = 0xC0230022, + MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED = 0xC023002A, + MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND = 0xC023002B, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION = 0xC023002C, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT = 0xC023002D, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE = 0xC023002E, + MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE = 0xC023002F, + MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED = 0xC0230030, ++ MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES = 0xC0230031, + MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED = 0xC02300BB, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY = 0xC023100F, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE = 0xC0232001, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE = 0xC0232005, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE = 0xC0232006, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED = 0xC0232007, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED = 0xC0232008, ++ MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE = 0xC0240000, ++ MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE = 0xC0240001, + MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK = 0xC0290000, + MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL = 0xC0290001, + MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX = 0xC0290002, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER = 0xC0290003, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE = 0xC0290004, + MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED = 0xC0290005, + MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED = 0xC0290006, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED = 0xC0290007, +@@ -1940,16 +2336,84 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS = 0xC029005B, + MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE = 0xC029005C, + MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION = 0xC029005D, + MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE = 0xC029005E, + MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY = 0xC029005F, + MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK = 0xC0290061, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE = 0xC0290062, + MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE = 0xC0290063, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC = 0xC0290081, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES = 0xC0290082, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH = 0xC0290083, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE = 0xC0290084, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY = 0xC0290085, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE = 0xC0290087, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF = 0xC0290088, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE = 0xC0290089, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE = 0xC029008A, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE = 0xC029008B, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF = 0xC029008C, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE = 0xC029008D, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL = 0xC029008E, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE = 0xC029008F, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP = 0xC0290090, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME = 0xC0290092, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE = 0xC0290095, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC = 0xC0290096, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG = 0xC0290097, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR = 0xC0290098, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT = 0xC029009A, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE = 0xC029009B, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY = 0xC029009C, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL = 0xC029009D, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY = 0xC029009F, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET = 0xC02900A0, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS = 0xC02900A1, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH = 0xC02900A2, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED = 0xC02900A3, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC = 0xC02900A4, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING = 0xC02900A5, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE = 0xC02900A6, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT = 0xC02900A7, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE = 0xC0290100, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE = 0xC0290101, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE = 0xC0290103, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE = 0xC029010B, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC = 0xC0290119, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED = 0xC0290120, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE = 0xC0290121, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE = 0xC0290123, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE = 0xC0290124, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING = 0xC0290125, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY = 0xC0290126, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR = 0xC0290127, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED = 0xC0290128, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE = 0xC029012D, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS = 0xC029012E, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE = 0xC029012F, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT = 0xC0290130, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED = 0xC0290131, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE = 0xC0290142, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE = 0xC0290143, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE = 0xC0290144, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT = 0xC0290145, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE = 0xC0290146, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE = 0xC0290147, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED = 0xC0290148, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION = 0xC0290149, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED = 0xC029014A, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE = 0xC029014B, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED = 0xC029014C, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT = 0xC0290150, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH = 0xC0290151, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT = 0xC0290152, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST = 0xC0290153, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT = 0xC0290154, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE = 0xC0290155, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED = 0xC0290400, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE = 0xC0290401, + MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE = 0xC0290402, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED = 0xC0290403, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED = 0xC0290404, + MD_NTSTATUS_WIN_STATUS_TPM_RETRY = 0xC0290800, + MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST = 0xC0290801, + MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST = 0xC0290802, +@@ -1969,16 +2433,42 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL = 0xC0292006, + MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR = 0xC0292007, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED = 0xC0292008, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED = 0xC0292009, + MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND = 0xC029200A, + MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND = 0xC029200B, + MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED = 0xC029200C, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND = 0xC029200D, ++ MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT = 0xC029200E, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED = 0xC029200F, ++ MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION = 0xC0292010, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED = 0xC0292011, ++ MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET = 0xC0292012, ++ MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND = 0xC0292013, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED = 0xC0292014, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED = 0xC0292015, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID = 0xC0292016, ++ MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR = 0xC0292017, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED = 0xC0292018, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK = 0xC0292019, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY = 0xC029201A, ++ MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT = 0xC029201B, ++ MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED = 0xC029201C, ++ MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED = 0xC029201D, ++ MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH = 0xC029201E, ++ MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED = 0xC029201F, ++ MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING = 0xC0292020, ++ MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED = 0xC0292021, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED = 0xC0292022, ++ MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT = 0xC0293002, ++ MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE = 0xC0293003, ++ MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT = 0xC0293004, ++ MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD = 0xC0293005, ++ MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED = 0xC0294000, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE = 0xC0350002, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT = 0xC0350003, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT = 0xC0350004, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER = 0xC0350005, + MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED = 0xC0350006, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE = 0xC0350007, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED = 0xC0350008, + MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY = 0xC0350009, +@@ -1986,28 +2476,46 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY = 0xC035000B, + MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP = 0xC035000C, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID = 0xC035000D, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX = 0xC035000E, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID = 0xC0350011, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID = 0xC0350012, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS = 0xC0350013, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED = 0xC0350014, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE = 0xC0350015, + MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED = 0xC0350016, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE = 0xC0350017, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE = 0xC0350018, + MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE = 0xC0350019, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO = 0xC035001A, + MD_NTSTATUS_WIN_STATUS_HV_NO_DATA = 0xC035001B, + MD_NTSTATUS_WIN_STATUS_HV_INACTIVE = 0xC035001C, + MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES = 0xC035001D, + MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE = 0xC035001E, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER = 0xC0350033, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS = 0xC0350038, ++ MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR = 0xC035003C, ++ MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR = 0xC035003D, ++ MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT = 0xC035003E, ++ MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED = 0xC035003F, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX = 0xC0350041, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE = 0xC0350050, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE = 0xC0350051, ++ MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED = 0xC0350055, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID = 0xC0350057, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE = 0xC0350058, ++ MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID = 0xC0350060, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID = 0xC035006F, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE = 0xC0350070, ++ MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED = 0xC0350071, ++ MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE = 0xC0350072, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY = 0xC0350073, ++ MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED = 0xC0350074, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY = 0xC0350075, + MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT = 0xC0351000, + MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI = 0xC0360001, + MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002, + MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA = 0xC0360003, + MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED = 0xC0360004, + MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET = 0xC0360005, + MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006, + MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP = 0xC0360007, +@@ -2056,16 +2564,17 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET = 0xC0370022, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED = 0xC0370023, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL = 0xC0370024, + MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE = 0xC0370025, + MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT = 0xC0370026, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT = 0xC0370027, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM = 0xC0370028, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE = 0xC0370029, ++ MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED = 0xC037002A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL = 0xC0380001, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED = 0xC0380002, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC = 0xC0380003, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED = 0xC0380004, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME = 0xC0380005, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE = 0xC0380006, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC = 0xC0380007, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID = 0xC0380008, +@@ -2186,25 +2695,32 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED = 0xC03A001E, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE = 0xC03A001F, + MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED = 0xC03A0020, + MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE = 0xC03A0021, + MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE = 0xC03A0022, + MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE = 0xC03A0023, + MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE = 0xC03A0024, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL = 0xC03A0028, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID = 0xC03A0029, ++ MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED = 0xC03A002A, ++ MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION = 0xC03A0030, ++ MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA = 0xC03A0031, ++ MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE = 0xC03A0032, ++ MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE = 0xC03A0033, + MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND = 0xC0400001, + MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY = 0xC0400002, + MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL = 0xC0400003, + MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL = 0xC0400004, + MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED = 0xC0400005, + MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY = 0xC0400006, + MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION = 0xC0410001, + MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION = 0xC0410002, + MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION = 0xC0410003, ++ MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP = 0xC0410004, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE = 0xC0420001, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED = 0xC0420002, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED = 0xC0420003, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU = 0xC0420004, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION = 0xC0420005, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED = 0xC0420006, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET = 0xC0420007, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION = 0xC0420008, +@@ -2219,40 +2735,113 @@ typedef enum { + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES = 0xC0420011, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR = 0xC0421000, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED = 0xC0430001, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION = 0xC0430002, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY = 0xC0430003, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 0xC0430004, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED = 0xC0430005, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED = 0xC0430007, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED = 0xC0430008, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN = 0xC0430009, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION = 0xC043000A, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH = 0xC043000B, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED = 0xC043000C, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH = 0xC043000D, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING = 0xC043000E, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY = 0xC043000F, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY = 0xC0430010, + MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND = 0xC0440001, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST = 0xC0440002, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED = 0xC0440003, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED = 0xC0440004, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY = 0xC0440005, ++ MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED = 0xC0450000, ++ MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE = 0xC0450001, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID = 0xC0500003, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT = 0xC0500004, + MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED = 0xC0510001, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED = 0xC05C0000, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE = 0xC05CFF00, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE = 0xC05CFF01, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED = 0xC05CFF02, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED = 0xC05CFF03, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED = 0xC05CFF04, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED = 0xC05CFF05, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED = 0xC05CFF06, + MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT = 0xC05CFF07, + MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE = 0xC05CFF08, + MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH = 0xC05CFF09, + MD_NTSTATUS_WIN_STATUS_VHD_SHARED = 0xC05CFF0A, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR = 0xC05CFF0B, ++ MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND = 0xC05CFF0C, ++ MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP = 0xC05D0000, ++ MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT = 0xC05D0001, ++ MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED = 0xC05D0002, ++ MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID = 0xC0E70001, + MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID = 0xC0E70003, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID = 0xC0E70004, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID = 0xC0E70006, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID = 0xC0E70007, + MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID = 0xC0E70009, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID = 0xC0E7000A, +- MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES = 0xC0E7000B ++ MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES = 0xC0E7000B, ++ MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR = 0xC0E7000C, ++ MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID = 0xC0E7000D, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID = 0xC0E7000E, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID = 0xC0E7000F, ++ MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID = 0xC0E70010, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID = 0xC0E70011, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID = 0xC0E70012, ++ MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE = 0xC0E70013, ++ MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED = 0xC0E70014, ++ MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION = 0xC0E70015, ++ MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA = 0xC0E70016, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL = 0xC0E70017, ++ MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY = 0xC0E70018, ++ MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY = 0xC0E70019, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY = 0xC0E7001A, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY = 0xC0E7001B, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT = 0xC0E7001C, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA = 0xC0E7001D, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE = 0xC0E7001E, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID = 0xC0E7001F, ++ MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY = 0xC0E70020, ++ MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND = 0xC0E80000, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED = 0xC0E90001, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION = 0xC0E90002, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY = 0xC0E90003, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED = 0xC0E90004, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES = 0xC0E90005, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED = 0xC0E90006, ++ MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND = 0xC0EA0001, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND = 0xC0EA0002, ++ MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING = 0xC0EA0003, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE = 0xC0EA0004, ++ MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID = 0xC0EA0005, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED = 0xC0EA0006, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE = 0xC0EA0007, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED = 0xC0EA0008, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE = 0xC0EA0009, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH = 0xC0EA000A, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED = 0xC0EB0001, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID = 0xC0EB0002, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED = 0xC0EB0003, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED = 0xC0EB0004, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND = 0xC0EB0005, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE = 0xC0EB0006, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED = 0xC0EB0007, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED = 0xC0EC0000, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED = 0xC0EC0001, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION = 0xC0EC0002, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION = 0xC0EC0003, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE = 0xC0EC0004, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR = 0xC0EC0005, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH = 0xC0EC0006, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER = 0xC0EC0007, + } MDNTStatusCodeWin; + + // These constants are defined in the MSDN documentation of + // the EXCEPTION_RECORD structure. + typedef enum { + MD_ACCESS_VIOLATION_WIN_READ = 0, + MD_ACCESS_VIOLATION_WIN_WRITE = 1, + MD_ACCESS_VIOLATION_WIN_EXEC = 8 +diff --git a/src/processor/exploitability_win.cc b/src/processor/exploitability_win.cc +--- a/src/processor/exploitability_win.cc ++++ b/src/processor/exploitability_win.cc +@@ -147,18 +147,18 @@ ExploitabilityRating ExploitabilityWin:: + break; + + // These represent bugs in exception handlers. + case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: + case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: + exploitability_weight += kSmallBump; + break; + +- case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: +- case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: ++ case MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION: ++ case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: + exploitability_weight += kHugeBump; + break; + + case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: + exploitability_weight += kLargeBump; + break; + + case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1138,19 +1138,16 @@ string MinidumpProcessor::GetCrashReason + break; + } + break; + } + + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: { + switch (exception_code) { +- case MD_EXCEPTION_CODE_WIN_CONTROL_C: +- reason = "DBG_CONTROL_C"; +- break; + case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: + reason = "EXCEPTION_GUARD_PAGE"; + break; + case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT: + reason = "EXCEPTION_DATATYPE_MISALIGNMENT"; + break; + case MD_EXCEPTION_CODE_WIN_BREAKPOINT: + reason = "EXCEPTION_BREAKPOINT"; +@@ -1245,17 +1242,17 @@ string MinidumpProcessor::GetCrashReason + break; + case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: + reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + break; + case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: + reason = "EXCEPTION_INVALID_DISPOSITION"; + break; + case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED: +- reason = "EXCEPTION_BOUNDS_EXCEEDED"; ++ reason = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND: + reason = "EXCEPTION_FLT_DENORMAL_OPERAND"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: + reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: +@@ -1286,41 +1283,41 @@ string MinidumpProcessor::GetCrashReason + reason = "EXCEPTION_STACK_OVERFLOW"; + break; + case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE: + reason = "EXCEPTION_BAD_FUNCTION_TABLE"; + break; + case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: + reason = "EXCEPTION_POSSIBLE_DEADLOCK"; + break; +- case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: +- reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; ++ case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: ++ reason = "STATUS_STACK_BUFFER_OVERRUN"; + if (raw_exception->exception_record.number_parameters > 0) { + uint32_t fast_fail_code = + static_cast + (raw_exception->exception_record.exception_information[0]); + reason.append(" / "); + reason.append(FastFailToString(fast_fail_code)); + } + + break; +- case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: +- reason = "EXCEPTION_HEAP_CORRUPTION"; +- break; + case MD_EXCEPTION_OUT_OF_MEMORY: + reason = "Out of Memory"; + break; + case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: + reason = "Unhandled C++ Exception"; + break; + case MD_EXCEPTION_CODE_WIN_SIMULATED: + reason = "Simulated Exception"; + break; + default: +- BPLOG(INFO) << "Unknown exception reason " << reason; ++ reason = NTStatusToString(exception_code); ++ if (reason.substr(0, 2) == "0x") { ++ BPLOG(INFO) << "Unknown exception reason " << reason; ++ } + break; + } + break; + } + + case MD_OS_ANDROID: + case MD_OS_LINUX: { + switch (exception_code) { +diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc +--- a/src/processor/symbolic_constants_win.cc ++++ b/src/processor/symbolic_constants_win.cc +@@ -39,31 +39,761 @@ + #include "google_breakpad/common/breakpad_types.h" + #include "google_breakpad/common/minidump_exception_win32.h" + #include "processor/symbolic_constants_win.h" + + namespace google_breakpad { + + string NTStatusToString(uint32_t ntstatus) { + string reason; +- // The content of this switch was created from ntstatus.h in the 8.1 SDK with ++ // The content of this switch was created from ntstatus.h in the 10 SDK ++ // (version 10.0.19041.0) with + // +- // egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0xC[0-9A-F]+L\)' ntstatus.h ++ // egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h + // | tr -d '\r' +- // | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0xC[0-9A-F]+)L\).*@\2 \1@' ++ // | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' + // | sort +- // | sed -r 's@(0xC[0-9A-F]+) ([A-Z_0-9]+)@ case MD_NTSTATUS_WIN_\2:\n reason = "\2";\n break;@' ++ // | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ case MD_NTSTATUS_WIN_\2:\n reason = "\2";\n break;@' + // + // With easy copy to clipboard with + // | xclip -selection c # on linux + // | clip # on windows + // | pbcopy # on mac + // + // and then the default case added. + switch (ntstatus) { ++ case MD_NTSTATUS_WIN_STATUS_SUCCESS: ++ reason = "STATUS_SUCCESS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAIT_1: ++ reason = "STATUS_WAIT_1"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAIT_2: ++ reason = "STATUS_WAIT_2"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAIT_3: ++ reason = "STATUS_WAIT_3"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAIT_63: ++ reason = "STATUS_WAIT_63"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ABANDONED: ++ reason = "STATUS_ABANDONED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63: ++ reason = "STATUS_ABANDONED_WAIT_63"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_USER_APC: ++ reason = "STATUS_USER_APC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE: ++ reason = "STATUS_ALREADY_COMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_KERNEL_APC: ++ reason = "STATUS_KERNEL_APC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALERTED: ++ reason = "STATUS_ALERTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TIMEOUT: ++ reason = "STATUS_TIMEOUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PENDING: ++ reason = "STATUS_PENDING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REPARSE: ++ reason = "STATUS_REPARSE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES: ++ reason = "STATUS_MORE_ENTRIES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED: ++ reason = "STATUS_NOT_ALL_ASSIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED: ++ reason = "STATUS_SOME_NOT_MAPPED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS: ++ reason = "STATUS_OPLOCK_BREAK_IN_PROGRESS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED: ++ reason = "STATUS_VOLUME_MOUNTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED: ++ reason = "STATUS_RXACT_COMMITTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP: ++ reason = "STATUS_NOTIFY_CLEANUP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR: ++ reason = "STATUS_NOTIFY_ENUM_DIR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT: ++ reason = "STATUS_NO_QUOTAS_FOR_ACCOUNT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED: ++ reason = "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION: ++ reason = "STATUS_PAGE_FAULT_TRANSITION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO: ++ reason = "STATUS_PAGE_FAULT_DEMAND_ZERO"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE: ++ reason = "STATUS_PAGE_FAULT_COPY_ON_WRITE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE: ++ reason = "STATUS_PAGE_FAULT_GUARD_PAGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE: ++ reason = "STATUS_PAGE_FAULT_PAGING_FILE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED: ++ reason = "STATUS_CACHE_PAGE_LOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CRASH_DUMP: ++ reason = "STATUS_CRASH_DUMP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS: ++ reason = "STATUS_BUFFER_ALL_ZEROS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT: ++ reason = "STATUS_REPARSE_OBJECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED: ++ reason = "STATUS_RESOURCE_REQUIREMENTS_CHANGED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE: ++ reason = "STATUS_TRANSLATION_COMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY: ++ reason = "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE: ++ reason = "STATUS_NOTHING_TO_TERMINATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB: ++ reason = "STATUS_PROCESS_NOT_IN_JOB"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB: ++ reason = "STATUS_PROCESS_IN_JOB"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY: ++ reason = "STATUS_VOLSNAP_HIBERNATE_READY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY: ++ reason = "STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: ++ reason = "STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED: ++ reason = "STATUS_INTERRUPT_STILL_CONNECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED: ++ reason = "STATUS_PROCESS_CLONED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS: ++ reason = "STATUS_FILE_LOCKED_WITH_ONLY_READERS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS: ++ reason = "STATUS_FILE_LOCKED_WITH_WRITERS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH: ++ reason = "STATUS_VALID_IMAGE_HASH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH: ++ reason = "STATUS_VALID_CATALOG_HASH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH: ++ reason = "STATUS_VALID_STRONG_CODE_HASH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GHOSTED: ++ reason = "STATUS_GHOSTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN: ++ reason = "STATUS_DATA_OVERWRITTEN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY: ++ reason = "STATUS_RESOURCEMANAGER_READ_ONLY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY: ++ reason = "STATUS_RING_PREVIOUSLY_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL: ++ reason = "STATUS_RING_PREVIOUSLY_FULL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA: ++ reason = "STATUS_RING_PREVIOUSLY_ABOVE_QUOTA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY: ++ reason = "STATUS_RING_NEWLY_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT: ++ reason = "STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE: ++ reason = "STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED: ++ reason = "STATUS_OPLOCK_HANDLE_CLOSED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK: ++ reason = "STATUS_WAIT_FOR_OPLOCK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL: ++ reason = "STATUS_REPARSE_GLOBAL"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED: ++ reason = "DBG_EXCEPTION_HANDLED"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_CONTINUE: ++ reason = "DBG_CONTINUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE: ++ reason = "STATUS_FLT_IO_COMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE: ++ reason = "STATUS_RTPM_CONTEXT_CONTINUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE: ++ reason = "STATUS_RTPM_CONTEXT_COMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS: ++ reason = "STATUS_HV_PENDING_PAGE_REQUESTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED: ++ reason = "STATUS_SPACES_REPAIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE: ++ reason = "STATUS_SPACES_PAUSE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE: ++ reason = "STATUS_SPACES_COMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT: ++ reason = "STATUS_SPACES_REDIRECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS: ++ reason = "STATUS_OBJECT_NAME_EXISTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED: ++ reason = "STATUS_THREAD_WAS_SUSPENDED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE: ++ reason = "STATUS_WORKING_SET_LIMIT_RANGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE: ++ reason = "STATUS_IMAGE_NOT_AT_BASE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED: ++ reason = "STATUS_RXACT_STATE_CREATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION: ++ reason = "STATUS_SEGMENT_NOTIFICATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY: ++ reason = "STATUS_LOCAL_USER_SESSION_KEY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY: ++ reason = "STATUS_BAD_CURRENT_DIRECTORY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES: ++ reason = "STATUS_SERIAL_MORE_WRITES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED: ++ reason = "STATUS_REGISTRY_RECOVERED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP: ++ reason = "STATUS_FT_READ_RECOVERY_FROM_BACKUP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY: ++ reason = "STATUS_FT_WRITE_RECOVERY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT: ++ reason = "STATUS_SERIAL_COUNTER_TIMEOUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD: ++ reason = "STATUS_NULL_LM_PASSWORD"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH: ++ reason = "STATUS_IMAGE_MACHINE_TYPE_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL: ++ reason = "STATUS_RECEIVE_PARTIAL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED: ++ reason = "STATUS_RECEIVE_EXPEDITED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED: ++ reason = "STATUS_RECEIVE_PARTIAL_EXPEDITED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EVENT_DONE: ++ reason = "STATUS_EVENT_DONE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EVENT_PENDING: ++ reason = "STATUS_EVENT_PENDING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM: ++ reason = "STATUS_CHECKING_FILE_SYSTEM"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT: ++ reason = "STATUS_FATAL_APP_EXIT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE: ++ reason = "STATUS_PREDEFINED_HANDLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED: ++ reason = "STATUS_WAS_UNLOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION: ++ reason = "STATUS_SERVICE_NOTIFICATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAS_LOCKED: ++ reason = "STATUS_WAS_LOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR: ++ reason = "STATUS_LOG_HARD_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32: ++ reason = "STATUS_ALREADY_WIN32"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE: ++ reason = "STATUS_WX86_UNSIMULATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE: ++ reason = "STATUS_WX86_CONTINUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP: ++ reason = "STATUS_WX86_SINGLE_STEP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT: ++ reason = "STATUS_WX86_BREAKPOINT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE: ++ reason = "STATUS_WX86_EXCEPTION_CONTINUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE: ++ reason = "STATUS_WX86_EXCEPTION_LASTCHANCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN: ++ reason = "STATUS_WX86_EXCEPTION_CHAIN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: ++ reason = "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED: ++ reason = "STATUS_NO_YIELD_PERFORMED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED: ++ reason = "STATUS_TIMER_RESUME_IGNORED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED: ++ reason = "STATUS_ARBITRATION_UNHANDLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED: ++ reason = "STATUS_CARDBUS_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB: ++ reason = "STATUS_WX86_CREATEWX86TIB"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH: ++ reason = "STATUS_MP_PROCESSOR_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HIBERNATED: ++ reason = "STATUS_HIBERNATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION: ++ reason = "STATUS_RESUME_HIBERNATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED: ++ reason = "STATUS_FIRMWARE_UPDATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES: ++ reason = "STATUS_DRIVERS_LEAKING_LOCKED_PAGES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED: ++ reason = "STATUS_MESSAGE_RETRIEVED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION: ++ reason = "STATUS_SYSTEM_POWERSTATE_TRANSITION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST: ++ reason = "STATUS_ALPC_CHECK_COMPLETION_LIST"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: ++ reason = "STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY: ++ reason = "STATUS_ACCESS_AUDIT_BY_POLICY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE: ++ reason = "STATUS_ABANDON_HIBERFILE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED: ++ reason = "STATUS_BIZRULES_NOT_ENABLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY: ++ reason = "STATUS_FT_READ_FROM_COPY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE: ++ reason = "STATUS_IMAGE_AT_DIFFERENT_BASE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED: ++ reason = "STATUS_PATCH_DEFERRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM: ++ reason = "STATUS_WAKE_SYSTEM"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN: ++ reason = "STATUS_DS_SHUTTING_DOWN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED: ++ reason = "STATUS_DISK_REPAIR_REDIRECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART: ++ reason = "STATUS_SERVICES_FAILED_AUTOSTART"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_REPLY_LATER: ++ reason = "DBG_REPLY_LATER"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE: ++ reason = "DBG_UNABLE_TO_PROVIDE_HANDLE"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD: ++ reason = "DBG_TERMINATE_THREAD"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS: ++ reason = "DBG_TERMINATE_PROCESS"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_CONTROL_C: ++ reason = "DBG_CONTROL_C"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C: ++ reason = "DBG_PRINTEXCEPTION_C"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_RIPEXCEPTION: ++ reason = "DBG_RIPEXCEPTION"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_CONTROL_BREAK: ++ reason = "DBG_CONTROL_BREAK"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION: ++ reason = "DBG_COMMAND_EXCEPTION"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C: ++ reason = "DBG_PRINTEXCEPTION_WIDE_C"; ++ break; ++ case MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY: ++ reason = "RPC_NT_UUID_LOCAL_ONLY"; ++ break; ++ case MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE: ++ reason = "RPC_NT_SEND_INCOMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT: ++ reason = "STATUS_CTX_CDM_CONNECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT: ++ reason = "STATUS_CTX_CDM_DISCONNECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT: ++ reason = "STATUS_SXS_RELEASE_ACTIVATION_CONTEXT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE: ++ reason = "STATUS_HEURISTIC_DAMAGE_POSSIBLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED: ++ reason = "STATUS_RECOVERY_NOT_NEEDED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED: ++ reason = "STATUS_RM_ALREADY_STARTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART: ++ reason = "STATUS_LOG_NO_RESTART"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST: ++ reason = "STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED: ++ reason = "STATUS_GRAPHICS_PARTIAL_DATA_POPULATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION: ++ reason = "STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED: ++ reason = "STATUS_GRAPHICS_MODE_NOT_PINNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE: ++ reason = "STATUS_GRAPHICS_NO_PREFERRED_MODE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY: ++ reason = "STATUS_GRAPHICS_DATASET_IS_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: ++ reason = "STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: ++ reason = "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS: ++ reason = "STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED: ++ reason = "STATUS_GRAPHICS_LEADLINK_START_DEFERRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY: ++ reason = "STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED: ++ reason = "STATUS_GRAPHICS_START_DEFERRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS: ++ reason = "STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED: ++ reason = "STATUS_NDIS_INDICATION_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT: ++ reason = "STATUS_PCP_UNSUPPORTED_PSS_SALT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION: ++ reason = "STATUS_GUARD_PAGE_VIOLATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT: ++ reason = "STATUS_DATATYPE_MISALIGNMENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BREAKPOINT: ++ reason = "STATUS_BREAKPOINT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SINGLE_STEP: ++ reason = "STATUS_SINGLE_STEP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW: ++ reason = "STATUS_BUFFER_OVERFLOW"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES: ++ reason = "STATUS_NO_MORE_FILES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER: ++ reason = "STATUS_WAKE_SYSTEM_DEBUGGER"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED: ++ reason = "STATUS_HANDLES_CLOSED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE: ++ reason = "STATUS_NO_INHERITANCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE: ++ reason = "STATUS_GUID_SUBSTITUTION_MADE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY: ++ reason = "STATUS_PARTIAL_COPY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY: ++ reason = "STATUS_DEVICE_PAPER_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF: ++ reason = "STATUS_DEVICE_POWERED_OFF"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE: ++ reason = "STATUS_DEVICE_OFF_LINE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY: ++ reason = "STATUS_DEVICE_BUSY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS: ++ reason = "STATUS_NO_MORE_EAS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME: ++ reason = "STATUS_INVALID_EA_NAME"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT: ++ reason = "STATUS_EA_LIST_INCONSISTENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG: ++ reason = "STATUS_INVALID_EA_FLAG"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED: ++ reason = "STATUS_VERIFY_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION: ++ reason = "STATUS_EXTRANEOUS_INFORMATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY: ++ reason = "STATUS_RXACT_COMMIT_NECESSARY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES: ++ reason = "STATUS_NO_MORE_ENTRIES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED: ++ reason = "STATUS_FILEMARK_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED: ++ reason = "STATUS_MEDIA_CHANGED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BUS_RESET: ++ reason = "STATUS_BUS_RESET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA: ++ reason = "STATUS_END_OF_MEDIA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA: ++ reason = "STATUS_BEGINNING_OF_MEDIA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK: ++ reason = "STATUS_MEDIA_CHECK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED: ++ reason = "STATUS_SETMARK_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED: ++ reason = "STATUS_NO_DATA_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES: ++ reason = "STATUS_REDIRECTOR_HAS_OPEN_HANDLES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES: ++ reason = "STATUS_SERVER_HAS_OPEN_HANDLES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED: ++ reason = "STATUS_ALREADY_DISCONNECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_LONGJUMP: ++ reason = "STATUS_LONGJUMP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED: ++ reason = "STATUS_CLEANER_CARTRIDGE_INSTALLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED: ++ reason = "STATUS_PLUGPLAY_QUERY_VETOED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE: ++ reason = "STATUS_UNWIND_CONSOLIDATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED: ++ reason = "STATUS_REGISTRY_HIVE_RECOVERED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE: ++ reason = "STATUS_DLL_MIGHT_BE_INSECURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE: ++ reason = "STATUS_DLL_MIGHT_BE_INCOMPATIBLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK: ++ reason = "STATUS_STOPPED_ON_SYMLINK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK: ++ reason = "STATUS_CANNOT_GRANT_REQUESTED_OPLOCK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION: ++ reason = "STATUS_NO_ACE_CONDITION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS: ++ reason = "STATUS_DEVICE_SUPPORT_IN_PROGRESS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED: ++ reason = "STATUS_DEVICE_POWER_CYCLE_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE: ++ reason = "STATUS_NO_WORK_DONE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT: ++ reason = "STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING: ++ reason = "STATUS_DEVICE_REQUIRES_CLEANING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN: ++ reason = "STATUS_DEVICE_DOOR_OPEN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR: ++ reason = "STATUS_DATA_LOST_REPAIR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED: ++ reason = "STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH: ++ reason = "STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE: ++ reason = "STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS: ++ reason = "STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS"; ++ break; ++ case MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED: ++ reason = "DBG_EXCEPTION_NOT_HANDLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP: ++ reason = "STATUS_CLUSTER_NODE_ALREADY_UP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN: ++ reason = "STATUS_CLUSTER_NODE_ALREADY_DOWN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE: ++ reason = "STATUS_CLUSTER_NETWORK_ALREADY_ONLINE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE: ++ reason = "STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER: ++ reason = "STATUS_CLUSTER_NODE_ALREADY_MEMBER"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG: ++ reason = "STATUS_COULD_NOT_RESIZE_LOG"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA: ++ reason = "STATUS_NO_TXF_METADATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN: ++ reason = "STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT: ++ reason = "STATUS_TXF_METADATA_ALREADY_PRESENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: ++ reason = "STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED: ++ reason = "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL: ++ reason = "STATUS_FLT_BUFFER_TOO_SMALL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA: ++ reason = "STATUS_FVE_PARTIAL_METADATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE: ++ reason = "STATUS_FVE_TRANSIENT_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED: ++ reason = "STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION: ++ reason = "STATUS_VOLMGR_INCOMPLETE_REGENERATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION: ++ reason = "STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED: ++ reason = "STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED: ++ reason = "STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR: ++ reason = "STATUS_QUERY_STORAGE_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK: ++ reason = "STATUS_GDI_HANDLE_LEAK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED: ++ reason = "STATUS_SECUREBOOT_NOT_ENABLED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL: + reason = "STATUS_UNSUCCESSFUL"; + break; + case MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED: + reason = "STATUS_NOT_IMPLEMENTED"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS: + reason = "STATUS_INVALID_INFO_CLASS"; +@@ -213,16 +943,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_OBJECT_NAME_INVALID"; + break; + case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND: + reason = "STATUS_OBJECT_NAME_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION: + reason = "STATUS_OBJECT_NAME_COLLISION"; + break; ++ case MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB: ++ reason = "STATUS_PORT_DO_NOT_DISTURB"; ++ break; + case MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED: + reason = "STATUS_PORT_DISCONNECTED"; + break; + case MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED: + reason = "STATUS_DEVICE_ALREADY_ATTACHED"; + break; + case MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID: + reason = "STATUS_OBJECT_PATH_INVALID"; +@@ -1317,16 +2050,40 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_REPAIR_NEEDED"; + break; + case MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED: + reason = "STATUS_QUOTA_NOT_ENABLED"; + break; + case MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE: + reason = "STATUS_NO_APPLICATION_PACKAGE"; + break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS: ++ reason = "STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT: ++ reason = "STATUS_NOT_SAME_OBJECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION: ++ reason = "STATUS_FATAL_MEMORY_EXHAUSTION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB: ++ reason = "STATUS_ERROR_PROCESS_NOT_IN_JOB"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID: ++ reason = "STATUS_CPU_SET_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA: ++ reason = "STATUS_IO_DEVICE_INVALID_DATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE: ++ reason = "STATUS_IO_UNALIGNED_WRITE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION: ++ reason = "STATUS_CONTROL_STACK_VIOLATION"; ++ break; + case MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION: + reason = "STATUS_NETWORK_OPEN_RESTRICTION"; + break; + case MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY: + reason = "STATUS_NO_USER_SESSION_KEY"; + break; + case MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED: + reason = "STATUS_USER_SESSION_DELETED"; +@@ -1662,16 +2419,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_IO_REPARSE_TAG_NOT_HANDLED"; + break; + case MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG: + reason = "STATUS_PWD_TOO_LONG"; + break; + case MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION: + reason = "STATUS_STOWED_EXCEPTION"; + break; ++ case MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION: ++ reason = "STATUS_CONTEXT_STOWED_EXCEPTION"; ++ break; + case MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED: + reason = "STATUS_REPARSE_POINT_NOT_RESOLVED"; + break; + case MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT: + reason = "STATUS_DIRECTORY_IS_A_REPARSE_POINT"; + break; + case MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT: + reason = "STATUS_RANGE_LIST_CONFLICT"; +@@ -2058,16 +2818,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_CSS_REGION_MISMATCH"; + break; + case MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED: + reason = "STATUS_CSS_RESETS_EXHAUSTED"; + break; + case MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED: + reason = "STATUS_PASSWORD_CHANGE_REQUIRED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION: ++ reason = "STATUS_LOST_MODE_LOGON_RESTRICTION"; ++ break; + case MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE: + reason = "STATUS_PKINIT_FAILURE"; + break; + case MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE: + reason = "STATUS_SMARTCARD_SUBSYSTEM_FAILURE"; + break; + case MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY: + reason = "STATUS_NO_KERB_KEY"; +@@ -2454,16 +3217,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_FT_DI_SCAN_REQUIRED"; + break; + case MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED: + reason = "STATUS_OBJECT_NOT_EXTERNALLY_BACKED"; + break; + case MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN: + reason = "STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN"; + break; ++ case MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL: ++ reason = "STATUS_COMPRESSION_NOT_BENEFICIAL"; ++ break; + case MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR: + reason = "STATUS_DATA_CHECKSUM_ERROR"; + break; + case MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION: + reason = "STATUS_INTERMIXED_KERNEL_EA_OPERATION"; + break; + case MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED: + reason = "STATUS_TRIM_READ_ZERO_NOT_SUPPORTED"; +@@ -2514,16 +3280,181 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_APISET_NOT_HOSTED"; + break; + case MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT: + reason = "STATUS_APISET_NOT_PRESENT"; + break; + case MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR: + reason = "STATUS_DEVICE_HARDWARE_ERROR"; + break; ++ case MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID: ++ reason = "STATUS_FIRMWARE_SLOT_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID: ++ reason = "STATUS_FIRMWARE_IMAGE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH: ++ reason = "STATUS_STORAGE_TOPOLOGY_ID_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE: ++ reason = "STATUS_WIM_NOT_BOOTABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS: ++ reason = "STATUS_BLOCKED_BY_PARENTAL_CONTROLS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION: ++ reason = "STATUS_NEEDS_REGISTRATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY: ++ reason = "STATUS_QUOTA_ACTIVITY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE: ++ reason = "STATUS_CALLBACK_INVOKE_INLINE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES: ++ reason = "STATUS_BLOCK_TOO_MANY_REFERENCES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES: ++ reason = "STATUS_MARKED_TO_DISALLOW_WRITES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP: ++ reason = "STATUS_NETWORK_ACCESS_DENIED_EDP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE: ++ reason = "STATUS_ENCLAVE_FAILURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS: ++ reason = "STATUS_PNP_NO_COMPAT_DRIVERS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND: ++ reason = "STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND: ++ reason = "STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE: ++ reason = "STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED: ++ reason = "STATUS_PNP_FUNCTION_DRIVER_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING: ++ reason = "STATUS_PNP_DEVICE_CONFIGURATION_PENDING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL: ++ reason = "STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE: ++ reason = "STATUS_PACKAGE_NOT_AVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE: ++ reason = "STATUS_DEVICE_IN_MAINTENANCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX: ++ reason = "STATUS_NOT_SUPPORTED_ON_DAX"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED: ++ reason = "STATUS_FREE_SPACE_TOO_FRAGMENTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS: ++ reason = "STATUS_DAX_MAPPING_EXISTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED: ++ reason = "STATUS_CHILD_PROCESS_BLOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE: ++ reason = "STATUS_STORAGE_LOST_DATA_PERSISTENCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED: ++ reason = "STATUS_VRF_CFG_AND_IO_ENABLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING: ++ reason = "STATUS_PARTITION_TERMINATING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED: ++ reason = "STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION: ++ reason = "STATUS_ENCLAVE_VIOLATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL: ++ reason = "STATUS_FILE_PROTECTED_UNDER_DPL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED: ++ reason = "STATUS_VOLUME_NOT_CLUSTER_ALIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND: ++ reason = "STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED: ++ reason = "STATUS_APPX_FILE_NOT_ENCRYPTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED: ++ reason = "STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET: ++ reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE: ++ reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER: ++ reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE: ++ reason = "STATUS_FT_READ_FAILURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT: ++ reason = "STATUS_PATCH_CONFLICT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID: ++ reason = "STATUS_STORAGE_RESERVE_ID_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST: ++ reason = "STATUS_STORAGE_RESERVE_DOES_NOT_EXIST"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS: ++ reason = "STATUS_STORAGE_RESERVE_ALREADY_EXISTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY: ++ reason = "STATUS_STORAGE_RESERVE_NOT_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME: ++ reason = "STATUS_NOT_A_DAX_VOLUME"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE: ++ reason = "STATUS_NOT_DAX_MAPPABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR: ++ reason = "STATUS_CASE_DIFFERING_NAMES_IN_DIR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED: ++ reason = "STATUS_FILE_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT: ++ reason = "STATUS_NOT_SUPPORTED_WITH_BTT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED: ++ reason = "STATUS_ENCRYPTION_DISABLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED: ++ reason = "STATUS_ENCRYPTING_METADATA_DISALLOWED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG: ++ reason = "STATUS_CANT_CLEAR_ENCRYPTION_FLAG"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES: ++ reason = "STATUS_UNSATISFIED_DEPENDENCIES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH: ++ reason = "STATUS_CASE_SENSITIVE_PATH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES: ++ reason = "STATUS_HAS_SYSTEM_CRITICAL_FILES"; ++ break; + case MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME: + reason = "STATUS_INVALID_TASK_NAME"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX: + reason = "STATUS_INVALID_TASK_INDEX"; + break; + case MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK: + reason = "STATUS_THREAD_ALREADY_IN_TASK"; +@@ -2535,25 +3466,85 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_UNDEFINED_SCOPE"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_CAP: + reason = "STATUS_INVALID_CAP"; + break; + case MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS: + reason = "STATUS_NOT_GUI_PROCESS"; + break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG: ++ reason = "STATUS_DEVICE_HUNG"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED: ++ reason = "STATUS_CONTAINER_ASSIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER: ++ reason = "STATUS_JOB_NO_CONTAINER"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE: ++ reason = "STATUS_DEVICE_UNRESPONSIVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED: ++ reason = "STATUS_REPARSE_POINT_ENCOUNTERED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT: ++ reason = "STATUS_ATTRIBUTE_NOT_PRESENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME: ++ reason = "STATUS_NOT_A_TIERED_VOLUME"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID: ++ reason = "STATUS_ALREADY_HAS_STREAM_ID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY: ++ reason = "STATUS_JOB_NOT_EMPTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED: ++ reason = "STATUS_ALREADY_INITIALIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED: ++ reason = "STATUS_ENCLAVE_NOT_TERMINATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING: ++ reason = "STATUS_ENCLAVE_IS_TERMINATING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE: ++ reason = "STATUS_SMB1_NOT_AVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED: ++ reason = "STATUS_SMR_GARBAGE_COLLECTION_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_INTERRUPTED: ++ reason = "STATUS_INTERRUPTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING: ++ reason = "STATUS_THREAD_NOT_RUNNING"; ++ break; + case MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION: + reason = "STATUS_FAIL_FAST_EXCEPTION"; + break; + case MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED: + reason = "STATUS_IMAGE_CERT_REVOKED"; + break; + case MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED: + reason = "STATUS_DYNAMIC_CODE_BLOCKED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED: ++ reason = "STATUS_IMAGE_CERT_EXPIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION: ++ reason = "STATUS_STRICT_CFG_VIOLATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED: ++ reason = "STATUS_SET_CONTEXT_DENIED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION: ++ reason = "STATUS_CROSS_PARTITION_VIOLATION"; ++ break; + case MD_NTSTATUS_WIN_STATUS_PORT_CLOSED: + reason = "STATUS_PORT_CLOSED"; + break; + case MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST: + reason = "STATUS_MESSAGE_LOST"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE: + reason = "STATUS_INVALID_MESSAGE"; +@@ -2646,16 +3637,31 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_CALLBACK_RETURNED_LANG"; + break; + case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK: + reason = "STATUS_CALLBACK_RETURNED_PRI_BACK"; + break; + case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY: + reason = "STATUS_CALLBACK_RETURNED_THREAD_AFFINITY"; + break; ++ case MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED: ++ reason = "STATUS_LPC_HANDLE_COUNT_EXCEEDED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE: ++ reason = "STATUS_EXECUTABLE_MEMORY_WRITE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE: ++ reason = "STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE: ++ reason = "STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE: ++ reason = "STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED: + reason = "STATUS_DISK_REPAIR_DISABLED"; + break; + case MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS: + reason = "STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"; + break; + case MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED: + reason = "STATUS_DISK_QUOTA_EXCEEDED"; +@@ -2754,16 +3760,25 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_INVALID_STATE_TRANSITION"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION: + reason = "STATUS_INVALID_KERNEL_INFO_VERSION"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION: + reason = "STATUS_INVALID_PEP_INFO_VERSION"; + break; ++ case MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED: ++ reason = "STATUS_HANDLE_REVOKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE: ++ reason = "STATUS_EOF_ON_GHOSTED_RANGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN: ++ reason = "STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN"; ++ break; + case MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW: + reason = "STATUS_IPSEC_QUEUE_OVERFLOW"; + break; + case MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW: + reason = "STATUS_ND_QUEUE_OVERFLOW"; + break; + case MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED: + reason = "STATUS_HOPLIMIT_EXCEEDED"; +@@ -2847,16 +3862,22 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_NOT_APPCONTAINER"; + break; + case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER: + reason = "STATUS_NOT_SUPPORTED_IN_APPCONTAINER"; + break; + case MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH: + reason = "STATUS_INVALID_PACKAGE_SID_LENGTH"; + break; ++ case MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED: ++ reason = "STATUS_LPAC_ACCESS_DENIED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED: ++ reason = "STATUS_ADMINLESS_ACCESS_DENIED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND: + reason = "STATUS_APP_DATA_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED: + reason = "STATUS_APP_DATA_EXPIRED"; + break; + case MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT: + reason = "STATUS_APP_DATA_CORRUPT"; +@@ -2874,16 +3895,151 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED"; + break; + case MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED: + reason = "STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED"; + break; + case MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: + reason = "STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT: ++ reason = "STATUS_WOF_WIM_HEADER_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT: ++ reason = "STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT: ++ reason = "STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT: ++ reason = "STATUS_CIMFS_IMAGE_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE: ++ reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT: ++ reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY: ++ reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN: ++ reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION: ++ reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT: ++ reason = "STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING: ++ reason = "STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT: ++ reason = "STATUS_CLOUD_FILE_METADATA_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE: ++ reason = "STATUS_CLOUD_FILE_METADATA_TOO_LARGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED: ++ reason = "STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE: ++ reason = "STATUS_NOT_A_CLOUD_FILE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC: ++ reason = "STATUS_CLOUD_FILE_NOT_IN_SYNC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED: ++ reason = "STATUS_CLOUD_FILE_ALREADY_CONNECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED: ++ reason = "STATUS_CLOUD_FILE_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST: ++ reason = "STATUS_CLOUD_FILE_INVALID_REQUEST"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME: ++ reason = "STATUS_CLOUD_FILE_READ_ONLY_VOLUME"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY: ++ reason = "STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED: ++ reason = "STATUS_CLOUD_FILE_VALIDATION_FAILED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED: ++ reason = "STATUS_CLOUD_FILE_AUTHENTICATION_FAILED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES: ++ reason = "STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE: ++ reason = "STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL: ++ reason = "STATUS_CLOUD_FILE_UNSUCCESSFUL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT: ++ reason = "STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE: ++ reason = "STATUS_CLOUD_FILE_IN_USE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED: ++ reason = "STATUS_CLOUD_FILE_PINNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED: ++ reason = "STATUS_CLOUD_FILE_REQUEST_ABORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT: ++ reason = "STATUS_CLOUD_FILE_PROPERTY_CORRUPT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED: ++ reason = "STATUS_CLOUD_FILE_ACCESS_DENIED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS: ++ reason = "STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT: ++ reason = "STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED: ++ reason = "STATUS_CLOUD_FILE_REQUEST_CANCELED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED: ++ reason = "STATUS_CLOUD_FILE_PROVIDER_TERMINATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT: ++ reason = "STATUS_NOT_A_CLOUD_SYNC_ROOT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT: ++ reason = "STATUS_CLOUD_FILE_REQUEST_TIMEOUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED: ++ reason = "STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS: ++ reason = "STATUS_FILE_SNAP_IN_PROGRESS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED: ++ reason = "STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED: ++ reason = "STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED: ++ reason = "STATUS_FILE_SNAP_IO_NOT_COORDINATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR: ++ reason = "STATUS_FILE_SNAP_UNEXPECTED_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER: ++ reason = "STATUS_FILE_SNAP_INVALID_PARAMETER"; ++ break; + case MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE: + reason = "DBG_NO_STATE_CHANGE"; + break; + case MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE: + reason = "DBG_APP_NOT_IDLE"; + break; + case MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING: + reason = "RPC_NT_INVALID_STRING_BINDING"; +@@ -3459,16 +4615,31 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_CLUSTER_CSV_VOLUME_DRAINING"; + break; + case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS: + reason = "STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS"; + break; + case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL: + reason = "STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL"; + break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS: ++ reason = "STATUS_CLUSTER_CSV_NO_SNAPSHOTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT: ++ reason = "STATUS_CSV_IO_PAUSE_TIMEOUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE: ++ reason = "STATUS_CLUSTER_CSV_INVALID_HANDLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR: ++ reason = "STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED: ++ reason = "STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE: + reason = "STATUS_ACPI_INVALID_OPCODE"; + break; + case MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW: + reason = "STATUS_ACPI_STACK_OVERFLOW"; + break; + case MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED: + reason = "STATUS_ACPI_ASSERT_FAILED"; +@@ -4182,16 +5353,31 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_GRAPHICS_PRESENT_UNOCCLUDED"; + break; + case MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE: + reason = "STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE"; + break; + case MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED: + reason = "STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW: ++ reason = "STATUS_GRAPHICS_PRESENT_INVALID_WINDOW"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND: ++ reason = "STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED: ++ reason = "STATUS_GRAPHICS_VAIL_STATE_CHANGED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN: ++ reason = "STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED: ++ reason = "STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY: + reason = "STATUS_GRAPHICS_NO_VIDEO_MEMORY"; + break; + case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY: + reason = "STATUS_GRAPHICS_CANT_LOCK_MEMORY"; + break; + case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY: + reason = "STATUS_GRAPHICS_ALLOCATION_BUSY"; +@@ -4845,16 +6031,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_FVE_NOT_DE_VOLUME"; + break; + case MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED: + reason = "STATUS_FVE_PROTECTION_DISABLED"; + break; + case MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED: + reason = "STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED: ++ reason = "STATUS_FVE_OSV_KSR_NOT_ALLOWED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND: + reason = "STATUS_FWP_CALLOUT_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND: + reason = "STATUS_FWP_CONDITION_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND: + reason = "STATUS_FWP_FILTER_NOT_FOUND"; +@@ -5166,16 +6355,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_NDIS_INVALID_PORT_STATE"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE: + reason = "STATUS_NDIS_LOW_POWER_STATE"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED: + reason = "STATUS_NDIS_REINIT_REQUIRED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES: ++ reason = "STATUS_NDIS_NO_QUEUES"; ++ break; + case MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED: + reason = "STATUS_NDIS_NOT_SUPPORTED"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY: + reason = "STATUS_NDIS_OFFLOAD_POLICY"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED: + reason = "STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED"; +@@ -5193,16 +6385,34 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_NDIS_DOT11_POWER_STATE_INVALID"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL: + reason = "STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL"; + break; + case MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: + reason = "STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL"; + break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE: ++ reason = "STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE: ++ reason = "STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED: ++ reason = "STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED: ++ reason = "STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE: ++ reason = "STATUS_QUIC_HANDSHAKE_FAILURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE: ++ reason = "STATUS_QUIC_VER_NEG_FAILURE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK: + reason = "STATUS_TPM_ERROR_MASK"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL: + reason = "STATUS_TPM_AUTHFAIL"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX: + reason = "STATUS_TPM_BADINDEX"; +@@ -5490,16 +6700,220 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_TPM_PERMANENTEK"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE: + reason = "STATUS_TPM_BAD_SIGNATURE"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE: + reason = "STATUS_TPM_NOCONTEXTSPACE"; + break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC: ++ reason = "STATUS_TPM_20_E_ASYMMETRIC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES: ++ reason = "STATUS_TPM_20_E_ATTRIBUTES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH: ++ reason = "STATUS_TPM_20_E_HASH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE: ++ reason = "STATUS_TPM_20_E_VALUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY: ++ reason = "STATUS_TPM_20_E_HIERARCHY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE: ++ reason = "STATUS_TPM_20_E_KEY_SIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF: ++ reason = "STATUS_TPM_20_E_MGF"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE: ++ reason = "STATUS_TPM_20_E_MODE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE: ++ reason = "STATUS_TPM_20_E_TYPE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE: ++ reason = "STATUS_TPM_20_E_HANDLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF: ++ reason = "STATUS_TPM_20_E_KDF"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE: ++ reason = "STATUS_TPM_20_E_RANGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL: ++ reason = "STATUS_TPM_20_E_AUTH_FAIL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE: ++ reason = "STATUS_TPM_20_E_NONCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP: ++ reason = "STATUS_TPM_20_E_PP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME: ++ reason = "STATUS_TPM_20_E_SCHEME"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE: ++ reason = "STATUS_TPM_20_E_SIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC: ++ reason = "STATUS_TPM_20_E_SYMMETRIC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG: ++ reason = "STATUS_TPM_20_E_TAG"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR: ++ reason = "STATUS_TPM_20_E_SELECTOR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT: ++ reason = "STATUS_TPM_20_E_INSUFFICIENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE: ++ reason = "STATUS_TPM_20_E_SIGNATURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY: ++ reason = "STATUS_TPM_20_E_KEY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL: ++ reason = "STATUS_TPM_20_E_POLICY_FAIL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY: ++ reason = "STATUS_TPM_20_E_INTEGRITY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET: ++ reason = "STATUS_TPM_20_E_TICKET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS: ++ reason = "STATUS_TPM_20_E_RESERVED_BITS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH: ++ reason = "STATUS_TPM_20_E_BAD_AUTH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED: ++ reason = "STATUS_TPM_20_E_EXPIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC: ++ reason = "STATUS_TPM_20_E_POLICY_CC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING: ++ reason = "STATUS_TPM_20_E_BINDING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE: ++ reason = "STATUS_TPM_20_E_CURVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT: ++ reason = "STATUS_TPM_20_E_ECC_POINT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE: ++ reason = "STATUS_TPM_20_E_INITIALIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE: ++ reason = "STATUS_TPM_20_E_FAILURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE: ++ reason = "STATUS_TPM_20_E_SEQUENCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE: ++ reason = "STATUS_TPM_20_E_PRIVATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC: ++ reason = "STATUS_TPM_20_E_HMAC"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED: ++ reason = "STATUS_TPM_20_E_DISABLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE: ++ reason = "STATUS_TPM_20_E_EXCLUSIVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE: ++ reason = "STATUS_TPM_20_E_ECC_CURVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE: ++ reason = "STATUS_TPM_20_E_AUTH_TYPE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING: ++ reason = "STATUS_TPM_20_E_AUTH_MISSING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY: ++ reason = "STATUS_TPM_20_E_POLICY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR: ++ reason = "STATUS_TPM_20_E_PCR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED: ++ reason = "STATUS_TPM_20_E_PCR_CHANGED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE: ++ reason = "STATUS_TPM_20_E_UPGRADE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS: ++ reason = "STATUS_TPM_20_E_TOO_MANY_CONTEXTS"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE: ++ reason = "STATUS_TPM_20_E_AUTH_UNAVAILABLE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT: ++ reason = "STATUS_TPM_20_E_REBOOT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED: ++ reason = "STATUS_TPM_20_E_UNBALANCED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE: ++ reason = "STATUS_TPM_20_E_COMMAND_SIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE: ++ reason = "STATUS_TPM_20_E_COMMAND_CODE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE: ++ reason = "STATUS_TPM_20_E_AUTHSIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT: ++ reason = "STATUS_TPM_20_E_AUTH_CONTEXT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE: ++ reason = "STATUS_TPM_20_E_NV_RANGE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE: ++ reason = "STATUS_TPM_20_E_NV_SIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED: ++ reason = "STATUS_TPM_20_E_NV_LOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION: ++ reason = "STATUS_TPM_20_E_NV_AUTHORIZATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED: ++ reason = "STATUS_TPM_20_E_NV_UNINITIALIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE: ++ reason = "STATUS_TPM_20_E_NV_SPACE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED: ++ reason = "STATUS_TPM_20_E_NV_DEFINED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT: ++ reason = "STATUS_TPM_20_E_BAD_CONTEXT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH: ++ reason = "STATUS_TPM_20_E_CPHASH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT: ++ reason = "STATUS_TPM_20_E_PARENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST: ++ reason = "STATUS_TPM_20_E_NEEDS_TEST"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT: ++ reason = "STATUS_TPM_20_E_NO_RESULT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE: ++ reason = "STATUS_TPM_20_E_SENSITIVE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED: + reason = "STATUS_TPM_COMMAND_BLOCKED"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE: + reason = "STATUS_TPM_INVALID_HANDLE"; + break; + case MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE: + reason = "STATUS_TPM_DUPLICATE_VHANDLE"; +@@ -5577,16 +6991,94 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_PCP_PROFILE_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED: + reason = "STATUS_PCP_VALIDATION_FAILED"; + break; + case MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND: + reason = "STATUS_PCP_DEVICE_NOT_FOUND"; + break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT: ++ reason = "STATUS_PCP_WRONG_PARENT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED: ++ reason = "STATUS_PCP_KEY_NOT_LOADED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION: ++ reason = "STATUS_PCP_NO_KEY_CERTIFICATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED: ++ reason = "STATUS_PCP_KEY_NOT_FINALIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET: ++ reason = "STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND: ++ reason = "STATUS_PCP_NOT_PCR_BOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED: ++ reason = "STATUS_PCP_KEY_ALREADY_FINALIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED: ++ reason = "STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID: ++ reason = "STATUS_PCP_KEY_USAGE_POLICY_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR: ++ reason = "STATUS_PCP_SOFT_KEY_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED: ++ reason = "STATUS_PCP_KEY_NOT_AUTHENTICATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK: ++ reason = "STATUS_PCP_KEY_NOT_AIK"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY: ++ reason = "STATUS_PCP_KEY_NOT_SIGNING_KEY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT: ++ reason = "STATUS_PCP_LOCKED_OUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED: ++ reason = "STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED: ++ reason = "STATUS_PCP_TPM_VERSION_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH: ++ reason = "STATUS_PCP_BUFFER_LENGTH_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED: ++ reason = "STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING: ++ reason = "STATUS_PCP_TICKET_MISSING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED: ++ reason = "STATUS_PCP_RAW_POLICY_NOT_SUPPORTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED: ++ reason = "STATUS_PCP_KEY_HANDLE_INVALIDATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT: ++ reason = "STATUS_RTPM_NO_RESULT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE: ++ reason = "STATUS_RTPM_PCR_READ_INCOMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT: ++ reason = "STATUS_RTPM_INVALID_CONTEXT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD: ++ reason = "STATUS_RTPM_UNSUPPORTED_CMD"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED: ++ reason = "STATUS_TPM_ZERO_EXHAUST_ENABLED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE: + reason = "STATUS_HV_INVALID_HYPERCALL_CODE"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT: + reason = "STATUS_HV_INVALID_HYPERCALL_INPUT"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT: + reason = "STATUS_HV_INVALID_ALIGNMENT"; +@@ -5628,16 +7120,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_HV_INVALID_CONNECTION_ID"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS: + reason = "STATUS_HV_INSUFFICIENT_BUFFERS"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED: + reason = "STATUS_HV_NOT_ACKNOWLEDGED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE: ++ reason = "STATUS_HV_INVALID_VP_STATE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED: + reason = "STATUS_HV_ACKNOWLEDGED"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE: + reason = "STATUS_HV_INVALID_SAVE_RESTORE_STATE"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE: + reason = "STATUS_HV_INVALID_SYNIC_STATE"; +@@ -5661,19 +7156,70 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_HV_FEATURE_UNAVAILABLE"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER: + reason = "STATUS_HV_INSUFFICIENT_BUFFER"; + break; + case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS: + reason = "STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS"; + break; ++ case MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR: ++ reason = "STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR: ++ reason = "STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT: ++ reason = "STATUS_HV_PROCESSOR_STARTUP_TIMEOUT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED: ++ reason = "STATUS_HV_SMX_ENABLED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX: + reason = "STATUS_HV_INVALID_LP_INDEX"; + break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE: ++ reason = "STATUS_HV_INVALID_REGISTER_VALUE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE: ++ reason = "STATUS_HV_INVALID_VTL_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED: ++ reason = "STATUS_HV_NX_NOT_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID: ++ reason = "STATUS_HV_INVALID_DEVICE_ID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE: ++ reason = "STATUS_HV_INVALID_DEVICE_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID: ++ reason = "STATUS_HV_PAGE_REQUEST_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID: ++ reason = "STATUS_HV_INVALID_CPU_GROUP_ID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE: ++ reason = "STATUS_HV_INVALID_CPU_GROUP_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED: ++ reason = "STATUS_HV_OPERATION_FAILED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE: ++ reason = "STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY: ++ reason = "STATUS_HV_INSUFFICIENT_ROOT_MEMORY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED: ++ reason = "STATUS_HV_EVENT_BUFFER_ALREADY_FREED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY: ++ reason = "STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY"; ++ break; + case MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT: + reason = "STATUS_HV_NOT_PRESENT"; + break; + case MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI: + reason = "STATUS_IPSEC_BAD_SPI"; + break; + case MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED: + reason = "STATUS_IPSEC_SA_LIFETIME_EXPIRED"; +@@ -5838,16 +7384,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_VID_SAVED_STATE_CORRUPT"; + break; + case MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM: + reason = "STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM"; + break; + case MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE: + reason = "STATUS_VID_SAVED_STATE_INCOMPATIBLE"; + break; ++ case MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED: ++ reason = "STATUS_VID_VTL_ACCESS_DENIED"; ++ break; + case MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL: + reason = "STATUS_VOLMGR_DATABASE_FULL"; + break; + case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED: + reason = "STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED"; + break; + case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC: + reason = "STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC"; +@@ -6228,16 +7777,34 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_CTLOG_INVALID_TRACKING_STATE"; + break; + case MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE: + reason = "STATUS_CTLOG_INCONSISTENT_TRACKING_FILE"; + break; + case MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL: + reason = "STATUS_VHD_METADATA_FULL"; + break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID: ++ reason = "STATUS_VHD_INVALID_CHANGE_TRACKING_ID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED: ++ reason = "STATUS_VHD_CHANGE_TRACKING_DISABLED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION: ++ reason = "STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA: ++ reason = "STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE: ++ reason = "STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE: ++ reason = "STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND: + reason = "STATUS_RKF_KEY_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY: + reason = "STATUS_RKF_DUPLICATE_KEY"; + break; + case MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL: + reason = "STATUS_RKF_BLOB_FULL"; +@@ -6255,16 +7822,19 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_RDBSS_RESTART_OPERATION"; + break; + case MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION: + reason = "STATUS_RDBSS_CONTINUE_OPERATION"; + break; + case MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION: + reason = "STATUS_RDBSS_POST_OPERATION"; + break; ++ case MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP: ++ reason = "STATUS_RDBSS_RETRY_LOOKUP"; ++ break; + case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE: + reason = "STATUS_BTH_ATT_INVALID_HANDLE"; + break; + case MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED: + reason = "STATUS_BTH_ATT_READ_NOT_PERMITTED"; + break; + case MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED: + reason = "STATUS_BTH_ATT_WRITE_NOT_PERMITTED"; +@@ -6327,34 +7897,70 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED: + reason = "STATUS_SECUREBOOT_POLICY_NOT_SIGNED"; + break; + case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED: + reason = "STATUS_SECUREBOOT_FILE_REPLACED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED: ++ reason = "STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN: ++ reason = "STATUS_SECUREBOOT_POLICY_UNKNOWN"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION: ++ reason = "STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH: ++ reason = "STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED: ++ reason = "STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH: ++ reason = "STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING: ++ reason = "STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY: ++ reason = "STATUS_SECUREBOOT_NOT_BASE_POLICY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY: ++ reason = "STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY"; ++ break; + case MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND: + reason = "STATUS_AUDIO_ENGINE_NODE_NOT_FOUND"; + break; + case MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST: + reason = "STATUS_HDAUDIO_EMPTY_CONNECTION_LIST"; + break; + case MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED: + reason = "STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED"; + break; + case MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED: + reason = "STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED"; + break; + case MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY: + reason = "STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY"; + break; ++ case MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED: ++ reason = "STATUS_VSM_NOT_INITIALIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE: ++ reason = "STATUS_VSM_DMA_PROTECTION_NOT_IN_USE"; ++ break; + case MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID: + reason = "STATUS_VOLSNAP_BOOTFILE_NOT_VALID"; + break; ++ case MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT: ++ reason = "STATUS_VOLSNAP_ACTIVATION_TIMEOUT"; ++ break; + case MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED: + reason = "STATUS_IO_PREEMPTED"; + break; + case MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED: + reason = "STATUS_SVHDX_ERROR_STORED"; + break; + case MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE: + reason = "STATUS_SVHDX_ERROR_NOT_AVAILABLE"; +@@ -6384,31 +7990,214 @@ string NTStatusToString(uint32_t ntstatu + reason = "STATUS_SVHDX_WRONG_FILE_TYPE"; + break; + case MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH: + reason = "STATUS_SVHDX_VERSION_MISMATCH"; + break; + case MD_NTSTATUS_WIN_STATUS_VHD_SHARED: + reason = "STATUS_VHD_SHARED"; + break; ++ case MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR: ++ reason = "STATUS_SVHDX_NO_INITIATOR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND: ++ reason = "STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP: ++ reason = "STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT: ++ reason = "STATUS_SMB_BAD_CLUSTER_DIALECT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED: ++ reason = "STATUS_SMB_GUEST_LOGON_BLOCKED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID: ++ reason = "STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID"; ++ break; + case MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID: + reason = "STATUS_SPACES_RESILIENCY_TYPE_INVALID"; + break; + case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID: + reason = "STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID"; + break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID: ++ reason = "STATUS_SPACES_DRIVE_REDUNDANCY_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID: ++ reason = "STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID"; ++ break; + case MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID: + reason = "STATUS_SPACES_INTERLEAVE_LENGTH_INVALID"; + break; + case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID: + reason = "STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID"; + break; + case MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES: + reason = "STATUS_SPACES_NOT_ENOUGH_DRIVES"; + break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR: ++ reason = "STATUS_SPACES_EXTENDED_ERROR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID: ++ reason = "STATUS_SPACES_PROVISIONING_TYPE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID: ++ reason = "STATUS_SPACES_ALLOCATION_SIZE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID: ++ reason = "STATUS_SPACES_ENCLOSURE_AWARE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID: ++ reason = "STATUS_SPACES_WRITE_CACHE_SIZE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID: ++ reason = "STATUS_SPACES_NUMBER_OF_GROUPS_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID: ++ reason = "STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE: ++ reason = "STATUS_SPACES_UPDATE_COLUMN_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED: ++ reason = "STATUS_SPACES_MAP_REQUIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION: ++ reason = "STATUS_SPACES_UNSUPPORTED_VERSION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA: ++ reason = "STATUS_SPACES_CORRUPT_METADATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL: ++ reason = "STATUS_SPACES_DRT_FULL"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY: ++ reason = "STATUS_SPACES_INCONSISTENCY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY: ++ reason = "STATUS_SPACES_LOG_NOT_READY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY: ++ reason = "STATUS_SPACES_NO_REDUNDANCY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY: ++ reason = "STATUS_SPACES_DRIVE_NOT_READY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT: ++ reason = "STATUS_SPACES_DRIVE_SPLIT"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA: ++ reason = "STATUS_SPACES_DRIVE_LOST_DATA"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE: ++ reason = "STATUS_SPACES_ENTRY_INCOMPLETE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID: ++ reason = "STATUS_SPACES_ENTRY_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY: ++ reason = "STATUS_SPACES_MARK_DIRTY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND: ++ reason = "STATUS_SECCORE_INVALID_COMMAND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED: ++ reason = "STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION: ++ reason = "STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY: ++ reason = "STATUS_SYSTEM_INTEGRITY_INVALID_POLICY"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED: ++ reason = "STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES: ++ reason = "STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED: ++ reason = "STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND: ++ reason = "STATUS_NO_APPLICABLE_APP_LICENSES_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND: ++ reason = "STATUS_CLIP_LICENSE_NOT_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING: ++ reason = "STATUS_CLIP_DEVICE_LICENSE_MISSING"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE: ++ reason = "STATUS_CLIP_LICENSE_INVALID_SIGNATURE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID: ++ reason = "STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED: ++ reason = "STATUS_CLIP_LICENSE_EXPIRED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE: ++ reason = "STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED: ++ reason = "STATUS_CLIP_LICENSE_NOT_SIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE: ++ reason = "STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH: ++ reason = "STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED: ++ reason = "STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID: ++ reason = "STATUS_PLATFORM_MANIFEST_INVALID"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED: ++ reason = "STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED: ++ reason = "STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND: ++ reason = "STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE: ++ reason = "STATUS_PLATFORM_MANIFEST_NOT_ACTIVE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED: ++ reason = "STATUS_PLATFORM_MANIFEST_NOT_SIGNED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED: ++ reason = "STATUS_APPEXEC_CONDITION_NOT_SATISFIED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED: ++ reason = "STATUS_APPEXEC_HANDLE_INVALIDATED"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION: ++ reason = "STATUS_APPEXEC_INVALID_HOST_GENERATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION: ++ reason = "STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE: ++ reason = "STATUS_APPEXEC_INVALID_HOST_STATE"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR: ++ reason = "STATUS_APPEXEC_NO_DONOR"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH: ++ reason = "STATUS_APPEXEC_HOST_ID_MISMATCH"; ++ break; ++ case MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER: ++ reason = "STATUS_APPEXEC_UNKNOWN_USER"; ++ break; + default: { + char reason_string[11]; + snprintf(reason_string, sizeof(reason_string), "0x%08x", ntstatus); + reason = reason_string; + break; + } + } + return reason; + diff --git a/toolkit/crashreporter/breakpad-patches/20-mac-crash-info.patch b/toolkit/crashreporter/breakpad-patches/20-mac-crash-info.patch new file mode 100644 index 0000000000..be971133a1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/20-mac-crash-info.patch @@ -0,0 +1,516 @@ +# HG changeset patch +# User Steven Michaud +# Date 1619800781 18000 +# Fri Apr 30 11:39:41 2021 -0500 +# Node ID 9f89eb3d68316e8c3a469d1c058ad40c1807d7bc +# Parent 0db412525773fff333e8d338551021e083c25619 +Bug 1577886 - Add support to for macOS __crash_info data to Breakpad. r=gsvelto +Differential Revision: https://phabricator.services.mozilla.com/D112871 + +diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h +--- a/src/google_breakpad/common/minidump_format.h ++++ b/src/google_breakpad/common/minidump_format.h +@@ -351,6 +351,10 @@ typedef enum { + /* Crashpad extension types. 0x4350 = "CP" + * See Crashpad's minidump/minidump_extensions.h. */ + MD_CRASHPAD_INFO_STREAM = 0x43500001, /* MDRawCrashpadInfo */ ++ ++ /* Data from the __DATA,__crash_info section of every module which contains ++ * one that has useful data. Only available on macOS. 0x4D7A = "Mz". */ ++ MOZ_MACOS_CRASH_INFO_STREAM = 0x4d7a0001, + } MDStreamType; /* MINIDUMP_STREAM_TYPE */ + + +@@ -1094,6 +1098,52 @@ typedef struct { + MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */ + } MDRawCrashpadInfo; + ++/* macOS __DATA,__crash_info data */ ++ ++typedef struct { ++ uint64_t stream_type; /* MOZ_MACOS_CRASH_INFO_STREAM */ ++ uint64_t version; ++ uint64_t thread; ++ uint64_t dialog_mode; ++ uint64_t abort_cause; /* Only valid when 'version' > 4 */ ++ /* If/when Apple adds more fields to crashreporter_annotations_t, add ++ * numerical fields here and change (MDRawMacCrashInfo).record_start_size ++ * accordingly. Make them all uint64_t, to keep this structure the same size ++ * on all platforms. 'data' should always be the last field. Add new string ++ * fields to the end of 'data'. */ ++ /* 'data' currently contains five null-terminated uint8_t arrays, each ++ * possibly empty (containing only a single terminal null), stored one after ++ * the other: ++ * module_path; ++ * message; ++ * signature_string; ++ * backtrace; ++ * message2; */ ++ uint8_t data[0]; ++} MDRawMacCrashInfoRecord; ++ ++/* This is the maximum supported size for each string in ++ * (MDRawMacCrashInfoRecord).data. If we encounter a string in the ++ * __crash_info section which seems larger than this, that's a sign of data ++ * corruption. */ ++#define MACCRASHINFO_STRING_MAXSIZE 8192 ++ ++/* In principle there should only be one or two non-empty __DATA,__crash_info ++ * sections per process. But the __crash_info section is almost entirely ++ * undocumented, so just in case we set a large maximum. */ ++#define MAC_CRASH_INFOS_MAX 20 ++ ++typedef struct { ++ uint32_t stream_type; /* MOZ_MACOS_CRASH_INFO_STREAM */ ++ uint32_t record_count; ++ /* The size of the "fixed-size" part of MDRawMacCrashInfoRecord, before the ++ * 'data' field. This will always be 'sizeof(MDRawMacCrashInfoRecord)'. But ++ * that value may change if more numerical fields are added to ++ * MDRawMacCrashInfoRecord in the future. */ ++ uint32_t record_start_size; ++ MDLocationDescriptor records[MAC_CRASH_INFOS_MAX]; ++} MDRawMacCrashInfo; ++ + #if defined(_MSC_VER) + #pragma warning(pop) + #endif /* _MSC_VER */ +diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h +--- a/src/google_breakpad/processor/minidump.h ++++ b/src/google_breakpad/processor/minidump.h +@@ -1151,6 +1151,57 @@ class MinidumpCrashpadInfo : public Mini + std::map simple_annotations_; + }; + ++// MinidumpMacCrashInfo wraps MDRawMacCrashInfo. It's an optional stream ++// in a minidump that records information from the __DATA,__crash_info ++// section of every module in the crashing process that contains one, and ++// which isn't empty of useful information. Only present on macOS. ++ ++// Friendly wrapper for the information in MDRawMacCrashInfoRecord. ++typedef struct crash_info_record { ++ string module_path; ++ unsigned long version; ++ string message; ++ string signature_string; ++ string backtrace; ++ string message2; ++ unsigned long long thread; ++ unsigned int dialog_mode; ++ long long abort_cause; // Only valid when 'version' > 4 ++ crash_info_record() ++ : version(0), thread(0), dialog_mode(0), abort_cause(0) ++ {} ++} crash_info_record_t; ++ ++class MinidumpMacCrashInfo : public MinidumpStream { ++ public: ++ // A human-readable representation of the data from the __DATA,__crash_info ++ // sections in all of the crashing process's modules that have one, if ++ // it's not empty of useful data. Suitable for use by "minidump_stackwalk". ++ string description() const { return description_; } ++ // A "machine-readable" copy of the same information, suitable for use by ++ // "minidump_stalkwalk -m". ++ vector const records() { ++ return records_; ++ } ++ ++ // Print a human-readable representation of the object to stdout. ++ void Print(); ++ ++ private: ++ friend class Minidump; ++ ++ static const uint32_t kStreamType = MOZ_MACOS_CRASH_INFO_STREAM; ++ ++ explicit MinidumpMacCrashInfo(Minidump* minidump_); ++ ++ bool ReadCrashInfoRecord(MDLocationDescriptor location, ++ uint32_t record_start_size); ++ bool Read(uint32_t expected_size); ++ ++ string description_; ++ vector records_; ++}; ++ + + // Minidump is the user's interface to a minidump file. It wraps MDRawHeader + // and provides access to the minidump's top-level stream directory. +@@ -1214,6 +1265,7 @@ class Minidump { + virtual MinidumpBreakpadInfo* GetBreakpadInfo(); + virtual MinidumpMemoryInfoList* GetMemoryInfoList(); + MinidumpCrashpadInfo* GetCrashpadInfo(); ++ MinidumpMacCrashInfo* GetMacCrashInfo(); + + // The next method also calls GetStream, but is exclusive for Linux dumps. + virtual MinidumpLinuxMapsList *GetLinuxMapsList(); +diff --git a/src/google_breakpad/processor/process_state.h b/src/google_breakpad/processor/process_state.h +--- a/src/google_breakpad/processor/process_state.h ++++ b/src/google_breakpad/processor/process_state.h +@@ -112,6 +112,14 @@ class ProcessState { + return &thread_memory_regions_; + } + const SystemInfo* system_info() const { return &system_info_; } ++ string mac_crash_info() const { return mac_crash_info_; } ++ size_t mac_crash_info_records_count() const { ++ return mac_crash_info_records_.size(); ++ } ++ const crash_info_record_t* mac_crash_info_records() const { ++ return reinterpret_cast( ++ &mac_crash_info_records_[0]); ++ } + const CodeModules* modules() const { return modules_; } + const CodeModules* unloaded_modules() const { return unloaded_modules_; } + const vector >* shrunk_range_modules() const { +@@ -179,6 +187,10 @@ class ProcessState { + // OS and CPU information. + SystemInfo system_info_; + ++ // Information from __DATA,__crash_info sections. Only present on macOS. ++ string mac_crash_info_; ++ vector mac_crash_info_records_; ++ + // The modules that were loaded into the process represented by the + // ProcessState. + const CodeModules *modules_; +diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc +--- a/src/processor/minidump.cc ++++ b/src/processor/minidump.cc +@@ -5116,6 +5116,230 @@ void MinidumpCrashpadInfo::Print() { + printf("\n"); + } + ++// ++// MinidumpMacCrashInfo ++// ++ ++MinidumpMacCrashInfo::MinidumpMacCrashInfo(Minidump* minidump) ++ : MinidumpStream(minidump), ++ description_(), ++ records_() { ++} ++ ++bool MinidumpMacCrashInfo::ReadCrashInfoRecord(MDLocationDescriptor location, ++ uint32_t record_start_size) { ++ if (!minidump_->SeekSet(location.rva)) { ++ BPLOG(ERROR) << "ReadCrashInfoRecord could not seek to record"; ++ return false; ++ } ++ ++ // We may be reading a minidump 1) created by (newer) code that defines more ++ // fields than we do in the fixed-size part of MDRawMacCrashInfoRecord ++ // (before 'data'), or 2) created by (older) code that defines fewer fields. ++ // In the first case we read in the newer fields but ignore them. In the ++ // second case we read in only the older fields, and leave the newer fields ++ // (in 'raw_record_start') set to zero. ++ uint32_t raw_record_size = sizeof(MDRawMacCrashInfoRecord); ++ if (record_start_size > raw_record_size) { ++ raw_record_size = record_start_size; ++ } ++ scoped_ptr< vector > raw_record( ++ new vector(raw_record_size)); ++ if (!minidump_->ReadBytes(&(*raw_record)[0], record_start_size)) { ++ BPLOG(ERROR) << "ReadCrashInfoRecord could not read " << ++ record_start_size << " bytes of record"; ++ return false; ++ } ++ MDRawMacCrashInfoRecord* raw_record_start = ++ (MDRawMacCrashInfoRecord*) &(*raw_record)[0]; ++ ++ if (minidump_->swap()) { ++ Swap(&raw_record_start->stream_type); ++ Swap(&raw_record_start->version); ++ Swap(&raw_record_start->thread); ++ Swap(&raw_record_start->dialog_mode); ++ Swap(&raw_record_start->abort_cause); ++ } ++ ++ if (raw_record_start->stream_type != MOZ_MACOS_CRASH_INFO_STREAM) { ++ BPLOG(ERROR) << "ReadCrashInfoRecord stream type mismatch, " << ++ raw_record_start->stream_type << " != " << ++ MOZ_MACOS_CRASH_INFO_STREAM; ++ return false; ++ } ++ ++ uint32_t string_data_size = location.data_size - record_start_size; ++ scoped_ptr< vector > data(new vector(string_data_size)); ++ if (!minidump_->ReadBytes(&(*data)[0], string_data_size)) { ++ BPLOG(ERROR) << "ReadCrashInfoRecord could not read " << ++ string_data_size << " bytes of record data"; ++ return false; ++ } ++ ++ crash_info_record_t record; ++ ++ record.version = (unsigned long) raw_record_start->version; ++ record.thread = (unsigned long long) raw_record_start->thread; ++ record.dialog_mode = (unsigned int) raw_record_start->dialog_mode; ++ record.abort_cause = (long long) raw_record_start->abort_cause; ++ ++ // Once again, we may be reading a minidump created by newer code that ++ // stores more strings than we expect in (MDRawMacCrashInfoRecord).data, ++ // or one created by older code that contains fewer strings than we ++ // expect. In the first case we ignore the "extra" strings. To deal with ++ // the second case we bail when 'offset >= string_data_size'. ++ const char* string_data = (const char*) &(*data)[0]; ++ size_t offset = 0; ++ for (int i = 1; i <= 5; ++i) { ++ switch (i) { ++ case 1: ++ record.module_path.append(string_data); ++ break; ++ case 2: ++ record.message.append(string_data); ++ break; ++ case 3: ++ record.signature_string.append(string_data); ++ break; ++ case 4: ++ record.backtrace.append(string_data); ++ break; ++ case 5: ++ record.message2.append(string_data); ++ break; ++ } ++ size_t char_array_size = strlen(string_data) + 1; ++ offset += char_array_size; ++ if (offset >= string_data_size) { ++ break; ++ } ++ string_data += char_array_size; ++ } ++ ++ records_.push_back(record); ++ ++ description_.append(" Module \""); ++ description_.append(record.module_path); ++ description_.append("\":\n"); ++ ++ int num_fields = 6; ++ if (record.version > 4) { ++ num_fields = 7; ++ } ++ for (int i = 1; i <= num_fields; ++i) { ++ switch (i) { ++ case 1: ++ if (!record.message.empty()) { ++ description_.append(" message: \""); ++ description_.append(record.message); ++ description_.append("\"\n"); ++ } ++ break; ++ case 2: ++ if (!record.signature_string.empty()) { ++ description_.append(" signature_string: \""); ++ description_.append(record.signature_string); ++ description_.append("\"\n"); ++ } ++ break; ++ case 3: ++ if (!record.backtrace.empty()) { ++ description_.append(" backtrace: \""); ++ description_.append(record.backtrace); ++ description_.append("\"\n"); ++ } ++ break; ++ case 4: ++ if (!record.message2.empty()) { ++ description_.append(" message2: \""); ++ description_.append(record.message2); ++ description_.append("\"\n"); ++ } ++ break; ++ case 5: ++ if (record.thread) { ++ char thread[128]; ++ snprintf(thread, sizeof(thread), " thread: 0x%llx\n", ++ record.thread); ++ description_.append(thread); ++ } ++ break; ++ case 6: ++ if (record.dialog_mode) { ++ char dialog_mode[128]; ++ snprintf(dialog_mode, sizeof(dialog_mode), " dialog_mode: 0x%x\n", ++ record.dialog_mode); ++ description_.append(dialog_mode); ++ } ++ break; ++ case 7: ++ if (record.abort_cause) { ++ char abort_cause[128]; ++ snprintf(abort_cause, sizeof(abort_cause), " abort_cause: %lld\n", ++ record.abort_cause); ++ description_.append(abort_cause); ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return true; ++} ++ ++bool MinidumpMacCrashInfo::Read(uint32_t expected_size) { ++ description_.clear(); ++ records_.clear(); ++ valid_ = false; ++ ++ MDRawMacCrashInfo crash_info; ++ if (expected_size != sizeof(crash_info)) { ++ BPLOG(ERROR) << "MinidumpMacCrashInfo size mismatch, " << ++ expected_size << " != " << sizeof(crash_info); ++ return false; ++ } ++ if (!minidump_->ReadBytes(&crash_info, sizeof(crash_info))) { ++ BPLOG(ERROR) << "MinidumpMacCrashInfo could not read " << ++ sizeof(crash_info) << " bytes"; ++ return false; ++ } ++ if (minidump_->swap()) { ++ Swap(&crash_info.stream_type); ++ Swap(&crash_info.record_count); ++ Swap(&crash_info.record_start_size); ++ for (uint32_t i = 0; i < crash_info.record_count; ++i) { ++ Swap(&crash_info.records[i].data_size); ++ Swap(&crash_info.records[i].rva); ++ } ++ } ++ if (crash_info.stream_type != MOZ_MACOS_CRASH_INFO_STREAM) { ++ BPLOG(ERROR) << "MinidumpMacCrashInfo stream type mismatch, " << ++ crash_info.stream_type << " != " << ++ MOZ_MACOS_CRASH_INFO_STREAM; ++ return false; ++ } ++ ++ for (uint32_t i = 0; i < crash_info.record_count; ++i) { ++ if (!ReadCrashInfoRecord(crash_info.records[i], ++ crash_info.record_start_size)) { ++ return false; ++ } ++ } ++ ++ valid_ = true; ++ return true; ++} ++ ++void MinidumpMacCrashInfo::Print() { ++ if (!valid_) { ++ BPLOG(ERROR) << "MinidumpMacCrashInfo cannot print invalid data"; ++ return; ++ } ++ ++ printf("MinidumpMacCrashInfo:\n\n"); ++ printf("%s", description_.c_str()); ++} + + // + // Minidump +@@ -5378,7 +5602,8 @@ bool Minidump::Read() { + case MD_SYSTEM_INFO_STREAM: + case MD_MISC_INFO_STREAM: + case MD_BREAKPAD_INFO_STREAM: +- case MD_CRASHPAD_INFO_STREAM: { ++ case MD_CRASHPAD_INFO_STREAM: ++ case MOZ_MACOS_CRASH_INFO_STREAM: { + if (stream_map_->find(stream_type) != stream_map_->end()) { + // Another stream with this type was already found. A minidump + // file should contain at most one of each of these stream types. +@@ -5499,6 +5724,11 @@ MinidumpCrashpadInfo* Minidump::GetCrash + return GetStream(&crashpad_info); + } + ++MinidumpMacCrashInfo* Minidump::GetMacCrashInfo() { ++ MinidumpMacCrashInfo* mac_crash_info; ++ return GetStream(&mac_crash_info); ++} ++ + static const char* get_stream_name(uint32_t stream_type) { + switch (stream_type) { + case MD_UNUSED_STREAM: +@@ -5571,6 +5801,8 @@ static const char* get_stream_name(uint3 + return "MD_LINUX_DSO_DEBUG"; + case MD_CRASHPAD_INFO_STREAM: + return "MD_CRASHPAD_INFO_STREAM"; ++ case MOZ_MACOS_CRASH_INFO_STREAM: ++ return "MOZ_MACOS_CRASH_INFO_STREAM"; + default: + return "unknown"; + } +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -137,6 +137,12 @@ ProcessResult MinidumpProcessor::Process + } + } + ++ MinidumpMacCrashInfo *crash_info = dump->GetMacCrashInfo(); ++ if (crash_info) { ++ process_state->mac_crash_info_ = crash_info->description(); ++ process_state->mac_crash_info_records_ = crash_info->records(); ++ } ++ + // This will just return an empty string if it doesn't exist. + process_state->assertion_ = GetAssertion(dump); + +diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc +--- a/src/processor/stackwalk_common.cc ++++ b/src/processor/stackwalk_common.cc +@@ -872,6 +872,12 @@ void PrintProcessState(const ProcessStat + printf("Process uptime: not available\n"); + } + ++ if (!process_state.mac_crash_info().empty()) { ++ printf("\n"); ++ printf("Application-specific information:\n"); ++ printf("%s", process_state.mac_crash_info().c_str()); ++ } ++ + // If the thread that requested the dump is known, print it first. + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { +@@ -955,6 +961,44 @@ void PrintProcessStateMachineReadable(co + printf("\n"); + } + ++ const crash_info_record_t* crash_info_records = ++ process_state.mac_crash_info_records(); ++ size_t num_records = ++ process_state.mac_crash_info_records_count(); ++ for (size_t i = 0; i < num_records; ++i) { ++ char thread_str[32]; ++ if (crash_info_records[i].thread) { ++ snprintf(thread_str, sizeof(thread_str), "0x%llx", ++ crash_info_records[i].thread); ++ } else { ++ strncpy(thread_str, "0", sizeof(thread_str)); ++ } ++ char dialog_mode_str[32]; ++ if (crash_info_records[i].dialog_mode) { ++ snprintf(dialog_mode_str, sizeof(dialog_mode_str), "0x%x", ++ crash_info_records[i].dialog_mode); ++ } else { ++ strncpy(dialog_mode_str, "0", sizeof(dialog_mode_str)); ++ } ++ char abort_cause_str[32]; ++ if (crash_info_records[i].abort_cause) { ++ snprintf(abort_cause_str, sizeof(abort_cause_str), "%lld", ++ crash_info_records[i].abort_cause); ++ } else { ++ strncpy(abort_cause_str, "0", sizeof(abort_cause_str)); ++ } ++ printf("MacCrashInfo%c%s%c%lu%c%s%c%s%c%s%c%s%c%s%c%s%c%s\n", ++ kOutputSeparator, crash_info_records[i].module_path.c_str(), ++ kOutputSeparator, crash_info_records[i].version, ++ kOutputSeparator, crash_info_records[i].message.c_str(), ++ kOutputSeparator, crash_info_records[i].signature_string.c_str(), ++ kOutputSeparator, crash_info_records[i].backtrace.c_str(), ++ kOutputSeparator, crash_info_records[i].message2.c_str(), ++ kOutputSeparator, thread_str, ++ kOutputSeparator, dialog_mode_str, ++ kOutputSeparator, abort_cause_str); ++ } ++ + PrintModulesMachineReadable(process_state.modules()); + PrintUnloadedModulesMachineReadable(process_state.unloaded_modules()); + diff --git a/toolkit/crashreporter/breakpad-patches/21-thread-names.patch b/toolkit/crashreporter/breakpad-patches/21-thread-names.patch new file mode 100644 index 0000000000..ea4dd67cd1 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/21-thread-names.patch @@ -0,0 +1,661 @@ +diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h +--- a/src/google_breakpad/common/minidump_format.h ++++ b/src/google_breakpad/common/minidump_format.h +@@ -227,17 +227,18 @@ typedef struct { + + /* + * DbgHelp.h + */ + + + /* An MDRVA is an offset into the minidump file. The beginning of the + * MDRawHeader is at offset 0. */ +-typedef uint32_t MDRVA; /* RVA */ ++typedef uint32_t MDRVA; /* RVA */ ++typedef uint64_t MDRVA64; /* RVA64 */ + + typedef struct { + uint32_t data_size; + MDRVA rva; + } MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */ + + + typedef struct { +@@ -327,16 +328,18 @@ typedef enum { + MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */ + MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */ + MD_THREAD_INFO_LIST_STREAM = 17, + MD_HANDLE_OPERATION_LIST_STREAM = 18, + MD_TOKEN_STREAM = 19, + MD_JAVASCRIPT_DATA_STREAM = 20, + MD_SYSTEM_MEMORY_INFO_STREAM = 21, + MD_PROCESS_VM_COUNTERS_STREAM = 22, ++ MD_IPT_TRACE_STREAM = 23, ++ MD_THREAD_NAMES_STREAM = 24, + MD_LAST_RESERVED_STREAM = 0x0000ffff, + + /* Breakpad extension types. 0x4767 = "Gg" */ + MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */ + MD_ASSERTION_INFO_STREAM = 0x47670002, /* MDRawAssertionInfo */ + /* These are additional minidump stream values which are specific to + * the linux breakpad implementation. */ + MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */ +@@ -1117,16 +1120,26 @@ typedef struct { + * module_path; + * message; + * signature_string; + * backtrace; + * message2; */ + uint8_t data[0]; + } MDRawMacCrashInfoRecord; + ++typedef struct __attribute__((packed,aligned(4))) { ++ uint32_t thread_id; ++ MDRVA64 rva_of_thread_name; ++} MDRawThreadName; ++ ++typedef struct { ++ uint32_t number_of_thread_names; ++ MDRawThreadName thread_names[0]; ++} MDRawThreadNamesList; ++ + /* This is the maximum supported size for each string in + * (MDRawMacCrashInfoRecord).data. If we encounter a string in the + * __crash_info section which seems larger than this, that's a sign of data + * corruption. */ + #define MACCRASHINFO_STRING_MAXSIZE 8192 + + /* In principle there should only be one or two non-empty __DATA,__crash_info + * sections per process. But the __crash_info section is almost entirely +diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h +--- a/src/google_breakpad/processor/call_stack.h ++++ b/src/google_breakpad/processor/call_stack.h +@@ -41,21 +41,23 @@ + // beginning with the innermost callee frame. + // + // Author: Mark Mentovai + + #ifndef GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ + #define GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ + + #include ++#include + #include + + namespace google_breakpad { + + using std::vector; ++using std::string; + + struct StackFrame; + template class linked_ptr; + + class CallStack { + public: + CallStack() { Clear(); } + ~CallStack(); +@@ -63,29 +65,33 @@ class CallStack { + // Resets the CallStack to its initial empty state + void Clear(); + + const vector* frames() const { return &frames_; } + + // Set the TID associated with this call stack. + void set_tid(uint32_t tid) { tid_ = tid; } + void set_last_error(uint32_t last_error) { last_error_ = last_error; } ++ void set_name(const string& name) { name_ = name; } + + uint32_t tid() const { return tid_; } + uint32_t last_error() const { return last_error_; } ++ const string name() const { return name_; } + + private: + // Stackwalker is responsible for building the frames_ vector. + friend class Stackwalker; + + // Storage for pushed frames. + vector frames_; + + // The TID associated with this call stack. Default to 0 if it's not + // available. + uint32_t tid_; + // The last error the OS set for this thread (win32's GetLastError()) + uint32_t last_error_; ++ // The name of this thread, empty if it's not available ++ string name_; + }; + + } // namespace google_breakpad + + #endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__ +diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h +--- a/src/google_breakpad/processor/minidump.h ++++ b/src/google_breakpad/processor/minidump.h +@@ -1197,16 +1197,96 @@ class MinidumpMacCrashInfo : public Mini + bool ReadCrashInfoRecord(MDLocationDescriptor location, + uint32_t record_start_size); + bool Read(uint32_t expected_size); + + string description_; + vector records_; + }; + ++// MinidumpThreadName wraps MDRawThreadName ++class MinidumpThreadName : public MinidumpObject { ++ public: ++ ~MinidumpThreadName() override; ++ ++ const MDRawThreadName* thread_name() const { ++ if (valid_) { ++ return &thread_name_; ++ } ++ ++ return NULL; ++ } ++ ++ uint32_t thread_id() const { ++ if (valid_) { ++ return thread_name_.thread_id; ++ } ++ ++ return 0; ++ } ++ ++ string name() const; ++ ++ // Print a human-readable representation of the object to stdout. ++ void Print(); ++ ++ protected: ++ explicit MinidumpThreadName(Minidump* minidump); ++ ++ private: ++ // These objects are managed by MinidumpThreadNameList ++ friend class MinidumpThreadNamesList; ++ ++ // This works like MinidumpStream::Read, but is driven by ++ // MinidumpThreadNameList. ++ bool Read(uint32_t expected_size); ++ ++ // Reads the thread name. This is done separately from Read to ++ // allow contiguous reading of thread names by MinidumpThreadNameList. ++ bool ReadAuxiliaryData(); ++ ++ bool valid_; ++ MDRawThreadName thread_name_; ++ const string* name_; ++}; ++ ++ ++// MinidumpThreadNamesList contains all the names for threads in a process ++// in the form of MinidumpThreadNames. ++class MinidumpThreadNamesList : public MinidumpStream { ++ public: ++ ~MinidumpThreadNamesList() override; ++ ++ unsigned int name_count() const { ++ return valid_ ? name_count_ : 0; ++ } ++ ++ const string GetNameForThreadId(uint32_t thread_id) const; ++ ++ // Print a human-readable representation of the object to stdout. ++ void Print(); ++ ++ protected: ++ explicit MinidumpThreadNamesList(Minidump* minidump_); ++ ++ private: ++ friend class Minidump; ++ ++ typedef vector MinidumpThreadNames; ++ ++ static const uint32_t kStreamType = MD_THREAD_NAMES_STREAM; ++ ++ bool Read(uint32_t expected_size_) override; ++ ++ MinidumpThreadNames* thread_names_; ++ uint32_t name_count_; ++ bool valid_; ++ ++ DISALLOW_COPY_AND_ASSIGN(MinidumpThreadNamesList); ++}; + + // 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, + bool hexdump=false, +@@ -1261,16 +1343,17 @@ class Minidump { + virtual MinidumpAssertion* GetAssertion(); + virtual MinidumpSystemInfo* GetSystemInfo(); + virtual MinidumpUnloadedModuleList* GetUnloadedModuleList(); + virtual MinidumpMiscInfo* GetMiscInfo(); + virtual MinidumpBreakpadInfo* GetBreakpadInfo(); + virtual MinidumpMemoryInfoList* GetMemoryInfoList(); + MinidumpCrashpadInfo* GetCrashpadInfo(); + MinidumpMacCrashInfo* GetMacCrashInfo(); ++ MinidumpThreadNamesList* GetThreadNamesList(); + + // The next method also calls GetStream, but is exclusive for Linux dumps. + virtual MinidumpLinuxMapsList *GetLinuxMapsList(); + + // 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. +diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc +--- a/src/processor/call_stack.cc ++++ b/src/processor/call_stack.cc +@@ -45,11 +45,12 @@ CallStack::~CallStack() { + void CallStack::Clear() { + for (vector::const_iterator iterator = frames_.begin(); + iterator != frames_.end(); + ++iterator) { + delete *iterator; + } + tid_ = 0; + last_error_ = 0; ++ name_ = ""; + } + + } // namespace google_breakpad +diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc +--- a/src/processor/minidump.cc ++++ b/src/processor/minidump.cc +@@ -5724,16 +5724,226 @@ MinidumpCrashpadInfo* Minidump::GetCrash + return GetStream(&crashpad_info); + } + + MinidumpMacCrashInfo* Minidump::GetMacCrashInfo() { + MinidumpMacCrashInfo* mac_crash_info; + return GetStream(&mac_crash_info); + } + ++MinidumpThreadNamesList* Minidump::GetThreadNamesList() { ++ MinidumpThreadNamesList* thread_names_list; ++ return GetStream(&thread_names_list); ++} ++ ++// ++// MinidumpThreadName ++// ++ ++ ++MinidumpThreadName::MinidumpThreadName(Minidump* minidump) ++ : MinidumpObject(minidump), ++ valid_(false), ++ thread_name_(), ++ name_(NULL) { ++ ++} ++ ++MinidumpThreadName::~MinidumpThreadName() { ++ ; ++} ++ ++void MinidumpThreadName::Print() { ++ if (!valid_) { ++ BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data"; ++ return; ++ } ++ ++ printf("MDRawThreadName\n"); ++ printf(" thread_id = 0x%x\n", ++ thread_name_.thread_id); ++ printf(" rva_of_thread_name = 0x%" PRIx64 "\n", ++ thread_name_.rva_of_thread_name); ++ ++ printf(" (name) = \"%s\"\n", name().c_str()); ++ printf("\n"); ++} ++ ++string MinidumpThreadName::name() const { ++ if (!valid_) { ++ BPLOG(ERROR) << "Invalid MinidumpThreadName for name"; ++ return ""; ++ } ++ ++ return *name_; ++} ++ ++bool MinidumpThreadName::Read(uint32_t expected_size) { ++ ++ delete name_; ++ ++ if (expected_size < sizeof(thread_name_)) { ++ BPLOG(ERROR) << "MinidumpThreadName expected size is less than size " ++ << "of struct " << expected_size << " < " ++ << sizeof(thread_name_); ++ return false; ++ } ++ ++ if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) { ++ BPLOG(ERROR) << "MinidumpThreadName cannot read name"; ++ return false; ++ } ++ ++ if (expected_size > sizeof(thread_name_)) { ++ uint32_t thread_name_bytes_remaining = expected_size - sizeof(thread_name_); ++ off_t pos = minidump_->Tell(); ++ if (!minidump_->SeekSet(pos + thread_name_bytes_remaining)) { ++ BPLOG(ERROR) << "MinidumpThreadName unable to seek to end of name"; ++ return false; ++ } ++ } ++ ++ if (minidump_->swap()) { ++ Swap(&thread_name_.thread_id); ++ uint64_t rva_of_thread_name; ++ memcpy(&rva_of_thread_name, &thread_name_.rva_of_thread_name, sizeof(uint64_t)); ++ Swap(&rva_of_thread_name); ++ memcpy(&thread_name_.rva_of_thread_name, &rva_of_thread_name, sizeof(uint64_t)); ++ } ++ ++ return true; ++} ++ ++bool MinidumpThreadName::ReadAuxiliaryData() { ++ // Each thread must have a name string. ++ name_ = minidump_->ReadString(thread_name_.rva_of_thread_name); ++ if (!name_) { ++ BPLOG(ERROR) << "MinidumpThreadName could not read name"; ++ valid_ = false; ++ return false; ++ } ++ ++ // At this point, we have enough info for the name to be valid. ++ valid_ = true; ++ return true; ++} ++ ++// ++// MinidumpThreadNamesList ++// ++ ++ ++MinidumpThreadNamesList::MinidumpThreadNamesList(Minidump* minidump) ++ : MinidumpStream(minidump), ++ thread_names_(NULL), ++ name_count_(0), ++ valid_(false) { ++ ; ++} ++ ++MinidumpThreadNamesList::~MinidumpThreadNamesList() { ++ delete thread_names_; ++} ++ ++const string MinidumpThreadNamesList::GetNameForThreadId(uint32_t thread_id) const { ++ if (valid_) { ++ for (unsigned int name_index = 0; ++ name_index < name_count_; ++ ++name_index) { ++ const MinidumpThreadName& thread_name = (*thread_names_)[name_index]; ++ if (thread_name.thread_id() == thread_id) { ++ return thread_name.name(); ++ } ++ } ++ } ++ ++ return ""; ++} ++ ++void MinidumpThreadNamesList::Print() { ++ if (!valid_) { ++ BPLOG(ERROR) << "MinidumpThreadNamesList cannot print invalid data"; ++ return; ++ } ++ ++ printf("MinidumpThreadNamesList\n"); ++ printf(" name_count = %d\n", name_count_); ++ printf("\n"); ++ ++ for (unsigned int name_index = 0; ++ name_index < name_count_; ++ ++name_index) { ++ printf("thread_name[%d]\n", name_index); ++ ++ (*thread_names_)[name_index].Print(); ++ } ++} ++ ++bool MinidumpThreadNamesList::Read(uint32_t expected_size) { ++ delete thread_names_; ++ thread_names_ = NULL; ++ name_count_ = 0; ++ ++ valid_ = false; ++ ++ uint32_t number_of_thread_names; ++ if (!minidump_->ReadBytes(&number_of_thread_names, sizeof(number_of_thread_names))) { ++ BPLOG(ERROR) << "MinidumpThreadNamesList could not read the number of thread names"; ++ return false; ++ } ++ ++ if (minidump_->swap()) { ++ Swap(&number_of_thread_names); ++ } ++ ++ if (expected_size != ++ sizeof(number_of_thread_names) + (sizeof(MDRawThreadName) * number_of_thread_names)) { ++ BPLOG(ERROR) << "MinidumpThreadNamesList expected_size mismatch " << ++ expected_size << " != " << sizeof(number_of_thread_names) << " + (" << ++ sizeof(MDRawThreadName) << " * " << number_of_thread_names << ")"; ++ return false; ++ } ++ ++ if (number_of_thread_names != 0) { ++ scoped_ptr thread_names( ++ new MinidumpThreadNames(number_of_thread_names, ++ MinidumpThreadName(minidump_))); ++ ++ for (unsigned int name_index = 0; ++ name_index < number_of_thread_names; ++ ++name_index) { ++ MinidumpThreadName* thread_name = &(*thread_names)[name_index]; ++ ++ if (!thread_name->Read(sizeof(MDRawThreadName))) { ++ BPLOG(ERROR) << "MinidumpThreadNamesList could not read name " << ++ name_index << "/" << number_of_thread_names; ++ return false; ++ } ++ } ++ ++ for (unsigned int name_index = 0; ++ name_index < number_of_thread_names; ++ ++name_index) { ++ MinidumpThreadName* thread_name = &(*thread_names)[name_index]; ++ ++ if (!thread_name->ReadAuxiliaryData()) { ++ BPLOG(ERROR) << "MinidumpThreadNamesList could not read required " ++ "auxiliary data for thread name " << ++ name_index << "/" << number_of_thread_names; ++ return false; ++ } ++ } ++ thread_names_ = thread_names.release(); ++ } ++ ++ name_count_ = number_of_thread_names; ++ valid_ = true; ++ return true; ++} ++ + static const char* get_stream_name(uint32_t stream_type) { + switch (stream_type) { + case MD_UNUSED_STREAM: + return "MD_UNUSED_STREAM"; + case MD_RESERVED_STREAM_0: + return "MD_RESERVED_STREAM_0"; + case MD_RESERVED_STREAM_1: + return "MD_RESERVED_STREAM_1"; +@@ -5772,16 +5982,20 @@ static const char* get_stream_name(uint3 + case MD_TOKEN_STREAM: + return "MD_TOKEN_STREAM"; + case MD_JAVASCRIPT_DATA_STREAM: + return "MD_JAVASCRIPT_DATA_STREAM"; + case MD_SYSTEM_MEMORY_INFO_STREAM: + return "MD_SYSTEM_MEMORY_INFO_STREAM"; + case MD_PROCESS_VM_COUNTERS_STREAM: + return "MD_PROCESS_VM_COUNTERS_STREAM"; ++ case MD_IPT_TRACE_STREAM: ++ return "MD_IPT_TRACE_STREAM"; ++ case MD_THREAD_NAMES_STREAM: ++ return "MD_THREAD_NAMES_STREAM"; + case MD_LAST_RESERVED_STREAM: + return "MD_LAST_RESERVED_STREAM"; + case MD_BREAKPAD_INFO_STREAM: + return "MD_BREAKPAD_INFO_STREAM"; + case MD_ASSERTION_INFO_STREAM: + return "MD_ASSERTION_INFO_STREAM"; + case MD_LINUX_CPU_INFO: + return "MD_LINUX_CPU_INFO"; +diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc +--- a/src/processor/minidump_dump.cc ++++ b/src/processor/minidump_dump.cc +@@ -49,16 +49,17 @@ using google_breakpad::MinidumpUnloadedM + using google_breakpad::MinidumpMemoryInfoList; + using google_breakpad::MinidumpMemoryList; + using google_breakpad::MinidumpException; + using google_breakpad::MinidumpAssertion; + using google_breakpad::MinidumpSystemInfo; + using google_breakpad::MinidumpMiscInfo; + using google_breakpad::MinidumpBreakpadInfo; + using google_breakpad::MinidumpCrashpadInfo; ++using google_breakpad::MinidumpThreadNamesList; + + struct Options { + Options() + : minidumpPath(), hexdump(false), hexdump_width(16) {} + + string minidumpPath; + bool hexdump; + unsigned int hexdump_width; +@@ -197,16 +198,21 @@ static bool PrintMinidumpDump(const Opti + } + + MinidumpCrashpadInfo *crashpad_info = minidump.GetCrashpadInfo(); + if (crashpad_info) { + // Crashpad info is optional, so don't treat absence as an error. + crashpad_info->Print(); + } + ++ MinidumpThreadNamesList *thread_names_list = minidump.GetThreadNamesList(); ++ if (thread_names_list) { ++ thread_names_list->Print(); ++ } ++ + DumpRawStream(&minidump, + MD_LINUX_CMD_LINE, + "MD_LINUX_CMD_LINE", + &errors); + DumpRawStream(&minidump, + MD_LINUX_ENVIRON, + "MD_LINUX_ENVIRON", + &errors); +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -173,16 +173,22 @@ ProcessResult MinidumpProcessor::Process + } + + MinidumpMemoryList *memory_list = dump->GetMemoryList(); + if (memory_list) { + BPLOG(INFO) << "Found " << memory_list->region_count() + << " memory regions."; + } + ++ MinidumpThreadNamesList* thread_names_list = dump->GetThreadNamesList(); ++ if (thread_names_list) { ++ BPLOG(INFO) << "Found " << thread_names_list->name_count() ++ << " thread names."; ++ } ++ + MinidumpThreadList *threads = dump->GetThreadList(); + if (!threads) { + BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list"; + return PROCESS_ERROR_NO_THREAD_LIST; + } + + BPLOG(INFO) << "Minidump " << dump->path() << " has " << + (has_cpu_info ? "" : "no ") << "CPU info, " << +@@ -308,16 +314,19 @@ ProcessResult MinidumpProcessor::Process + } else { + // Threads with missing CPU contexts will hit this, but + // don't abort processing the rest of the dump just for + // one bad thread. + BPLOG(ERROR) << "No stackwalker for " << thread_string; + } + stack->set_tid(thread_id); + stack->set_last_error(thread->GetLastError()); ++ if (thread_names_list) { ++ stack->set_name(thread_names_list->GetNameForThreadId(thread_id)); ++ } + process_state->threads_.push_back(stack.release()); + process_state->thread_memory_regions_.push_back(thread_memory); + } + + if (interrupted) { + BPLOG(INFO) << "Processing interrupted for " << dump->path(); + return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; + } +diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc +--- a/src/processor/stackwalk_common.cc ++++ b/src/processor/stackwalk_common.cc +@@ -876,35 +876,45 @@ void PrintProcessState(const ProcessStat + printf("\n"); + printf("Application-specific information:\n"); + printf("%s", process_state.mac_crash_info().c_str()); + } + + // If the thread that requested the dump is known, print it first. + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { +- printf("\n"); +- printf("Thread %d (%s)\n", +- requesting_thread, +- process_state.crashed() ? "crashed" : +- "requested dump, did not crash"); +- PrintStack(process_state.threads()->at(requesting_thread), cpu, ++ const CallStack* requesting_thread_callstack = ++ process_state.threads()->at(requesting_thread); ++ printf("\n" ++ "Thread %d (%s)", ++ requesting_thread, ++ process_state.crashed() ? "crashed" : ++ "requested dump, did not crash"); ++ if (!requesting_thread_callstack->name().empty()) { ++ printf(" - %s", requesting_thread_callstack->name().c_str()); ++ } ++ PrintStack(requesting_thread_callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(requesting_thread), + process_state.modules(), resolver); + } + + // Print all of the threads in the dump. + int thread_count = process_state.threads()->size(); + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. ++ const CallStack* callstack = process_state.threads()->at(thread_index); ++ printf("\n" ++ "Thread %d", thread_index); ++ if (!callstack->name().empty()) { ++ printf(" - %s", callstack->name().c_str()); ++ } + printf("\n"); +- printf("Thread %d\n", thread_index); +- PrintStack(process_state.threads()->at(thread_index), cpu, ++ PrintStack(callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(thread_index), + process_state.modules(), resolver); + } + } + + PrintModules(process_state.modules(), + process_state.modules_without_symbols(), diff --git a/toolkit/crashreporter/breakpad-patches/22-winerror-codes.patch b/toolkit/crashreporter/breakpad-patches/22-winerror-codes.patch new file mode 100644 index 0000000000..f0845366dc --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/22-winerror-codes.patch @@ -0,0 +1,22069 @@ +diff --git a/src/google_breakpad/common/minidump_exception_win32.h b/src/google_breakpad/common/minidump_exception_win32.h +--- a/src/google_breakpad/common/minidump_exception_win32.h ++++ b/src/google_breakpad/common/minidump_exception_win32.h +@@ -2925,9 +2925,2651 @@ typedef enum { + MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR = 58, + MD_FAST_FAIL_WIN_FLAGS_CORRUPTION = 59, + MD_FAST_FAIL_WIN_VEH_CORRUPTION = 60, + MD_FAST_FAIL_WIN_ETW_CORRUPTION = 61, + MD_FAST_FAIL_WIN_RIO_ABORT = 62, + MD_FAST_FAIL_WIN_INVALID_PFN = 63, + } MDFastFailWin; + ++/* For various (MDException).exception_information entries. This describes the ++* underlying reason for the crash. These values come from winerror.h. ++ * ++ * The content of this enum was created from winnt.h in the 10 SDK ++ * (version 10.0.19041.0) with ++ * ++ * egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h ++ * | tr -d '\r' ++ * | sed -r 's@#define ERROR_([A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' ++ * | sort -n ++ * | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_ERROR_WIN_\2 = \1,@' */ ++typedef enum { ++ MD_ERROR_WIN_SUCCESS = 0, ++ MD_ERROR_WIN_INVALID_FUNCTION = 1, ++ MD_ERROR_WIN_FILE_NOT_FOUND = 2, ++ MD_ERROR_WIN_PATH_NOT_FOUND = 3, ++ MD_ERROR_WIN_TOO_MANY_OPEN_FILES = 4, ++ MD_ERROR_WIN_ACCESS_DENIED = 5, ++ MD_ERROR_WIN_INVALID_HANDLE = 6, ++ MD_ERROR_WIN_ARENA_TRASHED = 7, ++ MD_ERROR_WIN_NOT_ENOUGH_MEMORY = 8, ++ MD_ERROR_WIN_INVALID_BLOCK = 9, ++ MD_ERROR_WIN_BAD_ENVIRONMENT = 10, ++ MD_ERROR_WIN_BAD_FORMAT = 11, ++ MD_ERROR_WIN_INVALID_ACCESS = 12, ++ MD_ERROR_WIN_INVALID_DATA = 13, ++ MD_ERROR_WIN_OUTOFMEMORY = 14, ++ MD_ERROR_WIN_INVALID_DRIVE = 15, ++ MD_ERROR_WIN_CURRENT_DIRECTORY = 16, ++ MD_ERROR_WIN_NOT_SAME_DEVICE = 17, ++ MD_ERROR_WIN_NO_MORE_FILES = 18, ++ MD_ERROR_WIN_WRITE_PROTECT = 19, ++ MD_ERROR_WIN_BAD_UNIT = 20, ++ MD_ERROR_WIN_NOT_READY = 21, ++ MD_ERROR_WIN_BAD_COMMAND = 22, ++ MD_ERROR_WIN_CRC = 23, ++ MD_ERROR_WIN_BAD_LENGTH = 24, ++ MD_ERROR_WIN_SEEK = 25, ++ MD_ERROR_WIN_NOT_DOS_DISK = 26, ++ MD_ERROR_WIN_SECTOR_NOT_FOUND = 27, ++ MD_ERROR_WIN_OUT_OF_PAPER = 28, ++ MD_ERROR_WIN_WRITE_FAULT = 29, ++ MD_ERROR_WIN_READ_FAULT = 30, ++ MD_ERROR_WIN_GEN_FAILURE = 31, ++ MD_ERROR_WIN_SHARING_VIOLATION = 32, ++ MD_ERROR_WIN_LOCK_VIOLATION = 33, ++ MD_ERROR_WIN_WRONG_DISK = 34, ++ MD_ERROR_WIN_SHARING_BUFFER_EXCEEDED = 36, ++ MD_ERROR_WIN_HANDLE_EOF = 38, ++ MD_ERROR_WIN_HANDLE_DISK_FULL = 39, ++ MD_ERROR_WIN_NOT_SUPPORTED = 50, ++ MD_ERROR_WIN_REM_NOT_LIST = 51, ++ MD_ERROR_WIN_DUP_NAME = 52, ++ MD_ERROR_WIN_BAD_NETPATH = 53, ++ MD_ERROR_WIN_NETWORK_BUSY = 54, ++ MD_ERROR_WIN_DEV_NOT_EXIST = 55, ++ MD_ERROR_WIN_TOO_MANY_CMDS = 56, ++ MD_ERROR_WIN_ADAP_HDW_ERR = 57, ++ MD_ERROR_WIN_BAD_NET_RESP = 58, ++ MD_ERROR_WIN_UNEXP_NET_ERR = 59, ++ MD_ERROR_WIN_BAD_REM_ADAP = 60, ++ MD_ERROR_WIN_PRINTQ_FULL = 61, ++ MD_ERROR_WIN_NO_SPOOL_SPACE = 62, ++ MD_ERROR_WIN_PRINT_CANCELLED = 63, ++ MD_ERROR_WIN_NETNAME_DELETED = 64, ++ MD_ERROR_WIN_NETWORK_ACCESS_DENIED = 65, ++ MD_ERROR_WIN_BAD_DEV_TYPE = 66, ++ MD_ERROR_WIN_BAD_NET_NAME = 67, ++ MD_ERROR_WIN_TOO_MANY_NAMES = 68, ++ MD_ERROR_WIN_TOO_MANY_SESS = 69, ++ MD_ERROR_WIN_SHARING_PAUSED = 70, ++ MD_ERROR_WIN_REQ_NOT_ACCEP = 71, ++ MD_ERROR_WIN_REDIR_PAUSED = 72, ++ MD_ERROR_WIN_FILE_EXISTS = 80, ++ MD_ERROR_WIN_CANNOT_MAKE = 82, ++ MD_ERROR_WIN_FAIL_I24 = 83, ++ MD_ERROR_WIN_OUT_OF_STRUCTURES = 84, ++ MD_ERROR_WIN_ALREADY_ASSIGNED = 85, ++ MD_ERROR_WIN_INVALID_PASSWORD = 86, ++ MD_ERROR_WIN_INVALID_PARAMETER = 87, ++ MD_ERROR_WIN_NET_WRITE_FAULT = 88, ++ MD_ERROR_WIN_NO_PROC_SLOTS = 89, ++ MD_ERROR_WIN_TOO_MANY_SEMAPHORES = 100, ++ MD_ERROR_WIN_EXCL_SEM_ALREADY_OWNED = 101, ++ MD_ERROR_WIN_SEM_IS_SET = 102, ++ MD_ERROR_WIN_TOO_MANY_SEM_REQUESTS = 103, ++ MD_ERROR_WIN_INVALID_AT_INTERRUPT_TIME = 104, ++ MD_ERROR_WIN_SEM_OWNER_DIED = 105, ++ MD_ERROR_WIN_SEM_USER_LIMIT = 106, ++ MD_ERROR_WIN_DISK_CHANGE = 107, ++ MD_ERROR_WIN_DRIVE_LOCKED = 108, ++ MD_ERROR_WIN_BROKEN_PIPE = 109, ++ MD_ERROR_WIN_OPEN_FAILED = 110, ++ MD_ERROR_WIN_BUFFER_OVERFLOW = 111, ++ MD_ERROR_WIN_DISK_FULL = 112, ++ MD_ERROR_WIN_NO_MORE_SEARCH_HANDLES = 113, ++ MD_ERROR_WIN_INVALID_TARGET_HANDLE = 114, ++ MD_ERROR_WIN_INVALID_CATEGORY = 117, ++ MD_ERROR_WIN_INVALID_VERIFY_SWITCH = 118, ++ MD_ERROR_WIN_BAD_DRIVER_LEVEL = 119, ++ MD_ERROR_WIN_CALL_NOT_IMPLEMENTED = 120, ++ MD_ERROR_WIN_SEM_TIMEOUT = 121, ++ MD_ERROR_WIN_INSUFFICIENT_BUFFER = 122, ++ MD_ERROR_WIN_INVALID_NAME = 123, ++ MD_ERROR_WIN_INVALID_LEVEL = 124, ++ MD_ERROR_WIN_NO_VOLUME_LABEL = 125, ++ MD_ERROR_WIN_MOD_NOT_FOUND = 126, ++ MD_ERROR_WIN_PROC_NOT_FOUND = 127, ++ MD_ERROR_WIN_WAIT_NO_CHILDREN = 128, ++ MD_ERROR_WIN_CHILD_NOT_COMPLETE = 129, ++ MD_ERROR_WIN_DIRECT_ACCESS_HANDLE = 130, ++ MD_ERROR_WIN_NEGATIVE_SEEK = 131, ++ MD_ERROR_WIN_SEEK_ON_DEVICE = 132, ++ MD_ERROR_WIN_IS_JOIN_TARGET = 133, ++ MD_ERROR_WIN_IS_JOINED = 134, ++ MD_ERROR_WIN_IS_SUBSTED = 135, ++ MD_ERROR_WIN_NOT_JOINED = 136, ++ MD_ERROR_WIN_NOT_SUBSTED = 137, ++ MD_ERROR_WIN_JOIN_TO_JOIN = 138, ++ MD_ERROR_WIN_SUBST_TO_SUBST = 139, ++ MD_ERROR_WIN_JOIN_TO_SUBST = 140, ++ MD_ERROR_WIN_SUBST_TO_JOIN = 141, ++ MD_ERROR_WIN_BUSY_DRIVE = 142, ++ MD_ERROR_WIN_SAME_DRIVE = 143, ++ MD_ERROR_WIN_DIR_NOT_ROOT = 144, ++ MD_ERROR_WIN_DIR_NOT_EMPTY = 145, ++ MD_ERROR_WIN_IS_SUBST_PATH = 146, ++ MD_ERROR_WIN_IS_JOIN_PATH = 147, ++ MD_ERROR_WIN_PATH_BUSY = 148, ++ MD_ERROR_WIN_IS_SUBST_TARGET = 149, ++ MD_ERROR_WIN_SYSTEM_TRACE = 150, ++ MD_ERROR_WIN_INVALID_EVENT_COUNT = 151, ++ MD_ERROR_WIN_TOO_MANY_MUXWAITERS = 152, ++ MD_ERROR_WIN_INVALID_LIST_FORMAT = 153, ++ MD_ERROR_WIN_LABEL_TOO_LONG = 154, ++ MD_ERROR_WIN_TOO_MANY_TCBS = 155, ++ MD_ERROR_WIN_SIGNAL_REFUSED = 156, ++ MD_ERROR_WIN_DISCARDED = 157, ++ MD_ERROR_WIN_NOT_LOCKED = 158, ++ MD_ERROR_WIN_BAD_THREADID_ADDR = 159, ++ MD_ERROR_WIN_BAD_ARGUMENTS = 160, ++ MD_ERROR_WIN_BAD_PATHNAME = 161, ++ MD_ERROR_WIN_SIGNAL_PENDING = 162, ++ MD_ERROR_WIN_MAX_THRDS_REACHED = 164, ++ MD_ERROR_WIN_LOCK_FAILED = 167, ++ MD_ERROR_WIN_BUSY = 170, ++ MD_ERROR_WIN_DEVICE_SUPPORT_IN_PROGRESS = 171, ++ MD_ERROR_WIN_CANCEL_VIOLATION = 173, ++ MD_ERROR_WIN_ATOMIC_LOCKS_NOT_SUPPORTED = 174, ++ MD_ERROR_WIN_INVALID_SEGMENT_NUMBER = 180, ++ MD_ERROR_WIN_INVALID_ORDINAL = 182, ++ MD_ERROR_WIN_ALREADY_EXISTS = 183, ++ MD_ERROR_WIN_INVALID_FLAG_NUMBER = 186, ++ MD_ERROR_WIN_SEM_NOT_FOUND = 187, ++ MD_ERROR_WIN_INVALID_STARTING_CODESEG = 188, ++ MD_ERROR_WIN_INVALID_STACKSEG = 189, ++ MD_ERROR_WIN_INVALID_MODULETYPE = 190, ++ MD_ERROR_WIN_INVALID_EXE_SIGNATURE = 191, ++ MD_ERROR_WIN_EXE_MARKED_INVALID = 192, ++ MD_ERROR_WIN_BAD_EXE_FORMAT = 193, ++ MD_ERROR_WIN_INVALID_MINALLOCSIZE = 195, ++ MD_ERROR_WIN_DYNLINK_FROM_INVALID_RING = 196, ++ MD_ERROR_WIN_IOPL_NOT_ENABLED = 197, ++ MD_ERROR_WIN_INVALID_SEGDPL = 198, ++ MD_ERROR_WIN_RING2SEG_MUST_BE_MOVABLE = 200, ++ MD_ERROR_WIN_RELOC_CHAIN_XEEDS_SEGLIM = 201, ++ MD_ERROR_WIN_INFLOOP_IN_RELOC_CHAIN = 202, ++ MD_ERROR_WIN_ENVVAR_NOT_FOUND = 203, ++ MD_ERROR_WIN_NO_SIGNAL_SENT = 205, ++ MD_ERROR_WIN_FILENAME_EXCED_RANGE = 206, ++ MD_ERROR_WIN_RING2_STACK_IN_USE = 207, ++ MD_ERROR_WIN_META_EXPANSION_TOO_LONG = 208, ++ MD_ERROR_WIN_INVALID_SIGNAL_NUMBER = 209, ++ MD_ERROR_WIN_THREAD_1_INACTIVE = 210, ++ MD_ERROR_WIN_LOCKED = 212, ++ MD_ERROR_WIN_TOO_MANY_MODULES = 214, ++ MD_ERROR_WIN_NESTING_NOT_ALLOWED = 215, ++ MD_ERROR_WIN_EXE_MACHINE_TYPE_MISMATCH = 216, ++ MD_ERROR_WIN_EXE_CANNOT_MODIFY_SIGNED_BINARY = 217, ++ MD_ERROR_WIN_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 218, ++ MD_ERROR_WIN_FILE_CHECKED_OUT = 220, ++ MD_ERROR_WIN_CHECKOUT_REQUIRED = 221, ++ MD_ERROR_WIN_BAD_FILE_TYPE = 222, ++ MD_ERROR_WIN_FILE_TOO_LARGE = 223, ++ MD_ERROR_WIN_FORMS_AUTH_REQUIRED = 224, ++ MD_ERROR_WIN_VIRUS_INFECTED = 225, ++ MD_ERROR_WIN_VIRUS_DELETED = 226, ++ MD_ERROR_WIN_PIPE_LOCAL = 229, ++ MD_ERROR_WIN_BAD_PIPE = 230, ++ MD_ERROR_WIN_PIPE_BUSY = 231, ++ MD_ERROR_WIN_NO_DATA = 232, ++ MD_ERROR_WIN_PIPE_NOT_CONNECTED = 233, ++ MD_ERROR_WIN_MORE_DATA = 234, ++ MD_ERROR_WIN_NO_WORK_DONE = 235, ++ MD_ERROR_WIN_VC_DISCONNECTED = 240, ++ MD_ERROR_WIN_INVALID_EA_NAME = 254, ++ MD_ERROR_WIN_EA_LIST_INCONSISTENT = 255, ++ MD_ERROR_WIN_NO_MORE_ITEMS = 259, ++ MD_ERROR_WIN_CANNOT_COPY = 266, ++ MD_ERROR_WIN_DIRECTORY = 267, ++ MD_ERROR_WIN_EAS_DIDNT_FIT = 275, ++ MD_ERROR_WIN_EA_FILE_CORRUPT = 276, ++ MD_ERROR_WIN_EA_TABLE_FULL = 277, ++ MD_ERROR_WIN_INVALID_EA_HANDLE = 278, ++ MD_ERROR_WIN_EAS_NOT_SUPPORTED = 282, ++ MD_ERROR_WIN_NOT_OWNER = 288, ++ MD_ERROR_WIN_TOO_MANY_POSTS = 298, ++ MD_ERROR_WIN_PARTIAL_COPY = 299, ++ MD_ERROR_WIN_OPLOCK_NOT_GRANTED = 300, ++ MD_ERROR_WIN_INVALID_OPLOCK_PROTOCOL = 301, ++ MD_ERROR_WIN_DISK_TOO_FRAGMENTED = 302, ++ MD_ERROR_WIN_DELETE_PENDING = 303, ++ MD_ERROR_WIN_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 304, ++ MD_ERROR_WIN_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 305, ++ MD_ERROR_WIN_SECURITY_STREAM_IS_INCONSISTENT = 306, ++ MD_ERROR_WIN_INVALID_LOCK_RANGE = 307, ++ MD_ERROR_WIN_IMAGE_SUBSYSTEM_NOT_PRESENT = 308, ++ MD_ERROR_WIN_NOTIFICATION_GUID_ALREADY_DEFINED = 309, ++ MD_ERROR_WIN_INVALID_EXCEPTION_HANDLER = 310, ++ MD_ERROR_WIN_DUPLICATE_PRIVILEGES = 311, ++ MD_ERROR_WIN_NO_RANGES_PROCESSED = 312, ++ MD_ERROR_WIN_NOT_ALLOWED_ON_SYSTEM_FILE = 313, ++ MD_ERROR_WIN_DISK_RESOURCES_EXHAUSTED = 314, ++ MD_ERROR_WIN_INVALID_TOKEN = 315, ++ MD_ERROR_WIN_DEVICE_FEATURE_NOT_SUPPORTED = 316, ++ MD_ERROR_WIN_MR_MID_NOT_FOUND = 317, ++ MD_ERROR_WIN_SCOPE_NOT_FOUND = 318, ++ MD_ERROR_WIN_UNDEFINED_SCOPE = 319, ++ MD_ERROR_WIN_INVALID_CAP = 320, ++ MD_ERROR_WIN_DEVICE_UNREACHABLE = 321, ++ MD_ERROR_WIN_DEVICE_NO_RESOURCES = 322, ++ MD_ERROR_WIN_DATA_CHECKSUM_ERROR = 323, ++ MD_ERROR_WIN_INTERMIXED_KERNEL_EA_OPERATION = 324, ++ MD_ERROR_WIN_FILE_LEVEL_TRIM_NOT_SUPPORTED = 326, ++ MD_ERROR_WIN_OFFSET_ALIGNMENT_VIOLATION = 327, ++ MD_ERROR_WIN_INVALID_FIELD_IN_PARAMETER_LIST = 328, ++ MD_ERROR_WIN_OPERATION_IN_PROGRESS = 329, ++ MD_ERROR_WIN_BAD_DEVICE_PATH = 330, ++ MD_ERROR_WIN_TOO_MANY_DESCRIPTORS = 331, ++ MD_ERROR_WIN_SCRUB_DATA_DISABLED = 332, ++ MD_ERROR_WIN_NOT_REDUNDANT_STORAGE = 333, ++ MD_ERROR_WIN_RESIDENT_FILE_NOT_SUPPORTED = 334, ++ MD_ERROR_WIN_COMPRESSED_FILE_NOT_SUPPORTED = 335, ++ MD_ERROR_WIN_DIRECTORY_NOT_SUPPORTED = 336, ++ MD_ERROR_WIN_NOT_READ_FROM_COPY = 337, ++ MD_ERROR_WIN_FT_WRITE_FAILURE = 338, ++ MD_ERROR_WIN_FT_DI_SCAN_REQUIRED = 339, ++ MD_ERROR_WIN_INVALID_KERNEL_INFO_VERSION = 340, ++ MD_ERROR_WIN_INVALID_PEP_INFO_VERSION = 341, ++ MD_ERROR_WIN_OBJECT_NOT_EXTERNALLY_BACKED = 342, ++ MD_ERROR_WIN_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 343, ++ MD_ERROR_WIN_COMPRESSION_NOT_BENEFICIAL = 344, ++ MD_ERROR_WIN_STORAGE_TOPOLOGY_ID_MISMATCH = 345, ++ MD_ERROR_WIN_BLOCKED_BY_PARENTAL_CONTROLS = 346, ++ MD_ERROR_WIN_BLOCK_TOO_MANY_REFERENCES = 347, ++ MD_ERROR_WIN_MARKED_TO_DISALLOW_WRITES = 348, ++ MD_ERROR_WIN_ENCLAVE_FAILURE = 349, ++ MD_ERROR_WIN_FAIL_NOACTION_REBOOT = 350, ++ MD_ERROR_WIN_FAIL_SHUTDOWN = 351, ++ MD_ERROR_WIN_FAIL_RESTART = 352, ++ MD_ERROR_WIN_MAX_SESSIONS_REACHED = 353, ++ MD_ERROR_WIN_NETWORK_ACCESS_DENIED_EDP = 354, ++ MD_ERROR_WIN_DEVICE_HINT_NAME_BUFFER_TOO_SMALL = 355, ++ MD_ERROR_WIN_EDP_POLICY_DENIES_OPERATION = 356, ++ MD_ERROR_WIN_EDP_DPL_POLICY_CANT_BE_SATISFIED = 357, ++ MD_ERROR_WIN_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT = 358, ++ MD_ERROR_WIN_DEVICE_IN_MAINTENANCE = 359, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_DAX = 360, ++ MD_ERROR_WIN_DAX_MAPPING_EXISTS = 361, ++ MD_ERROR_WIN_CLOUD_FILE_PROVIDER_NOT_RUNNING = 362, ++ MD_ERROR_WIN_CLOUD_FILE_METADATA_CORRUPT = 363, ++ MD_ERROR_WIN_CLOUD_FILE_METADATA_TOO_LARGE = 364, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE = 365, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH = 366, ++ MD_ERROR_WIN_CHILD_PROCESS_BLOCKED = 367, ++ MD_ERROR_WIN_STORAGE_LOST_DATA_PERSISTENCE = 368, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE = 369, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT = 370, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_BUSY = 371, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN = 372, ++ MD_ERROR_WIN_GDI_HANDLE_LEAK = 373, ++ MD_ERROR_WIN_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS = 374, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED = 375, ++ MD_ERROR_WIN_NOT_A_CLOUD_FILE = 376, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_IN_SYNC = 377, ++ MD_ERROR_WIN_CLOUD_FILE_ALREADY_CONNECTED = 378, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_SUPPORTED = 379, ++ MD_ERROR_WIN_CLOUD_FILE_INVALID_REQUEST = 380, ++ MD_ERROR_WIN_CLOUD_FILE_READ_ONLY_VOLUME = 381, ++ MD_ERROR_WIN_CLOUD_FILE_CONNECTED_PROVIDER_ONLY = 382, ++ MD_ERROR_WIN_CLOUD_FILE_VALIDATION_FAILED = 383, ++ MD_ERROR_WIN_SMB1_NOT_AVAILABLE = 384, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION = 385, ++ MD_ERROR_WIN_CLOUD_FILE_AUTHENTICATION_FAILED = 386, ++ MD_ERROR_WIN_CLOUD_FILE_INSUFFICIENT_RESOURCES = 387, ++ MD_ERROR_WIN_CLOUD_FILE_NETWORK_UNAVAILABLE = 388, ++ MD_ERROR_WIN_CLOUD_FILE_UNSUCCESSFUL = 389, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_UNDER_SYNC_ROOT = 390, ++ MD_ERROR_WIN_CLOUD_FILE_IN_USE = 391, ++ MD_ERROR_WIN_CLOUD_FILE_PINNED = 392, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_ABORTED = 393, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_CORRUPT = 394, ++ MD_ERROR_WIN_CLOUD_FILE_ACCESS_DENIED = 395, ++ MD_ERROR_WIN_CLOUD_FILE_INCOMPATIBLE_HARDLINKS = 396, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_LOCK_CONFLICT = 397, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_CANCELED = 398, ++ MD_ERROR_WIN_EXTERNAL_SYSKEY_NOT_SUPPORTED = 399, ++ MD_ERROR_WIN_THREAD_MODE_ALREADY_BACKGROUND = 400, ++ MD_ERROR_WIN_THREAD_MODE_NOT_BACKGROUND = 401, ++ MD_ERROR_WIN_PROCESS_MODE_ALREADY_BACKGROUND = 402, ++ MD_ERROR_WIN_PROCESS_MODE_NOT_BACKGROUND = 403, ++ MD_ERROR_WIN_CLOUD_FILE_PROVIDER_TERMINATED = 404, ++ MD_ERROR_WIN_NOT_A_CLOUD_SYNC_ROOT = 405, ++ MD_ERROR_WIN_FILE_PROTECTED_UNDER_DPL = 406, ++ MD_ERROR_WIN_VOLUME_NOT_CLUSTER_ALIGNED = 407, ++ MD_ERROR_WIN_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND = 408, ++ MD_ERROR_WIN_APPX_FILE_NOT_ENCRYPTED = 409, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED = 410, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET = 411, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE = 412, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER = 413, ++ MD_ERROR_WIN_LINUX_SUBSYSTEM_NOT_PRESENT = 414, ++ MD_ERROR_WIN_FT_READ_FAILURE = 415, ++ MD_ERROR_WIN_STORAGE_RESERVE_ID_INVALID = 416, ++ MD_ERROR_WIN_STORAGE_RESERVE_DOES_NOT_EXIST = 417, ++ MD_ERROR_WIN_STORAGE_RESERVE_ALREADY_EXISTS = 418, ++ MD_ERROR_WIN_STORAGE_RESERVE_NOT_EMPTY = 419, ++ MD_ERROR_WIN_NOT_A_DAX_VOLUME = 420, ++ MD_ERROR_WIN_NOT_DAX_MAPPABLE = 421, ++ MD_ERROR_WIN_TIME_SENSITIVE_THREAD = 422, ++ MD_ERROR_WIN_DPL_NOT_SUPPORTED_FOR_USER = 423, ++ MD_ERROR_WIN_CASE_DIFFERING_NAMES_IN_DIR = 424, ++ MD_ERROR_WIN_FILE_NOT_SUPPORTED = 425, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_TIMEOUT = 426, ++ MD_ERROR_WIN_NO_TASK_QUEUE = 427, ++ MD_ERROR_WIN_SRC_SRV_DLL_LOAD_FAILED = 428, ++ MD_ERROR_WIN_NOT_SUPPORTED_WITH_BTT = 429, ++ MD_ERROR_WIN_ENCRYPTION_DISABLED = 430, ++ MD_ERROR_WIN_ENCRYPTING_METADATA_DISALLOWED = 431, ++ MD_ERROR_WIN_CANT_CLEAR_ENCRYPTION_FLAG = 432, ++ MD_ERROR_WIN_NO_SUCH_DEVICE = 433, ++ MD_ERROR_WIN_CLOUD_FILE_DEHYDRATION_DISALLOWED = 434, ++ MD_ERROR_WIN_FILE_SNAP_IN_PROGRESS = 435, ++ MD_ERROR_WIN_FILE_SNAP_USER_SECTION_NOT_SUPPORTED = 436, ++ MD_ERROR_WIN_FILE_SNAP_MODIFY_NOT_SUPPORTED = 437, ++ MD_ERROR_WIN_FILE_SNAP_IO_NOT_COORDINATED = 438, ++ MD_ERROR_WIN_FILE_SNAP_UNEXPECTED_ERROR = 439, ++ MD_ERROR_WIN_FILE_SNAP_INVALID_PARAMETER = 440, ++ MD_ERROR_WIN_UNSATISFIED_DEPENDENCIES = 441, ++ MD_ERROR_WIN_CASE_SENSITIVE_PATH = 442, ++ MD_ERROR_WIN_UNEXPECTED_NTCACHEMANAGER_ERROR = 443, ++ MD_ERROR_WIN_LINUX_SUBSYSTEM_UPDATE_REQUIRED = 444, ++ MD_ERROR_WIN_DLP_POLICY_WARNS_AGAINST_OPERATION = 445, ++ MD_ERROR_WIN_DLP_POLICY_DENIES_OPERATION = 446, ++ MD_ERROR_WIN_DLP_POLICY_SILENTLY_FAIL = 449, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_DEVUNLOCKED = 450, ++ MD_ERROR_WIN_CAPAUTHZ_CHANGE_TYPE = 451, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_PROVISIONED = 452, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_AUTHORIZED = 453, ++ MD_ERROR_WIN_CAPAUTHZ_NO_POLICY = 454, ++ MD_ERROR_WIN_CAPAUTHZ_DB_CORRUPTED = 455, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_INVALID_CATALOG = 456, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_AUTH_ENTITY = 457, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_PARSE_ERROR = 458, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED = 459, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH = 460, ++ MD_ERROR_WIN_CIMFS_IMAGE_CORRUPT = 470, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_DEVICE_TIMEOUT = 480, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT = 481, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT = 482, ++ MD_ERROR_WIN_DEVICE_HARDWARE_ERROR = 483, ++ MD_ERROR_WIN_INVALID_ADDRESS = 487, ++ MD_ERROR_WIN_HAS_SYSTEM_CRITICAL_FILES = 488, ++ MD_ERROR_WIN_USER_PROFILE_LOAD = 500, ++ MD_ERROR_WIN_ARITHMETIC_OVERFLOW = 534, ++ MD_ERROR_WIN_PIPE_CONNECTED = 535, ++ MD_ERROR_WIN_PIPE_LISTENING = 536, ++ MD_ERROR_WIN_VERIFIER_STOP = 537, ++ MD_ERROR_WIN_ABIOS_ERROR = 538, ++ MD_ERROR_WIN_WX86_WARNING = 539, ++ MD_ERROR_WIN_WX86_ERROR = 540, ++ MD_ERROR_WIN_TIMER_NOT_CANCELED = 541, ++ MD_ERROR_WIN_UNWIND = 542, ++ MD_ERROR_WIN_BAD_STACK = 543, ++ MD_ERROR_WIN_INVALID_UNWIND_TARGET = 544, ++ MD_ERROR_WIN_INVALID_PORT_ATTRIBUTES = 545, ++ MD_ERROR_WIN_PORT_MESSAGE_TOO_LONG = 546, ++ MD_ERROR_WIN_INVALID_QUOTA_LOWER = 547, ++ MD_ERROR_WIN_DEVICE_ALREADY_ATTACHED = 548, ++ MD_ERROR_WIN_INSTRUCTION_MISALIGNMENT = 549, ++ MD_ERROR_WIN_PROFILING_NOT_STARTED = 550, ++ MD_ERROR_WIN_PROFILING_NOT_STOPPED = 551, ++ MD_ERROR_WIN_COULD_NOT_INTERPRET = 552, ++ MD_ERROR_WIN_PROFILING_AT_LIMIT = 553, ++ MD_ERROR_WIN_CANT_WAIT = 554, ++ MD_ERROR_WIN_CANT_TERMINATE_SELF = 555, ++ MD_ERROR_WIN_UNEXPECTED_MM_CREATE_ERR = 556, ++ MD_ERROR_WIN_UNEXPECTED_MM_MAP_ERROR = 557, ++ MD_ERROR_WIN_UNEXPECTED_MM_EXTEND_ERR = 558, ++ MD_ERROR_WIN_BAD_FUNCTION_TABLE = 559, ++ MD_ERROR_WIN_NO_GUID_TRANSLATION = 560, ++ MD_ERROR_WIN_INVALID_LDT_SIZE = 561, ++ MD_ERROR_WIN_INVALID_LDT_OFFSET = 563, ++ MD_ERROR_WIN_INVALID_LDT_DESCRIPTOR = 564, ++ MD_ERROR_WIN_TOO_MANY_THREADS = 565, ++ MD_ERROR_WIN_THREAD_NOT_IN_PROCESS = 566, ++ MD_ERROR_WIN_PAGEFILE_QUOTA_EXCEEDED = 567, ++ MD_ERROR_WIN_LOGON_SERVER_CONFLICT = 568, ++ MD_ERROR_WIN_SYNCHRONIZATION_REQUIRED = 569, ++ MD_ERROR_WIN_NET_OPEN_FAILED = 570, ++ MD_ERROR_WIN_IO_PRIVILEGE_FAILED = 571, ++ MD_ERROR_WIN_CONTROL_C_EXIT = 572, ++ MD_ERROR_WIN_MISSING_SYSTEMFILE = 573, ++ MD_ERROR_WIN_UNHANDLED_EXCEPTION = 574, ++ MD_ERROR_WIN_APP_INIT_FAILURE = 575, ++ MD_ERROR_WIN_PAGEFILE_CREATE_FAILED = 576, ++ MD_ERROR_WIN_INVALID_IMAGE_HASH = 577, ++ MD_ERROR_WIN_NO_PAGEFILE = 578, ++ MD_ERROR_WIN_ILLEGAL_FLOAT_CONTEXT = 579, ++ MD_ERROR_WIN_NO_EVENT_PAIR = 580, ++ MD_ERROR_WIN_DOMAIN_CTRLR_CONFIG_ERROR = 581, ++ MD_ERROR_WIN_ILLEGAL_CHARACTER = 582, ++ MD_ERROR_WIN_UNDEFINED_CHARACTER = 583, ++ MD_ERROR_WIN_FLOPPY_VOLUME = 584, ++ MD_ERROR_WIN_BIOS_FAILED_TO_CONNECT_INTERRUPT = 585, ++ MD_ERROR_WIN_BACKUP_CONTROLLER = 586, ++ MD_ERROR_WIN_MUTANT_LIMIT_EXCEEDED = 587, ++ MD_ERROR_WIN_FS_DRIVER_REQUIRED = 588, ++ MD_ERROR_WIN_CANNOT_LOAD_REGISTRY_FILE = 589, ++ MD_ERROR_WIN_DEBUG_ATTACH_FAILED = 590, ++ MD_ERROR_WIN_SYSTEM_PROCESS_TERMINATED = 591, ++ MD_ERROR_WIN_DATA_NOT_ACCEPTED = 592, ++ MD_ERROR_WIN_VDM_HARD_ERROR = 593, ++ MD_ERROR_WIN_DRIVER_CANCEL_TIMEOUT = 594, ++ MD_ERROR_WIN_REPLY_MESSAGE_MISMATCH = 595, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA = 596, ++ MD_ERROR_WIN_CLIENT_SERVER_PARAMETERS_INVALID = 597, ++ MD_ERROR_WIN_NOT_TINY_STREAM = 598, ++ MD_ERROR_WIN_STACK_OVERFLOW_READ = 599, ++ MD_ERROR_WIN_CONVERT_TO_LARGE = 600, ++ MD_ERROR_WIN_FOUND_OUT_OF_SCOPE = 601, ++ MD_ERROR_WIN_ALLOCATE_BUCKET = 602, ++ MD_ERROR_WIN_MARSHALL_OVERFLOW = 603, ++ MD_ERROR_WIN_INVALID_VARIANT = 604, ++ MD_ERROR_WIN_BAD_COMPRESSION_BUFFER = 605, ++ MD_ERROR_WIN_AUDIT_FAILED = 606, ++ MD_ERROR_WIN_TIMER_RESOLUTION_NOT_SET = 607, ++ MD_ERROR_WIN_INSUFFICIENT_LOGON_INFO = 608, ++ MD_ERROR_WIN_BAD_DLL_ENTRYPOINT = 609, ++ MD_ERROR_WIN_BAD_SERVICE_ENTRYPOINT = 610, ++ MD_ERROR_WIN_IP_ADDRESS_CONFLICT1 = 611, ++ MD_ERROR_WIN_IP_ADDRESS_CONFLICT2 = 612, ++ MD_ERROR_WIN_REGISTRY_QUOTA_LIMIT = 613, ++ MD_ERROR_WIN_NO_CALLBACK_ACTIVE = 614, ++ MD_ERROR_WIN_PWD_TOO_SHORT = 615, ++ MD_ERROR_WIN_PWD_TOO_RECENT = 616, ++ MD_ERROR_WIN_PWD_HISTORY_CONFLICT = 617, ++ MD_ERROR_WIN_UNSUPPORTED_COMPRESSION = 618, ++ MD_ERROR_WIN_INVALID_HW_PROFILE = 619, ++ MD_ERROR_WIN_INVALID_PLUGPLAY_DEVICE_PATH = 620, ++ MD_ERROR_WIN_QUOTA_LIST_INCONSISTENT = 621, ++ MD_ERROR_WIN_EVALUATION_EXPIRATION = 622, ++ MD_ERROR_WIN_ILLEGAL_DLL_RELOCATION = 623, ++ MD_ERROR_WIN_DLL_INIT_FAILED_LOGOFF = 624, ++ MD_ERROR_WIN_VALIDATE_CONTINUE = 625, ++ MD_ERROR_WIN_NO_MORE_MATCHES = 626, ++ MD_ERROR_WIN_RANGE_LIST_CONFLICT = 627, ++ MD_ERROR_WIN_SERVER_SID_MISMATCH = 628, ++ MD_ERROR_WIN_CANT_ENABLE_DENY_ONLY = 629, ++ MD_ERROR_WIN_FLOAT_MULTIPLE_FAULTS = 630, ++ MD_ERROR_WIN_FLOAT_MULTIPLE_TRAPS = 631, ++ MD_ERROR_WIN_NOINTERFACE = 632, ++ MD_ERROR_WIN_DRIVER_FAILED_SLEEP = 633, ++ MD_ERROR_WIN_CORRUPT_SYSTEM_FILE = 634, ++ MD_ERROR_WIN_COMMITMENT_MINIMUM = 635, ++ MD_ERROR_WIN_PNP_RESTART_ENUMERATION = 636, ++ MD_ERROR_WIN_SYSTEM_IMAGE_BAD_SIGNATURE = 637, ++ MD_ERROR_WIN_PNP_REBOOT_REQUIRED = 638, ++ MD_ERROR_WIN_INSUFFICIENT_POWER = 639, ++ MD_ERROR_WIN_MULTIPLE_FAULT_VIOLATION = 640, ++ MD_ERROR_WIN_SYSTEM_SHUTDOWN = 641, ++ MD_ERROR_WIN_PORT_NOT_SET = 642, ++ MD_ERROR_WIN_DS_VERSION_CHECK_FAILURE = 643, ++ MD_ERROR_WIN_RANGE_NOT_FOUND = 644, ++ MD_ERROR_WIN_NOT_SAFE_MODE_DRIVER = 646, ++ MD_ERROR_WIN_FAILED_DRIVER_ENTRY = 647, ++ MD_ERROR_WIN_DEVICE_ENUMERATION_ERROR = 648, ++ MD_ERROR_WIN_MOUNT_POINT_NOT_RESOLVED = 649, ++ MD_ERROR_WIN_INVALID_DEVICE_OBJECT_PARAMETER = 650, ++ MD_ERROR_WIN_MCA_OCCURED = 651, ++ MD_ERROR_WIN_DRIVER_DATABASE_ERROR = 652, ++ MD_ERROR_WIN_SYSTEM_HIVE_TOO_LARGE = 653, ++ MD_ERROR_WIN_DRIVER_FAILED_PRIOR_UNLOAD = 654, ++ MD_ERROR_WIN_VOLSNAP_PREPARE_HIBERNATE = 655, ++ MD_ERROR_WIN_HIBERNATION_FAILURE = 656, ++ MD_ERROR_WIN_PWD_TOO_LONG = 657, ++ MD_ERROR_WIN_FILE_SYSTEM_LIMITATION = 665, ++ MD_ERROR_WIN_ASSERTION_FAILURE = 668, ++ MD_ERROR_WIN_ACPI_ERROR = 669, ++ MD_ERROR_WIN_WOW_ASSERTION = 670, ++ MD_ERROR_WIN_PNP_BAD_MPS_TABLE = 671, ++ MD_ERROR_WIN_PNP_TRANSLATION_FAILED = 672, ++ MD_ERROR_WIN_PNP_IRQ_TRANSLATION_FAILED = 673, ++ MD_ERROR_WIN_PNP_INVALID_ID = 674, ++ MD_ERROR_WIN_WAKE_SYSTEM_DEBUGGER = 675, ++ MD_ERROR_WIN_HANDLES_CLOSED = 676, ++ MD_ERROR_WIN_EXTRANEOUS_INFORMATION = 677, ++ MD_ERROR_WIN_RXACT_COMMIT_NECESSARY = 678, ++ MD_ERROR_WIN_MEDIA_CHECK = 679, ++ MD_ERROR_WIN_GUID_SUBSTITUTION_MADE = 680, ++ MD_ERROR_WIN_STOPPED_ON_SYMLINK = 681, ++ MD_ERROR_WIN_LONGJUMP = 682, ++ MD_ERROR_WIN_PLUGPLAY_QUERY_VETOED = 683, ++ MD_ERROR_WIN_UNWIND_CONSOLIDATE = 684, ++ MD_ERROR_WIN_REGISTRY_HIVE_RECOVERED = 685, ++ MD_ERROR_WIN_DLL_MIGHT_BE_INSECURE = 686, ++ MD_ERROR_WIN_DLL_MIGHT_BE_INCOMPATIBLE = 687, ++ MD_ERROR_WIN_DBG_EXCEPTION_NOT_HANDLED = 688, ++ MD_ERROR_WIN_DBG_REPLY_LATER = 689, ++ MD_ERROR_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE = 690, ++ MD_ERROR_WIN_DBG_TERMINATE_THREAD = 691, ++ MD_ERROR_WIN_DBG_TERMINATE_PROCESS = 692, ++ MD_ERROR_WIN_DBG_CONTROL_C = 693, ++ MD_ERROR_WIN_DBG_PRINTEXCEPTION_C = 694, ++ MD_ERROR_WIN_DBG_RIPEXCEPTION = 695, ++ MD_ERROR_WIN_DBG_CONTROL_BREAK = 696, ++ MD_ERROR_WIN_DBG_COMMAND_EXCEPTION = 697, ++ MD_ERROR_WIN_OBJECT_NAME_EXISTS = 698, ++ MD_ERROR_WIN_THREAD_WAS_SUSPENDED = 699, ++ MD_ERROR_WIN_IMAGE_NOT_AT_BASE = 700, ++ MD_ERROR_WIN_RXACT_STATE_CREATED = 701, ++ MD_ERROR_WIN_SEGMENT_NOTIFICATION = 702, ++ MD_ERROR_WIN_BAD_CURRENT_DIRECTORY = 703, ++ MD_ERROR_WIN_FT_READ_RECOVERY_FROM_BACKUP = 704, ++ MD_ERROR_WIN_FT_WRITE_RECOVERY = 705, ++ MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH = 706, ++ MD_ERROR_WIN_RECEIVE_PARTIAL = 707, ++ MD_ERROR_WIN_RECEIVE_EXPEDITED = 708, ++ MD_ERROR_WIN_RECEIVE_PARTIAL_EXPEDITED = 709, ++ MD_ERROR_WIN_EVENT_DONE = 710, ++ MD_ERROR_WIN_EVENT_PENDING = 711, ++ MD_ERROR_WIN_CHECKING_FILE_SYSTEM = 712, ++ MD_ERROR_WIN_FATAL_APP_EXIT = 713, ++ MD_ERROR_WIN_PREDEFINED_HANDLE = 714, ++ MD_ERROR_WIN_WAS_UNLOCKED = 715, ++ MD_ERROR_WIN_SERVICE_NOTIFICATION = 716, ++ MD_ERROR_WIN_WAS_LOCKED = 717, ++ MD_ERROR_WIN_LOG_HARD_ERROR = 718, ++ MD_ERROR_WIN_ALREADY_WIN32 = 719, ++ MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH_EXE = 720, ++ MD_ERROR_WIN_NO_YIELD_PERFORMED = 721, ++ MD_ERROR_WIN_TIMER_RESUME_IGNORED = 722, ++ MD_ERROR_WIN_ARBITRATION_UNHANDLED = 723, ++ MD_ERROR_WIN_CARDBUS_NOT_SUPPORTED = 724, ++ MD_ERROR_WIN_MP_PROCESSOR_MISMATCH = 725, ++ MD_ERROR_WIN_HIBERNATED = 726, ++ MD_ERROR_WIN_RESUME_HIBERNATION = 727, ++ MD_ERROR_WIN_FIRMWARE_UPDATED = 728, ++ MD_ERROR_WIN_DRIVERS_LEAKING_LOCKED_PAGES = 729, ++ MD_ERROR_WIN_WAKE_SYSTEM = 730, ++ MD_ERROR_WIN_WAIT_1 = 731, ++ MD_ERROR_WIN_WAIT_2 = 732, ++ MD_ERROR_WIN_WAIT_3 = 733, ++ MD_ERROR_WIN_WAIT_63 = 734, ++ MD_ERROR_WIN_ABANDONED_WAIT_0 = 735, ++ MD_ERROR_WIN_ABANDONED_WAIT_63 = 736, ++ MD_ERROR_WIN_USER_APC = 737, ++ MD_ERROR_WIN_KERNEL_APC = 738, ++ MD_ERROR_WIN_ALERTED = 739, ++ MD_ERROR_WIN_ELEVATION_REQUIRED = 740, ++ MD_ERROR_WIN_REPARSE = 741, ++ MD_ERROR_WIN_OPLOCK_BREAK_IN_PROGRESS = 742, ++ MD_ERROR_WIN_VOLUME_MOUNTED = 743, ++ MD_ERROR_WIN_RXACT_COMMITTED = 744, ++ MD_ERROR_WIN_NOTIFY_CLEANUP = 745, ++ MD_ERROR_WIN_PRIMARY_TRANSPORT_CONNECT_FAILED = 746, ++ MD_ERROR_WIN_PAGE_FAULT_TRANSITION = 747, ++ MD_ERROR_WIN_PAGE_FAULT_DEMAND_ZERO = 748, ++ MD_ERROR_WIN_PAGE_FAULT_COPY_ON_WRITE = 749, ++ MD_ERROR_WIN_PAGE_FAULT_GUARD_PAGE = 750, ++ MD_ERROR_WIN_PAGE_FAULT_PAGING_FILE = 751, ++ MD_ERROR_WIN_CACHE_PAGE_LOCKED = 752, ++ MD_ERROR_WIN_CRASH_DUMP = 753, ++ MD_ERROR_WIN_BUFFER_ALL_ZEROS = 754, ++ MD_ERROR_WIN_REPARSE_OBJECT = 755, ++ MD_ERROR_WIN_RESOURCE_REQUIREMENTS_CHANGED = 756, ++ MD_ERROR_WIN_TRANSLATION_COMPLETE = 757, ++ MD_ERROR_WIN_NOTHING_TO_TERMINATE = 758, ++ MD_ERROR_WIN_PROCESS_NOT_IN_JOB = 759, ++ MD_ERROR_WIN_PROCESS_IN_JOB = 760, ++ MD_ERROR_WIN_VOLSNAP_HIBERNATE_READY = 761, ++ MD_ERROR_WIN_FSFILTER_OP_COMPLETED_SUCCESSFULLY = 762, ++ MD_ERROR_WIN_INTERRUPT_VECTOR_ALREADY_CONNECTED = 763, ++ MD_ERROR_WIN_INTERRUPT_STILL_CONNECTED = 764, ++ MD_ERROR_WIN_WAIT_FOR_OPLOCK = 765, ++ MD_ERROR_WIN_DBG_EXCEPTION_HANDLED = 766, ++ MD_ERROR_WIN_DBG_CONTINUE = 767, ++ MD_ERROR_WIN_CALLBACK_POP_STACK = 768, ++ MD_ERROR_WIN_COMPRESSION_DISABLED = 769, ++ MD_ERROR_WIN_CANTFETCHBACKWARDS = 770, ++ MD_ERROR_WIN_CANTSCROLLBACKWARDS = 771, ++ MD_ERROR_WIN_ROWSNOTRELEASED = 772, ++ MD_ERROR_WIN_BAD_ACCESSOR_FLAGS = 773, ++ MD_ERROR_WIN_ERRORS_ENCOUNTERED = 774, ++ MD_ERROR_WIN_NOT_CAPABLE = 775, ++ MD_ERROR_WIN_REQUEST_OUT_OF_SEQUENCE = 776, ++ MD_ERROR_WIN_VERSION_PARSE_ERROR = 777, ++ MD_ERROR_WIN_BADSTARTPOSITION = 778, ++ MD_ERROR_WIN_MEMORY_HARDWARE = 779, ++ MD_ERROR_WIN_DISK_REPAIR_DISABLED = 780, ++ MD_ERROR_WIN_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 781, ++ MD_ERROR_WIN_SYSTEM_POWERSTATE_TRANSITION = 782, ++ MD_ERROR_WIN_SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 783, ++ MD_ERROR_WIN_MCA_EXCEPTION = 784, ++ MD_ERROR_WIN_ACCESS_AUDIT_BY_POLICY = 785, ++ MD_ERROR_WIN_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 786, ++ MD_ERROR_WIN_ABANDON_HIBERFILE = 787, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 788, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 789, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 790, ++ MD_ERROR_WIN_BAD_MCFG_TABLE = 791, ++ MD_ERROR_WIN_DISK_REPAIR_REDIRECTED = 792, ++ MD_ERROR_WIN_DISK_REPAIR_UNSUCCESSFUL = 793, ++ MD_ERROR_WIN_CORRUPT_LOG_OVERFULL = 794, ++ MD_ERROR_WIN_CORRUPT_LOG_CORRUPTED = 795, ++ MD_ERROR_WIN_CORRUPT_LOG_UNAVAILABLE = 796, ++ MD_ERROR_WIN_CORRUPT_LOG_DELETED_FULL = 797, ++ MD_ERROR_WIN_CORRUPT_LOG_CLEARED = 798, ++ MD_ERROR_WIN_ORPHAN_NAME_EXHAUSTED = 799, ++ MD_ERROR_WIN_OPLOCK_SWITCHED_TO_NEW_HANDLE = 800, ++ MD_ERROR_WIN_CANNOT_GRANT_REQUESTED_OPLOCK = 801, ++ MD_ERROR_WIN_CANNOT_BREAK_OPLOCK = 802, ++ MD_ERROR_WIN_OPLOCK_HANDLE_CLOSED = 803, ++ MD_ERROR_WIN_NO_ACE_CONDITION = 804, ++ MD_ERROR_WIN_INVALID_ACE_CONDITION = 805, ++ MD_ERROR_WIN_FILE_HANDLE_REVOKED = 806, ++ MD_ERROR_WIN_IMAGE_AT_DIFFERENT_BASE = 807, ++ MD_ERROR_WIN_ENCRYPTED_IO_NOT_POSSIBLE = 808, ++ MD_ERROR_WIN_FILE_METADATA_OPTIMIZATION_IN_PROGRESS = 809, ++ MD_ERROR_WIN_QUOTA_ACTIVITY = 810, ++ MD_ERROR_WIN_HANDLE_REVOKED = 811, ++ MD_ERROR_WIN_CALLBACK_INVOKE_INLINE = 812, ++ MD_ERROR_WIN_CPU_SET_INVALID = 813, ++ MD_ERROR_WIN_ENCLAVE_NOT_TERMINATED = 814, ++ MD_ERROR_WIN_ENCLAVE_VIOLATION = 815, ++ MD_ERROR_WIN_EA_ACCESS_DENIED = 994, ++ MD_ERROR_WIN_OPERATION_ABORTED = 995, ++ MD_ERROR_WIN_IO_INCOMPLETE = 996, ++ MD_ERROR_WIN_IO_PENDING = 997, ++ MD_ERROR_WIN_NOACCESS = 998, ++ MD_ERROR_WIN_SWAPERROR = 999, ++ MD_ERROR_WIN_STACK_OVERFLOW = 1001, ++ MD_ERROR_WIN_INVALID_MESSAGE = 1002, ++ MD_ERROR_WIN_CAN_NOT_COMPLETE = 1003, ++ MD_ERROR_WIN_INVALID_FLAGS = 1004, ++ MD_ERROR_WIN_UNRECOGNIZED_VOLUME = 1005, ++ MD_ERROR_WIN_FILE_INVALID = 1006, ++ MD_ERROR_WIN_FULLSCREEN_MODE = 1007, ++ MD_ERROR_WIN_NO_TOKEN = 1008, ++ MD_ERROR_WIN_BADDB = 1009, ++ MD_ERROR_WIN_BADKEY = 1010, ++ MD_ERROR_WIN_CANTOPEN = 1011, ++ MD_ERROR_WIN_CANTREAD = 1012, ++ MD_ERROR_WIN_CANTWRITE = 1013, ++ MD_ERROR_WIN_REGISTRY_RECOVERED = 1014, ++ MD_ERROR_WIN_REGISTRY_CORRUPT = 1015, ++ MD_ERROR_WIN_REGISTRY_IO_FAILED = 1016, ++ MD_ERROR_WIN_NOT_REGISTRY_FILE = 1017, ++ MD_ERROR_WIN_KEY_DELETED = 1018, ++ MD_ERROR_WIN_NO_LOG_SPACE = 1019, ++ MD_ERROR_WIN_KEY_HAS_CHILDREN = 1020, ++ MD_ERROR_WIN_CHILD_MUST_BE_VOLATILE = 1021, ++ MD_ERROR_WIN_NOTIFY_ENUM_DIR = 1022, ++ MD_ERROR_WIN_DEPENDENT_SERVICES_RUNNING = 1051, ++ MD_ERROR_WIN_INVALID_SERVICE_CONTROL = 1052, ++ MD_ERROR_WIN_SERVICE_REQUEST_TIMEOUT = 1053, ++ MD_ERROR_WIN_SERVICE_NO_THREAD = 1054, ++ MD_ERROR_WIN_SERVICE_DATABASE_LOCKED = 1055, ++ MD_ERROR_WIN_SERVICE_ALREADY_RUNNING = 1056, ++ MD_ERROR_WIN_INVALID_SERVICE_ACCOUNT = 1057, ++ MD_ERROR_WIN_SERVICE_DISABLED = 1058, ++ MD_ERROR_WIN_CIRCULAR_DEPENDENCY = 1059, ++ MD_ERROR_WIN_SERVICE_DOES_NOT_EXIST = 1060, ++ MD_ERROR_WIN_SERVICE_CANNOT_ACCEPT_CTRL = 1061, ++ MD_ERROR_WIN_SERVICE_NOT_ACTIVE = 1062, ++ MD_ERROR_WIN_FAILED_SERVICE_CONTROLLER_CONNECT = 1063, ++ MD_ERROR_WIN_EXCEPTION_IN_SERVICE = 1064, ++ MD_ERROR_WIN_DATABASE_DOES_NOT_EXIST = 1065, ++ MD_ERROR_WIN_SERVICE_SPECIFIC_ERROR = 1066, ++ MD_ERROR_WIN_PROCESS_ABORTED = 1067, ++ MD_ERROR_WIN_SERVICE_DEPENDENCY_FAIL = 1068, ++ MD_ERROR_WIN_SERVICE_LOGON_FAILED = 1069, ++ MD_ERROR_WIN_SERVICE_START_HANG = 1070, ++ MD_ERROR_WIN_INVALID_SERVICE_LOCK = 1071, ++ MD_ERROR_WIN_SERVICE_MARKED_FOR_DELETE = 1072, ++ MD_ERROR_WIN_SERVICE_EXISTS = 1073, ++ MD_ERROR_WIN_ALREADY_RUNNING_LKG = 1074, ++ MD_ERROR_WIN_SERVICE_DEPENDENCY_DELETED = 1075, ++ MD_ERROR_WIN_BOOT_ALREADY_ACCEPTED = 1076, ++ MD_ERROR_WIN_SERVICE_NEVER_STARTED = 1077, ++ MD_ERROR_WIN_DUPLICATE_SERVICE_NAME = 1078, ++ MD_ERROR_WIN_DIFFERENT_SERVICE_ACCOUNT = 1079, ++ MD_ERROR_WIN_CANNOT_DETECT_DRIVER_FAILURE = 1080, ++ MD_ERROR_WIN_CANNOT_DETECT_PROCESS_ABORT = 1081, ++ MD_ERROR_WIN_NO_RECOVERY_PROGRAM = 1082, ++ MD_ERROR_WIN_SERVICE_NOT_IN_EXE = 1083, ++ MD_ERROR_WIN_NOT_SAFEBOOT_SERVICE = 1084, ++ MD_ERROR_WIN_END_OF_MEDIA = 1100, ++ MD_ERROR_WIN_FILEMARK_DETECTED = 1101, ++ MD_ERROR_WIN_BEGINNING_OF_MEDIA = 1102, ++ MD_ERROR_WIN_SETMARK_DETECTED = 1103, ++ MD_ERROR_WIN_NO_DATA_DETECTED = 1104, ++ MD_ERROR_WIN_PARTITION_FAILURE = 1105, ++ MD_ERROR_WIN_INVALID_BLOCK_LENGTH = 1106, ++ MD_ERROR_WIN_DEVICE_NOT_PARTITIONED = 1107, ++ MD_ERROR_WIN_UNABLE_TO_LOCK_MEDIA = 1108, ++ MD_ERROR_WIN_UNABLE_TO_UNLOAD_MEDIA = 1109, ++ MD_ERROR_WIN_MEDIA_CHANGED = 1110, ++ MD_ERROR_WIN_BUS_RESET = 1111, ++ MD_ERROR_WIN_NO_MEDIA_IN_DRIVE = 1112, ++ MD_ERROR_WIN_NO_UNICODE_TRANSLATION = 1113, ++ MD_ERROR_WIN_DLL_INIT_FAILED = 1114, ++ MD_ERROR_WIN_SHUTDOWN_IN_PROGRESS = 1115, ++ MD_ERROR_WIN_NO_SHUTDOWN_IN_PROGRESS = 1116, ++ MD_ERROR_WIN_IO_DEVICE = 1117, ++ MD_ERROR_WIN_SERIAL_NO_DEVICE = 1118, ++ MD_ERROR_WIN_IRQ_BUSY = 1119, ++ MD_ERROR_WIN_MORE_WRITES = 1120, ++ MD_ERROR_WIN_COUNTER_TIMEOUT = 1121, ++ MD_ERROR_WIN_FLOPPY_ID_MARK_NOT_FOUND = 1122, ++ MD_ERROR_WIN_FLOPPY_WRONG_CYLINDER = 1123, ++ MD_ERROR_WIN_FLOPPY_UNKNOWN_ERROR = 1124, ++ MD_ERROR_WIN_FLOPPY_BAD_REGISTERS = 1125, ++ MD_ERROR_WIN_DISK_RECALIBRATE_FAILED = 1126, ++ MD_ERROR_WIN_DISK_OPERATION_FAILED = 1127, ++ MD_ERROR_WIN_DISK_RESET_FAILED = 1128, ++ MD_ERROR_WIN_EOM_OVERFLOW = 1129, ++ MD_ERROR_WIN_NOT_ENOUGH_SERVER_MEMORY = 1130, ++ MD_ERROR_WIN_POSSIBLE_DEADLOCK = 1131, ++ MD_ERROR_WIN_MAPPED_ALIGNMENT = 1132, ++ MD_ERROR_WIN_SET_POWER_STATE_VETOED = 1140, ++ MD_ERROR_WIN_SET_POWER_STATE_FAILED = 1141, ++ MD_ERROR_WIN_TOO_MANY_LINKS = 1142, ++ MD_ERROR_WIN_OLD_WIN_VERSION = 1150, ++ MD_ERROR_WIN_APP_WRONG_OS = 1151, ++ MD_ERROR_WIN_SINGLE_INSTANCE_APP = 1152, ++ MD_ERROR_WIN_RMODE_APP = 1153, ++ MD_ERROR_WIN_INVALID_DLL = 1154, ++ MD_ERROR_WIN_NO_ASSOCIATION = 1155, ++ MD_ERROR_WIN_DDE_FAIL = 1156, ++ MD_ERROR_WIN_DLL_NOT_FOUND = 1157, ++ MD_ERROR_WIN_NO_MORE_USER_HANDLES = 1158, ++ MD_ERROR_WIN_MESSAGE_SYNC_ONLY = 1159, ++ MD_ERROR_WIN_SOURCE_ELEMENT_EMPTY = 1160, ++ MD_ERROR_WIN_DESTINATION_ELEMENT_FULL = 1161, ++ MD_ERROR_WIN_ILLEGAL_ELEMENT_ADDRESS = 1162, ++ MD_ERROR_WIN_MAGAZINE_NOT_PRESENT = 1163, ++ MD_ERROR_WIN_DEVICE_REINITIALIZATION_NEEDED = 1164, ++ MD_ERROR_WIN_DEVICE_REQUIRES_CLEANING = 1165, ++ MD_ERROR_WIN_DEVICE_DOOR_OPEN = 1166, ++ MD_ERROR_WIN_DEVICE_NOT_CONNECTED = 1167, ++ MD_ERROR_WIN_NOT_FOUND = 1168, ++ MD_ERROR_WIN_NO_MATCH = 1169, ++ MD_ERROR_WIN_SET_NOT_FOUND = 1170, ++ MD_ERROR_WIN_POINT_NOT_FOUND = 1171, ++ MD_ERROR_WIN_NO_TRACKING_SERVICE = 1172, ++ MD_ERROR_WIN_NO_VOLUME_ID = 1173, ++ MD_ERROR_WIN_UNABLE_TO_REMOVE_REPLACED = 1175, ++ MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT = 1176, ++ MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT_2 = 1177, ++ MD_ERROR_WIN_JOURNAL_DELETE_IN_PROGRESS = 1178, ++ MD_ERROR_WIN_JOURNAL_NOT_ACTIVE = 1179, ++ MD_ERROR_WIN_POTENTIAL_FILE_FOUND = 1180, ++ MD_ERROR_WIN_JOURNAL_ENTRY_DELETED = 1181, ++ MD_ERROR_WIN_VRF_CFG_AND_IO_ENABLED = 1183, ++ MD_ERROR_WIN_PARTITION_TERMINATING = 1184, ++ MD_ERROR_WIN_SHUTDOWN_IS_SCHEDULED = 1190, ++ MD_ERROR_WIN_SHUTDOWN_USERS_LOGGED_ON = 1191, ++ MD_ERROR_WIN_BAD_DEVICE = 1200, ++ MD_ERROR_WIN_CONNECTION_UNAVAIL = 1201, ++ MD_ERROR_WIN_DEVICE_ALREADY_REMEMBERED = 1202, ++ MD_ERROR_WIN_NO_NET_OR_BAD_PATH = 1203, ++ MD_ERROR_WIN_BAD_PROVIDER = 1204, ++ MD_ERROR_WIN_CANNOT_OPEN_PROFILE = 1205, ++ MD_ERROR_WIN_BAD_PROFILE = 1206, ++ MD_ERROR_WIN_NOT_CONTAINER = 1207, ++ MD_ERROR_WIN_EXTENDED_ERROR = 1208, ++ MD_ERROR_WIN_INVALID_GROUPNAME = 1209, ++ MD_ERROR_WIN_INVALID_COMPUTERNAME = 1210, ++ MD_ERROR_WIN_INVALID_EVENTNAME = 1211, ++ MD_ERROR_WIN_INVALID_DOMAINNAME = 1212, ++ MD_ERROR_WIN_INVALID_SERVICENAME = 1213, ++ MD_ERROR_WIN_INVALID_NETNAME = 1214, ++ MD_ERROR_WIN_INVALID_SHARENAME = 1215, ++ MD_ERROR_WIN_INVALID_PASSWORDNAME = 1216, ++ MD_ERROR_WIN_INVALID_MESSAGENAME = 1217, ++ MD_ERROR_WIN_INVALID_MESSAGEDEST = 1218, ++ MD_ERROR_WIN_SESSION_CREDENTIAL_CONFLICT = 1219, ++ MD_ERROR_WIN_REMOTE_SESSION_LIMIT_EXCEEDED = 1220, ++ MD_ERROR_WIN_DUP_DOMAINNAME = 1221, ++ MD_ERROR_WIN_NO_NETWORK = 1222, ++ MD_ERROR_WIN_CANCELLED = 1223, ++ MD_ERROR_WIN_USER_MAPPED_FILE = 1224, ++ MD_ERROR_WIN_CONNECTION_REFUSED = 1225, ++ MD_ERROR_WIN_GRACEFUL_DISCONNECT = 1226, ++ MD_ERROR_WIN_ADDRESS_ALREADY_ASSOCIATED = 1227, ++ MD_ERROR_WIN_ADDRESS_NOT_ASSOCIATED = 1228, ++ MD_ERROR_WIN_CONNECTION_INVALID = 1229, ++ MD_ERROR_WIN_CONNECTION_ACTIVE = 1230, ++ MD_ERROR_WIN_NETWORK_UNREACHABLE = 1231, ++ MD_ERROR_WIN_HOST_UNREACHABLE = 1232, ++ MD_ERROR_WIN_PROTOCOL_UNREACHABLE = 1233, ++ MD_ERROR_WIN_PORT_UNREACHABLE = 1234, ++ MD_ERROR_WIN_REQUEST_ABORTED = 1235, ++ MD_ERROR_WIN_CONNECTION_ABORTED = 1236, ++ MD_ERROR_WIN_RETRY = 1237, ++ MD_ERROR_WIN_CONNECTION_COUNT_LIMIT = 1238, ++ MD_ERROR_WIN_LOGIN_TIME_RESTRICTION = 1239, ++ MD_ERROR_WIN_LOGIN_WKSTA_RESTRICTION = 1240, ++ MD_ERROR_WIN_INCORRECT_ADDRESS = 1241, ++ MD_ERROR_WIN_ALREADY_REGISTERED = 1242, ++ MD_ERROR_WIN_SERVICE_NOT_FOUND = 1243, ++ MD_ERROR_WIN_NOT_AUTHENTICATED = 1244, ++ MD_ERROR_WIN_NOT_LOGGED_ON = 1245, ++ MD_ERROR_WIN_CONTINUE = 1246, ++ MD_ERROR_WIN_ALREADY_INITIALIZED = 1247, ++ MD_ERROR_WIN_NO_MORE_DEVICES = 1248, ++ MD_ERROR_WIN_NO_SUCH_SITE = 1249, ++ MD_ERROR_WIN_DOMAIN_CONTROLLER_EXISTS = 1250, ++ MD_ERROR_WIN_ONLY_IF_CONNECTED = 1251, ++ MD_ERROR_WIN_OVERRIDE_NOCHANGES = 1252, ++ MD_ERROR_WIN_BAD_USER_PROFILE = 1253, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_SBS = 1254, ++ MD_ERROR_WIN_SERVER_SHUTDOWN_IN_PROGRESS = 1255, ++ MD_ERROR_WIN_HOST_DOWN = 1256, ++ MD_ERROR_WIN_NON_ACCOUNT_SID = 1257, ++ MD_ERROR_WIN_NON_DOMAIN_SID = 1258, ++ MD_ERROR_WIN_APPHELP_BLOCK = 1259, ++ MD_ERROR_WIN_ACCESS_DISABLED_BY_POLICY = 1260, ++ MD_ERROR_WIN_REG_NAT_CONSUMPTION = 1261, ++ MD_ERROR_WIN_CSCSHARE_OFFLINE = 1262, ++ MD_ERROR_WIN_PKINIT_FAILURE = 1263, ++ MD_ERROR_WIN_SMARTCARD_SUBSYSTEM_FAILURE = 1264, ++ MD_ERROR_WIN_DOWNGRADE_DETECTED = 1265, ++ MD_ERROR_WIN_MACHINE_LOCKED = 1271, ++ MD_ERROR_WIN_SMB_GUEST_LOGON_BLOCKED = 1272, ++ MD_ERROR_WIN_CALLBACK_SUPPLIED_INVALID_DATA = 1273, ++ MD_ERROR_WIN_SYNC_FOREGROUND_REFRESH_REQUIRED = 1274, ++ MD_ERROR_WIN_DRIVER_BLOCKED = 1275, ++ MD_ERROR_WIN_INVALID_IMPORT_OF_NON_DLL = 1276, ++ MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE = 1277, ++ MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE_TAMPER = 1278, ++ MD_ERROR_WIN_RECOVERY_FAILURE = 1279, ++ MD_ERROR_WIN_ALREADY_FIBER = 1280, ++ MD_ERROR_WIN_ALREADY_THREAD = 1281, ++ MD_ERROR_WIN_STACK_BUFFER_OVERRUN = 1282, ++ MD_ERROR_WIN_PARAMETER_QUOTA_EXCEEDED = 1283, ++ MD_ERROR_WIN_DEBUGGER_INACTIVE = 1284, ++ MD_ERROR_WIN_DELAY_LOAD_FAILED = 1285, ++ MD_ERROR_WIN_VDM_DISALLOWED = 1286, ++ MD_ERROR_WIN_UNIDENTIFIED_ERROR = 1287, ++ MD_ERROR_WIN_INVALID_CRUNTIME_PARAMETER = 1288, ++ MD_ERROR_WIN_BEYOND_VDL = 1289, ++ MD_ERROR_WIN_INCOMPATIBLE_SERVICE_SID_TYPE = 1290, ++ MD_ERROR_WIN_DRIVER_PROCESS_TERMINATED = 1291, ++ MD_ERROR_WIN_IMPLEMENTATION_LIMIT = 1292, ++ MD_ERROR_WIN_PROCESS_IS_PROTECTED = 1293, ++ MD_ERROR_WIN_SERVICE_NOTIFY_CLIENT_LAGGING = 1294, ++ MD_ERROR_WIN_DISK_QUOTA_EXCEEDED = 1295, ++ MD_ERROR_WIN_CONTENT_BLOCKED = 1296, ++ MD_ERROR_WIN_INCOMPATIBLE_SERVICE_PRIVILEGE = 1297, ++ MD_ERROR_WIN_APP_HANG = 1298, ++ MD_ERROR_WIN_INVALID_LABEL = 1299, ++ MD_ERROR_WIN_NOT_ALL_ASSIGNED = 1300, ++ MD_ERROR_WIN_SOME_NOT_MAPPED = 1301, ++ MD_ERROR_WIN_NO_QUOTAS_FOR_ACCOUNT = 1302, ++ MD_ERROR_WIN_LOCAL_USER_SESSION_KEY = 1303, ++ MD_ERROR_WIN_NULL_LM_PASSWORD = 1304, ++ MD_ERROR_WIN_UNKNOWN_REVISION = 1305, ++ MD_ERROR_WIN_REVISION_MISMATCH = 1306, ++ MD_ERROR_WIN_INVALID_OWNER = 1307, ++ MD_ERROR_WIN_INVALID_PRIMARY_GROUP = 1308, ++ MD_ERROR_WIN_NO_IMPERSONATION_TOKEN = 1309, ++ MD_ERROR_WIN_CANT_DISABLE_MANDATORY = 1310, ++ MD_ERROR_WIN_NO_LOGON_SERVERS = 1311, ++ MD_ERROR_WIN_NO_SUCH_LOGON_SESSION = 1312, ++ MD_ERROR_WIN_NO_SUCH_PRIVILEGE = 1313, ++ MD_ERROR_WIN_PRIVILEGE_NOT_HELD = 1314, ++ MD_ERROR_WIN_INVALID_ACCOUNT_NAME = 1315, ++ MD_ERROR_WIN_USER_EXISTS = 1316, ++ MD_ERROR_WIN_NO_SUCH_USER = 1317, ++ MD_ERROR_WIN_GROUP_EXISTS = 1318, ++ MD_ERROR_WIN_NO_SUCH_GROUP = 1319, ++ MD_ERROR_WIN_MEMBER_IN_GROUP = 1320, ++ MD_ERROR_WIN_MEMBER_NOT_IN_GROUP = 1321, ++ MD_ERROR_WIN_LAST_ADMIN = 1322, ++ MD_ERROR_WIN_WRONG_PASSWORD = 1323, ++ MD_ERROR_WIN_ILL_FORMED_PASSWORD = 1324, ++ MD_ERROR_WIN_PASSWORD_RESTRICTION = 1325, ++ MD_ERROR_WIN_LOGON_FAILURE = 1326, ++ MD_ERROR_WIN_ACCOUNT_RESTRICTION = 1327, ++ MD_ERROR_WIN_INVALID_LOGON_HOURS = 1328, ++ MD_ERROR_WIN_INVALID_WORKSTATION = 1329, ++ MD_ERROR_WIN_PASSWORD_EXPIRED = 1330, ++ MD_ERROR_WIN_ACCOUNT_DISABLED = 1331, ++ MD_ERROR_WIN_NONE_MAPPED = 1332, ++ MD_ERROR_WIN_TOO_MANY_LUIDS_REQUESTED = 1333, ++ MD_ERROR_WIN_LUIDS_EXHAUSTED = 1334, ++ MD_ERROR_WIN_INVALID_SUB_AUTHORITY = 1335, ++ MD_ERROR_WIN_INVALID_ACL = 1336, ++ MD_ERROR_WIN_INVALID_SID = 1337, ++ MD_ERROR_WIN_INVALID_SECURITY_DESCR = 1338, ++ MD_ERROR_WIN_BAD_INHERITANCE_ACL = 1340, ++ MD_ERROR_WIN_SERVER_DISABLED = 1341, ++ MD_ERROR_WIN_SERVER_NOT_DISABLED = 1342, ++ MD_ERROR_WIN_INVALID_ID_AUTHORITY = 1343, ++ MD_ERROR_WIN_ALLOTTED_SPACE_EXCEEDED = 1344, ++ MD_ERROR_WIN_INVALID_GROUP_ATTRIBUTES = 1345, ++ MD_ERROR_WIN_BAD_IMPERSONATION_LEVEL = 1346, ++ MD_ERROR_WIN_CANT_OPEN_ANONYMOUS = 1347, ++ MD_ERROR_WIN_BAD_VALIDATION_CLASS = 1348, ++ MD_ERROR_WIN_BAD_TOKEN_TYPE = 1349, ++ MD_ERROR_WIN_NO_SECURITY_ON_OBJECT = 1350, ++ MD_ERROR_WIN_CANT_ACCESS_DOMAIN_INFO = 1351, ++ MD_ERROR_WIN_INVALID_SERVER_STATE = 1352, ++ MD_ERROR_WIN_INVALID_DOMAIN_STATE = 1353, ++ MD_ERROR_WIN_INVALID_DOMAIN_ROLE = 1354, ++ MD_ERROR_WIN_NO_SUCH_DOMAIN = 1355, ++ MD_ERROR_WIN_DOMAIN_EXISTS = 1356, ++ MD_ERROR_WIN_DOMAIN_LIMIT_EXCEEDED = 1357, ++ MD_ERROR_WIN_INTERNAL_DB_CORRUPTION = 1358, ++ MD_ERROR_WIN_INTERNAL_ERROR = 1359, ++ MD_ERROR_WIN_GENERIC_NOT_MAPPED = 1360, ++ MD_ERROR_WIN_BAD_DESCRIPTOR_FORMAT = 1361, ++ MD_ERROR_WIN_NOT_LOGON_PROCESS = 1362, ++ MD_ERROR_WIN_LOGON_SESSION_EXISTS = 1363, ++ MD_ERROR_WIN_NO_SUCH_PACKAGE = 1364, ++ MD_ERROR_WIN_BAD_LOGON_SESSION_STATE = 1365, ++ MD_ERROR_WIN_LOGON_SESSION_COLLISION = 1366, ++ MD_ERROR_WIN_INVALID_LOGON_TYPE = 1367, ++ MD_ERROR_WIN_CANNOT_IMPERSONATE = 1368, ++ MD_ERROR_WIN_RXACT_INVALID_STATE = 1369, ++ MD_ERROR_WIN_RXACT_COMMIT_FAILURE = 1370, ++ MD_ERROR_WIN_SPECIAL_ACCOUNT = 1371, ++ MD_ERROR_WIN_SPECIAL_GROUP = 1372, ++ MD_ERROR_WIN_SPECIAL_USER = 1373, ++ MD_ERROR_WIN_MEMBERS_PRIMARY_GROUP = 1374, ++ MD_ERROR_WIN_TOKEN_ALREADY_IN_USE = 1375, ++ MD_ERROR_WIN_NO_SUCH_ALIAS = 1376, ++ MD_ERROR_WIN_MEMBER_NOT_IN_ALIAS = 1377, ++ MD_ERROR_WIN_MEMBER_IN_ALIAS = 1378, ++ MD_ERROR_WIN_ALIAS_EXISTS = 1379, ++ MD_ERROR_WIN_LOGON_NOT_GRANTED = 1380, ++ MD_ERROR_WIN_TOO_MANY_SECRETS = 1381, ++ MD_ERROR_WIN_SECRET_TOO_LONG = 1382, ++ MD_ERROR_WIN_INTERNAL_DB_ERROR = 1383, ++ MD_ERROR_WIN_TOO_MANY_CONTEXT_IDS = 1384, ++ MD_ERROR_WIN_LOGON_TYPE_NOT_GRANTED = 1385, ++ MD_ERROR_WIN_NT_CROSS_ENCRYPTION_REQUIRED = 1386, ++ MD_ERROR_WIN_NO_SUCH_MEMBER = 1387, ++ MD_ERROR_WIN_INVALID_MEMBER = 1388, ++ MD_ERROR_WIN_TOO_MANY_SIDS = 1389, ++ MD_ERROR_WIN_LM_CROSS_ENCRYPTION_REQUIRED = 1390, ++ MD_ERROR_WIN_NO_INHERITANCE = 1391, ++ MD_ERROR_WIN_FILE_CORRUPT = 1392, ++ MD_ERROR_WIN_DISK_CORRUPT = 1393, ++ MD_ERROR_WIN_NO_USER_SESSION_KEY = 1394, ++ MD_ERROR_WIN_LICENSE_QUOTA_EXCEEDED = 1395, ++ MD_ERROR_WIN_WRONG_TARGET_NAME = 1396, ++ MD_ERROR_WIN_MUTUAL_AUTH_FAILED = 1397, ++ MD_ERROR_WIN_TIME_SKEW = 1398, ++ MD_ERROR_WIN_CURRENT_DOMAIN_NOT_ALLOWED = 1399, ++ MD_ERROR_WIN_INVALID_WINDOW_HANDLE = 1400, ++ MD_ERROR_WIN_INVALID_MENU_HANDLE = 1401, ++ MD_ERROR_WIN_INVALID_CURSOR_HANDLE = 1402, ++ MD_ERROR_WIN_INVALID_ACCEL_HANDLE = 1403, ++ MD_ERROR_WIN_INVALID_HOOK_HANDLE = 1404, ++ MD_ERROR_WIN_INVALID_DWP_HANDLE = 1405, ++ MD_ERROR_WIN_TLW_WITH_WSCHILD = 1406, ++ MD_ERROR_WIN_CANNOT_FIND_WND_CLASS = 1407, ++ MD_ERROR_WIN_WINDOW_OF_OTHER_THREAD = 1408, ++ MD_ERROR_WIN_HOTKEY_ALREADY_REGISTERED = 1409, ++ MD_ERROR_WIN_CLASS_ALREADY_EXISTS = 1410, ++ MD_ERROR_WIN_CLASS_DOES_NOT_EXIST = 1411, ++ MD_ERROR_WIN_CLASS_HAS_WINDOWS = 1412, ++ MD_ERROR_WIN_INVALID_INDEX = 1413, ++ MD_ERROR_WIN_INVALID_ICON_HANDLE = 1414, ++ MD_ERROR_WIN_PRIVATE_DIALOG_INDEX = 1415, ++ MD_ERROR_WIN_LISTBOX_ID_NOT_FOUND = 1416, ++ MD_ERROR_WIN_NO_WILDCARD_CHARACTERS = 1417, ++ MD_ERROR_WIN_CLIPBOARD_NOT_OPEN = 1418, ++ MD_ERROR_WIN_HOTKEY_NOT_REGISTERED = 1419, ++ MD_ERROR_WIN_WINDOW_NOT_DIALOG = 1420, ++ MD_ERROR_WIN_CONTROL_ID_NOT_FOUND = 1421, ++ MD_ERROR_WIN_INVALID_COMBOBOX_MESSAGE = 1422, ++ MD_ERROR_WIN_WINDOW_NOT_COMBOBOX = 1423, ++ MD_ERROR_WIN_INVALID_EDIT_HEIGHT = 1424, ++ MD_ERROR_WIN_DC_NOT_FOUND = 1425, ++ MD_ERROR_WIN_INVALID_HOOK_FILTER = 1426, ++ MD_ERROR_WIN_INVALID_FILTER_PROC = 1427, ++ MD_ERROR_WIN_HOOK_NEEDS_HMOD = 1428, ++ MD_ERROR_WIN_GLOBAL_ONLY_HOOK = 1429, ++ MD_ERROR_WIN_JOURNAL_HOOK_SET = 1430, ++ MD_ERROR_WIN_HOOK_NOT_INSTALLED = 1431, ++ MD_ERROR_WIN_INVALID_LB_MESSAGE = 1432, ++ MD_ERROR_WIN_SETCOUNT_ON_BAD_LB = 1433, ++ MD_ERROR_WIN_LB_WITHOUT_TABSTOPS = 1434, ++ MD_ERROR_WIN_DESTROY_OBJECT_OF_OTHER_THREAD = 1435, ++ MD_ERROR_WIN_CHILD_WINDOW_MENU = 1436, ++ MD_ERROR_WIN_NO_SYSTEM_MENU = 1437, ++ MD_ERROR_WIN_INVALID_MSGBOX_STYLE = 1438, ++ MD_ERROR_WIN_INVALID_SPI_VALUE = 1439, ++ MD_ERROR_WIN_SCREEN_ALREADY_LOCKED = 1440, ++ MD_ERROR_WIN_HWNDS_HAVE_DIFF_PARENT = 1441, ++ MD_ERROR_WIN_NOT_CHILD_WINDOW = 1442, ++ MD_ERROR_WIN_INVALID_GW_COMMAND = 1443, ++ MD_ERROR_WIN_INVALID_THREAD_ID = 1444, ++ MD_ERROR_WIN_NON_MDICHILD_WINDOW = 1445, ++ MD_ERROR_WIN_POPUP_ALREADY_ACTIVE = 1446, ++ MD_ERROR_WIN_NO_SCROLLBARS = 1447, ++ MD_ERROR_WIN_INVALID_SCROLLBAR_RANGE = 1448, ++ MD_ERROR_WIN_INVALID_SHOWWIN_COMMAND = 1449, ++ MD_ERROR_WIN_NO_SYSTEM_RESOURCES = 1450, ++ MD_ERROR_WIN_NONPAGED_SYSTEM_RESOURCES = 1451, ++ MD_ERROR_WIN_PAGED_SYSTEM_RESOURCES = 1452, ++ MD_ERROR_WIN_WORKING_SET_QUOTA = 1453, ++ MD_ERROR_WIN_PAGEFILE_QUOTA = 1454, ++ MD_ERROR_WIN_COMMITMENT_LIMIT = 1455, ++ MD_ERROR_WIN_MENU_ITEM_NOT_FOUND = 1456, ++ MD_ERROR_WIN_INVALID_KEYBOARD_HANDLE = 1457, ++ MD_ERROR_WIN_HOOK_TYPE_NOT_ALLOWED = 1458, ++ MD_ERROR_WIN_REQUIRES_INTERACTIVE_WINDOWSTATION = 1459, ++ MD_ERROR_WIN_TIMEOUT = 1460, ++ MD_ERROR_WIN_INVALID_MONITOR_HANDLE = 1461, ++ MD_ERROR_WIN_INCORRECT_SIZE = 1462, ++ MD_ERROR_WIN_SYMLINK_CLASS_DISABLED = 1463, ++ MD_ERROR_WIN_SYMLINK_NOT_SUPPORTED = 1464, ++ MD_ERROR_WIN_XML_PARSE_ERROR = 1465, ++ MD_ERROR_WIN_XMLDSIG_ERROR = 1466, ++ MD_ERROR_WIN_RESTART_APPLICATION = 1467, ++ MD_ERROR_WIN_WRONG_COMPARTMENT = 1468, ++ MD_ERROR_WIN_AUTHIP_FAILURE = 1469, ++ MD_ERROR_WIN_NO_NVRAM_RESOURCES = 1470, ++ MD_ERROR_WIN_NOT_GUI_PROCESS = 1471, ++ MD_ERROR_WIN_EVENTLOG_FILE_CORRUPT = 1500, ++ MD_ERROR_WIN_EVENTLOG_CANT_START = 1501, ++ MD_ERROR_WIN_LOG_FILE_FULL = 1502, ++ MD_ERROR_WIN_EVENTLOG_FILE_CHANGED = 1503, ++ MD_ERROR_WIN_CONTAINER_ASSIGNED = 1504, ++ MD_ERROR_WIN_JOB_NO_CONTAINER = 1505, ++ MD_ERROR_WIN_INVALID_TASK_NAME = 1550, ++ MD_ERROR_WIN_INVALID_TASK_INDEX = 1551, ++ MD_ERROR_WIN_THREAD_ALREADY_IN_TASK = 1552, ++ MD_ERROR_WIN_INSTALL_SERVICE_FAILURE = 1601, ++ MD_ERROR_WIN_INSTALL_USEREXIT = 1602, ++ MD_ERROR_WIN_INSTALL_FAILURE = 1603, ++ MD_ERROR_WIN_INSTALL_SUSPEND = 1604, ++ MD_ERROR_WIN_UNKNOWN_PRODUCT = 1605, ++ MD_ERROR_WIN_UNKNOWN_FEATURE = 1606, ++ MD_ERROR_WIN_UNKNOWN_COMPONENT = 1607, ++ MD_ERROR_WIN_UNKNOWN_PROPERTY = 1608, ++ MD_ERROR_WIN_INVALID_HANDLE_STATE = 1609, ++ MD_ERROR_WIN_BAD_CONFIGURATION = 1610, ++ MD_ERROR_WIN_INDEX_ABSENT = 1611, ++ MD_ERROR_WIN_INSTALL_SOURCE_ABSENT = 1612, ++ MD_ERROR_WIN_INSTALL_PACKAGE_VERSION = 1613, ++ MD_ERROR_WIN_PRODUCT_UNINSTALLED = 1614, ++ MD_ERROR_WIN_BAD_QUERY_SYNTAX = 1615, ++ MD_ERROR_WIN_INVALID_FIELD = 1616, ++ MD_ERROR_WIN_DEVICE_REMOVED = 1617, ++ MD_ERROR_WIN_INSTALL_ALREADY_RUNNING = 1618, ++ MD_ERROR_WIN_INSTALL_PACKAGE_OPEN_FAILED = 1619, ++ MD_ERROR_WIN_INSTALL_PACKAGE_INVALID = 1620, ++ MD_ERROR_WIN_INSTALL_UI_FAILURE = 1621, ++ MD_ERROR_WIN_INSTALL_LOG_FAILURE = 1622, ++ MD_ERROR_WIN_INSTALL_LANGUAGE_UNSUPPORTED = 1623, ++ MD_ERROR_WIN_INSTALL_TRANSFORM_FAILURE = 1624, ++ MD_ERROR_WIN_INSTALL_PACKAGE_REJECTED = 1625, ++ MD_ERROR_WIN_FUNCTION_NOT_CALLED = 1626, ++ MD_ERROR_WIN_FUNCTION_FAILED = 1627, ++ MD_ERROR_WIN_INVALID_TABLE = 1628, ++ MD_ERROR_WIN_DATATYPE_MISMATCH = 1629, ++ MD_ERROR_WIN_UNSUPPORTED_TYPE = 1630, ++ MD_ERROR_WIN_CREATE_FAILED = 1631, ++ MD_ERROR_WIN_INSTALL_TEMP_UNWRITABLE = 1632, ++ MD_ERROR_WIN_INSTALL_PLATFORM_UNSUPPORTED = 1633, ++ MD_ERROR_WIN_INSTALL_NOTUSED = 1634, ++ MD_ERROR_WIN_PATCH_PACKAGE_OPEN_FAILED = 1635, ++ MD_ERROR_WIN_PATCH_PACKAGE_INVALID = 1636, ++ MD_ERROR_WIN_PATCH_PACKAGE_UNSUPPORTED = 1637, ++ MD_ERROR_WIN_PRODUCT_VERSION = 1638, ++ MD_ERROR_WIN_INVALID_COMMAND_LINE = 1639, ++ MD_ERROR_WIN_INSTALL_REMOTE_DISALLOWED = 1640, ++ MD_ERROR_WIN_SUCCESS_REBOOT_INITIATED = 1641, ++ MD_ERROR_WIN_PATCH_TARGET_NOT_FOUND = 1642, ++ MD_ERROR_WIN_PATCH_PACKAGE_REJECTED = 1643, ++ MD_ERROR_WIN_INSTALL_TRANSFORM_REJECTED = 1644, ++ MD_ERROR_WIN_INSTALL_REMOTE_PROHIBITED = 1645, ++ MD_ERROR_WIN_PATCH_REMOVAL_UNSUPPORTED = 1646, ++ MD_ERROR_WIN_UNKNOWN_PATCH = 1647, ++ MD_ERROR_WIN_PATCH_NO_SEQUENCE = 1648, ++ MD_ERROR_WIN_PATCH_REMOVAL_DISALLOWED = 1649, ++ MD_ERROR_WIN_INVALID_PATCH_XML = 1650, ++ MD_ERROR_WIN_PATCH_MANAGED_ADVERTISED_PRODUCT = 1651, ++ MD_ERROR_WIN_INSTALL_SERVICE_SAFEBOOT = 1652, ++ MD_ERROR_WIN_FAIL_FAST_EXCEPTION = 1653, ++ MD_ERROR_WIN_INSTALL_REJECTED = 1654, ++ MD_ERROR_WIN_DYNAMIC_CODE_BLOCKED = 1655, ++ MD_ERROR_WIN_NOT_SAME_OBJECT = 1656, ++ MD_ERROR_WIN_STRICT_CFG_VIOLATION = 1657, ++ MD_ERROR_WIN_SET_CONTEXT_DENIED = 1660, ++ MD_ERROR_WIN_CROSS_PARTITION_VIOLATION = 1661, ++ MD_ERROR_WIN_RETURN_ADDRESS_HIJACK_ATTEMPT = 1662, ++ MD_ERROR_WIN_INVALID_USER_BUFFER = 1784, ++ MD_ERROR_WIN_UNRECOGNIZED_MEDIA = 1785, ++ MD_ERROR_WIN_NO_TRUST_LSA_SECRET = 1786, ++ MD_ERROR_WIN_NO_TRUST_SAM_ACCOUNT = 1787, ++ MD_ERROR_WIN_TRUSTED_DOMAIN_FAILURE = 1788, ++ MD_ERROR_WIN_TRUSTED_RELATIONSHIP_FAILURE = 1789, ++ MD_ERROR_WIN_TRUST_FAILURE = 1790, ++ MD_ERROR_WIN_NETLOGON_NOT_STARTED = 1792, ++ MD_ERROR_WIN_ACCOUNT_EXPIRED = 1793, ++ MD_ERROR_WIN_REDIRECTOR_HAS_OPEN_HANDLES = 1794, ++ MD_ERROR_WIN_PRINTER_DRIVER_ALREADY_INSTALLED = 1795, ++ MD_ERROR_WIN_UNKNOWN_PORT = 1796, ++ MD_ERROR_WIN_UNKNOWN_PRINTER_DRIVER = 1797, ++ MD_ERROR_WIN_UNKNOWN_PRINTPROCESSOR = 1798, ++ MD_ERROR_WIN_INVALID_SEPARATOR_FILE = 1799, ++ MD_ERROR_WIN_INVALID_PRIORITY = 1800, ++ MD_ERROR_WIN_INVALID_PRINTER_NAME = 1801, ++ MD_ERROR_WIN_PRINTER_ALREADY_EXISTS = 1802, ++ MD_ERROR_WIN_INVALID_PRINTER_COMMAND = 1803, ++ MD_ERROR_WIN_INVALID_DATATYPE = 1804, ++ MD_ERROR_WIN_INVALID_ENVIRONMENT = 1805, ++ MD_ERROR_WIN_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807, ++ MD_ERROR_WIN_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808, ++ MD_ERROR_WIN_NOLOGON_SERVER_TRUST_ACCOUNT = 1809, ++ MD_ERROR_WIN_DOMAIN_TRUST_INCONSISTENT = 1810, ++ MD_ERROR_WIN_SERVER_HAS_OPEN_HANDLES = 1811, ++ MD_ERROR_WIN_RESOURCE_DATA_NOT_FOUND = 1812, ++ MD_ERROR_WIN_RESOURCE_TYPE_NOT_FOUND = 1813, ++ MD_ERROR_WIN_RESOURCE_NAME_NOT_FOUND = 1814, ++ MD_ERROR_WIN_RESOURCE_LANG_NOT_FOUND = 1815, ++ MD_ERROR_WIN_NOT_ENOUGH_QUOTA = 1816, ++ MD_ERROR_WIN_INVALID_TIME = 1901, ++ MD_ERROR_WIN_INVALID_FORM_NAME = 1902, ++ MD_ERROR_WIN_INVALID_FORM_SIZE = 1903, ++ MD_ERROR_WIN_ALREADY_WAITING = 1904, ++ MD_ERROR_WIN_PRINTER_DELETED = 1905, ++ MD_ERROR_WIN_INVALID_PRINTER_STATE = 1906, ++ MD_ERROR_WIN_PASSWORD_MUST_CHANGE = 1907, ++ MD_ERROR_WIN_DOMAIN_CONTROLLER_NOT_FOUND = 1908, ++ MD_ERROR_WIN_ACCOUNT_LOCKED_OUT = 1909, ++ MD_ERROR_WIN_NO_SITENAME = 1919, ++ MD_ERROR_WIN_CANT_ACCESS_FILE = 1920, ++ MD_ERROR_WIN_CANT_RESOLVE_FILENAME = 1921, ++ MD_ERROR_WIN_KM_DRIVER_BLOCKED = 1930, ++ MD_ERROR_WIN_CONTEXT_EXPIRED = 1931, ++ MD_ERROR_WIN_PER_USER_TRUST_QUOTA_EXCEEDED = 1932, ++ MD_ERROR_WIN_ALL_USER_TRUST_QUOTA_EXCEEDED = 1933, ++ MD_ERROR_WIN_USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934, ++ MD_ERROR_WIN_AUTHENTICATION_FIREWALL_FAILED = 1935, ++ MD_ERROR_WIN_REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936, ++ MD_ERROR_WIN_NTLM_BLOCKED = 1937, ++ MD_ERROR_WIN_PASSWORD_CHANGE_REQUIRED = 1938, ++ MD_ERROR_WIN_LOST_MODE_LOGON_RESTRICTION = 1939, ++ MD_ERROR_WIN_INVALID_PIXEL_FORMAT = 2000, ++ MD_ERROR_WIN_BAD_DRIVER = 2001, ++ MD_ERROR_WIN_INVALID_WINDOW_STYLE = 2002, ++ MD_ERROR_WIN_METAFILE_NOT_SUPPORTED = 2003, ++ MD_ERROR_WIN_TRANSFORM_NOT_SUPPORTED = 2004, ++ MD_ERROR_WIN_CLIPPING_NOT_SUPPORTED = 2005, ++ MD_ERROR_WIN_INVALID_CMM = 2010, ++ MD_ERROR_WIN_INVALID_PROFILE = 2011, ++ MD_ERROR_WIN_TAG_NOT_FOUND = 2012, ++ MD_ERROR_WIN_TAG_NOT_PRESENT = 2013, ++ MD_ERROR_WIN_DUPLICATE_TAG = 2014, ++ MD_ERROR_WIN_PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015, ++ MD_ERROR_WIN_PROFILE_NOT_FOUND = 2016, ++ MD_ERROR_WIN_INVALID_COLORSPACE = 2017, ++ MD_ERROR_WIN_ICM_NOT_ENABLED = 2018, ++ MD_ERROR_WIN_DELETING_ICM_XFORM = 2019, ++ MD_ERROR_WIN_INVALID_TRANSFORM = 2020, ++ MD_ERROR_WIN_COLORSPACE_MISMATCH = 2021, ++ MD_ERROR_WIN_INVALID_COLORINDEX = 2022, ++ MD_ERROR_WIN_PROFILE_DOES_NOT_MATCH_DEVICE = 2023, ++ MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD = 2108, ++ MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD_DEFAULT = 2109, ++ MD_ERROR_WIN_BAD_USERNAME = 2202, ++ MD_ERROR_WIN_NOT_CONNECTED = 2250, ++ MD_ERROR_WIN_OPEN_FILES = 2401, ++ MD_ERROR_WIN_ACTIVE_CONNECTIONS = 2402, ++ MD_ERROR_WIN_DEVICE_IN_USE = 2404, ++ MD_ERROR_WIN_UNKNOWN_PRINT_MONITOR = 3000, ++ MD_ERROR_WIN_PRINTER_DRIVER_IN_USE = 3001, ++ MD_ERROR_WIN_SPOOL_FILE_NOT_FOUND = 3002, ++ MD_ERROR_WIN_SPL_NO_STARTDOC = 3003, ++ MD_ERROR_WIN_SPL_NO_ADDJOB = 3004, ++ MD_ERROR_WIN_PRINT_PROCESSOR_ALREADY_INSTALLED = 3005, ++ MD_ERROR_WIN_PRINT_MONITOR_ALREADY_INSTALLED = 3006, ++ MD_ERROR_WIN_INVALID_PRINT_MONITOR = 3007, ++ MD_ERROR_WIN_PRINT_MONITOR_IN_USE = 3008, ++ MD_ERROR_WIN_PRINTER_HAS_JOBS_QUEUED = 3009, ++ MD_ERROR_WIN_SUCCESS_REBOOT_REQUIRED = 3010, ++ MD_ERROR_WIN_SUCCESS_RESTART_REQUIRED = 3011, ++ MD_ERROR_WIN_PRINTER_NOT_FOUND = 3012, ++ MD_ERROR_WIN_PRINTER_DRIVER_WARNED = 3013, ++ MD_ERROR_WIN_PRINTER_DRIVER_BLOCKED = 3014, ++ MD_ERROR_WIN_PRINTER_DRIVER_PACKAGE_IN_USE = 3015, ++ MD_ERROR_WIN_CORE_DRIVER_PACKAGE_NOT_FOUND = 3016, ++ MD_ERROR_WIN_FAIL_REBOOT_REQUIRED = 3017, ++ MD_ERROR_WIN_FAIL_REBOOT_INITIATED = 3018, ++ MD_ERROR_WIN_PRINTER_DRIVER_DOWNLOAD_NEEDED = 3019, ++ MD_ERROR_WIN_PRINT_JOB_RESTART_REQUIRED = 3020, ++ MD_ERROR_WIN_INVALID_PRINTER_DRIVER_MANIFEST = 3021, ++ MD_ERROR_WIN_PRINTER_NOT_SHAREABLE = 3022, ++ MD_ERROR_WIN_REQUEST_PAUSED = 3050, ++ MD_ERROR_WIN_APPEXEC_CONDITION_NOT_SATISFIED = 3060, ++ MD_ERROR_WIN_APPEXEC_HANDLE_INVALIDATED = 3061, ++ MD_ERROR_WIN_APPEXEC_INVALID_HOST_GENERATION = 3062, ++ MD_ERROR_WIN_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION = 3063, ++ MD_ERROR_WIN_APPEXEC_INVALID_HOST_STATE = 3064, ++ MD_ERROR_WIN_APPEXEC_NO_DONOR = 3065, ++ MD_ERROR_WIN_APPEXEC_HOST_ID_MISMATCH = 3066, ++ MD_ERROR_WIN_APPEXEC_UNKNOWN_USER = 3067, ++ MD_ERROR_WIN_IO_REISSUE_AS_CACHED = 3950, ++ MD_ERROR_WIN_WINS_INTERNAL = 4000, ++ MD_ERROR_WIN_CAN_NOT_DEL_LOCAL_WINS = 4001, ++ MD_ERROR_WIN_STATIC_INIT = 4002, ++ MD_ERROR_WIN_INC_BACKUP = 4003, ++ MD_ERROR_WIN_FULL_BACKUP = 4004, ++ MD_ERROR_WIN_REC_NON_EXISTENT = 4005, ++ MD_ERROR_WIN_RPL_NOT_ALLOWED = 4006, ++ MD_ERROR_WIN_DHCP_ADDRESS_CONFLICT = 4100, ++ MD_ERROR_WIN_WMI_GUID_NOT_FOUND = 4200, ++ MD_ERROR_WIN_WMI_INSTANCE_NOT_FOUND = 4201, ++ MD_ERROR_WIN_WMI_ITEMID_NOT_FOUND = 4202, ++ MD_ERROR_WIN_WMI_TRY_AGAIN = 4203, ++ MD_ERROR_WIN_WMI_DP_NOT_FOUND = 4204, ++ MD_ERROR_WIN_WMI_UNRESOLVED_INSTANCE_REF = 4205, ++ MD_ERROR_WIN_WMI_ALREADY_ENABLED = 4206, ++ MD_ERROR_WIN_WMI_GUID_DISCONNECTED = 4207, ++ MD_ERROR_WIN_WMI_SERVER_UNAVAILABLE = 4208, ++ MD_ERROR_WIN_WMI_DP_FAILED = 4209, ++ MD_ERROR_WIN_WMI_INVALID_MOF = 4210, ++ MD_ERROR_WIN_WMI_INVALID_REGINFO = 4211, ++ MD_ERROR_WIN_WMI_ALREADY_DISABLED = 4212, ++ MD_ERROR_WIN_WMI_READ_ONLY = 4213, ++ MD_ERROR_WIN_WMI_SET_FAILURE = 4214, ++ MD_ERROR_WIN_NOT_APPCONTAINER = 4250, ++ MD_ERROR_WIN_APPCONTAINER_REQUIRED = 4251, ++ MD_ERROR_WIN_NOT_SUPPORTED_IN_APPCONTAINER = 4252, ++ MD_ERROR_WIN_INVALID_PACKAGE_SID_LENGTH = 4253, ++ MD_ERROR_WIN_INVALID_MEDIA = 4300, ++ MD_ERROR_WIN_INVALID_LIBRARY = 4301, ++ MD_ERROR_WIN_INVALID_MEDIA_POOL = 4302, ++ MD_ERROR_WIN_DRIVE_MEDIA_MISMATCH = 4303, ++ MD_ERROR_WIN_MEDIA_OFFLINE = 4304, ++ MD_ERROR_WIN_LIBRARY_OFFLINE = 4305, ++ MD_ERROR_WIN_EMPTY = 4306, ++ MD_ERROR_WIN_NOT_EMPTY = 4307, ++ MD_ERROR_WIN_MEDIA_UNAVAILABLE = 4308, ++ MD_ERROR_WIN_RESOURCE_DISABLED = 4309, ++ MD_ERROR_WIN_INVALID_CLEANER = 4310, ++ MD_ERROR_WIN_UNABLE_TO_CLEAN = 4311, ++ MD_ERROR_WIN_OBJECT_NOT_FOUND = 4312, ++ MD_ERROR_WIN_DATABASE_FAILURE = 4313, ++ MD_ERROR_WIN_DATABASE_FULL = 4314, ++ MD_ERROR_WIN_MEDIA_INCOMPATIBLE = 4315, ++ MD_ERROR_WIN_RESOURCE_NOT_PRESENT = 4316, ++ MD_ERROR_WIN_INVALID_OPERATION = 4317, ++ MD_ERROR_WIN_MEDIA_NOT_AVAILABLE = 4318, ++ MD_ERROR_WIN_DEVICE_NOT_AVAILABLE = 4319, ++ MD_ERROR_WIN_REQUEST_REFUSED = 4320, ++ MD_ERROR_WIN_INVALID_DRIVE_OBJECT = 4321, ++ MD_ERROR_WIN_LIBRARY_FULL = 4322, ++ MD_ERROR_WIN_MEDIUM_NOT_ACCESSIBLE = 4323, ++ MD_ERROR_WIN_UNABLE_TO_LOAD_MEDIUM = 4324, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_DRIVE = 4325, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_SLOT = 4326, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_TRANSPORT = 4327, ++ MD_ERROR_WIN_TRANSPORT_FULL = 4328, ++ MD_ERROR_WIN_CONTROLLING_IEPORT = 4329, ++ MD_ERROR_WIN_UNABLE_TO_EJECT_MOUNTED_MEDIA = 4330, ++ MD_ERROR_WIN_CLEANER_SLOT_SET = 4331, ++ MD_ERROR_WIN_CLEANER_SLOT_NOT_SET = 4332, ++ MD_ERROR_WIN_CLEANER_CARTRIDGE_SPENT = 4333, ++ MD_ERROR_WIN_UNEXPECTED_OMID = 4334, ++ MD_ERROR_WIN_CANT_DELETE_LAST_ITEM = 4335, ++ MD_ERROR_WIN_MESSAGE_EXCEEDS_MAX_SIZE = 4336, ++ MD_ERROR_WIN_VOLUME_CONTAINS_SYS_FILES = 4337, ++ MD_ERROR_WIN_INDIGENOUS_TYPE = 4338, ++ MD_ERROR_WIN_NO_SUPPORTING_DRIVES = 4339, ++ MD_ERROR_WIN_CLEANER_CARTRIDGE_INSTALLED = 4340, ++ MD_ERROR_WIN_IEPORT_FULL = 4341, ++ MD_ERROR_WIN_FILE_OFFLINE = 4350, ++ MD_ERROR_WIN_REMOTE_STORAGE_NOT_ACTIVE = 4351, ++ MD_ERROR_WIN_REMOTE_STORAGE_MEDIA_ERROR = 4352, ++ MD_ERROR_WIN_NOT_A_REPARSE_POINT = 4390, ++ MD_ERROR_WIN_REPARSE_ATTRIBUTE_CONFLICT = 4391, ++ MD_ERROR_WIN_INVALID_REPARSE_DATA = 4392, ++ MD_ERROR_WIN_REPARSE_TAG_INVALID = 4393, ++ MD_ERROR_WIN_REPARSE_TAG_MISMATCH = 4394, ++ MD_ERROR_WIN_REPARSE_POINT_ENCOUNTERED = 4395, ++ MD_ERROR_WIN_APP_DATA_NOT_FOUND = 4400, ++ MD_ERROR_WIN_APP_DATA_EXPIRED = 4401, ++ MD_ERROR_WIN_APP_DATA_CORRUPT = 4402, ++ MD_ERROR_WIN_APP_DATA_LIMIT_EXCEEDED = 4403, ++ MD_ERROR_WIN_APP_DATA_REBOOT_REQUIRED = 4404, ++ MD_ERROR_WIN_SECUREBOOT_ROLLBACK_DETECTED = 4420, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_VIOLATION = 4421, ++ MD_ERROR_WIN_SECUREBOOT_INVALID_POLICY = 4422, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 4423, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_SIGNED = 4424, ++ MD_ERROR_WIN_SECUREBOOT_NOT_ENABLED = 4425, ++ MD_ERROR_WIN_SECUREBOOT_FILE_REPLACED = 4426, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_AUTHORIZED = 4427, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_UNKNOWN = 4428, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION = 4429, ++ MD_ERROR_WIN_SECUREBOOT_PLATFORM_ID_MISMATCH = 4430, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_ROLLBACK_DETECTED = 4431, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_UPGRADE_MISMATCH = 4432, ++ MD_ERROR_WIN_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING = 4433, ++ MD_ERROR_WIN_SECUREBOOT_NOT_BASE_POLICY = 4434, ++ MD_ERROR_WIN_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY = 4435, ++ MD_ERROR_WIN_OFFLOAD_READ_FLT_NOT_SUPPORTED = 4440, ++ MD_ERROR_WIN_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 4441, ++ MD_ERROR_WIN_OFFLOAD_READ_FILE_NOT_SUPPORTED = 4442, ++ MD_ERROR_WIN_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 4443, ++ MD_ERROR_WIN_ALREADY_HAS_STREAM_ID = 4444, ++ MD_ERROR_WIN_SMR_GARBAGE_COLLECTION_REQUIRED = 4445, ++ MD_ERROR_WIN_WOF_WIM_HEADER_CORRUPT = 4446, ++ MD_ERROR_WIN_WOF_WIM_RESOURCE_TABLE_CORRUPT = 4447, ++ MD_ERROR_WIN_WOF_FILE_RESOURCE_TABLE_CORRUPT = 4448, ++ MD_ERROR_WIN_VOLUME_NOT_SIS_ENABLED = 4500, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_ROLLBACK_DETECTED = 4550, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_VIOLATION = 4551, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_INVALID_POLICY = 4552, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED = 4553, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_TOO_MANY_POLICIES = 4554, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED = 4555, ++ MD_ERROR_WIN_VSM_NOT_INITIALIZED = 4560, ++ MD_ERROR_WIN_VSM_DMA_PROTECTION_NOT_IN_USE = 4561, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_AUTHORIZED = 4570, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_INVALID = 4571, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED = 4572, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED = 4573, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND = 4574, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_ACTIVE = 4575, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_SIGNED = 4576, ++ MD_ERROR_WIN_DEPENDENT_RESOURCE_EXISTS = 5001, ++ MD_ERROR_WIN_DEPENDENCY_NOT_FOUND = 5002, ++ MD_ERROR_WIN_DEPENDENCY_ALREADY_EXISTS = 5003, ++ MD_ERROR_WIN_RESOURCE_NOT_ONLINE = 5004, ++ MD_ERROR_WIN_HOST_NODE_NOT_AVAILABLE = 5005, ++ MD_ERROR_WIN_RESOURCE_NOT_AVAILABLE = 5006, ++ MD_ERROR_WIN_RESOURCE_NOT_FOUND = 5007, ++ MD_ERROR_WIN_SHUTDOWN_CLUSTER = 5008, ++ MD_ERROR_WIN_CANT_EVICT_ACTIVE_NODE = 5009, ++ MD_ERROR_WIN_OBJECT_ALREADY_EXISTS = 5010, ++ MD_ERROR_WIN_OBJECT_IN_LIST = 5011, ++ MD_ERROR_WIN_GROUP_NOT_AVAILABLE = 5012, ++ MD_ERROR_WIN_GROUP_NOT_FOUND = 5013, ++ MD_ERROR_WIN_GROUP_NOT_ONLINE = 5014, ++ MD_ERROR_WIN_HOST_NODE_NOT_RESOURCE_OWNER = 5015, ++ MD_ERROR_WIN_HOST_NODE_NOT_GROUP_OWNER = 5016, ++ MD_ERROR_WIN_RESMON_CREATE_FAILED = 5017, ++ MD_ERROR_WIN_RESMON_ONLINE_FAILED = 5018, ++ MD_ERROR_WIN_RESOURCE_ONLINE = 5019, ++ MD_ERROR_WIN_QUORUM_RESOURCE = 5020, ++ MD_ERROR_WIN_NOT_QUORUM_CAPABLE = 5021, ++ MD_ERROR_WIN_CLUSTER_SHUTTING_DOWN = 5022, ++ MD_ERROR_WIN_INVALID_STATE = 5023, ++ MD_ERROR_WIN_RESOURCE_PROPERTIES_STORED = 5024, ++ MD_ERROR_WIN_NOT_QUORUM_CLASS = 5025, ++ MD_ERROR_WIN_CORE_RESOURCE = 5026, ++ MD_ERROR_WIN_QUORUM_RESOURCE_ONLINE_FAILED = 5027, ++ MD_ERROR_WIN_QUORUMLOG_OPEN_FAILED = 5028, ++ MD_ERROR_WIN_CLUSTERLOG_CORRUPT = 5029, ++ MD_ERROR_WIN_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE = 5030, ++ MD_ERROR_WIN_CLUSTERLOG_EXCEEDS_MAXSIZE = 5031, ++ MD_ERROR_WIN_CLUSTERLOG_CHKPOINT_NOT_FOUND = 5032, ++ MD_ERROR_WIN_CLUSTERLOG_NOT_ENOUGH_SPACE = 5033, ++ MD_ERROR_WIN_QUORUM_OWNER_ALIVE = 5034, ++ MD_ERROR_WIN_NETWORK_NOT_AVAILABLE = 5035, ++ MD_ERROR_WIN_NODE_NOT_AVAILABLE = 5036, ++ MD_ERROR_WIN_ALL_NODES_NOT_AVAILABLE = 5037, ++ MD_ERROR_WIN_RESOURCE_FAILED = 5038, ++ MD_ERROR_WIN_CLUSTER_INVALID_NODE = 5039, ++ MD_ERROR_WIN_CLUSTER_NODE_EXISTS = 5040, ++ MD_ERROR_WIN_CLUSTER_JOIN_IN_PROGRESS = 5041, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_FOUND = 5042, ++ MD_ERROR_WIN_CLUSTER_LOCAL_NODE_NOT_FOUND = 5043, ++ MD_ERROR_WIN_CLUSTER_NETWORK_EXISTS = 5044, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND = 5045, ++ MD_ERROR_WIN_CLUSTER_NETINTERFACE_EXISTS = 5046, ++ MD_ERROR_WIN_CLUSTER_NETINTERFACE_NOT_FOUND = 5047, ++ MD_ERROR_WIN_CLUSTER_INVALID_REQUEST = 5048, ++ MD_ERROR_WIN_CLUSTER_INVALID_NETWORK_PROVIDER = 5049, ++ MD_ERROR_WIN_CLUSTER_NODE_DOWN = 5050, ++ MD_ERROR_WIN_CLUSTER_NODE_UNREACHABLE = 5051, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_MEMBER = 5052, ++ MD_ERROR_WIN_CLUSTER_JOIN_NOT_IN_PROGRESS = 5053, ++ MD_ERROR_WIN_CLUSTER_INVALID_NETWORK = 5054, ++ MD_ERROR_WIN_CLUSTER_NODE_UP = 5056, ++ MD_ERROR_WIN_CLUSTER_IPADDR_IN_USE = 5057, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_PAUSED = 5058, ++ MD_ERROR_WIN_CLUSTER_NO_SECURITY_CONTEXT = 5059, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_INTERNAL = 5060, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_UP = 5061, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_DOWN = 5062, ++ MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_ONLINE = 5063, ++ MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_OFFLINE = 5064, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_MEMBER = 5065, ++ MD_ERROR_WIN_CLUSTER_LAST_INTERNAL_NETWORK = 5066, ++ MD_ERROR_WIN_CLUSTER_NETWORK_HAS_DEPENDENTS = 5067, ++ MD_ERROR_WIN_INVALID_OPERATION_ON_QUORUM = 5068, ++ MD_ERROR_WIN_DEPENDENCY_NOT_ALLOWED = 5069, ++ MD_ERROR_WIN_CLUSTER_NODE_PAUSED = 5070, ++ MD_ERROR_WIN_NODE_CANT_HOST_RESOURCE = 5071, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_READY = 5072, ++ MD_ERROR_WIN_CLUSTER_NODE_SHUTTING_DOWN = 5073, ++ MD_ERROR_WIN_CLUSTER_JOIN_ABORTED = 5074, ++ MD_ERROR_WIN_CLUSTER_INCOMPATIBLE_VERSIONS = 5075, ++ MD_ERROR_WIN_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED = 5076, ++ MD_ERROR_WIN_CLUSTER_SYSTEM_CONFIG_CHANGED = 5077, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_NOT_FOUND = 5078, ++ MD_ERROR_WIN_CLUSTER_RESTYPE_NOT_SUPPORTED = 5079, ++ MD_ERROR_WIN_CLUSTER_RESNAME_NOT_FOUND = 5080, ++ MD_ERROR_WIN_CLUSTER_NO_RPC_PACKAGES_REGISTERED = 5081, ++ MD_ERROR_WIN_CLUSTER_OWNER_NOT_IN_PREFLIST = 5082, ++ MD_ERROR_WIN_CLUSTER_DATABASE_SEQMISMATCH = 5083, ++ MD_ERROR_WIN_RESMON_INVALID_STATE = 5084, ++ MD_ERROR_WIN_CLUSTER_GUM_NOT_LOCKER = 5085, ++ MD_ERROR_WIN_QUORUM_DISK_NOT_FOUND = 5086, ++ MD_ERROR_WIN_DATABASE_BACKUP_CORRUPT = 5087, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT = 5088, ++ MD_ERROR_WIN_RESOURCE_PROPERTY_UNCHANGEABLE = 5089, ++ MD_ERROR_WIN_NO_ADMIN_ACCESS_POINT = 5090, ++ MD_ERROR_WIN_CLUSTER_MEMBERSHIP_INVALID_STATE = 5890, ++ MD_ERROR_WIN_CLUSTER_QUORUMLOG_NOT_FOUND = 5891, ++ MD_ERROR_WIN_CLUSTER_MEMBERSHIP_HALT = 5892, ++ MD_ERROR_WIN_CLUSTER_INSTANCE_ID_MISMATCH = 5893, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND_FOR_IP = 5894, ++ MD_ERROR_WIN_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH = 5895, ++ MD_ERROR_WIN_CLUSTER_EVICT_WITHOUT_CLEANUP = 5896, ++ MD_ERROR_WIN_CLUSTER_PARAMETER_MISMATCH = 5897, ++ MD_ERROR_WIN_NODE_CANNOT_BE_CLUSTERED = 5898, ++ MD_ERROR_WIN_CLUSTER_WRONG_OS_VERSION = 5899, ++ MD_ERROR_WIN_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME = 5900, ++ MD_ERROR_WIN_CLUSCFG_ALREADY_COMMITTED = 5901, ++ MD_ERROR_WIN_CLUSCFG_ROLLBACK_FAILED = 5902, ++ MD_ERROR_WIN_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT = 5903, ++ MD_ERROR_WIN_CLUSTER_OLD_VERSION = 5904, ++ MD_ERROR_WIN_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME = 5905, ++ MD_ERROR_WIN_CLUSTER_NO_NET_ADAPTERS = 5906, ++ MD_ERROR_WIN_CLUSTER_POISONED = 5907, ++ MD_ERROR_WIN_CLUSTER_GROUP_MOVING = 5908, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_BUSY = 5909, ++ MD_ERROR_WIN_RESOURCE_CALL_TIMED_OUT = 5910, ++ MD_ERROR_WIN_INVALID_CLUSTER_IPV6_ADDRESS = 5911, ++ MD_ERROR_WIN_CLUSTER_INTERNAL_INVALID_FUNCTION = 5912, ++ MD_ERROR_WIN_CLUSTER_PARAMETER_OUT_OF_BOUNDS = 5913, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_SEND = 5914, ++ MD_ERROR_WIN_CLUSTER_REGISTRY_INVALID_FUNCTION = 5915, ++ MD_ERROR_WIN_CLUSTER_INVALID_STRING_TERMINATION = 5916, ++ MD_ERROR_WIN_CLUSTER_INVALID_STRING_FORMAT = 5917, ++ MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS = 5918, ++ MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS = 5919, ++ MD_ERROR_WIN_CLUSTER_NULL_DATA = 5920, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_READ = 5921, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_WRITE = 5922, ++ MD_ERROR_WIN_CLUSTER_CANT_DESERIALIZE_DATA = 5923, ++ MD_ERROR_WIN_DEPENDENT_RESOURCE_PROPERTY_CONFLICT = 5924, ++ MD_ERROR_WIN_CLUSTER_NO_QUORUM = 5925, ++ MD_ERROR_WIN_CLUSTER_INVALID_IPV6_NETWORK = 5926, ++ MD_ERROR_WIN_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK = 5927, ++ MD_ERROR_WIN_QUORUM_NOT_ALLOWED_IN_THIS_GROUP = 5928, ++ MD_ERROR_WIN_DEPENDENCY_TREE_TOO_COMPLEX = 5929, ++ MD_ERROR_WIN_EXCEPTION_IN_RESOURCE_CALL = 5930, ++ MD_ERROR_WIN_CLUSTER_RHS_FAILED_INITIALIZATION = 5931, ++ MD_ERROR_WIN_CLUSTER_NOT_INSTALLED = 5932, ++ MD_ERROR_WIN_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE = 5933, ++ MD_ERROR_WIN_CLUSTER_MAX_NODES_IN_CLUSTER = 5934, ++ MD_ERROR_WIN_CLUSTER_TOO_MANY_NODES = 5935, ++ MD_ERROR_WIN_CLUSTER_OBJECT_ALREADY_USED = 5936, ++ MD_ERROR_WIN_NONCORE_GROUPS_FOUND = 5937, ++ MD_ERROR_WIN_FILE_SHARE_RESOURCE_CONFLICT = 5938, ++ MD_ERROR_WIN_CLUSTER_EVICT_INVALID_REQUEST = 5939, ++ MD_ERROR_WIN_CLUSTER_SINGLETON_RESOURCE = 5940, ++ MD_ERROR_WIN_CLUSTER_GROUP_SINGLETON_RESOURCE = 5941, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_PROVIDER_FAILED = 5942, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_CONFIGURATION_ERROR = 5943, ++ MD_ERROR_WIN_CLUSTER_GROUP_BUSY = 5944, ++ MD_ERROR_WIN_CLUSTER_NOT_SHARED_VOLUME = 5945, ++ MD_ERROR_WIN_CLUSTER_INVALID_SECURITY_DESCRIPTOR = 5946, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUMES_IN_USE = 5947, ++ MD_ERROR_WIN_CLUSTER_USE_SHARED_VOLUMES_API = 5948, ++ MD_ERROR_WIN_CLUSTER_BACKUP_IN_PROGRESS = 5949, ++ MD_ERROR_WIN_NON_CSV_PATH = 5950, ++ MD_ERROR_WIN_CSV_VOLUME_NOT_LOCAL = 5951, ++ MD_ERROR_WIN_CLUSTER_WATCHDOG_TERMINATING = 5952, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES = 5953, ++ MD_ERROR_WIN_CLUSTER_INVALID_NODE_WEIGHT = 5954, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_CALL = 5955, ++ MD_ERROR_WIN_RESMON_SYSTEM_RESOURCES_LACKING = 5956, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION = 5957, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE = 5958, ++ MD_ERROR_WIN_CLUSTER_GROUP_QUEUED = 5959, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_LOCKED_STATUS = 5960, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED = 5961, ++ MD_ERROR_WIN_CLUSTER_NODE_DRAIN_IN_PROGRESS = 5962, ++ MD_ERROR_WIN_CLUSTER_DISK_NOT_CONNECTED = 5963, ++ MD_ERROR_WIN_DISK_NOT_CSV_CAPABLE = 5964, ++ MD_ERROR_WIN_RESOURCE_NOT_IN_AVAILABLE_STORAGE = 5965, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_REDIRECTED = 5966, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED = 5967, ++ MD_ERROR_WIN_CLUSTER_CANNOT_RETURN_PROPERTIES = 5968, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES = 5969, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE = 5970, ++ MD_ERROR_WIN_CLUSTER_AFFINITY_CONFLICT = 5971, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE = 5972, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS = 5973, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED = 5974, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_RESTART_REQUIRED = 5975, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_IN_PROGRESS = 5976, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPLETE = 5977, ++ MD_ERROR_WIN_CLUSTER_NODE_IN_GRACE_PERIOD = 5978, ++ MD_ERROR_WIN_CLUSTER_CSV_IO_PAUSE_TIMEOUT = 5979, ++ MD_ERROR_WIN_NODE_NOT_ACTIVE_CLUSTER_MEMBER = 5980, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_NOT_MONITORED = 5981, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED = 5982, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICATED = 5983, ++ MD_ERROR_WIN_CLUSTER_NODE_ISOLATED = 5984, ++ MD_ERROR_WIN_CLUSTER_NODE_QUARANTINED = 5985, ++ MD_ERROR_WIN_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED = 5986, ++ MD_ERROR_WIN_CLUSTER_SPACE_DEGRADED = 5987, ++ MD_ERROR_WIN_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED = 5988, ++ MD_ERROR_WIN_CLUSTER_CSV_INVALID_HANDLE = 5989, ++ MD_ERROR_WIN_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR = 5990, ++ MD_ERROR_WIN_GROUPSET_NOT_AVAILABLE = 5991, ++ MD_ERROR_WIN_GROUPSET_NOT_FOUND = 5992, ++ MD_ERROR_WIN_GROUPSET_CANT_PROVIDE = 5993, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND = 5994, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY = 5995, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION = 5996, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS = 5997, ++ MD_ERROR_WIN_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME = 5998, ++ MD_ERROR_WIN_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE = 5999, ++ MD_ERROR_WIN_ENCRYPTION_FAILED = 6000, ++ MD_ERROR_WIN_DECRYPTION_FAILED = 6001, ++ MD_ERROR_WIN_FILE_ENCRYPTED = 6002, ++ MD_ERROR_WIN_NO_RECOVERY_POLICY = 6003, ++ MD_ERROR_WIN_NO_EFS = 6004, ++ MD_ERROR_WIN_WRONG_EFS = 6005, ++ MD_ERROR_WIN_NO_USER_KEYS = 6006, ++ MD_ERROR_WIN_FILE_NOT_ENCRYPTED = 6007, ++ MD_ERROR_WIN_NOT_EXPORT_FORMAT = 6008, ++ MD_ERROR_WIN_FILE_READ_ONLY = 6009, ++ MD_ERROR_WIN_DIR_EFS_DISALLOWED = 6010, ++ MD_ERROR_WIN_EFS_SERVER_NOT_TRUSTED = 6011, ++ MD_ERROR_WIN_BAD_RECOVERY_POLICY = 6012, ++ MD_ERROR_WIN_EFS_ALG_BLOB_TOO_BIG = 6013, ++ MD_ERROR_WIN_VOLUME_NOT_SUPPORT_EFS = 6014, ++ MD_ERROR_WIN_EFS_DISABLED = 6015, ++ MD_ERROR_WIN_EFS_VERSION_NOT_SUPPORT = 6016, ++ MD_ERROR_WIN_CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 6017, ++ MD_ERROR_WIN_CS_ENCRYPTION_UNSUPPORTED_SERVER = 6018, ++ MD_ERROR_WIN_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 6019, ++ MD_ERROR_WIN_CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 6020, ++ MD_ERROR_WIN_CS_ENCRYPTION_FILE_NOT_CSE = 6021, ++ MD_ERROR_WIN_ENCRYPTION_POLICY_DENIES_OPERATION = 6022, ++ MD_ERROR_WIN_WIP_ENCRYPTION_FAILED = 6023, ++ MD_ERROR_WIN_NO_BROWSER_SERVERS_FOUND = 6118, ++ MD_ERROR_WIN_CLUSTER_OBJECT_IS_CLUSTER_SET_VM = 6250, ++ MD_ERROR_WIN_LOG_SECTOR_INVALID = 6600, ++ MD_ERROR_WIN_LOG_SECTOR_PARITY_INVALID = 6601, ++ MD_ERROR_WIN_LOG_SECTOR_REMAPPED = 6602, ++ MD_ERROR_WIN_LOG_BLOCK_INCOMPLETE = 6603, ++ MD_ERROR_WIN_LOG_INVALID_RANGE = 6604, ++ MD_ERROR_WIN_LOG_BLOCKS_EXHAUSTED = 6605, ++ MD_ERROR_WIN_LOG_READ_CONTEXT_INVALID = 6606, ++ MD_ERROR_WIN_LOG_RESTART_INVALID = 6607, ++ MD_ERROR_WIN_LOG_BLOCK_VERSION = 6608, ++ MD_ERROR_WIN_LOG_BLOCK_INVALID = 6609, ++ MD_ERROR_WIN_LOG_READ_MODE_INVALID = 6610, ++ MD_ERROR_WIN_LOG_NO_RESTART = 6611, ++ MD_ERROR_WIN_LOG_METADATA_CORRUPT = 6612, ++ MD_ERROR_WIN_LOG_METADATA_INVALID = 6613, ++ MD_ERROR_WIN_LOG_METADATA_INCONSISTENT = 6614, ++ MD_ERROR_WIN_LOG_RESERVATION_INVALID = 6615, ++ MD_ERROR_WIN_LOG_CANT_DELETE = 6616, ++ MD_ERROR_WIN_LOG_CONTAINER_LIMIT_EXCEEDED = 6617, ++ MD_ERROR_WIN_LOG_START_OF_LOG = 6618, ++ MD_ERROR_WIN_LOG_POLICY_ALREADY_INSTALLED = 6619, ++ MD_ERROR_WIN_LOG_POLICY_NOT_INSTALLED = 6620, ++ MD_ERROR_WIN_LOG_POLICY_INVALID = 6621, ++ MD_ERROR_WIN_LOG_POLICY_CONFLICT = 6622, ++ MD_ERROR_WIN_LOG_PINNED_ARCHIVE_TAIL = 6623, ++ MD_ERROR_WIN_LOG_RECORD_NONEXISTENT = 6624, ++ MD_ERROR_WIN_LOG_RECORDS_RESERVED_INVALID = 6625, ++ MD_ERROR_WIN_LOG_SPACE_RESERVED_INVALID = 6626, ++ MD_ERROR_WIN_LOG_TAIL_INVALID = 6627, ++ MD_ERROR_WIN_LOG_FULL = 6628, ++ MD_ERROR_WIN_COULD_NOT_RESIZE_LOG = 6629, ++ MD_ERROR_WIN_LOG_MULTIPLEXED = 6630, ++ MD_ERROR_WIN_LOG_DEDICATED = 6631, ++ MD_ERROR_WIN_LOG_ARCHIVE_NOT_IN_PROGRESS = 6632, ++ MD_ERROR_WIN_LOG_ARCHIVE_IN_PROGRESS = 6633, ++ MD_ERROR_WIN_LOG_EPHEMERAL = 6634, ++ MD_ERROR_WIN_LOG_NOT_ENOUGH_CONTAINERS = 6635, ++ MD_ERROR_WIN_LOG_CLIENT_ALREADY_REGISTERED = 6636, ++ MD_ERROR_WIN_LOG_CLIENT_NOT_REGISTERED = 6637, ++ MD_ERROR_WIN_LOG_FULL_HANDLER_IN_PROGRESS = 6638, ++ MD_ERROR_WIN_LOG_CONTAINER_READ_FAILED = 6639, ++ MD_ERROR_WIN_LOG_CONTAINER_WRITE_FAILED = 6640, ++ MD_ERROR_WIN_LOG_CONTAINER_OPEN_FAILED = 6641, ++ MD_ERROR_WIN_LOG_CONTAINER_STATE_INVALID = 6642, ++ MD_ERROR_WIN_LOG_STATE_INVALID = 6643, ++ MD_ERROR_WIN_LOG_PINNED = 6644, ++ MD_ERROR_WIN_LOG_METADATA_FLUSH_FAILED = 6645, ++ MD_ERROR_WIN_LOG_INCONSISTENT_SECURITY = 6646, ++ MD_ERROR_WIN_LOG_APPENDED_FLUSH_FAILED = 6647, ++ MD_ERROR_WIN_LOG_PINNED_RESERVATION = 6648, ++ MD_ERROR_WIN_INVALID_TRANSACTION = 6700, ++ MD_ERROR_WIN_TRANSACTION_NOT_ACTIVE = 6701, ++ MD_ERROR_WIN_TRANSACTION_REQUEST_NOT_VALID = 6702, ++ MD_ERROR_WIN_TRANSACTION_NOT_REQUESTED = 6703, ++ MD_ERROR_WIN_TRANSACTION_ALREADY_ABORTED = 6704, ++ MD_ERROR_WIN_TRANSACTION_ALREADY_COMMITTED = 6705, ++ MD_ERROR_WIN_TM_INITIALIZATION_FAILED = 6706, ++ MD_ERROR_WIN_RESOURCEMANAGER_READ_ONLY = 6707, ++ MD_ERROR_WIN_TRANSACTION_NOT_JOINED = 6708, ++ MD_ERROR_WIN_TRANSACTION_SUPERIOR_EXISTS = 6709, ++ MD_ERROR_WIN_CRM_PROTOCOL_ALREADY_EXISTS = 6710, ++ MD_ERROR_WIN_TRANSACTION_PROPAGATION_FAILED = 6711, ++ MD_ERROR_WIN_CRM_PROTOCOL_NOT_FOUND = 6712, ++ MD_ERROR_WIN_TRANSACTION_INVALID_MARSHALL_BUFFER = 6713, ++ MD_ERROR_WIN_CURRENT_TRANSACTION_NOT_VALID = 6714, ++ MD_ERROR_WIN_TRANSACTION_NOT_FOUND = 6715, ++ MD_ERROR_WIN_RESOURCEMANAGER_NOT_FOUND = 6716, ++ MD_ERROR_WIN_ENLISTMENT_NOT_FOUND = 6717, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_FOUND = 6718, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_ONLINE = 6719, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 6720, ++ MD_ERROR_WIN_TRANSACTION_NOT_ROOT = 6721, ++ MD_ERROR_WIN_TRANSACTION_OBJECT_EXPIRED = 6722, ++ MD_ERROR_WIN_TRANSACTION_RESPONSE_NOT_ENLISTED = 6723, ++ MD_ERROR_WIN_TRANSACTION_RECORD_TOO_LONG = 6724, ++ MD_ERROR_WIN_IMPLICIT_TRANSACTION_NOT_SUPPORTED = 6725, ++ MD_ERROR_WIN_TRANSACTION_INTEGRITY_VIOLATED = 6726, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_IDENTITY_MISMATCH = 6727, ++ MD_ERROR_WIN_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT = 6728, ++ MD_ERROR_WIN_TRANSACTION_MUST_WRITETHROUGH = 6729, ++ MD_ERROR_WIN_TRANSACTION_NO_SUPERIOR = 6730, ++ MD_ERROR_WIN_HEURISTIC_DAMAGE_POSSIBLE = 6731, ++ MD_ERROR_WIN_TRANSACTIONAL_CONFLICT = 6800, ++ MD_ERROR_WIN_RM_NOT_ACTIVE = 6801, ++ MD_ERROR_WIN_RM_METADATA_CORRUPT = 6802, ++ MD_ERROR_WIN_DIRECTORY_NOT_RM = 6803, ++ MD_ERROR_WIN_TRANSACTIONS_UNSUPPORTED_REMOTE = 6805, ++ MD_ERROR_WIN_LOG_RESIZE_INVALID_SIZE = 6806, ++ MD_ERROR_WIN_OBJECT_NO_LONGER_EXISTS = 6807, ++ MD_ERROR_WIN_STREAM_MINIVERSION_NOT_FOUND = 6808, ++ MD_ERROR_WIN_STREAM_MINIVERSION_NOT_VALID = 6809, ++ MD_ERROR_WIN_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 6810, ++ MD_ERROR_WIN_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 6811, ++ MD_ERROR_WIN_CANT_CREATE_MORE_STREAM_MINIVERSIONS = 6812, ++ MD_ERROR_WIN_REMOTE_FILE_VERSION_MISMATCH = 6814, ++ MD_ERROR_WIN_HANDLE_NO_LONGER_VALID = 6815, ++ MD_ERROR_WIN_NO_TXF_METADATA = 6816, ++ MD_ERROR_WIN_LOG_CORRUPTION_DETECTED = 6817, ++ MD_ERROR_WIN_CANT_RECOVER_WITH_HANDLE_OPEN = 6818, ++ MD_ERROR_WIN_RM_DISCONNECTED = 6819, ++ MD_ERROR_WIN_ENLISTMENT_NOT_SUPERIOR = 6820, ++ MD_ERROR_WIN_RECOVERY_NOT_NEEDED = 6821, ++ MD_ERROR_WIN_RM_ALREADY_STARTED = 6822, ++ MD_ERROR_WIN_FILE_IDENTITY_NOT_PERSISTENT = 6823, ++ MD_ERROR_WIN_CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 6824, ++ MD_ERROR_WIN_CANT_CROSS_RM_BOUNDARY = 6825, ++ MD_ERROR_WIN_TXF_DIR_NOT_EMPTY = 6826, ++ MD_ERROR_WIN_INDOUBT_TRANSACTIONS_EXIST = 6827, ++ MD_ERROR_WIN_TM_VOLATILE = 6828, ++ MD_ERROR_WIN_ROLLBACK_TIMER_EXPIRED = 6829, ++ MD_ERROR_WIN_TXF_ATTRIBUTE_CORRUPT = 6830, ++ MD_ERROR_WIN_EFS_NOT_ALLOWED_IN_TRANSACTION = 6831, ++ MD_ERROR_WIN_TRANSACTIONAL_OPEN_NOT_ALLOWED = 6832, ++ MD_ERROR_WIN_LOG_GROWTH_FAILED = 6833, ++ MD_ERROR_WIN_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 6834, ++ MD_ERROR_WIN_TXF_METADATA_ALREADY_PRESENT = 6835, ++ MD_ERROR_WIN_TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 6836, ++ MD_ERROR_WIN_TRANSACTION_REQUIRED_PROMOTION = 6837, ++ MD_ERROR_WIN_CANNOT_EXECUTE_FILE_IN_TRANSACTION = 6838, ++ MD_ERROR_WIN_TRANSACTIONS_NOT_FROZEN = 6839, ++ MD_ERROR_WIN_TRANSACTION_FREEZE_IN_PROGRESS = 6840, ++ MD_ERROR_WIN_NOT_SNAPSHOT_VOLUME = 6841, ++ MD_ERROR_WIN_NO_SAVEPOINT_WITH_OPEN_FILES = 6842, ++ MD_ERROR_WIN_DATA_LOST_REPAIR = 6843, ++ MD_ERROR_WIN_SPARSE_NOT_ALLOWED_IN_TRANSACTION = 6844, ++ MD_ERROR_WIN_TM_IDENTITY_MISMATCH = 6845, ++ MD_ERROR_WIN_FLOATED_SECTION = 6846, ++ MD_ERROR_WIN_CANNOT_ACCEPT_TRANSACTED_WORK = 6847, ++ MD_ERROR_WIN_CANNOT_ABORT_TRANSACTIONS = 6848, ++ MD_ERROR_WIN_BAD_CLUSTERS = 6849, ++ MD_ERROR_WIN_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 6850, ++ MD_ERROR_WIN_VOLUME_DIRTY = 6851, ++ MD_ERROR_WIN_NO_LINK_TRACKING_IN_TRANSACTION = 6852, ++ MD_ERROR_WIN_OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 6853, ++ MD_ERROR_WIN_EXPIRED_HANDLE = 6854, ++ MD_ERROR_WIN_TRANSACTION_NOT_ENLISTED = 6855, ++ MD_ERROR_WIN_CTX_WINSTATION_NAME_INVALID = 7001, ++ MD_ERROR_WIN_CTX_INVALID_PD = 7002, ++ MD_ERROR_WIN_CTX_PD_NOT_FOUND = 7003, ++ MD_ERROR_WIN_CTX_WD_NOT_FOUND = 7004, ++ MD_ERROR_WIN_CTX_CANNOT_MAKE_EVENTLOG_ENTRY = 7005, ++ MD_ERROR_WIN_CTX_SERVICE_NAME_COLLISION = 7006, ++ MD_ERROR_WIN_CTX_CLOSE_PENDING = 7007, ++ MD_ERROR_WIN_CTX_NO_OUTBUF = 7008, ++ MD_ERROR_WIN_CTX_MODEM_INF_NOT_FOUND = 7009, ++ MD_ERROR_WIN_CTX_INVALID_MODEMNAME = 7010, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_ERROR = 7011, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_TIMEOUT = 7012, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_CARRIER = 7013, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_DIALTONE = 7014, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_BUSY = 7015, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_VOICE = 7016, ++ MD_ERROR_WIN_CTX_TD_ERROR = 7017, ++ MD_ERROR_WIN_CTX_WINSTATION_NOT_FOUND = 7022, ++ MD_ERROR_WIN_CTX_WINSTATION_ALREADY_EXISTS = 7023, ++ MD_ERROR_WIN_CTX_WINSTATION_BUSY = 7024, ++ MD_ERROR_WIN_CTX_BAD_VIDEO_MODE = 7025, ++ MD_ERROR_WIN_CTX_GRAPHICS_INVALID = 7035, ++ MD_ERROR_WIN_CTX_LOGON_DISABLED = 7037, ++ MD_ERROR_WIN_CTX_NOT_CONSOLE = 7038, ++ MD_ERROR_WIN_CTX_CLIENT_QUERY_TIMEOUT = 7040, ++ MD_ERROR_WIN_CTX_CONSOLE_DISCONNECT = 7041, ++ MD_ERROR_WIN_CTX_CONSOLE_CONNECT = 7042, ++ MD_ERROR_WIN_CTX_SHADOW_DENIED = 7044, ++ MD_ERROR_WIN_CTX_WINSTATION_ACCESS_DENIED = 7045, ++ MD_ERROR_WIN_CTX_INVALID_WD = 7049, ++ MD_ERROR_WIN_CTX_SHADOW_INVALID = 7050, ++ MD_ERROR_WIN_CTX_SHADOW_DISABLED = 7051, ++ MD_ERROR_WIN_CTX_CLIENT_LICENSE_IN_USE = 7052, ++ MD_ERROR_WIN_CTX_CLIENT_LICENSE_NOT_SET = 7053, ++ MD_ERROR_WIN_CTX_LICENSE_NOT_AVAILABLE = 7054, ++ MD_ERROR_WIN_CTX_LICENSE_CLIENT_INVALID = 7055, ++ MD_ERROR_WIN_CTX_LICENSE_EXPIRED = 7056, ++ MD_ERROR_WIN_CTX_SHADOW_NOT_RUNNING = 7057, ++ MD_ERROR_WIN_CTX_SHADOW_ENDED_BY_MODE_CHANGE = 7058, ++ MD_ERROR_WIN_ACTIVATION_COUNT_EXCEEDED = 7059, ++ MD_ERROR_WIN_CTX_WINSTATIONS_DISABLED = 7060, ++ MD_ERROR_WIN_CTX_ENCRYPTION_LEVEL_REQUIRED = 7061, ++ MD_ERROR_WIN_CTX_SESSION_IN_USE = 7062, ++ MD_ERROR_WIN_CTX_NO_FORCE_LOGOFF = 7063, ++ MD_ERROR_WIN_CTX_ACCOUNT_RESTRICTION = 7064, ++ MD_ERROR_WIN_RDP_PROTOCOL_ERROR = 7065, ++ MD_ERROR_WIN_CTX_CDM_CONNECT = 7066, ++ MD_ERROR_WIN_CTX_CDM_DISCONNECT = 7067, ++ MD_ERROR_WIN_CTX_SECURITY_LAYER_ERROR = 7068, ++ MD_ERROR_WIN_TS_INCOMPATIBLE_SESSIONS = 7069, ++ MD_ERROR_WIN_TS_VIDEO_SUBSYSTEM_ERROR = 7070, ++ MD_ERROR_WIN_DS_NOT_INSTALLED = 8200, ++ MD_ERROR_WIN_DS_MEMBERSHIP_EVALUATED_LOCALLY = 8201, ++ MD_ERROR_WIN_DS_NO_ATTRIBUTE_OR_VALUE = 8202, ++ MD_ERROR_WIN_DS_INVALID_ATTRIBUTE_SYNTAX = 8203, ++ MD_ERROR_WIN_DS_ATTRIBUTE_TYPE_UNDEFINED = 8204, ++ MD_ERROR_WIN_DS_ATTRIBUTE_OR_VALUE_EXISTS = 8205, ++ MD_ERROR_WIN_DS_BUSY = 8206, ++ MD_ERROR_WIN_DS_UNAVAILABLE = 8207, ++ MD_ERROR_WIN_DS_NO_RIDS_ALLOCATED = 8208, ++ MD_ERROR_WIN_DS_NO_MORE_RIDS = 8209, ++ MD_ERROR_WIN_DS_INCORRECT_ROLE_OWNER = 8210, ++ MD_ERROR_WIN_DS_RIDMGR_INIT_ERROR = 8211, ++ MD_ERROR_WIN_DS_OBJ_CLASS_VIOLATION = 8212, ++ MD_ERROR_WIN_DS_CANT_ON_NON_LEAF = 8213, ++ MD_ERROR_WIN_DS_CANT_ON_RDN = 8214, ++ MD_ERROR_WIN_DS_CANT_MOD_OBJ_CLASS = 8215, ++ MD_ERROR_WIN_DS_CROSS_DOM_MOVE_ERROR = 8216, ++ MD_ERROR_WIN_DS_GC_NOT_AVAILABLE = 8217, ++ MD_ERROR_WIN_SHARED_POLICY = 8218, ++ MD_ERROR_WIN_POLICY_OBJECT_NOT_FOUND = 8219, ++ MD_ERROR_WIN_POLICY_ONLY_IN_DS = 8220, ++ MD_ERROR_WIN_PROMOTION_ACTIVE = 8221, ++ MD_ERROR_WIN_NO_PROMOTION_ACTIVE = 8222, ++ MD_ERROR_WIN_DS_OPERATIONS_ERROR = 8224, ++ MD_ERROR_WIN_DS_PROTOCOL_ERROR = 8225, ++ MD_ERROR_WIN_DS_TIMELIMIT_EXCEEDED = 8226, ++ MD_ERROR_WIN_DS_SIZELIMIT_EXCEEDED = 8227, ++ MD_ERROR_WIN_DS_ADMIN_LIMIT_EXCEEDED = 8228, ++ MD_ERROR_WIN_DS_COMPARE_FALSE = 8229, ++ MD_ERROR_WIN_DS_COMPARE_TRUE = 8230, ++ MD_ERROR_WIN_DS_AUTH_METHOD_NOT_SUPPORTED = 8231, ++ MD_ERROR_WIN_DS_STRONG_AUTH_REQUIRED = 8232, ++ MD_ERROR_WIN_DS_INAPPROPRIATE_AUTH = 8233, ++ MD_ERROR_WIN_DS_AUTH_UNKNOWN = 8234, ++ MD_ERROR_WIN_DS_REFERRAL = 8235, ++ MD_ERROR_WIN_DS_UNAVAILABLE_CRIT_EXTENSION = 8236, ++ MD_ERROR_WIN_DS_CONFIDENTIALITY_REQUIRED = 8237, ++ MD_ERROR_WIN_DS_INAPPROPRIATE_MATCHING = 8238, ++ MD_ERROR_WIN_DS_CONSTRAINT_VIOLATION = 8239, ++ MD_ERROR_WIN_DS_NO_SUCH_OBJECT = 8240, ++ MD_ERROR_WIN_DS_ALIAS_PROBLEM = 8241, ++ MD_ERROR_WIN_DS_INVALID_DN_SYNTAX = 8242, ++ MD_ERROR_WIN_DS_IS_LEAF = 8243, ++ MD_ERROR_WIN_DS_ALIAS_DEREF_PROBLEM = 8244, ++ MD_ERROR_WIN_DS_UNWILLING_TO_PERFORM = 8245, ++ MD_ERROR_WIN_DS_LOOP_DETECT = 8246, ++ MD_ERROR_WIN_DS_NAMING_VIOLATION = 8247, ++ MD_ERROR_WIN_DS_OBJECT_RESULTS_TOO_LARGE = 8248, ++ MD_ERROR_WIN_DS_AFFECTS_MULTIPLE_DSAS = 8249, ++ MD_ERROR_WIN_DS_SERVER_DOWN = 8250, ++ MD_ERROR_WIN_DS_LOCAL_ERROR = 8251, ++ MD_ERROR_WIN_DS_ENCODING_ERROR = 8252, ++ MD_ERROR_WIN_DS_DECODING_ERROR = 8253, ++ MD_ERROR_WIN_DS_FILTER_UNKNOWN = 8254, ++ MD_ERROR_WIN_DS_PARAM_ERROR = 8255, ++ MD_ERROR_WIN_DS_NOT_SUPPORTED = 8256, ++ MD_ERROR_WIN_DS_NO_RESULTS_RETURNED = 8257, ++ MD_ERROR_WIN_DS_CONTROL_NOT_FOUND = 8258, ++ MD_ERROR_WIN_DS_CLIENT_LOOP = 8259, ++ MD_ERROR_WIN_DS_REFERRAL_LIMIT_EXCEEDED = 8260, ++ MD_ERROR_WIN_DS_SORT_CONTROL_MISSING = 8261, ++ MD_ERROR_WIN_DS_OFFSET_RANGE_ERROR = 8262, ++ MD_ERROR_WIN_DS_RIDMGR_DISABLED = 8263, ++ MD_ERROR_WIN_DS_ROOT_MUST_BE_NC = 8301, ++ MD_ERROR_WIN_DS_ADD_REPLICA_INHIBITED = 8302, ++ MD_ERROR_WIN_DS_ATT_NOT_DEF_IN_SCHEMA = 8303, ++ MD_ERROR_WIN_DS_MAX_OBJ_SIZE_EXCEEDED = 8304, ++ MD_ERROR_WIN_DS_OBJ_STRING_NAME_EXISTS = 8305, ++ MD_ERROR_WIN_DS_NO_RDN_DEFINED_IN_SCHEMA = 8306, ++ MD_ERROR_WIN_DS_RDN_DOESNT_MATCH_SCHEMA = 8307, ++ MD_ERROR_WIN_DS_NO_REQUESTED_ATTS_FOUND = 8308, ++ MD_ERROR_WIN_DS_USER_BUFFER_TO_SMALL = 8309, ++ MD_ERROR_WIN_DS_ATT_IS_NOT_ON_OBJ = 8310, ++ MD_ERROR_WIN_DS_ILLEGAL_MOD_OPERATION = 8311, ++ MD_ERROR_WIN_DS_OBJ_TOO_LARGE = 8312, ++ MD_ERROR_WIN_DS_BAD_INSTANCE_TYPE = 8313, ++ MD_ERROR_WIN_DS_MASTERDSA_REQUIRED = 8314, ++ MD_ERROR_WIN_DS_OBJECT_CLASS_REQUIRED = 8315, ++ MD_ERROR_WIN_DS_MISSING_REQUIRED_ATT = 8316, ++ MD_ERROR_WIN_DS_ATT_NOT_DEF_FOR_CLASS = 8317, ++ MD_ERROR_WIN_DS_ATT_ALREADY_EXISTS = 8318, ++ MD_ERROR_WIN_DS_CANT_ADD_ATT_VALUES = 8320, ++ MD_ERROR_WIN_DS_SINGLE_VALUE_CONSTRAINT = 8321, ++ MD_ERROR_WIN_DS_RANGE_CONSTRAINT = 8322, ++ MD_ERROR_WIN_DS_ATT_VAL_ALREADY_EXISTS = 8323, ++ MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT = 8324, ++ MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT_VAL = 8325, ++ MD_ERROR_WIN_DS_ROOT_CANT_BE_SUBREF = 8326, ++ MD_ERROR_WIN_DS_NO_CHAINING = 8327, ++ MD_ERROR_WIN_DS_NO_CHAINED_EVAL = 8328, ++ MD_ERROR_WIN_DS_NO_PARENT_OBJECT = 8329, ++ MD_ERROR_WIN_DS_PARENT_IS_AN_ALIAS = 8330, ++ MD_ERROR_WIN_DS_CANT_MIX_MASTER_AND_REPS = 8331, ++ MD_ERROR_WIN_DS_CHILDREN_EXIST = 8332, ++ MD_ERROR_WIN_DS_OBJ_NOT_FOUND = 8333, ++ MD_ERROR_WIN_DS_ALIASED_OBJ_MISSING = 8334, ++ MD_ERROR_WIN_DS_BAD_NAME_SYNTAX = 8335, ++ MD_ERROR_WIN_DS_ALIAS_POINTS_TO_ALIAS = 8336, ++ MD_ERROR_WIN_DS_CANT_DEREF_ALIAS = 8337, ++ MD_ERROR_WIN_DS_OUT_OF_SCOPE = 8338, ++ MD_ERROR_WIN_DS_OBJECT_BEING_REMOVED = 8339, ++ MD_ERROR_WIN_DS_CANT_DELETE_DSA_OBJ = 8340, ++ MD_ERROR_WIN_DS_GENERIC_ERROR = 8341, ++ MD_ERROR_WIN_DS_DSA_MUST_BE_INT_MASTER = 8342, ++ MD_ERROR_WIN_DS_CLASS_NOT_DSA = 8343, ++ MD_ERROR_WIN_DS_INSUFF_ACCESS_RIGHTS = 8344, ++ MD_ERROR_WIN_DS_ILLEGAL_SUPERIOR = 8345, ++ MD_ERROR_WIN_DS_ATTRIBUTE_OWNED_BY_SAM = 8346, ++ MD_ERROR_WIN_DS_NAME_TOO_MANY_PARTS = 8347, ++ MD_ERROR_WIN_DS_NAME_TOO_LONG = 8348, ++ MD_ERROR_WIN_DS_NAME_VALUE_TOO_LONG = 8349, ++ MD_ERROR_WIN_DS_NAME_UNPARSEABLE = 8350, ++ MD_ERROR_WIN_DS_NAME_TYPE_UNKNOWN = 8351, ++ MD_ERROR_WIN_DS_NOT_AN_OBJECT = 8352, ++ MD_ERROR_WIN_DS_SEC_DESC_TOO_SHORT = 8353, ++ MD_ERROR_WIN_DS_SEC_DESC_INVALID = 8354, ++ MD_ERROR_WIN_DS_NO_DELETED_NAME = 8355, ++ MD_ERROR_WIN_DS_SUBREF_MUST_HAVE_PARENT = 8356, ++ MD_ERROR_WIN_DS_NCNAME_MUST_BE_NC = 8357, ++ MD_ERROR_WIN_DS_CANT_ADD_SYSTEM_ONLY = 8358, ++ MD_ERROR_WIN_DS_CLASS_MUST_BE_CONCRETE = 8359, ++ MD_ERROR_WIN_DS_INVALID_DMD = 8360, ++ MD_ERROR_WIN_DS_OBJ_GUID_EXISTS = 8361, ++ MD_ERROR_WIN_DS_NOT_ON_BACKLINK = 8362, ++ MD_ERROR_WIN_DS_NO_CROSSREF_FOR_NC = 8363, ++ MD_ERROR_WIN_DS_SHUTTING_DOWN = 8364, ++ MD_ERROR_WIN_DS_UNKNOWN_OPERATION = 8365, ++ MD_ERROR_WIN_DS_INVALID_ROLE_OWNER = 8366, ++ MD_ERROR_WIN_DS_COULDNT_CONTACT_FSMO = 8367, ++ MD_ERROR_WIN_DS_CROSS_NC_DN_RENAME = 8368, ++ MD_ERROR_WIN_DS_CANT_MOD_SYSTEM_ONLY = 8369, ++ MD_ERROR_WIN_DS_REPLICATOR_ONLY = 8370, ++ MD_ERROR_WIN_DS_OBJ_CLASS_NOT_DEFINED = 8371, ++ MD_ERROR_WIN_DS_OBJ_CLASS_NOT_SUBCLASS = 8372, ++ MD_ERROR_WIN_DS_NAME_REFERENCE_INVALID = 8373, ++ MD_ERROR_WIN_DS_CROSS_REF_EXISTS = 8374, ++ MD_ERROR_WIN_DS_CANT_DEL_MASTER_CROSSREF = 8375, ++ MD_ERROR_WIN_DS_SUBTREE_NOTIFY_NOT_NC_HEAD = 8376, ++ MD_ERROR_WIN_DS_NOTIFY_FILTER_TOO_COMPLEX = 8377, ++ MD_ERROR_WIN_DS_DUP_RDN = 8378, ++ MD_ERROR_WIN_DS_DUP_OID = 8379, ++ MD_ERROR_WIN_DS_DUP_MAPI_ID = 8380, ++ MD_ERROR_WIN_DS_DUP_SCHEMA_ID_GUID = 8381, ++ MD_ERROR_WIN_DS_DUP_LDAP_DISPLAY_NAME = 8382, ++ MD_ERROR_WIN_DS_SEMANTIC_ATT_TEST = 8383, ++ MD_ERROR_WIN_DS_SYNTAX_MISMATCH = 8384, ++ MD_ERROR_WIN_DS_EXISTS_IN_MUST_HAVE = 8385, ++ MD_ERROR_WIN_DS_EXISTS_IN_MAY_HAVE = 8386, ++ MD_ERROR_WIN_DS_NONEXISTENT_MAY_HAVE = 8387, ++ MD_ERROR_WIN_DS_NONEXISTENT_MUST_HAVE = 8388, ++ MD_ERROR_WIN_DS_AUX_CLS_TEST_FAIL = 8389, ++ MD_ERROR_WIN_DS_NONEXISTENT_POSS_SUP = 8390, ++ MD_ERROR_WIN_DS_SUB_CLS_TEST_FAIL = 8391, ++ MD_ERROR_WIN_DS_BAD_RDN_ATT_ID_SYNTAX = 8392, ++ MD_ERROR_WIN_DS_EXISTS_IN_AUX_CLS = 8393, ++ MD_ERROR_WIN_DS_EXISTS_IN_SUB_CLS = 8394, ++ MD_ERROR_WIN_DS_EXISTS_IN_POSS_SUP = 8395, ++ MD_ERROR_WIN_DS_RECALCSCHEMA_FAILED = 8396, ++ MD_ERROR_WIN_DS_TREE_DELETE_NOT_FINISHED = 8397, ++ MD_ERROR_WIN_DS_CANT_DELETE = 8398, ++ MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_ID = 8399, ++ MD_ERROR_WIN_DS_BAD_ATT_SCHEMA_SYNTAX = 8400, ++ MD_ERROR_WIN_DS_CANT_CACHE_ATT = 8401, ++ MD_ERROR_WIN_DS_CANT_CACHE_CLASS = 8402, ++ MD_ERROR_WIN_DS_CANT_REMOVE_ATT_CACHE = 8403, ++ MD_ERROR_WIN_DS_CANT_REMOVE_CLASS_CACHE = 8404, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_DN = 8405, ++ MD_ERROR_WIN_DS_MISSING_SUPREF = 8406, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_INSTANCE = 8407, ++ MD_ERROR_WIN_DS_CODE_INCONSISTENCY = 8408, ++ MD_ERROR_WIN_DS_DATABASE_ERROR = 8409, ++ MD_ERROR_WIN_DS_GOVERNSID_MISSING = 8410, ++ MD_ERROR_WIN_DS_MISSING_EXPECTED_ATT = 8411, ++ MD_ERROR_WIN_DS_NCNAME_MISSING_CR_REF = 8412, ++ MD_ERROR_WIN_DS_SECURITY_CHECKING_ERROR = 8413, ++ MD_ERROR_WIN_DS_SCHEMA_NOT_LOADED = 8414, ++ MD_ERROR_WIN_DS_SCHEMA_ALLOC_FAILED = 8415, ++ MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_SYNTAX = 8416, ++ MD_ERROR_WIN_DS_GCVERIFY_ERROR = 8417, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_MISMATCH = 8418, ++ MD_ERROR_WIN_DS_CANT_FIND_DSA_OBJ = 8419, ++ MD_ERROR_WIN_DS_CANT_FIND_EXPECTED_NC = 8420, ++ MD_ERROR_WIN_DS_CANT_FIND_NC_IN_CACHE = 8421, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_CHILD = 8422, ++ MD_ERROR_WIN_DS_SECURITY_ILLEGAL_MODIFY = 8423, ++ MD_ERROR_WIN_DS_CANT_REPLACE_HIDDEN_REC = 8424, ++ MD_ERROR_WIN_DS_BAD_HIERARCHY_FILE = 8425, ++ MD_ERROR_WIN_DS_BUILD_HIERARCHY_TABLE_FAILED = 8426, ++ MD_ERROR_WIN_DS_CONFIG_PARAM_MISSING = 8427, ++ MD_ERROR_WIN_DS_COUNTING_AB_INDICES_FAILED = 8428, ++ MD_ERROR_WIN_DS_HIERARCHY_TABLE_MALLOC_FAILED = 8429, ++ MD_ERROR_WIN_DS_INTERNAL_FAILURE = 8430, ++ MD_ERROR_WIN_DS_UNKNOWN_ERROR = 8431, ++ MD_ERROR_WIN_DS_ROOT_REQUIRES_CLASS_TOP = 8432, ++ MD_ERROR_WIN_DS_REFUSING_FSMO_ROLES = 8433, ++ MD_ERROR_WIN_DS_MISSING_FSMO_SETTINGS = 8434, ++ MD_ERROR_WIN_DS_UNABLE_TO_SURRENDER_ROLES = 8435, ++ MD_ERROR_WIN_DS_DRA_GENERIC = 8436, ++ MD_ERROR_WIN_DS_DRA_INVALID_PARAMETER = 8437, ++ MD_ERROR_WIN_DS_DRA_BUSY = 8438, ++ MD_ERROR_WIN_DS_DRA_BAD_DN = 8439, ++ MD_ERROR_WIN_DS_DRA_BAD_NC = 8440, ++ MD_ERROR_WIN_DS_DRA_DN_EXISTS = 8441, ++ MD_ERROR_WIN_DS_DRA_INTERNAL_ERROR = 8442, ++ MD_ERROR_WIN_DS_DRA_INCONSISTENT_DIT = 8443, ++ MD_ERROR_WIN_DS_DRA_CONNECTION_FAILED = 8444, ++ MD_ERROR_WIN_DS_DRA_BAD_INSTANCE_TYPE = 8445, ++ MD_ERROR_WIN_DS_DRA_OUT_OF_MEM = 8446, ++ MD_ERROR_WIN_DS_DRA_MAIL_PROBLEM = 8447, ++ MD_ERROR_WIN_DS_DRA_REF_ALREADY_EXISTS = 8448, ++ MD_ERROR_WIN_DS_DRA_REF_NOT_FOUND = 8449, ++ MD_ERROR_WIN_DS_DRA_OBJ_IS_REP_SOURCE = 8450, ++ MD_ERROR_WIN_DS_DRA_DB_ERROR = 8451, ++ MD_ERROR_WIN_DS_DRA_NO_REPLICA = 8452, ++ MD_ERROR_WIN_DS_DRA_ACCESS_DENIED = 8453, ++ MD_ERROR_WIN_DS_DRA_NOT_SUPPORTED = 8454, ++ MD_ERROR_WIN_DS_DRA_RPC_CANCELLED = 8455, ++ MD_ERROR_WIN_DS_DRA_SOURCE_DISABLED = 8456, ++ MD_ERROR_WIN_DS_DRA_SINK_DISABLED = 8457, ++ MD_ERROR_WIN_DS_DRA_NAME_COLLISION = 8458, ++ MD_ERROR_WIN_DS_DRA_SOURCE_REINSTALLED = 8459, ++ MD_ERROR_WIN_DS_DRA_MISSING_PARENT = 8460, ++ MD_ERROR_WIN_DS_DRA_PREEMPTED = 8461, ++ MD_ERROR_WIN_DS_DRA_ABANDON_SYNC = 8462, ++ MD_ERROR_WIN_DS_DRA_SHUTDOWN = 8463, ++ MD_ERROR_WIN_DS_DRA_INCOMPATIBLE_PARTIAL_SET = 8464, ++ MD_ERROR_WIN_DS_DRA_SOURCE_IS_PARTIAL_REPLICA = 8465, ++ MD_ERROR_WIN_DS_DRA_EXTN_CONNECTION_FAILED = 8466, ++ MD_ERROR_WIN_DS_INSTALL_SCHEMA_MISMATCH = 8467, ++ MD_ERROR_WIN_DS_DUP_LINK_ID = 8468, ++ MD_ERROR_WIN_DS_NAME_ERROR_RESOLVING = 8469, ++ MD_ERROR_WIN_DS_NAME_ERROR_NOT_FOUND = 8470, ++ MD_ERROR_WIN_DS_NAME_ERROR_NOT_UNIQUE = 8471, ++ MD_ERROR_WIN_DS_NAME_ERROR_NO_MAPPING = 8472, ++ MD_ERROR_WIN_DS_NAME_ERROR_DOMAIN_ONLY = 8473, ++ MD_ERROR_WIN_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING = 8474, ++ MD_ERROR_WIN_DS_CONSTRUCTED_ATT_MOD = 8475, ++ MD_ERROR_WIN_DS_WRONG_OM_OBJ_CLASS = 8476, ++ MD_ERROR_WIN_DS_DRA_REPL_PENDING = 8477, ++ MD_ERROR_WIN_DS_DS_REQUIRED = 8478, ++ MD_ERROR_WIN_DS_INVALID_LDAP_DISPLAY_NAME = 8479, ++ MD_ERROR_WIN_DS_NON_BASE_SEARCH = 8480, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_ATTS = 8481, ++ MD_ERROR_WIN_DS_BACKLINK_WITHOUT_LINK = 8482, ++ MD_ERROR_WIN_DS_EPOCH_MISMATCH = 8483, ++ MD_ERROR_WIN_DS_SRC_NAME_MISMATCH = 8484, ++ MD_ERROR_WIN_DS_SRC_AND_DST_NC_IDENTICAL = 8485, ++ MD_ERROR_WIN_DS_DST_NC_MISMATCH = 8486, ++ MD_ERROR_WIN_DS_NOT_AUTHORITIVE_FOR_DST_NC = 8487, ++ MD_ERROR_WIN_DS_SRC_GUID_MISMATCH = 8488, ++ MD_ERROR_WIN_DS_CANT_MOVE_DELETED_OBJECT = 8489, ++ MD_ERROR_WIN_DS_PDC_OPERATION_IN_PROGRESS = 8490, ++ MD_ERROR_WIN_DS_CROSS_DOMAIN_CLEANUP_REQD = 8491, ++ MD_ERROR_WIN_DS_ILLEGAL_XDOM_MOVE_OPERATION = 8492, ++ MD_ERROR_WIN_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS = 8493, ++ MD_ERROR_WIN_DS_NC_MUST_HAVE_NC_PARENT = 8494, ++ MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE = 8495, ++ MD_ERROR_WIN_DS_DST_DOMAIN_NOT_NATIVE = 8496, ++ MD_ERROR_WIN_DS_MISSING_INFRASTRUCTURE_CONTAINER = 8497, ++ MD_ERROR_WIN_DS_CANT_MOVE_ACCOUNT_GROUP = 8498, ++ MD_ERROR_WIN_DS_CANT_MOVE_RESOURCE_GROUP = 8499, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG = 8500, ++ MD_ERROR_WIN_DS_NO_TREE_DELETE_ABOVE_NC = 8501, ++ MD_ERROR_WIN_DS_COULDNT_LOCK_TREE_FOR_DELETE = 8502, ++ MD_ERROR_WIN_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE = 8503, ++ MD_ERROR_WIN_DS_SAM_INIT_FAILURE = 8504, ++ MD_ERROR_WIN_DS_SENSITIVE_GROUP_VIOLATION = 8505, ++ MD_ERROR_WIN_DS_CANT_MOD_PRIMARYGROUPID = 8506, ++ MD_ERROR_WIN_DS_ILLEGAL_BASE_SCHEMA_MOD = 8507, ++ MD_ERROR_WIN_DS_NONSAFE_SCHEMA_CHANGE = 8508, ++ MD_ERROR_WIN_DS_SCHEMA_UPDATE_DISALLOWED = 8509, ++ MD_ERROR_WIN_DS_CANT_CREATE_UNDER_SCHEMA = 8510, ++ MD_ERROR_WIN_DS_INSTALL_NO_SRC_SCH_VERSION = 8511, ++ MD_ERROR_WIN_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE = 8512, ++ MD_ERROR_WIN_DS_INVALID_GROUP_TYPE = 8513, ++ MD_ERROR_WIN_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 8514, ++ MD_ERROR_WIN_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 8515, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 8516, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 8517, ++ MD_ERROR_WIN_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 8518, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 8519, ++ MD_ERROR_WIN_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 8520, ++ MD_ERROR_WIN_DS_HAVE_PRIMARY_MEMBERS = 8521, ++ MD_ERROR_WIN_DS_STRING_SD_CONVERSION_FAILED = 8522, ++ MD_ERROR_WIN_DS_NAMING_MASTER_GC = 8523, ++ MD_ERROR_WIN_DS_DNS_LOOKUP_FAILURE = 8524, ++ MD_ERROR_WIN_DS_COULDNT_UPDATE_SPNS = 8525, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_SD = 8526, ++ MD_ERROR_WIN_DS_KEY_NOT_UNIQUE = 8527, ++ MD_ERROR_WIN_DS_WRONG_LINKED_ATT_SYNTAX = 8528, ++ MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_PASSWORD = 8529, ++ MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_FLOPPY = 8530, ++ MD_ERROR_WIN_DS_CANT_START = 8531, ++ MD_ERROR_WIN_DS_INIT_FAILURE = 8532, ++ MD_ERROR_WIN_DS_NO_PKT_PRIVACY_ON_CONNECTION = 8533, ++ MD_ERROR_WIN_DS_SOURCE_DOMAIN_IN_FOREST = 8534, ++ MD_ERROR_WIN_DS_DESTINATION_DOMAIN_NOT_IN_FOREST = 8535, ++ MD_ERROR_WIN_DS_DESTINATION_AUDITING_NOT_ENABLED = 8536, ++ MD_ERROR_WIN_DS_CANT_FIND_DC_FOR_SRC_DOMAIN = 8537, ++ MD_ERROR_WIN_DS_SRC_OBJ_NOT_GROUP_OR_USER = 8538, ++ MD_ERROR_WIN_DS_SRC_SID_EXISTS_IN_FOREST = 8539, ++ MD_ERROR_WIN_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH = 8540, ++ MD_ERROR_WIN_SAM_INIT_FAILURE = 8541, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_INFO_SHIP = 8542, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_CONFLICT = 8543, ++ MD_ERROR_WIN_DS_DRA_EARLIER_SCHEMA_CONFLICT = 8544, ++ MD_ERROR_WIN_DS_DRA_OBJ_NC_MISMATCH = 8545, ++ MD_ERROR_WIN_DS_NC_STILL_HAS_DSAS = 8546, ++ MD_ERROR_WIN_DS_GC_REQUIRED = 8547, ++ MD_ERROR_WIN_DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 8548, ++ MD_ERROR_WIN_DS_NO_FPO_IN_UNIVERSAL_GROUPS = 8549, ++ MD_ERROR_WIN_DS_CANT_ADD_TO_GC = 8550, ++ MD_ERROR_WIN_DS_NO_CHECKPOINT_WITH_PDC = 8551, ++ MD_ERROR_WIN_DS_SOURCE_AUDITING_NOT_ENABLED = 8552, ++ MD_ERROR_WIN_DS_CANT_CREATE_IN_NONDOMAIN_NC = 8553, ++ MD_ERROR_WIN_DS_INVALID_NAME_FOR_SPN = 8554, ++ MD_ERROR_WIN_DS_FILTER_USES_CONTRUCTED_ATTRS = 8555, ++ MD_ERROR_WIN_DS_UNICODEPWD_NOT_IN_QUOTES = 8556, ++ MD_ERROR_WIN_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 8557, ++ MD_ERROR_WIN_DS_MUST_BE_RUN_ON_DST_DC = 8558, ++ MD_ERROR_WIN_DS_SRC_DC_MUST_BE_SP4_OR_GREATER = 8559, ++ MD_ERROR_WIN_DS_CANT_TREE_DELETE_CRITICAL_OBJ = 8560, ++ MD_ERROR_WIN_DS_INIT_FAILURE_CONSOLE = 8561, ++ MD_ERROR_WIN_DS_SAM_INIT_FAILURE_CONSOLE = 8562, ++ MD_ERROR_WIN_DS_FOREST_VERSION_TOO_HIGH = 8563, ++ MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_HIGH = 8564, ++ MD_ERROR_WIN_DS_FOREST_VERSION_TOO_LOW = 8565, ++ MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_LOW = 8566, ++ MD_ERROR_WIN_DS_INCOMPATIBLE_VERSION = 8567, ++ MD_ERROR_WIN_DS_LOW_DSA_VERSION = 8568, ++ MD_ERROR_WIN_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN = 8569, ++ MD_ERROR_WIN_DS_NOT_SUPPORTED_SORT_ORDER = 8570, ++ MD_ERROR_WIN_DS_NAME_NOT_UNIQUE = 8571, ++ MD_ERROR_WIN_DS_MACHINE_ACCOUNT_CREATED_PRENT4 = 8572, ++ MD_ERROR_WIN_DS_OUT_OF_VERSION_STORE = 8573, ++ MD_ERROR_WIN_DS_INCOMPATIBLE_CONTROLS_USED = 8574, ++ MD_ERROR_WIN_DS_NO_REF_DOMAIN = 8575, ++ MD_ERROR_WIN_DS_RESERVED_LINK_ID = 8576, ++ MD_ERROR_WIN_DS_LINK_ID_NOT_AVAILABLE = 8577, ++ MD_ERROR_WIN_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 8578, ++ MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE = 8579, ++ MD_ERROR_WIN_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC = 8580, ++ MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_FLAG = 8581, ++ MD_ERROR_WIN_DS_MODIFYDN_WRONG_GRANDPARENT = 8582, ++ MD_ERROR_WIN_DS_NAME_ERROR_TRUST_REFERRAL = 8583, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_STANDARD_SERVER = 8584, ++ MD_ERROR_WIN_DS_CANT_ACCESS_REMOTE_PART_OF_AD = 8585, ++ MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 = 8586, ++ MD_ERROR_WIN_DS_THREAD_LIMIT_EXCEEDED = 8587, ++ MD_ERROR_WIN_DS_NOT_CLOSEST = 8588, ++ MD_ERROR_WIN_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF = 8589, ++ MD_ERROR_WIN_DS_SINGLE_USER_MODE_FAILED = 8590, ++ MD_ERROR_WIN_DS_NTDSCRIPT_SYNTAX_ERROR = 8591, ++ MD_ERROR_WIN_DS_NTDSCRIPT_PROCESS_ERROR = 8592, ++ MD_ERROR_WIN_DS_DIFFERENT_REPL_EPOCHS = 8593, ++ MD_ERROR_WIN_DS_DRS_EXTENSIONS_CHANGED = 8594, ++ MD_ERROR_WIN_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR = 8595, ++ MD_ERROR_WIN_DS_NO_MSDS_INTID = 8596, ++ MD_ERROR_WIN_DS_DUP_MSDS_INTID = 8597, ++ MD_ERROR_WIN_DS_EXISTS_IN_RDNATTID = 8598, ++ MD_ERROR_WIN_DS_AUTHORIZATION_FAILED = 8599, ++ MD_ERROR_WIN_DS_INVALID_SCRIPT = 8600, ++ MD_ERROR_WIN_DS_REMOTE_CROSSREF_OP_FAILED = 8601, ++ MD_ERROR_WIN_DS_CROSS_REF_BUSY = 8602, ++ MD_ERROR_WIN_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN = 8603, ++ MD_ERROR_WIN_DS_CANT_DEMOTE_WITH_WRITEABLE_NC = 8604, ++ MD_ERROR_WIN_DS_DUPLICATE_ID_FOUND = 8605, ++ MD_ERROR_WIN_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT = 8606, ++ MD_ERROR_WIN_DS_GROUP_CONVERSION_ERROR = 8607, ++ MD_ERROR_WIN_DS_CANT_MOVE_APP_BASIC_GROUP = 8608, ++ MD_ERROR_WIN_DS_CANT_MOVE_APP_QUERY_GROUP = 8609, ++ MD_ERROR_WIN_DS_ROLE_NOT_VERIFIED = 8610, ++ MD_ERROR_WIN_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL = 8611, ++ MD_ERROR_WIN_DS_DOMAIN_RENAME_IN_PROGRESS = 8612, ++ MD_ERROR_WIN_DS_EXISTING_AD_CHILD_NC = 8613, ++ MD_ERROR_WIN_DS_REPL_LIFETIME_EXCEEDED = 8614, ++ MD_ERROR_WIN_DS_DISALLOWED_IN_SYSTEM_CONTAINER = 8615, ++ MD_ERROR_WIN_DS_LDAP_SEND_QUEUE_FULL = 8616, ++ MD_ERROR_WIN_DS_DRA_OUT_SCHEDULE_WINDOW = 8617, ++ MD_ERROR_WIN_DS_POLICY_NOT_KNOWN = 8618, ++ MD_ERROR_WIN_NO_SITE_SETTINGS_OBJECT = 8619, ++ MD_ERROR_WIN_NO_SECRETS = 8620, ++ MD_ERROR_WIN_NO_WRITABLE_DC_FOUND = 8621, ++ MD_ERROR_WIN_DS_NO_SERVER_OBJECT = 8622, ++ MD_ERROR_WIN_DS_NO_NTDSA_OBJECT = 8623, ++ MD_ERROR_WIN_DS_NON_ASQ_SEARCH = 8624, ++ MD_ERROR_WIN_DS_AUDIT_FAILURE = 8625, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_SUBTREE = 8626, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_TUPLE = 8627, ++ MD_ERROR_WIN_DS_HIERARCHY_TABLE_TOO_DEEP = 8628, ++ MD_ERROR_WIN_DS_DRA_CORRUPT_UTD_VECTOR = 8629, ++ MD_ERROR_WIN_DS_DRA_SECRETS_DENIED = 8630, ++ MD_ERROR_WIN_DS_RESERVED_MAPI_ID = 8631, ++ MD_ERROR_WIN_DS_MAPI_ID_NOT_AVAILABLE = 8632, ++ MD_ERROR_WIN_DS_DRA_MISSING_KRBTGT_SECRET = 8633, ++ MD_ERROR_WIN_DS_DOMAIN_NAME_EXISTS_IN_FOREST = 8634, ++ MD_ERROR_WIN_DS_FLAT_NAME_EXISTS_IN_FOREST = 8635, ++ MD_ERROR_WIN_INVALID_USER_PRINCIPAL_NAME = 8636, ++ MD_ERROR_WIN_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 8637, ++ MD_ERROR_WIN_DS_OID_NOT_FOUND = 8638, ++ MD_ERROR_WIN_DS_DRA_RECYCLED_TARGET = 8639, ++ MD_ERROR_WIN_DS_DISALLOWED_NC_REDIRECT = 8640, ++ MD_ERROR_WIN_DS_HIGH_ADLDS_FFL = 8641, ++ MD_ERROR_WIN_DS_HIGH_DSA_VERSION = 8642, ++ MD_ERROR_WIN_DS_LOW_ADLDS_FFL = 8643, ++ MD_ERROR_WIN_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION = 8644, ++ MD_ERROR_WIN_DS_UNDELETE_SAM_VALIDATION_FAILED = 8645, ++ MD_ERROR_WIN_INCORRECT_ACCOUNT_TYPE = 8646, ++ MD_ERROR_WIN_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST = 8647, ++ MD_ERROR_WIN_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST = 8648, ++ MD_ERROR_WIN_DS_MISSING_FOREST_TRUST = 8649, ++ MD_ERROR_WIN_DS_VALUE_KEY_NOT_UNIQUE = 8650, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_EXISTS = 13000, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_NOT_FOUND = 13001, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_IN_USE = 13002, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_EXISTS = 13003, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_NOT_FOUND = 13004, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_IN_USE = 13005, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_EXISTS = 13006, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_NOT_FOUND = 13007, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_EXISTS = 13008, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_NOT_FOUND = 13009, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_EXISTS = 13010, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_NOT_FOUND = 13011, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_IN_USE = 13012, ++ MD_ERROR_WIN_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND = 13013, ++ MD_ERROR_WIN_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND = 13014, ++ MD_ERROR_WIN_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND = 13015, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_EXISTS = 13016, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_NOT_FOUND = 13017, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_PENDING_DELETION = 13018, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_PENDING_DELETION = 13019, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_PENDING_DELETION = 13020, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_PENDING_DELETION = 13021, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_PENDING_DELETION = 13022, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_PENDING_DELETION = 13023, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_BEGIN = 13800, ++ MD_ERROR_WIN_IPSEC_IKE_AUTH_FAIL = 13801, ++ MD_ERROR_WIN_IPSEC_IKE_ATTRIB_FAIL = 13802, ++ MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_PENDING = 13803, ++ MD_ERROR_WIN_IPSEC_IKE_GENERAL_PROCESSING_ERROR = 13804, ++ MD_ERROR_WIN_IPSEC_IKE_TIMED_OUT = 13805, ++ MD_ERROR_WIN_IPSEC_IKE_NO_CERT = 13806, ++ MD_ERROR_WIN_IPSEC_IKE_SA_DELETED = 13807, ++ MD_ERROR_WIN_IPSEC_IKE_SA_REAPED = 13808, ++ MD_ERROR_WIN_IPSEC_IKE_MM_ACQUIRE_DROP = 13809, ++ MD_ERROR_WIN_IPSEC_IKE_QM_ACQUIRE_DROP = 13810, ++ MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_MM = 13811, ++ MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_NO_MM = 13812, ++ MD_ERROR_WIN_IPSEC_IKE_DROP_NO_RESPONSE = 13813, ++ MD_ERROR_WIN_IPSEC_IKE_MM_DELAY_DROP = 13814, ++ MD_ERROR_WIN_IPSEC_IKE_QM_DELAY_DROP = 13815, ++ MD_ERROR_WIN_IPSEC_IKE_ERROR = 13816, ++ MD_ERROR_WIN_IPSEC_IKE_CRL_FAILED = 13817, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_KEY_USAGE = 13818, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_TYPE = 13819, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PRIVATE_KEY = 13820, ++ MD_ERROR_WIN_IPSEC_IKE_SIMULTANEOUS_REKEY = 13821, ++ MD_ERROR_WIN_IPSEC_IKE_DH_FAIL = 13822, ++ MD_ERROR_WIN_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED = 13823, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HEADER = 13824, ++ MD_ERROR_WIN_IPSEC_IKE_NO_POLICY = 13825, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SIGNATURE = 13826, ++ MD_ERROR_WIN_IPSEC_IKE_KERBEROS_ERROR = 13827, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PUBLIC_KEY = 13828, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR = 13829, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SA = 13830, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_PROP = 13831, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_TRANS = 13832, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_KE = 13833, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_ID = 13834, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT = 13835, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT_REQ = 13836, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_HASH = 13837, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SIG = 13838, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NONCE = 13839, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NOTIFY = 13840, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_DELETE = 13841, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_VENDOR = 13842, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_PAYLOAD = 13843, ++ MD_ERROR_WIN_IPSEC_IKE_LOAD_SOFT_SA = 13844, ++ MD_ERROR_WIN_IPSEC_IKE_SOFT_SA_TORN_DOWN = 13845, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_COOKIE = 13846, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PEER_CERT = 13847, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_CRL_FAILED = 13848, ++ MD_ERROR_WIN_IPSEC_IKE_POLICY_CHANGE = 13849, ++ MD_ERROR_WIN_IPSEC_IKE_NO_MM_POLICY = 13850, ++ MD_ERROR_WIN_IPSEC_IKE_NOTCBPRIV = 13851, ++ MD_ERROR_WIN_IPSEC_IKE_SECLOADFAIL = 13852, ++ MD_ERROR_WIN_IPSEC_IKE_FAILSSPINIT = 13853, ++ MD_ERROR_WIN_IPSEC_IKE_FAILQUERYSSP = 13854, ++ MD_ERROR_WIN_IPSEC_IKE_SRVACQFAIL = 13855, ++ MD_ERROR_WIN_IPSEC_IKE_SRVQUERYCRED = 13856, ++ MD_ERROR_WIN_IPSEC_IKE_GETSPIFAIL = 13857, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_FILTER = 13858, ++ MD_ERROR_WIN_IPSEC_IKE_OUT_OF_MEMORY = 13859, ++ MD_ERROR_WIN_IPSEC_IKE_ADD_UPDATE_KEY_FAILED = 13860, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_POLICY = 13861, ++ MD_ERROR_WIN_IPSEC_IKE_UNKNOWN_DOI = 13862, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SITUATION = 13863, ++ MD_ERROR_WIN_IPSEC_IKE_DH_FAILURE = 13864, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_GROUP = 13865, ++ MD_ERROR_WIN_IPSEC_IKE_ENCRYPT = 13866, ++ MD_ERROR_WIN_IPSEC_IKE_DECRYPT = 13867, ++ MD_ERROR_WIN_IPSEC_IKE_POLICY_MATCH = 13868, ++ MD_ERROR_WIN_IPSEC_IKE_UNSUPPORTED_ID = 13869, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH = 13870, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_ALG = 13871, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_SIZE = 13872, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_ENCRYPT_ALG = 13873, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_ALG = 13874, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SIG = 13875, ++ MD_ERROR_WIN_IPSEC_IKE_LOAD_FAILED = 13876, ++ MD_ERROR_WIN_IPSEC_IKE_RPC_DELETE = 13877, ++ MD_ERROR_WIN_IPSEC_IKE_BENIGN_REINIT = 13878, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY = 13879, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_MAJOR_VERSION = 13880, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_KEYLEN = 13881, ++ MD_ERROR_WIN_IPSEC_IKE_MM_LIMIT = 13882, ++ MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_DISABLED = 13883, ++ MD_ERROR_WIN_IPSEC_IKE_QM_LIMIT = 13884, ++ MD_ERROR_WIN_IPSEC_IKE_MM_EXPIRED = 13885, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_MM_ASSUMED_INVALID = 13886, ++ MD_ERROR_WIN_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH = 13887, ++ MD_ERROR_WIN_IPSEC_IKE_UNEXPECTED_MESSAGE_ID = 13888, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_PAYLOAD = 13889, ++ MD_ERROR_WIN_IPSEC_IKE_DOS_COOKIE_SENT = 13890, ++ MD_ERROR_WIN_IPSEC_IKE_SHUTTING_DOWN = 13891, ++ MD_ERROR_WIN_IPSEC_IKE_CGA_AUTH_FAILED = 13892, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NATOA = 13893, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_MM_FOR_QM = 13894, ++ MD_ERROR_WIN_IPSEC_IKE_QM_EXPIRED = 13895, ++ MD_ERROR_WIN_IPSEC_IKE_TOO_MANY_FILTERS = 13896, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_END = 13897, ++ MD_ERROR_WIN_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL = 13898, ++ MD_ERROR_WIN_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE = 13899, ++ MD_ERROR_WIN_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING = 13900, ++ MD_ERROR_WIN_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING = 13901, ++ MD_ERROR_WIN_IPSEC_IKE_COEXISTENCE_SUPPRESS = 13902, ++ MD_ERROR_WIN_IPSEC_IKE_RATELIMIT_DROP = 13903, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE = 13904, ++ MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE = 13905, ++ MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE = 13906, ++ MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY = 13907, ++ MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE = 13908, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_EXTENDED_END = 13909, ++ MD_ERROR_WIN_IPSEC_BAD_SPI = 13910, ++ MD_ERROR_WIN_IPSEC_SA_LIFETIME_EXPIRED = 13911, ++ MD_ERROR_WIN_IPSEC_WRONG_SA = 13912, ++ MD_ERROR_WIN_IPSEC_REPLAY_CHECK_FAILED = 13913, ++ MD_ERROR_WIN_IPSEC_INVALID_PACKET = 13914, ++ MD_ERROR_WIN_IPSEC_INTEGRITY_CHECK_FAILED = 13915, ++ MD_ERROR_WIN_IPSEC_CLEAR_TEXT_DROP = 13916, ++ MD_ERROR_WIN_IPSEC_AUTH_FIREWALL_DROP = 13917, ++ MD_ERROR_WIN_IPSEC_THROTTLE_DROP = 13918, ++ MD_ERROR_WIN_IPSEC_DOSP_BLOCK = 13925, ++ MD_ERROR_WIN_IPSEC_DOSP_RECEIVED_MULTICAST = 13926, ++ MD_ERROR_WIN_IPSEC_DOSP_INVALID_PACKET = 13927, ++ MD_ERROR_WIN_IPSEC_DOSP_STATE_LOOKUP_FAILED = 13928, ++ MD_ERROR_WIN_IPSEC_DOSP_MAX_ENTRIES = 13929, ++ MD_ERROR_WIN_IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 13930, ++ MD_ERROR_WIN_IPSEC_DOSP_NOT_INSTALLED = 13931, ++ MD_ERROR_WIN_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 13932, ++ MD_ERROR_WIN_SXS_SECTION_NOT_FOUND = 14000, ++ MD_ERROR_WIN_SXS_CANT_GEN_ACTCTX = 14001, ++ MD_ERROR_WIN_SXS_INVALID_ACTCTXDATA_FORMAT = 14002, ++ MD_ERROR_WIN_SXS_ASSEMBLY_NOT_FOUND = 14003, ++ MD_ERROR_WIN_SXS_MANIFEST_FORMAT_ERROR = 14004, ++ MD_ERROR_WIN_SXS_MANIFEST_PARSE_ERROR = 14005, ++ MD_ERROR_WIN_SXS_ACTIVATION_CONTEXT_DISABLED = 14006, ++ MD_ERROR_WIN_SXS_KEY_NOT_FOUND = 14007, ++ MD_ERROR_WIN_SXS_VERSION_CONFLICT = 14008, ++ MD_ERROR_WIN_SXS_WRONG_SECTION_TYPE = 14009, ++ MD_ERROR_WIN_SXS_THREAD_QUERIES_DISABLED = 14010, ++ MD_ERROR_WIN_SXS_PROCESS_DEFAULT_ALREADY_SET = 14011, ++ MD_ERROR_WIN_SXS_UNKNOWN_ENCODING_GROUP = 14012, ++ MD_ERROR_WIN_SXS_UNKNOWN_ENCODING = 14013, ++ MD_ERROR_WIN_SXS_INVALID_XML_NAMESPACE_URI = 14014, ++ MD_ERROR_WIN_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED = 14015, ++ MD_ERROR_WIN_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED = 14016, ++ MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE = 14017, ++ MD_ERROR_WIN_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE = 14018, ++ MD_ERROR_WIN_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE = 14019, ++ MD_ERROR_WIN_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT = 14020, ++ MD_ERROR_WIN_SXS_DUPLICATE_DLL_NAME = 14021, ++ MD_ERROR_WIN_SXS_DUPLICATE_WINDOWCLASS_NAME = 14022, ++ MD_ERROR_WIN_SXS_DUPLICATE_CLSID = 14023, ++ MD_ERROR_WIN_SXS_DUPLICATE_IID = 14024, ++ MD_ERROR_WIN_SXS_DUPLICATE_TLBID = 14025, ++ MD_ERROR_WIN_SXS_DUPLICATE_PROGID = 14026, ++ MD_ERROR_WIN_SXS_DUPLICATE_ASSEMBLY_NAME = 14027, ++ MD_ERROR_WIN_SXS_FILE_HASH_MISMATCH = 14028, ++ MD_ERROR_WIN_SXS_POLICY_PARSE_ERROR = 14029, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGQUOTE = 14030, ++ MD_ERROR_WIN_SXS_XML_E_COMMENTSYNTAX = 14031, ++ MD_ERROR_WIN_SXS_XML_E_BADSTARTNAMECHAR = 14032, ++ MD_ERROR_WIN_SXS_XML_E_BADNAMECHAR = 14033, ++ MD_ERROR_WIN_SXS_XML_E_BADCHARINSTRING = 14034, ++ MD_ERROR_WIN_SXS_XML_E_XMLDECLSYNTAX = 14035, ++ MD_ERROR_WIN_SXS_XML_E_BADCHARDATA = 14036, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGWHITESPACE = 14037, ++ MD_ERROR_WIN_SXS_XML_E_EXPECTINGTAGEND = 14038, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGSEMICOLON = 14039, ++ MD_ERROR_WIN_SXS_XML_E_UNBALANCEDPAREN = 14040, ++ MD_ERROR_WIN_SXS_XML_E_INTERNALERROR = 14041, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_WHITESPACE = 14042, ++ MD_ERROR_WIN_SXS_XML_E_INCOMPLETE_ENCODING = 14043, ++ MD_ERROR_WIN_SXS_XML_E_MISSING_PAREN = 14044, ++ MD_ERROR_WIN_SXS_XML_E_EXPECTINGCLOSEQUOTE = 14045, ++ MD_ERROR_WIN_SXS_XML_E_MULTIPLE_COLONS = 14046, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_DECIMAL = 14047, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_HEXIDECIMAL = 14048, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_UNICODE = 14049, ++ MD_ERROR_WIN_SXS_XML_E_WHITESPACEORQUESTIONMARK = 14050, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDENDTAG = 14051, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDTAG = 14052, ++ MD_ERROR_WIN_SXS_XML_E_DUPLICATEATTRIBUTE = 14053, ++ MD_ERROR_WIN_SXS_XML_E_MULTIPLEROOTS = 14054, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDATROOTLEVEL = 14055, ++ MD_ERROR_WIN_SXS_XML_E_BADXMLDECL = 14056, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGROOT = 14057, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDEOF = 14058, ++ MD_ERROR_WIN_SXS_XML_E_BADPEREFINSUBSET = 14059, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTARTTAG = 14060, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDENDTAG = 14061, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTRING = 14062, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCOMMENT = 14063, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDDECL = 14064, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCDATA = 14065, ++ MD_ERROR_WIN_SXS_XML_E_RESERVEDNAMESPACE = 14066, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDENCODING = 14067, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDSWITCH = 14068, ++ MD_ERROR_WIN_SXS_XML_E_BADXMLCASE = 14069, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_STANDALONE = 14070, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_STANDALONE = 14071, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_VERSION = 14072, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGEQUALS = 14073, ++ MD_ERROR_WIN_SXS_PROTECTION_RECOVERY_FAILED = 14074, ++ MD_ERROR_WIN_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT = 14075, ++ MD_ERROR_WIN_SXS_PROTECTION_CATALOG_NOT_VALID = 14076, ++ MD_ERROR_WIN_SXS_UNTRANSLATABLE_HRESULT = 14077, ++ MD_ERROR_WIN_SXS_PROTECTION_CATALOG_FILE_MISSING = 14078, ++ MD_ERROR_WIN_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE = 14079, ++ MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME = 14080, ++ MD_ERROR_WIN_SXS_ASSEMBLY_MISSING = 14081, ++ MD_ERROR_WIN_SXS_CORRUPT_ACTIVATION_STACK = 14082, ++ MD_ERROR_WIN_SXS_CORRUPTION = 14083, ++ MD_ERROR_WIN_SXS_EARLY_DEACTIVATION = 14084, ++ MD_ERROR_WIN_SXS_INVALID_DEACTIVATION = 14085, ++ MD_ERROR_WIN_SXS_MULTIPLE_DEACTIVATION = 14086, ++ MD_ERROR_WIN_SXS_PROCESS_TERMINATION_REQUESTED = 14087, ++ MD_ERROR_WIN_SXS_RELEASE_ACTIVATION_CONTEXT = 14088, ++ MD_ERROR_WIN_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 14089, ++ MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 14090, ++ MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 14091, ++ MD_ERROR_WIN_SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 14092, ++ MD_ERROR_WIN_SXS_IDENTITY_PARSE_ERROR = 14093, ++ MD_ERROR_WIN_MALFORMED_SUBSTITUTION_STRING = 14094, ++ MD_ERROR_WIN_SXS_INCORRECT_PUBLIC_KEY_TOKEN = 14095, ++ MD_ERROR_WIN_UNMAPPED_SUBSTITUTION_STRING = 14096, ++ MD_ERROR_WIN_SXS_ASSEMBLY_NOT_LOCKED = 14097, ++ MD_ERROR_WIN_SXS_COMPONENT_STORE_CORRUPT = 14098, ++ MD_ERROR_WIN_ADVANCED_INSTALLER_FAILED = 14099, ++ MD_ERROR_WIN_XML_ENCODING_MISMATCH = 14100, ++ MD_ERROR_WIN_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 14101, ++ MD_ERROR_WIN_SXS_IDENTITIES_DIFFERENT = 14102, ++ MD_ERROR_WIN_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 14103, ++ MD_ERROR_WIN_SXS_FILE_NOT_PART_OF_ASSEMBLY = 14104, ++ MD_ERROR_WIN_SXS_MANIFEST_TOO_BIG = 14105, ++ MD_ERROR_WIN_SXS_SETTING_NOT_REGISTERED = 14106, ++ MD_ERROR_WIN_SXS_TRANSACTION_CLOSURE_INCOMPLETE = 14107, ++ MD_ERROR_WIN_SMI_PRIMITIVE_INSTALLER_FAILED = 14108, ++ MD_ERROR_WIN_GENERIC_COMMAND_FAILED = 14109, ++ MD_ERROR_WIN_SXS_FILE_HASH_MISSING = 14110, ++ MD_ERROR_WIN_SXS_DUPLICATE_ACTIVATABLE_CLASS = 14111, ++ MD_ERROR_WIN_EVT_INVALID_CHANNEL_PATH = 15000, ++ MD_ERROR_WIN_EVT_INVALID_QUERY = 15001, ++ MD_ERROR_WIN_EVT_PUBLISHER_METADATA_NOT_FOUND = 15002, ++ MD_ERROR_WIN_EVT_EVENT_TEMPLATE_NOT_FOUND = 15003, ++ MD_ERROR_WIN_EVT_INVALID_PUBLISHER_NAME = 15004, ++ MD_ERROR_WIN_EVT_INVALID_EVENT_DATA = 15005, ++ MD_ERROR_WIN_EVT_CHANNEL_NOT_FOUND = 15007, ++ MD_ERROR_WIN_EVT_MALFORMED_XML_TEXT = 15008, ++ MD_ERROR_WIN_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL = 15009, ++ MD_ERROR_WIN_EVT_CONFIGURATION_ERROR = 15010, ++ MD_ERROR_WIN_EVT_QUERY_RESULT_STALE = 15011, ++ MD_ERROR_WIN_EVT_QUERY_RESULT_INVALID_POSITION = 15012, ++ MD_ERROR_WIN_EVT_NON_VALIDATING_MSXML = 15013, ++ MD_ERROR_WIN_EVT_FILTER_ALREADYSCOPED = 15014, ++ MD_ERROR_WIN_EVT_FILTER_NOTELTSET = 15015, ++ MD_ERROR_WIN_EVT_FILTER_INVARG = 15016, ++ MD_ERROR_WIN_EVT_FILTER_INVTEST = 15017, ++ MD_ERROR_WIN_EVT_FILTER_INVTYPE = 15018, ++ MD_ERROR_WIN_EVT_FILTER_PARSEERR = 15019, ++ MD_ERROR_WIN_EVT_FILTER_UNSUPPORTEDOP = 15020, ++ MD_ERROR_WIN_EVT_FILTER_UNEXPECTEDTOKEN = 15021, ++ MD_ERROR_WIN_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL = 15022, ++ MD_ERROR_WIN_EVT_INVALID_CHANNEL_PROPERTY_VALUE = 15023, ++ MD_ERROR_WIN_EVT_INVALID_PUBLISHER_PROPERTY_VALUE = 15024, ++ MD_ERROR_WIN_EVT_CHANNEL_CANNOT_ACTIVATE = 15025, ++ MD_ERROR_WIN_EVT_FILTER_TOO_COMPLEX = 15026, ++ MD_ERROR_WIN_EVT_MESSAGE_NOT_FOUND = 15027, ++ MD_ERROR_WIN_EVT_MESSAGE_ID_NOT_FOUND = 15028, ++ MD_ERROR_WIN_EVT_UNRESOLVED_VALUE_INSERT = 15029, ++ MD_ERROR_WIN_EVT_UNRESOLVED_PARAMETER_INSERT = 15030, ++ MD_ERROR_WIN_EVT_MAX_INSERTS_REACHED = 15031, ++ MD_ERROR_WIN_EVT_EVENT_DEFINITION_NOT_FOUND = 15032, ++ MD_ERROR_WIN_EVT_MESSAGE_LOCALE_NOT_FOUND = 15033, ++ MD_ERROR_WIN_EVT_VERSION_TOO_OLD = 15034, ++ MD_ERROR_WIN_EVT_VERSION_TOO_NEW = 15035, ++ MD_ERROR_WIN_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY = 15036, ++ MD_ERROR_WIN_EVT_PUBLISHER_DISABLED = 15037, ++ MD_ERROR_WIN_EVT_FILTER_OUT_OF_RANGE = 15038, ++ MD_ERROR_WIN_EC_SUBSCRIPTION_CANNOT_ACTIVATE = 15080, ++ MD_ERROR_WIN_EC_LOG_DISABLED = 15081, ++ MD_ERROR_WIN_EC_CIRCULAR_FORWARDING = 15082, ++ MD_ERROR_WIN_EC_CREDSTORE_FULL = 15083, ++ MD_ERROR_WIN_EC_CRED_NOT_FOUND = 15084, ++ MD_ERROR_WIN_EC_NO_ACTIVE_CHANNEL = 15085, ++ MD_ERROR_WIN_MUI_FILE_NOT_FOUND = 15100, ++ MD_ERROR_WIN_MUI_INVALID_FILE = 15101, ++ MD_ERROR_WIN_MUI_INVALID_RC_CONFIG = 15102, ++ MD_ERROR_WIN_MUI_INVALID_LOCALE_NAME = 15103, ++ MD_ERROR_WIN_MUI_INVALID_ULTIMATEFALLBACK_NAME = 15104, ++ MD_ERROR_WIN_MUI_FILE_NOT_LOADED = 15105, ++ MD_ERROR_WIN_RESOURCE_ENUM_USER_STOP = 15106, ++ MD_ERROR_WIN_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED = 15107, ++ MD_ERROR_WIN_MUI_INTLSETTINGS_INVALID_LOCALE_NAME = 15108, ++ MD_ERROR_WIN_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE = 15110, ++ MD_ERROR_WIN_MRM_INVALID_PRICONFIG = 15111, ++ MD_ERROR_WIN_MRM_INVALID_FILE_TYPE = 15112, ++ MD_ERROR_WIN_MRM_UNKNOWN_QUALIFIER = 15113, ++ MD_ERROR_WIN_MRM_INVALID_QUALIFIER_VALUE = 15114, ++ MD_ERROR_WIN_MRM_NO_CANDIDATE = 15115, ++ MD_ERROR_WIN_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE = 15116, ++ MD_ERROR_WIN_MRM_RESOURCE_TYPE_MISMATCH = 15117, ++ MD_ERROR_WIN_MRM_DUPLICATE_MAP_NAME = 15118, ++ MD_ERROR_WIN_MRM_DUPLICATE_ENTRY = 15119, ++ MD_ERROR_WIN_MRM_INVALID_RESOURCE_IDENTIFIER = 15120, ++ MD_ERROR_WIN_MRM_FILEPATH_TOO_LONG = 15121, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_DIRECTORY_TYPE = 15122, ++ MD_ERROR_WIN_MRM_INVALID_PRI_FILE = 15126, ++ MD_ERROR_WIN_MRM_NAMED_RESOURCE_NOT_FOUND = 15127, ++ MD_ERROR_WIN_MRM_MAP_NOT_FOUND = 15135, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_PROFILE_TYPE = 15136, ++ MD_ERROR_WIN_MRM_INVALID_QUALIFIER_OPERATOR = 15137, ++ MD_ERROR_WIN_MRM_INDETERMINATE_QUALIFIER_VALUE = 15138, ++ MD_ERROR_WIN_MRM_AUTOMERGE_ENABLED = 15139, ++ MD_ERROR_WIN_MRM_TOO_MANY_RESOURCES = 15140, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE = 15141, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE = 15142, ++ MD_ERROR_WIN_MRM_NO_CURRENT_VIEW_ON_THREAD = 15143, ++ MD_ERROR_WIN_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST = 15144, ++ MD_ERROR_WIN_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT = 15145, ++ MD_ERROR_WIN_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE = 15146, ++ MD_ERROR_WIN_MRM_GENERATION_COUNT_MISMATCH = 15147, ++ MD_ERROR_WIN_PRI_MERGE_VERSION_MISMATCH = 15148, ++ MD_ERROR_WIN_PRI_MERGE_MISSING_SCHEMA = 15149, ++ MD_ERROR_WIN_PRI_MERGE_LOAD_FILE_FAILED = 15150, ++ MD_ERROR_WIN_PRI_MERGE_ADD_FILE_FAILED = 15151, ++ MD_ERROR_WIN_PRI_MERGE_WRITE_FILE_FAILED = 15152, ++ MD_ERROR_WIN_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED = 15153, ++ MD_ERROR_WIN_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED = 15154, ++ MD_ERROR_WIN_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED = 15155, ++ MD_ERROR_WIN_PRI_MERGE_MAIN_PACKAGE_REQUIRED = 15156, ++ MD_ERROR_WIN_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED = 15157, ++ MD_ERROR_WIN_PRI_MERGE_INVALID_FILE_NAME = 15158, ++ MD_ERROR_WIN_MRM_PACKAGE_NOT_FOUND = 15159, ++ MD_ERROR_WIN_MRM_MISSING_DEFAULT_LANGUAGE = 15160, ++ MD_ERROR_WIN_MCA_INVALID_CAPABILITIES_STRING = 15200, ++ MD_ERROR_WIN_MCA_INVALID_VCP_VERSION = 15201, ++ MD_ERROR_WIN_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION = 15202, ++ MD_ERROR_WIN_MCA_MCCS_VERSION_MISMATCH = 15203, ++ MD_ERROR_WIN_MCA_UNSUPPORTED_MCCS_VERSION = 15204, ++ MD_ERROR_WIN_MCA_INTERNAL_ERROR = 15205, ++ MD_ERROR_WIN_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED = 15206, ++ MD_ERROR_WIN_MCA_UNSUPPORTED_COLOR_TEMPERATURE = 15207, ++ MD_ERROR_WIN_AMBIGUOUS_SYSTEM_DEVICE = 15250, ++ MD_ERROR_WIN_SYSTEM_DEVICE_NOT_FOUND = 15299, ++ MD_ERROR_WIN_HASH_NOT_SUPPORTED = 15300, ++ MD_ERROR_WIN_HASH_NOT_PRESENT = 15301, ++ MD_ERROR_WIN_SECONDARY_IC_PROVIDER_NOT_REGISTERED = 15321, ++ MD_ERROR_WIN_GPIO_CLIENT_INFORMATION_INVALID = 15322, ++ MD_ERROR_WIN_GPIO_VERSION_NOT_SUPPORTED = 15323, ++ MD_ERROR_WIN_GPIO_INVALID_REGISTRATION_PACKET = 15324, ++ MD_ERROR_WIN_GPIO_OPERATION_DENIED = 15325, ++ MD_ERROR_WIN_GPIO_INCOMPATIBLE_CONNECT_MODE = 15326, ++ MD_ERROR_WIN_GPIO_INTERRUPT_ALREADY_UNMASKED = 15327, ++ MD_ERROR_WIN_CANNOT_SWITCH_RUNLEVEL = 15400, ++ MD_ERROR_WIN_INVALID_RUNLEVEL_SETTING = 15401, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_TIMEOUT = 15402, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 15403, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_IN_PROGRESS = 15404, ++ MD_ERROR_WIN_SERVICES_FAILED_AUTOSTART = 15405, ++ MD_ERROR_WIN_COM_TASK_STOP_PENDING = 15501, ++ MD_ERROR_WIN_INSTALL_OPEN_PACKAGE_FAILED = 15600, ++ MD_ERROR_WIN_INSTALL_PACKAGE_NOT_FOUND = 15601, ++ MD_ERROR_WIN_INSTALL_INVALID_PACKAGE = 15602, ++ MD_ERROR_WIN_INSTALL_RESOLVE_DEPENDENCY_FAILED = 15603, ++ MD_ERROR_WIN_INSTALL_OUT_OF_DISK_SPACE = 15604, ++ MD_ERROR_WIN_INSTALL_NETWORK_FAILURE = 15605, ++ MD_ERROR_WIN_INSTALL_REGISTRATION_FAILURE = 15606, ++ MD_ERROR_WIN_INSTALL_DEREGISTRATION_FAILURE = 15607, ++ MD_ERROR_WIN_INSTALL_CANCEL = 15608, ++ MD_ERROR_WIN_INSTALL_FAILED = 15609, ++ MD_ERROR_WIN_REMOVE_FAILED = 15610, ++ MD_ERROR_WIN_PACKAGE_ALREADY_EXISTS = 15611, ++ MD_ERROR_WIN_NEEDS_REMEDIATION = 15612, ++ MD_ERROR_WIN_INSTALL_PREREQUISITE_FAILED = 15613, ++ MD_ERROR_WIN_PACKAGE_REPOSITORY_CORRUPTED = 15614, ++ MD_ERROR_WIN_INSTALL_POLICY_FAILURE = 15615, ++ MD_ERROR_WIN_PACKAGE_UPDATING = 15616, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_POLICY = 15617, ++ MD_ERROR_WIN_PACKAGES_IN_USE = 15618, ++ MD_ERROR_WIN_RECOVERY_FILE_CORRUPT = 15619, ++ MD_ERROR_WIN_INVALID_STAGED_SIGNATURE = 15620, ++ MD_ERROR_WIN_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED = 15621, ++ MD_ERROR_WIN_INSTALL_PACKAGE_DOWNGRADE = 15622, ++ MD_ERROR_WIN_SYSTEM_NEEDS_REMEDIATION = 15623, ++ MD_ERROR_WIN_APPX_INTEGRITY_FAILURE_CLR_NGEN = 15624, ++ MD_ERROR_WIN_RESILIENCY_FILE_CORRUPT = 15625, ++ MD_ERROR_WIN_INSTALL_FIREWALL_SERVICE_NOT_RUNNING = 15626, ++ MD_ERROR_WIN_PACKAGE_MOVE_FAILED = 15627, ++ MD_ERROR_WIN_INSTALL_VOLUME_NOT_EMPTY = 15628, ++ MD_ERROR_WIN_INSTALL_VOLUME_OFFLINE = 15629, ++ MD_ERROR_WIN_INSTALL_VOLUME_CORRUPT = 15630, ++ MD_ERROR_WIN_NEEDS_REGISTRATION = 15631, ++ MD_ERROR_WIN_INSTALL_WRONG_PROCESSOR_ARCHITECTURE = 15632, ++ MD_ERROR_WIN_DEV_SIDELOAD_LIMIT_EXCEEDED = 15633, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE = 15634, ++ MD_ERROR_WIN_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM = 15635, ++ MD_ERROR_WIN_PACKAGE_MOVE_BLOCKED_BY_STREAMING = 15636, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE = 15637, ++ MD_ERROR_WIN_PACKAGE_STAGING_ONHOLD = 15638, ++ MD_ERROR_WIN_INSTALL_INVALID_RELATED_SET_UPDATE = 15639, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY = 15640, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF = 15641, ++ MD_ERROR_WIN_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED = 15642, ++ MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_FAILED = 15643, ++ MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_TIMEDOUT = 15644, ++ MD_ERROR_WIN_DEPLOYMENT_OPTION_NOT_SUPPORTED = 15645, ++ MD_ERROR_WIN_APPINSTALLER_ACTIVATION_BLOCKED = 15646, ++ MD_ERROR_WIN_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED = 15647, ++ MD_ERROR_WIN_APPX_RAW_DATA_WRITE_FAILED = 15648, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE = 15649, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE = 15650, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY = 15651, ++ MD_ERROR_WIN_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY = 15652, ++ MD_ERROR_WIN_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER = 15653, ++ MD_ERROR_WIN_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED = 15654, ++ MD_ERROR_WIN_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE = 15655, ++ MD_ERROR_WIN_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES = 15656, ++ MD_ERROR_WIN_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED = 15657, ++ MD_ERROR_WIN_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST = 15658, ++ MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_CONTENT = 15659, ++ MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE = 15660, ++ MD_ERROR_WIN_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE = 15661, ++ MD_ERROR_WIN_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED = 15662, ++ MD_ERROR_WIN_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY = 15663, ++ MD_ERROR_WIN_STATE_LOAD_STORE_FAILED = 15800, ++ MD_ERROR_WIN_STATE_GET_VERSION_FAILED = 15801, ++ MD_ERROR_WIN_STATE_SET_VERSION_FAILED = 15802, ++ MD_ERROR_WIN_STATE_STRUCTURED_RESET_FAILED = 15803, ++ MD_ERROR_WIN_STATE_OPEN_CONTAINER_FAILED = 15804, ++ MD_ERROR_WIN_STATE_CREATE_CONTAINER_FAILED = 15805, ++ MD_ERROR_WIN_STATE_DELETE_CONTAINER_FAILED = 15806, ++ MD_ERROR_WIN_STATE_READ_SETTING_FAILED = 15807, ++ MD_ERROR_WIN_STATE_WRITE_SETTING_FAILED = 15808, ++ MD_ERROR_WIN_STATE_DELETE_SETTING_FAILED = 15809, ++ MD_ERROR_WIN_STATE_QUERY_SETTING_FAILED = 15810, ++ MD_ERROR_WIN_STATE_READ_COMPOSITE_SETTING_FAILED = 15811, ++ MD_ERROR_WIN_STATE_WRITE_COMPOSITE_SETTING_FAILED = 15812, ++ MD_ERROR_WIN_STATE_ENUMERATE_CONTAINER_FAILED = 15813, ++ MD_ERROR_WIN_STATE_ENUMERATE_SETTINGS_FAILED = 15814, ++ MD_ERROR_WIN_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED = 15815, ++ MD_ERROR_WIN_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED = 15816, ++ MD_ERROR_WIN_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED = 15817, ++ MD_ERROR_WIN_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED = 15818, ++ MD_ERROR_WIN_API_UNAVAILABLE = 15841, ++} MDErrorWin; ++ + #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1241,17 +1241,23 @@ string MinidumpProcessor::GetCrashReason + *address = + raw_exception->exception_record.exception_information[1]; + } + if (raw_exception->exception_record.number_parameters >= 3) { + uint32_t ntstatus = + static_cast + (raw_exception->exception_record.exception_information[2]); + reason.append(" / "); +- reason.append(NTStatusToString(ntstatus)); ++ const char* ntstatus_str = NTStatusToString(ntstatus); ++ if (ntstatus_str) { ++ reason.append(ntstatus_str); ++ } else { ++ snprintf(reason_string, sizeof(reason_string), "%#010x", ntstatus); ++ reason.append(reason_string); ++ } + } + break; + case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE: + reason = "EXCEPTION_INVALID_HANDLE"; + break; + case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: + reason = "EXCEPTION_ILLEGAL_INSTRUCTION"; + break; +@@ -1304,34 +1310,47 @@ string MinidumpProcessor::GetCrashReason + reason = "EXCEPTION_POSSIBLE_DEADLOCK"; + break; + case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: + reason = "STATUS_STACK_BUFFER_OVERRUN"; + if (raw_exception->exception_record.number_parameters > 0) { + uint32_t fast_fail_code = + static_cast + (raw_exception->exception_record.exception_information[0]); ++ char fast_fail_buff[13] = {}; ++ const char* fast_fail_string = FastFailToString(fast_fail_code); ++ if (!fast_fail_string) { ++ snprintf(fast_fail_buff, sizeof(fast_fail_buff), "%#010x", ++ fast_fail_code); ++ fast_fail_string = fast_fail_buff; ++ } ++ + reason.append(" / "); +- reason.append(FastFailToString(fast_fail_code)); ++ reason.append(fast_fail_string); + } + + break; + case MD_EXCEPTION_OUT_OF_MEMORY: + reason = "Out of Memory"; + break; + case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: + reason = "Unhandled C++ Exception"; + break; + case MD_EXCEPTION_CODE_WIN_SIMULATED: + reason = "Simulated Exception"; + break; + default: +- reason = NTStatusToString(exception_code); +- if (reason.substr(0, 2) == "0x") { +- BPLOG(INFO) << "Unknown exception reason " << reason; ++ fprintf(stderr, "exception_code = %u\n", exception_code); ++ const char* exception_str = NTStatusToString(exception_code); ++ fprintf(stderr, "exception_str = %s\n", exception_str); ++ if (exception_str == nullptr) { ++ exception_str = WinErrorToString(exception_code); ++ } ++ if (exception_str != nullptr) { ++ reason = exception_str; + } + break; + } + break; + } + + case MD_OS_ANDROID: + case MD_OS_LINUX: { +diff --git a/src/processor/symbolic_constants_win.cc b/src/processor/symbolic_constants_win.cc +--- a/src/processor/symbolic_constants_win.cc ++++ b/src/processor/symbolic_constants_win.cc +@@ -28,8384 +28,10931 @@ + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + // ntstatus_reason_win.h: Windows NTSTATUS code to string. + // + // Provides a means to convert NTSTATUS codes to strings. + // + // Author: Ben Wagner + ++#include + #include + + #include "common/stdio_wrapper.h" + #include "google_breakpad/common/breakpad_types.h" + #include "google_breakpad/common/minidump_exception_win32.h" + #include "processor/symbolic_constants_win.h" + + namespace google_breakpad { + +-string NTStatusToString(uint32_t ntstatus) { +- string reason; +- // The content of this switch was created from ntstatus.h in the 10 SDK +- // (version 10.0.19041.0) with +- // +- // egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h +- // | tr -d '\r' +- // | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' +- // | sort +- // | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ case MD_NTSTATUS_WIN_\2:\n reason = "\2";\n break;@' +- // +- // With easy copy to clipboard with +- // | xclip -selection c # on linux +- // | clip # on windows +- // | pbcopy # on mac +- // +- // and then the default case added. +- switch (ntstatus) { +- case MD_NTSTATUS_WIN_STATUS_SUCCESS: +- reason = "STATUS_SUCCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAIT_1: +- reason = "STATUS_WAIT_1"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAIT_2: +- reason = "STATUS_WAIT_2"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAIT_3: +- reason = "STATUS_WAIT_3"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAIT_63: +- reason = "STATUS_WAIT_63"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABANDONED: +- reason = "STATUS_ABANDONED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63: +- reason = "STATUS_ABANDONED_WAIT_63"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER_APC: +- reason = "STATUS_USER_APC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE: +- reason = "STATUS_ALREADY_COMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KERNEL_APC: +- reason = "STATUS_KERNEL_APC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALERTED: +- reason = "STATUS_ALERTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TIMEOUT: +- reason = "STATUS_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PENDING: +- reason = "STATUS_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE: +- reason = "STATUS_REPARSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES: +- reason = "STATUS_MORE_ENTRIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED: +- reason = "STATUS_NOT_ALL_ASSIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED: +- reason = "STATUS_SOME_NOT_MAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS: +- reason = "STATUS_OPLOCK_BREAK_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED: +- reason = "STATUS_VOLUME_MOUNTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED: +- reason = "STATUS_RXACT_COMMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP: +- reason = "STATUS_NOTIFY_CLEANUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR: +- reason = "STATUS_NOTIFY_ENUM_DIR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT: +- reason = "STATUS_NO_QUOTAS_FOR_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED: +- reason = "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION: +- reason = "STATUS_PAGE_FAULT_TRANSITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO: +- reason = "STATUS_PAGE_FAULT_DEMAND_ZERO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE: +- reason = "STATUS_PAGE_FAULT_COPY_ON_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE: +- reason = "STATUS_PAGE_FAULT_GUARD_PAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE: +- reason = "STATUS_PAGE_FAULT_PAGING_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED: +- reason = "STATUS_CACHE_PAGE_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRASH_DUMP: +- reason = "STATUS_CRASH_DUMP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS: +- reason = "STATUS_BUFFER_ALL_ZEROS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT: +- reason = "STATUS_REPARSE_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED: +- reason = "STATUS_RESOURCE_REQUIREMENTS_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE: +- reason = "STATUS_TRANSLATION_COMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY: +- reason = "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE: +- reason = "STATUS_NOTHING_TO_TERMINATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB: +- reason = "STATUS_PROCESS_NOT_IN_JOB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB: +- reason = "STATUS_PROCESS_IN_JOB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY: +- reason = "STATUS_VOLSNAP_HIBERNATE_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY: +- reason = "STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: +- reason = "STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED: +- reason = "STATUS_INTERRUPT_STILL_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED: +- reason = "STATUS_PROCESS_CLONED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS: +- reason = "STATUS_FILE_LOCKED_WITH_ONLY_READERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS: +- reason = "STATUS_FILE_LOCKED_WITH_WRITERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH: +- reason = "STATUS_VALID_IMAGE_HASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH: +- reason = "STATUS_VALID_CATALOG_HASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH: +- reason = "STATUS_VALID_STRONG_CODE_HASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GHOSTED: +- reason = "STATUS_GHOSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN: +- reason = "STATUS_DATA_OVERWRITTEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY: +- reason = "STATUS_RESOURCEMANAGER_READ_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY: +- reason = "STATUS_RING_PREVIOUSLY_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL: +- reason = "STATUS_RING_PREVIOUSLY_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA: +- reason = "STATUS_RING_PREVIOUSLY_ABOVE_QUOTA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY: +- reason = "STATUS_RING_NEWLY_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT: +- reason = "STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE: +- reason = "STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED: +- reason = "STATUS_OPLOCK_HANDLE_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK: +- reason = "STATUS_WAIT_FOR_OPLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL: +- reason = "STATUS_REPARSE_GLOBAL"; +- break; +- case MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED: +- reason = "DBG_EXCEPTION_HANDLED"; +- break; +- case MD_NTSTATUS_WIN_DBG_CONTINUE: +- reason = "DBG_CONTINUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE: +- reason = "STATUS_FLT_IO_COMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE: +- reason = "STATUS_RTPM_CONTEXT_CONTINUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE: +- reason = "STATUS_RTPM_CONTEXT_COMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS: +- reason = "STATUS_HV_PENDING_PAGE_REQUESTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED: +- reason = "STATUS_SPACES_REPAIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE: +- reason = "STATUS_SPACES_PAUSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE: +- reason = "STATUS_SPACES_COMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT: +- reason = "STATUS_SPACES_REDIRECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS: +- reason = "STATUS_OBJECT_NAME_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED: +- reason = "STATUS_THREAD_WAS_SUSPENDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE: +- reason = "STATUS_WORKING_SET_LIMIT_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE: +- reason = "STATUS_IMAGE_NOT_AT_BASE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED: +- reason = "STATUS_RXACT_STATE_CREATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION: +- reason = "STATUS_SEGMENT_NOTIFICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY: +- reason = "STATUS_LOCAL_USER_SESSION_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY: +- reason = "STATUS_BAD_CURRENT_DIRECTORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES: +- reason = "STATUS_SERIAL_MORE_WRITES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED: +- reason = "STATUS_REGISTRY_RECOVERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP: +- reason = "STATUS_FT_READ_RECOVERY_FROM_BACKUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY: +- reason = "STATUS_FT_WRITE_RECOVERY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT: +- reason = "STATUS_SERIAL_COUNTER_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD: +- reason = "STATUS_NULL_LM_PASSWORD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH: +- reason = "STATUS_IMAGE_MACHINE_TYPE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL: +- reason = "STATUS_RECEIVE_PARTIAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED: +- reason = "STATUS_RECEIVE_EXPEDITED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED: +- reason = "STATUS_RECEIVE_PARTIAL_EXPEDITED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVENT_DONE: +- reason = "STATUS_EVENT_DONE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVENT_PENDING: +- reason = "STATUS_EVENT_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM: +- reason = "STATUS_CHECKING_FILE_SYSTEM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT: +- reason = "STATUS_FATAL_APP_EXIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE: +- reason = "STATUS_PREDEFINED_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED: +- reason = "STATUS_WAS_UNLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION: +- reason = "STATUS_SERVICE_NOTIFICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAS_LOCKED: +- reason = "STATUS_WAS_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR: +- reason = "STATUS_LOG_HARD_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32: +- reason = "STATUS_ALREADY_WIN32"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE: +- reason = "STATUS_WX86_UNSIMULATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE: +- reason = "STATUS_WX86_CONTINUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP: +- reason = "STATUS_WX86_SINGLE_STEP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT: +- reason = "STATUS_WX86_BREAKPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE: +- reason = "STATUS_WX86_EXCEPTION_CONTINUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE: +- reason = "STATUS_WX86_EXCEPTION_LASTCHANCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN: +- reason = "STATUS_WX86_EXCEPTION_CHAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: +- reason = "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED: +- reason = "STATUS_NO_YIELD_PERFORMED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED: +- reason = "STATUS_TIMER_RESUME_IGNORED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED: +- reason = "STATUS_ARBITRATION_UNHANDLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED: +- reason = "STATUS_CARDBUS_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB: +- reason = "STATUS_WX86_CREATEWX86TIB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH: +- reason = "STATUS_MP_PROCESSOR_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HIBERNATED: +- reason = "STATUS_HIBERNATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION: +- reason = "STATUS_RESUME_HIBERNATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED: +- reason = "STATUS_FIRMWARE_UPDATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES: +- reason = "STATUS_DRIVERS_LEAKING_LOCKED_PAGES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED: +- reason = "STATUS_MESSAGE_RETRIEVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION: +- reason = "STATUS_SYSTEM_POWERSTATE_TRANSITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST: +- reason = "STATUS_ALPC_CHECK_COMPLETION_LIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: +- reason = "STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY: +- reason = "STATUS_ACCESS_AUDIT_BY_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE: +- reason = "STATUS_ABANDON_HIBERFILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED: +- reason = "STATUS_BIZRULES_NOT_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY: +- reason = "STATUS_FT_READ_FROM_COPY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE: +- reason = "STATUS_IMAGE_AT_DIFFERENT_BASE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED: +- reason = "STATUS_PATCH_DEFERRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM: +- reason = "STATUS_WAKE_SYSTEM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN: +- reason = "STATUS_DS_SHUTTING_DOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED: +- reason = "STATUS_DISK_REPAIR_REDIRECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART: +- reason = "STATUS_SERVICES_FAILED_AUTOSTART"; +- break; +- case MD_NTSTATUS_WIN_DBG_REPLY_LATER: +- reason = "DBG_REPLY_LATER"; +- break; +- case MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE: +- reason = "DBG_UNABLE_TO_PROVIDE_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD: +- reason = "DBG_TERMINATE_THREAD"; +- break; +- case MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS: +- reason = "DBG_TERMINATE_PROCESS"; +- break; +- case MD_NTSTATUS_WIN_DBG_CONTROL_C: +- reason = "DBG_CONTROL_C"; +- break; +- case MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C: +- reason = "DBG_PRINTEXCEPTION_C"; +- break; +- case MD_NTSTATUS_WIN_DBG_RIPEXCEPTION: +- reason = "DBG_RIPEXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_DBG_CONTROL_BREAK: +- reason = "DBG_CONTROL_BREAK"; +- break; +- case MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION: +- reason = "DBG_COMMAND_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C: +- reason = "DBG_PRINTEXCEPTION_WIDE_C"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY: +- reason = "RPC_NT_UUID_LOCAL_ONLY"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE: +- reason = "RPC_NT_SEND_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT: +- reason = "STATUS_CTX_CDM_CONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT: +- reason = "STATUS_CTX_CDM_DISCONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT: +- reason = "STATUS_SXS_RELEASE_ACTIVATION_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE: +- reason = "STATUS_HEURISTIC_DAMAGE_POSSIBLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED: +- reason = "STATUS_RECOVERY_NOT_NEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED: +- reason = "STATUS_RM_ALREADY_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART: +- reason = "STATUS_LOG_NO_RESTART"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST: +- reason = "STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED: +- reason = "STATUS_GRAPHICS_PARTIAL_DATA_POPULATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION: +- reason = "STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED: +- reason = "STATUS_GRAPHICS_MODE_NOT_PINNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE: +- reason = "STATUS_GRAPHICS_NO_PREFERRED_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY: +- reason = "STATUS_GRAPHICS_DATASET_IS_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: +- reason = "STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: +- reason = "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS: +- reason = "STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED: +- reason = "STATUS_GRAPHICS_LEADLINK_START_DEFERRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY: +- reason = "STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED: +- reason = "STATUS_GRAPHICS_START_DEFERRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS: +- reason = "STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED: +- reason = "STATUS_NDIS_INDICATION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT: +- reason = "STATUS_PCP_UNSUPPORTED_PSS_SALT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION: +- reason = "STATUS_GUARD_PAGE_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT: +- reason = "STATUS_DATATYPE_MISALIGNMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BREAKPOINT: +- reason = "STATUS_BREAKPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SINGLE_STEP: +- reason = "STATUS_SINGLE_STEP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW: +- reason = "STATUS_BUFFER_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES: +- reason = "STATUS_NO_MORE_FILES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER: +- reason = "STATUS_WAKE_SYSTEM_DEBUGGER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED: +- reason = "STATUS_HANDLES_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE: +- reason = "STATUS_NO_INHERITANCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE: +- reason = "STATUS_GUID_SUBSTITUTION_MADE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY: +- reason = "STATUS_PARTIAL_COPY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY: +- reason = "STATUS_DEVICE_PAPER_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF: +- reason = "STATUS_DEVICE_POWERED_OFF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE: +- reason = "STATUS_DEVICE_OFF_LINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY: +- reason = "STATUS_DEVICE_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS: +- reason = "STATUS_NO_MORE_EAS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME: +- reason = "STATUS_INVALID_EA_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT: +- reason = "STATUS_EA_LIST_INCONSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG: +- reason = "STATUS_INVALID_EA_FLAG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED: +- reason = "STATUS_VERIFY_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION: +- reason = "STATUS_EXTRANEOUS_INFORMATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY: +- reason = "STATUS_RXACT_COMMIT_NECESSARY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES: +- reason = "STATUS_NO_MORE_ENTRIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED: +- reason = "STATUS_FILEMARK_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED: +- reason = "STATUS_MEDIA_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BUS_RESET: +- reason = "STATUS_BUS_RESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA: +- reason = "STATUS_END_OF_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA: +- reason = "STATUS_BEGINNING_OF_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK: +- reason = "STATUS_MEDIA_CHECK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED: +- reason = "STATUS_SETMARK_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED: +- reason = "STATUS_NO_DATA_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES: +- reason = "STATUS_REDIRECTOR_HAS_OPEN_HANDLES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES: +- reason = "STATUS_SERVER_HAS_OPEN_HANDLES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED: +- reason = "STATUS_ALREADY_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LONGJUMP: +- reason = "STATUS_LONGJUMP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED: +- reason = "STATUS_CLEANER_CARTRIDGE_INSTALLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED: +- reason = "STATUS_PLUGPLAY_QUERY_VETOED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE: +- reason = "STATUS_UNWIND_CONSOLIDATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED: +- reason = "STATUS_REGISTRY_HIVE_RECOVERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE: +- reason = "STATUS_DLL_MIGHT_BE_INSECURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE: +- reason = "STATUS_DLL_MIGHT_BE_INCOMPATIBLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK: +- reason = "STATUS_STOPPED_ON_SYMLINK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK: +- reason = "STATUS_CANNOT_GRANT_REQUESTED_OPLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION: +- reason = "STATUS_NO_ACE_CONDITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS: +- reason = "STATUS_DEVICE_SUPPORT_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED: +- reason = "STATUS_DEVICE_POWER_CYCLE_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE: +- reason = "STATUS_NO_WORK_DONE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT: +- reason = "STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING: +- reason = "STATUS_DEVICE_REQUIRES_CLEANING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN: +- reason = "STATUS_DEVICE_DOOR_OPEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR: +- reason = "STATUS_DATA_LOST_REPAIR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED: +- reason = "STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH: +- reason = "STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE: +- reason = "STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS: +- reason = "STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS"; +- break; +- case MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED: +- reason = "DBG_EXCEPTION_NOT_HANDLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP: +- reason = "STATUS_CLUSTER_NODE_ALREADY_UP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN: +- reason = "STATUS_CLUSTER_NODE_ALREADY_DOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE: +- reason = "STATUS_CLUSTER_NETWORK_ALREADY_ONLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE: +- reason = "STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER: +- reason = "STATUS_CLUSTER_NODE_ALREADY_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG: +- reason = "STATUS_COULD_NOT_RESIZE_LOG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA: +- reason = "STATUS_NO_TXF_METADATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN: +- reason = "STATUS_CANT_RECOVER_WITH_HANDLE_OPEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT: +- reason = "STATUS_TXF_METADATA_ALREADY_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: +- reason = "STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED: +- reason = "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL: +- reason = "STATUS_FLT_BUFFER_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA: +- reason = "STATUS_FVE_PARTIAL_METADATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE: +- reason = "STATUS_FVE_TRANSIENT_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED: +- reason = "STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION: +- reason = "STATUS_VOLMGR_INCOMPLETE_REGENERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION: +- reason = "STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED: +- reason = "STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED: +- reason = "STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR: +- reason = "STATUS_QUERY_STORAGE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK: +- reason = "STATUS_GDI_HANDLE_LEAK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED: +- reason = "STATUS_SECUREBOOT_NOT_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL: +- reason = "STATUS_UNSUCCESSFUL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED: +- reason = "STATUS_NOT_IMPLEMENTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS: +- reason = "STATUS_INVALID_INFO_CLASS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH: +- reason = "STATUS_INFO_LENGTH_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION: +- reason = "STATUS_ACCESS_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR: +- reason = "STATUS_IN_PAGE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA: +- reason = "STATUS_PAGEFILE_QUOTA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE: +- reason = "STATUS_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK: +- reason = "STATUS_BAD_INITIAL_STACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC: +- reason = "STATUS_BAD_INITIAL_PC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_CID: +- reason = "STATUS_INVALID_CID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED: +- reason = "STATUS_TIMER_NOT_CANCELED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER: +- reason = "STATUS_INVALID_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE: +- reason = "STATUS_NO_SUCH_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE: +- reason = "STATUS_NO_SUCH_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST: +- reason = "STATUS_INVALID_DEVICE_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_END_OF_FILE: +- reason = "STATUS_END_OF_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME: +- reason = "STATUS_WRONG_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE: +- reason = "STATUS_NO_MEDIA_IN_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA: +- reason = "STATUS_UNRECOGNIZED_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR: +- reason = "STATUS_NONEXISTENT_SECTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED: +- reason = "STATUS_MORE_PROCESSING_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MEMORY: +- reason = "STATUS_NO_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES: +- reason = "STATUS_CONFLICTING_ADDRESSES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW: +- reason = "STATUS_NOT_MAPPED_VIEW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM: +- reason = "STATUS_UNABLE_TO_FREE_VM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION: +- reason = "STATUS_UNABLE_TO_DELETE_SECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE: +- reason = "STATUS_INVALID_SYSTEM_SERVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION: +- reason = "STATUS_ILLEGAL_INSTRUCTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE: +- reason = "STATUS_INVALID_LOCK_SEQUENCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE: +- reason = "STATUS_INVALID_VIEW_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION: +- reason = "STATUS_INVALID_FILE_FOR_SECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED: +- reason = "STATUS_ALREADY_COMMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED: +- reason = "STATUS_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL: +- reason = "STATUS_BUFFER_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH: +- reason = "STATUS_OBJECT_TYPE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION: +- reason = "STATUS_NONCONTINUABLE_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION: +- reason = "STATUS_INVALID_DISPOSITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNWIND: +- reason = "STATUS_UNWIND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_STACK: +- reason = "STATUS_BAD_STACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET: +- reason = "STATUS_INVALID_UNWIND_TARGET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_LOCKED: +- reason = "STATUS_NOT_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PARITY_ERROR: +- reason = "STATUS_PARITY_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM: +- reason = "STATUS_UNABLE_TO_DECOMMIT_VM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED: +- reason = "STATUS_NOT_COMMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES: +- reason = "STATUS_INVALID_PORT_ATTRIBUTES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG: +- reason = "STATUS_PORT_MESSAGE_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX: +- reason = "STATUS_INVALID_PARAMETER_MIX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER: +- reason = "STATUS_INVALID_QUOTA_LOWER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR: +- reason = "STATUS_DISK_CORRUPT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID: +- reason = "STATUS_OBJECT_NAME_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND: +- reason = "STATUS_OBJECT_NAME_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION: +- reason = "STATUS_OBJECT_NAME_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB: +- reason = "STATUS_PORT_DO_NOT_DISTURB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED: +- reason = "STATUS_PORT_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED: +- reason = "STATUS_DEVICE_ALREADY_ATTACHED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID: +- reason = "STATUS_OBJECT_PATH_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND: +- reason = "STATUS_OBJECT_PATH_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD: +- reason = "STATUS_OBJECT_PATH_SYNTAX_BAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN: +- reason = "STATUS_DATA_OVERRUN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR: +- reason = "STATUS_DATA_LATE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_ERROR: +- reason = "STATUS_DATA_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRC_ERROR: +- reason = "STATUS_CRC_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG: +- reason = "STATUS_SECTION_TOO_BIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED: +- reason = "STATUS_PORT_CONNECTION_REFUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE: +- reason = "STATUS_INVALID_PORT_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION: +- reason = "STATUS_SHARING_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED: +- reason = "STATUS_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION: +- reason = "STATUS_INVALID_PAGE_PROTECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED: +- reason = "STATUS_MUTANT_NOT_OWNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED: +- reason = "STATUS_SEMAPHORE_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET: +- reason = "STATUS_PORT_ALREADY_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE: +- reason = "STATUS_SECTION_NOT_IMAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED: +- reason = "STATUS_SUSPEND_COUNT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING: +- reason = "STATUS_THREAD_IS_TERMINATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT: +- reason = "STATUS_BAD_WORKING_SET_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP: +- reason = "STATUS_INCOMPATIBLE_FILE_MAP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION: +- reason = "STATUS_SECTION_PROTECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED: +- reason = "STATUS_EAS_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE: +- reason = "STATUS_EA_TOO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY: +- reason = "STATUS_NONEXISTENT_EA_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE: +- reason = "STATUS_NO_EAS_ON_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR: +- reason = "STATUS_EA_CORRUPT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT: +- reason = "STATUS_FILE_LOCK_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED: +- reason = "STATUS_LOCK_NOT_GRANTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DELETE_PENDING: +- reason = "STATUS_DELETE_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED: +- reason = "STATUS_CTL_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION: +- reason = "STATUS_UNKNOWN_REVISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH: +- reason = "STATUS_REVISION_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_OWNER: +- reason = "STATUS_INVALID_OWNER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP: +- reason = "STATUS_INVALID_PRIMARY_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN: +- reason = "STATUS_NO_IMPERSONATION_TOKEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY: +- reason = "STATUS_CANT_DISABLE_MANDATORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS: +- reason = "STATUS_NO_LOGON_SERVERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION: +- reason = "STATUS_NO_SUCH_LOGON_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE: +- reason = "STATUS_NO_SUCH_PRIVILEGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD: +- reason = "STATUS_PRIVILEGE_NOT_HELD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME: +- reason = "STATUS_INVALID_ACCOUNT_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER_EXISTS: +- reason = "STATUS_USER_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER: +- reason = "STATUS_NO_SUCH_USER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS: +- reason = "STATUS_GROUP_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP: +- reason = "STATUS_NO_SUCH_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP: +- reason = "STATUS_MEMBER_IN_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP: +- reason = "STATUS_MEMBER_NOT_IN_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LAST_ADMIN: +- reason = "STATUS_LAST_ADMIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD: +- reason = "STATUS_WRONG_PASSWORD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD: +- reason = "STATUS_ILL_FORMED_PASSWORD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION: +- reason = "STATUS_PASSWORD_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE: +- reason = "STATUS_LOGON_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION: +- reason = "STATUS_ACCOUNT_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS: +- reason = "STATUS_INVALID_LOGON_HOURS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION: +- reason = "STATUS_INVALID_WORKSTATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED: +- reason = "STATUS_PASSWORD_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED: +- reason = "STATUS_ACCOUNT_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NONE_MAPPED: +- reason = "STATUS_NONE_MAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED: +- reason = "STATUS_TOO_MANY_LUIDS_REQUESTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED: +- reason = "STATUS_LUIDS_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY: +- reason = "STATUS_INVALID_SUB_AUTHORITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ACL: +- reason = "STATUS_INVALID_ACL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SID: +- reason = "STATUS_INVALID_SID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR: +- reason = "STATUS_INVALID_SECURITY_DESCR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND: +- reason = "STATUS_PROCEDURE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT: +- reason = "STATUS_INVALID_IMAGE_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TOKEN: +- reason = "STATUS_NO_TOKEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL: +- reason = "STATUS_BAD_INHERITANCE_ACL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED: +- reason = "STATUS_RANGE_NOT_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_FULL: +- reason = "STATUS_DISK_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED: +- reason = "STATUS_SERVER_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED: +- reason = "STATUS_SERVER_NOT_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED: +- reason = "STATUS_TOO_MANY_GUIDS_REQUESTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED: +- reason = "STATUS_GUIDS_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY: +- reason = "STATUS_INVALID_ID_AUTHORITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED: +- reason = "STATUS_AGENTS_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL: +- reason = "STATUS_INVALID_VOLUME_LABEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED: +- reason = "STATUS_SECTION_NOT_EXTENDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA: +- reason = "STATUS_NOT_MAPPED_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND: +- reason = "STATUS_RESOURCE_DATA_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND: +- reason = "STATUS_RESOURCE_TYPE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND: +- reason = "STATUS_RESOURCE_NAME_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED: +- reason = "STATUS_ARRAY_BOUNDS_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND: +- reason = "STATUS_FLOAT_DENORMAL_OPERAND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO: +- reason = "STATUS_FLOAT_DIVIDE_BY_ZERO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT: +- reason = "STATUS_FLOAT_INEXACT_RESULT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION: +- reason = "STATUS_FLOAT_INVALID_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW: +- reason = "STATUS_FLOAT_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK: +- reason = "STATUS_FLOAT_STACK_CHECK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW: +- reason = "STATUS_FLOAT_UNDERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO: +- reason = "STATUS_INTEGER_DIVIDE_BY_ZERO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW: +- reason = "STATUS_INTEGER_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION: +- reason = "STATUS_PRIVILEGED_INSTRUCTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES: +- reason = "STATUS_TOO_MANY_PAGING_FILES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_INVALID: +- reason = "STATUS_FILE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED: +- reason = "STATUS_ALLOTTED_SPACE_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES: +- reason = "STATUS_INSUFFICIENT_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND: +- reason = "STATUS_DFS_EXIT_PATH_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR: +- reason = "STATUS_DEVICE_DATA_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED: +- reason = "STATUS_DEVICE_NOT_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE: +- reason = "STATUS_DEVICE_POWER_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE: +- reason = "STATUS_FREE_VM_NOT_AT_BASE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED: +- reason = "STATUS_MEMORY_NOT_ALLOCATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA: +- reason = "STATUS_WORKING_SET_QUOTA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED: +- reason = "STATUS_MEDIA_WRITE_PROTECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY: +- reason = "STATUS_DEVICE_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES: +- reason = "STATUS_INVALID_GROUP_ATTRIBUTES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL: +- reason = "STATUS_BAD_IMPERSONATION_LEVEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS: +- reason = "STATUS_CANT_OPEN_ANONYMOUS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS: +- reason = "STATUS_BAD_VALIDATION_CLASS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE: +- reason = "STATUS_BAD_TOKEN_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD: +- reason = "STATUS_BAD_MASTER_BOOT_RECORD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT: +- reason = "STATUS_INSTRUCTION_MISALIGNMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE: +- reason = "STATUS_INSTANCE_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE: +- reason = "STATUS_PIPE_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE: +- reason = "STATUS_INVALID_PIPE_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_BUSY: +- reason = "STATUS_PIPE_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION: +- reason = "STATUS_ILLEGAL_FUNCTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED: +- reason = "STATUS_PIPE_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING: +- reason = "STATUS_PIPE_CLOSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED: +- reason = "STATUS_PIPE_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING: +- reason = "STATUS_PIPE_LISTENING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE: +- reason = "STATUS_INVALID_READ_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT: +- reason = "STATUS_IO_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED: +- reason = "STATUS_FILE_FORCED_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED: +- reason = "STATUS_PROFILING_NOT_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED: +- reason = "STATUS_PROFILING_NOT_STOPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET: +- reason = "STATUS_COULD_NOT_INTERPRET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY: +- reason = "STATUS_FILE_IS_A_DIRECTORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED: +- reason = "STATUS_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING: +- reason = "STATUS_REMOTE_NOT_LISTENING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME: +- reason = "STATUS_DUPLICATE_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH: +- reason = "STATUS_BAD_NETWORK_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY: +- reason = "STATUS_NETWORK_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST: +- reason = "STATUS_DEVICE_DOES_NOT_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS: +- reason = "STATUS_TOO_MANY_COMMANDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR: +- reason = "STATUS_ADAPTER_HARDWARE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE: +- reason = "STATUS_INVALID_NETWORK_RESPONSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR: +- reason = "STATUS_UNEXPECTED_NETWORK_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER: +- reason = "STATUS_BAD_REMOTE_ADAPTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL: +- reason = "STATUS_PRINT_QUEUE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE: +- reason = "STATUS_NO_SPOOL_SPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED: +- reason = "STATUS_PRINT_CANCELLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED: +- reason = "STATUS_NETWORK_NAME_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED: +- reason = "STATUS_NETWORK_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE: +- reason = "STATUS_BAD_DEVICE_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME: +- reason = "STATUS_BAD_NETWORK_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES: +- reason = "STATUS_TOO_MANY_NAMES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS: +- reason = "STATUS_TOO_MANY_SESSIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED: +- reason = "STATUS_SHARING_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED: +- reason = "STATUS_REQUEST_NOT_ACCEPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED: +- reason = "STATUS_REDIRECTOR_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT: +- reason = "STATUS_NET_WRITE_FAULT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT: +- reason = "STATUS_PROFILING_AT_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE: +- reason = "STATUS_NOT_SAME_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_RENAMED: +- reason = "STATUS_FILE_RENAMED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED: +- reason = "STATUS_VIRTUAL_CIRCUIT_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT: +- reason = "STATUS_NO_SECURITY_ON_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_WAIT: +- reason = "STATUS_CANT_WAIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY: +- reason = "STATUS_PIPE_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO: +- reason = "STATUS_CANT_ACCESS_DOMAIN_INFO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF: +- reason = "STATUS_CANT_TERMINATE_SELF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE: +- reason = "STATUS_INVALID_SERVER_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE: +- reason = "STATUS_INVALID_DOMAIN_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE: +- reason = "STATUS_INVALID_DOMAIN_ROLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN: +- reason = "STATUS_NO_SUCH_DOMAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS: +- reason = "STATUS_DOMAIN_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED: +- reason = "STATUS_DOMAIN_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED: +- reason = "STATUS_OPLOCK_NOT_GRANTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL: +- reason = "STATUS_INVALID_OPLOCK_PROTOCOL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION: +- reason = "STATUS_INTERNAL_DB_CORRUPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR: +- reason = "STATUS_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED: +- reason = "STATUS_GENERIC_NOT_MAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT: +- reason = "STATUS_BAD_DESCRIPTOR_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER: +- reason = "STATUS_INVALID_USER_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR: +- reason = "STATUS_UNEXPECTED_IO_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR: +- reason = "STATUS_UNEXPECTED_MM_CREATE_ERR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR: +- reason = "STATUS_UNEXPECTED_MM_MAP_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR: +- reason = "STATUS_UNEXPECTED_MM_EXTEND_ERR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS: +- reason = "STATUS_NOT_LOGON_PROCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS: +- reason = "STATUS_LOGON_SESSION_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1: +- reason = "STATUS_INVALID_PARAMETER_1"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2: +- reason = "STATUS_INVALID_PARAMETER_2"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3: +- reason = "STATUS_INVALID_PARAMETER_3"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4: +- reason = "STATUS_INVALID_PARAMETER_4"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5: +- reason = "STATUS_INVALID_PARAMETER_5"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6: +- reason = "STATUS_INVALID_PARAMETER_6"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7: +- reason = "STATUS_INVALID_PARAMETER_7"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8: +- reason = "STATUS_INVALID_PARAMETER_8"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9: +- reason = "STATUS_INVALID_PARAMETER_9"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10: +- reason = "STATUS_INVALID_PARAMETER_10"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11: +- reason = "STATUS_INVALID_PARAMETER_11"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12: +- reason = "STATUS_INVALID_PARAMETER_12"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED: +- reason = "STATUS_REDIRECTOR_NOT_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED: +- reason = "STATUS_REDIRECTOR_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW: +- reason = "STATUS_STACK_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE: +- reason = "STATUS_NO_SUCH_PACKAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE: +- reason = "STATUS_BAD_FUNCTION_TABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND: +- reason = "STATUS_VARIABLE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY: +- reason = "STATUS_DIRECTORY_NOT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR: +- reason = "STATUS_FILE_CORRUPT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY: +- reason = "STATUS_NOT_A_DIRECTORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE: +- reason = "STATUS_BAD_LOGON_SESSION_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION: +- reason = "STATUS_LOGON_SESSION_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG: +- reason = "STATUS_NAME_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILES_OPEN: +- reason = "STATUS_FILES_OPEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE: +- reason = "STATUS_CONNECTION_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND: +- reason = "STATUS_MESSAGE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING: +- reason = "STATUS_PROCESS_IS_TERMINATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE: +- reason = "STATUS_INVALID_LOGON_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION: +- reason = "STATUS_NO_GUID_TRANSLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE: +- reason = "STATUS_CANNOT_IMPERSONATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED: +- reason = "STATUS_IMAGE_ALREADY_LOADED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT: +- reason = "STATUS_ABIOS_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST: +- reason = "STATUS_ABIOS_LID_NOT_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED: +- reason = "STATUS_ABIOS_LID_ALREADY_OWNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER: +- reason = "STATUS_ABIOS_NOT_LID_OWNER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND: +- reason = "STATUS_ABIOS_INVALID_COMMAND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID: +- reason = "STATUS_ABIOS_INVALID_LID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE: +- reason = "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR: +- reason = "STATUS_ABIOS_INVALID_SELECTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_LDT: +- reason = "STATUS_NO_LDT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE: +- reason = "STATUS_INVALID_LDT_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET: +- reason = "STATUS_INVALID_LDT_OFFSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR: +- reason = "STATUS_INVALID_LDT_DESCRIPTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT: +- reason = "STATUS_INVALID_IMAGE_NE_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE: +- reason = "STATUS_RXACT_INVALID_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE: +- reason = "STATUS_RXACT_COMMIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO: +- reason = "STATUS_MAPPED_FILE_SIZE_ZERO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES: +- reason = "STATUS_TOO_MANY_OPENED_FILES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANCELLED: +- reason = "STATUS_CANCELLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE: +- reason = "STATUS_CANNOT_DELETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME: +- reason = "STATUS_INVALID_COMPUTER_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_DELETED: +- reason = "STATUS_FILE_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT: +- reason = "STATUS_SPECIAL_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP: +- reason = "STATUS_SPECIAL_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPECIAL_USER: +- reason = "STATUS_SPECIAL_USER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP: +- reason = "STATUS_MEMBERS_PRIMARY_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_CLOSED: +- reason = "STATUS_FILE_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS: +- reason = "STATUS_TOO_MANY_THREADS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS: +- reason = "STATUS_THREAD_NOT_IN_PROCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE: +- reason = "STATUS_TOKEN_ALREADY_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED: +- reason = "STATUS_PAGEFILE_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT: +- reason = "STATUS_COMMITMENT_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT: +- reason = "STATUS_INVALID_IMAGE_LE_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ: +- reason = "STATUS_INVALID_IMAGE_NOT_MZ"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT: +- reason = "STATUS_INVALID_IMAGE_PROTECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16: +- reason = "STATUS_INVALID_IMAGE_WIN_16"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT: +- reason = "STATUS_LOGON_SERVER_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC: +- reason = "STATUS_TIME_DIFFERENCE_AT_DC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED: +- reason = "STATUS_SYNCHRONIZATION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND: +- reason = "STATUS_DLL_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPEN_FAILED: +- reason = "STATUS_OPEN_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED: +- reason = "STATUS_IO_PRIVILEGE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND: +- reason = "STATUS_ORDINAL_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND: +- reason = "STATUS_ENTRYPOINT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT: +- reason = "STATUS_CONTROL_C_EXIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT: +- reason = "STATUS_LOCAL_DISCONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT: +- reason = "STATUS_REMOTE_DISCONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES: +- reason = "STATUS_REMOTE_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LINK_FAILED: +- reason = "STATUS_LINK_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT: +- reason = "STATUS_LINK_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION: +- reason = "STATUS_INVALID_CONNECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS: +- reason = "STATUS_INVALID_ADDRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED: +- reason = "STATUS_DLL_INIT_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE: +- reason = "STATUS_MISSING_SYSTEMFILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION: +- reason = "STATUS_UNHANDLED_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE: +- reason = "STATUS_APP_INIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED: +- reason = "STATUS_PAGEFILE_CREATE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE: +- reason = "STATUS_NO_PAGEFILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL: +- reason = "STATUS_INVALID_LEVEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE: +- reason = "STATUS_WRONG_PASSWORD_CORE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT: +- reason = "STATUS_ILLEGAL_FLOAT_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN: +- reason = "STATUS_PIPE_BROKEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT: +- reason = "STATUS_REGISTRY_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED: +- reason = "STATUS_REGISTRY_IO_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR: +- reason = "STATUS_NO_EVENT_PAIR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME: +- reason = "STATUS_UNRECOGNIZED_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED: +- reason = "STATUS_SERIAL_NO_DEVICE_INITED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS: +- reason = "STATUS_NO_SUCH_ALIAS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS: +- reason = "STATUS_MEMBER_NOT_IN_ALIAS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS: +- reason = "STATUS_MEMBER_IN_ALIAS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS: +- reason = "STATUS_ALIAS_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED: +- reason = "STATUS_LOGON_NOT_GRANTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS: +- reason = "STATUS_TOO_MANY_SECRETS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG: +- reason = "STATUS_SECRET_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR: +- reason = "STATUS_INTERNAL_DB_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE: +- reason = "STATUS_FULLSCREEN_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS: +- reason = "STATUS_TOO_MANY_CONTEXT_IDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED: +- reason = "STATUS_LOGON_TYPE_NOT_GRANTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE: +- reason = "STATUS_NOT_REGISTRY_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED: +- reason = "STATUS_NT_CROSS_ENCRYPTION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR: +- reason = "STATUS_DOMAIN_CTRLR_CONFIG_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER: +- reason = "STATUS_FT_MISSING_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY: +- reason = "STATUS_ILL_FORMED_SERVICE_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER: +- reason = "STATUS_ILLEGAL_CHARACTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER: +- reason = "STATUS_UNMAPPABLE_CHARACTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER: +- reason = "STATUS_UNDEFINED_CHARACTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME: +- reason = "STATUS_FLOPPY_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND: +- reason = "STATUS_FLOPPY_ID_MARK_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER: +- reason = "STATUS_FLOPPY_WRONG_CYLINDER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR: +- reason = "STATUS_FLOPPY_UNKNOWN_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS: +- reason = "STATUS_FLOPPY_BAD_REGISTERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED: +- reason = "STATUS_DISK_RECALIBRATE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED: +- reason = "STATUS_DISK_OPERATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED: +- reason = "STATUS_DISK_RESET_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY: +- reason = "STATUS_SHARED_IRQ_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_ORPHANING: +- reason = "STATUS_FT_ORPHANING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT: +- reason = "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE: +- reason = "STATUS_PARTITION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH: +- reason = "STATUS_INVALID_BLOCK_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED: +- reason = "STATUS_DEVICE_NOT_PARTITIONED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA: +- reason = "STATUS_UNABLE_TO_LOCK_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA: +- reason = "STATUS_UNABLE_TO_UNLOAD_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW: +- reason = "STATUS_EOM_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MEDIA: +- reason = "STATUS_NO_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER: +- reason = "STATUS_NO_SUCH_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER: +- reason = "STATUS_INVALID_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KEY_DELETED: +- reason = "STATUS_KEY_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE: +- reason = "STATUS_NO_LOG_SPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS: +- reason = "STATUS_TOO_MANY_SIDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED: +- reason = "STATUS_LM_CROSS_ENCRYPTION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN: +- reason = "STATUS_KEY_HAS_CHILDREN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE: +- reason = "STATUS_CHILD_MUST_BE_VOLATILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR: +- reason = "STATUS_DEVICE_CONFIGURATION_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR: +- reason = "STATUS_DRIVER_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE: +- reason = "STATUS_INVALID_DEVICE_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR: +- reason = "STATUS_IO_DEVICE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR: +- reason = "STATUS_DEVICE_PROTOCOL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER: +- reason = "STATUS_BACKUP_CONTROLLER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL: +- reason = "STATUS_LOG_FILE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_LATE: +- reason = "STATUS_TOO_LATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET: +- reason = "STATUS_NO_TRUST_LSA_SECRET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT: +- reason = "STATUS_NO_TRUST_SAM_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE: +- reason = "STATUS_TRUSTED_DOMAIN_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE: +- reason = "STATUS_TRUSTED_RELATIONSHIP_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT: +- reason = "STATUS_EVENTLOG_FILE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START: +- reason = "STATUS_EVENTLOG_CANT_START"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE: +- reason = "STATUS_TRUST_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED: +- reason = "STATUS_MUTANT_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED: +- reason = "STATUS_NETLOGON_NOT_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED: +- reason = "STATUS_ACCOUNT_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK: +- reason = "STATUS_POSSIBLE_DEADLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT: +- reason = "STATUS_NETWORK_CREDENTIAL_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT: +- reason = "STATUS_REMOTE_SESSION_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED: +- reason = "STATUS_EVENTLOG_FILE_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: +- reason = "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT: +- reason = "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT: +- reason = "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT: +- reason = "STATUS_DOMAIN_TRUST_INCONSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED: +- reason = "STATUS_FS_DRIVER_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL: +- reason = "STATUS_IMAGE_ALREADY_LOADED_AS_DLL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING: +- reason = "STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME: +- reason = "STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT: +- reason = "STATUS_SECURITY_STREAM_IS_INCONSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE: +- reason = "STATUS_INVALID_LOCK_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION: +- reason = "STATUS_INVALID_ACE_CONDITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: +- reason = "STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED: +- reason = "STATUS_NOTIFICATION_GUID_ALREADY_DEFINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER: +- reason = "STATUS_INVALID_EXCEPTION_HANDLER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES: +- reason = "STATUS_DUPLICATE_PRIVILEGES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE: +- reason = "STATUS_NOT_ALLOWED_ON_SYSTEM_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED: +- reason = "STATUS_REPAIR_NEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED: +- reason = "STATUS_QUOTA_NOT_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE: +- reason = "STATUS_NO_APPLICATION_PACKAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS: +- reason = "STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT: +- reason = "STATUS_NOT_SAME_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION: +- reason = "STATUS_FATAL_MEMORY_EXHAUSTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB: +- reason = "STATUS_ERROR_PROCESS_NOT_IN_JOB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID: +- reason = "STATUS_CPU_SET_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA: +- reason = "STATUS_IO_DEVICE_INVALID_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE: +- reason = "STATUS_IO_UNALIGNED_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION: +- reason = "STATUS_CONTROL_STACK_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION: +- reason = "STATUS_NETWORK_OPEN_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY: +- reason = "STATUS_NO_USER_SESSION_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED: +- reason = "STATUS_USER_SESSION_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND: +- reason = "STATUS_RESOURCE_LANG_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES: +- reason = "STATUS_INSUFF_SERVER_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE: +- reason = "STATUS_INVALID_BUFFER_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT: +- reason = "STATUS_INVALID_ADDRESS_COMPONENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD: +- reason = "STATUS_INVALID_ADDRESS_WILDCARD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES: +- reason = "STATUS_TOO_MANY_ADDRESSES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS: +- reason = "STATUS_ADDRESS_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED: +- reason = "STATUS_ADDRESS_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED: +- reason = "STATUS_CONNECTION_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET: +- reason = "STATUS_CONNECTION_RESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES: +- reason = "STATUS_TOO_MANY_NODES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED: +- reason = "STATUS_TRANSACTION_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT: +- reason = "STATUS_TRANSACTION_TIMED_OUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE: +- reason = "STATUS_TRANSACTION_NO_RELEASE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH: +- reason = "STATUS_TRANSACTION_NO_MATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED: +- reason = "STATUS_TRANSACTION_RESPONDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID: +- reason = "STATUS_TRANSACTION_INVALID_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE: +- reason = "STATUS_TRANSACTION_INVALID_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION: +- reason = "STATUS_NOT_SERVER_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION: +- reason = "STATUS_NOT_CLIENT_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE: +- reason = "STATUS_CANNOT_LOAD_REGISTRY_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED: +- reason = "STATUS_DEBUG_ATTACH_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED: +- reason = "STATUS_SYSTEM_PROCESS_TERMINATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED: +- reason = "STATUS_DATA_NOT_ACCEPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND: +- reason = "STATUS_NO_BROWSER_SERVERS_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR: +- reason = "STATUS_VDM_HARD_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT: +- reason = "STATUS_DRIVER_CANCEL_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH: +- reason = "STATUS_REPLY_MESSAGE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT: +- reason = "STATUS_MAPPED_ALIGNMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH: +- reason = "STATUS_IMAGE_CHECKSUM_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA: +- reason = "STATUS_LOST_WRITEBEHIND_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID: +- reason = "STATUS_CLIENT_SERVER_PARAMETERS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE: +- reason = "STATUS_PASSWORD_MUST_CHANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_FOUND: +- reason = "STATUS_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM: +- reason = "STATUS_NOT_TINY_STREAM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE: +- reason = "STATUS_RECOVERY_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ: +- reason = "STATUS_STACK_OVERFLOW_READ"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FAIL_CHECK: +- reason = "STATUS_FAIL_CHECK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID: +- reason = "STATUS_DUPLICATE_OBJECTID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS: +- reason = "STATUS_OBJECTID_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE: +- reason = "STATUS_CONVERT_TO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RETRY: +- reason = "STATUS_RETRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE: +- reason = "STATUS_FOUND_OUT_OF_SCOPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET: +- reason = "STATUS_ALLOCATE_BUCKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND: +- reason = "STATUS_PROPSET_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW: +- reason = "STATUS_MARSHALL_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT: +- reason = "STATUS_INVALID_VARIANT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND: +- reason = "STATUS_DOMAIN_CONTROLLER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT: +- reason = "STATUS_ACCOUNT_LOCKED_OUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE: +- reason = "STATUS_HANDLE_NOT_CLOSABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED: +- reason = "STATUS_CONNECTION_REFUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT: +- reason = "STATUS_GRACEFUL_DISCONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED: +- reason = "STATUS_ADDRESS_ALREADY_ASSOCIATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED: +- reason = "STATUS_ADDRESS_NOT_ASSOCIATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID: +- reason = "STATUS_CONNECTION_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE: +- reason = "STATUS_CONNECTION_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE: +- reason = "STATUS_NETWORK_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE: +- reason = "STATUS_HOST_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE: +- reason = "STATUS_PROTOCOL_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE: +- reason = "STATUS_PORT_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED: +- reason = "STATUS_REQUEST_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED: +- reason = "STATUS_CONNECTION_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER: +- reason = "STATUS_BAD_COMPRESSION_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE: +- reason = "STATUS_USER_MAPPED_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED: +- reason = "STATUS_AUDIT_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET: +- reason = "STATUS_TIMER_RESOLUTION_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT: +- reason = "STATUS_CONNECTION_COUNT_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION: +- reason = "STATUS_LOGIN_TIME_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION: +- reason = "STATUS_LOGIN_WKSTA_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH: +- reason = "STATUS_IMAGE_MP_UP_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO: +- reason = "STATUS_INSUFFICIENT_LOGON_INFO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT: +- reason = "STATUS_BAD_DLL_ENTRYPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT: +- reason = "STATUS_BAD_SERVICE_ENTRYPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST: +- reason = "STATUS_LPC_REPLY_LOST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1: +- reason = "STATUS_IP_ADDRESS_CONFLICT1"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2: +- reason = "STATUS_IP_ADDRESS_CONFLICT2"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT: +- reason = "STATUS_REGISTRY_QUOTA_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED: +- reason = "STATUS_PATH_NOT_COVERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE: +- reason = "STATUS_NO_CALLBACK_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED: +- reason = "STATUS_LICENSE_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT: +- reason = "STATUS_PWD_TOO_SHORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT: +- reason = "STATUS_PWD_TOO_RECENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT: +- reason = "STATUS_PWD_HISTORY_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE: +- reason = "STATUS_PLUGPLAY_NO_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION: +- reason = "STATUS_UNSUPPORTED_COMPRESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE: +- reason = "STATUS_INVALID_HW_PROFILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH: +- reason = "STATUS_INVALID_PLUGPLAY_DEVICE_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND: +- reason = "STATUS_DRIVER_ORDINAL_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND: +- reason = "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED: +- reason = "STATUS_RESOURCE_NOT_OWNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS: +- reason = "STATUS_TOO_MANY_LINKS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT: +- reason = "STATUS_QUOTA_LIST_INCONSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE: +- reason = "STATUS_FILE_IS_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION: +- reason = "STATUS_EVALUATION_EXPIRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION: +- reason = "STATUS_ILLEGAL_DLL_RELOCATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION: +- reason = "STATUS_LICENSE_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF: +- reason = "STATUS_DLL_INIT_FAILED_LOGOFF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD: +- reason = "STATUS_DRIVER_UNABLE_TO_LOAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE: +- reason = "STATUS_DFS_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED: +- reason = "STATUS_VOLUME_DISMOUNTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR: +- reason = "STATUS_WX86_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK: +- reason = "STATUS_WX86_FLOAT_STACK_CHECK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE: +- reason = "STATUS_VALIDATE_CONTINUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MATCH: +- reason = "STATUS_NO_MATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES: +- reason = "STATUS_NO_MORE_MATCHES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT: +- reason = "STATUS_NOT_A_REPARSE_POINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID: +- reason = "STATUS_IO_REPARSE_TAG_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH: +- reason = "STATUS_IO_REPARSE_TAG_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID: +- reason = "STATUS_IO_REPARSE_DATA_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED: +- reason = "STATUS_IO_REPARSE_TAG_NOT_HANDLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG: +- reason = "STATUS_PWD_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION: +- reason = "STATUS_STOWED_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION: +- reason = "STATUS_CONTEXT_STOWED_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED: +- reason = "STATUS_REPARSE_POINT_NOT_RESOLVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT: +- reason = "STATUS_DIRECTORY_IS_A_REPARSE_POINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT: +- reason = "STATUS_RANGE_LIST_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY: +- reason = "STATUS_SOURCE_ELEMENT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL: +- reason = "STATUS_DESTINATION_ELEMENT_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS: +- reason = "STATUS_ILLEGAL_ELEMENT_ADDRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT: +- reason = "STATUS_MAGAZINE_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED: +- reason = "STATUS_REINITIALIZATION_NEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED: +- reason = "STATUS_ENCRYPTION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED: +- reason = "STATUS_DECRYPTION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND: +- reason = "STATUS_RANGE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY: +- reason = "STATUS_NO_RECOVERY_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_EFS: +- reason = "STATUS_NO_EFS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_EFS: +- reason = "STATUS_WRONG_EFS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS: +- reason = "STATUS_NO_USER_KEYS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED: +- reason = "STATUS_FILE_NOT_ENCRYPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT: +- reason = "STATUS_NOT_EXPORT_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED: +- reason = "STATUS_FILE_ENCRYPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND: +- reason = "STATUS_WMI_GUID_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND: +- reason = "STATUS_WMI_INSTANCE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND: +- reason = "STATUS_WMI_ITEMID_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN: +- reason = "STATUS_WMI_TRY_AGAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHARED_POLICY: +- reason = "STATUS_SHARED_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND: +- reason = "STATUS_POLICY_OBJECT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS: +- reason = "STATUS_POLICY_ONLY_IN_DS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED: +- reason = "STATUS_VOLUME_NOT_UPGRADED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE: +- reason = "STATUS_REMOTE_STORAGE_NOT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR: +- reason = "STATUS_REMOTE_STORAGE_MEDIA_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE: +- reason = "STATUS_NO_TRACKING_SERVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH: +- reason = "STATUS_SERVER_SID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE: +- reason = "STATUS_DS_NO_ATTRIBUTE_OR_VALUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX: +- reason = "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED: +- reason = "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS: +- reason = "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_BUSY: +- reason = "STATUS_DS_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE: +- reason = "STATUS_DS_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED: +- reason = "STATUS_DS_NO_RIDS_ALLOCATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS: +- reason = "STATUS_DS_NO_MORE_RIDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER: +- reason = "STATUS_DS_INCORRECT_ROLE_OWNER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR: +- reason = "STATUS_DS_RIDMGR_INIT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION: +- reason = "STATUS_DS_OBJ_CLASS_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF: +- reason = "STATUS_DS_CANT_ON_NON_LEAF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN: +- reason = "STATUS_DS_CANT_ON_RDN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS: +- reason = "STATUS_DS_CANT_MOD_OBJ_CLASS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED: +- reason = "STATUS_DS_CROSS_DOM_MOVE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE: +- reason = "STATUS_DS_GC_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED: +- reason = "STATUS_DIRECTORY_SERVICE_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT: +- reason = "STATUS_REPARSE_ATTRIBUTE_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY: +- reason = "STATUS_CANT_ENABLE_DENY_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS: +- reason = "STATUS_FLOAT_MULTIPLE_FAULTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS: +- reason = "STATUS_FLOAT_MULTIPLE_TRAPS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED: +- reason = "STATUS_DEVICE_REMOVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS: +- reason = "STATUS_JOURNAL_DELETE_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE: +- reason = "STATUS_JOURNAL_NOT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOINTERFACE: +- reason = "STATUS_NOINTERFACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED: +- reason = "STATUS_DS_RIDMGR_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED: +- reason = "STATUS_DS_ADMIN_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP: +- reason = "STATUS_DRIVER_FAILED_SLEEP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED: +- reason = "STATUS_MUTUAL_AUTHENTICATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE: +- reason = "STATUS_CORRUPT_SYSTEM_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR: +- reason = "STATUS_DATATYPE_MISALIGNMENT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY: +- reason = "STATUS_WMI_READ_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE: +- reason = "STATUS_WMI_SET_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM: +- reason = "STATUS_COMMITMENT_MINIMUM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION: +- reason = "STATUS_REG_NAT_CONSUMPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL: +- reason = "STATUS_TRANSPORT_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE: +- reason = "STATUS_DS_SAM_INIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED: +- reason = "STATUS_ONLY_IF_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION: +- reason = "STATUS_DS_SENSITIVE_GROUP_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION: +- reason = "STATUS_PNP_RESTART_ENUMERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED: +- reason = "STATUS_JOURNAL_ENTRY_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID: +- reason = "STATUS_DS_CANT_MOD_PRIMARYGROUPID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: +- reason = "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED: +- reason = "STATUS_PNP_REBOOT_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID: +- reason = "STATUS_POWER_STATE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE: +- reason = "STATUS_DS_INVALID_GROUP_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: +- reason = "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: +- reason = "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: +- reason = "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: +- reason = "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: +- reason = "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: +- reason = "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: +- reason = "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS: +- reason = "STATUS_DS_HAVE_PRIMARY_MEMBERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED: +- reason = "STATUS_WMI_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER: +- reason = "STATUS_INSUFFICIENT_POWER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD: +- reason = "STATUS_SAM_NEED_BOOTKEY_PASSWORD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY: +- reason = "STATUS_SAM_NEED_BOOTKEY_FLOPPY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_CANT_START: +- reason = "STATUS_DS_CANT_START"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE: +- reason = "STATUS_DS_INIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE: +- reason = "STATUS_SAM_INIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED: +- reason = "STATUS_DS_GC_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: +- reason = "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS: +- reason = "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: +- reason = "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION: +- reason = "STATUS_MULTIPLE_FAULT_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED: +- reason = "STATUS_CURRENT_DOMAIN_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE: +- reason = "STATUS_CANNOT_MAKE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN: +- reason = "STATUS_SYSTEM_SHUTDOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE: +- reason = "STATUS_DS_INIT_FAILURE_CONSOLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE: +- reason = "STATUS_DS_SAM_INIT_FAILURE_CONSOLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED: +- reason = "STATUS_UNFINISHED_CONTEXT_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY: +- reason = "STATUS_NO_TGT_REPLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND: +- reason = "STATUS_OBJECTID_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES: +- reason = "STATUS_NO_IP_ADDRESSES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE: +- reason = "STATUS_WRONG_CREDENTIAL_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID: +- reason = "STATUS_CRYPTO_SYSTEM_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED: +- reason = "STATUS_MAX_REFERRALS_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC: +- reason = "STATUS_MUST_BE_KDC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED: +- reason = "STATUS_STRONG_CRYPTO_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS: +- reason = "STATUS_TOO_MANY_PRINCIPALS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_PA_DATA: +- reason = "STATUS_NO_PA_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH: +- reason = "STATUS_PKINIT_NAME_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED: +- reason = "STATUS_SMARTCARD_LOGON_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST: +- reason = "STATUS_KDC_INVALID_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER: +- reason = "STATUS_KDC_UNABLE_TO_REFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE: +- reason = "STATUS_KDC_UNKNOWN_ETYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS: +- reason = "STATUS_SHUTDOWN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS: +- reason = "STATUS_SERVER_SHUTDOWN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS: +- reason = "STATUS_NOT_SUPPORTED_ON_SBS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED: +- reason = "STATUS_WMI_GUID_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED: +- reason = "STATUS_WMI_ALREADY_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED: +- reason = "STATUS_WMI_ALREADY_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED: +- reason = "STATUS_MFT_TOO_FRAGMENTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE: +- reason = "STATUS_COPY_PROTECTION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE: +- reason = "STATUS_CSS_AUTHENTICATION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT: +- reason = "STATUS_CSS_KEY_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED: +- reason = "STATUS_CSS_KEY_NOT_ESTABLISHED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR: +- reason = "STATUS_CSS_SCRAMBLED_SECTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH: +- reason = "STATUS_CSS_REGION_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED: +- reason = "STATUS_CSS_RESETS_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED: +- reason = "STATUS_PASSWORD_CHANGE_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION: +- reason = "STATUS_LOST_MODE_LOGON_RESTRICTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE: +- reason = "STATUS_PKINIT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE: +- reason = "STATUS_SMARTCARD_SUBSYSTEM_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY: +- reason = "STATUS_NO_KERB_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HOST_DOWN: +- reason = "STATUS_HOST_DOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH: +- reason = "STATUS_UNSUPPORTED_PREAUTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG: +- reason = "STATUS_EFS_ALG_BLOB_TOO_BIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET: +- reason = "STATUS_PORT_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE: +- reason = "STATUS_DEBUGGER_INACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE: +- reason = "STATUS_DS_VERSION_CHECK_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED: +- reason = "STATUS_AUDITING_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT: +- reason = "STATUS_PRENT4_MACHINE_ACCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: +- reason = "STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32: +- reason = "STATUS_INVALID_IMAGE_WIN_32"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64: +- reason = "STATUS_INVALID_IMAGE_WIN_64"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS: +- reason = "STATUS_BAD_BINDINGS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED: +- reason = "STATUS_NETWORK_SESSION_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK: +- reason = "STATUS_APPHELP_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED: +- reason = "STATUS_ALL_SIDS_FILTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER: +- reason = "STATUS_NOT_SAFE_MODE_DRIVER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT: +- reason = "STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH: +- reason = "STATUS_ACCESS_DISABLED_BY_POLICY_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER: +- reason = "STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER: +- reason = "STATUS_ACCESS_DISABLED_BY_POLICY_OTHER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY: +- reason = "STATUS_FAILED_DRIVER_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR: +- reason = "STATUS_DEVICE_ENUMERATION_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED: +- reason = "STATUS_MOUNT_POINT_NOT_RESOLVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER: +- reason = "STATUS_INVALID_DEVICE_OBJECT_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MCA_OCCURED: +- reason = "STATUS_MCA_OCCURED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL: +- reason = "STATUS_DRIVER_BLOCKED_CRITICAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED: +- reason = "STATUS_DRIVER_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR: +- reason = "STATUS_DRIVER_DATABASE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE: +- reason = "STATUS_SYSTEM_HIVE_TOO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL: +- reason = "STATUS_INVALID_IMPORT_OF_NON_DLL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SECRETS: +- reason = "STATUS_NO_SECRETS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY: +- reason = "STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH: +- reason = "STATUS_FAILED_STACK_SWITCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION: +- reason = "STATUS_HEAP_CORRUPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN: +- reason = "STATUS_SMARTCARD_WRONG_PIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED: +- reason = "STATUS_SMARTCARD_CARD_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED: +- reason = "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD: +- reason = "STATUS_SMARTCARD_NO_CARD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER: +- reason = "STATUS_SMARTCARD_NO_KEY_CONTAINER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE: +- reason = "STATUS_SMARTCARD_NO_CERTIFICATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET: +- reason = "STATUS_SMARTCARD_NO_KEYSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR: +- reason = "STATUS_SMARTCARD_IO_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED: +- reason = "STATUS_DOWNGRADE_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED: +- reason = "STATUS_SMARTCARD_CERT_REVOKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED: +- reason = "STATUS_ISSUING_CA_UNTRUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C: +- reason = "STATUS_REVOCATION_OFFLINE_C"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE: +- reason = "STATUS_PKINIT_CLIENT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED: +- reason = "STATUS_SMARTCARD_CERT_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD: +- reason = "STATUS_DRIVER_FAILED_PRIOR_UNLOAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT: +- reason = "STATUS_SMARTCARD_SILENT_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED: +- reason = "STATUS_PER_USER_TRUST_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED: +- reason = "STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED: +- reason = "STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE: +- reason = "STATUS_DS_NAME_NOT_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND: +- reason = "STATUS_DS_DUPLICATE_ID_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR: +- reason = "STATUS_DS_GROUP_CONVERSION_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE: +- reason = "STATUS_VOLSNAP_PREPARE_HIBERNATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED: +- reason = "STATUS_USER2USER_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: +- reason = "STATUS_STACK_BUFFER_OVERRUN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT: +- reason = "STATUS_NO_S4U_PROT_SUPPORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE: +- reason = "STATUS_CROSSREALM_DELEGATION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC: +- reason = "STATUS_REVOCATION_OFFLINE_KDC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC: +- reason = "STATUS_ISSUING_CA_UNTRUSTED_KDC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED: +- reason = "STATUS_KDC_CERT_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED: +- reason = "STATUS_KDC_CERT_REVOKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED: +- reason = "STATUS_PARAMETER_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE: +- reason = "STATUS_HIBERNATION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED: +- reason = "STATUS_DELAY_LOAD_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED: +- reason = "STATUS_AUTHENTICATION_FIREWALL_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED: +- reason = "STATUS_VDM_DISALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD: +- reason = "STATUS_HUNG_DISPLAY_DRIVER_THREAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE: +- reason = "STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER: +- reason = "STATUS_INVALID_CRUNTIME_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED: +- reason = "STATUS_NTLM_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST: +- reason = "STATUS_DS_SRC_SID_EXISTS_IN_FOREST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST: +- reason = "STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST: +- reason = "STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME: +- reason = "STATUS_INVALID_USER_PRINCIPAL_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION: +- reason = "STATUS_FATAL_USER_CALLBACK_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE: +- reason = "STATUS_ASSERTION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP: +- reason = "STATUS_VERIFIER_STOP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK: +- reason = "STATUS_CALLBACK_POP_STACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED: +- reason = "STATUS_INCOMPATIBLE_DRIVER_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED: +- reason = "STATUS_HIVE_UNLOADED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED: +- reason = "STATUS_COMPRESSION_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION: +- reason = "STATUS_FILE_SYSTEM_LIMITATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH: +- reason = "STATUS_INVALID_IMAGE_HASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE: +- reason = "STATUS_NOT_CAPABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE: +- reason = "STATUS_REQUEST_OUT_OF_SEQUENCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT: +- reason = "STATUS_IMPLEMENTATION_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED: +- reason = "STATUS_ELEVATION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT: +- reason = "STATUS_NO_SECURITY_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE: +- reason = "STATUS_PKU2U_CERT_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BEYOND_VDL: +- reason = "STATUS_BEYOND_VDL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS: +- reason = "STATUS_ENCOUNTERED_WRITE_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PTE_CHANGED: +- reason = "STATUS_PTE_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PURGE_FAILED: +- reason = "STATUS_PURGE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION: +- reason = "STATUS_CRED_REQUIRES_CONFIRMATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE: +- reason = "STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER: +- reason = "STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE: +- reason = "STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE: +- reason = "STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE: +- reason = "STATUS_CS_ENCRYPTION_FILE_NOT_CSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_LABEL: +- reason = "STATUS_INVALID_LABEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED: +- reason = "STATUS_DRIVER_PROCESS_TERMINATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE: +- reason = "STATUS_AMBIGUOUS_SYSTEM_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND: +- reason = "STATUS_SYSTEM_DEVICE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION: +- reason = "STATUS_RESTART_BOOT_APPLICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES: +- reason = "STATUS_INSUFFICIENT_NVRAM_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SESSION: +- reason = "STATUS_INVALID_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION: +- reason = "STATUS_THREAD_ALREADY_IN_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION: +- reason = "STATUS_THREAD_NOT_IN_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT: +- reason = "STATUS_INVALID_WEIGHT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED: +- reason = "STATUS_REQUEST_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED: +- reason = "STATUS_NO_RANGES_PROCESSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED: +- reason = "STATUS_DISK_RESOURCES_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION: +- reason = "STATUS_NEEDS_REMEDIATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED: +- reason = "STATUS_DEVICE_FEATURE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE: +- reason = "STATUS_DEVICE_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN: +- reason = "STATUS_INVALID_TOKEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE: +- reason = "STATUS_SERVER_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE: +- reason = "STATUS_FILE_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES: +- reason = "STATUS_DEVICE_INSUFFICIENT_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING: +- reason = "STATUS_PACKAGE_UPDATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY: +- reason = "STATUS_NOT_READ_FROM_COPY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE: +- reason = "STATUS_FT_WRITE_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED: +- reason = "STATUS_FT_DI_SCAN_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED: +- reason = "STATUS_OBJECT_NOT_EXTERNALLY_BACKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN: +- reason = "STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL: +- reason = "STATUS_COMPRESSION_NOT_BENEFICIAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR: +- reason = "STATUS_DATA_CHECKSUM_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION: +- reason = "STATUS_INTERMIXED_KERNEL_EA_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED: +- reason = "STATUS_TRIM_READ_ZERO_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS: +- reason = "STATUS_TOO_MANY_SEGMENT_DESCRIPTORS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT: +- reason = "STATUS_INVALID_OFFSET_ALIGNMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST: +- reason = "STATUS_INVALID_FIELD_IN_PARAMETER_LIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS: +- reason = "STATUS_OPERATION_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH: +- reason = "STATUS_INVALID_INITIATOR_TARGET_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED: +- reason = "STATUS_SCRUB_DATA_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE: +- reason = "STATUS_NOT_REDUNDANT_STORAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED: +- reason = "STATUS_RESIDENT_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED: +- reason = "STATUS_COMPRESSED_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED: +- reason = "STATUS_DIRECTORY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT: +- reason = "STATUS_IO_OPERATION_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION: +- reason = "STATUS_SYSTEM_NEEDS_REMEDIATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN: +- reason = "STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE: +- reason = "STATUS_SHARE_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED: +- reason = "STATUS_APISET_NOT_HOSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT: +- reason = "STATUS_APISET_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR: +- reason = "STATUS_DEVICE_HARDWARE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID: +- reason = "STATUS_FIRMWARE_SLOT_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID: +- reason = "STATUS_FIRMWARE_IMAGE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH: +- reason = "STATUS_STORAGE_TOPOLOGY_ID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE: +- reason = "STATUS_WIM_NOT_BOOTABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS: +- reason = "STATUS_BLOCKED_BY_PARENTAL_CONTROLS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION: +- reason = "STATUS_NEEDS_REGISTRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY: +- reason = "STATUS_QUOTA_ACTIVITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE: +- reason = "STATUS_CALLBACK_INVOKE_INLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES: +- reason = "STATUS_BLOCK_TOO_MANY_REFERENCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES: +- reason = "STATUS_MARKED_TO_DISALLOW_WRITES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP: +- reason = "STATUS_NETWORK_ACCESS_DENIED_EDP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE: +- reason = "STATUS_ENCLAVE_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS: +- reason = "STATUS_PNP_NO_COMPAT_DRIVERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND: +- reason = "STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND: +- reason = "STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE: +- reason = "STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED: +- reason = "STATUS_PNP_FUNCTION_DRIVER_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING: +- reason = "STATUS_PNP_DEVICE_CONFIGURATION_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL: +- reason = "STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE: +- reason = "STATUS_PACKAGE_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE: +- reason = "STATUS_DEVICE_IN_MAINTENANCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX: +- reason = "STATUS_NOT_SUPPORTED_ON_DAX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED: +- reason = "STATUS_FREE_SPACE_TOO_FRAGMENTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS: +- reason = "STATUS_DAX_MAPPING_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED: +- reason = "STATUS_CHILD_PROCESS_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE: +- reason = "STATUS_STORAGE_LOST_DATA_PERSISTENCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED: +- reason = "STATUS_VRF_CFG_AND_IO_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING: +- reason = "STATUS_PARTITION_TERMINATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED: +- reason = "STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION: +- reason = "STATUS_ENCLAVE_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL: +- reason = "STATUS_FILE_PROTECTED_UNDER_DPL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED: +- reason = "STATUS_VOLUME_NOT_CLUSTER_ALIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND: +- reason = "STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED: +- reason = "STATUS_APPX_FILE_NOT_ENCRYPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED: +- reason = "STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET: +- reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE: +- reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER: +- reason = "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE: +- reason = "STATUS_FT_READ_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT: +- reason = "STATUS_PATCH_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID: +- reason = "STATUS_STORAGE_RESERVE_ID_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST: +- reason = "STATUS_STORAGE_RESERVE_DOES_NOT_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS: +- reason = "STATUS_STORAGE_RESERVE_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY: +- reason = "STATUS_STORAGE_RESERVE_NOT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME: +- reason = "STATUS_NOT_A_DAX_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE: +- reason = "STATUS_NOT_DAX_MAPPABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR: +- reason = "STATUS_CASE_DIFFERING_NAMES_IN_DIR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED: +- reason = "STATUS_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT: +- reason = "STATUS_NOT_SUPPORTED_WITH_BTT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED: +- reason = "STATUS_ENCRYPTION_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED: +- reason = "STATUS_ENCRYPTING_METADATA_DISALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG: +- reason = "STATUS_CANT_CLEAR_ENCRYPTION_FLAG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES: +- reason = "STATUS_UNSATISFIED_DEPENDENCIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH: +- reason = "STATUS_CASE_SENSITIVE_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES: +- reason = "STATUS_HAS_SYSTEM_CRITICAL_FILES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME: +- reason = "STATUS_INVALID_TASK_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX: +- reason = "STATUS_INVALID_TASK_INDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK: +- reason = "STATUS_THREAD_ALREADY_IN_TASK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS: +- reason = "STATUS_CALLBACK_BYPASS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE: +- reason = "STATUS_UNDEFINED_SCOPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_CAP: +- reason = "STATUS_INVALID_CAP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS: +- reason = "STATUS_NOT_GUI_PROCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG: +- reason = "STATUS_DEVICE_HUNG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED: +- reason = "STATUS_CONTAINER_ASSIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER: +- reason = "STATUS_JOB_NO_CONTAINER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE: +- reason = "STATUS_DEVICE_UNRESPONSIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED: +- reason = "STATUS_REPARSE_POINT_ENCOUNTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT: +- reason = "STATUS_ATTRIBUTE_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME: +- reason = "STATUS_NOT_A_TIERED_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID: +- reason = "STATUS_ALREADY_HAS_STREAM_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY: +- reason = "STATUS_JOB_NOT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED: +- reason = "STATUS_ALREADY_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED: +- reason = "STATUS_ENCLAVE_NOT_TERMINATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING: +- reason = "STATUS_ENCLAVE_IS_TERMINATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE: +- reason = "STATUS_SMB1_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED: +- reason = "STATUS_SMR_GARBAGE_COLLECTION_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INTERRUPTED: +- reason = "STATUS_INTERRUPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING: +- reason = "STATUS_THREAD_NOT_RUNNING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION: +- reason = "STATUS_FAIL_FAST_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED: +- reason = "STATUS_IMAGE_CERT_REVOKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED: +- reason = "STATUS_DYNAMIC_CODE_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED: +- reason = "STATUS_IMAGE_CERT_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION: +- reason = "STATUS_STRICT_CFG_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED: +- reason = "STATUS_SET_CONTEXT_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION: +- reason = "STATUS_CROSS_PARTITION_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_CLOSED: +- reason = "STATUS_PORT_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST: +- reason = "STATUS_MESSAGE_LOST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE: +- reason = "STATUS_INVALID_MESSAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED: +- reason = "STATUS_REQUEST_CANCELED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH: +- reason = "STATUS_RECURSIVE_DISPATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED: +- reason = "STATUS_LPC_RECEIVE_BUFFER_EXPECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE: +- reason = "STATUS_LPC_INVALID_CONNECTION_USAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED: +- reason = "STATUS_LPC_REQUESTS_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE: +- reason = "STATUS_RESOURCE_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR: +- reason = "STATUS_HARDWARE_MEMORY_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION: +- reason = "STATUS_THREADPOOL_HANDLE_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED: +- reason = "STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED: +- reason = "STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED: +- reason = "STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED: +- reason = "STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION: +- reason = "STATUS_THREADPOOL_RELEASED_DURING_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING: +- reason = "STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING: +- reason = "STATUS_APC_RETURNED_WHILE_IMPERSONATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED: +- reason = "STATUS_PROCESS_IS_PROTECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION: +- reason = "STATUS_MCA_EXCEPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE: +- reason = "STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED: +- reason = "STATUS_SYMLINK_CLASS_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION: +- reason = "STATUS_INVALID_IDN_NORMALIZATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION: +- reason = "STATUS_NO_UNICODE_TRANSLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED: +- reason = "STATUS_ALREADY_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH: +- reason = "STATUS_CONTEXT_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST: +- reason = "STATUS_PORT_ALREADY_HAS_COMPLETION_LIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY: +- reason = "STATUS_CALLBACK_RETURNED_THREAD_PRIORITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_THREAD: +- reason = "STATUS_INVALID_THREAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION: +- reason = "STATUS_CALLBACK_RETURNED_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK: +- reason = "STATUS_CALLBACK_RETURNED_LDR_LOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG: +- reason = "STATUS_CALLBACK_RETURNED_LANG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK: +- reason = "STATUS_CALLBACK_RETURNED_PRI_BACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY: +- reason = "STATUS_CALLBACK_RETURNED_THREAD_AFFINITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED: +- reason = "STATUS_LPC_HANDLE_COUNT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE: +- reason = "STATUS_EXECUTABLE_MEMORY_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE: +- reason = "STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE: +- reason = "STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE: +- reason = "STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED: +- reason = "STATUS_DISK_REPAIR_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS: +- reason = "STATUS_DS_DOMAIN_RENAME_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED: +- reason = "STATUS_DISK_QUOTA_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED: +- reason = "STATUS_CONTENT_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS: +- reason = "STATUS_BAD_CLUSTERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY: +- reason = "STATUS_VOLUME_DIRTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL: +- reason = "STATUS_DISK_REPAIR_UNSUCCESSFUL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL: +- reason = "STATUS_CORRUPT_LOG_OVERFULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED: +- reason = "STATUS_CORRUPT_LOG_CORRUPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE: +- reason = "STATUS_CORRUPT_LOG_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL: +- reason = "STATUS_CORRUPT_LOG_DELETED_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED: +- reason = "STATUS_CORRUPT_LOG_CLEARED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED: +- reason = "STATUS_ORPHAN_NAME_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS: +- reason = "STATUS_PROACTIVE_SCAN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE: +- reason = "STATUS_ENCRYPTED_IO_NOT_POSSIBLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS: +- reason = "STATUS_CORRUPT_LOG_UPLEVEL_RECORDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT: +- reason = "STATUS_FILE_CHECKED_OUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED: +- reason = "STATUS_CHECKOUT_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE: +- reason = "STATUS_BAD_FILE_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE: +- reason = "STATUS_FILE_TOO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED: +- reason = "STATUS_FORMS_AUTH_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED: +- reason = "STATUS_VIRUS_INFECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED: +- reason = "STATUS_VIRUS_DELETED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE: +- reason = "STATUS_BAD_MCFG_TABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK: +- reason = "STATUS_CANNOT_BREAK_OPLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_KEY: +- reason = "STATUS_BAD_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BAD_DATA: +- reason = "STATUS_BAD_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_KEY: +- reason = "STATUS_NO_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED: +- reason = "STATUS_FILE_HANDLE_REVOKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION: +- reason = "STATUS_WOW_ASSERTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE: +- reason = "STATUS_INVALID_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED: +- reason = "STATUS_HMAC_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH: +- reason = "STATUS_AUTH_TAG_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION: +- reason = "STATUS_INVALID_STATE_TRANSITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION: +- reason = "STATUS_INVALID_KERNEL_INFO_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION: +- reason = "STATUS_INVALID_PEP_INFO_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED: +- reason = "STATUS_HANDLE_REVOKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE: +- reason = "STATUS_EOF_ON_GHOSTED_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN: +- reason = "STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW: +- reason = "STATUS_IPSEC_QUEUE_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW: +- reason = "STATUS_ND_QUEUE_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED: +- reason = "STATUS_HOPLIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED: +- reason = "STATUS_PROTOCOL_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED: +- reason = "STATUS_FASTPATH_REJECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED: +- reason = "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR: +- reason = "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR: +- reason = "STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR: +- reason = "STATUS_XML_PARSE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR: +- reason = "STATUS_XMLDSIG_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT: +- reason = "STATUS_WRONG_COMPARTMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE: +- reason = "STATUS_AUTHIP_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS: +- reason = "STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND: +- reason = "STATUS_DS_OID_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE: +- reason = "STATUS_INCORRECT_ACCOUNT_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED: +- reason = "STATUS_HASH_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT: +- reason = "STATUS_HASH_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED: +- reason = "STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID: +- reason = "STATUS_GPIO_CLIENT_INFORMATION_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED: +- reason = "STATUS_GPIO_VERSION_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET: +- reason = "STATUS_GPIO_INVALID_REGISTRATION_PACKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED: +- reason = "STATUS_GPIO_OPERATION_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE: +- reason = "STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL: +- reason = "STATUS_CANNOT_SWITCH_RUNLEVEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING: +- reason = "STATUS_INVALID_RUNLEVEL_SETTING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT: +- reason = "STATUS_RUNLEVEL_SWITCH_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT: +- reason = "STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS: +- reason = "STATUS_RUNLEVEL_SWITCH_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER: +- reason = "STATUS_NOT_APPCONTAINER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER: +- reason = "STATUS_NOT_SUPPORTED_IN_APPCONTAINER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH: +- reason = "STATUS_INVALID_PACKAGE_SID_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED: +- reason = "STATUS_LPAC_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED: +- reason = "STATUS_ADMINLESS_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND: +- reason = "STATUS_APP_DATA_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED: +- reason = "STATUS_APP_DATA_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT: +- reason = "STATUS_APP_DATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED: +- reason = "STATUS_APP_DATA_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED: +- reason = "STATUS_APP_DATA_REBOOT_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED: +- reason = "STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED: +- reason = "STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED: +- reason = "STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: +- reason = "STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT: +- reason = "STATUS_WOF_WIM_HEADER_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT: +- reason = "STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT: +- reason = "STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT: +- reason = "STATUS_CIMFS_IMAGE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE: +- reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT: +- reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY: +- reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN: +- reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION: +- reason = "STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT: +- reason = "STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING: +- reason = "STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT: +- reason = "STATUS_CLOUD_FILE_METADATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE: +- reason = "STATUS_CLOUD_FILE_METADATA_TOO_LARGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED: +- reason = "STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE: +- reason = "STATUS_NOT_A_CLOUD_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC: +- reason = "STATUS_CLOUD_FILE_NOT_IN_SYNC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED: +- reason = "STATUS_CLOUD_FILE_ALREADY_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED: +- reason = "STATUS_CLOUD_FILE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST: +- reason = "STATUS_CLOUD_FILE_INVALID_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME: +- reason = "STATUS_CLOUD_FILE_READ_ONLY_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY: +- reason = "STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED: +- reason = "STATUS_CLOUD_FILE_VALIDATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED: +- reason = "STATUS_CLOUD_FILE_AUTHENTICATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES: +- reason = "STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE: +- reason = "STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL: +- reason = "STATUS_CLOUD_FILE_UNSUCCESSFUL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT: +- reason = "STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE: +- reason = "STATUS_CLOUD_FILE_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED: +- reason = "STATUS_CLOUD_FILE_PINNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED: +- reason = "STATUS_CLOUD_FILE_REQUEST_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT: +- reason = "STATUS_CLOUD_FILE_PROPERTY_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED: +- reason = "STATUS_CLOUD_FILE_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS: +- reason = "STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT: +- reason = "STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED: +- reason = "STATUS_CLOUD_FILE_REQUEST_CANCELED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED: +- reason = "STATUS_CLOUD_FILE_PROVIDER_TERMINATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT: +- reason = "STATUS_NOT_A_CLOUD_SYNC_ROOT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT: +- reason = "STATUS_CLOUD_FILE_REQUEST_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED: +- reason = "STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS: +- reason = "STATUS_FILE_SNAP_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED: +- reason = "STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED: +- reason = "STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED: +- reason = "STATUS_FILE_SNAP_IO_NOT_COORDINATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR: +- reason = "STATUS_FILE_SNAP_UNEXPECTED_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER: +- reason = "STATUS_FILE_SNAP_INVALID_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE: +- reason = "DBG_NO_STATE_CHANGE"; +- break; +- case MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE: +- reason = "DBG_APP_NOT_IDLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING: +- reason = "RPC_NT_INVALID_STRING_BINDING"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING: +- reason = "RPC_NT_WRONG_KIND_OF_BINDING"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING: +- reason = "RPC_NT_INVALID_BINDING"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED: +- reason = "RPC_NT_PROTSEQ_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ: +- reason = "RPC_NT_INVALID_RPC_PROTSEQ"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID: +- reason = "RPC_NT_INVALID_STRING_UUID"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT: +- reason = "RPC_NT_INVALID_ENDPOINT_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR: +- reason = "RPC_NT_INVALID_NET_ADDR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND: +- reason = "RPC_NT_NO_ENDPOINT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT: +- reason = "RPC_NT_INVALID_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND: +- reason = "RPC_NT_OBJECT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED: +- reason = "RPC_NT_ALREADY_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED: +- reason = "RPC_NT_TYPE_ALREADY_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING: +- reason = "RPC_NT_ALREADY_LISTENING"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED: +- reason = "RPC_NT_NO_PROTSEQS_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING: +- reason = "RPC_NT_NOT_LISTENING"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE: +- reason = "RPC_NT_UNKNOWN_MGR_TYPE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF: +- reason = "RPC_NT_UNKNOWN_IF"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS: +- reason = "RPC_NT_NO_BINDINGS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS: +- reason = "RPC_NT_NO_PROTSEQS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT: +- reason = "RPC_NT_CANT_CREATE_ENDPOINT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES: +- reason = "RPC_NT_OUT_OF_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE: +- reason = "RPC_NT_SERVER_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY: +- reason = "RPC_NT_SERVER_TOO_BUSY"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS: +- reason = "RPC_NT_INVALID_NETWORK_OPTIONS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE: +- reason = "RPC_NT_NO_CALL_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED: +- reason = "RPC_NT_CALL_FAILED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE: +- reason = "RPC_NT_CALL_FAILED_DNE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR: +- reason = "RPC_NT_PROTOCOL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN: +- reason = "RPC_NT_UNSUPPORTED_TRANS_SYN"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE: +- reason = "RPC_NT_UNSUPPORTED_TYPE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG: +- reason = "RPC_NT_INVALID_TAG"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND: +- reason = "RPC_NT_INVALID_BOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME: +- reason = "RPC_NT_NO_ENTRY_NAME"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX: +- reason = "RPC_NT_INVALID_NAME_SYNTAX"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX: +- reason = "RPC_NT_UNSUPPORTED_NAME_SYNTAX"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS: +- reason = "RPC_NT_UUID_NO_ADDRESS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT: +- reason = "RPC_NT_DUPLICATE_ENDPOINT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE: +- reason = "RPC_NT_UNKNOWN_AUTHN_TYPE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL: +- reason = "RPC_NT_MAX_CALLS_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG: +- reason = "RPC_NT_STRING_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND: +- reason = "RPC_NT_PROTSEQ_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE: +- reason = "RPC_NT_PROCNUM_OUT_OF_RANGE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH: +- reason = "RPC_NT_BINDING_HAS_NO_AUTH"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE: +- reason = "RPC_NT_UNKNOWN_AUTHN_SERVICE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL: +- reason = "RPC_NT_UNKNOWN_AUTHN_LEVEL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY: +- reason = "RPC_NT_INVALID_AUTH_IDENTITY"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE: +- reason = "RPC_NT_UNKNOWN_AUTHZ_SERVICE"; +- break; +- case MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY: +- reason = "EPT_NT_INVALID_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP: +- reason = "EPT_NT_CANT_PERFORM_OP"; +- break; +- case MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED: +- reason = "EPT_NT_NOT_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT: +- reason = "RPC_NT_NOTHING_TO_EXPORT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME: +- reason = "RPC_NT_INCOMPLETE_NAME"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION: +- reason = "RPC_NT_INVALID_VERS_OPTION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS: +- reason = "RPC_NT_NO_MORE_MEMBERS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED: +- reason = "RPC_NT_NOT_ALL_OBJS_UNEXPORTED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND: +- reason = "RPC_NT_INTERFACE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS: +- reason = "RPC_NT_ENTRY_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND: +- reason = "RPC_NT_ENTRY_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE: +- reason = "RPC_NT_NAME_SERVICE_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID: +- reason = "RPC_NT_INVALID_NAF_ID"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT: +- reason = "RPC_NT_CANNOT_SUPPORT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE: +- reason = "RPC_NT_NO_CONTEXT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR: +- reason = "RPC_NT_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE: +- reason = "RPC_NT_ZERO_DIVIDE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR: +- reason = "RPC_NT_ADDRESS_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO: +- reason = "RPC_NT_FP_DIV_ZERO"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW: +- reason = "RPC_NT_FP_UNDERFLOW"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW: +- reason = "RPC_NT_FP_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS: +- reason = "RPC_NT_CALL_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS: +- reason = "RPC_NT_NO_MORE_BINDINGS"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND: +- reason = "RPC_NT_GROUP_MEMBER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE: +- reason = "EPT_NT_CANT_CREATE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT: +- reason = "RPC_NT_INVALID_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES: +- reason = "RPC_NT_NO_INTERFACES"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED: +- reason = "RPC_NT_CALL_CANCELLED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE: +- reason = "RPC_NT_BINDING_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE: +- reason = "RPC_NT_COMM_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL: +- reason = "RPC_NT_UNSUPPORTED_AUTHN_LEVEL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME: +- reason = "RPC_NT_NO_PRINC_NAME"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR: +- reason = "RPC_NT_NOT_RPC_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR: +- reason = "RPC_NT_SEC_PKG_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED: +- reason = "RPC_NT_NOT_CANCELLED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE: +- reason = "RPC_NT_INVALID_ASYNC_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL: +- reason = "RPC_NT_INVALID_ASYNC_CALL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED: +- reason = "RPC_NT_PROXY_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED: +- reason = "RPC_NT_COOKIE_AUTH_FAILED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES: +- reason = "RPC_NT_NO_MORE_ENTRIES"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL: +- reason = "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE: +- reason = "RPC_NT_SS_CHAR_TRANS_SHORT_FILE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT: +- reason = "RPC_NT_SS_IN_NULL_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH: +- reason = "RPC_NT_SS_CONTEXT_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED: +- reason = "RPC_NT_SS_CONTEXT_DAMAGED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH: +- reason = "RPC_NT_SS_HANDLES_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE: +- reason = "RPC_NT_SS_CANNOT_GET_CALL_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER: +- reason = "RPC_NT_NULL_REF_POINTER"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE: +- reason = "RPC_NT_ENUM_VALUE_OUT_OF_RANGE"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL: +- reason = "RPC_NT_BYTE_COUNT_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA: +- reason = "RPC_NT_BAD_STUB_DATA"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION: +- reason = "RPC_NT_INVALID_ES_ACTION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION: +- reason = "RPC_NT_WRONG_ES_VERSION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION: +- reason = "RPC_NT_WRONG_STUB_VERSION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT: +- reason = "RPC_NT_INVALID_PIPE_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION: +- reason = "RPC_NT_INVALID_PIPE_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION: +- reason = "RPC_NT_WRONG_PIPE_VERSION"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED: +- reason = "RPC_NT_PIPE_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR: +- reason = "RPC_NT_PIPE_DISCIPLINE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY: +- reason = "RPC_NT_PIPE_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE: +- reason = "STATUS_PNP_BAD_MPS_TABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED: +- reason = "STATUS_PNP_TRANSLATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED: +- reason = "STATUS_PNP_IRQ_TRANSLATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID: +- reason = "STATUS_PNP_INVALID_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED: +- reason = "STATUS_IO_REISSUE_AS_CACHED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID: +- reason = "STATUS_CTX_WINSTATION_NAME_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD: +- reason = "STATUS_CTX_INVALID_PD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND: +- reason = "STATUS_CTX_PD_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING: +- reason = "STATUS_CTX_CLOSE_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF: +- reason = "STATUS_CTX_NO_OUTBUF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND: +- reason = "STATUS_CTX_MODEM_INF_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME: +- reason = "STATUS_CTX_INVALID_MODEMNAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR: +- reason = "STATUS_CTX_RESPONSE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT: +- reason = "STATUS_CTX_MODEM_RESPONSE_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER: +- reason = "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE: +- reason = "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY: +- reason = "STATUS_CTX_MODEM_RESPONSE_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE: +- reason = "STATUS_CTX_MODEM_RESPONSE_VOICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR: +- reason = "STATUS_CTX_TD_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID: +- reason = "STATUS_CTX_LICENSE_CLIENT_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE: +- reason = "STATUS_CTX_LICENSE_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED: +- reason = "STATUS_CTX_LICENSE_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND: +- reason = "STATUS_CTX_WINSTATION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION: +- reason = "STATUS_CTX_WINSTATION_NAME_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY: +- reason = "STATUS_CTX_WINSTATION_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE: +- reason = "STATUS_CTX_BAD_VIDEO_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID: +- reason = "STATUS_CTX_GRAPHICS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE: +- reason = "STATUS_CTX_NOT_CONSOLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT: +- reason = "STATUS_CTX_CLIENT_QUERY_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT: +- reason = "STATUS_CTX_CONSOLE_DISCONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT: +- reason = "STATUS_CTX_CONSOLE_CONNECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED: +- reason = "STATUS_CTX_SHADOW_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED: +- reason = "STATUS_CTX_WINSTATION_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD: +- reason = "STATUS_CTX_INVALID_WD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND: +- reason = "STATUS_CTX_WD_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID: +- reason = "STATUS_CTX_SHADOW_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED: +- reason = "STATUS_CTX_SHADOW_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR: +- reason = "STATUS_RDP_PROTOCOL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET: +- reason = "STATUS_CTX_CLIENT_LICENSE_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE: +- reason = "STATUS_CTX_CLIENT_LICENSE_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE: +- reason = "STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING: +- reason = "STATUS_CTX_SHADOW_NOT_RUNNING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED: +- reason = "STATUS_CTX_LOGON_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR: +- reason = "STATUS_CTX_SECURITY_LAYER_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS: +- reason = "STATUS_TS_INCOMPATIBLE_SESSIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR: +- reason = "STATUS_TS_VIDEO_SUBSYSTEM_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND: +- reason = "STATUS_MUI_FILE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE: +- reason = "STATUS_MUI_INVALID_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG: +- reason = "STATUS_MUI_INVALID_RC_CONFIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME: +- reason = "STATUS_MUI_INVALID_LOCALE_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME: +- reason = "STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED: +- reason = "STATUS_MUI_FILE_NOT_LOADED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP: +- reason = "STATUS_RESOURCE_ENUM_USER_STOP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE: +- reason = "STATUS_CLUSTER_INVALID_NODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS: +- reason = "STATUS_CLUSTER_NODE_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS: +- reason = "STATUS_CLUSTER_JOIN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND: +- reason = "STATUS_CLUSTER_NODE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND: +- reason = "STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS: +- reason = "STATUS_CLUSTER_NETWORK_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND: +- reason = "STATUS_CLUSTER_NETWORK_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS: +- reason = "STATUS_CLUSTER_NETINTERFACE_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND: +- reason = "STATUS_CLUSTER_NETINTERFACE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST: +- reason = "STATUS_CLUSTER_INVALID_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER: +- reason = "STATUS_CLUSTER_INVALID_NETWORK_PROVIDER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN: +- reason = "STATUS_CLUSTER_NODE_DOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE: +- reason = "STATUS_CLUSTER_NODE_UNREACHABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER: +- reason = "STATUS_CLUSTER_NODE_NOT_MEMBER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS: +- reason = "STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK: +- reason = "STATUS_CLUSTER_INVALID_NETWORK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS: +- reason = "STATUS_CLUSTER_NO_NET_ADAPTERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP: +- reason = "STATUS_CLUSTER_NODE_UP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED: +- reason = "STATUS_CLUSTER_NODE_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED: +- reason = "STATUS_CLUSTER_NODE_NOT_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT: +- reason = "STATUS_CLUSTER_NO_SECURITY_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL: +- reason = "STATUS_CLUSTER_NETWORK_NOT_INTERNAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED: +- reason = "STATUS_CLUSTER_POISONED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH: +- reason = "STATUS_CLUSTER_NON_CSV_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL: +- reason = "STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS: +- reason = "STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR: +- reason = "STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED: +- reason = "STATUS_CLUSTER_CSV_REDIRECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED: +- reason = "STATUS_CLUSTER_CSV_NOT_REDIRECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING: +- reason = "STATUS_CLUSTER_CSV_VOLUME_DRAINING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS: +- reason = "STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL: +- reason = "STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS: +- reason = "STATUS_CLUSTER_CSV_NO_SNAPSHOTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT: +- reason = "STATUS_CSV_IO_PAUSE_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE: +- reason = "STATUS_CLUSTER_CSV_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR: +- reason = "STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED: +- reason = "STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE: +- reason = "STATUS_ACPI_INVALID_OPCODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW: +- reason = "STATUS_ACPI_STACK_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED: +- reason = "STATUS_ACPI_ASSERT_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX: +- reason = "STATUS_ACPI_INVALID_INDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT: +- reason = "STATUS_ACPI_INVALID_ARGUMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_FATAL: +- reason = "STATUS_ACPI_FATAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME: +- reason = "STATUS_ACPI_INVALID_SUPERNAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE: +- reason = "STATUS_ACPI_INVALID_ARGTYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE: +- reason = "STATUS_ACPI_INVALID_OBJTYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE: +- reason = "STATUS_ACPI_INVALID_TARGETTYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT: +- reason = "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED: +- reason = "STATUS_ACPI_ADDRESS_NOT_MAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE: +- reason = "STATUS_ACPI_INVALID_EVENTTYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION: +- reason = "STATUS_ACPI_HANDLER_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA: +- reason = "STATUS_ACPI_INVALID_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION: +- reason = "STATUS_ACPI_INVALID_REGION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE: +- reason = "STATUS_ACPI_INVALID_ACCESS_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK: +- reason = "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED: +- reason = "STATUS_ACPI_ALREADY_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED: +- reason = "STATUS_ACPI_NOT_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL: +- reason = "STATUS_ACPI_INVALID_MUTEX_LEVEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED: +- reason = "STATUS_ACPI_MUTEX_NOT_OWNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER: +- reason = "STATUS_ACPI_MUTEX_NOT_OWNER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS: +- reason = "STATUS_ACPI_RS_ACCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE: +- reason = "STATUS_ACPI_INVALID_TABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED: +- reason = "STATUS_ACPI_REG_HANDLER_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED: +- reason = "STATUS_ACPI_POWER_REQUEST_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND: +- reason = "STATUS_SXS_SECTION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX: +- reason = "STATUS_SXS_CANT_GEN_ACTCTX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT: +- reason = "STATUS_SXS_INVALID_ACTCTXDATA_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND: +- reason = "STATUS_SXS_ASSEMBLY_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR: +- reason = "STATUS_SXS_MANIFEST_FORMAT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR: +- reason = "STATUS_SXS_MANIFEST_PARSE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED: +- reason = "STATUS_SXS_ACTIVATION_CONTEXT_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND: +- reason = "STATUS_SXS_KEY_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT: +- reason = "STATUS_SXS_VERSION_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE: +- reason = "STATUS_SXS_WRONG_SECTION_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED: +- reason = "STATUS_SXS_THREAD_QUERIES_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING: +- reason = "STATUS_SXS_ASSEMBLY_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET: +- reason = "STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION: +- reason = "STATUS_SXS_EARLY_DEACTIVATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION: +- reason = "STATUS_SXS_INVALID_DEACTIVATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION: +- reason = "STATUS_SXS_MULTIPLE_DEACTIVATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: +- reason = "STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED: +- reason = "STATUS_SXS_PROCESS_TERMINATION_REQUESTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK: +- reason = "STATUS_SXS_CORRUPT_ACTIVATION_STACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION: +- reason = "STATUS_SXS_CORRUPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: +- reason = "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: +- reason = "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: +- reason = "STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR: +- reason = "STATUS_SXS_IDENTITY_PARSE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT: +- reason = "STATUS_SXS_COMPONENT_STORE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH: +- reason = "STATUS_SXS_FILE_HASH_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: +- reason = "STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT: +- reason = "STATUS_SXS_IDENTITIES_DIFFERENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: +- reason = "STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY: +- reason = "STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED: +- reason = "STATUS_ADVANCED_INSTALLER_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH: +- reason = "STATUS_XML_ENCODING_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG: +- reason = "STATUS_SXS_MANIFEST_TOO_BIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED: +- reason = "STATUS_SXS_SETTING_NOT_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE: +- reason = "STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED: +- reason = "STATUS_SMI_PRIMITIVE_INSTALLER_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED: +- reason = "STATUS_GENERIC_COMMAND_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING: +- reason = "STATUS_SXS_FILE_HASH_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT: +- reason = "STATUS_TRANSACTIONAL_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION: +- reason = "STATUS_INVALID_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE: +- reason = "STATUS_TRANSACTION_NOT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED: +- reason = "STATUS_TM_INITIALIZATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE: +- reason = "STATUS_RM_NOT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT: +- reason = "STATUS_RM_METADATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED: +- reason = "STATUS_TRANSACTION_NOT_JOINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM: +- reason = "STATUS_DIRECTORY_NOT_RM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE: +- reason = "STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE: +- reason = "STATUS_LOG_RESIZE_INVALID_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH: +- reason = "STATUS_REMOTE_FILE_VERSION_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS: +- reason = "STATUS_CRM_PROTOCOL_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED: +- reason = "STATUS_TRANSACTION_PROPAGATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND: +- reason = "STATUS_CRM_PROTOCOL_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS: +- reason = "STATUS_TRANSACTION_SUPERIOR_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID: +- reason = "STATUS_TRANSACTION_REQUEST_NOT_VALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED: +- reason = "STATUS_TRANSACTION_NOT_REQUESTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED: +- reason = "STATUS_TRANSACTION_ALREADY_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED: +- reason = "STATUS_TRANSACTION_ALREADY_COMMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER: +- reason = "STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID: +- reason = "STATUS_CURRENT_TRANSACTION_NOT_VALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED: +- reason = "STATUS_LOG_GROWTH_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS: +- reason = "STATUS_OBJECT_NO_LONGER_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND: +- reason = "STATUS_STREAM_MINIVERSION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID: +- reason = "STATUS_STREAM_MINIVERSION_NOT_VALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION: +- reason = "STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT: +- reason = "STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS: +- reason = "STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID: +- reason = "STATUS_HANDLE_NO_LONGER_VALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED: +- reason = "STATUS_LOG_CORRUPTION_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED: +- reason = "STATUS_RM_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR: +- reason = "STATUS_ENLISTMENT_NOT_SUPERIOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT: +- reason = "STATUS_FILE_IDENTITY_NOT_PERSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY: +- reason = "STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY: +- reason = "STATUS_CANT_CROSS_RM_BOUNDARY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY: +- reason = "STATUS_TXF_DIR_NOT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST: +- reason = "STATUS_INDOUBT_TRANSACTIONS_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TM_VOLATILE: +- reason = "STATUS_TM_VOLATILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED: +- reason = "STATUS_ROLLBACK_TIMER_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT: +- reason = "STATUS_TXF_ATTRIBUTE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION: +- reason = "STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED: +- reason = "STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE: +- reason = "STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION: +- reason = "STATUS_TRANSACTION_REQUIRED_PROMOTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION: +- reason = "STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN: +- reason = "STATUS_TRANSACTIONS_NOT_FROZEN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS: +- reason = "STATUS_TRANSACTION_FREEZE_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME: +- reason = "STATUS_NOT_SNAPSHOT_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES: +- reason = "STATUS_NO_SAVEPOINT_WITH_OPEN_FILES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION: +- reason = "STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH: +- reason = "STATUS_TM_IDENTITY_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION: +- reason = "STATUS_FLOATED_SECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK: +- reason = "STATUS_CANNOT_ACCEPT_TRANSACTED_WORK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS: +- reason = "STATUS_CANNOT_ABORT_TRANSACTIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND: +- reason = "STATUS_TRANSACTION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND: +- reason = "STATUS_RESOURCEMANAGER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND: +- reason = "STATUS_ENLISTMENT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND: +- reason = "STATUS_TRANSACTIONMANAGER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE: +- reason = "STATUS_TRANSACTIONMANAGER_NOT_ONLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION: +- reason = "STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT: +- reason = "STATUS_TRANSACTION_NOT_ROOT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED: +- reason = "STATUS_TRANSACTION_OBJECT_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION: +- reason = "STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED: +- reason = "STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG: +- reason = "STATUS_TRANSACTION_RECORD_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION: +- reason = "STATUS_NO_LINK_TRACKING_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION: +- reason = "STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED: +- reason = "STATUS_TRANSACTION_INTEGRITY_VIOLATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH: +- reason = "STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT: +- reason = "STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH: +- reason = "STATUS_TRANSACTION_MUST_WRITETHROUGH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR: +- reason = "STATUS_TRANSACTION_NO_SUPERIOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE: +- reason = "STATUS_EXPIRED_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED: +- reason = "STATUS_TRANSACTION_NOT_ENLISTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID: +- reason = "STATUS_LOG_SECTOR_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID: +- reason = "STATUS_LOG_SECTOR_PARITY_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED: +- reason = "STATUS_LOG_SECTOR_REMAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE: +- reason = "STATUS_LOG_BLOCK_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE: +- reason = "STATUS_LOG_INVALID_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED: +- reason = "STATUS_LOG_BLOCKS_EXHAUSTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID: +- reason = "STATUS_LOG_READ_CONTEXT_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID: +- reason = "STATUS_LOG_RESTART_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION: +- reason = "STATUS_LOG_BLOCK_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID: +- reason = "STATUS_LOG_BLOCK_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID: +- reason = "STATUS_LOG_READ_MODE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT: +- reason = "STATUS_LOG_METADATA_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID: +- reason = "STATUS_LOG_METADATA_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT: +- reason = "STATUS_LOG_METADATA_INCONSISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID: +- reason = "STATUS_LOG_RESERVATION_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE: +- reason = "STATUS_LOG_CANT_DELETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED: +- reason = "STATUS_LOG_CONTAINER_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG: +- reason = "STATUS_LOG_START_OF_LOG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED: +- reason = "STATUS_LOG_POLICY_ALREADY_INSTALLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED: +- reason = "STATUS_LOG_POLICY_NOT_INSTALLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID: +- reason = "STATUS_LOG_POLICY_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT: +- reason = "STATUS_LOG_POLICY_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL: +- reason = "STATUS_LOG_PINNED_ARCHIVE_TAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT: +- reason = "STATUS_LOG_RECORD_NONEXISTENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID: +- reason = "STATUS_LOG_RECORDS_RESERVED_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID: +- reason = "STATUS_LOG_SPACE_RESERVED_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID: +- reason = "STATUS_LOG_TAIL_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_FULL: +- reason = "STATUS_LOG_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED: +- reason = "STATUS_LOG_MULTIPLEXED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED: +- reason = "STATUS_LOG_DEDICATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS: +- reason = "STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS: +- reason = "STATUS_LOG_ARCHIVE_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL: +- reason = "STATUS_LOG_EPHEMERAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS: +- reason = "STATUS_LOG_NOT_ENOUGH_CONTAINERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED: +- reason = "STATUS_LOG_CLIENT_ALREADY_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED: +- reason = "STATUS_LOG_CLIENT_NOT_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS: +- reason = "STATUS_LOG_FULL_HANDLER_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED: +- reason = "STATUS_LOG_CONTAINER_READ_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED: +- reason = "STATUS_LOG_CONTAINER_WRITE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED: +- reason = "STATUS_LOG_CONTAINER_OPEN_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID: +- reason = "STATUS_LOG_CONTAINER_STATE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID: +- reason = "STATUS_LOG_STATE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_PINNED: +- reason = "STATUS_LOG_PINNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED: +- reason = "STATUS_LOG_METADATA_FLUSH_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY: +- reason = "STATUS_LOG_INCONSISTENT_SECURITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED: +- reason = "STATUS_LOG_APPENDED_FLUSH_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION: +- reason = "STATUS_LOG_PINNED_RESERVATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD: +- reason = "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED: +- reason = "STATUS_FLT_NO_HANDLER_DEFINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED: +- reason = "STATUS_FLT_CONTEXT_ALREADY_DEFINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST: +- reason = "STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO: +- reason = "STATUS_FLT_DISALLOW_FAST_IO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST: +- reason = "STATUS_FLT_INVALID_NAME_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION: +- reason = "STATUS_FLT_NOT_SAFE_TO_POST_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED: +- reason = "STATUS_FLT_NOT_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY: +- reason = "STATUS_FLT_FILTER_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP: +- reason = "STATUS_FLT_POST_OPERATION_CLEANUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR: +- reason = "STATUS_FLT_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT: +- reason = "STATUS_FLT_DELETING_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL: +- reason = "STATUS_FLT_MUST_BE_NONPAGED_POOL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY: +- reason = "STATUS_FLT_DUPLICATE_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED: +- reason = "STATUS_FLT_CBDQ_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH: +- reason = "STATUS_FLT_DO_NOT_ATTACH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH: +- reason = "STATUS_FLT_DO_NOT_DETACH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION: +- reason = "STATUS_FLT_INSTANCE_ALTITUDE_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION: +- reason = "STATUS_FLT_INSTANCE_NAME_COLLISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND: +- reason = "STATUS_FLT_FILTER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND: +- reason = "STATUS_FLT_VOLUME_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND: +- reason = "STATUS_FLT_INSTANCE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND: +- reason = "STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION: +- reason = "STATUS_FLT_INVALID_CONTEXT_REGISTRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS: +- reason = "STATUS_FLT_NAME_CACHE_MISS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT: +- reason = "STATUS_FLT_NO_DEVICE_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED: +- reason = "STATUS_FLT_VOLUME_ALREADY_MOUNTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED: +- reason = "STATUS_FLT_ALREADY_ENLISTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED: +- reason = "STATUS_FLT_CONTEXT_ALREADY_LINKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY: +- reason = "STATUS_FLT_NO_WAITER_FOR_REPLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY: +- reason = "STATUS_FLT_REGISTRATION_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR: +- reason = "STATUS_MONITOR_NO_DESCRIPTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT: +- reason = "STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM: +- reason = "STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK: +- reason = "STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED: +- reason = "STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK: +- reason = "STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK: +- reason = "STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA: +- reason = "STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK: +- reason = "STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE: +- reason = "STATUS_MONITOR_INVALID_MANUFACTURE_DATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER: +- reason = "STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER: +- reason = "STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER: +- reason = "STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET: +- reason = "STATUS_GRAPHICS_ADAPTER_WAS_RESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL: +- reason = "STATUS_GRAPHICS_INVALID_DRIVER_MODEL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED: +- reason = "STATUS_GRAPHICS_PRESENT_MODE_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED: +- reason = "STATUS_GRAPHICS_PRESENT_OCCLUDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED: +- reason = "STATUS_GRAPHICS_PRESENT_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT: +- reason = "STATUS_GRAPHICS_CANNOTCOLORCONVERT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH: +- reason = "STATUS_GRAPHICS_DRIVER_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED: +- reason = "STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED: +- reason = "STATUS_GRAPHICS_PRESENT_UNOCCLUDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE: +- reason = "STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED: +- reason = "STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW: +- reason = "STATUS_GRAPHICS_PRESENT_INVALID_WINDOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND: +- reason = "STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED: +- reason = "STATUS_GRAPHICS_VAIL_STATE_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN: +- reason = "STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED: +- reason = "STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY: +- reason = "STATUS_GRAPHICS_NO_VIDEO_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY: +- reason = "STATUS_GRAPHICS_CANT_LOCK_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY: +- reason = "STATUS_GRAPHICS_ALLOCATION_BUSY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES: +- reason = "STATUS_GRAPHICS_TOO_MANY_REFERENCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER: +- reason = "STATUS_GRAPHICS_TRY_AGAIN_LATER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW: +- reason = "STATUS_GRAPHICS_TRY_AGAIN_NOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID: +- reason = "STATUS_GRAPHICS_ALLOCATION_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE: +- reason = "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED: +- reason = "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION: +- reason = "STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE: +- reason = "STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION: +- reason = "STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED: +- reason = "STATUS_GRAPHICS_ALLOCATION_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE: +- reason = "STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE: +- reason = "STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE: +- reason = "STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST: +- reason = "STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE: +- reason = "STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE: +- reason = "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET: +- reason = "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY: +- reason = "STATUS_GRAPHICS_INVALID_FREQUENCY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION: +- reason = "STATUS_GRAPHICS_INVALID_ACTIVE_REGION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION: +- reason = "STATUS_GRAPHICS_INVALID_TOTAL_REGION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE: +- reason = "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE: +- reason = "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET: +- reason = "STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET: +- reason = "STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET: +- reason = "STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET: +- reason = "STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET: +- reason = "STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET: +- reason = "STATUS_GRAPHICS_TARGET_ALREADY_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET: +- reason = "STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET: +- reason = "STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET: +- reason = "STATUS_GRAPHICS_STALE_MODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN: +- reason = "STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE: +- reason = "STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION: +- reason = "STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES: +- reason = "STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE: +- reason = "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET: +- reason = "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET: +- reason = "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR: +- reason = "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET: +- reason = "STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET: +- reason = "STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE: +- reason = "STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED: +- reason = "STATUS_GRAPHICS_RESOURCES_NOT_RELATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE: +- reason = "STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE: +- reason = "STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET: +- reason = "STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER: +- reason = "STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR: +- reason = "STATUS_GRAPHICS_NO_VIDPNMGR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN: +- reason = "STATUS_GRAPHICS_NO_ACTIVE_VIDPN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED: +- reason = "STATUS_GRAPHICS_MONITOR_NOT_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE: +- reason = "STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE: +- reason = "STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE: +- reason = "STATUS_GRAPHICS_INVALID_STRIDE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT: +- reason = "STATUS_GRAPHICS_INVALID_PIXELFORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS: +- reason = "STATUS_GRAPHICS_INVALID_COLORBASIS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE: +- reason = "STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY: +- reason = "STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT: +- reason = "STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: +- reason = "STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN: +- reason = "STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL: +- reason = "STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION: +- reason = "STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP: +- reason = "STATUS_GRAPHICS_INVALID_GAMMA_RAMP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET: +- reason = "STATUS_GRAPHICS_MODE_NOT_IN_MODESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON: +- reason = "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE: +- reason = "STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE: +- reason = "STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS: +- reason = "STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING: +- reason = "STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED: +- reason = "STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS: +- reason = "STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT: +- reason = "STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM: +- reason = "STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT: +- reason = "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED: +- reason = "STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION: +- reason = "STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE: +- reason = "STATUS_GRAPHICS_INVALID_CLIENT_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET: +- reason = "STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED: +- reason = "STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER: +- reason = "STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED: +- reason = "STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED: +- reason = "STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY: +- reason = "STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED: +- reason = "STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON: +- reason = "STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE: +- reason = "STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER: +- reason = "STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED: +- reason = "STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_OPM_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_COPP_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_UAB_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS: +- reason = "STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST: +- reason = "STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR: +- reason = "STATUS_GRAPHICS_OPM_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE: +- reason = "STATUS_GRAPHICS_OPM_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH: +- reason = "STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED: +- reason = "STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED: +- reason = "STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED: +- reason = "STATUS_GRAPHICS_PVP_HFS_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM: +- reason = "STATUS_GRAPHICS_OPM_INVALID_SRM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP: +- reason = "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP: +- reason = "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA: +- reason = "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET: +- reason = "STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH: +- reason = "STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE: +- reason = "STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS: +- reason = "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS: +- reason = "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST: +- reason = "STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR: +- reason = "STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS: +- reason = "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST: +- reason = "STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_I2C_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST: +- reason = "STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA: +- reason = "STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA: +- reason = "STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA: +- reason = "STATUS_GRAPHICS_DDCCI_INVALID_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE: +- reason = "STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING: +- reason = "STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR: +- reason = "STATUS_GRAPHICS_MCA_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND: +- reason = "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH: +- reason = "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM: +- reason = "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE: +- reason = "STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS: +- reason = "STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED: +- reason = "STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: +- reason = "STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: +- reason = "STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED: +- reason = "STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER: +- reason = "STATUS_GRAPHICS_INVALID_POINTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: +- reason = "STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL: +- reason = "STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR: +- reason = "STATUS_GRAPHICS_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS: +- reason = "STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME: +- reason = "STATUS_FVE_LOCKED_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED: +- reason = "STATUS_FVE_NOT_ENCRYPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION: +- reason = "STATUS_FVE_BAD_INFORMATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL: +- reason = "STATUS_FVE_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS: +- reason = "STATUS_FVE_FAILED_WRONG_FS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE: +- reason = "STATUS_FVE_BAD_PARTITION_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED: +- reason = "STATUS_FVE_FS_NOT_EXTENDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED: +- reason = "STATUS_FVE_FS_MOUNTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE: +- reason = "STATUS_FVE_NO_LICENSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED: +- reason = "STATUS_FVE_ACTION_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA: +- reason = "STATUS_FVE_BAD_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND: +- reason = "STATUS_FVE_VOLUME_NOT_BOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME: +- reason = "STATUS_FVE_NOT_DATA_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR: +- reason = "STATUS_FVE_CONV_READ_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR: +- reason = "STATUS_FVE_CONV_WRITE_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE: +- reason = "STATUS_FVE_OVERLAPPED_UPDATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE: +- reason = "STATUS_FVE_FAILED_SECTOR_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION: +- reason = "STATUS_FVE_FAILED_AUTHENTICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME: +- reason = "STATUS_FVE_NOT_OS_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND: +- reason = "STATUS_FVE_KEYFILE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID: +- reason = "STATUS_FVE_KEYFILE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK: +- reason = "STATUS_FVE_KEYFILE_NO_VMK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED: +- reason = "STATUS_FVE_TPM_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO: +- reason = "STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR: +- reason = "STATUS_FVE_TPM_INVALID_PCR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK: +- reason = "STATUS_FVE_TPM_NO_VMK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID: +- reason = "STATUS_FVE_PIN_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION: +- reason = "STATUS_FVE_AUTH_INVALID_APPLICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG: +- reason = "STATUS_FVE_AUTH_INVALID_CONFIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED: +- reason = "STATUS_FVE_DEBUGGER_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED: +- reason = "STATUS_FVE_DRY_RUN_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER: +- reason = "STATUS_FVE_BAD_METADATA_POINTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY: +- reason = "STATUS_FVE_OLD_METADATA_COPY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED: +- reason = "STATUS_FVE_REBOOT_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS: +- reason = "STATUS_FVE_RAW_ACCESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED: +- reason = "STATUS_FVE_RAW_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY: +- reason = "STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED: +- reason = "STATUS_FVE_MOR_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE: +- reason = "STATUS_FVE_NO_FEATURE_LICENSE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED: +- reason = "STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED: +- reason = "STATUS_FVE_CONV_RECOVERY_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG: +- reason = "STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE: +- reason = "STATUS_FVE_INVALID_DATUM_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL: +- reason = "STATUS_FVE_VOLUME_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID: +- reason = "STATUS_FVE_ENH_PIN_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE: +- reason = "STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE: +- reason = "STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK: +- reason = "STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER: +- reason = "STATUS_FVE_NOT_ALLOWED_ON_CLUSTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING: +- reason = "STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE: +- reason = "STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED: +- reason = "STATUS_FVE_EDRIVE_DRY_RUN_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED: +- reason = "STATUS_FVE_SECUREBOOT_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE: +- reason = "STATUS_FVE_SECUREBOOT_CONFIG_CHANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT: +- reason = "STATUS_FVE_DEVICE_LOCKEDOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT: +- reason = "STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME: +- reason = "STATUS_FVE_NOT_DE_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED: +- reason = "STATUS_FVE_PROTECTION_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED: +- reason = "STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED: +- reason = "STATUS_FVE_OSV_KSR_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND: +- reason = "STATUS_FWP_CALLOUT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND: +- reason = "STATUS_FWP_CONDITION_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND: +- reason = "STATUS_FWP_FILTER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND: +- reason = "STATUS_FWP_LAYER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND: +- reason = "STATUS_FWP_PROVIDER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND: +- reason = "STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND: +- reason = "STATUS_FWP_SUBLAYER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND: +- reason = "STATUS_FWP_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS: +- reason = "STATUS_FWP_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_IN_USE: +- reason = "STATUS_FWP_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS: +- reason = "STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION: +- reason = "STATUS_FWP_WRONG_SESSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS: +- reason = "STATUS_FWP_NO_TXN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS: +- reason = "STATUS_FWP_TXN_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED: +- reason = "STATUS_FWP_TXN_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED: +- reason = "STATUS_FWP_SESSION_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN: +- reason = "STATUS_FWP_INCOMPATIBLE_TXN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT: +- reason = "STATUS_FWP_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED: +- reason = "STATUS_FWP_NET_EVENTS_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER: +- reason = "STATUS_FWP_INCOMPATIBLE_LAYER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY: +- reason = "STATUS_FWP_KM_CLIENTS_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH: +- reason = "STATUS_FWP_LIFETIME_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT: +- reason = "STATUS_FWP_BUILTIN_OBJECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS: +- reason = "STATUS_FWP_TOO_MANY_CALLOUTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED: +- reason = "STATUS_FWP_NOTIFICATION_DROPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH: +- reason = "STATUS_FWP_TRAFFIC_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE: +- reason = "STATUS_FWP_INCOMPATIBLE_SA_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER: +- reason = "STATUS_FWP_NULL_POINTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR: +- reason = "STATUS_FWP_INVALID_ENUMERATOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS: +- reason = "STATUS_FWP_INVALID_FLAGS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK: +- reason = "STATUS_FWP_INVALID_NET_MASK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE: +- reason = "STATUS_FWP_INVALID_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL: +- reason = "STATUS_FWP_INVALID_INTERVAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY: +- reason = "STATUS_FWP_ZERO_LENGTH_ARRAY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME: +- reason = "STATUS_FWP_NULL_DISPLAY_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE: +- reason = "STATUS_FWP_INVALID_ACTION_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT: +- reason = "STATUS_FWP_INVALID_WEIGHT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH: +- reason = "STATUS_FWP_MATCH_TYPE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH: +- reason = "STATUS_FWP_TYPE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS: +- reason = "STATUS_FWP_OUT_OF_BOUNDS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_RESERVED: +- reason = "STATUS_FWP_RESERVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION: +- reason = "STATUS_FWP_DUPLICATE_CONDITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD: +- reason = "STATUS_FWP_DUPLICATE_KEYMOD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER: +- reason = "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER: +- reason = "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER: +- reason = "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT: +- reason = "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD: +- reason = "STATUS_FWP_INCOMPATIBLE_AUTH_METHOD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP: +- reason = "STATUS_FWP_INCOMPATIBLE_DH_GROUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED: +- reason = "STATUS_FWP_EM_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH: +- reason = "STATUS_FWP_NEVER_MATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH: +- reason = "STATUS_FWP_PROVIDER_CONTEXT_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER: +- reason = "STATUS_FWP_INVALID_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS: +- reason = "STATUS_FWP_TOO_MANY_SUBLAYERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED: +- reason = "STATUS_FWP_CALLOUT_NOTIFICATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM: +- reason = "STATUS_FWP_INVALID_AUTH_TRANSFORM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM: +- reason = "STATUS_FWP_INVALID_CIPHER_TRANSFORM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM: +- reason = "STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION: +- reason = "STATUS_FWP_INVALID_TRANSFORM_COMBINATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD: +- reason = "STATUS_FWP_DUPLICATE_AUTH_METHOD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT: +- reason = "STATUS_FWP_INVALID_TUNNEL_ENDPOINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY: +- reason = "STATUS_FWP_L2_DRIVER_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED: +- reason = "STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL: +- reason = "STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED: +- reason = "STATUS_FWP_CONNECTIONS_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME: +- reason = "STATUS_FWP_INVALID_DNS_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON: +- reason = "STATUS_FWP_STILL_ON"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING: +- reason = "STATUS_FWP_IKEEXT_NOT_RUNNING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY: +- reason = "STATUS_FWP_TCPIP_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING: +- reason = "STATUS_FWP_INJECT_HANDLE_CLOSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE: +- reason = "STATUS_FWP_INJECT_HANDLE_STALE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND: +- reason = "STATUS_FWP_CANNOT_PEND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP: +- reason = "STATUS_FWP_DROP_NOICMP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING: +- reason = "STATUS_NDIS_CLOSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION: +- reason = "STATUS_NDIS_BAD_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS: +- reason = "STATUS_NDIS_BAD_CHARACTERISTICS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND: +- reason = "STATUS_NDIS_ADAPTER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED: +- reason = "STATUS_NDIS_OPEN_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED: +- reason = "STATUS_NDIS_DEVICE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL: +- reason = "STATUS_NDIS_MULTICAST_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS: +- reason = "STATUS_NDIS_MULTICAST_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND: +- reason = "STATUS_NDIS_MULTICAST_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED: +- reason = "STATUS_NDIS_REQUEST_ABORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS: +- reason = "STATUS_NDIS_RESET_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET: +- reason = "STATUS_NDIS_INVALID_PACKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST: +- reason = "STATUS_NDIS_INVALID_DEVICE_REQUEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY: +- reason = "STATUS_NDIS_ADAPTER_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH: +- reason = "STATUS_NDIS_INVALID_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA: +- reason = "STATUS_NDIS_INVALID_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT: +- reason = "STATUS_NDIS_BUFFER_TOO_SHORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID: +- reason = "STATUS_NDIS_INVALID_OID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED: +- reason = "STATUS_NDIS_ADAPTER_REMOVED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA: +- reason = "STATUS_NDIS_UNSUPPORTED_MEDIA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE: +- reason = "STATUS_NDIS_GROUP_ADDRESS_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND: +- reason = "STATUS_NDIS_FILE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE: +- reason = "STATUS_NDIS_ERROR_READING_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED: +- reason = "STATUS_NDIS_ALREADY_MAPPED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT: +- reason = "STATUS_NDIS_RESOURCE_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED: +- reason = "STATUS_NDIS_MEDIA_DISCONNECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS: +- reason = "STATUS_NDIS_INVALID_ADDRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED: +- reason = "STATUS_NDIS_PAUSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND: +- reason = "STATUS_NDIS_INTERFACE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION: +- reason = "STATUS_NDIS_UNSUPPORTED_REVISION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT: +- reason = "STATUS_NDIS_INVALID_PORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE: +- reason = "STATUS_NDIS_INVALID_PORT_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE: +- reason = "STATUS_NDIS_LOW_POWER_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED: +- reason = "STATUS_NDIS_REINIT_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES: +- reason = "STATUS_NDIS_NO_QUEUES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED: +- reason = "STATUS_NDIS_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY: +- reason = "STATUS_NDIS_OFFLOAD_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED: +- reason = "STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED: +- reason = "STATUS_NDIS_OFFLOAD_PATH_REJECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED: +- reason = "STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE: +- reason = "STATUS_NDIS_DOT11_MEDIA_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID: +- reason = "STATUS_NDIS_DOT11_POWER_STATE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL: +- reason = "STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: +- reason = "STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE: +- reason = "STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE: +- reason = "STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED: +- reason = "STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED: +- reason = "STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE: +- reason = "STATUS_QUIC_HANDSHAKE_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE: +- reason = "STATUS_QUIC_VER_NEG_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK: +- reason = "STATUS_TPM_ERROR_MASK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL: +- reason = "STATUS_TPM_AUTHFAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX: +- reason = "STATUS_TPM_BADINDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER: +- reason = "STATUS_TPM_BAD_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE: +- reason = "STATUS_TPM_AUDITFAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED: +- reason = "STATUS_TPM_CLEAR_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED: +- reason = "STATUS_TPM_DEACTIVATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DISABLED: +- reason = "STATUS_TPM_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD: +- reason = "STATUS_TPM_DISABLED_CMD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_FAIL: +- reason = "STATUS_TPM_FAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL: +- reason = "STATUS_TPM_BAD_ORDINAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED: +- reason = "STATUS_TPM_INSTALL_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE: +- reason = "STATUS_TPM_INVALID_KEYHANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND: +- reason = "STATUS_TPM_KEYNOTFOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC: +- reason = "STATUS_TPM_INAPPROPRIATE_ENC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL: +- reason = "STATUS_TPM_MIGRATEFAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO: +- reason = "STATUS_TPM_INVALID_PCR_INFO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE: +- reason = "STATUS_TPM_NOSPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOSRK: +- reason = "STATUS_TPM_NOSRK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB: +- reason = "STATUS_TPM_NOTSEALED_BLOB"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET: +- reason = "STATUS_TPM_OWNER_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES: +- reason = "STATUS_TPM_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM: +- reason = "STATUS_TPM_SHORTRANDOM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_SIZE: +- reason = "STATUS_TPM_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL: +- reason = "STATUS_TPM_WRONGPCRVAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE: +- reason = "STATUS_TPM_BAD_PARAM_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD: +- reason = "STATUS_TPM_SHA_THREAD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR: +- reason = "STATUS_TPM_SHA_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST: +- reason = "STATUS_TPM_FAILEDSELFTEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL: +- reason = "STATUS_TPM_AUTH2FAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BADTAG: +- reason = "STATUS_TPM_BADTAG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_IOERROR: +- reason = "STATUS_TPM_IOERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR: +- reason = "STATUS_TPM_ENCRYPT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR: +- reason = "STATUS_TPM_DECRYPT_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE: +- reason = "STATUS_TPM_INVALID_AUTHHANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT: +- reason = "STATUS_TPM_NO_ENDORSEMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE: +- reason = "STATUS_TPM_INVALID_KEYUSAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE: +- reason = "STATUS_TPM_WRONG_ENTITYTYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT: +- reason = "STATUS_TPM_INVALID_POSTINIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG: +- reason = "STATUS_TPM_INAPPROPRIATE_SIG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY: +- reason = "STATUS_TPM_BAD_KEY_PROPERTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION: +- reason = "STATUS_TPM_BAD_MIGRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME: +- reason = "STATUS_TPM_BAD_SCHEME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE: +- reason = "STATUS_TPM_BAD_DATASIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE: +- reason = "STATUS_TPM_BAD_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE: +- reason = "STATUS_TPM_BAD_PRESENCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION: +- reason = "STATUS_TPM_BAD_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT: +- reason = "STATUS_TPM_NO_WRAP_TRANSPORT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL: +- reason = "STATUS_TPM_AUDITFAIL_UNSUCCESSFUL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL: +- reason = "STATUS_TPM_AUDITFAIL_SUCCESSFUL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE: +- reason = "STATUS_TPM_NOTRESETABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL: +- reason = "STATUS_TPM_NOTLOCAL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE: +- reason = "STATUS_TPM_BAD_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE: +- reason = "STATUS_TPM_INVALID_RESOURCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS: +- reason = "STATUS_TPM_NOTFIPS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY: +- reason = "STATUS_TPM_INVALID_FAMILY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION: +- reason = "STATUS_TPM_NO_NV_PERMISSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN: +- reason = "STATUS_TPM_REQUIRES_SIGN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED: +- reason = "STATUS_TPM_KEY_NOTSUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT: +- reason = "STATUS_TPM_AUTH_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED: +- reason = "STATUS_TPM_AREA_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY: +- reason = "STATUS_TPM_BAD_LOCALITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY: +- reason = "STATUS_TPM_READ_ONLY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE: +- reason = "STATUS_TPM_PER_NOWRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT: +- reason = "STATUS_TPM_FAMILYCOUNT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED: +- reason = "STATUS_TPM_WRITE_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES: +- reason = "STATUS_TPM_BAD_ATTRIBUTES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE: +- reason = "STATUS_TPM_INVALID_STRUCTURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL: +- reason = "STATUS_TPM_KEY_OWNER_CONTROL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER: +- reason = "STATUS_TPM_BAD_COUNTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE: +- reason = "STATUS_TPM_NOT_FULLWRITE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP: +- reason = "STATUS_TPM_CONTEXT_GAP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES: +- reason = "STATUS_TPM_MAXNVWRITES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR: +- reason = "STATUS_TPM_NOOPERATOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING: +- reason = "STATUS_TPM_RESOURCEMISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK: +- reason = "STATUS_TPM_DELEGATE_LOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY: +- reason = "STATUS_TPM_DELEGATE_FAMILY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN: +- reason = "STATUS_TPM_DELEGATE_ADMIN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE: +- reason = "STATUS_TPM_TRANSPORT_NOTEXCLUSIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL: +- reason = "STATUS_TPM_OWNER_CONTROL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES: +- reason = "STATUS_TPM_DAA_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0: +- reason = "STATUS_TPM_DAA_INPUT_DATA0"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1: +- reason = "STATUS_TPM_DAA_INPUT_DATA1"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS: +- reason = "STATUS_TPM_DAA_ISSUER_SETTINGS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS: +- reason = "STATUS_TPM_DAA_TPM_SETTINGS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE: +- reason = "STATUS_TPM_DAA_STAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY: +- reason = "STATUS_TPM_DAA_ISSUER_VALIDITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W: +- reason = "STATUS_TPM_DAA_WRONG_W"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE: +- reason = "STATUS_TPM_BAD_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE: +- reason = "STATUS_TPM_BAD_DELEGATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT: +- reason = "STATUS_TPM_BADCONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS: +- reason = "STATUS_TPM_TOOMANYCONTEXTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE: +- reason = "STATUS_TPM_MA_TICKET_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION: +- reason = "STATUS_TPM_MA_DESTINATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE: +- reason = "STATUS_TPM_MA_SOURCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY: +- reason = "STATUS_TPM_MA_AUTHORITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK: +- reason = "STATUS_TPM_PERMANENTEK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE: +- reason = "STATUS_TPM_BAD_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE: +- reason = "STATUS_TPM_NOCONTEXTSPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC: +- reason = "STATUS_TPM_20_E_ASYMMETRIC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES: +- reason = "STATUS_TPM_20_E_ATTRIBUTES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH: +- reason = "STATUS_TPM_20_E_HASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE: +- reason = "STATUS_TPM_20_E_VALUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY: +- reason = "STATUS_TPM_20_E_HIERARCHY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE: +- reason = "STATUS_TPM_20_E_KEY_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF: +- reason = "STATUS_TPM_20_E_MGF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE: +- reason = "STATUS_TPM_20_E_MODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE: +- reason = "STATUS_TPM_20_E_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE: +- reason = "STATUS_TPM_20_E_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF: +- reason = "STATUS_TPM_20_E_KDF"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE: +- reason = "STATUS_TPM_20_E_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL: +- reason = "STATUS_TPM_20_E_AUTH_FAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE: +- reason = "STATUS_TPM_20_E_NONCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP: +- reason = "STATUS_TPM_20_E_PP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME: +- reason = "STATUS_TPM_20_E_SCHEME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE: +- reason = "STATUS_TPM_20_E_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC: +- reason = "STATUS_TPM_20_E_SYMMETRIC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG: +- reason = "STATUS_TPM_20_E_TAG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR: +- reason = "STATUS_TPM_20_E_SELECTOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT: +- reason = "STATUS_TPM_20_E_INSUFFICIENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE: +- reason = "STATUS_TPM_20_E_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY: +- reason = "STATUS_TPM_20_E_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL: +- reason = "STATUS_TPM_20_E_POLICY_FAIL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY: +- reason = "STATUS_TPM_20_E_INTEGRITY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET: +- reason = "STATUS_TPM_20_E_TICKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS: +- reason = "STATUS_TPM_20_E_RESERVED_BITS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH: +- reason = "STATUS_TPM_20_E_BAD_AUTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED: +- reason = "STATUS_TPM_20_E_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC: +- reason = "STATUS_TPM_20_E_POLICY_CC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING: +- reason = "STATUS_TPM_20_E_BINDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE: +- reason = "STATUS_TPM_20_E_CURVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT: +- reason = "STATUS_TPM_20_E_ECC_POINT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE: +- reason = "STATUS_TPM_20_E_INITIALIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE: +- reason = "STATUS_TPM_20_E_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE: +- reason = "STATUS_TPM_20_E_SEQUENCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE: +- reason = "STATUS_TPM_20_E_PRIVATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC: +- reason = "STATUS_TPM_20_E_HMAC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED: +- reason = "STATUS_TPM_20_E_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE: +- reason = "STATUS_TPM_20_E_EXCLUSIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE: +- reason = "STATUS_TPM_20_E_ECC_CURVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE: +- reason = "STATUS_TPM_20_E_AUTH_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING: +- reason = "STATUS_TPM_20_E_AUTH_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY: +- reason = "STATUS_TPM_20_E_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR: +- reason = "STATUS_TPM_20_E_PCR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED: +- reason = "STATUS_TPM_20_E_PCR_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE: +- reason = "STATUS_TPM_20_E_UPGRADE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS: +- reason = "STATUS_TPM_20_E_TOO_MANY_CONTEXTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE: +- reason = "STATUS_TPM_20_E_AUTH_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT: +- reason = "STATUS_TPM_20_E_REBOOT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED: +- reason = "STATUS_TPM_20_E_UNBALANCED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE: +- reason = "STATUS_TPM_20_E_COMMAND_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE: +- reason = "STATUS_TPM_20_E_COMMAND_CODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE: +- reason = "STATUS_TPM_20_E_AUTHSIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT: +- reason = "STATUS_TPM_20_E_AUTH_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE: +- reason = "STATUS_TPM_20_E_NV_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE: +- reason = "STATUS_TPM_20_E_NV_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED: +- reason = "STATUS_TPM_20_E_NV_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION: +- reason = "STATUS_TPM_20_E_NV_AUTHORIZATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED: +- reason = "STATUS_TPM_20_E_NV_UNINITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE: +- reason = "STATUS_TPM_20_E_NV_SPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED: +- reason = "STATUS_TPM_20_E_NV_DEFINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT: +- reason = "STATUS_TPM_20_E_BAD_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH: +- reason = "STATUS_TPM_20_E_CPHASH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT: +- reason = "STATUS_TPM_20_E_PARENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST: +- reason = "STATUS_TPM_20_E_NEEDS_TEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT: +- reason = "STATUS_TPM_20_E_NO_RESULT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE: +- reason = "STATUS_TPM_20_E_SENSITIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED: +- reason = "STATUS_TPM_COMMAND_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE: +- reason = "STATUS_TPM_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE: +- reason = "STATUS_TPM_DUPLICATE_VHANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED: +- reason = "STATUS_TPM_EMBEDDED_COMMAND_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED: +- reason = "STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_RETRY: +- reason = "STATUS_TPM_RETRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST: +- reason = "STATUS_TPM_NEEDS_SELFTEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST: +- reason = "STATUS_TPM_DOING_SELFTEST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING: +- reason = "STATUS_TPM_DEFEND_LOCK_RUNNING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED: +- reason = "STATUS_TPM_COMMAND_CANCELED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS: +- reason = "STATUS_TPM_TOO_MANY_CONTEXTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND: +- reason = "STATUS_TPM_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED: +- reason = "STATUS_TPM_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER: +- reason = "STATUS_TPM_INSUFFICIENT_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED: +- reason = "STATUS_TPM_PPI_FUNCTION_UNSUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK: +- reason = "STATUS_PCP_ERROR_MASK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY: +- reason = "STATUS_PCP_DEVICE_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE: +- reason = "STATUS_PCP_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER: +- reason = "STATUS_PCP_INVALID_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED: +- reason = "STATUS_PCP_FLAG_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED: +- reason = "STATUS_PCP_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL: +- reason = "STATUS_PCP_BUFFER_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR: +- reason = "STATUS_PCP_INTERNAL_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED: +- reason = "STATUS_PCP_AUTHENTICATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED: +- reason = "STATUS_PCP_AUTHENTICATION_IGNORED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND: +- reason = "STATUS_PCP_POLICY_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND: +- reason = "STATUS_PCP_PROFILE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED: +- reason = "STATUS_PCP_VALIDATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND: +- reason = "STATUS_PCP_DEVICE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT: +- reason = "STATUS_PCP_WRONG_PARENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED: +- reason = "STATUS_PCP_KEY_NOT_LOADED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION: +- reason = "STATUS_PCP_NO_KEY_CERTIFICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED: +- reason = "STATUS_PCP_KEY_NOT_FINALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET: +- reason = "STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND: +- reason = "STATUS_PCP_NOT_PCR_BOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED: +- reason = "STATUS_PCP_KEY_ALREADY_FINALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED: +- reason = "STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID: +- reason = "STATUS_PCP_KEY_USAGE_POLICY_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR: +- reason = "STATUS_PCP_SOFT_KEY_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED: +- reason = "STATUS_PCP_KEY_NOT_AUTHENTICATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK: +- reason = "STATUS_PCP_KEY_NOT_AIK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY: +- reason = "STATUS_PCP_KEY_NOT_SIGNING_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT: +- reason = "STATUS_PCP_LOCKED_OUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED: +- reason = "STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED: +- reason = "STATUS_PCP_TPM_VERSION_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH: +- reason = "STATUS_PCP_BUFFER_LENGTH_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED: +- reason = "STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING: +- reason = "STATUS_PCP_TICKET_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED: +- reason = "STATUS_PCP_RAW_POLICY_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED: +- reason = "STATUS_PCP_KEY_HANDLE_INVALIDATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT: +- reason = "STATUS_RTPM_NO_RESULT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE: +- reason = "STATUS_RTPM_PCR_READ_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT: +- reason = "STATUS_RTPM_INVALID_CONTEXT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD: +- reason = "STATUS_RTPM_UNSUPPORTED_CMD"; +- break; +- case MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED: +- reason = "STATUS_TPM_ZERO_EXHAUST_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE: +- reason = "STATUS_HV_INVALID_HYPERCALL_CODE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT: +- reason = "STATUS_HV_INVALID_HYPERCALL_INPUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT: +- reason = "STATUS_HV_INVALID_ALIGNMENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER: +- reason = "STATUS_HV_INVALID_PARAMETER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED: +- reason = "STATUS_HV_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE: +- reason = "STATUS_HV_INVALID_PARTITION_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED: +- reason = "STATUS_HV_OPERATION_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY: +- reason = "STATUS_HV_UNKNOWN_PROPERTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE: +- reason = "STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY: +- reason = "STATUS_HV_INSUFFICIENT_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP: +- reason = "STATUS_HV_PARTITION_TOO_DEEP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID: +- reason = "STATUS_HV_INVALID_PARTITION_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX: +- reason = "STATUS_HV_INVALID_VP_INDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID: +- reason = "STATUS_HV_INVALID_PORT_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID: +- reason = "STATUS_HV_INVALID_CONNECTION_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS: +- reason = "STATUS_HV_INSUFFICIENT_BUFFERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED: +- reason = "STATUS_HV_NOT_ACKNOWLEDGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE: +- reason = "STATUS_HV_INVALID_VP_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED: +- reason = "STATUS_HV_ACKNOWLEDGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE: +- reason = "STATUS_HV_INVALID_SAVE_RESTORE_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE: +- reason = "STATUS_HV_INVALID_SYNIC_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE: +- reason = "STATUS_HV_OBJECT_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO: +- reason = "STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NO_DATA: +- reason = "STATUS_HV_NO_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INACTIVE: +- reason = "STATUS_HV_INACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES: +- reason = "STATUS_HV_NO_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE: +- reason = "STATUS_HV_FEATURE_UNAVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER: +- reason = "STATUS_HV_INSUFFICIENT_BUFFER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS: +- reason = "STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR: +- reason = "STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR: +- reason = "STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT: +- reason = "STATUS_HV_PROCESSOR_STARTUP_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED: +- reason = "STATUS_HV_SMX_ENABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX: +- reason = "STATUS_HV_INVALID_LP_INDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE: +- reason = "STATUS_HV_INVALID_REGISTER_VALUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE: +- reason = "STATUS_HV_INVALID_VTL_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED: +- reason = "STATUS_HV_NX_NOT_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID: +- reason = "STATUS_HV_INVALID_DEVICE_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE: +- reason = "STATUS_HV_INVALID_DEVICE_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID: +- reason = "STATUS_HV_PAGE_REQUEST_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID: +- reason = "STATUS_HV_INVALID_CPU_GROUP_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE: +- reason = "STATUS_HV_INVALID_CPU_GROUP_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED: +- reason = "STATUS_HV_OPERATION_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE: +- reason = "STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY: +- reason = "STATUS_HV_INSUFFICIENT_ROOT_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED: +- reason = "STATUS_HV_EVENT_BUFFER_ALREADY_FREED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY: +- reason = "STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT: +- reason = "STATUS_HV_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI: +- reason = "STATUS_IPSEC_BAD_SPI"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED: +- reason = "STATUS_IPSEC_SA_LIFETIME_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA: +- reason = "STATUS_IPSEC_WRONG_SA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED: +- reason = "STATUS_IPSEC_REPLAY_CHECK_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET: +- reason = "STATUS_IPSEC_INVALID_PACKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED: +- reason = "STATUS_IPSEC_INTEGRITY_CHECK_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP: +- reason = "STATUS_IPSEC_CLEAR_TEXT_DROP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP: +- reason = "STATUS_IPSEC_AUTH_FIREWALL_DROP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP: +- reason = "STATUS_IPSEC_THROTTLE_DROP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK: +- reason = "STATUS_IPSEC_DOSP_BLOCK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST: +- reason = "STATUS_IPSEC_DOSP_RECEIVED_MULTICAST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET: +- reason = "STATUS_IPSEC_DOSP_INVALID_PACKET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED: +- reason = "STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES: +- reason = "STATUS_IPSEC_DOSP_MAX_ENTRIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: +- reason = "STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: +- reason = "STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER: +- reason = "STATUS_VID_DUPLICATE_HANDLER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS: +- reason = "STATUS_VID_TOO_MANY_HANDLERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL: +- reason = "STATUS_VID_QUEUE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT: +- reason = "STATUS_VID_HANDLER_NOT_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME: +- reason = "STATUS_VID_INVALID_OBJECT_NAME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG: +- reason = "STATUS_VID_PARTITION_NAME_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG: +- reason = "STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS: +- reason = "STATUS_VID_PARTITION_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST: +- reason = "STATUS_VID_PARTITION_DOES_NOT_EXIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND: +- reason = "STATUS_VID_PARTITION_NAME_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS: +- reason = "STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT: +- reason = "STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED: +- reason = "STATUS_VID_MB_STILL_REFERENCED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED: +- reason = "STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS: +- reason = "STATUS_VID_INVALID_NUMA_SETTINGS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX: +- reason = "STATUS_VID_INVALID_NUMA_NODE_INDEX"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED: +- reason = "STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE: +- reason = "STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW: +- reason = "STATUS_VID_PAGE_RANGE_OVERFLOW"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE: +- reason = "STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE: +- reason = "STATUS_VID_INVALID_GPA_RANGE_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE: +- reason = "STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED: +- reason = "STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE: +- reason = "STATUS_VID_INVALID_PPM_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED: +- reason = "STATUS_VID_MBPS_ARE_LOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED: +- reason = "STATUS_VID_MESSAGE_QUEUE_CLOSED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED: +- reason = "STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING: +- reason = "STATUS_VID_STOP_PENDING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE: +- reason = "STATUS_VID_INVALID_PROCESSOR_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT: +- reason = "STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED: +- reason = "STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET: +- reason = "STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED: +- reason = "STATUS_VID_MMIO_RANGE_DESTROYED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET: +- reason = "STATUS_VID_INVALID_CHILD_GPA_PAGE_SET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED: +- reason = "STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL: +- reason = "STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE: +- reason = "STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT: +- reason = "STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT: +- reason = "STATUS_VID_SAVED_STATE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM: +- reason = "STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE: +- reason = "STATUS_VID_SAVED_STATE_INCOMPATIBLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED: +- reason = "STATUS_VID_VTL_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL: +- reason = "STATUS_VOLMGR_DATABASE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED: +- reason = "STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC: +- reason = "STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED: +- reason = "STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME: +- reason = "STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE: +- reason = "STATUS_VOLMGR_DISK_DUPLICATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC: +- reason = "STATUS_VOLMGR_DISK_DYNAMIC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID: +- reason = "STATUS_VOLMGR_DISK_ID_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID: +- reason = "STATUS_VOLMGR_DISK_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER: +- reason = "STATUS_VOLMGR_DISK_LAST_VOTER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS: +- reason = "STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING: +- reason = "STATUS_VOLMGR_DISK_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY: +- reason = "STATUS_VOLMGR_DISK_NOT_EMPTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE: +- reason = "STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED: +- reason = "STATUS_VOLMGR_DISK_REVECTORING_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID: +- reason = "STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED: +- reason = "STATUS_VOLMGR_DISK_SET_NOT_CONTAINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS: +- reason = "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES: +- reason = "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED: +- reason = "STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED: +- reason = "STATUS_VOLMGR_EXTENT_ALREADY_USED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS: +- reason = "STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION: +- reason = "STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED: +- reason = "STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION: +- reason = "STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH: +- reason = "STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED: +- reason = "STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID: +- reason = "STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS: +- reason = "STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC: +- reason = "STATUS_VOLMGR_MEMBER_IN_SYNC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE: +- reason = "STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID: +- reason = "STATUS_VOLMGR_MEMBER_INDEX_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING: +- reason = "STATUS_VOLMGR_MEMBER_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED: +- reason = "STATUS_VOLMGR_MEMBER_NOT_DETACHED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING: +- reason = "STATUS_VOLMGR_MEMBER_REGENERATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED: +- reason = "STATUS_VOLMGR_ALL_DISKS_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS: +- reason = "STATUS_VOLMGR_NO_REGISTERED_USERS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER: +- reason = "STATUS_VOLMGR_NO_SUCH_USER"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET: +- reason = "STATUS_VOLMGR_NOTIFICATION_RESET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE: +- reason = "STATUS_VOLMGR_PACK_DUPLICATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID: +- reason = "STATUS_VOLMGR_PACK_ID_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID: +- reason = "STATUS_VOLMGR_PACK_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID: +- reason = "STATUS_VOLMGR_PACK_NAME_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE: +- reason = "STATUS_VOLMGR_PACK_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM: +- reason = "STATUS_VOLMGR_PACK_HAS_QUORUM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM: +- reason = "STATUS_VOLMGR_PACK_WITHOUT_QUORUM"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID: +- reason = "STATUS_VOLMGR_PARTITION_STYLE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED: +- reason = "STATUS_VOLMGR_PARTITION_UPDATE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC: +- reason = "STATUS_VOLMGR_PLEX_IN_SYNC"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE: +- reason = "STATUS_VOLMGR_PLEX_INDEX_DUPLICATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID: +- reason = "STATUS_VOLMGR_PLEX_INDEX_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE: +- reason = "STATUS_VOLMGR_PLEX_LAST_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING: +- reason = "STATUS_VOLMGR_PLEX_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING: +- reason = "STATUS_VOLMGR_PLEX_REGENERATING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID: +- reason = "STATUS_VOLMGR_PLEX_TYPE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5: +- reason = "STATUS_VOLMGR_PLEX_NOT_RAID5"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE: +- reason = "STATUS_VOLMGR_PLEX_NOT_SIMPLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID: +- reason = "STATUS_VOLMGR_STRUCTURE_SIZE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS: +- reason = "STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS: +- reason = "STATUS_VOLMGR_TRANSACTION_IN_PROGRESS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE: +- reason = "STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK: +- reason = "STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID: +- reason = "STATUS_VOLMGR_VOLUME_ID_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID: +- reason = "STATUS_VOLMGR_VOLUME_LENGTH_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE: +- reason = "STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED: +- reason = "STATUS_VOLMGR_VOLUME_NOT_MIRRORED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED: +- reason = "STATUS_VOLMGR_VOLUME_NOT_RETAINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE: +- reason = "STATUS_VOLMGR_VOLUME_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED: +- reason = "STATUS_VOLMGR_VOLUME_RETAINED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE: +- reason = "STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK: +- reason = "STATUS_VOLMGR_BAD_BOOT_DISK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE: +- reason = "STATUS_VOLMGR_PACK_CONFIG_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE: +- reason = "STATUS_VOLMGR_PACK_CONFIG_ONLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK: +- reason = "STATUS_VOLMGR_NOT_PRIMARY_PACK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED: +- reason = "STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED: +- reason = "STATUS_VOLMGR_VOLUME_MIRRORED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED: +- reason = "STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES: +- reason = "STATUS_VOLMGR_NO_VALID_LOG_COPIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT: +- reason = "STATUS_VOLMGR_PRIMARY_PACK_PRESENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID: +- reason = "STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED: +- reason = "STATUS_VOLMGR_MIRROR_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED: +- reason = "STATUS_VOLMGR_RAID5_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS: +- reason = "STATUS_BCD_TOO_MANY_ELEMENTS"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING: +- reason = "STATUS_VHD_DRIVE_FOOTER_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH: +- reason = "STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT: +- reason = "STATUS_VHD_DRIVE_FOOTER_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN: +- reason = "STATUS_VHD_FORMAT_UNKNOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION: +- reason = "STATUS_VHD_FORMAT_UNSUPPORTED_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH: +- reason = "STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION: +- reason = "STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT: +- reason = "STATUS_VHD_SPARSE_HEADER_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE: +- reason = "STATUS_VHD_BLOCK_ALLOCATION_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT: +- reason = "STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE: +- reason = "STATUS_VHD_INVALID_BLOCK_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH: +- reason = "STATUS_VHD_BITMAP_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND: +- reason = "STATUS_VHD_PARENT_VHD_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH: +- reason = "STATUS_VHD_CHILD_PARENT_ID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH: +- reason = "STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE: +- reason = "STATUS_VHD_METADATA_READ_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE: +- reason = "STATUS_VHD_METADATA_WRITE_FAILURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE: +- reason = "STATUS_VHD_INVALID_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE: +- reason = "STATUS_VHD_INVALID_FILE_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND: +- reason = "STATUS_VIRTDISK_PROVIDER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK: +- reason = "STATUS_VIRTDISK_NOT_VIRTUAL_DISK"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED: +- reason = "STATUS_VHD_PARENT_VHD_ACCESS_DENIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH: +- reason = "STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED: +- reason = "STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT: +- reason = "STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION: +- reason = "STATUS_VIRTUAL_DISK_LIMITATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE: +- reason = "STATUS_VHD_INVALID_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE: +- reason = "STATUS_VHD_INVALID_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE: +- reason = "STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED: +- reason = "STATUS_VIRTDISK_DISK_ALREADY_OWNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE: +- reason = "STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED: +- reason = "STATUS_CTLOG_TRACKING_NOT_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE: +- reason = "STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE: +- reason = "STATUS_CTLOG_VHD_CHANGED_OFFLINE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE: +- reason = "STATUS_CTLOG_INVALID_TRACKING_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE: +- reason = "STATUS_CTLOG_INCONSISTENT_TRACKING_FILE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL: +- reason = "STATUS_VHD_METADATA_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID: +- reason = "STATUS_VHD_INVALID_CHANGE_TRACKING_ID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED: +- reason = "STATUS_VHD_CHANGE_TRACKING_DISABLED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION: +- reason = "STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA: +- reason = "STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE: +- reason = "STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE: +- reason = "STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND: +- reason = "STATUS_RKF_KEY_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY: +- reason = "STATUS_RKF_DUPLICATE_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL: +- reason = "STATUS_RKF_BLOB_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL: +- reason = "STATUS_RKF_STORE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED: +- reason = "STATUS_RKF_FILE_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY: +- reason = "STATUS_RKF_ACTIVE_KEY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION: +- reason = "STATUS_RDBSS_RESTART_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION: +- reason = "STATUS_RDBSS_CONTINUE_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION: +- reason = "STATUS_RDBSS_POST_OPERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP: +- reason = "STATUS_RDBSS_RETRY_LOOKUP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE: +- reason = "STATUS_BTH_ATT_INVALID_HANDLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED: +- reason = "STATUS_BTH_ATT_READ_NOT_PERMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED: +- reason = "STATUS_BTH_ATT_WRITE_NOT_PERMITTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU: +- reason = "STATUS_BTH_ATT_INVALID_PDU"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION: +- reason = "STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED: +- reason = "STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET: +- reason = "STATUS_BTH_ATT_INVALID_OFFSET"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION: +- reason = "STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL: +- reason = "STATUS_BTH_ATT_PREPARE_QUEUE_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND: +- reason = "STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG: +- reason = "STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE: +- reason = "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: +- reason = "STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY: +- reason = "STATUS_BTH_ATT_UNLIKELY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION: +- reason = "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE: +- reason = "STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES: +- reason = "STATUS_BTH_ATT_INSUFFICIENT_RESOURCES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR: +- reason = "STATUS_BTH_ATT_UNKNOWN_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED: +- reason = "STATUS_SECUREBOOT_ROLLBACK_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION: +- reason = "STATUS_SECUREBOOT_POLICY_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY: +- reason = "STATUS_SECUREBOOT_INVALID_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND: +- reason = "STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED: +- reason = "STATUS_SECUREBOOT_POLICY_NOT_SIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED: +- reason = "STATUS_SECUREBOOT_FILE_REPLACED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED: +- reason = "STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN: +- reason = "STATUS_SECUREBOOT_POLICY_UNKNOWN"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION: +- reason = "STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH: +- reason = "STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED: +- reason = "STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH: +- reason = "STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING: +- reason = "STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY: +- reason = "STATUS_SECUREBOOT_NOT_BASE_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY: +- reason = "STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND: +- reason = "STATUS_AUDIO_ENGINE_NODE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST: +- reason = "STATUS_HDAUDIO_EMPTY_CONNECTION_LIST"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED: +- reason = "STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED: +- reason = "STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY: +- reason = "STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED: +- reason = "STATUS_VSM_NOT_INITIALIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE: +- reason = "STATUS_VSM_DMA_PROTECTION_NOT_IN_USE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID: +- reason = "STATUS_VOLSNAP_BOOTFILE_NOT_VALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT: +- reason = "STATUS_VOLSNAP_ACTIVATION_TIMEOUT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED: +- reason = "STATUS_IO_PREEMPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED: +- reason = "STATUS_SVHDX_ERROR_STORED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE: +- reason = "STATUS_SVHDX_ERROR_NOT_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED: +- reason = "STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT: +- reason = "STATUS_SVHDX_RESERVATION_CONFLICT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE: +- reason = "STATUS_SVHDX_WRONG_FILE_TYPE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH: +- reason = "STATUS_SVHDX_VERSION_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHD_SHARED: +- reason = "STATUS_VHD_SHARED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR: +- reason = "STATUS_SVHDX_NO_INITIATOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND: +- reason = "STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP: +- reason = "STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT: +- reason = "STATUS_SMB_BAD_CLUSTER_DIALECT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED: +- reason = "STATUS_SMB_GUEST_LOGON_BLOCKED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID: +- reason = "STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID: +- reason = "STATUS_SPACES_RESILIENCY_TYPE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID: +- reason = "STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID: +- reason = "STATUS_SPACES_DRIVE_REDUNDANCY_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID: +- reason = "STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID: +- reason = "STATUS_SPACES_INTERLEAVE_LENGTH_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID: +- reason = "STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES: +- reason = "STATUS_SPACES_NOT_ENOUGH_DRIVES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR: +- reason = "STATUS_SPACES_EXTENDED_ERROR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID: +- reason = "STATUS_SPACES_PROVISIONING_TYPE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID: +- reason = "STATUS_SPACES_ALLOCATION_SIZE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID: +- reason = "STATUS_SPACES_ENCLOSURE_AWARE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID: +- reason = "STATUS_SPACES_WRITE_CACHE_SIZE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID: +- reason = "STATUS_SPACES_NUMBER_OF_GROUPS_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID: +- reason = "STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE: +- reason = "STATUS_SPACES_UPDATE_COLUMN_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED: +- reason = "STATUS_SPACES_MAP_REQUIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION: +- reason = "STATUS_SPACES_UNSUPPORTED_VERSION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA: +- reason = "STATUS_SPACES_CORRUPT_METADATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL: +- reason = "STATUS_SPACES_DRT_FULL"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY: +- reason = "STATUS_SPACES_INCONSISTENCY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY: +- reason = "STATUS_SPACES_LOG_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY: +- reason = "STATUS_SPACES_NO_REDUNDANCY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY: +- reason = "STATUS_SPACES_DRIVE_NOT_READY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT: +- reason = "STATUS_SPACES_DRIVE_SPLIT"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA: +- reason = "STATUS_SPACES_DRIVE_LOST_DATA"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE: +- reason = "STATUS_SPACES_ENTRY_INCOMPLETE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID: +- reason = "STATUS_SPACES_ENTRY_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY: +- reason = "STATUS_SPACES_MARK_DIRTY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND: +- reason = "STATUS_SECCORE_INVALID_COMMAND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED: +- reason = "STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION: +- reason = "STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY: +- reason = "STATUS_SYSTEM_INTEGRITY_INVALID_POLICY"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED: +- reason = "STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES: +- reason = "STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES"; +- break; +- case MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED: +- reason = "STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND: +- reason = "STATUS_NO_APPLICABLE_APP_LICENSES_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND: +- reason = "STATUS_CLIP_LICENSE_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING: +- reason = "STATUS_CLIP_DEVICE_LICENSE_MISSING"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE: +- reason = "STATUS_CLIP_LICENSE_INVALID_SIGNATURE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID: +- reason = "STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED: +- reason = "STATUS_CLIP_LICENSE_EXPIRED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE: +- reason = "STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED: +- reason = "STATUS_CLIP_LICENSE_NOT_SIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE: +- reason = "STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH: +- reason = "STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED: +- reason = "STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID: +- reason = "STATUS_PLATFORM_MANIFEST_INVALID"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED: +- reason = "STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED: +- reason = "STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND: +- reason = "STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE: +- reason = "STATUS_PLATFORM_MANIFEST_NOT_ACTIVE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED: +- reason = "STATUS_PLATFORM_MANIFEST_NOT_SIGNED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED: +- reason = "STATUS_APPEXEC_CONDITION_NOT_SATISFIED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED: +- reason = "STATUS_APPEXEC_HANDLE_INVALIDATED"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION: +- reason = "STATUS_APPEXEC_INVALID_HOST_GENERATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION: +- reason = "STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE: +- reason = "STATUS_APPEXEC_INVALID_HOST_STATE"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR: +- reason = "STATUS_APPEXEC_NO_DONOR"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH: +- reason = "STATUS_APPEXEC_HOST_ID_MISMATCH"; +- break; +- case MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER: +- reason = "STATUS_APPEXEC_UNKNOWN_USER"; +- break; +- default: { +- char reason_string[11]; +- snprintf(reason_string, sizeof(reason_string), "0x%08x", ntstatus); +- reason = reason_string; +- break; +- } ++// The content of this array was created from ntstatus.h in the 10 SDK ++// (version 10.0.19041.0) with ++// ++// egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h ++// | tr -d '\r' ++// | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' ++// | sort ++// | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2,@' ++// ++// With easy copy to clipboard with ++// | xclip -selection c # on linux ++// | clip # on windows ++// | pbcopy # on mac ++static const uint32_t kNTStatusValues[] = { ++ MD_NTSTATUS_WIN_STATUS_SUCCESS, ++ MD_NTSTATUS_WIN_STATUS_WAIT_0, ++ MD_NTSTATUS_WIN_STATUS_WAIT_1, ++ MD_NTSTATUS_WIN_STATUS_WAIT_2, ++ MD_NTSTATUS_WIN_STATUS_WAIT_3, ++ MD_NTSTATUS_WIN_STATUS_WAIT_63, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_0, ++ MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63, ++ MD_NTSTATUS_WIN_STATUS_USER_APC, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE, ++ MD_NTSTATUS_WIN_STATUS_KERNEL_APC, ++ MD_NTSTATUS_WIN_STATUS_ALERTED, ++ MD_NTSTATUS_WIN_STATUS_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_PENDING, ++ MD_NTSTATUS_WIN_STATUS_REPARSE, ++ MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES, ++ MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED, ++ MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED, ++ MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED, ++ MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP, ++ MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR, ++ MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE, ++ MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE, ++ MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_CRASH_DUMP, ++ MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE, ++ MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY, ++ MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY, ++ MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED, ++ MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS, ++ MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS, ++ MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH, ++ MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH, ++ MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH, ++ MD_NTSTATUS_WIN_STATUS_GHOSTED, ++ MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN, ++ MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL, ++ MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA, ++ MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL, ++ MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED, ++ MD_NTSTATUS_WIN_DBG_CONTINUE, ++ MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE, ++ MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE, ++ MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE, ++ MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS, ++ MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED, ++ MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE, ++ MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE, ++ MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED, ++ MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE, ++ MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED, ++ MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION, ++ MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY, ++ MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY, ++ MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP, ++ MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY, ++ MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED, ++ MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED, ++ MD_NTSTATUS_WIN_STATUS_EVENT_DONE, ++ MD_NTSTATUS_WIN_STATUS_EVENT_PENDING, ++ MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM, ++ MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT, ++ MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED, ++ MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION, ++ MD_NTSTATUS_WIN_STATUS_WAS_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32, ++ MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE, ++ MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE, ++ MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP, ++ MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE, ++ MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, ++ MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED, ++ MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED, ++ MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED, ++ MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB, ++ MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_HIBERNATED, ++ MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED, ++ MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES, ++ MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION, ++ MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY, ++ MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE, ++ MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE, ++ MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED, ++ MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM, ++ MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN, ++ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED, ++ MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART, ++ MD_NTSTATUS_WIN_DBG_REPLY_LATER, ++ MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE, ++ MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD, ++ MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS, ++ MD_NTSTATUS_WIN_DBG_CONTROL_C, ++ MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C, ++ MD_NTSTATUS_WIN_DBG_RIPEXCEPTION, ++ MD_NTSTATUS_WIN_DBG_CONTROL_BREAK, ++ MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION, ++ MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C, ++ MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY, ++ MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT, ++ MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT, ++ MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE, ++ MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED, ++ MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED, ++ MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART, ++ MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT, ++ MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT, ++ MD_NTSTATUS_WIN_STATUS_BREAKPOINT, ++ MD_NTSTATUS_WIN_STATUS_SINGLE_STEP, ++ MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES, ++ MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER, ++ MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE, ++ MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE, ++ MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS, ++ MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME, ++ MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG, ++ MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION, ++ MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES, ++ MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_BUS_RESET, ++ MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK, ++ MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES, ++ MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_LONGJUMP, ++ MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED, ++ MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED, ++ MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED, ++ MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE, ++ MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE, ++ MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK, ++ MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE, ++ MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN, ++ MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR, ++ MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS, ++ MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG, ++ MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA, ++ MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN, ++ MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED, ++ MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA, ++ MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE, ++ MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION, ++ MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED, ++ MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED, ++ MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL, ++ MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS, ++ MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA, ++ MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK, ++ MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC, ++ MD_NTSTATUS_WIN_STATUS_INVALID_CID, ++ MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_END_OF_FILE, ++ MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR, ++ MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_NO_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES, ++ MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW, ++ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM, ++ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION, ++ MD_NTSTATUS_WIN_STATUS_UNWIND, ++ MD_NTSTATUS_WIN_STATUS_BAD_STACK, ++ MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET, ++ MD_NTSTATUS_WIN_STATUS_NOT_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_PARITY_ERROR, ++ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM, ++ MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES, ++ MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX, ++ MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER, ++ MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB, ++ MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD, ++ MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN, ++ MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DATA_ERROR, ++ MD_NTSTATUS_WIN_STATUS_CRC_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG, ++ MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION, ++ MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED, ++ MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET, ++ MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE, ++ MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING, ++ MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP, ++ MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION, ++ MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY, ++ MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE, ++ MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED, ++ MD_NTSTATUS_WIN_STATUS_DELETE_PENDING, ++ MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION, ++ MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_INVALID_OWNER, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP, ++ MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN, ++ MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY, ++ MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE, ++ MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME, ++ MD_NTSTATUS_WIN_STATUS_USER_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER, ++ MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP, ++ MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP, ++ MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP, ++ MD_NTSTATUS_WIN_STATUS_LAST_ADMIN, ++ MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD, ++ MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD, ++ MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS, ++ MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION, ++ MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_NONE_MAPPED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED, ++ MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ACL, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SID, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR, ++ MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_NO_TOKEN, ++ MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL, ++ MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_DISK_FULL, ++ MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED, ++ MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY, ++ MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL, ++ MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED, ++ MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW, ++ MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO, ++ MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES, ++ MD_NTSTATUS_WIN_STATUS_FILE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE, ++ MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED, ++ MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA, ++ MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES, ++ MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL, ++ MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS, ++ MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS, ++ MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE, ++ MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD, ++ MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT, ++ MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE, ++ MD_NTSTATUS_WIN_STATUS_PIPE_BUSY, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION, ++ MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING, ++ MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING, ++ MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE, ++ MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED, ++ MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED, ++ MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET, ++ MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING, ++ MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME, ++ MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS, ++ MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE, ++ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR, ++ MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER, ++ MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL, ++ MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE, ++ MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE, ++ MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS, ++ MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED, ++ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT, ++ MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_FILE_RENAMED, ++ MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_CANT_WAIT, ++ MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO, ++ MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN, ++ MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL, ++ MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION, ++ MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED, ++ MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR, ++ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR, ++ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR, ++ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR, ++ MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS, ++ MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12, ++ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED, ++ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED, ++ MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE, ++ MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE, ++ MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY, ++ MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE, ++ MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_FILES_OPEN, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE, ++ MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR, ++ MD_NTSTATUS_WIN_STATUS_NO_LDT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE, ++ MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES, ++ MD_NTSTATUS_WIN_STATUS_CANCELLED, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME, ++ MD_NTSTATUS_WIN_STATUS_FILE_DELETED, ++ MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP, ++ MD_NTSTATUS_WIN_STATUS_SPECIAL_USER, ++ MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP, ++ MD_NTSTATUS_WIN_STATUS_FILE_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS, ++ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS, ++ MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16, ++ MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC, ++ MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_OPEN_FAILED, ++ MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT, ++ MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_LINK_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS, ++ MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED, ++ MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE, ++ MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL, ++ MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED, ++ MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR, ++ MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS, ++ MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS, ++ MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS, ++ MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS, ++ MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS, ++ MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED, ++ MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE, ++ MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER, ++ MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER, ++ MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER, ++ MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER, ++ MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS, ++ MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED, ++ MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY, ++ MD_NTSTATUS_WIN_STATUS_FT_ORPHANING, ++ MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT, ++ MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED, ++ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_NO_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_KEY_DELETED, ++ MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS, ++ MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN, ++ MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE, ++ MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER, ++ MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL, ++ MD_NTSTATUS_WIN_STATUS_TOO_LATE, ++ MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET, ++ MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START, ++ MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED, ++ MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT, ++ MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL, ++ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING, ++ MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER, ++ MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES, ++ MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE, ++ MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED, ++ MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE, ++ MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION, ++ MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB, ++ MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID, ++ MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA, ++ MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE, ++ MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY, ++ MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES, ++ MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE, ++ MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION, ++ MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE, ++ MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED, ++ MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED, ++ MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND, ++ MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA, ++ MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE, ++ MD_NTSTATUS_WIN_STATUS_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM, ++ MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ, ++ MD_NTSTATUS_WIN_STATUS_FAIL_CHECK, ++ MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID, ++ MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_RETRY, ++ MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE, ++ MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET, ++ MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT, ++ MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT, ++ MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED, ++ MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT, ++ MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED, ++ MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE, ++ MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED, ++ MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO, ++ MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT, ++ MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT, ++ MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST, ++ MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1, ++ MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2, ++ MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED, ++ MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT, ++ MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT, ++ MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS, ++ MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT, ++ MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION, ++ MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD, ++ MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED, ++ MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK, ++ MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE, ++ MD_NTSTATUS_WIN_STATUS_NO_MATCH, ++ MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT, ++ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID, ++ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID, ++ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED, ++ MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED, ++ MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT, ++ MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL, ++ MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS, ++ MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY, ++ MD_NTSTATUS_WIN_STATUS_NO_EFS, ++ MD_NTSTATUS_WIN_STATUS_WRONG_EFS, ++ MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS, ++ MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED, ++ MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED, ++ MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN, ++ MD_NTSTATUS_WIN_STATUS_SHARED_POLICY, ++ MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR, ++ MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE, ++ MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE, ++ MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX, ++ MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED, ++ MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_DS_BUSY, ++ MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS, ++ MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER, ++ MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF, ++ MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN, ++ MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS, ++ MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS, ++ MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED, ++ MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_NOINTERFACE, ++ MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP, ++ MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE, ++ MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY, ++ MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM, ++ MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL, ++ MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION, ++ MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED, ++ MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, ++ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS, ++ MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER, ++ MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD, ++ MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY, ++ MD_NTSTATUS_WIN_STATUS_DS_CANT_START, ++ MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, ++ MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS, ++ MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN, ++ MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE, ++ MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE, ++ MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED, ++ MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY, ++ MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES, ++ MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID, ++ MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC, ++ MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS, ++ MD_NTSTATUS_WIN_STATUS_NO_PA_DATA, ++ MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER, ++ MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE, ++ MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS, ++ MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED, ++ MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED, ++ MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR, ++ MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION, ++ MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY, ++ MD_NTSTATUS_WIN_STATUS_HOST_DOWN, ++ MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH, ++ MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG, ++ MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE, ++ MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT, ++ MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64, ++ MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED, ++ MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER, ++ MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR, ++ MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_MCA_OCCURED, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL, ++ MD_NTSTATUS_WIN_STATUS_NO_SECRETS, ++ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, ++ MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH, ++ MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR, ++ MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED, ++ MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED, ++ MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C, ++ MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD, ++ MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND, ++ MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE, ++ MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN, ++ MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT, ++ MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC, ++ MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC, ++ MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED, ++ MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED, ++ MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED, ++ MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD, ++ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST, ++ MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST, ++ MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST, ++ MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME, ++ MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK, ++ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED, ++ MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH, ++ MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE, ++ MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE, ++ MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_BEYOND_VDL, ++ MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_PTE_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_PURGE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION, ++ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, ++ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER, ++ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, ++ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, ++ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_LABEL, ++ MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED, ++ MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION, ++ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SESSION, ++ MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION, ++ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT, ++ MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED, ++ MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN, ++ MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING, ++ MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY, ++ MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED, ++ MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN, ++ MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL, ++ MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR, ++ MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS, ++ MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST, ++ MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH, ++ MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE, ++ MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION, ++ MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN, ++ MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED, ++ MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID, ++ MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE, ++ MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS, ++ MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION, ++ MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE, ++ MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES, ++ MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES, ++ MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX, ++ MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED, ++ MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE, ++ MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING, ++ MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED, ++ MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND, ++ MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE, ++ MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE, ++ MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR, ++ MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED, ++ MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG, ++ MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES, ++ MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH, ++ MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES, ++ MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME, ++ MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX, ++ MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS, ++ MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE, ++ MD_NTSTATUS_WIN_STATUS_INVALID_CAP, ++ MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG, ++ MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED, ++ MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER, ++ MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE, ++ MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED, ++ MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID, ++ MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED, ++ MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING, ++ MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_INTERRUPTED, ++ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING, ++ MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED, ++ MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED, ++ MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_PORT_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST, ++ MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE, ++ MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED, ++ MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH, ++ MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED, ++ MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE, ++ MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING, ++ MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING, ++ MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED, ++ MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION, ++ MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION, ++ MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION, ++ MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY, ++ MD_NTSTATUS_WIN_STATUS_INVALID_THREAD, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK, ++ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY, ++ MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE, ++ MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE, ++ MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE, ++ MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE, ++ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS, ++ MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY, ++ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED, ++ MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE, ++ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS, ++ MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT, ++ MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE, ++ MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED, ++ MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED, ++ MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK, ++ MD_NTSTATUS_WIN_STATUS_BAD_KEY, ++ MD_NTSTATUS_WIN_STATUS_BAD_DATA, ++ MD_NTSTATUS_WIN_STATUS_NO_KEY, ++ MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED, ++ MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION, ++ MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED, ++ MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE, ++ MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED, ++ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, ++ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, ++ MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR, ++ MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT, ++ MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS, ++ MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE, ++ MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID, ++ MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET, ++ MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED, ++ MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL, ++ MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING, ++ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER, ++ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER, ++ MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN, ++ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED, ++ MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER, ++ MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE, ++ MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING, ++ MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING, ++ MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR, ++ MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT, ++ MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND, ++ MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED, ++ MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED, ++ MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING, ++ MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED, ++ MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF, ++ MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS, ++ MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS, ++ MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT, ++ MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES, ++ MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE, ++ MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS, ++ MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE, ++ MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED, ++ MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE, ++ MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN, ++ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND, ++ MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX, ++ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX, ++ MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS, ++ MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE, ++ MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL, ++ MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG, ++ MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND, ++ MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE, ++ MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY, ++ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE, ++ MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY, ++ MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP, ++ MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED, ++ MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT, ++ MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION, ++ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS, ++ MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED, ++ MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND, ++ MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND, ++ MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID, ++ MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT, ++ MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE, ++ MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE, ++ MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO, ++ MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW, ++ MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW, ++ MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS, ++ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS, ++ MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND, ++ MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT, ++ MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES, ++ MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED, ++ MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE, ++ MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE, ++ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL, ++ MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME, ++ MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL, ++ MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED, ++ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES, ++ MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL, ++ MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE, ++ MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT, ++ MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH, ++ MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED, ++ MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH, ++ MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE, ++ MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER, ++ MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE, ++ MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL, ++ MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION, ++ MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION, ++ MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT, ++ MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION, ++ MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION, ++ MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED, ++ MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR, ++ MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE, ++ MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID, ++ MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED, ++ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD, ++ MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING, ++ MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME, ++ MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY, ++ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE, ++ MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR, ++ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY, ++ MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE, ++ MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE, ++ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT, ++ MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT, ++ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED, ++ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD, ++ MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE, ++ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING, ++ MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR, ++ MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS, ++ MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR, ++ MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE, ++ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG, ++ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME, ++ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME, ++ MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED, ++ MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS, ++ MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR, ++ MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT, ++ MD_NTSTATUS_WIN_STATUS_ACPI_FATAL, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, ++ MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK, ++ MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL, ++ MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER, ++ MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS, ++ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE, ++ MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED, ++ MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED, ++ MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX, ++ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE, ++ MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING, ++ MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET, ++ MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION, ++ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION, ++ MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION, ++ MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED, ++ MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK, ++ MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION, ++ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, ++ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, ++ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, ++ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, ++ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT, ++ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, ++ MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY, ++ MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED, ++ MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG, ++ MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED, ++ MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED, ++ MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED, ++ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE, ++ MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE, ++ MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED, ++ MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID, ++ MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, ++ MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS, ++ MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR, ++ MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT, ++ MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, ++ MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY, ++ MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST, ++ MD_NTSTATUS_WIN_STATUS_TM_VOLATILE, ++ MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES, ++ MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK, ++ MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR, ++ MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED, ++ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED, ++ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE, ++ MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED, ++ MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION, ++ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT, ++ MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE, ++ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG, ++ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED, ++ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED, ++ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL, ++ MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT, ++ MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_FULL, ++ MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED, ++ MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED, ++ MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL, ++ MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS, ++ MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_LOG_PINNED, ++ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY, ++ MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED, ++ MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION, ++ MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD, ++ MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED, ++ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED, ++ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO, ++ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP, ++ MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL, ++ MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY, ++ MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH, ++ MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH, ++ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION, ++ MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION, ++ MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS, ++ MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED, ++ MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED, ++ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED, ++ MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY, ++ MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED, ++ MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION, ++ MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS, ++ MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE, ++ MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED, ++ MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED, ++ MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE, ++ MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA, ++ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR, ++ MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE, ++ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE, ++ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK, ++ MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO, ++ MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR, ++ MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK, ++ MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID, ++ MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION, ++ MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG, ++ MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED, ++ MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER, ++ MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY, ++ MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS, ++ MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY, ++ MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED, ++ MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE, ++ MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED, ++ MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG, ++ MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE, ++ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID, ++ MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE, ++ MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING, ++ MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE, ++ MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED, ++ MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE, ++ MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT, ++ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT, ++ MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_FWP_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION, ++ MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN, ++ MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER, ++ MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY, ++ MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT, ++ MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS, ++ MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED, ++ MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE, ++ MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL, ++ MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY, ++ MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT, ++ MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS, ++ MD_NTSTATUS_WIN_STATUS_FWP_RESERVED, ++ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION, ++ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD, ++ MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER, ++ MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER, ++ MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER, ++ MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP, ++ MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS, ++ MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM, ++ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION, ++ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT, ++ MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED, ++ MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL, ++ MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME, ++ MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON, ++ MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING, ++ MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING, ++ MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE, ++ MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND, ++ MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP, ++ MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING, ++ MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION, ++ MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS, ++ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL, ++ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST, ++ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA, ++ MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID, ++ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA, ++ MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS, ++ MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT, ++ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES, ++ MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY, ++ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL, ++ MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED, ++ MD_NTSTATUS_WIN_STATUS_TPM_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD, ++ MD_NTSTATUS_WIN_STATUS_TPM_FAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL, ++ MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND, ++ MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC, ++ MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOSRK, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB, ++ MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET, ++ MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM, ++ MD_NTSTATUS_WIN_STATUS_TPM_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD, ++ MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR, ++ MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BADTAG, ++ MD_NTSTATUS_WIN_STATUS_TPM_IOERROR, ++ MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE, ++ MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT, ++ MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION, ++ MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY, ++ MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION, ++ MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN, ++ MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY, ++ MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY, ++ MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE, ++ MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT, ++ MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE, ++ MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP, ++ MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR, ++ MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING, ++ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK, ++ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY, ++ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN, ++ MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE, ++ MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY, ++ MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE, ++ MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT, ++ MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS, ++ MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION, ++ MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE, ++ MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY, ++ MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK, ++ MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT, ++ MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE, ++ MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE, ++ MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_TPM_RETRY, ++ MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST, ++ MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST, ++ MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING, ++ MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED, ++ MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS, ++ MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK, ++ MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR, ++ MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED, ++ MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED, ++ MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED, ++ MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET, ++ MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID, ++ MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY, ++ MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT, ++ MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING, ++ MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED, ++ MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT, ++ MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT, ++ MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD, ++ MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER, ++ MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED, ++ MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY, ++ MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS, ++ MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO, ++ MD_NTSTATUS_WIN_STATUS_HV_NO_DATA, ++ MD_NTSTATUS_WIN_STATUS_HV_INACTIVE, ++ MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS, ++ MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR, ++ MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR, ++ MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID, ++ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE, ++ MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED, ++ MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED, ++ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY, ++ MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED, ++ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES, ++ MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER, ++ MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS, ++ MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL, ++ MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME, ++ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG, ++ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST, ++ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS, ++ MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED, ++ MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX, ++ MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE, ++ MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED, ++ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED, ++ MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED, ++ MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE, ++ MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET, ++ MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED, ++ MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET, ++ MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED, ++ MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE, ++ MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT, ++ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM, ++ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE, ++ MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS, ++ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING, ++ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN, ++ MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION, ++ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION, ++ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK, ++ MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED, ++ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT, ++ MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE, ++ MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED, ++ MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE, ++ MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE, ++ MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE, ++ MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE, ++ MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE, ++ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL, ++ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID, ++ MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED, ++ MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION, ++ MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA, ++ MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE, ++ MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE, ++ MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY, ++ MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL, ++ MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL, ++ MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY, ++ MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION, ++ MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES, ++ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY, ++ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY, ++ MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST, ++ MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED, ++ MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED, ++ MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY, ++ MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED, ++ MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID, ++ MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT, ++ MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_VHD_SHARED, ++ MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR, ++ MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP, ++ MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT, ++ MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED, ++ MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES, ++ MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR, ++ MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE, ++ MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED, ++ MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION, ++ MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL, ++ MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY, ++ MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT, ++ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE, ++ MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID, ++ MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY, ++ MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES, ++ MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED, ++ MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE, ++ MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE, ++ MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE, ++ MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH, ++ MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER, ++}; ++ ++// The content of this array was created from ntstatus.h in the 10 SDK ++// (version 10.0.19041.0) with ++// ++// egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h ++// | tr -d '\r' ++// | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' ++// | sort ++// | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ "\2",@' ++// ++// With easy copy to clipboard with ++// | xclip -selection c # on linux ++// | clip # on windows ++// | pbcopy # on mac ++static const char* kNTStatusStrings[] = { ++ "STATUS_SUCCESS", ++ "STATUS_WAIT_0", ++ "STATUS_WAIT_1", ++ "STATUS_WAIT_2", ++ "STATUS_WAIT_3", ++ "STATUS_WAIT_63", ++ "STATUS_ABANDONED", ++ "STATUS_ABANDONED_WAIT_0", ++ "STATUS_ABANDONED_WAIT_63", ++ "STATUS_USER_APC", ++ "STATUS_ALREADY_COMPLETE", ++ "STATUS_KERNEL_APC", ++ "STATUS_ALERTED", ++ "STATUS_TIMEOUT", ++ "STATUS_PENDING", ++ "STATUS_REPARSE", ++ "STATUS_MORE_ENTRIES", ++ "STATUS_NOT_ALL_ASSIGNED", ++ "STATUS_SOME_NOT_MAPPED", ++ "STATUS_OPLOCK_BREAK_IN_PROGRESS", ++ "STATUS_VOLUME_MOUNTED", ++ "STATUS_RXACT_COMMITTED", ++ "STATUS_NOTIFY_CLEANUP", ++ "STATUS_NOTIFY_ENUM_DIR", ++ "STATUS_NO_QUOTAS_FOR_ACCOUNT", ++ "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED", ++ "STATUS_PAGE_FAULT_TRANSITION", ++ "STATUS_PAGE_FAULT_DEMAND_ZERO", ++ "STATUS_PAGE_FAULT_COPY_ON_WRITE", ++ "STATUS_PAGE_FAULT_GUARD_PAGE", ++ "STATUS_PAGE_FAULT_PAGING_FILE", ++ "STATUS_CACHE_PAGE_LOCKED", ++ "STATUS_CRASH_DUMP", ++ "STATUS_BUFFER_ALL_ZEROS", ++ "STATUS_REPARSE_OBJECT", ++ "STATUS_RESOURCE_REQUIREMENTS_CHANGED", ++ "STATUS_TRANSLATION_COMPLETE", ++ "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY", ++ "STATUS_NOTHING_TO_TERMINATE", ++ "STATUS_PROCESS_NOT_IN_JOB", ++ "STATUS_PROCESS_IN_JOB", ++ "STATUS_VOLSNAP_HIBERNATE_READY", ++ "STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY", ++ "STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED", ++ "STATUS_INTERRUPT_STILL_CONNECTED", ++ "STATUS_PROCESS_CLONED", ++ "STATUS_FILE_LOCKED_WITH_ONLY_READERS", ++ "STATUS_FILE_LOCKED_WITH_WRITERS", ++ "STATUS_VALID_IMAGE_HASH", ++ "STATUS_VALID_CATALOG_HASH", ++ "STATUS_VALID_STRONG_CODE_HASH", ++ "STATUS_GHOSTED", ++ "STATUS_DATA_OVERWRITTEN", ++ "STATUS_RESOURCEMANAGER_READ_ONLY", ++ "STATUS_RING_PREVIOUSLY_EMPTY", ++ "STATUS_RING_PREVIOUSLY_FULL", ++ "STATUS_RING_PREVIOUSLY_ABOVE_QUOTA", ++ "STATUS_RING_NEWLY_EMPTY", ++ "STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT", ++ "STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE", ++ "STATUS_OPLOCK_HANDLE_CLOSED", ++ "STATUS_WAIT_FOR_OPLOCK", ++ "STATUS_REPARSE_GLOBAL", ++ "DBG_EXCEPTION_HANDLED", ++ "DBG_CONTINUE", ++ "STATUS_FLT_IO_COMPLETE", ++ "STATUS_RTPM_CONTEXT_CONTINUE", ++ "STATUS_RTPM_CONTEXT_COMPLETE", ++ "STATUS_HV_PENDING_PAGE_REQUESTS", ++ "STATUS_SPACES_REPAIRED", ++ "STATUS_SPACES_PAUSE", ++ "STATUS_SPACES_COMPLETE", ++ "STATUS_SPACES_REDIRECT", ++ "STATUS_OBJECT_NAME_EXISTS", ++ "STATUS_THREAD_WAS_SUSPENDED", ++ "STATUS_WORKING_SET_LIMIT_RANGE", ++ "STATUS_IMAGE_NOT_AT_BASE", ++ "STATUS_RXACT_STATE_CREATED", ++ "STATUS_SEGMENT_NOTIFICATION", ++ "STATUS_LOCAL_USER_SESSION_KEY", ++ "STATUS_BAD_CURRENT_DIRECTORY", ++ "STATUS_SERIAL_MORE_WRITES", ++ "STATUS_REGISTRY_RECOVERED", ++ "STATUS_FT_READ_RECOVERY_FROM_BACKUP", ++ "STATUS_FT_WRITE_RECOVERY", ++ "STATUS_SERIAL_COUNTER_TIMEOUT", ++ "STATUS_NULL_LM_PASSWORD", ++ "STATUS_IMAGE_MACHINE_TYPE_MISMATCH", ++ "STATUS_RECEIVE_PARTIAL", ++ "STATUS_RECEIVE_EXPEDITED", ++ "STATUS_RECEIVE_PARTIAL_EXPEDITED", ++ "STATUS_EVENT_DONE", ++ "STATUS_EVENT_PENDING", ++ "STATUS_CHECKING_FILE_SYSTEM", ++ "STATUS_FATAL_APP_EXIT", ++ "STATUS_PREDEFINED_HANDLE", ++ "STATUS_WAS_UNLOCKED", ++ "STATUS_SERVICE_NOTIFICATION", ++ "STATUS_WAS_LOCKED", ++ "STATUS_LOG_HARD_ERROR", ++ "STATUS_ALREADY_WIN32", ++ "STATUS_WX86_UNSIMULATE", ++ "STATUS_WX86_CONTINUE", ++ "STATUS_WX86_SINGLE_STEP", ++ "STATUS_WX86_BREAKPOINT", ++ "STATUS_WX86_EXCEPTION_CONTINUE", ++ "STATUS_WX86_EXCEPTION_LASTCHANCE", ++ "STATUS_WX86_EXCEPTION_CHAIN", ++ "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE", ++ "STATUS_NO_YIELD_PERFORMED", ++ "STATUS_TIMER_RESUME_IGNORED", ++ "STATUS_ARBITRATION_UNHANDLED", ++ "STATUS_CARDBUS_NOT_SUPPORTED", ++ "STATUS_WX86_CREATEWX86TIB", ++ "STATUS_MP_PROCESSOR_MISMATCH", ++ "STATUS_HIBERNATED", ++ "STATUS_RESUME_HIBERNATION", ++ "STATUS_FIRMWARE_UPDATED", ++ "STATUS_DRIVERS_LEAKING_LOCKED_PAGES", ++ "STATUS_MESSAGE_RETRIEVED", ++ "STATUS_SYSTEM_POWERSTATE_TRANSITION", ++ "STATUS_ALPC_CHECK_COMPLETION_LIST", ++ "STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION", ++ "STATUS_ACCESS_AUDIT_BY_POLICY", ++ "STATUS_ABANDON_HIBERFILE", ++ "STATUS_BIZRULES_NOT_ENABLED", ++ "STATUS_FT_READ_FROM_COPY", ++ "STATUS_IMAGE_AT_DIFFERENT_BASE", ++ "STATUS_PATCH_DEFERRED", ++ "STATUS_WAKE_SYSTEM", ++ "STATUS_DS_SHUTTING_DOWN", ++ "STATUS_DISK_REPAIR_REDIRECTED", ++ "STATUS_SERVICES_FAILED_AUTOSTART", ++ "DBG_REPLY_LATER", ++ "DBG_UNABLE_TO_PROVIDE_HANDLE", ++ "DBG_TERMINATE_THREAD", ++ "DBG_TERMINATE_PROCESS", ++ "DBG_CONTROL_C", ++ "DBG_PRINTEXCEPTION_C", ++ "DBG_RIPEXCEPTION", ++ "DBG_CONTROL_BREAK", ++ "DBG_COMMAND_EXCEPTION", ++ "DBG_PRINTEXCEPTION_WIDE_C", ++ "RPC_NT_UUID_LOCAL_ONLY", ++ "RPC_NT_SEND_INCOMPLETE", ++ "STATUS_CTX_CDM_CONNECT", ++ "STATUS_CTX_CDM_DISCONNECT", ++ "STATUS_SXS_RELEASE_ACTIVATION_CONTEXT", ++ "STATUS_HEURISTIC_DAMAGE_POSSIBLE", ++ "STATUS_RECOVERY_NOT_NEEDED", ++ "STATUS_RM_ALREADY_STARTED", ++ "STATUS_LOG_NO_RESTART", ++ "STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST", ++ "STATUS_GRAPHICS_PARTIAL_DATA_POPULATED", ++ "STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION", ++ "STATUS_GRAPHICS_MODE_NOT_PINNED", ++ "STATUS_GRAPHICS_NO_PREFERRED_MODE", ++ "STATUS_GRAPHICS_DATASET_IS_EMPTY", ++ "STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET", ++ "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED", ++ "STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS", ++ "STATUS_GRAPHICS_LEADLINK_START_DEFERRED", ++ "STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY", ++ "STATUS_GRAPHICS_START_DEFERRED", ++ "STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS", ++ "STATUS_NDIS_INDICATION_REQUIRED", ++ "STATUS_PCP_UNSUPPORTED_PSS_SALT", ++ "STATUS_GUARD_PAGE_VIOLATION", ++ "STATUS_DATATYPE_MISALIGNMENT", ++ "STATUS_BREAKPOINT", ++ "STATUS_SINGLE_STEP", ++ "STATUS_BUFFER_OVERFLOW", ++ "STATUS_NO_MORE_FILES", ++ "STATUS_WAKE_SYSTEM_DEBUGGER", ++ "STATUS_HANDLES_CLOSED", ++ "STATUS_NO_INHERITANCE", ++ "STATUS_GUID_SUBSTITUTION_MADE", ++ "STATUS_PARTIAL_COPY", ++ "STATUS_DEVICE_PAPER_EMPTY", ++ "STATUS_DEVICE_POWERED_OFF", ++ "STATUS_DEVICE_OFF_LINE", ++ "STATUS_DEVICE_BUSY", ++ "STATUS_NO_MORE_EAS", ++ "STATUS_INVALID_EA_NAME", ++ "STATUS_EA_LIST_INCONSISTENT", ++ "STATUS_INVALID_EA_FLAG", ++ "STATUS_VERIFY_REQUIRED", ++ "STATUS_EXTRANEOUS_INFORMATION", ++ "STATUS_RXACT_COMMIT_NECESSARY", ++ "STATUS_NO_MORE_ENTRIES", ++ "STATUS_FILEMARK_DETECTED", ++ "STATUS_MEDIA_CHANGED", ++ "STATUS_BUS_RESET", ++ "STATUS_END_OF_MEDIA", ++ "STATUS_BEGINNING_OF_MEDIA", ++ "STATUS_MEDIA_CHECK", ++ "STATUS_SETMARK_DETECTED", ++ "STATUS_NO_DATA_DETECTED", ++ "STATUS_REDIRECTOR_HAS_OPEN_HANDLES", ++ "STATUS_SERVER_HAS_OPEN_HANDLES", ++ "STATUS_ALREADY_DISCONNECTED", ++ "STATUS_LONGJUMP", ++ "STATUS_CLEANER_CARTRIDGE_INSTALLED", ++ "STATUS_PLUGPLAY_QUERY_VETOED", ++ "STATUS_UNWIND_CONSOLIDATE", ++ "STATUS_REGISTRY_HIVE_RECOVERED", ++ "STATUS_DLL_MIGHT_BE_INSECURE", ++ "STATUS_DLL_MIGHT_BE_INCOMPATIBLE", ++ "STATUS_STOPPED_ON_SYMLINK", ++ "STATUS_CANNOT_GRANT_REQUESTED_OPLOCK", ++ "STATUS_NO_ACE_CONDITION", ++ "STATUS_DEVICE_SUPPORT_IN_PROGRESS", ++ "STATUS_DEVICE_POWER_CYCLE_REQUIRED", ++ "STATUS_NO_WORK_DONE", ++ "STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT", ++ "STATUS_DEVICE_REQUIRES_CLEANING", ++ "STATUS_DEVICE_DOOR_OPEN", ++ "STATUS_DATA_LOST_REPAIR", ++ "STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED", ++ "STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH", ++ "STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE", ++ "STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS", ++ "DBG_EXCEPTION_NOT_HANDLED", ++ "STATUS_CLUSTER_NODE_ALREADY_UP", ++ "STATUS_CLUSTER_NODE_ALREADY_DOWN", ++ "STATUS_CLUSTER_NETWORK_ALREADY_ONLINE", ++ "STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE", ++ "STATUS_CLUSTER_NODE_ALREADY_MEMBER", ++ "STATUS_COULD_NOT_RESIZE_LOG", ++ "STATUS_NO_TXF_METADATA", ++ "STATUS_CANT_RECOVER_WITH_HANDLE_OPEN", ++ "STATUS_TXF_METADATA_ALREADY_PRESENT", ++ "STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET", ++ "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED", ++ "STATUS_FLT_BUFFER_TOO_SMALL", ++ "STATUS_FVE_PARTIAL_METADATA", ++ "STATUS_FVE_TRANSIENT_STATE", ++ "STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED", ++ "STATUS_VOLMGR_INCOMPLETE_REGENERATION", ++ "STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION", ++ "STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED", ++ "STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED", ++ "STATUS_QUERY_STORAGE_ERROR", ++ "STATUS_GDI_HANDLE_LEAK", ++ "STATUS_SECUREBOOT_NOT_ENABLED", ++ "STATUS_UNSUCCESSFUL", ++ "STATUS_NOT_IMPLEMENTED", ++ "STATUS_INVALID_INFO_CLASS", ++ "STATUS_INFO_LENGTH_MISMATCH", ++ "STATUS_ACCESS_VIOLATION", ++ "STATUS_IN_PAGE_ERROR", ++ "STATUS_PAGEFILE_QUOTA", ++ "STATUS_INVALID_HANDLE", ++ "STATUS_BAD_INITIAL_STACK", ++ "STATUS_BAD_INITIAL_PC", ++ "STATUS_INVALID_CID", ++ "STATUS_TIMER_NOT_CANCELED", ++ "STATUS_INVALID_PARAMETER", ++ "STATUS_NO_SUCH_DEVICE", ++ "STATUS_NO_SUCH_FILE", ++ "STATUS_INVALID_DEVICE_REQUEST", ++ "STATUS_END_OF_FILE", ++ "STATUS_WRONG_VOLUME", ++ "STATUS_NO_MEDIA_IN_DEVICE", ++ "STATUS_UNRECOGNIZED_MEDIA", ++ "STATUS_NONEXISTENT_SECTOR", ++ "STATUS_MORE_PROCESSING_REQUIRED", ++ "STATUS_NO_MEMORY", ++ "STATUS_CONFLICTING_ADDRESSES", ++ "STATUS_NOT_MAPPED_VIEW", ++ "STATUS_UNABLE_TO_FREE_VM", ++ "STATUS_UNABLE_TO_DELETE_SECTION", ++ "STATUS_INVALID_SYSTEM_SERVICE", ++ "STATUS_ILLEGAL_INSTRUCTION", ++ "STATUS_INVALID_LOCK_SEQUENCE", ++ "STATUS_INVALID_VIEW_SIZE", ++ "STATUS_INVALID_FILE_FOR_SECTION", ++ "STATUS_ALREADY_COMMITTED", ++ "STATUS_ACCESS_DENIED", ++ "STATUS_BUFFER_TOO_SMALL", ++ "STATUS_OBJECT_TYPE_MISMATCH", ++ "STATUS_NONCONTINUABLE_EXCEPTION", ++ "STATUS_INVALID_DISPOSITION", ++ "STATUS_UNWIND", ++ "STATUS_BAD_STACK", ++ "STATUS_INVALID_UNWIND_TARGET", ++ "STATUS_NOT_LOCKED", ++ "STATUS_PARITY_ERROR", ++ "STATUS_UNABLE_TO_DECOMMIT_VM", ++ "STATUS_NOT_COMMITTED", ++ "STATUS_INVALID_PORT_ATTRIBUTES", ++ "STATUS_PORT_MESSAGE_TOO_LONG", ++ "STATUS_INVALID_PARAMETER_MIX", ++ "STATUS_INVALID_QUOTA_LOWER", ++ "STATUS_DISK_CORRUPT_ERROR", ++ "STATUS_OBJECT_NAME_INVALID", ++ "STATUS_OBJECT_NAME_NOT_FOUND", ++ "STATUS_OBJECT_NAME_COLLISION", ++ "STATUS_PORT_DO_NOT_DISTURB", ++ "STATUS_PORT_DISCONNECTED", ++ "STATUS_DEVICE_ALREADY_ATTACHED", ++ "STATUS_OBJECT_PATH_INVALID", ++ "STATUS_OBJECT_PATH_NOT_FOUND", ++ "STATUS_OBJECT_PATH_SYNTAX_BAD", ++ "STATUS_DATA_OVERRUN", ++ "STATUS_DATA_LATE_ERROR", ++ "STATUS_DATA_ERROR", ++ "STATUS_CRC_ERROR", ++ "STATUS_SECTION_TOO_BIG", ++ "STATUS_PORT_CONNECTION_REFUSED", ++ "STATUS_INVALID_PORT_HANDLE", ++ "STATUS_SHARING_VIOLATION", ++ "STATUS_QUOTA_EXCEEDED", ++ "STATUS_INVALID_PAGE_PROTECTION", ++ "STATUS_MUTANT_NOT_OWNED", ++ "STATUS_SEMAPHORE_LIMIT_EXCEEDED", ++ "STATUS_PORT_ALREADY_SET", ++ "STATUS_SECTION_NOT_IMAGE", ++ "STATUS_SUSPEND_COUNT_EXCEEDED", ++ "STATUS_THREAD_IS_TERMINATING", ++ "STATUS_BAD_WORKING_SET_LIMIT", ++ "STATUS_INCOMPATIBLE_FILE_MAP", ++ "STATUS_SECTION_PROTECTION", ++ "STATUS_EAS_NOT_SUPPORTED", ++ "STATUS_EA_TOO_LARGE", ++ "STATUS_NONEXISTENT_EA_ENTRY", ++ "STATUS_NO_EAS_ON_FILE", ++ "STATUS_EA_CORRUPT_ERROR", ++ "STATUS_FILE_LOCK_CONFLICT", ++ "STATUS_LOCK_NOT_GRANTED", ++ "STATUS_DELETE_PENDING", ++ "STATUS_CTL_FILE_NOT_SUPPORTED", ++ "STATUS_UNKNOWN_REVISION", ++ "STATUS_REVISION_MISMATCH", ++ "STATUS_INVALID_OWNER", ++ "STATUS_INVALID_PRIMARY_GROUP", ++ "STATUS_NO_IMPERSONATION_TOKEN", ++ "STATUS_CANT_DISABLE_MANDATORY", ++ "STATUS_NO_LOGON_SERVERS", ++ "STATUS_NO_SUCH_LOGON_SESSION", ++ "STATUS_NO_SUCH_PRIVILEGE", ++ "STATUS_PRIVILEGE_NOT_HELD", ++ "STATUS_INVALID_ACCOUNT_NAME", ++ "STATUS_USER_EXISTS", ++ "STATUS_NO_SUCH_USER", ++ "STATUS_GROUP_EXISTS", ++ "STATUS_NO_SUCH_GROUP", ++ "STATUS_MEMBER_IN_GROUP", ++ "STATUS_MEMBER_NOT_IN_GROUP", ++ "STATUS_LAST_ADMIN", ++ "STATUS_WRONG_PASSWORD", ++ "STATUS_ILL_FORMED_PASSWORD", ++ "STATUS_PASSWORD_RESTRICTION", ++ "STATUS_LOGON_FAILURE", ++ "STATUS_ACCOUNT_RESTRICTION", ++ "STATUS_INVALID_LOGON_HOURS", ++ "STATUS_INVALID_WORKSTATION", ++ "STATUS_PASSWORD_EXPIRED", ++ "STATUS_ACCOUNT_DISABLED", ++ "STATUS_NONE_MAPPED", ++ "STATUS_TOO_MANY_LUIDS_REQUESTED", ++ "STATUS_LUIDS_EXHAUSTED", ++ "STATUS_INVALID_SUB_AUTHORITY", ++ "STATUS_INVALID_ACL", ++ "STATUS_INVALID_SID", ++ "STATUS_INVALID_SECURITY_DESCR", ++ "STATUS_PROCEDURE_NOT_FOUND", ++ "STATUS_INVALID_IMAGE_FORMAT", ++ "STATUS_NO_TOKEN", ++ "STATUS_BAD_INHERITANCE_ACL", ++ "STATUS_RANGE_NOT_LOCKED", ++ "STATUS_DISK_FULL", ++ "STATUS_SERVER_DISABLED", ++ "STATUS_SERVER_NOT_DISABLED", ++ "STATUS_TOO_MANY_GUIDS_REQUESTED", ++ "STATUS_GUIDS_EXHAUSTED", ++ "STATUS_INVALID_ID_AUTHORITY", ++ "STATUS_AGENTS_EXHAUSTED", ++ "STATUS_INVALID_VOLUME_LABEL", ++ "STATUS_SECTION_NOT_EXTENDED", ++ "STATUS_NOT_MAPPED_DATA", ++ "STATUS_RESOURCE_DATA_NOT_FOUND", ++ "STATUS_RESOURCE_TYPE_NOT_FOUND", ++ "STATUS_RESOURCE_NAME_NOT_FOUND", ++ "STATUS_ARRAY_BOUNDS_EXCEEDED", ++ "STATUS_FLOAT_DENORMAL_OPERAND", ++ "STATUS_FLOAT_DIVIDE_BY_ZERO", ++ "STATUS_FLOAT_INEXACT_RESULT", ++ "STATUS_FLOAT_INVALID_OPERATION", ++ "STATUS_FLOAT_OVERFLOW", ++ "STATUS_FLOAT_STACK_CHECK", ++ "STATUS_FLOAT_UNDERFLOW", ++ "STATUS_INTEGER_DIVIDE_BY_ZERO", ++ "STATUS_INTEGER_OVERFLOW", ++ "STATUS_PRIVILEGED_INSTRUCTION", ++ "STATUS_TOO_MANY_PAGING_FILES", ++ "STATUS_FILE_INVALID", ++ "STATUS_ALLOTTED_SPACE_EXCEEDED", ++ "STATUS_INSUFFICIENT_RESOURCES", ++ "STATUS_DFS_EXIT_PATH_FOUND", ++ "STATUS_DEVICE_DATA_ERROR", ++ "STATUS_DEVICE_NOT_CONNECTED", ++ "STATUS_DEVICE_POWER_FAILURE", ++ "STATUS_FREE_VM_NOT_AT_BASE", ++ "STATUS_MEMORY_NOT_ALLOCATED", ++ "STATUS_WORKING_SET_QUOTA", ++ "STATUS_MEDIA_WRITE_PROTECTED", ++ "STATUS_DEVICE_NOT_READY", ++ "STATUS_INVALID_GROUP_ATTRIBUTES", ++ "STATUS_BAD_IMPERSONATION_LEVEL", ++ "STATUS_CANT_OPEN_ANONYMOUS", ++ "STATUS_BAD_VALIDATION_CLASS", ++ "STATUS_BAD_TOKEN_TYPE", ++ "STATUS_BAD_MASTER_BOOT_RECORD", ++ "STATUS_INSTRUCTION_MISALIGNMENT", ++ "STATUS_INSTANCE_NOT_AVAILABLE", ++ "STATUS_PIPE_NOT_AVAILABLE", ++ "STATUS_INVALID_PIPE_STATE", ++ "STATUS_PIPE_BUSY", ++ "STATUS_ILLEGAL_FUNCTION", ++ "STATUS_PIPE_DISCONNECTED", ++ "STATUS_PIPE_CLOSING", ++ "STATUS_PIPE_CONNECTED", ++ "STATUS_PIPE_LISTENING", ++ "STATUS_INVALID_READ_MODE", ++ "STATUS_IO_TIMEOUT", ++ "STATUS_FILE_FORCED_CLOSED", ++ "STATUS_PROFILING_NOT_STARTED", ++ "STATUS_PROFILING_NOT_STOPPED", ++ "STATUS_COULD_NOT_INTERPRET", ++ "STATUS_FILE_IS_A_DIRECTORY", ++ "STATUS_NOT_SUPPORTED", ++ "STATUS_REMOTE_NOT_LISTENING", ++ "STATUS_DUPLICATE_NAME", ++ "STATUS_BAD_NETWORK_PATH", ++ "STATUS_NETWORK_BUSY", ++ "STATUS_DEVICE_DOES_NOT_EXIST", ++ "STATUS_TOO_MANY_COMMANDS", ++ "STATUS_ADAPTER_HARDWARE_ERROR", ++ "STATUS_INVALID_NETWORK_RESPONSE", ++ "STATUS_UNEXPECTED_NETWORK_ERROR", ++ "STATUS_BAD_REMOTE_ADAPTER", ++ "STATUS_PRINT_QUEUE_FULL", ++ "STATUS_NO_SPOOL_SPACE", ++ "STATUS_PRINT_CANCELLED", ++ "STATUS_NETWORK_NAME_DELETED", ++ "STATUS_NETWORK_ACCESS_DENIED", ++ "STATUS_BAD_DEVICE_TYPE", ++ "STATUS_BAD_NETWORK_NAME", ++ "STATUS_TOO_MANY_NAMES", ++ "STATUS_TOO_MANY_SESSIONS", ++ "STATUS_SHARING_PAUSED", ++ "STATUS_REQUEST_NOT_ACCEPTED", ++ "STATUS_REDIRECTOR_PAUSED", ++ "STATUS_NET_WRITE_FAULT", ++ "STATUS_PROFILING_AT_LIMIT", ++ "STATUS_NOT_SAME_DEVICE", ++ "STATUS_FILE_RENAMED", ++ "STATUS_VIRTUAL_CIRCUIT_CLOSED", ++ "STATUS_NO_SECURITY_ON_OBJECT", ++ "STATUS_CANT_WAIT", ++ "STATUS_PIPE_EMPTY", ++ "STATUS_CANT_ACCESS_DOMAIN_INFO", ++ "STATUS_CANT_TERMINATE_SELF", ++ "STATUS_INVALID_SERVER_STATE", ++ "STATUS_INVALID_DOMAIN_STATE", ++ "STATUS_INVALID_DOMAIN_ROLE", ++ "STATUS_NO_SUCH_DOMAIN", ++ "STATUS_DOMAIN_EXISTS", ++ "STATUS_DOMAIN_LIMIT_EXCEEDED", ++ "STATUS_OPLOCK_NOT_GRANTED", ++ "STATUS_INVALID_OPLOCK_PROTOCOL", ++ "STATUS_INTERNAL_DB_CORRUPTION", ++ "STATUS_INTERNAL_ERROR", ++ "STATUS_GENERIC_NOT_MAPPED", ++ "STATUS_BAD_DESCRIPTOR_FORMAT", ++ "STATUS_INVALID_USER_BUFFER", ++ "STATUS_UNEXPECTED_IO_ERROR", ++ "STATUS_UNEXPECTED_MM_CREATE_ERR", ++ "STATUS_UNEXPECTED_MM_MAP_ERROR", ++ "STATUS_UNEXPECTED_MM_EXTEND_ERR", ++ "STATUS_NOT_LOGON_PROCESS", ++ "STATUS_LOGON_SESSION_EXISTS", ++ "STATUS_INVALID_PARAMETER_1", ++ "STATUS_INVALID_PARAMETER_2", ++ "STATUS_INVALID_PARAMETER_3", ++ "STATUS_INVALID_PARAMETER_4", ++ "STATUS_INVALID_PARAMETER_5", ++ "STATUS_INVALID_PARAMETER_6", ++ "STATUS_INVALID_PARAMETER_7", ++ "STATUS_INVALID_PARAMETER_8", ++ "STATUS_INVALID_PARAMETER_9", ++ "STATUS_INVALID_PARAMETER_10", ++ "STATUS_INVALID_PARAMETER_11", ++ "STATUS_INVALID_PARAMETER_12", ++ "STATUS_REDIRECTOR_NOT_STARTED", ++ "STATUS_REDIRECTOR_STARTED", ++ "STATUS_STACK_OVERFLOW", ++ "STATUS_NO_SUCH_PACKAGE", ++ "STATUS_BAD_FUNCTION_TABLE", ++ "STATUS_VARIABLE_NOT_FOUND", ++ "STATUS_DIRECTORY_NOT_EMPTY", ++ "STATUS_FILE_CORRUPT_ERROR", ++ "STATUS_NOT_A_DIRECTORY", ++ "STATUS_BAD_LOGON_SESSION_STATE", ++ "STATUS_LOGON_SESSION_COLLISION", ++ "STATUS_NAME_TOO_LONG", ++ "STATUS_FILES_OPEN", ++ "STATUS_CONNECTION_IN_USE", ++ "STATUS_MESSAGE_NOT_FOUND", ++ "STATUS_PROCESS_IS_TERMINATING", ++ "STATUS_INVALID_LOGON_TYPE", ++ "STATUS_NO_GUID_TRANSLATION", ++ "STATUS_CANNOT_IMPERSONATE", ++ "STATUS_IMAGE_ALREADY_LOADED", ++ "STATUS_ABIOS_NOT_PRESENT", ++ "STATUS_ABIOS_LID_NOT_EXIST", ++ "STATUS_ABIOS_LID_ALREADY_OWNED", ++ "STATUS_ABIOS_NOT_LID_OWNER", ++ "STATUS_ABIOS_INVALID_COMMAND", ++ "STATUS_ABIOS_INVALID_LID", ++ "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", ++ "STATUS_ABIOS_INVALID_SELECTOR", ++ "STATUS_NO_LDT", ++ "STATUS_INVALID_LDT_SIZE", ++ "STATUS_INVALID_LDT_OFFSET", ++ "STATUS_INVALID_LDT_DESCRIPTOR", ++ "STATUS_INVALID_IMAGE_NE_FORMAT", ++ "STATUS_RXACT_INVALID_STATE", ++ "STATUS_RXACT_COMMIT_FAILURE", ++ "STATUS_MAPPED_FILE_SIZE_ZERO", ++ "STATUS_TOO_MANY_OPENED_FILES", ++ "STATUS_CANCELLED", ++ "STATUS_CANNOT_DELETE", ++ "STATUS_INVALID_COMPUTER_NAME", ++ "STATUS_FILE_DELETED", ++ "STATUS_SPECIAL_ACCOUNT", ++ "STATUS_SPECIAL_GROUP", ++ "STATUS_SPECIAL_USER", ++ "STATUS_MEMBERS_PRIMARY_GROUP", ++ "STATUS_FILE_CLOSED", ++ "STATUS_TOO_MANY_THREADS", ++ "STATUS_THREAD_NOT_IN_PROCESS", ++ "STATUS_TOKEN_ALREADY_IN_USE", ++ "STATUS_PAGEFILE_QUOTA_EXCEEDED", ++ "STATUS_COMMITMENT_LIMIT", ++ "STATUS_INVALID_IMAGE_LE_FORMAT", ++ "STATUS_INVALID_IMAGE_NOT_MZ", ++ "STATUS_INVALID_IMAGE_PROTECT", ++ "STATUS_INVALID_IMAGE_WIN_16", ++ "STATUS_LOGON_SERVER_CONFLICT", ++ "STATUS_TIME_DIFFERENCE_AT_DC", ++ "STATUS_SYNCHRONIZATION_REQUIRED", ++ "STATUS_DLL_NOT_FOUND", ++ "STATUS_OPEN_FAILED", ++ "STATUS_IO_PRIVILEGE_FAILED", ++ "STATUS_ORDINAL_NOT_FOUND", ++ "STATUS_ENTRYPOINT_NOT_FOUND", ++ "STATUS_CONTROL_C_EXIT", ++ "STATUS_LOCAL_DISCONNECT", ++ "STATUS_REMOTE_DISCONNECT", ++ "STATUS_REMOTE_RESOURCES", ++ "STATUS_LINK_FAILED", ++ "STATUS_LINK_TIMEOUT", ++ "STATUS_INVALID_CONNECTION", ++ "STATUS_INVALID_ADDRESS", ++ "STATUS_DLL_INIT_FAILED", ++ "STATUS_MISSING_SYSTEMFILE", ++ "STATUS_UNHANDLED_EXCEPTION", ++ "STATUS_APP_INIT_FAILURE", ++ "STATUS_PAGEFILE_CREATE_FAILED", ++ "STATUS_NO_PAGEFILE", ++ "STATUS_INVALID_LEVEL", ++ "STATUS_WRONG_PASSWORD_CORE", ++ "STATUS_ILLEGAL_FLOAT_CONTEXT", ++ "STATUS_PIPE_BROKEN", ++ "STATUS_REGISTRY_CORRUPT", ++ "STATUS_REGISTRY_IO_FAILED", ++ "STATUS_NO_EVENT_PAIR", ++ "STATUS_UNRECOGNIZED_VOLUME", ++ "STATUS_SERIAL_NO_DEVICE_INITED", ++ "STATUS_NO_SUCH_ALIAS", ++ "STATUS_MEMBER_NOT_IN_ALIAS", ++ "STATUS_MEMBER_IN_ALIAS", ++ "STATUS_ALIAS_EXISTS", ++ "STATUS_LOGON_NOT_GRANTED", ++ "STATUS_TOO_MANY_SECRETS", ++ "STATUS_SECRET_TOO_LONG", ++ "STATUS_INTERNAL_DB_ERROR", ++ "STATUS_FULLSCREEN_MODE", ++ "STATUS_TOO_MANY_CONTEXT_IDS", ++ "STATUS_LOGON_TYPE_NOT_GRANTED", ++ "STATUS_NOT_REGISTRY_FILE", ++ "STATUS_NT_CROSS_ENCRYPTION_REQUIRED", ++ "STATUS_DOMAIN_CTRLR_CONFIG_ERROR", ++ "STATUS_FT_MISSING_MEMBER", ++ "STATUS_ILL_FORMED_SERVICE_ENTRY", ++ "STATUS_ILLEGAL_CHARACTER", ++ "STATUS_UNMAPPABLE_CHARACTER", ++ "STATUS_UNDEFINED_CHARACTER", ++ "STATUS_FLOPPY_VOLUME", ++ "STATUS_FLOPPY_ID_MARK_NOT_FOUND", ++ "STATUS_FLOPPY_WRONG_CYLINDER", ++ "STATUS_FLOPPY_UNKNOWN_ERROR", ++ "STATUS_FLOPPY_BAD_REGISTERS", ++ "STATUS_DISK_RECALIBRATE_FAILED", ++ "STATUS_DISK_OPERATION_FAILED", ++ "STATUS_DISK_RESET_FAILED", ++ "STATUS_SHARED_IRQ_BUSY", ++ "STATUS_FT_ORPHANING", ++ "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT", ++ "STATUS_PARTITION_FAILURE", ++ "STATUS_INVALID_BLOCK_LENGTH", ++ "STATUS_DEVICE_NOT_PARTITIONED", ++ "STATUS_UNABLE_TO_LOCK_MEDIA", ++ "STATUS_UNABLE_TO_UNLOAD_MEDIA", ++ "STATUS_EOM_OVERFLOW", ++ "STATUS_NO_MEDIA", ++ "STATUS_NO_SUCH_MEMBER", ++ "STATUS_INVALID_MEMBER", ++ "STATUS_KEY_DELETED", ++ "STATUS_NO_LOG_SPACE", ++ "STATUS_TOO_MANY_SIDS", ++ "STATUS_LM_CROSS_ENCRYPTION_REQUIRED", ++ "STATUS_KEY_HAS_CHILDREN", ++ "STATUS_CHILD_MUST_BE_VOLATILE", ++ "STATUS_DEVICE_CONFIGURATION_ERROR", ++ "STATUS_DRIVER_INTERNAL_ERROR", ++ "STATUS_INVALID_DEVICE_STATE", ++ "STATUS_IO_DEVICE_ERROR", ++ "STATUS_DEVICE_PROTOCOL_ERROR", ++ "STATUS_BACKUP_CONTROLLER", ++ "STATUS_LOG_FILE_FULL", ++ "STATUS_TOO_LATE", ++ "STATUS_NO_TRUST_LSA_SECRET", ++ "STATUS_NO_TRUST_SAM_ACCOUNT", ++ "STATUS_TRUSTED_DOMAIN_FAILURE", ++ "STATUS_TRUSTED_RELATIONSHIP_FAILURE", ++ "STATUS_EVENTLOG_FILE_CORRUPT", ++ "STATUS_EVENTLOG_CANT_START", ++ "STATUS_TRUST_FAILURE", ++ "STATUS_MUTANT_LIMIT_EXCEEDED", ++ "STATUS_NETLOGON_NOT_STARTED", ++ "STATUS_ACCOUNT_EXPIRED", ++ "STATUS_POSSIBLE_DEADLOCK", ++ "STATUS_NETWORK_CREDENTIAL_CONFLICT", ++ "STATUS_REMOTE_SESSION_LIMIT", ++ "STATUS_EVENTLOG_FILE_CHANGED", ++ "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", ++ "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", ++ "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", ++ "STATUS_DOMAIN_TRUST_INCONSISTENT", ++ "STATUS_FS_DRIVER_REQUIRED", ++ "STATUS_IMAGE_ALREADY_LOADED_AS_DLL", ++ "STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING", ++ "STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME", ++ "STATUS_SECURITY_STREAM_IS_INCONSISTENT", ++ "STATUS_INVALID_LOCK_RANGE", ++ "STATUS_INVALID_ACE_CONDITION", ++ "STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT", ++ "STATUS_NOTIFICATION_GUID_ALREADY_DEFINED", ++ "STATUS_INVALID_EXCEPTION_HANDLER", ++ "STATUS_DUPLICATE_PRIVILEGES", ++ "STATUS_NOT_ALLOWED_ON_SYSTEM_FILE", ++ "STATUS_REPAIR_NEEDED", ++ "STATUS_QUOTA_NOT_ENABLED", ++ "STATUS_NO_APPLICATION_PACKAGE", ++ "STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS", ++ "STATUS_NOT_SAME_OBJECT", ++ "STATUS_FATAL_MEMORY_EXHAUSTION", ++ "STATUS_ERROR_PROCESS_NOT_IN_JOB", ++ "STATUS_CPU_SET_INVALID", ++ "STATUS_IO_DEVICE_INVALID_DATA", ++ "STATUS_IO_UNALIGNED_WRITE", ++ "STATUS_CONTROL_STACK_VIOLATION", ++ "STATUS_NETWORK_OPEN_RESTRICTION", ++ "STATUS_NO_USER_SESSION_KEY", ++ "STATUS_USER_SESSION_DELETED", ++ "STATUS_RESOURCE_LANG_NOT_FOUND", ++ "STATUS_INSUFF_SERVER_RESOURCES", ++ "STATUS_INVALID_BUFFER_SIZE", ++ "STATUS_INVALID_ADDRESS_COMPONENT", ++ "STATUS_INVALID_ADDRESS_WILDCARD", ++ "STATUS_TOO_MANY_ADDRESSES", ++ "STATUS_ADDRESS_ALREADY_EXISTS", ++ "STATUS_ADDRESS_CLOSED", ++ "STATUS_CONNECTION_DISCONNECTED", ++ "STATUS_CONNECTION_RESET", ++ "STATUS_TOO_MANY_NODES", ++ "STATUS_TRANSACTION_ABORTED", ++ "STATUS_TRANSACTION_TIMED_OUT", ++ "STATUS_TRANSACTION_NO_RELEASE", ++ "STATUS_TRANSACTION_NO_MATCH", ++ "STATUS_TRANSACTION_RESPONDED", ++ "STATUS_TRANSACTION_INVALID_ID", ++ "STATUS_TRANSACTION_INVALID_TYPE", ++ "STATUS_NOT_SERVER_SESSION", ++ "STATUS_NOT_CLIENT_SESSION", ++ "STATUS_CANNOT_LOAD_REGISTRY_FILE", ++ "STATUS_DEBUG_ATTACH_FAILED", ++ "STATUS_SYSTEM_PROCESS_TERMINATED", ++ "STATUS_DATA_NOT_ACCEPTED", ++ "STATUS_NO_BROWSER_SERVERS_FOUND", ++ "STATUS_VDM_HARD_ERROR", ++ "STATUS_DRIVER_CANCEL_TIMEOUT", ++ "STATUS_REPLY_MESSAGE_MISMATCH", ++ "STATUS_MAPPED_ALIGNMENT", ++ "STATUS_IMAGE_CHECKSUM_MISMATCH", ++ "STATUS_LOST_WRITEBEHIND_DATA", ++ "STATUS_CLIENT_SERVER_PARAMETERS_INVALID", ++ "STATUS_PASSWORD_MUST_CHANGE", ++ "STATUS_NOT_FOUND", ++ "STATUS_NOT_TINY_STREAM", ++ "STATUS_RECOVERY_FAILURE", ++ "STATUS_STACK_OVERFLOW_READ", ++ "STATUS_FAIL_CHECK", ++ "STATUS_DUPLICATE_OBJECTID", ++ "STATUS_OBJECTID_EXISTS", ++ "STATUS_CONVERT_TO_LARGE", ++ "STATUS_RETRY", ++ "STATUS_FOUND_OUT_OF_SCOPE", ++ "STATUS_ALLOCATE_BUCKET", ++ "STATUS_PROPSET_NOT_FOUND", ++ "STATUS_MARSHALL_OVERFLOW", ++ "STATUS_INVALID_VARIANT", ++ "STATUS_DOMAIN_CONTROLLER_NOT_FOUND", ++ "STATUS_ACCOUNT_LOCKED_OUT", ++ "STATUS_HANDLE_NOT_CLOSABLE", ++ "STATUS_CONNECTION_REFUSED", ++ "STATUS_GRACEFUL_DISCONNECT", ++ "STATUS_ADDRESS_ALREADY_ASSOCIATED", ++ "STATUS_ADDRESS_NOT_ASSOCIATED", ++ "STATUS_CONNECTION_INVALID", ++ "STATUS_CONNECTION_ACTIVE", ++ "STATUS_NETWORK_UNREACHABLE", ++ "STATUS_HOST_UNREACHABLE", ++ "STATUS_PROTOCOL_UNREACHABLE", ++ "STATUS_PORT_UNREACHABLE", ++ "STATUS_REQUEST_ABORTED", ++ "STATUS_CONNECTION_ABORTED", ++ "STATUS_BAD_COMPRESSION_BUFFER", ++ "STATUS_USER_MAPPED_FILE", ++ "STATUS_AUDIT_FAILED", ++ "STATUS_TIMER_RESOLUTION_NOT_SET", ++ "STATUS_CONNECTION_COUNT_LIMIT", ++ "STATUS_LOGIN_TIME_RESTRICTION", ++ "STATUS_LOGIN_WKSTA_RESTRICTION", ++ "STATUS_IMAGE_MP_UP_MISMATCH", ++ "STATUS_INSUFFICIENT_LOGON_INFO", ++ "STATUS_BAD_DLL_ENTRYPOINT", ++ "STATUS_BAD_SERVICE_ENTRYPOINT", ++ "STATUS_LPC_REPLY_LOST", ++ "STATUS_IP_ADDRESS_CONFLICT1", ++ "STATUS_IP_ADDRESS_CONFLICT2", ++ "STATUS_REGISTRY_QUOTA_LIMIT", ++ "STATUS_PATH_NOT_COVERED", ++ "STATUS_NO_CALLBACK_ACTIVE", ++ "STATUS_LICENSE_QUOTA_EXCEEDED", ++ "STATUS_PWD_TOO_SHORT", ++ "STATUS_PWD_TOO_RECENT", ++ "STATUS_PWD_HISTORY_CONFLICT", ++ "STATUS_PLUGPLAY_NO_DEVICE", ++ "STATUS_UNSUPPORTED_COMPRESSION", ++ "STATUS_INVALID_HW_PROFILE", ++ "STATUS_INVALID_PLUGPLAY_DEVICE_PATH", ++ "STATUS_DRIVER_ORDINAL_NOT_FOUND", ++ "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", ++ "STATUS_RESOURCE_NOT_OWNED", ++ "STATUS_TOO_MANY_LINKS", ++ "STATUS_QUOTA_LIST_INCONSISTENT", ++ "STATUS_FILE_IS_OFFLINE", ++ "STATUS_EVALUATION_EXPIRATION", ++ "STATUS_ILLEGAL_DLL_RELOCATION", ++ "STATUS_LICENSE_VIOLATION", ++ "STATUS_DLL_INIT_FAILED_LOGOFF", ++ "STATUS_DRIVER_UNABLE_TO_LOAD", ++ "STATUS_DFS_UNAVAILABLE", ++ "STATUS_VOLUME_DISMOUNTED", ++ "STATUS_WX86_INTERNAL_ERROR", ++ "STATUS_WX86_FLOAT_STACK_CHECK", ++ "STATUS_VALIDATE_CONTINUE", ++ "STATUS_NO_MATCH", ++ "STATUS_NO_MORE_MATCHES", ++ "STATUS_NOT_A_REPARSE_POINT", ++ "STATUS_IO_REPARSE_TAG_INVALID", ++ "STATUS_IO_REPARSE_TAG_MISMATCH", ++ "STATUS_IO_REPARSE_DATA_INVALID", ++ "STATUS_IO_REPARSE_TAG_NOT_HANDLED", ++ "STATUS_PWD_TOO_LONG", ++ "STATUS_STOWED_EXCEPTION", ++ "STATUS_CONTEXT_STOWED_EXCEPTION", ++ "STATUS_REPARSE_POINT_NOT_RESOLVED", ++ "STATUS_DIRECTORY_IS_A_REPARSE_POINT", ++ "STATUS_RANGE_LIST_CONFLICT", ++ "STATUS_SOURCE_ELEMENT_EMPTY", ++ "STATUS_DESTINATION_ELEMENT_FULL", ++ "STATUS_ILLEGAL_ELEMENT_ADDRESS", ++ "STATUS_MAGAZINE_NOT_PRESENT", ++ "STATUS_REINITIALIZATION_NEEDED", ++ "STATUS_ENCRYPTION_FAILED", ++ "STATUS_DECRYPTION_FAILED", ++ "STATUS_RANGE_NOT_FOUND", ++ "STATUS_NO_RECOVERY_POLICY", ++ "STATUS_NO_EFS", ++ "STATUS_WRONG_EFS", ++ "STATUS_NO_USER_KEYS", ++ "STATUS_FILE_NOT_ENCRYPTED", ++ "STATUS_NOT_EXPORT_FORMAT", ++ "STATUS_FILE_ENCRYPTED", ++ "STATUS_WMI_GUID_NOT_FOUND", ++ "STATUS_WMI_INSTANCE_NOT_FOUND", ++ "STATUS_WMI_ITEMID_NOT_FOUND", ++ "STATUS_WMI_TRY_AGAIN", ++ "STATUS_SHARED_POLICY", ++ "STATUS_POLICY_OBJECT_NOT_FOUND", ++ "STATUS_POLICY_ONLY_IN_DS", ++ "STATUS_VOLUME_NOT_UPGRADED", ++ "STATUS_REMOTE_STORAGE_NOT_ACTIVE", ++ "STATUS_REMOTE_STORAGE_MEDIA_ERROR", ++ "STATUS_NO_TRACKING_SERVICE", ++ "STATUS_SERVER_SID_MISMATCH", ++ "STATUS_DS_NO_ATTRIBUTE_OR_VALUE", ++ "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX", ++ "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED", ++ "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS", ++ "STATUS_DS_BUSY", ++ "STATUS_DS_UNAVAILABLE", ++ "STATUS_DS_NO_RIDS_ALLOCATED", ++ "STATUS_DS_NO_MORE_RIDS", ++ "STATUS_DS_INCORRECT_ROLE_OWNER", ++ "STATUS_DS_RIDMGR_INIT_ERROR", ++ "STATUS_DS_OBJ_CLASS_VIOLATION", ++ "STATUS_DS_CANT_ON_NON_LEAF", ++ "STATUS_DS_CANT_ON_RDN", ++ "STATUS_DS_CANT_MOD_OBJ_CLASS", ++ "STATUS_DS_CROSS_DOM_MOVE_FAILED", ++ "STATUS_DS_GC_NOT_AVAILABLE", ++ "STATUS_DIRECTORY_SERVICE_REQUIRED", ++ "STATUS_REPARSE_ATTRIBUTE_CONFLICT", ++ "STATUS_CANT_ENABLE_DENY_ONLY", ++ "STATUS_FLOAT_MULTIPLE_FAULTS", ++ "STATUS_FLOAT_MULTIPLE_TRAPS", ++ "STATUS_DEVICE_REMOVED", ++ "STATUS_JOURNAL_DELETE_IN_PROGRESS", ++ "STATUS_JOURNAL_NOT_ACTIVE", ++ "STATUS_NOINTERFACE", ++ "STATUS_DS_RIDMGR_DISABLED", ++ "STATUS_DS_ADMIN_LIMIT_EXCEEDED", ++ "STATUS_DRIVER_FAILED_SLEEP", ++ "STATUS_MUTUAL_AUTHENTICATION_FAILED", ++ "STATUS_CORRUPT_SYSTEM_FILE", ++ "STATUS_DATATYPE_MISALIGNMENT_ERROR", ++ "STATUS_WMI_READ_ONLY", ++ "STATUS_WMI_SET_FAILURE", ++ "STATUS_COMMITMENT_MINIMUM", ++ "STATUS_REG_NAT_CONSUMPTION", ++ "STATUS_TRANSPORT_FULL", ++ "STATUS_DS_SAM_INIT_FAILURE", ++ "STATUS_ONLY_IF_CONNECTED", ++ "STATUS_DS_SENSITIVE_GROUP_VIOLATION", ++ "STATUS_PNP_RESTART_ENUMERATION", ++ "STATUS_JOURNAL_ENTRY_DELETED", ++ "STATUS_DS_CANT_MOD_PRIMARYGROUPID", ++ "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE", ++ "STATUS_PNP_REBOOT_REQUIRED", ++ "STATUS_POWER_STATE_INVALID", ++ "STATUS_DS_INVALID_GROUP_TYPE", ++ "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN", ++ "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN", ++ "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER", ++ "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER", ++ "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER", ++ "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER", ++ "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER", ++ "STATUS_DS_HAVE_PRIMARY_MEMBERS", ++ "STATUS_WMI_NOT_SUPPORTED", ++ "STATUS_INSUFFICIENT_POWER", ++ "STATUS_SAM_NEED_BOOTKEY_PASSWORD", ++ "STATUS_SAM_NEED_BOOTKEY_FLOPPY", ++ "STATUS_DS_CANT_START", ++ "STATUS_DS_INIT_FAILURE", ++ "STATUS_SAM_INIT_FAILURE", ++ "STATUS_DS_GC_REQUIRED", ++ "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY", ++ "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS", ++ "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED", ++ "STATUS_MULTIPLE_FAULT_VIOLATION", ++ "STATUS_CURRENT_DOMAIN_NOT_ALLOWED", ++ "STATUS_CANNOT_MAKE", ++ "STATUS_SYSTEM_SHUTDOWN", ++ "STATUS_DS_INIT_FAILURE_CONSOLE", ++ "STATUS_DS_SAM_INIT_FAILURE_CONSOLE", ++ "STATUS_UNFINISHED_CONTEXT_DELETED", ++ "STATUS_NO_TGT_REPLY", ++ "STATUS_OBJECTID_NOT_FOUND", ++ "STATUS_NO_IP_ADDRESSES", ++ "STATUS_WRONG_CREDENTIAL_HANDLE", ++ "STATUS_CRYPTO_SYSTEM_INVALID", ++ "STATUS_MAX_REFERRALS_EXCEEDED", ++ "STATUS_MUST_BE_KDC", ++ "STATUS_STRONG_CRYPTO_NOT_SUPPORTED", ++ "STATUS_TOO_MANY_PRINCIPALS", ++ "STATUS_NO_PA_DATA", ++ "STATUS_PKINIT_NAME_MISMATCH", ++ "STATUS_SMARTCARD_LOGON_REQUIRED", ++ "STATUS_KDC_INVALID_REQUEST", ++ "STATUS_KDC_UNABLE_TO_REFER", ++ "STATUS_KDC_UNKNOWN_ETYPE", ++ "STATUS_SHUTDOWN_IN_PROGRESS", ++ "STATUS_SERVER_SHUTDOWN_IN_PROGRESS", ++ "STATUS_NOT_SUPPORTED_ON_SBS", ++ "STATUS_WMI_GUID_DISCONNECTED", ++ "STATUS_WMI_ALREADY_DISABLED", ++ "STATUS_WMI_ALREADY_ENABLED", ++ "STATUS_MFT_TOO_FRAGMENTED", ++ "STATUS_COPY_PROTECTION_FAILURE", ++ "STATUS_CSS_AUTHENTICATION_FAILURE", ++ "STATUS_CSS_KEY_NOT_PRESENT", ++ "STATUS_CSS_KEY_NOT_ESTABLISHED", ++ "STATUS_CSS_SCRAMBLED_SECTOR", ++ "STATUS_CSS_REGION_MISMATCH", ++ "STATUS_CSS_RESETS_EXHAUSTED", ++ "STATUS_PASSWORD_CHANGE_REQUIRED", ++ "STATUS_LOST_MODE_LOGON_RESTRICTION", ++ "STATUS_PKINIT_FAILURE", ++ "STATUS_SMARTCARD_SUBSYSTEM_FAILURE", ++ "STATUS_NO_KERB_KEY", ++ "STATUS_HOST_DOWN", ++ "STATUS_UNSUPPORTED_PREAUTH", ++ "STATUS_EFS_ALG_BLOB_TOO_BIG", ++ "STATUS_PORT_NOT_SET", ++ "STATUS_DEBUGGER_INACTIVE", ++ "STATUS_DS_VERSION_CHECK_FAILURE", ++ "STATUS_AUDITING_DISABLED", ++ "STATUS_PRENT4_MACHINE_ACCOUNT", ++ "STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER", ++ "STATUS_INVALID_IMAGE_WIN_32", ++ "STATUS_INVALID_IMAGE_WIN_64", ++ "STATUS_BAD_BINDINGS", ++ "STATUS_NETWORK_SESSION_EXPIRED", ++ "STATUS_APPHELP_BLOCK", ++ "STATUS_ALL_SIDS_FILTERED", ++ "STATUS_NOT_SAFE_MODE_DRIVER", ++ "STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT", ++ "STATUS_ACCESS_DISABLED_BY_POLICY_PATH", ++ "STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER", ++ "STATUS_ACCESS_DISABLED_BY_POLICY_OTHER", ++ "STATUS_FAILED_DRIVER_ENTRY", ++ "STATUS_DEVICE_ENUMERATION_ERROR", ++ "STATUS_MOUNT_POINT_NOT_RESOLVED", ++ "STATUS_INVALID_DEVICE_OBJECT_PARAMETER", ++ "STATUS_MCA_OCCURED", ++ "STATUS_DRIVER_BLOCKED_CRITICAL", ++ "STATUS_DRIVER_BLOCKED", ++ "STATUS_DRIVER_DATABASE_ERROR", ++ "STATUS_SYSTEM_HIVE_TOO_LARGE", ++ "STATUS_INVALID_IMPORT_OF_NON_DLL", ++ "STATUS_NO_SECRETS", ++ "STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY", ++ "STATUS_FAILED_STACK_SWITCH", ++ "STATUS_HEAP_CORRUPTION", ++ "STATUS_SMARTCARD_WRONG_PIN", ++ "STATUS_SMARTCARD_CARD_BLOCKED", ++ "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED", ++ "STATUS_SMARTCARD_NO_CARD", ++ "STATUS_SMARTCARD_NO_KEY_CONTAINER", ++ "STATUS_SMARTCARD_NO_CERTIFICATE", ++ "STATUS_SMARTCARD_NO_KEYSET", ++ "STATUS_SMARTCARD_IO_ERROR", ++ "STATUS_DOWNGRADE_DETECTED", ++ "STATUS_SMARTCARD_CERT_REVOKED", ++ "STATUS_ISSUING_CA_UNTRUSTED", ++ "STATUS_REVOCATION_OFFLINE_C", ++ "STATUS_PKINIT_CLIENT_FAILURE", ++ "STATUS_SMARTCARD_CERT_EXPIRED", ++ "STATUS_DRIVER_FAILED_PRIOR_UNLOAD", ++ "STATUS_SMARTCARD_SILENT_CONTEXT", ++ "STATUS_PER_USER_TRUST_QUOTA_EXCEEDED", ++ "STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED", ++ "STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED", ++ "STATUS_DS_NAME_NOT_UNIQUE", ++ "STATUS_DS_DUPLICATE_ID_FOUND", ++ "STATUS_DS_GROUP_CONVERSION_ERROR", ++ "STATUS_VOLSNAP_PREPARE_HIBERNATE", ++ "STATUS_USER2USER_REQUIRED", ++ "STATUS_STACK_BUFFER_OVERRUN", ++ "STATUS_NO_S4U_PROT_SUPPORT", ++ "STATUS_CROSSREALM_DELEGATION_FAILURE", ++ "STATUS_REVOCATION_OFFLINE_KDC", ++ "STATUS_ISSUING_CA_UNTRUSTED_KDC", ++ "STATUS_KDC_CERT_EXPIRED", ++ "STATUS_KDC_CERT_REVOKED", ++ "STATUS_PARAMETER_QUOTA_EXCEEDED", ++ "STATUS_HIBERNATION_FAILURE", ++ "STATUS_DELAY_LOAD_FAILED", ++ "STATUS_AUTHENTICATION_FIREWALL_FAILED", ++ "STATUS_VDM_DISALLOWED", ++ "STATUS_HUNG_DISPLAY_DRIVER_THREAD", ++ "STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE", ++ "STATUS_INVALID_CRUNTIME_PARAMETER", ++ "STATUS_NTLM_BLOCKED", ++ "STATUS_DS_SRC_SID_EXISTS_IN_FOREST", ++ "STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST", ++ "STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST", ++ "STATUS_INVALID_USER_PRINCIPAL_NAME", ++ "STATUS_FATAL_USER_CALLBACK_EXCEPTION", ++ "STATUS_ASSERTION_FAILURE", ++ "STATUS_VERIFIER_STOP", ++ "STATUS_CALLBACK_POP_STACK", ++ "STATUS_INCOMPATIBLE_DRIVER_BLOCKED", ++ "STATUS_HIVE_UNLOADED", ++ "STATUS_COMPRESSION_DISABLED", ++ "STATUS_FILE_SYSTEM_LIMITATION", ++ "STATUS_INVALID_IMAGE_HASH", ++ "STATUS_NOT_CAPABLE", ++ "STATUS_REQUEST_OUT_OF_SEQUENCE", ++ "STATUS_IMPLEMENTATION_LIMIT", ++ "STATUS_ELEVATION_REQUIRED", ++ "STATUS_NO_SECURITY_CONTEXT", ++ "STATUS_PKU2U_CERT_FAILURE", ++ "STATUS_BEYOND_VDL", ++ "STATUS_ENCOUNTERED_WRITE_IN_PROGRESS", ++ "STATUS_PTE_CHANGED", ++ "STATUS_PURGE_FAILED", ++ "STATUS_CRED_REQUIRES_CONFIRMATION", ++ "STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE", ++ "STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER", ++ "STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE", ++ "STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE", ++ "STATUS_CS_ENCRYPTION_FILE_NOT_CSE", ++ "STATUS_INVALID_LABEL", ++ "STATUS_DRIVER_PROCESS_TERMINATED", ++ "STATUS_AMBIGUOUS_SYSTEM_DEVICE", ++ "STATUS_SYSTEM_DEVICE_NOT_FOUND", ++ "STATUS_RESTART_BOOT_APPLICATION", ++ "STATUS_INSUFFICIENT_NVRAM_RESOURCES", ++ "STATUS_INVALID_SESSION", ++ "STATUS_THREAD_ALREADY_IN_SESSION", ++ "STATUS_THREAD_NOT_IN_SESSION", ++ "STATUS_INVALID_WEIGHT", ++ "STATUS_REQUEST_PAUSED", ++ "STATUS_NO_RANGES_PROCESSED", ++ "STATUS_DISK_RESOURCES_EXHAUSTED", ++ "STATUS_NEEDS_REMEDIATION", ++ "STATUS_DEVICE_FEATURE_NOT_SUPPORTED", ++ "STATUS_DEVICE_UNREACHABLE", ++ "STATUS_INVALID_TOKEN", ++ "STATUS_SERVER_UNAVAILABLE", ++ "STATUS_FILE_NOT_AVAILABLE", ++ "STATUS_DEVICE_INSUFFICIENT_RESOURCES", ++ "STATUS_PACKAGE_UPDATING", ++ "STATUS_NOT_READ_FROM_COPY", ++ "STATUS_FT_WRITE_FAILURE", ++ "STATUS_FT_DI_SCAN_REQUIRED", ++ "STATUS_OBJECT_NOT_EXTERNALLY_BACKED", ++ "STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN", ++ "STATUS_COMPRESSION_NOT_BENEFICIAL", ++ "STATUS_DATA_CHECKSUM_ERROR", ++ "STATUS_INTERMIXED_KERNEL_EA_OPERATION", ++ "STATUS_TRIM_READ_ZERO_NOT_SUPPORTED", ++ "STATUS_TOO_MANY_SEGMENT_DESCRIPTORS", ++ "STATUS_INVALID_OFFSET_ALIGNMENT", ++ "STATUS_INVALID_FIELD_IN_PARAMETER_LIST", ++ "STATUS_OPERATION_IN_PROGRESS", ++ "STATUS_INVALID_INITIATOR_TARGET_PATH", ++ "STATUS_SCRUB_DATA_DISABLED", ++ "STATUS_NOT_REDUNDANT_STORAGE", ++ "STATUS_RESIDENT_FILE_NOT_SUPPORTED", ++ "STATUS_COMPRESSED_FILE_NOT_SUPPORTED", ++ "STATUS_DIRECTORY_NOT_SUPPORTED", ++ "STATUS_IO_OPERATION_TIMEOUT", ++ "STATUS_SYSTEM_NEEDS_REMEDIATION", ++ "STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN", ++ "STATUS_SHARE_UNAVAILABLE", ++ "STATUS_APISET_NOT_HOSTED", ++ "STATUS_APISET_NOT_PRESENT", ++ "STATUS_DEVICE_HARDWARE_ERROR", ++ "STATUS_FIRMWARE_SLOT_INVALID", ++ "STATUS_FIRMWARE_IMAGE_INVALID", ++ "STATUS_STORAGE_TOPOLOGY_ID_MISMATCH", ++ "STATUS_WIM_NOT_BOOTABLE", ++ "STATUS_BLOCKED_BY_PARENTAL_CONTROLS", ++ "STATUS_NEEDS_REGISTRATION", ++ "STATUS_QUOTA_ACTIVITY", ++ "STATUS_CALLBACK_INVOKE_INLINE", ++ "STATUS_BLOCK_TOO_MANY_REFERENCES", ++ "STATUS_MARKED_TO_DISALLOW_WRITES", ++ "STATUS_NETWORK_ACCESS_DENIED_EDP", ++ "STATUS_ENCLAVE_FAILURE", ++ "STATUS_PNP_NO_COMPAT_DRIVERS", ++ "STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND", ++ "STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND", ++ "STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE", ++ "STATUS_PNP_FUNCTION_DRIVER_REQUIRED", ++ "STATUS_PNP_DEVICE_CONFIGURATION_PENDING", ++ "STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL", ++ "STATUS_PACKAGE_NOT_AVAILABLE", ++ "STATUS_DEVICE_IN_MAINTENANCE", ++ "STATUS_NOT_SUPPORTED_ON_DAX", ++ "STATUS_FREE_SPACE_TOO_FRAGMENTED", ++ "STATUS_DAX_MAPPING_EXISTS", ++ "STATUS_CHILD_PROCESS_BLOCKED", ++ "STATUS_STORAGE_LOST_DATA_PERSISTENCE", ++ "STATUS_VRF_CFG_AND_IO_ENABLED", ++ "STATUS_PARTITION_TERMINATING", ++ "STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED", ++ "STATUS_ENCLAVE_VIOLATION", ++ "STATUS_FILE_PROTECTED_UNDER_DPL", ++ "STATUS_VOLUME_NOT_CLUSTER_ALIGNED", ++ "STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND", ++ "STATUS_APPX_FILE_NOT_ENCRYPTED", ++ "STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED", ++ "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET", ++ "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE", ++ "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER", ++ "STATUS_FT_READ_FAILURE", ++ "STATUS_PATCH_CONFLICT", ++ "STATUS_STORAGE_RESERVE_ID_INVALID", ++ "STATUS_STORAGE_RESERVE_DOES_NOT_EXIST", ++ "STATUS_STORAGE_RESERVE_ALREADY_EXISTS", ++ "STATUS_STORAGE_RESERVE_NOT_EMPTY", ++ "STATUS_NOT_A_DAX_VOLUME", ++ "STATUS_NOT_DAX_MAPPABLE", ++ "STATUS_CASE_DIFFERING_NAMES_IN_DIR", ++ "STATUS_FILE_NOT_SUPPORTED", ++ "STATUS_NOT_SUPPORTED_WITH_BTT", ++ "STATUS_ENCRYPTION_DISABLED", ++ "STATUS_ENCRYPTING_METADATA_DISALLOWED", ++ "STATUS_CANT_CLEAR_ENCRYPTION_FLAG", ++ "STATUS_UNSATISFIED_DEPENDENCIES", ++ "STATUS_CASE_SENSITIVE_PATH", ++ "STATUS_HAS_SYSTEM_CRITICAL_FILES", ++ "STATUS_INVALID_TASK_NAME", ++ "STATUS_INVALID_TASK_INDEX", ++ "STATUS_THREAD_ALREADY_IN_TASK", ++ "STATUS_CALLBACK_BYPASS", ++ "STATUS_UNDEFINED_SCOPE", ++ "STATUS_INVALID_CAP", ++ "STATUS_NOT_GUI_PROCESS", ++ "STATUS_DEVICE_HUNG", ++ "STATUS_CONTAINER_ASSIGNED", ++ "STATUS_JOB_NO_CONTAINER", ++ "STATUS_DEVICE_UNRESPONSIVE", ++ "STATUS_REPARSE_POINT_ENCOUNTERED", ++ "STATUS_ATTRIBUTE_NOT_PRESENT", ++ "STATUS_NOT_A_TIERED_VOLUME", ++ "STATUS_ALREADY_HAS_STREAM_ID", ++ "STATUS_JOB_NOT_EMPTY", ++ "STATUS_ALREADY_INITIALIZED", ++ "STATUS_ENCLAVE_NOT_TERMINATED", ++ "STATUS_ENCLAVE_IS_TERMINATING", ++ "STATUS_SMB1_NOT_AVAILABLE", ++ "STATUS_SMR_GARBAGE_COLLECTION_REQUIRED", ++ "STATUS_INTERRUPTED", ++ "STATUS_THREAD_NOT_RUNNING", ++ "STATUS_FAIL_FAST_EXCEPTION", ++ "STATUS_IMAGE_CERT_REVOKED", ++ "STATUS_DYNAMIC_CODE_BLOCKED", ++ "STATUS_IMAGE_CERT_EXPIRED", ++ "STATUS_STRICT_CFG_VIOLATION", ++ "STATUS_SET_CONTEXT_DENIED", ++ "STATUS_CROSS_PARTITION_VIOLATION", ++ "STATUS_PORT_CLOSED", ++ "STATUS_MESSAGE_LOST", ++ "STATUS_INVALID_MESSAGE", ++ "STATUS_REQUEST_CANCELED", ++ "STATUS_RECURSIVE_DISPATCH", ++ "STATUS_LPC_RECEIVE_BUFFER_EXPECTED", ++ "STATUS_LPC_INVALID_CONNECTION_USAGE", ++ "STATUS_LPC_REQUESTS_NOT_ALLOWED", ++ "STATUS_RESOURCE_IN_USE", ++ "STATUS_HARDWARE_MEMORY_ERROR", ++ "STATUS_THREADPOOL_HANDLE_EXCEPTION", ++ "STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED", ++ "STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED", ++ "STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED", ++ "STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED", ++ "STATUS_THREADPOOL_RELEASED_DURING_OPERATION", ++ "STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING", ++ "STATUS_APC_RETURNED_WHILE_IMPERSONATING", ++ "STATUS_PROCESS_IS_PROTECTED", ++ "STATUS_MCA_EXCEPTION", ++ "STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE", ++ "STATUS_SYMLINK_CLASS_DISABLED", ++ "STATUS_INVALID_IDN_NORMALIZATION", ++ "STATUS_NO_UNICODE_TRANSLATION", ++ "STATUS_ALREADY_REGISTERED", ++ "STATUS_CONTEXT_MISMATCH", ++ "STATUS_PORT_ALREADY_HAS_COMPLETION_LIST", ++ "STATUS_CALLBACK_RETURNED_THREAD_PRIORITY", ++ "STATUS_INVALID_THREAD", ++ "STATUS_CALLBACK_RETURNED_TRANSACTION", ++ "STATUS_CALLBACK_RETURNED_LDR_LOCK", ++ "STATUS_CALLBACK_RETURNED_LANG", ++ "STATUS_CALLBACK_RETURNED_PRI_BACK", ++ "STATUS_CALLBACK_RETURNED_THREAD_AFFINITY", ++ "STATUS_LPC_HANDLE_COUNT_EXCEEDED", ++ "STATUS_EXECUTABLE_MEMORY_WRITE", ++ "STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE", ++ "STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE", ++ "STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE", ++ "STATUS_DISK_REPAIR_DISABLED", ++ "STATUS_DS_DOMAIN_RENAME_IN_PROGRESS", ++ "STATUS_DISK_QUOTA_EXCEEDED", ++ "STATUS_CONTENT_BLOCKED", ++ "STATUS_BAD_CLUSTERS", ++ "STATUS_VOLUME_DIRTY", ++ "STATUS_DISK_REPAIR_UNSUCCESSFUL", ++ "STATUS_CORRUPT_LOG_OVERFULL", ++ "STATUS_CORRUPT_LOG_CORRUPTED", ++ "STATUS_CORRUPT_LOG_UNAVAILABLE", ++ "STATUS_CORRUPT_LOG_DELETED_FULL", ++ "STATUS_CORRUPT_LOG_CLEARED", ++ "STATUS_ORPHAN_NAME_EXHAUSTED", ++ "STATUS_PROACTIVE_SCAN_IN_PROGRESS", ++ "STATUS_ENCRYPTED_IO_NOT_POSSIBLE", ++ "STATUS_CORRUPT_LOG_UPLEVEL_RECORDS", ++ "STATUS_FILE_CHECKED_OUT", ++ "STATUS_CHECKOUT_REQUIRED", ++ "STATUS_BAD_FILE_TYPE", ++ "STATUS_FILE_TOO_LARGE", ++ "STATUS_FORMS_AUTH_REQUIRED", ++ "STATUS_VIRUS_INFECTED", ++ "STATUS_VIRUS_DELETED", ++ "STATUS_BAD_MCFG_TABLE", ++ "STATUS_CANNOT_BREAK_OPLOCK", ++ "STATUS_BAD_KEY", ++ "STATUS_BAD_DATA", ++ "STATUS_NO_KEY", ++ "STATUS_FILE_HANDLE_REVOKED", ++ "STATUS_WOW_ASSERTION", ++ "STATUS_INVALID_SIGNATURE", ++ "STATUS_HMAC_NOT_SUPPORTED", ++ "STATUS_AUTH_TAG_MISMATCH", ++ "STATUS_INVALID_STATE_TRANSITION", ++ "STATUS_INVALID_KERNEL_INFO_VERSION", ++ "STATUS_INVALID_PEP_INFO_VERSION", ++ "STATUS_HANDLE_REVOKED", ++ "STATUS_EOF_ON_GHOSTED_RANGE", ++ "STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN", ++ "STATUS_IPSEC_QUEUE_OVERFLOW", ++ "STATUS_ND_QUEUE_OVERFLOW", ++ "STATUS_HOPLIMIT_EXCEEDED", ++ "STATUS_PROTOCOL_NOT_SUPPORTED", ++ "STATUS_FASTPATH_REJECTED", ++ "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED", ++ "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR", ++ "STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR", ++ "STATUS_XML_PARSE_ERROR", ++ "STATUS_XMLDSIG_ERROR", ++ "STATUS_WRONG_COMPARTMENT", ++ "STATUS_AUTHIP_FAILURE", ++ "STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS", ++ "STATUS_DS_OID_NOT_FOUND", ++ "STATUS_INCORRECT_ACCOUNT_TYPE", ++ "STATUS_HASH_NOT_SUPPORTED", ++ "STATUS_HASH_NOT_PRESENT", ++ "STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED", ++ "STATUS_GPIO_CLIENT_INFORMATION_INVALID", ++ "STATUS_GPIO_VERSION_NOT_SUPPORTED", ++ "STATUS_GPIO_INVALID_REGISTRATION_PACKET", ++ "STATUS_GPIO_OPERATION_DENIED", ++ "STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE", ++ "STATUS_CANNOT_SWITCH_RUNLEVEL", ++ "STATUS_INVALID_RUNLEVEL_SETTING", ++ "STATUS_RUNLEVEL_SWITCH_TIMEOUT", ++ "STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT", ++ "STATUS_RUNLEVEL_SWITCH_IN_PROGRESS", ++ "STATUS_NOT_APPCONTAINER", ++ "STATUS_NOT_SUPPORTED_IN_APPCONTAINER", ++ "STATUS_INVALID_PACKAGE_SID_LENGTH", ++ "STATUS_LPAC_ACCESS_DENIED", ++ "STATUS_ADMINLESS_ACCESS_DENIED", ++ "STATUS_APP_DATA_NOT_FOUND", ++ "STATUS_APP_DATA_EXPIRED", ++ "STATUS_APP_DATA_CORRUPT", ++ "STATUS_APP_DATA_LIMIT_EXCEEDED", ++ "STATUS_APP_DATA_REBOOT_REQUIRED", ++ "STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED", ++ "STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED", ++ "STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED", ++ "STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED", ++ "STATUS_WOF_WIM_HEADER_CORRUPT", ++ "STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT", ++ "STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT", ++ "STATUS_CIMFS_IMAGE_CORRUPT", ++ "STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE", ++ "STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT", ++ "STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY", ++ "STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN", ++ "STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION", ++ "STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT", ++ "STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING", ++ "STATUS_CLOUD_FILE_METADATA_CORRUPT", ++ "STATUS_CLOUD_FILE_METADATA_TOO_LARGE", ++ "STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED", ++ "STATUS_NOT_A_CLOUD_FILE", ++ "STATUS_CLOUD_FILE_NOT_IN_SYNC", ++ "STATUS_CLOUD_FILE_ALREADY_CONNECTED", ++ "STATUS_CLOUD_FILE_NOT_SUPPORTED", ++ "STATUS_CLOUD_FILE_INVALID_REQUEST", ++ "STATUS_CLOUD_FILE_READ_ONLY_VOLUME", ++ "STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY", ++ "STATUS_CLOUD_FILE_VALIDATION_FAILED", ++ "STATUS_CLOUD_FILE_AUTHENTICATION_FAILED", ++ "STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES", ++ "STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE", ++ "STATUS_CLOUD_FILE_UNSUCCESSFUL", ++ "STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT", ++ "STATUS_CLOUD_FILE_IN_USE", ++ "STATUS_CLOUD_FILE_PINNED", ++ "STATUS_CLOUD_FILE_REQUEST_ABORTED", ++ "STATUS_CLOUD_FILE_PROPERTY_CORRUPT", ++ "STATUS_CLOUD_FILE_ACCESS_DENIED", ++ "STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS", ++ "STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT", ++ "STATUS_CLOUD_FILE_REQUEST_CANCELED", ++ "STATUS_CLOUD_FILE_PROVIDER_TERMINATED", ++ "STATUS_NOT_A_CLOUD_SYNC_ROOT", ++ "STATUS_CLOUD_FILE_REQUEST_TIMEOUT", ++ "STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED", ++ "STATUS_FILE_SNAP_IN_PROGRESS", ++ "STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED", ++ "STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED", ++ "STATUS_FILE_SNAP_IO_NOT_COORDINATED", ++ "STATUS_FILE_SNAP_UNEXPECTED_ERROR", ++ "STATUS_FILE_SNAP_INVALID_PARAMETER", ++ "DBG_NO_STATE_CHANGE", ++ "DBG_APP_NOT_IDLE", ++ "RPC_NT_INVALID_STRING_BINDING", ++ "RPC_NT_WRONG_KIND_OF_BINDING", ++ "RPC_NT_INVALID_BINDING", ++ "RPC_NT_PROTSEQ_NOT_SUPPORTED", ++ "RPC_NT_INVALID_RPC_PROTSEQ", ++ "RPC_NT_INVALID_STRING_UUID", ++ "RPC_NT_INVALID_ENDPOINT_FORMAT", ++ "RPC_NT_INVALID_NET_ADDR", ++ "RPC_NT_NO_ENDPOINT_FOUND", ++ "RPC_NT_INVALID_TIMEOUT", ++ "RPC_NT_OBJECT_NOT_FOUND", ++ "RPC_NT_ALREADY_REGISTERED", ++ "RPC_NT_TYPE_ALREADY_REGISTERED", ++ "RPC_NT_ALREADY_LISTENING", ++ "RPC_NT_NO_PROTSEQS_REGISTERED", ++ "RPC_NT_NOT_LISTENING", ++ "RPC_NT_UNKNOWN_MGR_TYPE", ++ "RPC_NT_UNKNOWN_IF", ++ "RPC_NT_NO_BINDINGS", ++ "RPC_NT_NO_PROTSEQS", ++ "RPC_NT_CANT_CREATE_ENDPOINT", ++ "RPC_NT_OUT_OF_RESOURCES", ++ "RPC_NT_SERVER_UNAVAILABLE", ++ "RPC_NT_SERVER_TOO_BUSY", ++ "RPC_NT_INVALID_NETWORK_OPTIONS", ++ "RPC_NT_NO_CALL_ACTIVE", ++ "RPC_NT_CALL_FAILED", ++ "RPC_NT_CALL_FAILED_DNE", ++ "RPC_NT_PROTOCOL_ERROR", ++ "RPC_NT_UNSUPPORTED_TRANS_SYN", ++ "RPC_NT_UNSUPPORTED_TYPE", ++ "RPC_NT_INVALID_TAG", ++ "RPC_NT_INVALID_BOUND", ++ "RPC_NT_NO_ENTRY_NAME", ++ "RPC_NT_INVALID_NAME_SYNTAX", ++ "RPC_NT_UNSUPPORTED_NAME_SYNTAX", ++ "RPC_NT_UUID_NO_ADDRESS", ++ "RPC_NT_DUPLICATE_ENDPOINT", ++ "RPC_NT_UNKNOWN_AUTHN_TYPE", ++ "RPC_NT_MAX_CALLS_TOO_SMALL", ++ "RPC_NT_STRING_TOO_LONG", ++ "RPC_NT_PROTSEQ_NOT_FOUND", ++ "RPC_NT_PROCNUM_OUT_OF_RANGE", ++ "RPC_NT_BINDING_HAS_NO_AUTH", ++ "RPC_NT_UNKNOWN_AUTHN_SERVICE", ++ "RPC_NT_UNKNOWN_AUTHN_LEVEL", ++ "RPC_NT_INVALID_AUTH_IDENTITY", ++ "RPC_NT_UNKNOWN_AUTHZ_SERVICE", ++ "EPT_NT_INVALID_ENTRY", ++ "EPT_NT_CANT_PERFORM_OP", ++ "EPT_NT_NOT_REGISTERED", ++ "RPC_NT_NOTHING_TO_EXPORT", ++ "RPC_NT_INCOMPLETE_NAME", ++ "RPC_NT_INVALID_VERS_OPTION", ++ "RPC_NT_NO_MORE_MEMBERS", ++ "RPC_NT_NOT_ALL_OBJS_UNEXPORTED", ++ "RPC_NT_INTERFACE_NOT_FOUND", ++ "RPC_NT_ENTRY_ALREADY_EXISTS", ++ "RPC_NT_ENTRY_NOT_FOUND", ++ "RPC_NT_NAME_SERVICE_UNAVAILABLE", ++ "RPC_NT_INVALID_NAF_ID", ++ "RPC_NT_CANNOT_SUPPORT", ++ "RPC_NT_NO_CONTEXT_AVAILABLE", ++ "RPC_NT_INTERNAL_ERROR", ++ "RPC_NT_ZERO_DIVIDE", ++ "RPC_NT_ADDRESS_ERROR", ++ "RPC_NT_FP_DIV_ZERO", ++ "RPC_NT_FP_UNDERFLOW", ++ "RPC_NT_FP_OVERFLOW", ++ "RPC_NT_CALL_IN_PROGRESS", ++ "RPC_NT_NO_MORE_BINDINGS", ++ "RPC_NT_GROUP_MEMBER_NOT_FOUND", ++ "EPT_NT_CANT_CREATE", ++ "RPC_NT_INVALID_OBJECT", ++ "RPC_NT_NO_INTERFACES", ++ "RPC_NT_CALL_CANCELLED", ++ "RPC_NT_BINDING_INCOMPLETE", ++ "RPC_NT_COMM_FAILURE", ++ "RPC_NT_UNSUPPORTED_AUTHN_LEVEL", ++ "RPC_NT_NO_PRINC_NAME", ++ "RPC_NT_NOT_RPC_ERROR", ++ "RPC_NT_SEC_PKG_ERROR", ++ "RPC_NT_NOT_CANCELLED", ++ "RPC_NT_INVALID_ASYNC_HANDLE", ++ "RPC_NT_INVALID_ASYNC_CALL", ++ "RPC_NT_PROXY_ACCESS_DENIED", ++ "RPC_NT_COOKIE_AUTH_FAILED", ++ "RPC_NT_NO_MORE_ENTRIES", ++ "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL", ++ "RPC_NT_SS_CHAR_TRANS_SHORT_FILE", ++ "RPC_NT_SS_IN_NULL_CONTEXT", ++ "RPC_NT_SS_CONTEXT_MISMATCH", ++ "RPC_NT_SS_CONTEXT_DAMAGED", ++ "RPC_NT_SS_HANDLES_MISMATCH", ++ "RPC_NT_SS_CANNOT_GET_CALL_HANDLE", ++ "RPC_NT_NULL_REF_POINTER", ++ "RPC_NT_ENUM_VALUE_OUT_OF_RANGE", ++ "RPC_NT_BYTE_COUNT_TOO_SMALL", ++ "RPC_NT_BAD_STUB_DATA", ++ "RPC_NT_INVALID_ES_ACTION", ++ "RPC_NT_WRONG_ES_VERSION", ++ "RPC_NT_WRONG_STUB_VERSION", ++ "RPC_NT_INVALID_PIPE_OBJECT", ++ "RPC_NT_INVALID_PIPE_OPERATION", ++ "RPC_NT_WRONG_PIPE_VERSION", ++ "RPC_NT_PIPE_CLOSED", ++ "RPC_NT_PIPE_DISCIPLINE_ERROR", ++ "RPC_NT_PIPE_EMPTY", ++ "STATUS_PNP_BAD_MPS_TABLE", ++ "STATUS_PNP_TRANSLATION_FAILED", ++ "STATUS_PNP_IRQ_TRANSLATION_FAILED", ++ "STATUS_PNP_INVALID_ID", ++ "STATUS_IO_REISSUE_AS_CACHED", ++ "STATUS_CTX_WINSTATION_NAME_INVALID", ++ "STATUS_CTX_INVALID_PD", ++ "STATUS_CTX_PD_NOT_FOUND", ++ "STATUS_CTX_CLOSE_PENDING", ++ "STATUS_CTX_NO_OUTBUF", ++ "STATUS_CTX_MODEM_INF_NOT_FOUND", ++ "STATUS_CTX_INVALID_MODEMNAME", ++ "STATUS_CTX_RESPONSE_ERROR", ++ "STATUS_CTX_MODEM_RESPONSE_TIMEOUT", ++ "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER", ++ "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE", ++ "STATUS_CTX_MODEM_RESPONSE_BUSY", ++ "STATUS_CTX_MODEM_RESPONSE_VOICE", ++ "STATUS_CTX_TD_ERROR", ++ "STATUS_CTX_LICENSE_CLIENT_INVALID", ++ "STATUS_CTX_LICENSE_NOT_AVAILABLE", ++ "STATUS_CTX_LICENSE_EXPIRED", ++ "STATUS_CTX_WINSTATION_NOT_FOUND", ++ "STATUS_CTX_WINSTATION_NAME_COLLISION", ++ "STATUS_CTX_WINSTATION_BUSY", ++ "STATUS_CTX_BAD_VIDEO_MODE", ++ "STATUS_CTX_GRAPHICS_INVALID", ++ "STATUS_CTX_NOT_CONSOLE", ++ "STATUS_CTX_CLIENT_QUERY_TIMEOUT", ++ "STATUS_CTX_CONSOLE_DISCONNECT", ++ "STATUS_CTX_CONSOLE_CONNECT", ++ "STATUS_CTX_SHADOW_DENIED", ++ "STATUS_CTX_WINSTATION_ACCESS_DENIED", ++ "STATUS_CTX_INVALID_WD", ++ "STATUS_CTX_WD_NOT_FOUND", ++ "STATUS_CTX_SHADOW_INVALID", ++ "STATUS_CTX_SHADOW_DISABLED", ++ "STATUS_RDP_PROTOCOL_ERROR", ++ "STATUS_CTX_CLIENT_LICENSE_NOT_SET", ++ "STATUS_CTX_CLIENT_LICENSE_IN_USE", ++ "STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE", ++ "STATUS_CTX_SHADOW_NOT_RUNNING", ++ "STATUS_CTX_LOGON_DISABLED", ++ "STATUS_CTX_SECURITY_LAYER_ERROR", ++ "STATUS_TS_INCOMPATIBLE_SESSIONS", ++ "STATUS_TS_VIDEO_SUBSYSTEM_ERROR", ++ "STATUS_MUI_FILE_NOT_FOUND", ++ "STATUS_MUI_INVALID_FILE", ++ "STATUS_MUI_INVALID_RC_CONFIG", ++ "STATUS_MUI_INVALID_LOCALE_NAME", ++ "STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME", ++ "STATUS_MUI_FILE_NOT_LOADED", ++ "STATUS_RESOURCE_ENUM_USER_STOP", ++ "STATUS_CLUSTER_INVALID_NODE", ++ "STATUS_CLUSTER_NODE_EXISTS", ++ "STATUS_CLUSTER_JOIN_IN_PROGRESS", ++ "STATUS_CLUSTER_NODE_NOT_FOUND", ++ "STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND", ++ "STATUS_CLUSTER_NETWORK_EXISTS", ++ "STATUS_CLUSTER_NETWORK_NOT_FOUND", ++ "STATUS_CLUSTER_NETINTERFACE_EXISTS", ++ "STATUS_CLUSTER_NETINTERFACE_NOT_FOUND", ++ "STATUS_CLUSTER_INVALID_REQUEST", ++ "STATUS_CLUSTER_INVALID_NETWORK_PROVIDER", ++ "STATUS_CLUSTER_NODE_DOWN", ++ "STATUS_CLUSTER_NODE_UNREACHABLE", ++ "STATUS_CLUSTER_NODE_NOT_MEMBER", ++ "STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS", ++ "STATUS_CLUSTER_INVALID_NETWORK", ++ "STATUS_CLUSTER_NO_NET_ADAPTERS", ++ "STATUS_CLUSTER_NODE_UP", ++ "STATUS_CLUSTER_NODE_PAUSED", ++ "STATUS_CLUSTER_NODE_NOT_PAUSED", ++ "STATUS_CLUSTER_NO_SECURITY_CONTEXT", ++ "STATUS_CLUSTER_NETWORK_NOT_INTERNAL", ++ "STATUS_CLUSTER_POISONED", ++ "STATUS_CLUSTER_NON_CSV_PATH", ++ "STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL", ++ "STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS", ++ "STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR", ++ "STATUS_CLUSTER_CSV_REDIRECTED", ++ "STATUS_CLUSTER_CSV_NOT_REDIRECTED", ++ "STATUS_CLUSTER_CSV_VOLUME_DRAINING", ++ "STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS", ++ "STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL", ++ "STATUS_CLUSTER_CSV_NO_SNAPSHOTS", ++ "STATUS_CSV_IO_PAUSE_TIMEOUT", ++ "STATUS_CLUSTER_CSV_INVALID_HANDLE", ++ "STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR", ++ "STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED", ++ "STATUS_ACPI_INVALID_OPCODE", ++ "STATUS_ACPI_STACK_OVERFLOW", ++ "STATUS_ACPI_ASSERT_FAILED", ++ "STATUS_ACPI_INVALID_INDEX", ++ "STATUS_ACPI_INVALID_ARGUMENT", ++ "STATUS_ACPI_FATAL", ++ "STATUS_ACPI_INVALID_SUPERNAME", ++ "STATUS_ACPI_INVALID_ARGTYPE", ++ "STATUS_ACPI_INVALID_OBJTYPE", ++ "STATUS_ACPI_INVALID_TARGETTYPE", ++ "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT", ++ "STATUS_ACPI_ADDRESS_NOT_MAPPED", ++ "STATUS_ACPI_INVALID_EVENTTYPE", ++ "STATUS_ACPI_HANDLER_COLLISION", ++ "STATUS_ACPI_INVALID_DATA", ++ "STATUS_ACPI_INVALID_REGION", ++ "STATUS_ACPI_INVALID_ACCESS_SIZE", ++ "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK", ++ "STATUS_ACPI_ALREADY_INITIALIZED", ++ "STATUS_ACPI_NOT_INITIALIZED", ++ "STATUS_ACPI_INVALID_MUTEX_LEVEL", ++ "STATUS_ACPI_MUTEX_NOT_OWNED", ++ "STATUS_ACPI_MUTEX_NOT_OWNER", ++ "STATUS_ACPI_RS_ACCESS", ++ "STATUS_ACPI_INVALID_TABLE", ++ "STATUS_ACPI_REG_HANDLER_FAILED", ++ "STATUS_ACPI_POWER_REQUEST_FAILED", ++ "STATUS_SXS_SECTION_NOT_FOUND", ++ "STATUS_SXS_CANT_GEN_ACTCTX", ++ "STATUS_SXS_INVALID_ACTCTXDATA_FORMAT", ++ "STATUS_SXS_ASSEMBLY_NOT_FOUND", ++ "STATUS_SXS_MANIFEST_FORMAT_ERROR", ++ "STATUS_SXS_MANIFEST_PARSE_ERROR", ++ "STATUS_SXS_ACTIVATION_CONTEXT_DISABLED", ++ "STATUS_SXS_KEY_NOT_FOUND", ++ "STATUS_SXS_VERSION_CONFLICT", ++ "STATUS_SXS_WRONG_SECTION_TYPE", ++ "STATUS_SXS_THREAD_QUERIES_DISABLED", ++ "STATUS_SXS_ASSEMBLY_MISSING", ++ "STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET", ++ "STATUS_SXS_EARLY_DEACTIVATION", ++ "STATUS_SXS_INVALID_DEACTIVATION", ++ "STATUS_SXS_MULTIPLE_DEACTIVATION", ++ "STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY", ++ "STATUS_SXS_PROCESS_TERMINATION_REQUESTED", ++ "STATUS_SXS_CORRUPT_ACTIVATION_STACK", ++ "STATUS_SXS_CORRUPTION", ++ "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE", ++ "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME", ++ "STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE", ++ "STATUS_SXS_IDENTITY_PARSE_ERROR", ++ "STATUS_SXS_COMPONENT_STORE_CORRUPT", ++ "STATUS_SXS_FILE_HASH_MISMATCH", ++ "STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT", ++ "STATUS_SXS_IDENTITIES_DIFFERENT", ++ "STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT", ++ "STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY", ++ "STATUS_ADVANCED_INSTALLER_FAILED", ++ "STATUS_XML_ENCODING_MISMATCH", ++ "STATUS_SXS_MANIFEST_TOO_BIG", ++ "STATUS_SXS_SETTING_NOT_REGISTERED", ++ "STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE", ++ "STATUS_SMI_PRIMITIVE_INSTALLER_FAILED", ++ "STATUS_GENERIC_COMMAND_FAILED", ++ "STATUS_SXS_FILE_HASH_MISSING", ++ "STATUS_TRANSACTIONAL_CONFLICT", ++ "STATUS_INVALID_TRANSACTION", ++ "STATUS_TRANSACTION_NOT_ACTIVE", ++ "STATUS_TM_INITIALIZATION_FAILED", ++ "STATUS_RM_NOT_ACTIVE", ++ "STATUS_RM_METADATA_CORRUPT", ++ "STATUS_TRANSACTION_NOT_JOINED", ++ "STATUS_DIRECTORY_NOT_RM", ++ "STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE", ++ "STATUS_LOG_RESIZE_INVALID_SIZE", ++ "STATUS_REMOTE_FILE_VERSION_MISMATCH", ++ "STATUS_CRM_PROTOCOL_ALREADY_EXISTS", ++ "STATUS_TRANSACTION_PROPAGATION_FAILED", ++ "STATUS_CRM_PROTOCOL_NOT_FOUND", ++ "STATUS_TRANSACTION_SUPERIOR_EXISTS", ++ "STATUS_TRANSACTION_REQUEST_NOT_VALID", ++ "STATUS_TRANSACTION_NOT_REQUESTED", ++ "STATUS_TRANSACTION_ALREADY_ABORTED", ++ "STATUS_TRANSACTION_ALREADY_COMMITTED", ++ "STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER", ++ "STATUS_CURRENT_TRANSACTION_NOT_VALID", ++ "STATUS_LOG_GROWTH_FAILED", ++ "STATUS_OBJECT_NO_LONGER_EXISTS", ++ "STATUS_STREAM_MINIVERSION_NOT_FOUND", ++ "STATUS_STREAM_MINIVERSION_NOT_VALID", ++ "STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION", ++ "STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT", ++ "STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS", ++ "STATUS_HANDLE_NO_LONGER_VALID", ++ "STATUS_LOG_CORRUPTION_DETECTED", ++ "STATUS_RM_DISCONNECTED", ++ "STATUS_ENLISTMENT_NOT_SUPERIOR", ++ "STATUS_FILE_IDENTITY_NOT_PERSISTENT", ++ "STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY", ++ "STATUS_CANT_CROSS_RM_BOUNDARY", ++ "STATUS_TXF_DIR_NOT_EMPTY", ++ "STATUS_INDOUBT_TRANSACTIONS_EXIST", ++ "STATUS_TM_VOLATILE", ++ "STATUS_ROLLBACK_TIMER_EXPIRED", ++ "STATUS_TXF_ATTRIBUTE_CORRUPT", ++ "STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION", ++ "STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED", ++ "STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE", ++ "STATUS_TRANSACTION_REQUIRED_PROMOTION", ++ "STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION", ++ "STATUS_TRANSACTIONS_NOT_FROZEN", ++ "STATUS_TRANSACTION_FREEZE_IN_PROGRESS", ++ "STATUS_NOT_SNAPSHOT_VOLUME", ++ "STATUS_NO_SAVEPOINT_WITH_OPEN_FILES", ++ "STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION", ++ "STATUS_TM_IDENTITY_MISMATCH", ++ "STATUS_FLOATED_SECTION", ++ "STATUS_CANNOT_ACCEPT_TRANSACTED_WORK", ++ "STATUS_CANNOT_ABORT_TRANSACTIONS", ++ "STATUS_TRANSACTION_NOT_FOUND", ++ "STATUS_RESOURCEMANAGER_NOT_FOUND", ++ "STATUS_ENLISTMENT_NOT_FOUND", ++ "STATUS_TRANSACTIONMANAGER_NOT_FOUND", ++ "STATUS_TRANSACTIONMANAGER_NOT_ONLINE", ++ "STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION", ++ "STATUS_TRANSACTION_NOT_ROOT", ++ "STATUS_TRANSACTION_OBJECT_EXPIRED", ++ "STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION", ++ "STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED", ++ "STATUS_TRANSACTION_RECORD_TOO_LONG", ++ "STATUS_NO_LINK_TRACKING_IN_TRANSACTION", ++ "STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION", ++ "STATUS_TRANSACTION_INTEGRITY_VIOLATED", ++ "STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH", ++ "STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT", ++ "STATUS_TRANSACTION_MUST_WRITETHROUGH", ++ "STATUS_TRANSACTION_NO_SUPERIOR", ++ "STATUS_EXPIRED_HANDLE", ++ "STATUS_TRANSACTION_NOT_ENLISTED", ++ "STATUS_LOG_SECTOR_INVALID", ++ "STATUS_LOG_SECTOR_PARITY_INVALID", ++ "STATUS_LOG_SECTOR_REMAPPED", ++ "STATUS_LOG_BLOCK_INCOMPLETE", ++ "STATUS_LOG_INVALID_RANGE", ++ "STATUS_LOG_BLOCKS_EXHAUSTED", ++ "STATUS_LOG_READ_CONTEXT_INVALID", ++ "STATUS_LOG_RESTART_INVALID", ++ "STATUS_LOG_BLOCK_VERSION", ++ "STATUS_LOG_BLOCK_INVALID", ++ "STATUS_LOG_READ_MODE_INVALID", ++ "STATUS_LOG_METADATA_CORRUPT", ++ "STATUS_LOG_METADATA_INVALID", ++ "STATUS_LOG_METADATA_INCONSISTENT", ++ "STATUS_LOG_RESERVATION_INVALID", ++ "STATUS_LOG_CANT_DELETE", ++ "STATUS_LOG_CONTAINER_LIMIT_EXCEEDED", ++ "STATUS_LOG_START_OF_LOG", ++ "STATUS_LOG_POLICY_ALREADY_INSTALLED", ++ "STATUS_LOG_POLICY_NOT_INSTALLED", ++ "STATUS_LOG_POLICY_INVALID", ++ "STATUS_LOG_POLICY_CONFLICT", ++ "STATUS_LOG_PINNED_ARCHIVE_TAIL", ++ "STATUS_LOG_RECORD_NONEXISTENT", ++ "STATUS_LOG_RECORDS_RESERVED_INVALID", ++ "STATUS_LOG_SPACE_RESERVED_INVALID", ++ "STATUS_LOG_TAIL_INVALID", ++ "STATUS_LOG_FULL", ++ "STATUS_LOG_MULTIPLEXED", ++ "STATUS_LOG_DEDICATED", ++ "STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS", ++ "STATUS_LOG_ARCHIVE_IN_PROGRESS", ++ "STATUS_LOG_EPHEMERAL", ++ "STATUS_LOG_NOT_ENOUGH_CONTAINERS", ++ "STATUS_LOG_CLIENT_ALREADY_REGISTERED", ++ "STATUS_LOG_CLIENT_NOT_REGISTERED", ++ "STATUS_LOG_FULL_HANDLER_IN_PROGRESS", ++ "STATUS_LOG_CONTAINER_READ_FAILED", ++ "STATUS_LOG_CONTAINER_WRITE_FAILED", ++ "STATUS_LOG_CONTAINER_OPEN_FAILED", ++ "STATUS_LOG_CONTAINER_STATE_INVALID", ++ "STATUS_LOG_STATE_INVALID", ++ "STATUS_LOG_PINNED", ++ "STATUS_LOG_METADATA_FLUSH_FAILED", ++ "STATUS_LOG_INCONSISTENT_SECURITY", ++ "STATUS_LOG_APPENDED_FLUSH_FAILED", ++ "STATUS_LOG_PINNED_RESERVATION", ++ "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD", ++ "STATUS_FLT_NO_HANDLER_DEFINED", ++ "STATUS_FLT_CONTEXT_ALREADY_DEFINED", ++ "STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST", ++ "STATUS_FLT_DISALLOW_FAST_IO", ++ "STATUS_FLT_INVALID_NAME_REQUEST", ++ "STATUS_FLT_NOT_SAFE_TO_POST_OPERATION", ++ "STATUS_FLT_NOT_INITIALIZED", ++ "STATUS_FLT_FILTER_NOT_READY", ++ "STATUS_FLT_POST_OPERATION_CLEANUP", ++ "STATUS_FLT_INTERNAL_ERROR", ++ "STATUS_FLT_DELETING_OBJECT", ++ "STATUS_FLT_MUST_BE_NONPAGED_POOL", ++ "STATUS_FLT_DUPLICATE_ENTRY", ++ "STATUS_FLT_CBDQ_DISABLED", ++ "STATUS_FLT_DO_NOT_ATTACH", ++ "STATUS_FLT_DO_NOT_DETACH", ++ "STATUS_FLT_INSTANCE_ALTITUDE_COLLISION", ++ "STATUS_FLT_INSTANCE_NAME_COLLISION", ++ "STATUS_FLT_FILTER_NOT_FOUND", ++ "STATUS_FLT_VOLUME_NOT_FOUND", ++ "STATUS_FLT_INSTANCE_NOT_FOUND", ++ "STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND", ++ "STATUS_FLT_INVALID_CONTEXT_REGISTRATION", ++ "STATUS_FLT_NAME_CACHE_MISS", ++ "STATUS_FLT_NO_DEVICE_OBJECT", ++ "STATUS_FLT_VOLUME_ALREADY_MOUNTED", ++ "STATUS_FLT_ALREADY_ENLISTED", ++ "STATUS_FLT_CONTEXT_ALREADY_LINKED", ++ "STATUS_FLT_NO_WAITER_FOR_REPLY", ++ "STATUS_FLT_REGISTRATION_BUSY", ++ "STATUS_MONITOR_NO_DESCRIPTOR", ++ "STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT", ++ "STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM", ++ "STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK", ++ "STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED", ++ "STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK", ++ "STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK", ++ "STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA", ++ "STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK", ++ "STATUS_MONITOR_INVALID_MANUFACTURE_DATE", ++ "STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER", ++ "STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER", ++ "STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER", ++ "STATUS_GRAPHICS_ADAPTER_WAS_RESET", ++ "STATUS_GRAPHICS_INVALID_DRIVER_MODEL", ++ "STATUS_GRAPHICS_PRESENT_MODE_CHANGED", ++ "STATUS_GRAPHICS_PRESENT_OCCLUDED", ++ "STATUS_GRAPHICS_PRESENT_DENIED", ++ "STATUS_GRAPHICS_CANNOTCOLORCONVERT", ++ "STATUS_GRAPHICS_DRIVER_MISMATCH", ++ "STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED", ++ "STATUS_GRAPHICS_PRESENT_UNOCCLUDED", ++ "STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE", ++ "STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED", ++ "STATUS_GRAPHICS_PRESENT_INVALID_WINDOW", ++ "STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND", ++ "STATUS_GRAPHICS_VAIL_STATE_CHANGED", ++ "STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN", ++ "STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED", ++ "STATUS_GRAPHICS_NO_VIDEO_MEMORY", ++ "STATUS_GRAPHICS_CANT_LOCK_MEMORY", ++ "STATUS_GRAPHICS_ALLOCATION_BUSY", ++ "STATUS_GRAPHICS_TOO_MANY_REFERENCES", ++ "STATUS_GRAPHICS_TRY_AGAIN_LATER", ++ "STATUS_GRAPHICS_TRY_AGAIN_NOW", ++ "STATUS_GRAPHICS_ALLOCATION_INVALID", ++ "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE", ++ "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED", ++ "STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION", ++ "STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE", ++ "STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION", ++ "STATUS_GRAPHICS_ALLOCATION_CLOSED", ++ "STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE", ++ "STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE", ++ "STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE", ++ "STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST", ++ "STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE", ++ "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY", ++ "STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_INVALID_VIDPN", ++ "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE", ++ "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET", ++ "STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET", ++ "STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET", ++ "STATUS_GRAPHICS_INVALID_FREQUENCY", ++ "STATUS_GRAPHICS_INVALID_ACTIVE_REGION", ++ "STATUS_GRAPHICS_INVALID_TOTAL_REGION", ++ "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE", ++ "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE", ++ "STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET", ++ "STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY", ++ "STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET", ++ "STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET", ++ "STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET", ++ "STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET", ++ "STATUS_GRAPHICS_TARGET_ALREADY_IN_SET", ++ "STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH", ++ "STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY", ++ "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET", ++ "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE", ++ "STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET", ++ "STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET", ++ "STATUS_GRAPHICS_STALE_MODESET", ++ "STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET", ++ "STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE", ++ "STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN", ++ "STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE", ++ "STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION", ++ "STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES", ++ "STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY", ++ "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE", ++ "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET", ++ "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET", ++ "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR", ++ "STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET", ++ "STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET", ++ "STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE", ++ "STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE", ++ "STATUS_GRAPHICS_RESOURCES_NOT_RELATED", ++ "STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE", ++ "STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE", ++ "STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET", ++ "STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER", ++ "STATUS_GRAPHICS_NO_VIDPNMGR", ++ "STATUS_GRAPHICS_NO_ACTIVE_VIDPN", ++ "STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY", ++ "STATUS_GRAPHICS_MONITOR_NOT_CONNECTED", ++ "STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY", ++ "STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE", ++ "STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE", ++ "STATUS_GRAPHICS_INVALID_STRIDE", ++ "STATUS_GRAPHICS_INVALID_PIXELFORMAT", ++ "STATUS_GRAPHICS_INVALID_COLORBASIS", ++ "STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE", ++ "STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY", ++ "STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT", ++ "STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE", ++ "STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN", ++ "STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL", ++ "STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION", ++ "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_INVALID_GAMMA_RAMP", ++ "STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_MODE_NOT_IN_MODESET", ++ "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON", ++ "STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE", ++ "STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE", ++ "STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS", ++ "STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING", ++ "STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED", ++ "STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS", ++ "STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT", ++ "STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM", ++ "STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN", ++ "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT", ++ "STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED", ++ "STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION", ++ "STATUS_GRAPHICS_INVALID_CLIENT_TYPE", ++ "STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET", ++ "STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED", ++ "STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER", ++ "STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED", ++ "STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED", ++ "STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY", ++ "STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED", ++ "STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON", ++ "STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE", ++ "STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER", ++ "STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED", ++ "STATUS_GRAPHICS_OPM_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_COPP_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_UAB_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS", ++ "STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST", ++ "STATUS_GRAPHICS_OPM_INTERNAL_ERROR", ++ "STATUS_GRAPHICS_OPM_INVALID_HANDLE", ++ "STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH", ++ "STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED", ++ "STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED", ++ "STATUS_GRAPHICS_PVP_HFS_FAILED", ++ "STATUS_GRAPHICS_OPM_INVALID_SRM", ++ "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP", ++ "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP", ++ "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA", ++ "STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET", ++ "STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH", ++ "STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE", ++ "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS", ++ "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS", ++ "STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST", ++ "STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR", ++ "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS", ++ "STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST", ++ "STATUS_GRAPHICS_I2C_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST", ++ "STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA", ++ "STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA", ++ "STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_DDCCI_INVALID_DATA", ++ "STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE", ++ "STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING", ++ "STATUS_GRAPHICS_MCA_INTERNAL_ERROR", ++ "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND", ++ "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH", ++ "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM", ++ "STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE", ++ "STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS", ++ "STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED", ++ "STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME", ++ "STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP", ++ "STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED", ++ "STATUS_GRAPHICS_INVALID_POINTER", ++ "STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE", ++ "STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL", ++ "STATUS_GRAPHICS_INTERNAL_ERROR", ++ "STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS", ++ "STATUS_FVE_LOCKED_VOLUME", ++ "STATUS_FVE_NOT_ENCRYPTED", ++ "STATUS_FVE_BAD_INFORMATION", ++ "STATUS_FVE_TOO_SMALL", ++ "STATUS_FVE_FAILED_WRONG_FS", ++ "STATUS_FVE_BAD_PARTITION_SIZE", ++ "STATUS_FVE_FS_NOT_EXTENDED", ++ "STATUS_FVE_FS_MOUNTED", ++ "STATUS_FVE_NO_LICENSE", ++ "STATUS_FVE_ACTION_NOT_ALLOWED", ++ "STATUS_FVE_BAD_DATA", ++ "STATUS_FVE_VOLUME_NOT_BOUND", ++ "STATUS_FVE_NOT_DATA_VOLUME", ++ "STATUS_FVE_CONV_READ_ERROR", ++ "STATUS_FVE_CONV_WRITE_ERROR", ++ "STATUS_FVE_OVERLAPPED_UPDATE", ++ "STATUS_FVE_FAILED_SECTOR_SIZE", ++ "STATUS_FVE_FAILED_AUTHENTICATION", ++ "STATUS_FVE_NOT_OS_VOLUME", ++ "STATUS_FVE_KEYFILE_NOT_FOUND", ++ "STATUS_FVE_KEYFILE_INVALID", ++ "STATUS_FVE_KEYFILE_NO_VMK", ++ "STATUS_FVE_TPM_DISABLED", ++ "STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO", ++ "STATUS_FVE_TPM_INVALID_PCR", ++ "STATUS_FVE_TPM_NO_VMK", ++ "STATUS_FVE_PIN_INVALID", ++ "STATUS_FVE_AUTH_INVALID_APPLICATION", ++ "STATUS_FVE_AUTH_INVALID_CONFIG", ++ "STATUS_FVE_DEBUGGER_ENABLED", ++ "STATUS_FVE_DRY_RUN_FAILED", ++ "STATUS_FVE_BAD_METADATA_POINTER", ++ "STATUS_FVE_OLD_METADATA_COPY", ++ "STATUS_FVE_REBOOT_REQUIRED", ++ "STATUS_FVE_RAW_ACCESS", ++ "STATUS_FVE_RAW_BLOCKED", ++ "STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY", ++ "STATUS_FVE_MOR_FAILED", ++ "STATUS_FVE_NO_FEATURE_LICENSE", ++ "STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED", ++ "STATUS_FVE_CONV_RECOVERY_FAILED", ++ "STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG", ++ "STATUS_FVE_INVALID_DATUM_TYPE", ++ "STATUS_FVE_VOLUME_TOO_SMALL", ++ "STATUS_FVE_ENH_PIN_INVALID", ++ "STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE", ++ "STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE", ++ "STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK", ++ "STATUS_FVE_NOT_ALLOWED_ON_CLUSTER", ++ "STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING", ++ "STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE", ++ "STATUS_FVE_EDRIVE_DRY_RUN_FAILED", ++ "STATUS_FVE_SECUREBOOT_DISABLED", ++ "STATUS_FVE_SECUREBOOT_CONFIG_CHANGE", ++ "STATUS_FVE_DEVICE_LOCKEDOUT", ++ "STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT", ++ "STATUS_FVE_NOT_DE_VOLUME", ++ "STATUS_FVE_PROTECTION_DISABLED", ++ "STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED", ++ "STATUS_FVE_OSV_KSR_NOT_ALLOWED", ++ "STATUS_FWP_CALLOUT_NOT_FOUND", ++ "STATUS_FWP_CONDITION_NOT_FOUND", ++ "STATUS_FWP_FILTER_NOT_FOUND", ++ "STATUS_FWP_LAYER_NOT_FOUND", ++ "STATUS_FWP_PROVIDER_NOT_FOUND", ++ "STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND", ++ "STATUS_FWP_SUBLAYER_NOT_FOUND", ++ "STATUS_FWP_NOT_FOUND", ++ "STATUS_FWP_ALREADY_EXISTS", ++ "STATUS_FWP_IN_USE", ++ "STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS", ++ "STATUS_FWP_WRONG_SESSION", ++ "STATUS_FWP_NO_TXN_IN_PROGRESS", ++ "STATUS_FWP_TXN_IN_PROGRESS", ++ "STATUS_FWP_TXN_ABORTED", ++ "STATUS_FWP_SESSION_ABORTED", ++ "STATUS_FWP_INCOMPATIBLE_TXN", ++ "STATUS_FWP_TIMEOUT", ++ "STATUS_FWP_NET_EVENTS_DISABLED", ++ "STATUS_FWP_INCOMPATIBLE_LAYER", ++ "STATUS_FWP_KM_CLIENTS_ONLY", ++ "STATUS_FWP_LIFETIME_MISMATCH", ++ "STATUS_FWP_BUILTIN_OBJECT", ++ "STATUS_FWP_TOO_MANY_CALLOUTS", ++ "STATUS_FWP_NOTIFICATION_DROPPED", ++ "STATUS_FWP_TRAFFIC_MISMATCH", ++ "STATUS_FWP_INCOMPATIBLE_SA_STATE", ++ "STATUS_FWP_NULL_POINTER", ++ "STATUS_FWP_INVALID_ENUMERATOR", ++ "STATUS_FWP_INVALID_FLAGS", ++ "STATUS_FWP_INVALID_NET_MASK", ++ "STATUS_FWP_INVALID_RANGE", ++ "STATUS_FWP_INVALID_INTERVAL", ++ "STATUS_FWP_ZERO_LENGTH_ARRAY", ++ "STATUS_FWP_NULL_DISPLAY_NAME", ++ "STATUS_FWP_INVALID_ACTION_TYPE", ++ "STATUS_FWP_INVALID_WEIGHT", ++ "STATUS_FWP_MATCH_TYPE_MISMATCH", ++ "STATUS_FWP_TYPE_MISMATCH", ++ "STATUS_FWP_OUT_OF_BOUNDS", ++ "STATUS_FWP_RESERVED", ++ "STATUS_FWP_DUPLICATE_CONDITION", ++ "STATUS_FWP_DUPLICATE_KEYMOD", ++ "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER", ++ "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER", ++ "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER", ++ "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT", ++ "STATUS_FWP_INCOMPATIBLE_AUTH_METHOD", ++ "STATUS_FWP_INCOMPATIBLE_DH_GROUP", ++ "STATUS_FWP_EM_NOT_SUPPORTED", ++ "STATUS_FWP_NEVER_MATCH", ++ "STATUS_FWP_PROVIDER_CONTEXT_MISMATCH", ++ "STATUS_FWP_INVALID_PARAMETER", ++ "STATUS_FWP_TOO_MANY_SUBLAYERS", ++ "STATUS_FWP_CALLOUT_NOTIFICATION_FAILED", ++ "STATUS_FWP_INVALID_AUTH_TRANSFORM", ++ "STATUS_FWP_INVALID_CIPHER_TRANSFORM", ++ "STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM", ++ "STATUS_FWP_INVALID_TRANSFORM_COMBINATION", ++ "STATUS_FWP_DUPLICATE_AUTH_METHOD", ++ "STATUS_FWP_INVALID_TUNNEL_ENDPOINT", ++ "STATUS_FWP_L2_DRIVER_NOT_READY", ++ "STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED", ++ "STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL", ++ "STATUS_FWP_CONNECTIONS_DISABLED", ++ "STATUS_FWP_INVALID_DNS_NAME", ++ "STATUS_FWP_STILL_ON", ++ "STATUS_FWP_IKEEXT_NOT_RUNNING", ++ "STATUS_FWP_TCPIP_NOT_READY", ++ "STATUS_FWP_INJECT_HANDLE_CLOSING", ++ "STATUS_FWP_INJECT_HANDLE_STALE", ++ "STATUS_FWP_CANNOT_PEND", ++ "STATUS_FWP_DROP_NOICMP", ++ "STATUS_NDIS_CLOSING", ++ "STATUS_NDIS_BAD_VERSION", ++ "STATUS_NDIS_BAD_CHARACTERISTICS", ++ "STATUS_NDIS_ADAPTER_NOT_FOUND", ++ "STATUS_NDIS_OPEN_FAILED", ++ "STATUS_NDIS_DEVICE_FAILED", ++ "STATUS_NDIS_MULTICAST_FULL", ++ "STATUS_NDIS_MULTICAST_EXISTS", ++ "STATUS_NDIS_MULTICAST_NOT_FOUND", ++ "STATUS_NDIS_REQUEST_ABORTED", ++ "STATUS_NDIS_RESET_IN_PROGRESS", ++ "STATUS_NDIS_INVALID_PACKET", ++ "STATUS_NDIS_INVALID_DEVICE_REQUEST", ++ "STATUS_NDIS_ADAPTER_NOT_READY", ++ "STATUS_NDIS_INVALID_LENGTH", ++ "STATUS_NDIS_INVALID_DATA", ++ "STATUS_NDIS_BUFFER_TOO_SHORT", ++ "STATUS_NDIS_INVALID_OID", ++ "STATUS_NDIS_ADAPTER_REMOVED", ++ "STATUS_NDIS_UNSUPPORTED_MEDIA", ++ "STATUS_NDIS_GROUP_ADDRESS_IN_USE", ++ "STATUS_NDIS_FILE_NOT_FOUND", ++ "STATUS_NDIS_ERROR_READING_FILE", ++ "STATUS_NDIS_ALREADY_MAPPED", ++ "STATUS_NDIS_RESOURCE_CONFLICT", ++ "STATUS_NDIS_MEDIA_DISCONNECTED", ++ "STATUS_NDIS_INVALID_ADDRESS", ++ "STATUS_NDIS_PAUSED", ++ "STATUS_NDIS_INTERFACE_NOT_FOUND", ++ "STATUS_NDIS_UNSUPPORTED_REVISION", ++ "STATUS_NDIS_INVALID_PORT", ++ "STATUS_NDIS_INVALID_PORT_STATE", ++ "STATUS_NDIS_LOW_POWER_STATE", ++ "STATUS_NDIS_REINIT_REQUIRED", ++ "STATUS_NDIS_NO_QUEUES", ++ "STATUS_NDIS_NOT_SUPPORTED", ++ "STATUS_NDIS_OFFLOAD_POLICY", ++ "STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED", ++ "STATUS_NDIS_OFFLOAD_PATH_REJECTED", ++ "STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED", ++ "STATUS_NDIS_DOT11_MEDIA_IN_USE", ++ "STATUS_NDIS_DOT11_POWER_STATE_INVALID", ++ "STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL", ++ "STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL", ++ "STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE", ++ "STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE", ++ "STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED", ++ "STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED", ++ "STATUS_QUIC_HANDSHAKE_FAILURE", ++ "STATUS_QUIC_VER_NEG_FAILURE", ++ "STATUS_TPM_ERROR_MASK", ++ "STATUS_TPM_AUTHFAIL", ++ "STATUS_TPM_BADINDEX", ++ "STATUS_TPM_BAD_PARAMETER", ++ "STATUS_TPM_AUDITFAILURE", ++ "STATUS_TPM_CLEAR_DISABLED", ++ "STATUS_TPM_DEACTIVATED", ++ "STATUS_TPM_DISABLED", ++ "STATUS_TPM_DISABLED_CMD", ++ "STATUS_TPM_FAIL", ++ "STATUS_TPM_BAD_ORDINAL", ++ "STATUS_TPM_INSTALL_DISABLED", ++ "STATUS_TPM_INVALID_KEYHANDLE", ++ "STATUS_TPM_KEYNOTFOUND", ++ "STATUS_TPM_INAPPROPRIATE_ENC", ++ "STATUS_TPM_MIGRATEFAIL", ++ "STATUS_TPM_INVALID_PCR_INFO", ++ "STATUS_TPM_NOSPACE", ++ "STATUS_TPM_NOSRK", ++ "STATUS_TPM_NOTSEALED_BLOB", ++ "STATUS_TPM_OWNER_SET", ++ "STATUS_TPM_RESOURCES", ++ "STATUS_TPM_SHORTRANDOM", ++ "STATUS_TPM_SIZE", ++ "STATUS_TPM_WRONGPCRVAL", ++ "STATUS_TPM_BAD_PARAM_SIZE", ++ "STATUS_TPM_SHA_THREAD", ++ "STATUS_TPM_SHA_ERROR", ++ "STATUS_TPM_FAILEDSELFTEST", ++ "STATUS_TPM_AUTH2FAIL", ++ "STATUS_TPM_BADTAG", ++ "STATUS_TPM_IOERROR", ++ "STATUS_TPM_ENCRYPT_ERROR", ++ "STATUS_TPM_DECRYPT_ERROR", ++ "STATUS_TPM_INVALID_AUTHHANDLE", ++ "STATUS_TPM_NO_ENDORSEMENT", ++ "STATUS_TPM_INVALID_KEYUSAGE", ++ "STATUS_TPM_WRONG_ENTITYTYPE", ++ "STATUS_TPM_INVALID_POSTINIT", ++ "STATUS_TPM_INAPPROPRIATE_SIG", ++ "STATUS_TPM_BAD_KEY_PROPERTY", ++ "STATUS_TPM_BAD_MIGRATION", ++ "STATUS_TPM_BAD_SCHEME", ++ "STATUS_TPM_BAD_DATASIZE", ++ "STATUS_TPM_BAD_MODE", ++ "STATUS_TPM_BAD_PRESENCE", ++ "STATUS_TPM_BAD_VERSION", ++ "STATUS_TPM_NO_WRAP_TRANSPORT", ++ "STATUS_TPM_AUDITFAIL_UNSUCCESSFUL", ++ "STATUS_TPM_AUDITFAIL_SUCCESSFUL", ++ "STATUS_TPM_NOTRESETABLE", ++ "STATUS_TPM_NOTLOCAL", ++ "STATUS_TPM_BAD_TYPE", ++ "STATUS_TPM_INVALID_RESOURCE", ++ "STATUS_TPM_NOTFIPS", ++ "STATUS_TPM_INVALID_FAMILY", ++ "STATUS_TPM_NO_NV_PERMISSION", ++ "STATUS_TPM_REQUIRES_SIGN", ++ "STATUS_TPM_KEY_NOTSUPPORTED", ++ "STATUS_TPM_AUTH_CONFLICT", ++ "STATUS_TPM_AREA_LOCKED", ++ "STATUS_TPM_BAD_LOCALITY", ++ "STATUS_TPM_READ_ONLY", ++ "STATUS_TPM_PER_NOWRITE", ++ "STATUS_TPM_FAMILYCOUNT", ++ "STATUS_TPM_WRITE_LOCKED", ++ "STATUS_TPM_BAD_ATTRIBUTES", ++ "STATUS_TPM_INVALID_STRUCTURE", ++ "STATUS_TPM_KEY_OWNER_CONTROL", ++ "STATUS_TPM_BAD_COUNTER", ++ "STATUS_TPM_NOT_FULLWRITE", ++ "STATUS_TPM_CONTEXT_GAP", ++ "STATUS_TPM_MAXNVWRITES", ++ "STATUS_TPM_NOOPERATOR", ++ "STATUS_TPM_RESOURCEMISSING", ++ "STATUS_TPM_DELEGATE_LOCK", ++ "STATUS_TPM_DELEGATE_FAMILY", ++ "STATUS_TPM_DELEGATE_ADMIN", ++ "STATUS_TPM_TRANSPORT_NOTEXCLUSIVE", ++ "STATUS_TPM_OWNER_CONTROL", ++ "STATUS_TPM_DAA_RESOURCES", ++ "STATUS_TPM_DAA_INPUT_DATA0", ++ "STATUS_TPM_DAA_INPUT_DATA1", ++ "STATUS_TPM_DAA_ISSUER_SETTINGS", ++ "STATUS_TPM_DAA_TPM_SETTINGS", ++ "STATUS_TPM_DAA_STAGE", ++ "STATUS_TPM_DAA_ISSUER_VALIDITY", ++ "STATUS_TPM_DAA_WRONG_W", ++ "STATUS_TPM_BAD_HANDLE", ++ "STATUS_TPM_BAD_DELEGATE", ++ "STATUS_TPM_BADCONTEXT", ++ "STATUS_TPM_TOOMANYCONTEXTS", ++ "STATUS_TPM_MA_TICKET_SIGNATURE", ++ "STATUS_TPM_MA_DESTINATION", ++ "STATUS_TPM_MA_SOURCE", ++ "STATUS_TPM_MA_AUTHORITY", ++ "STATUS_TPM_PERMANENTEK", ++ "STATUS_TPM_BAD_SIGNATURE", ++ "STATUS_TPM_NOCONTEXTSPACE", ++ "STATUS_TPM_20_E_ASYMMETRIC", ++ "STATUS_TPM_20_E_ATTRIBUTES", ++ "STATUS_TPM_20_E_HASH", ++ "STATUS_TPM_20_E_VALUE", ++ "STATUS_TPM_20_E_HIERARCHY", ++ "STATUS_TPM_20_E_KEY_SIZE", ++ "STATUS_TPM_20_E_MGF", ++ "STATUS_TPM_20_E_MODE", ++ "STATUS_TPM_20_E_TYPE", ++ "STATUS_TPM_20_E_HANDLE", ++ "STATUS_TPM_20_E_KDF", ++ "STATUS_TPM_20_E_RANGE", ++ "STATUS_TPM_20_E_AUTH_FAIL", ++ "STATUS_TPM_20_E_NONCE", ++ "STATUS_TPM_20_E_PP", ++ "STATUS_TPM_20_E_SCHEME", ++ "STATUS_TPM_20_E_SIZE", ++ "STATUS_TPM_20_E_SYMMETRIC", ++ "STATUS_TPM_20_E_TAG", ++ "STATUS_TPM_20_E_SELECTOR", ++ "STATUS_TPM_20_E_INSUFFICIENT", ++ "STATUS_TPM_20_E_SIGNATURE", ++ "STATUS_TPM_20_E_KEY", ++ "STATUS_TPM_20_E_POLICY_FAIL", ++ "STATUS_TPM_20_E_INTEGRITY", ++ "STATUS_TPM_20_E_TICKET", ++ "STATUS_TPM_20_E_RESERVED_BITS", ++ "STATUS_TPM_20_E_BAD_AUTH", ++ "STATUS_TPM_20_E_EXPIRED", ++ "STATUS_TPM_20_E_POLICY_CC", ++ "STATUS_TPM_20_E_BINDING", ++ "STATUS_TPM_20_E_CURVE", ++ "STATUS_TPM_20_E_ECC_POINT", ++ "STATUS_TPM_20_E_INITIALIZE", ++ "STATUS_TPM_20_E_FAILURE", ++ "STATUS_TPM_20_E_SEQUENCE", ++ "STATUS_TPM_20_E_PRIVATE", ++ "STATUS_TPM_20_E_HMAC", ++ "STATUS_TPM_20_E_DISABLED", ++ "STATUS_TPM_20_E_EXCLUSIVE", ++ "STATUS_TPM_20_E_ECC_CURVE", ++ "STATUS_TPM_20_E_AUTH_TYPE", ++ "STATUS_TPM_20_E_AUTH_MISSING", ++ "STATUS_TPM_20_E_POLICY", ++ "STATUS_TPM_20_E_PCR", ++ "STATUS_TPM_20_E_PCR_CHANGED", ++ "STATUS_TPM_20_E_UPGRADE", ++ "STATUS_TPM_20_E_TOO_MANY_CONTEXTS", ++ "STATUS_TPM_20_E_AUTH_UNAVAILABLE", ++ "STATUS_TPM_20_E_REBOOT", ++ "STATUS_TPM_20_E_UNBALANCED", ++ "STATUS_TPM_20_E_COMMAND_SIZE", ++ "STATUS_TPM_20_E_COMMAND_CODE", ++ "STATUS_TPM_20_E_AUTHSIZE", ++ "STATUS_TPM_20_E_AUTH_CONTEXT", ++ "STATUS_TPM_20_E_NV_RANGE", ++ "STATUS_TPM_20_E_NV_SIZE", ++ "STATUS_TPM_20_E_NV_LOCKED", ++ "STATUS_TPM_20_E_NV_AUTHORIZATION", ++ "STATUS_TPM_20_E_NV_UNINITIALIZED", ++ "STATUS_TPM_20_E_NV_SPACE", ++ "STATUS_TPM_20_E_NV_DEFINED", ++ "STATUS_TPM_20_E_BAD_CONTEXT", ++ "STATUS_TPM_20_E_CPHASH", ++ "STATUS_TPM_20_E_PARENT", ++ "STATUS_TPM_20_E_NEEDS_TEST", ++ "STATUS_TPM_20_E_NO_RESULT", ++ "STATUS_TPM_20_E_SENSITIVE", ++ "STATUS_TPM_COMMAND_BLOCKED", ++ "STATUS_TPM_INVALID_HANDLE", ++ "STATUS_TPM_DUPLICATE_VHANDLE", ++ "STATUS_TPM_EMBEDDED_COMMAND_BLOCKED", ++ "STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED", ++ "STATUS_TPM_RETRY", ++ "STATUS_TPM_NEEDS_SELFTEST", ++ "STATUS_TPM_DOING_SELFTEST", ++ "STATUS_TPM_DEFEND_LOCK_RUNNING", ++ "STATUS_TPM_COMMAND_CANCELED", ++ "STATUS_TPM_TOO_MANY_CONTEXTS", ++ "STATUS_TPM_NOT_FOUND", ++ "STATUS_TPM_ACCESS_DENIED", ++ "STATUS_TPM_INSUFFICIENT_BUFFER", ++ "STATUS_TPM_PPI_FUNCTION_UNSUPPORTED", ++ "STATUS_PCP_ERROR_MASK", ++ "STATUS_PCP_DEVICE_NOT_READY", ++ "STATUS_PCP_INVALID_HANDLE", ++ "STATUS_PCP_INVALID_PARAMETER", ++ "STATUS_PCP_FLAG_NOT_SUPPORTED", ++ "STATUS_PCP_NOT_SUPPORTED", ++ "STATUS_PCP_BUFFER_TOO_SMALL", ++ "STATUS_PCP_INTERNAL_ERROR", ++ "STATUS_PCP_AUTHENTICATION_FAILED", ++ "STATUS_PCP_AUTHENTICATION_IGNORED", ++ "STATUS_PCP_POLICY_NOT_FOUND", ++ "STATUS_PCP_PROFILE_NOT_FOUND", ++ "STATUS_PCP_VALIDATION_FAILED", ++ "STATUS_PCP_DEVICE_NOT_FOUND", ++ "STATUS_PCP_WRONG_PARENT", ++ "STATUS_PCP_KEY_NOT_LOADED", ++ "STATUS_PCP_NO_KEY_CERTIFICATION", ++ "STATUS_PCP_KEY_NOT_FINALIZED", ++ "STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET", ++ "STATUS_PCP_NOT_PCR_BOUND", ++ "STATUS_PCP_KEY_ALREADY_FINALIZED", ++ "STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED", ++ "STATUS_PCP_KEY_USAGE_POLICY_INVALID", ++ "STATUS_PCP_SOFT_KEY_ERROR", ++ "STATUS_PCP_KEY_NOT_AUTHENTICATED", ++ "STATUS_PCP_KEY_NOT_AIK", ++ "STATUS_PCP_KEY_NOT_SIGNING_KEY", ++ "STATUS_PCP_LOCKED_OUT", ++ "STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED", ++ "STATUS_PCP_TPM_VERSION_NOT_SUPPORTED", ++ "STATUS_PCP_BUFFER_LENGTH_MISMATCH", ++ "STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED", ++ "STATUS_PCP_TICKET_MISSING", ++ "STATUS_PCP_RAW_POLICY_NOT_SUPPORTED", ++ "STATUS_PCP_KEY_HANDLE_INVALIDATED", ++ "STATUS_RTPM_NO_RESULT", ++ "STATUS_RTPM_PCR_READ_INCOMPLETE", ++ "STATUS_RTPM_INVALID_CONTEXT", ++ "STATUS_RTPM_UNSUPPORTED_CMD", ++ "STATUS_TPM_ZERO_EXHAUST_ENABLED", ++ "STATUS_HV_INVALID_HYPERCALL_CODE", ++ "STATUS_HV_INVALID_HYPERCALL_INPUT", ++ "STATUS_HV_INVALID_ALIGNMENT", ++ "STATUS_HV_INVALID_PARAMETER", ++ "STATUS_HV_ACCESS_DENIED", ++ "STATUS_HV_INVALID_PARTITION_STATE", ++ "STATUS_HV_OPERATION_DENIED", ++ "STATUS_HV_UNKNOWN_PROPERTY", ++ "STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE", ++ "STATUS_HV_INSUFFICIENT_MEMORY", ++ "STATUS_HV_PARTITION_TOO_DEEP", ++ "STATUS_HV_INVALID_PARTITION_ID", ++ "STATUS_HV_INVALID_VP_INDEX", ++ "STATUS_HV_INVALID_PORT_ID", ++ "STATUS_HV_INVALID_CONNECTION_ID", ++ "STATUS_HV_INSUFFICIENT_BUFFERS", ++ "STATUS_HV_NOT_ACKNOWLEDGED", ++ "STATUS_HV_INVALID_VP_STATE", ++ "STATUS_HV_ACKNOWLEDGED", ++ "STATUS_HV_INVALID_SAVE_RESTORE_STATE", ++ "STATUS_HV_INVALID_SYNIC_STATE", ++ "STATUS_HV_OBJECT_IN_USE", ++ "STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO", ++ "STATUS_HV_NO_DATA", ++ "STATUS_HV_INACTIVE", ++ "STATUS_HV_NO_RESOURCES", ++ "STATUS_HV_FEATURE_UNAVAILABLE", ++ "STATUS_HV_INSUFFICIENT_BUFFER", ++ "STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS", ++ "STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR", ++ "STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR", ++ "STATUS_HV_PROCESSOR_STARTUP_TIMEOUT", ++ "STATUS_HV_SMX_ENABLED", ++ "STATUS_HV_INVALID_LP_INDEX", ++ "STATUS_HV_INVALID_REGISTER_VALUE", ++ "STATUS_HV_INVALID_VTL_STATE", ++ "STATUS_HV_NX_NOT_DETECTED", ++ "STATUS_HV_INVALID_DEVICE_ID", ++ "STATUS_HV_INVALID_DEVICE_STATE", ++ "STATUS_HV_PAGE_REQUEST_INVALID", ++ "STATUS_HV_INVALID_CPU_GROUP_ID", ++ "STATUS_HV_INVALID_CPU_GROUP_STATE", ++ "STATUS_HV_OPERATION_FAILED", ++ "STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE", ++ "STATUS_HV_INSUFFICIENT_ROOT_MEMORY", ++ "STATUS_HV_EVENT_BUFFER_ALREADY_FREED", ++ "STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY", ++ "STATUS_HV_NOT_PRESENT", ++ "STATUS_IPSEC_BAD_SPI", ++ "STATUS_IPSEC_SA_LIFETIME_EXPIRED", ++ "STATUS_IPSEC_WRONG_SA", ++ "STATUS_IPSEC_REPLAY_CHECK_FAILED", ++ "STATUS_IPSEC_INVALID_PACKET", ++ "STATUS_IPSEC_INTEGRITY_CHECK_FAILED", ++ "STATUS_IPSEC_CLEAR_TEXT_DROP", ++ "STATUS_IPSEC_AUTH_FIREWALL_DROP", ++ "STATUS_IPSEC_THROTTLE_DROP", ++ "STATUS_IPSEC_DOSP_BLOCK", ++ "STATUS_IPSEC_DOSP_RECEIVED_MULTICAST", ++ "STATUS_IPSEC_DOSP_INVALID_PACKET", ++ "STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED", ++ "STATUS_IPSEC_DOSP_MAX_ENTRIES", ++ "STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED", ++ "STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES", ++ "STATUS_VID_DUPLICATE_HANDLER", ++ "STATUS_VID_TOO_MANY_HANDLERS", ++ "STATUS_VID_QUEUE_FULL", ++ "STATUS_VID_HANDLER_NOT_PRESENT", ++ "STATUS_VID_INVALID_OBJECT_NAME", ++ "STATUS_VID_PARTITION_NAME_TOO_LONG", ++ "STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG", ++ "STATUS_VID_PARTITION_ALREADY_EXISTS", ++ "STATUS_VID_PARTITION_DOES_NOT_EXIST", ++ "STATUS_VID_PARTITION_NAME_NOT_FOUND", ++ "STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS", ++ "STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT", ++ "STATUS_VID_MB_STILL_REFERENCED", ++ "STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED", ++ "STATUS_VID_INVALID_NUMA_SETTINGS", ++ "STATUS_VID_INVALID_NUMA_NODE_INDEX", ++ "STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED", ++ "STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE", ++ "STATUS_VID_PAGE_RANGE_OVERFLOW", ++ "STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE", ++ "STATUS_VID_INVALID_GPA_RANGE_HANDLE", ++ "STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE", ++ "STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED", ++ "STATUS_VID_INVALID_PPM_HANDLE", ++ "STATUS_VID_MBPS_ARE_LOCKED", ++ "STATUS_VID_MESSAGE_QUEUE_CLOSED", ++ "STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED", ++ "STATUS_VID_STOP_PENDING", ++ "STATUS_VID_INVALID_PROCESSOR_STATE", ++ "STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT", ++ "STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED", ++ "STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET", ++ "STATUS_VID_MMIO_RANGE_DESTROYED", ++ "STATUS_VID_INVALID_CHILD_GPA_PAGE_SET", ++ "STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED", ++ "STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL", ++ "STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE", ++ "STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT", ++ "STATUS_VID_SAVED_STATE_CORRUPT", ++ "STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM", ++ "STATUS_VID_SAVED_STATE_INCOMPATIBLE", ++ "STATUS_VID_VTL_ACCESS_DENIED", ++ "STATUS_VOLMGR_DATABASE_FULL", ++ "STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED", ++ "STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC", ++ "STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED", ++ "STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME", ++ "STATUS_VOLMGR_DISK_DUPLICATE", ++ "STATUS_VOLMGR_DISK_DYNAMIC", ++ "STATUS_VOLMGR_DISK_ID_INVALID", ++ "STATUS_VOLMGR_DISK_INVALID", ++ "STATUS_VOLMGR_DISK_LAST_VOTER", ++ "STATUS_VOLMGR_DISK_LAYOUT_INVALID", ++ "STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS", ++ "STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED", ++ "STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL", ++ "STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS", ++ "STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS", ++ "STATUS_VOLMGR_DISK_MISSING", ++ "STATUS_VOLMGR_DISK_NOT_EMPTY", ++ "STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE", ++ "STATUS_VOLMGR_DISK_REVECTORING_FAILED", ++ "STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID", ++ "STATUS_VOLMGR_DISK_SET_NOT_CONTAINED", ++ "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS", ++ "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES", ++ "STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED", ++ "STATUS_VOLMGR_EXTENT_ALREADY_USED", ++ "STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS", ++ "STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION", ++ "STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED", ++ "STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION", ++ "STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH", ++ "STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED", ++ "STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID", ++ "STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS", ++ "STATUS_VOLMGR_MEMBER_IN_SYNC", ++ "STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE", ++ "STATUS_VOLMGR_MEMBER_INDEX_INVALID", ++ "STATUS_VOLMGR_MEMBER_MISSING", ++ "STATUS_VOLMGR_MEMBER_NOT_DETACHED", ++ "STATUS_VOLMGR_MEMBER_REGENERATING", ++ "STATUS_VOLMGR_ALL_DISKS_FAILED", ++ "STATUS_VOLMGR_NO_REGISTERED_USERS", ++ "STATUS_VOLMGR_NO_SUCH_USER", ++ "STATUS_VOLMGR_NOTIFICATION_RESET", ++ "STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID", ++ "STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID", ++ "STATUS_VOLMGR_PACK_DUPLICATE", ++ "STATUS_VOLMGR_PACK_ID_INVALID", ++ "STATUS_VOLMGR_PACK_INVALID", ++ "STATUS_VOLMGR_PACK_NAME_INVALID", ++ "STATUS_VOLMGR_PACK_OFFLINE", ++ "STATUS_VOLMGR_PACK_HAS_QUORUM", ++ "STATUS_VOLMGR_PACK_WITHOUT_QUORUM", ++ "STATUS_VOLMGR_PARTITION_STYLE_INVALID", ++ "STATUS_VOLMGR_PARTITION_UPDATE_FAILED", ++ "STATUS_VOLMGR_PLEX_IN_SYNC", ++ "STATUS_VOLMGR_PLEX_INDEX_DUPLICATE", ++ "STATUS_VOLMGR_PLEX_INDEX_INVALID", ++ "STATUS_VOLMGR_PLEX_LAST_ACTIVE", ++ "STATUS_VOLMGR_PLEX_MISSING", ++ "STATUS_VOLMGR_PLEX_REGENERATING", ++ "STATUS_VOLMGR_PLEX_TYPE_INVALID", ++ "STATUS_VOLMGR_PLEX_NOT_RAID5", ++ "STATUS_VOLMGR_PLEX_NOT_SIMPLE", ++ "STATUS_VOLMGR_STRUCTURE_SIZE_INVALID", ++ "STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS", ++ "STATUS_VOLMGR_TRANSACTION_IN_PROGRESS", ++ "STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE", ++ "STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK", ++ "STATUS_VOLMGR_VOLUME_ID_INVALID", ++ "STATUS_VOLMGR_VOLUME_LENGTH_INVALID", ++ "STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE", ++ "STATUS_VOLMGR_VOLUME_NOT_MIRRORED", ++ "STATUS_VOLMGR_VOLUME_NOT_RETAINED", ++ "STATUS_VOLMGR_VOLUME_OFFLINE", ++ "STATUS_VOLMGR_VOLUME_RETAINED", ++ "STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID", ++ "STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE", ++ "STATUS_VOLMGR_BAD_BOOT_DISK", ++ "STATUS_VOLMGR_PACK_CONFIG_OFFLINE", ++ "STATUS_VOLMGR_PACK_CONFIG_ONLINE", ++ "STATUS_VOLMGR_NOT_PRIMARY_PACK", ++ "STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED", ++ "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID", ++ "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID", ++ "STATUS_VOLMGR_VOLUME_MIRRORED", ++ "STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED", ++ "STATUS_VOLMGR_NO_VALID_LOG_COPIES", ++ "STATUS_VOLMGR_PRIMARY_PACK_PRESENT", ++ "STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID", ++ "STATUS_VOLMGR_MIRROR_NOT_SUPPORTED", ++ "STATUS_VOLMGR_RAID5_NOT_SUPPORTED", ++ "STATUS_BCD_TOO_MANY_ELEMENTS", ++ "STATUS_VHD_DRIVE_FOOTER_MISSING", ++ "STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH", ++ "STATUS_VHD_DRIVE_FOOTER_CORRUPT", ++ "STATUS_VHD_FORMAT_UNKNOWN", ++ "STATUS_VHD_FORMAT_UNSUPPORTED_VERSION", ++ "STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH", ++ "STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION", ++ "STATUS_VHD_SPARSE_HEADER_CORRUPT", ++ "STATUS_VHD_BLOCK_ALLOCATION_FAILURE", ++ "STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT", ++ "STATUS_VHD_INVALID_BLOCK_SIZE", ++ "STATUS_VHD_BITMAP_MISMATCH", ++ "STATUS_VHD_PARENT_VHD_NOT_FOUND", ++ "STATUS_VHD_CHILD_PARENT_ID_MISMATCH", ++ "STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH", ++ "STATUS_VHD_METADATA_READ_FAILURE", ++ "STATUS_VHD_METADATA_WRITE_FAILURE", ++ "STATUS_VHD_INVALID_SIZE", ++ "STATUS_VHD_INVALID_FILE_SIZE", ++ "STATUS_VIRTDISK_PROVIDER_NOT_FOUND", ++ "STATUS_VIRTDISK_NOT_VIRTUAL_DISK", ++ "STATUS_VHD_PARENT_VHD_ACCESS_DENIED", ++ "STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH", ++ "STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED", ++ "STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT", ++ "STATUS_VIRTUAL_DISK_LIMITATION", ++ "STATUS_VHD_INVALID_TYPE", ++ "STATUS_VHD_INVALID_STATE", ++ "STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE", ++ "STATUS_VIRTDISK_DISK_ALREADY_OWNED", ++ "STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE", ++ "STATUS_CTLOG_TRACKING_NOT_INITIALIZED", ++ "STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE", ++ "STATUS_CTLOG_VHD_CHANGED_OFFLINE", ++ "STATUS_CTLOG_INVALID_TRACKING_STATE", ++ "STATUS_CTLOG_INCONSISTENT_TRACKING_FILE", ++ "STATUS_VHD_METADATA_FULL", ++ "STATUS_VHD_INVALID_CHANGE_TRACKING_ID", ++ "STATUS_VHD_CHANGE_TRACKING_DISABLED", ++ "STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION", ++ "STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA", ++ "STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE", ++ "STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE", ++ "STATUS_RKF_KEY_NOT_FOUND", ++ "STATUS_RKF_DUPLICATE_KEY", ++ "STATUS_RKF_BLOB_FULL", ++ "STATUS_RKF_STORE_FULL", ++ "STATUS_RKF_FILE_BLOCKED", ++ "STATUS_RKF_ACTIVE_KEY", ++ "STATUS_RDBSS_RESTART_OPERATION", ++ "STATUS_RDBSS_CONTINUE_OPERATION", ++ "STATUS_RDBSS_POST_OPERATION", ++ "STATUS_RDBSS_RETRY_LOOKUP", ++ "STATUS_BTH_ATT_INVALID_HANDLE", ++ "STATUS_BTH_ATT_READ_NOT_PERMITTED", ++ "STATUS_BTH_ATT_WRITE_NOT_PERMITTED", ++ "STATUS_BTH_ATT_INVALID_PDU", ++ "STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION", ++ "STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED", ++ "STATUS_BTH_ATT_INVALID_OFFSET", ++ "STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION", ++ "STATUS_BTH_ATT_PREPARE_QUEUE_FULL", ++ "STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND", ++ "STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG", ++ "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE", ++ "STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH", ++ "STATUS_BTH_ATT_UNLIKELY", ++ "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION", ++ "STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE", ++ "STATUS_BTH_ATT_INSUFFICIENT_RESOURCES", ++ "STATUS_BTH_ATT_UNKNOWN_ERROR", ++ "STATUS_SECUREBOOT_ROLLBACK_DETECTED", ++ "STATUS_SECUREBOOT_POLICY_VIOLATION", ++ "STATUS_SECUREBOOT_INVALID_POLICY", ++ "STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND", ++ "STATUS_SECUREBOOT_POLICY_NOT_SIGNED", ++ "STATUS_SECUREBOOT_FILE_REPLACED", ++ "STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED", ++ "STATUS_SECUREBOOT_POLICY_UNKNOWN", ++ "STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION", ++ "STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH", ++ "STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED", ++ "STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH", ++ "STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING", ++ "STATUS_SECUREBOOT_NOT_BASE_POLICY", ++ "STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY", ++ "STATUS_AUDIO_ENGINE_NODE_NOT_FOUND", ++ "STATUS_HDAUDIO_EMPTY_CONNECTION_LIST", ++ "STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED", ++ "STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED", ++ "STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY", ++ "STATUS_VSM_NOT_INITIALIZED", ++ "STATUS_VSM_DMA_PROTECTION_NOT_IN_USE", ++ "STATUS_VOLSNAP_BOOTFILE_NOT_VALID", ++ "STATUS_VOLSNAP_ACTIVATION_TIMEOUT", ++ "STATUS_IO_PREEMPTED", ++ "STATUS_SVHDX_ERROR_STORED", ++ "STATUS_SVHDX_ERROR_NOT_AVAILABLE", ++ "STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE", ++ "STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED", ++ "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED", ++ "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED", ++ "STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED", ++ "STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED", ++ "STATUS_SVHDX_RESERVATION_CONFLICT", ++ "STATUS_SVHDX_WRONG_FILE_TYPE", ++ "STATUS_SVHDX_VERSION_MISMATCH", ++ "STATUS_VHD_SHARED", ++ "STATUS_SVHDX_NO_INITIATOR", ++ "STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND", ++ "STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", ++ "STATUS_SMB_BAD_CLUSTER_DIALECT", ++ "STATUS_SMB_GUEST_LOGON_BLOCKED", ++ "STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID", ++ "STATUS_SPACES_RESILIENCY_TYPE_INVALID", ++ "STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID", ++ "STATUS_SPACES_DRIVE_REDUNDANCY_INVALID", ++ "STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID", ++ "STATUS_SPACES_INTERLEAVE_LENGTH_INVALID", ++ "STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID", ++ "STATUS_SPACES_NOT_ENOUGH_DRIVES", ++ "STATUS_SPACES_EXTENDED_ERROR", ++ "STATUS_SPACES_PROVISIONING_TYPE_INVALID", ++ "STATUS_SPACES_ALLOCATION_SIZE_INVALID", ++ "STATUS_SPACES_ENCLOSURE_AWARE_INVALID", ++ "STATUS_SPACES_WRITE_CACHE_SIZE_INVALID", ++ "STATUS_SPACES_NUMBER_OF_GROUPS_INVALID", ++ "STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID", ++ "STATUS_SPACES_UPDATE_COLUMN_STATE", ++ "STATUS_SPACES_MAP_REQUIRED", ++ "STATUS_SPACES_UNSUPPORTED_VERSION", ++ "STATUS_SPACES_CORRUPT_METADATA", ++ "STATUS_SPACES_DRT_FULL", ++ "STATUS_SPACES_INCONSISTENCY", ++ "STATUS_SPACES_LOG_NOT_READY", ++ "STATUS_SPACES_NO_REDUNDANCY", ++ "STATUS_SPACES_DRIVE_NOT_READY", ++ "STATUS_SPACES_DRIVE_SPLIT", ++ "STATUS_SPACES_DRIVE_LOST_DATA", ++ "STATUS_SPACES_ENTRY_INCOMPLETE", ++ "STATUS_SPACES_ENTRY_INVALID", ++ "STATUS_SPACES_MARK_DIRTY", ++ "STATUS_SECCORE_INVALID_COMMAND", ++ "STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED", ++ "STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION", ++ "STATUS_SYSTEM_INTEGRITY_INVALID_POLICY", ++ "STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED", ++ "STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES", ++ "STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED", ++ "STATUS_NO_APPLICABLE_APP_LICENSES_FOUND", ++ "STATUS_CLIP_LICENSE_NOT_FOUND", ++ "STATUS_CLIP_DEVICE_LICENSE_MISSING", ++ "STATUS_CLIP_LICENSE_INVALID_SIGNATURE", ++ "STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID", ++ "STATUS_CLIP_LICENSE_EXPIRED", ++ "STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE", ++ "STATUS_CLIP_LICENSE_NOT_SIGNED", ++ "STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE", ++ "STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH", ++ "STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED", ++ "STATUS_PLATFORM_MANIFEST_INVALID", ++ "STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED", ++ "STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED", ++ "STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND", ++ "STATUS_PLATFORM_MANIFEST_NOT_ACTIVE", ++ "STATUS_PLATFORM_MANIFEST_NOT_SIGNED", ++ "STATUS_APPEXEC_CONDITION_NOT_SATISFIED", ++ "STATUS_APPEXEC_HANDLE_INVALIDATED", ++ "STATUS_APPEXEC_INVALID_HOST_GENERATION", ++ "STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION", ++ "STATUS_APPEXEC_INVALID_HOST_STATE", ++ "STATUS_APPEXEC_NO_DONOR", ++ "STATUS_APPEXEC_HOST_ID_MISMATCH", ++ "STATUS_APPEXEC_UNKNOWN_USER", ++}; ++ ++const char* NTStatusToString(uint32_t ntstatus) { ++ auto itr = std::find(std::begin(kNTStatusValues), ++ std::end(kNTStatusValues), ++ ntstatus); ++ if (itr == std::end(kNTStatusValues)) { ++ return nullptr; + } +- return reason; ++ ++ return kNTStatusStrings[itr - std::begin(kNTStatusValues)]; + } + +-string FastFailToString(uint32_t fast_fail_code) { +- string code_string; +- // The content of this switch was created from winnt.h in the 10 SDK +- // (version 10.0.19041.0) with +- // +- // egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h +- // | tr -d '\r' +- // | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' +- // | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ case MD_FAST_FAIL_WIN_\2:\n code_string = "FAST_FAIL_\2";\n break;@' +- // +- // and then the default case added. +- switch (fast_fail_code) { +- case MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION: +- code_string = "FAST_FAIL_LEGACY_GS_VIOLATION"; +- break; +- case MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE: +- code_string = "FAST_FAIL_VTGUARD_CHECK_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE: +- code_string = "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY: +- code_string = "FAST_FAIL_CORRUPT_LIST_ENTRY"; +- break; +- case MD_FAST_FAIL_WIN_INCORRECT_STACK: +- code_string = "FAST_FAIL_INCORRECT_STACK"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_ARG: +- code_string = "FAST_FAIL_INVALID_ARG"; +- break; +- case MD_FAST_FAIL_WIN_GS_COOKIE_INIT: +- code_string = "FAST_FAIL_GS_COOKIE_INIT"; +- break; +- case MD_FAST_FAIL_WIN_FATAL_APP_EXIT: +- code_string = "FAST_FAIL_FATAL_APP_EXIT"; +- break; +- case MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE: +- code_string = "FAST_FAIL_RANGE_CHECK_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS: +- code_string = "FAST_FAIL_UNSAFE_REGISTRY_ACCESS"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE: +- code_string = "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE: +- code_string = "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH: +- code_string = "FAST_FAIL_INVALID_FIBER_SWITCH"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT: +- code_string = "FAST_FAIL_INVALID_SET_OF_CONTEXT"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT: +- code_string = "FAST_FAIL_INVALID_REFERENCE_COUNT"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER: +- code_string = "FAST_FAIL_INVALID_JUMP_BUFFER"; +- break; +- case MD_FAST_FAIL_WIN_MRDATA_MODIFIED: +- code_string = "FAST_FAIL_MRDATA_MODIFIED"; +- break; +- case MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE: +- code_string = "FAST_FAIL_CERTIFICATION_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN: +- code_string = "FAST_FAIL_INVALID_EXCEPTION_CHAIN"; +- break; +- case MD_FAST_FAIL_WIN_CRYPTO_LIBRARY: +- code_string = "FAST_FAIL_CRYPTO_LIBRARY"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT: +- code_string = "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE: +- code_string = "FAST_FAIL_INVALID_IMAGE_BASE"; +- break; +- case MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE: +- code_string = "FAST_FAIL_DLOAD_PROTECTION_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL: +- code_string = "FAST_FAIL_UNSAFE_EXTENSION_CALL"; +- break; +- case MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED: +- code_string = "FAST_FAIL_DEPRECATED_SERVICE_INVOKED"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS: +- code_string = "FAST_FAIL_INVALID_BUFFER_ACCESS"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE: +- code_string = "FAST_FAIL_INVALID_BALANCED_TREE"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD: +- code_string = "FAST_FAIL_INVALID_NEXT_THREAD"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED: +- code_string = "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED"; +- break; +- case MD_FAST_FAIL_WIN_APCS_DISABLED: +- code_string = "FAST_FAIL_APCS_DISABLED"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_IDLE_STATE: +- code_string = "FAST_FAIL_INVALID_IDLE_STATE"; +- break; +- case MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE: +- code_string = "FAST_FAIL_MRDATA_PROTECTION_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION: +- code_string = "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_LOCK_STATE: +- code_string = "FAST_FAIL_INVALID_LOCK_STATE"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_JUMPTABLE: +- code_string = "FAST_FAIL_GUARD_JUMPTABLE"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET: +- code_string = "FAST_FAIL_INVALID_LONGJUMP_TARGET"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT: +- code_string = "FAST_FAIL_INVALID_DISPATCH_CONTEXT"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_THREAD: +- code_string = "FAST_FAIL_INVALID_THREAD"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER: +- code_string = "FAST_FAIL_INVALID_SYSCALL_NUMBER"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION: +- code_string = "FAST_FAIL_INVALID_FILE_OPERATION"; +- break; +- case MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED: +- code_string = "FAST_FAIL_LPAC_ACCESS_DENIED"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_SS_FAILURE: +- code_string = "FAST_FAIL_GUARD_SS_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE: +- code_string = "FAST_FAIL_LOADER_CONTINUITY_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE: +- code_string = "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK: +- code_string = "FAST_FAIL_INVALID_CONTROL_STACK"; +- break; +- case MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED: +- code_string = "FAST_FAIL_SET_CONTEXT_DENIED"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_IAT: +- code_string = "FAST_FAIL_INVALID_IAT"; +- break; +- case MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION: +- code_string = "FAST_FAIL_HEAP_METADATA_CORRUPTION"; +- break; +- case MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION: +- code_string = "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION"; +- break; +- case MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED: +- code_string = "FAST_FAIL_LOW_LABEL_ACCESS_DENIED"; +- break; +- case MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE: +- code_string = "FAST_FAIL_ENCLAVE_CALL_FAILURE"; +- break; +- case MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON: +- code_string = "FAST_FAIL_UNHANDLED_LSS_EXCEPTON"; +- break; +- case MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED: +- code_string = "FAST_FAIL_ADMINLESS_ACCESS_DENIED"; +- break; +- case MD_FAST_FAIL_WIN_UNEXPECTED_CALL: +- code_string = "FAST_FAIL_UNEXPECTED_CALL"; +- break; +- case MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS: +- code_string = "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS"; +- break; +- case MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR: +- code_string = "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR"; +- break; +- case MD_FAST_FAIL_WIN_FLAGS_CORRUPTION: +- code_string = "FAST_FAIL_FLAGS_CORRUPTION"; +- break; +- case MD_FAST_FAIL_WIN_VEH_CORRUPTION: +- code_string = "FAST_FAIL_VEH_CORRUPTION"; +- break; +- case MD_FAST_FAIL_WIN_ETW_CORRUPTION: +- code_string = "FAST_FAIL_ETW_CORRUPTION"; +- break; +- case MD_FAST_FAIL_WIN_RIO_ABORT: +- code_string = "FAST_FAIL_RIO_ABORT"; +- break; +- case MD_FAST_FAIL_WIN_INVALID_PFN: +- code_string = "FAST_FAIL_INVALID_PFN"; +- break; +- default: { +- char buffer[11]; +- snprintf(buffer, sizeof(buffer), "%u", fast_fail_code); +- code_string = buffer; +- break; +- } ++// The content of this array was created from winnt.h in the 10 SDK ++// (version 10.0.19041.0) with the following script: ++// ++// egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h ++// | tr -d '\r' ++// | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' ++// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_FAST_FAIL_WIN_\2,@' ++// | head -n -1 ++static const uint8_t kFastFailValues[] = { ++ MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION, ++ MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE, ++ MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE, ++ MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY, ++ MD_FAST_FAIL_WIN_INCORRECT_STACK, ++ MD_FAST_FAIL_WIN_INVALID_ARG, ++ MD_FAST_FAIL_WIN_GS_COOKIE_INIT, ++ MD_FAST_FAIL_WIN_FATAL_APP_EXIT, ++ MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE, ++ MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS, ++ MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE, ++ MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE, ++ MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH, ++ MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT, ++ MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT, ++ MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER, ++ MD_FAST_FAIL_WIN_MRDATA_MODIFIED, ++ MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE, ++ MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN, ++ MD_FAST_FAIL_WIN_CRYPTO_LIBRARY, ++ MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT, ++ MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE, ++ MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE, ++ MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL, ++ MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED, ++ MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS, ++ MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE, ++ MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD, ++ MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED, ++ MD_FAST_FAIL_WIN_APCS_DISABLED, ++ MD_FAST_FAIL_WIN_INVALID_IDLE_STATE, ++ MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE, ++ MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION, ++ MD_FAST_FAIL_WIN_INVALID_LOCK_STATE, ++ MD_FAST_FAIL_WIN_GUARD_JUMPTABLE, ++ MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET, ++ MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT, ++ MD_FAST_FAIL_WIN_INVALID_THREAD, ++ MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER, ++ MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION, ++ MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED, ++ MD_FAST_FAIL_WIN_GUARD_SS_FAILURE, ++ MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE, ++ MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE, ++ MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK, ++ MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED, ++ MD_FAST_FAIL_WIN_INVALID_IAT, ++ MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION, ++ MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION, ++ MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED, ++ MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE, ++ MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON, ++ MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED, ++ MD_FAST_FAIL_WIN_UNEXPECTED_CALL, ++ MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS, ++ MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR, ++ MD_FAST_FAIL_WIN_FLAGS_CORRUPTION, ++ MD_FAST_FAIL_WIN_VEH_CORRUPTION, ++ MD_FAST_FAIL_WIN_ETW_CORRUPTION, ++ MD_FAST_FAIL_WIN_RIO_ABORT, ++ MD_FAST_FAIL_WIN_INVALID_PFN, ++}; ++ ++// The content of this array was created from winnt.h in the 10 SDK ++// (version 10.0.19041.0) with the following script: ++// ++// egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h ++// | tr -d '\r' ++// | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' ++// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ "FAST_FAIL_\2",@' ++// | head -n -1 ++static const char* kFastFailStrings[] = { ++ "FAST_FAIL_LEGACY_GS_VIOLATION", ++ "FAST_FAIL_VTGUARD_CHECK_FAILURE", ++ "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE", ++ "FAST_FAIL_CORRUPT_LIST_ENTRY", ++ "FAST_FAIL_INCORRECT_STACK", ++ "FAST_FAIL_INVALID_ARG", ++ "FAST_FAIL_GS_COOKIE_INIT", ++ "FAST_FAIL_FATAL_APP_EXIT", ++ "FAST_FAIL_RANGE_CHECK_FAILURE", ++ "FAST_FAIL_UNSAFE_REGISTRY_ACCESS", ++ "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE", ++ "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE", ++ "FAST_FAIL_INVALID_FIBER_SWITCH", ++ "FAST_FAIL_INVALID_SET_OF_CONTEXT", ++ "FAST_FAIL_INVALID_REFERENCE_COUNT", ++ "FAST_FAIL_INVALID_JUMP_BUFFER", ++ "FAST_FAIL_MRDATA_MODIFIED", ++ "FAST_FAIL_CERTIFICATION_FAILURE", ++ "FAST_FAIL_INVALID_EXCEPTION_CHAIN", ++ "FAST_FAIL_CRYPTO_LIBRARY", ++ "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT", ++ "FAST_FAIL_INVALID_IMAGE_BASE", ++ "FAST_FAIL_DLOAD_PROTECTION_FAILURE", ++ "FAST_FAIL_UNSAFE_EXTENSION_CALL", ++ "FAST_FAIL_DEPRECATED_SERVICE_INVOKED", ++ "FAST_FAIL_INVALID_BUFFER_ACCESS", ++ "FAST_FAIL_INVALID_BALANCED_TREE", ++ "FAST_FAIL_INVALID_NEXT_THREAD", ++ "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED", ++ "FAST_FAIL_APCS_DISABLED", ++ "FAST_FAIL_INVALID_IDLE_STATE", ++ "FAST_FAIL_MRDATA_PROTECTION_FAILURE", ++ "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION", ++ "FAST_FAIL_INVALID_LOCK_STATE", ++ "FAST_FAIL_GUARD_JUMPTABLE", ++ "FAST_FAIL_INVALID_LONGJUMP_TARGET", ++ "FAST_FAIL_INVALID_DISPATCH_CONTEXT", ++ "FAST_FAIL_INVALID_THREAD", ++ "FAST_FAIL_INVALID_SYSCALL_NUMBER", ++ "FAST_FAIL_INVALID_FILE_OPERATION", ++ "FAST_FAIL_LPAC_ACCESS_DENIED", ++ "FAST_FAIL_GUARD_SS_FAILURE", ++ "FAST_FAIL_LOADER_CONTINUITY_FAILURE", ++ "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE", ++ "FAST_FAIL_INVALID_CONTROL_STACK", ++ "FAST_FAIL_SET_CONTEXT_DENIED", ++ "FAST_FAIL_INVALID_IAT", ++ "FAST_FAIL_HEAP_METADATA_CORRUPTION", ++ "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION", ++ "FAST_FAIL_LOW_LABEL_ACCESS_DENIED", ++ "FAST_FAIL_ENCLAVE_CALL_FAILURE", ++ "FAST_FAIL_UNHANDLED_LSS_EXCEPTON", ++ "FAST_FAIL_ADMINLESS_ACCESS_DENIED", ++ "FAST_FAIL_UNEXPECTED_CALL", ++ "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS", ++ "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR", ++ "FAST_FAIL_FLAGS_CORRUPTION", ++ "FAST_FAIL_VEH_CORRUPTION", ++ "FAST_FAIL_ETW_CORRUPTION", ++ "FAST_FAIL_RIO_ABORT", ++ "FAST_FAIL_INVALID_PFN", ++}; ++ ++const char* FastFailToString(uint32_t fast_fail_code) { ++ auto itr = std::find(std::begin(kFastFailValues), ++ std::end(kFastFailValues), ++ fast_fail_code); ++ if (itr == std::end(kFastFailValues)) { ++ return nullptr; + } +- return code_string; ++ ++ return kFastFailStrings[itr - std::begin(kFastFailValues)]; ++} ++ ++// The content of this array was created from winerror.h in the 10 SDK ++// (version 10.0.19041.0) with the following script: ++// ++// egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h ++// | tr -d '\r' ++// | sed -r 's@#define ERROR_([A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' ++// | sort -n ++// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_ERROR_WIN_\2,@' ++static const uint16_t kWinErrorValues[] = { ++ MD_ERROR_WIN_SUCCESS, ++ MD_ERROR_WIN_INVALID_FUNCTION, ++ MD_ERROR_WIN_FILE_NOT_FOUND, ++ MD_ERROR_WIN_PATH_NOT_FOUND, ++ MD_ERROR_WIN_TOO_MANY_OPEN_FILES, ++ MD_ERROR_WIN_ACCESS_DENIED, ++ MD_ERROR_WIN_INVALID_HANDLE, ++ MD_ERROR_WIN_ARENA_TRASHED, ++ MD_ERROR_WIN_NOT_ENOUGH_MEMORY, ++ MD_ERROR_WIN_INVALID_BLOCK, ++ MD_ERROR_WIN_BAD_ENVIRONMENT, ++ MD_ERROR_WIN_BAD_FORMAT, ++ MD_ERROR_WIN_INVALID_ACCESS, ++ MD_ERROR_WIN_INVALID_DATA, ++ MD_ERROR_WIN_OUTOFMEMORY, ++ MD_ERROR_WIN_INVALID_DRIVE, ++ MD_ERROR_WIN_CURRENT_DIRECTORY, ++ MD_ERROR_WIN_NOT_SAME_DEVICE, ++ MD_ERROR_WIN_NO_MORE_FILES, ++ MD_ERROR_WIN_WRITE_PROTECT, ++ MD_ERROR_WIN_BAD_UNIT, ++ MD_ERROR_WIN_NOT_READY, ++ MD_ERROR_WIN_BAD_COMMAND, ++ MD_ERROR_WIN_CRC, ++ MD_ERROR_WIN_BAD_LENGTH, ++ MD_ERROR_WIN_SEEK, ++ MD_ERROR_WIN_NOT_DOS_DISK, ++ MD_ERROR_WIN_SECTOR_NOT_FOUND, ++ MD_ERROR_WIN_OUT_OF_PAPER, ++ MD_ERROR_WIN_WRITE_FAULT, ++ MD_ERROR_WIN_READ_FAULT, ++ MD_ERROR_WIN_GEN_FAILURE, ++ MD_ERROR_WIN_SHARING_VIOLATION, ++ MD_ERROR_WIN_LOCK_VIOLATION, ++ MD_ERROR_WIN_WRONG_DISK, ++ MD_ERROR_WIN_SHARING_BUFFER_EXCEEDED, ++ MD_ERROR_WIN_HANDLE_EOF, ++ MD_ERROR_WIN_HANDLE_DISK_FULL, ++ MD_ERROR_WIN_NOT_SUPPORTED, ++ MD_ERROR_WIN_REM_NOT_LIST, ++ MD_ERROR_WIN_DUP_NAME, ++ MD_ERROR_WIN_BAD_NETPATH, ++ MD_ERROR_WIN_NETWORK_BUSY, ++ MD_ERROR_WIN_DEV_NOT_EXIST, ++ MD_ERROR_WIN_TOO_MANY_CMDS, ++ MD_ERROR_WIN_ADAP_HDW_ERR, ++ MD_ERROR_WIN_BAD_NET_RESP, ++ MD_ERROR_WIN_UNEXP_NET_ERR, ++ MD_ERROR_WIN_BAD_REM_ADAP, ++ MD_ERROR_WIN_PRINTQ_FULL, ++ MD_ERROR_WIN_NO_SPOOL_SPACE, ++ MD_ERROR_WIN_PRINT_CANCELLED, ++ MD_ERROR_WIN_NETNAME_DELETED, ++ MD_ERROR_WIN_NETWORK_ACCESS_DENIED, ++ MD_ERROR_WIN_BAD_DEV_TYPE, ++ MD_ERROR_WIN_BAD_NET_NAME, ++ MD_ERROR_WIN_TOO_MANY_NAMES, ++ MD_ERROR_WIN_TOO_MANY_SESS, ++ MD_ERROR_WIN_SHARING_PAUSED, ++ MD_ERROR_WIN_REQ_NOT_ACCEP, ++ MD_ERROR_WIN_REDIR_PAUSED, ++ MD_ERROR_WIN_FILE_EXISTS, ++ MD_ERROR_WIN_CANNOT_MAKE, ++ MD_ERROR_WIN_FAIL_I24, ++ MD_ERROR_WIN_OUT_OF_STRUCTURES, ++ MD_ERROR_WIN_ALREADY_ASSIGNED, ++ MD_ERROR_WIN_INVALID_PASSWORD, ++ MD_ERROR_WIN_INVALID_PARAMETER, ++ MD_ERROR_WIN_NET_WRITE_FAULT, ++ MD_ERROR_WIN_NO_PROC_SLOTS, ++ MD_ERROR_WIN_TOO_MANY_SEMAPHORES, ++ MD_ERROR_WIN_EXCL_SEM_ALREADY_OWNED, ++ MD_ERROR_WIN_SEM_IS_SET, ++ MD_ERROR_WIN_TOO_MANY_SEM_REQUESTS, ++ MD_ERROR_WIN_INVALID_AT_INTERRUPT_TIME, ++ MD_ERROR_WIN_SEM_OWNER_DIED, ++ MD_ERROR_WIN_SEM_USER_LIMIT, ++ MD_ERROR_WIN_DISK_CHANGE, ++ MD_ERROR_WIN_DRIVE_LOCKED, ++ MD_ERROR_WIN_BROKEN_PIPE, ++ MD_ERROR_WIN_OPEN_FAILED, ++ MD_ERROR_WIN_BUFFER_OVERFLOW, ++ MD_ERROR_WIN_DISK_FULL, ++ MD_ERROR_WIN_NO_MORE_SEARCH_HANDLES, ++ MD_ERROR_WIN_INVALID_TARGET_HANDLE, ++ MD_ERROR_WIN_INVALID_CATEGORY, ++ MD_ERROR_WIN_INVALID_VERIFY_SWITCH, ++ MD_ERROR_WIN_BAD_DRIVER_LEVEL, ++ MD_ERROR_WIN_CALL_NOT_IMPLEMENTED, ++ MD_ERROR_WIN_SEM_TIMEOUT, ++ MD_ERROR_WIN_INSUFFICIENT_BUFFER, ++ MD_ERROR_WIN_INVALID_NAME, ++ MD_ERROR_WIN_INVALID_LEVEL, ++ MD_ERROR_WIN_NO_VOLUME_LABEL, ++ MD_ERROR_WIN_MOD_NOT_FOUND, ++ MD_ERROR_WIN_PROC_NOT_FOUND, ++ MD_ERROR_WIN_WAIT_NO_CHILDREN, ++ MD_ERROR_WIN_CHILD_NOT_COMPLETE, ++ MD_ERROR_WIN_DIRECT_ACCESS_HANDLE, ++ MD_ERROR_WIN_NEGATIVE_SEEK, ++ MD_ERROR_WIN_SEEK_ON_DEVICE, ++ MD_ERROR_WIN_IS_JOIN_TARGET, ++ MD_ERROR_WIN_IS_JOINED, ++ MD_ERROR_WIN_IS_SUBSTED, ++ MD_ERROR_WIN_NOT_JOINED, ++ MD_ERROR_WIN_NOT_SUBSTED, ++ MD_ERROR_WIN_JOIN_TO_JOIN, ++ MD_ERROR_WIN_SUBST_TO_SUBST, ++ MD_ERROR_WIN_JOIN_TO_SUBST, ++ MD_ERROR_WIN_SUBST_TO_JOIN, ++ MD_ERROR_WIN_BUSY_DRIVE, ++ MD_ERROR_WIN_SAME_DRIVE, ++ MD_ERROR_WIN_DIR_NOT_ROOT, ++ MD_ERROR_WIN_DIR_NOT_EMPTY, ++ MD_ERROR_WIN_IS_SUBST_PATH, ++ MD_ERROR_WIN_IS_JOIN_PATH, ++ MD_ERROR_WIN_PATH_BUSY, ++ MD_ERROR_WIN_IS_SUBST_TARGET, ++ MD_ERROR_WIN_SYSTEM_TRACE, ++ MD_ERROR_WIN_INVALID_EVENT_COUNT, ++ MD_ERROR_WIN_TOO_MANY_MUXWAITERS, ++ MD_ERROR_WIN_INVALID_LIST_FORMAT, ++ MD_ERROR_WIN_LABEL_TOO_LONG, ++ MD_ERROR_WIN_TOO_MANY_TCBS, ++ MD_ERROR_WIN_SIGNAL_REFUSED, ++ MD_ERROR_WIN_DISCARDED, ++ MD_ERROR_WIN_NOT_LOCKED, ++ MD_ERROR_WIN_BAD_THREADID_ADDR, ++ MD_ERROR_WIN_BAD_ARGUMENTS, ++ MD_ERROR_WIN_BAD_PATHNAME, ++ MD_ERROR_WIN_SIGNAL_PENDING, ++ MD_ERROR_WIN_MAX_THRDS_REACHED, ++ MD_ERROR_WIN_LOCK_FAILED, ++ MD_ERROR_WIN_BUSY, ++ MD_ERROR_WIN_DEVICE_SUPPORT_IN_PROGRESS, ++ MD_ERROR_WIN_CANCEL_VIOLATION, ++ MD_ERROR_WIN_ATOMIC_LOCKS_NOT_SUPPORTED, ++ MD_ERROR_WIN_INVALID_SEGMENT_NUMBER, ++ MD_ERROR_WIN_INVALID_ORDINAL, ++ MD_ERROR_WIN_ALREADY_EXISTS, ++ MD_ERROR_WIN_INVALID_FLAG_NUMBER, ++ MD_ERROR_WIN_SEM_NOT_FOUND, ++ MD_ERROR_WIN_INVALID_STARTING_CODESEG, ++ MD_ERROR_WIN_INVALID_STACKSEG, ++ MD_ERROR_WIN_INVALID_MODULETYPE, ++ MD_ERROR_WIN_INVALID_EXE_SIGNATURE, ++ MD_ERROR_WIN_EXE_MARKED_INVALID, ++ MD_ERROR_WIN_BAD_EXE_FORMAT, ++ MD_ERROR_WIN_INVALID_MINALLOCSIZE, ++ MD_ERROR_WIN_DYNLINK_FROM_INVALID_RING, ++ MD_ERROR_WIN_IOPL_NOT_ENABLED, ++ MD_ERROR_WIN_INVALID_SEGDPL, ++ MD_ERROR_WIN_RING2SEG_MUST_BE_MOVABLE, ++ MD_ERROR_WIN_RELOC_CHAIN_XEEDS_SEGLIM, ++ MD_ERROR_WIN_INFLOOP_IN_RELOC_CHAIN, ++ MD_ERROR_WIN_ENVVAR_NOT_FOUND, ++ MD_ERROR_WIN_NO_SIGNAL_SENT, ++ MD_ERROR_WIN_FILENAME_EXCED_RANGE, ++ MD_ERROR_WIN_RING2_STACK_IN_USE, ++ MD_ERROR_WIN_META_EXPANSION_TOO_LONG, ++ MD_ERROR_WIN_INVALID_SIGNAL_NUMBER, ++ MD_ERROR_WIN_THREAD_1_INACTIVE, ++ MD_ERROR_WIN_LOCKED, ++ MD_ERROR_WIN_TOO_MANY_MODULES, ++ MD_ERROR_WIN_NESTING_NOT_ALLOWED, ++ MD_ERROR_WIN_EXE_MACHINE_TYPE_MISMATCH, ++ MD_ERROR_WIN_EXE_CANNOT_MODIFY_SIGNED_BINARY, ++ MD_ERROR_WIN_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY, ++ MD_ERROR_WIN_FILE_CHECKED_OUT, ++ MD_ERROR_WIN_CHECKOUT_REQUIRED, ++ MD_ERROR_WIN_BAD_FILE_TYPE, ++ MD_ERROR_WIN_FILE_TOO_LARGE, ++ MD_ERROR_WIN_FORMS_AUTH_REQUIRED, ++ MD_ERROR_WIN_VIRUS_INFECTED, ++ MD_ERROR_WIN_VIRUS_DELETED, ++ MD_ERROR_WIN_PIPE_LOCAL, ++ MD_ERROR_WIN_BAD_PIPE, ++ MD_ERROR_WIN_PIPE_BUSY, ++ MD_ERROR_WIN_NO_DATA, ++ MD_ERROR_WIN_PIPE_NOT_CONNECTED, ++ MD_ERROR_WIN_MORE_DATA, ++ MD_ERROR_WIN_NO_WORK_DONE, ++ MD_ERROR_WIN_VC_DISCONNECTED, ++ MD_ERROR_WIN_INVALID_EA_NAME, ++ MD_ERROR_WIN_EA_LIST_INCONSISTENT, ++ MD_ERROR_WIN_NO_MORE_ITEMS, ++ MD_ERROR_WIN_CANNOT_COPY, ++ MD_ERROR_WIN_DIRECTORY, ++ MD_ERROR_WIN_EAS_DIDNT_FIT, ++ MD_ERROR_WIN_EA_FILE_CORRUPT, ++ MD_ERROR_WIN_EA_TABLE_FULL, ++ MD_ERROR_WIN_INVALID_EA_HANDLE, ++ MD_ERROR_WIN_EAS_NOT_SUPPORTED, ++ MD_ERROR_WIN_NOT_OWNER, ++ MD_ERROR_WIN_TOO_MANY_POSTS, ++ MD_ERROR_WIN_PARTIAL_COPY, ++ MD_ERROR_WIN_OPLOCK_NOT_GRANTED, ++ MD_ERROR_WIN_INVALID_OPLOCK_PROTOCOL, ++ MD_ERROR_WIN_DISK_TOO_FRAGMENTED, ++ MD_ERROR_WIN_DELETE_PENDING, ++ MD_ERROR_WIN_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING, ++ MD_ERROR_WIN_SHORT_NAMES_NOT_ENABLED_ON_VOLUME, ++ MD_ERROR_WIN_SECURITY_STREAM_IS_INCONSISTENT, ++ MD_ERROR_WIN_INVALID_LOCK_RANGE, ++ MD_ERROR_WIN_IMAGE_SUBSYSTEM_NOT_PRESENT, ++ MD_ERROR_WIN_NOTIFICATION_GUID_ALREADY_DEFINED, ++ MD_ERROR_WIN_INVALID_EXCEPTION_HANDLER, ++ MD_ERROR_WIN_DUPLICATE_PRIVILEGES, ++ MD_ERROR_WIN_NO_RANGES_PROCESSED, ++ MD_ERROR_WIN_NOT_ALLOWED_ON_SYSTEM_FILE, ++ MD_ERROR_WIN_DISK_RESOURCES_EXHAUSTED, ++ MD_ERROR_WIN_INVALID_TOKEN, ++ MD_ERROR_WIN_DEVICE_FEATURE_NOT_SUPPORTED, ++ MD_ERROR_WIN_MR_MID_NOT_FOUND, ++ MD_ERROR_WIN_SCOPE_NOT_FOUND, ++ MD_ERROR_WIN_UNDEFINED_SCOPE, ++ MD_ERROR_WIN_INVALID_CAP, ++ MD_ERROR_WIN_DEVICE_UNREACHABLE, ++ MD_ERROR_WIN_DEVICE_NO_RESOURCES, ++ MD_ERROR_WIN_DATA_CHECKSUM_ERROR, ++ MD_ERROR_WIN_INTERMIXED_KERNEL_EA_OPERATION, ++ MD_ERROR_WIN_FILE_LEVEL_TRIM_NOT_SUPPORTED, ++ MD_ERROR_WIN_OFFSET_ALIGNMENT_VIOLATION, ++ MD_ERROR_WIN_INVALID_FIELD_IN_PARAMETER_LIST, ++ MD_ERROR_WIN_OPERATION_IN_PROGRESS, ++ MD_ERROR_WIN_BAD_DEVICE_PATH, ++ MD_ERROR_WIN_TOO_MANY_DESCRIPTORS, ++ MD_ERROR_WIN_SCRUB_DATA_DISABLED, ++ MD_ERROR_WIN_NOT_REDUNDANT_STORAGE, ++ MD_ERROR_WIN_RESIDENT_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_COMPRESSED_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_DIRECTORY_NOT_SUPPORTED, ++ MD_ERROR_WIN_NOT_READ_FROM_COPY, ++ MD_ERROR_WIN_FT_WRITE_FAILURE, ++ MD_ERROR_WIN_FT_DI_SCAN_REQUIRED, ++ MD_ERROR_WIN_INVALID_KERNEL_INFO_VERSION, ++ MD_ERROR_WIN_INVALID_PEP_INFO_VERSION, ++ MD_ERROR_WIN_OBJECT_NOT_EXTERNALLY_BACKED, ++ MD_ERROR_WIN_EXTERNAL_BACKING_PROVIDER_UNKNOWN, ++ MD_ERROR_WIN_COMPRESSION_NOT_BENEFICIAL, ++ MD_ERROR_WIN_STORAGE_TOPOLOGY_ID_MISMATCH, ++ MD_ERROR_WIN_BLOCKED_BY_PARENTAL_CONTROLS, ++ MD_ERROR_WIN_BLOCK_TOO_MANY_REFERENCES, ++ MD_ERROR_WIN_MARKED_TO_DISALLOW_WRITES, ++ MD_ERROR_WIN_ENCLAVE_FAILURE, ++ MD_ERROR_WIN_FAIL_NOACTION_REBOOT, ++ MD_ERROR_WIN_FAIL_SHUTDOWN, ++ MD_ERROR_WIN_FAIL_RESTART, ++ MD_ERROR_WIN_MAX_SESSIONS_REACHED, ++ MD_ERROR_WIN_NETWORK_ACCESS_DENIED_EDP, ++ MD_ERROR_WIN_DEVICE_HINT_NAME_BUFFER_TOO_SMALL, ++ MD_ERROR_WIN_EDP_POLICY_DENIES_OPERATION, ++ MD_ERROR_WIN_EDP_DPL_POLICY_CANT_BE_SATISFIED, ++ MD_ERROR_WIN_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT, ++ MD_ERROR_WIN_DEVICE_IN_MAINTENANCE, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_DAX, ++ MD_ERROR_WIN_DAX_MAPPING_EXISTS, ++ MD_ERROR_WIN_CLOUD_FILE_PROVIDER_NOT_RUNNING, ++ MD_ERROR_WIN_CLOUD_FILE_METADATA_CORRUPT, ++ MD_ERROR_WIN_CLOUD_FILE_METADATA_TOO_LARGE, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH, ++ MD_ERROR_WIN_CHILD_PROCESS_BLOCKED, ++ MD_ERROR_WIN_STORAGE_LOST_DATA_PERSISTENCE, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_BUSY, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN, ++ MD_ERROR_WIN_GDI_HANDLE_LEAK, ++ MD_ERROR_WIN_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED, ++ MD_ERROR_WIN_NOT_A_CLOUD_FILE, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_IN_SYNC, ++ MD_ERROR_WIN_CLOUD_FILE_ALREADY_CONNECTED, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLOUD_FILE_INVALID_REQUEST, ++ MD_ERROR_WIN_CLOUD_FILE_READ_ONLY_VOLUME, ++ MD_ERROR_WIN_CLOUD_FILE_CONNECTED_PROVIDER_ONLY, ++ MD_ERROR_WIN_CLOUD_FILE_VALIDATION_FAILED, ++ MD_ERROR_WIN_SMB1_NOT_AVAILABLE, ++ MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION, ++ MD_ERROR_WIN_CLOUD_FILE_AUTHENTICATION_FAILED, ++ MD_ERROR_WIN_CLOUD_FILE_INSUFFICIENT_RESOURCES, ++ MD_ERROR_WIN_CLOUD_FILE_NETWORK_UNAVAILABLE, ++ MD_ERROR_WIN_CLOUD_FILE_UNSUCCESSFUL, ++ MD_ERROR_WIN_CLOUD_FILE_NOT_UNDER_SYNC_ROOT, ++ MD_ERROR_WIN_CLOUD_FILE_IN_USE, ++ MD_ERROR_WIN_CLOUD_FILE_PINNED, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_ABORTED, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_CORRUPT, ++ MD_ERROR_WIN_CLOUD_FILE_ACCESS_DENIED, ++ MD_ERROR_WIN_CLOUD_FILE_INCOMPATIBLE_HARDLINKS, ++ MD_ERROR_WIN_CLOUD_FILE_PROPERTY_LOCK_CONFLICT, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_CANCELED, ++ MD_ERROR_WIN_EXTERNAL_SYSKEY_NOT_SUPPORTED, ++ MD_ERROR_WIN_THREAD_MODE_ALREADY_BACKGROUND, ++ MD_ERROR_WIN_THREAD_MODE_NOT_BACKGROUND, ++ MD_ERROR_WIN_PROCESS_MODE_ALREADY_BACKGROUND, ++ MD_ERROR_WIN_PROCESS_MODE_NOT_BACKGROUND, ++ MD_ERROR_WIN_CLOUD_FILE_PROVIDER_TERMINATED, ++ MD_ERROR_WIN_NOT_A_CLOUD_SYNC_ROOT, ++ MD_ERROR_WIN_FILE_PROTECTED_UNDER_DPL, ++ MD_ERROR_WIN_VOLUME_NOT_CLUSTER_ALIGNED, ++ MD_ERROR_WIN_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND, ++ MD_ERROR_WIN_APPX_FILE_NOT_ENCRYPTED, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE, ++ MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER, ++ MD_ERROR_WIN_LINUX_SUBSYSTEM_NOT_PRESENT, ++ MD_ERROR_WIN_FT_READ_FAILURE, ++ MD_ERROR_WIN_STORAGE_RESERVE_ID_INVALID, ++ MD_ERROR_WIN_STORAGE_RESERVE_DOES_NOT_EXIST, ++ MD_ERROR_WIN_STORAGE_RESERVE_ALREADY_EXISTS, ++ MD_ERROR_WIN_STORAGE_RESERVE_NOT_EMPTY, ++ MD_ERROR_WIN_NOT_A_DAX_VOLUME, ++ MD_ERROR_WIN_NOT_DAX_MAPPABLE, ++ MD_ERROR_WIN_TIME_SENSITIVE_THREAD, ++ MD_ERROR_WIN_DPL_NOT_SUPPORTED_FOR_USER, ++ MD_ERROR_WIN_CASE_DIFFERING_NAMES_IN_DIR, ++ MD_ERROR_WIN_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLOUD_FILE_REQUEST_TIMEOUT, ++ MD_ERROR_WIN_NO_TASK_QUEUE, ++ MD_ERROR_WIN_SRC_SRV_DLL_LOAD_FAILED, ++ MD_ERROR_WIN_NOT_SUPPORTED_WITH_BTT, ++ MD_ERROR_WIN_ENCRYPTION_DISABLED, ++ MD_ERROR_WIN_ENCRYPTING_METADATA_DISALLOWED, ++ MD_ERROR_WIN_CANT_CLEAR_ENCRYPTION_FLAG, ++ MD_ERROR_WIN_NO_SUCH_DEVICE, ++ MD_ERROR_WIN_CLOUD_FILE_DEHYDRATION_DISALLOWED, ++ MD_ERROR_WIN_FILE_SNAP_IN_PROGRESS, ++ MD_ERROR_WIN_FILE_SNAP_USER_SECTION_NOT_SUPPORTED, ++ MD_ERROR_WIN_FILE_SNAP_MODIFY_NOT_SUPPORTED, ++ MD_ERROR_WIN_FILE_SNAP_IO_NOT_COORDINATED, ++ MD_ERROR_WIN_FILE_SNAP_UNEXPECTED_ERROR, ++ MD_ERROR_WIN_FILE_SNAP_INVALID_PARAMETER, ++ MD_ERROR_WIN_UNSATISFIED_DEPENDENCIES, ++ MD_ERROR_WIN_CASE_SENSITIVE_PATH, ++ MD_ERROR_WIN_UNEXPECTED_NTCACHEMANAGER_ERROR, ++ MD_ERROR_WIN_LINUX_SUBSYSTEM_UPDATE_REQUIRED, ++ MD_ERROR_WIN_DLP_POLICY_WARNS_AGAINST_OPERATION, ++ MD_ERROR_WIN_DLP_POLICY_DENIES_OPERATION, ++ MD_ERROR_WIN_DLP_POLICY_SILENTLY_FAIL, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_DEVUNLOCKED, ++ MD_ERROR_WIN_CAPAUTHZ_CHANGE_TYPE, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_PROVISIONED, ++ MD_ERROR_WIN_CAPAUTHZ_NOT_AUTHORIZED, ++ MD_ERROR_WIN_CAPAUTHZ_NO_POLICY, ++ MD_ERROR_WIN_CAPAUTHZ_DB_CORRUPTED, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_INVALID_CATALOG, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_AUTH_ENTITY, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_PARSE_ERROR, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED, ++ MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH, ++ MD_ERROR_WIN_CIMFS_IMAGE_CORRUPT, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_DEVICE_TIMEOUT, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT, ++ MD_ERROR_WIN_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT, ++ MD_ERROR_WIN_DEVICE_HARDWARE_ERROR, ++ MD_ERROR_WIN_INVALID_ADDRESS, ++ MD_ERROR_WIN_HAS_SYSTEM_CRITICAL_FILES, ++ MD_ERROR_WIN_USER_PROFILE_LOAD, ++ MD_ERROR_WIN_ARITHMETIC_OVERFLOW, ++ MD_ERROR_WIN_PIPE_CONNECTED, ++ MD_ERROR_WIN_PIPE_LISTENING, ++ MD_ERROR_WIN_VERIFIER_STOP, ++ MD_ERROR_WIN_ABIOS_ERROR, ++ MD_ERROR_WIN_WX86_WARNING, ++ MD_ERROR_WIN_WX86_ERROR, ++ MD_ERROR_WIN_TIMER_NOT_CANCELED, ++ MD_ERROR_WIN_UNWIND, ++ MD_ERROR_WIN_BAD_STACK, ++ MD_ERROR_WIN_INVALID_UNWIND_TARGET, ++ MD_ERROR_WIN_INVALID_PORT_ATTRIBUTES, ++ MD_ERROR_WIN_PORT_MESSAGE_TOO_LONG, ++ MD_ERROR_WIN_INVALID_QUOTA_LOWER, ++ MD_ERROR_WIN_DEVICE_ALREADY_ATTACHED, ++ MD_ERROR_WIN_INSTRUCTION_MISALIGNMENT, ++ MD_ERROR_WIN_PROFILING_NOT_STARTED, ++ MD_ERROR_WIN_PROFILING_NOT_STOPPED, ++ MD_ERROR_WIN_COULD_NOT_INTERPRET, ++ MD_ERROR_WIN_PROFILING_AT_LIMIT, ++ MD_ERROR_WIN_CANT_WAIT, ++ MD_ERROR_WIN_CANT_TERMINATE_SELF, ++ MD_ERROR_WIN_UNEXPECTED_MM_CREATE_ERR, ++ MD_ERROR_WIN_UNEXPECTED_MM_MAP_ERROR, ++ MD_ERROR_WIN_UNEXPECTED_MM_EXTEND_ERR, ++ MD_ERROR_WIN_BAD_FUNCTION_TABLE, ++ MD_ERROR_WIN_NO_GUID_TRANSLATION, ++ MD_ERROR_WIN_INVALID_LDT_SIZE, ++ MD_ERROR_WIN_INVALID_LDT_OFFSET, ++ MD_ERROR_WIN_INVALID_LDT_DESCRIPTOR, ++ MD_ERROR_WIN_TOO_MANY_THREADS, ++ MD_ERROR_WIN_THREAD_NOT_IN_PROCESS, ++ MD_ERROR_WIN_PAGEFILE_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_LOGON_SERVER_CONFLICT, ++ MD_ERROR_WIN_SYNCHRONIZATION_REQUIRED, ++ MD_ERROR_WIN_NET_OPEN_FAILED, ++ MD_ERROR_WIN_IO_PRIVILEGE_FAILED, ++ MD_ERROR_WIN_CONTROL_C_EXIT, ++ MD_ERROR_WIN_MISSING_SYSTEMFILE, ++ MD_ERROR_WIN_UNHANDLED_EXCEPTION, ++ MD_ERROR_WIN_APP_INIT_FAILURE, ++ MD_ERROR_WIN_PAGEFILE_CREATE_FAILED, ++ MD_ERROR_WIN_INVALID_IMAGE_HASH, ++ MD_ERROR_WIN_NO_PAGEFILE, ++ MD_ERROR_WIN_ILLEGAL_FLOAT_CONTEXT, ++ MD_ERROR_WIN_NO_EVENT_PAIR, ++ MD_ERROR_WIN_DOMAIN_CTRLR_CONFIG_ERROR, ++ MD_ERROR_WIN_ILLEGAL_CHARACTER, ++ MD_ERROR_WIN_UNDEFINED_CHARACTER, ++ MD_ERROR_WIN_FLOPPY_VOLUME, ++ MD_ERROR_WIN_BIOS_FAILED_TO_CONNECT_INTERRUPT, ++ MD_ERROR_WIN_BACKUP_CONTROLLER, ++ MD_ERROR_WIN_MUTANT_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_FS_DRIVER_REQUIRED, ++ MD_ERROR_WIN_CANNOT_LOAD_REGISTRY_FILE, ++ MD_ERROR_WIN_DEBUG_ATTACH_FAILED, ++ MD_ERROR_WIN_SYSTEM_PROCESS_TERMINATED, ++ MD_ERROR_WIN_DATA_NOT_ACCEPTED, ++ MD_ERROR_WIN_VDM_HARD_ERROR, ++ MD_ERROR_WIN_DRIVER_CANCEL_TIMEOUT, ++ MD_ERROR_WIN_REPLY_MESSAGE_MISMATCH, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA, ++ MD_ERROR_WIN_CLIENT_SERVER_PARAMETERS_INVALID, ++ MD_ERROR_WIN_NOT_TINY_STREAM, ++ MD_ERROR_WIN_STACK_OVERFLOW_READ, ++ MD_ERROR_WIN_CONVERT_TO_LARGE, ++ MD_ERROR_WIN_FOUND_OUT_OF_SCOPE, ++ MD_ERROR_WIN_ALLOCATE_BUCKET, ++ MD_ERROR_WIN_MARSHALL_OVERFLOW, ++ MD_ERROR_WIN_INVALID_VARIANT, ++ MD_ERROR_WIN_BAD_COMPRESSION_BUFFER, ++ MD_ERROR_WIN_AUDIT_FAILED, ++ MD_ERROR_WIN_TIMER_RESOLUTION_NOT_SET, ++ MD_ERROR_WIN_INSUFFICIENT_LOGON_INFO, ++ MD_ERROR_WIN_BAD_DLL_ENTRYPOINT, ++ MD_ERROR_WIN_BAD_SERVICE_ENTRYPOINT, ++ MD_ERROR_WIN_IP_ADDRESS_CONFLICT1, ++ MD_ERROR_WIN_IP_ADDRESS_CONFLICT2, ++ MD_ERROR_WIN_REGISTRY_QUOTA_LIMIT, ++ MD_ERROR_WIN_NO_CALLBACK_ACTIVE, ++ MD_ERROR_WIN_PWD_TOO_SHORT, ++ MD_ERROR_WIN_PWD_TOO_RECENT, ++ MD_ERROR_WIN_PWD_HISTORY_CONFLICT, ++ MD_ERROR_WIN_UNSUPPORTED_COMPRESSION, ++ MD_ERROR_WIN_INVALID_HW_PROFILE, ++ MD_ERROR_WIN_INVALID_PLUGPLAY_DEVICE_PATH, ++ MD_ERROR_WIN_QUOTA_LIST_INCONSISTENT, ++ MD_ERROR_WIN_EVALUATION_EXPIRATION, ++ MD_ERROR_WIN_ILLEGAL_DLL_RELOCATION, ++ MD_ERROR_WIN_DLL_INIT_FAILED_LOGOFF, ++ MD_ERROR_WIN_VALIDATE_CONTINUE, ++ MD_ERROR_WIN_NO_MORE_MATCHES, ++ MD_ERROR_WIN_RANGE_LIST_CONFLICT, ++ MD_ERROR_WIN_SERVER_SID_MISMATCH, ++ MD_ERROR_WIN_CANT_ENABLE_DENY_ONLY, ++ MD_ERROR_WIN_FLOAT_MULTIPLE_FAULTS, ++ MD_ERROR_WIN_FLOAT_MULTIPLE_TRAPS, ++ MD_ERROR_WIN_NOINTERFACE, ++ MD_ERROR_WIN_DRIVER_FAILED_SLEEP, ++ MD_ERROR_WIN_CORRUPT_SYSTEM_FILE, ++ MD_ERROR_WIN_COMMITMENT_MINIMUM, ++ MD_ERROR_WIN_PNP_RESTART_ENUMERATION, ++ MD_ERROR_WIN_SYSTEM_IMAGE_BAD_SIGNATURE, ++ MD_ERROR_WIN_PNP_REBOOT_REQUIRED, ++ MD_ERROR_WIN_INSUFFICIENT_POWER, ++ MD_ERROR_WIN_MULTIPLE_FAULT_VIOLATION, ++ MD_ERROR_WIN_SYSTEM_SHUTDOWN, ++ MD_ERROR_WIN_PORT_NOT_SET, ++ MD_ERROR_WIN_DS_VERSION_CHECK_FAILURE, ++ MD_ERROR_WIN_RANGE_NOT_FOUND, ++ MD_ERROR_WIN_NOT_SAFE_MODE_DRIVER, ++ MD_ERROR_WIN_FAILED_DRIVER_ENTRY, ++ MD_ERROR_WIN_DEVICE_ENUMERATION_ERROR, ++ MD_ERROR_WIN_MOUNT_POINT_NOT_RESOLVED, ++ MD_ERROR_WIN_INVALID_DEVICE_OBJECT_PARAMETER, ++ MD_ERROR_WIN_MCA_OCCURED, ++ MD_ERROR_WIN_DRIVER_DATABASE_ERROR, ++ MD_ERROR_WIN_SYSTEM_HIVE_TOO_LARGE, ++ MD_ERROR_WIN_DRIVER_FAILED_PRIOR_UNLOAD, ++ MD_ERROR_WIN_VOLSNAP_PREPARE_HIBERNATE, ++ MD_ERROR_WIN_HIBERNATION_FAILURE, ++ MD_ERROR_WIN_PWD_TOO_LONG, ++ MD_ERROR_WIN_FILE_SYSTEM_LIMITATION, ++ MD_ERROR_WIN_ASSERTION_FAILURE, ++ MD_ERROR_WIN_ACPI_ERROR, ++ MD_ERROR_WIN_WOW_ASSERTION, ++ MD_ERROR_WIN_PNP_BAD_MPS_TABLE, ++ MD_ERROR_WIN_PNP_TRANSLATION_FAILED, ++ MD_ERROR_WIN_PNP_IRQ_TRANSLATION_FAILED, ++ MD_ERROR_WIN_PNP_INVALID_ID, ++ MD_ERROR_WIN_WAKE_SYSTEM_DEBUGGER, ++ MD_ERROR_WIN_HANDLES_CLOSED, ++ MD_ERROR_WIN_EXTRANEOUS_INFORMATION, ++ MD_ERROR_WIN_RXACT_COMMIT_NECESSARY, ++ MD_ERROR_WIN_MEDIA_CHECK, ++ MD_ERROR_WIN_GUID_SUBSTITUTION_MADE, ++ MD_ERROR_WIN_STOPPED_ON_SYMLINK, ++ MD_ERROR_WIN_LONGJUMP, ++ MD_ERROR_WIN_PLUGPLAY_QUERY_VETOED, ++ MD_ERROR_WIN_UNWIND_CONSOLIDATE, ++ MD_ERROR_WIN_REGISTRY_HIVE_RECOVERED, ++ MD_ERROR_WIN_DLL_MIGHT_BE_INSECURE, ++ MD_ERROR_WIN_DLL_MIGHT_BE_INCOMPATIBLE, ++ MD_ERROR_WIN_DBG_EXCEPTION_NOT_HANDLED, ++ MD_ERROR_WIN_DBG_REPLY_LATER, ++ MD_ERROR_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE, ++ MD_ERROR_WIN_DBG_TERMINATE_THREAD, ++ MD_ERROR_WIN_DBG_TERMINATE_PROCESS, ++ MD_ERROR_WIN_DBG_CONTROL_C, ++ MD_ERROR_WIN_DBG_PRINTEXCEPTION_C, ++ MD_ERROR_WIN_DBG_RIPEXCEPTION, ++ MD_ERROR_WIN_DBG_CONTROL_BREAK, ++ MD_ERROR_WIN_DBG_COMMAND_EXCEPTION, ++ MD_ERROR_WIN_OBJECT_NAME_EXISTS, ++ MD_ERROR_WIN_THREAD_WAS_SUSPENDED, ++ MD_ERROR_WIN_IMAGE_NOT_AT_BASE, ++ MD_ERROR_WIN_RXACT_STATE_CREATED, ++ MD_ERROR_WIN_SEGMENT_NOTIFICATION, ++ MD_ERROR_WIN_BAD_CURRENT_DIRECTORY, ++ MD_ERROR_WIN_FT_READ_RECOVERY_FROM_BACKUP, ++ MD_ERROR_WIN_FT_WRITE_RECOVERY, ++ MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH, ++ MD_ERROR_WIN_RECEIVE_PARTIAL, ++ MD_ERROR_WIN_RECEIVE_EXPEDITED, ++ MD_ERROR_WIN_RECEIVE_PARTIAL_EXPEDITED, ++ MD_ERROR_WIN_EVENT_DONE, ++ MD_ERROR_WIN_EVENT_PENDING, ++ MD_ERROR_WIN_CHECKING_FILE_SYSTEM, ++ MD_ERROR_WIN_FATAL_APP_EXIT, ++ MD_ERROR_WIN_PREDEFINED_HANDLE, ++ MD_ERROR_WIN_WAS_UNLOCKED, ++ MD_ERROR_WIN_SERVICE_NOTIFICATION, ++ MD_ERROR_WIN_WAS_LOCKED, ++ MD_ERROR_WIN_LOG_HARD_ERROR, ++ MD_ERROR_WIN_ALREADY_WIN32, ++ MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH_EXE, ++ MD_ERROR_WIN_NO_YIELD_PERFORMED, ++ MD_ERROR_WIN_TIMER_RESUME_IGNORED, ++ MD_ERROR_WIN_ARBITRATION_UNHANDLED, ++ MD_ERROR_WIN_CARDBUS_NOT_SUPPORTED, ++ MD_ERROR_WIN_MP_PROCESSOR_MISMATCH, ++ MD_ERROR_WIN_HIBERNATED, ++ MD_ERROR_WIN_RESUME_HIBERNATION, ++ MD_ERROR_WIN_FIRMWARE_UPDATED, ++ MD_ERROR_WIN_DRIVERS_LEAKING_LOCKED_PAGES, ++ MD_ERROR_WIN_WAKE_SYSTEM, ++ MD_ERROR_WIN_WAIT_1, ++ MD_ERROR_WIN_WAIT_2, ++ MD_ERROR_WIN_WAIT_3, ++ MD_ERROR_WIN_WAIT_63, ++ MD_ERROR_WIN_ABANDONED_WAIT_0, ++ MD_ERROR_WIN_ABANDONED_WAIT_63, ++ MD_ERROR_WIN_USER_APC, ++ MD_ERROR_WIN_KERNEL_APC, ++ MD_ERROR_WIN_ALERTED, ++ MD_ERROR_WIN_ELEVATION_REQUIRED, ++ MD_ERROR_WIN_REPARSE, ++ MD_ERROR_WIN_OPLOCK_BREAK_IN_PROGRESS, ++ MD_ERROR_WIN_VOLUME_MOUNTED, ++ MD_ERROR_WIN_RXACT_COMMITTED, ++ MD_ERROR_WIN_NOTIFY_CLEANUP, ++ MD_ERROR_WIN_PRIMARY_TRANSPORT_CONNECT_FAILED, ++ MD_ERROR_WIN_PAGE_FAULT_TRANSITION, ++ MD_ERROR_WIN_PAGE_FAULT_DEMAND_ZERO, ++ MD_ERROR_WIN_PAGE_FAULT_COPY_ON_WRITE, ++ MD_ERROR_WIN_PAGE_FAULT_GUARD_PAGE, ++ MD_ERROR_WIN_PAGE_FAULT_PAGING_FILE, ++ MD_ERROR_WIN_CACHE_PAGE_LOCKED, ++ MD_ERROR_WIN_CRASH_DUMP, ++ MD_ERROR_WIN_BUFFER_ALL_ZEROS, ++ MD_ERROR_WIN_REPARSE_OBJECT, ++ MD_ERROR_WIN_RESOURCE_REQUIREMENTS_CHANGED, ++ MD_ERROR_WIN_TRANSLATION_COMPLETE, ++ MD_ERROR_WIN_NOTHING_TO_TERMINATE, ++ MD_ERROR_WIN_PROCESS_NOT_IN_JOB, ++ MD_ERROR_WIN_PROCESS_IN_JOB, ++ MD_ERROR_WIN_VOLSNAP_HIBERNATE_READY, ++ MD_ERROR_WIN_FSFILTER_OP_COMPLETED_SUCCESSFULLY, ++ MD_ERROR_WIN_INTERRUPT_VECTOR_ALREADY_CONNECTED, ++ MD_ERROR_WIN_INTERRUPT_STILL_CONNECTED, ++ MD_ERROR_WIN_WAIT_FOR_OPLOCK, ++ MD_ERROR_WIN_DBG_EXCEPTION_HANDLED, ++ MD_ERROR_WIN_DBG_CONTINUE, ++ MD_ERROR_WIN_CALLBACK_POP_STACK, ++ MD_ERROR_WIN_COMPRESSION_DISABLED, ++ MD_ERROR_WIN_CANTFETCHBACKWARDS, ++ MD_ERROR_WIN_CANTSCROLLBACKWARDS, ++ MD_ERROR_WIN_ROWSNOTRELEASED, ++ MD_ERROR_WIN_BAD_ACCESSOR_FLAGS, ++ MD_ERROR_WIN_ERRORS_ENCOUNTERED, ++ MD_ERROR_WIN_NOT_CAPABLE, ++ MD_ERROR_WIN_REQUEST_OUT_OF_SEQUENCE, ++ MD_ERROR_WIN_VERSION_PARSE_ERROR, ++ MD_ERROR_WIN_BADSTARTPOSITION, ++ MD_ERROR_WIN_MEMORY_HARDWARE, ++ MD_ERROR_WIN_DISK_REPAIR_DISABLED, ++ MD_ERROR_WIN_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, ++ MD_ERROR_WIN_SYSTEM_POWERSTATE_TRANSITION, ++ MD_ERROR_WIN_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, ++ MD_ERROR_WIN_MCA_EXCEPTION, ++ MD_ERROR_WIN_ACCESS_AUDIT_BY_POLICY, ++ MD_ERROR_WIN_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, ++ MD_ERROR_WIN_ABANDON_HIBERFILE, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, ++ MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, ++ MD_ERROR_WIN_BAD_MCFG_TABLE, ++ MD_ERROR_WIN_DISK_REPAIR_REDIRECTED, ++ MD_ERROR_WIN_DISK_REPAIR_UNSUCCESSFUL, ++ MD_ERROR_WIN_CORRUPT_LOG_OVERFULL, ++ MD_ERROR_WIN_CORRUPT_LOG_CORRUPTED, ++ MD_ERROR_WIN_CORRUPT_LOG_UNAVAILABLE, ++ MD_ERROR_WIN_CORRUPT_LOG_DELETED_FULL, ++ MD_ERROR_WIN_CORRUPT_LOG_CLEARED, ++ MD_ERROR_WIN_ORPHAN_NAME_EXHAUSTED, ++ MD_ERROR_WIN_OPLOCK_SWITCHED_TO_NEW_HANDLE, ++ MD_ERROR_WIN_CANNOT_GRANT_REQUESTED_OPLOCK, ++ MD_ERROR_WIN_CANNOT_BREAK_OPLOCK, ++ MD_ERROR_WIN_OPLOCK_HANDLE_CLOSED, ++ MD_ERROR_WIN_NO_ACE_CONDITION, ++ MD_ERROR_WIN_INVALID_ACE_CONDITION, ++ MD_ERROR_WIN_FILE_HANDLE_REVOKED, ++ MD_ERROR_WIN_IMAGE_AT_DIFFERENT_BASE, ++ MD_ERROR_WIN_ENCRYPTED_IO_NOT_POSSIBLE, ++ MD_ERROR_WIN_FILE_METADATA_OPTIMIZATION_IN_PROGRESS, ++ MD_ERROR_WIN_QUOTA_ACTIVITY, ++ MD_ERROR_WIN_HANDLE_REVOKED, ++ MD_ERROR_WIN_CALLBACK_INVOKE_INLINE, ++ MD_ERROR_WIN_CPU_SET_INVALID, ++ MD_ERROR_WIN_ENCLAVE_NOT_TERMINATED, ++ MD_ERROR_WIN_ENCLAVE_VIOLATION, ++ MD_ERROR_WIN_EA_ACCESS_DENIED, ++ MD_ERROR_WIN_OPERATION_ABORTED, ++ MD_ERROR_WIN_IO_INCOMPLETE, ++ MD_ERROR_WIN_IO_PENDING, ++ MD_ERROR_WIN_NOACCESS, ++ MD_ERROR_WIN_SWAPERROR, ++ MD_ERROR_WIN_STACK_OVERFLOW, ++ MD_ERROR_WIN_INVALID_MESSAGE, ++ MD_ERROR_WIN_CAN_NOT_COMPLETE, ++ MD_ERROR_WIN_INVALID_FLAGS, ++ MD_ERROR_WIN_UNRECOGNIZED_VOLUME, ++ MD_ERROR_WIN_FILE_INVALID, ++ MD_ERROR_WIN_FULLSCREEN_MODE, ++ MD_ERROR_WIN_NO_TOKEN, ++ MD_ERROR_WIN_BADDB, ++ MD_ERROR_WIN_BADKEY, ++ MD_ERROR_WIN_CANTOPEN, ++ MD_ERROR_WIN_CANTREAD, ++ MD_ERROR_WIN_CANTWRITE, ++ MD_ERROR_WIN_REGISTRY_RECOVERED, ++ MD_ERROR_WIN_REGISTRY_CORRUPT, ++ MD_ERROR_WIN_REGISTRY_IO_FAILED, ++ MD_ERROR_WIN_NOT_REGISTRY_FILE, ++ MD_ERROR_WIN_KEY_DELETED, ++ MD_ERROR_WIN_NO_LOG_SPACE, ++ MD_ERROR_WIN_KEY_HAS_CHILDREN, ++ MD_ERROR_WIN_CHILD_MUST_BE_VOLATILE, ++ MD_ERROR_WIN_NOTIFY_ENUM_DIR, ++ MD_ERROR_WIN_DEPENDENT_SERVICES_RUNNING, ++ MD_ERROR_WIN_INVALID_SERVICE_CONTROL, ++ MD_ERROR_WIN_SERVICE_REQUEST_TIMEOUT, ++ MD_ERROR_WIN_SERVICE_NO_THREAD, ++ MD_ERROR_WIN_SERVICE_DATABASE_LOCKED, ++ MD_ERROR_WIN_SERVICE_ALREADY_RUNNING, ++ MD_ERROR_WIN_INVALID_SERVICE_ACCOUNT, ++ MD_ERROR_WIN_SERVICE_DISABLED, ++ MD_ERROR_WIN_CIRCULAR_DEPENDENCY, ++ MD_ERROR_WIN_SERVICE_DOES_NOT_EXIST, ++ MD_ERROR_WIN_SERVICE_CANNOT_ACCEPT_CTRL, ++ MD_ERROR_WIN_SERVICE_NOT_ACTIVE, ++ MD_ERROR_WIN_FAILED_SERVICE_CONTROLLER_CONNECT, ++ MD_ERROR_WIN_EXCEPTION_IN_SERVICE, ++ MD_ERROR_WIN_DATABASE_DOES_NOT_EXIST, ++ MD_ERROR_WIN_SERVICE_SPECIFIC_ERROR, ++ MD_ERROR_WIN_PROCESS_ABORTED, ++ MD_ERROR_WIN_SERVICE_DEPENDENCY_FAIL, ++ MD_ERROR_WIN_SERVICE_LOGON_FAILED, ++ MD_ERROR_WIN_SERVICE_START_HANG, ++ MD_ERROR_WIN_INVALID_SERVICE_LOCK, ++ MD_ERROR_WIN_SERVICE_MARKED_FOR_DELETE, ++ MD_ERROR_WIN_SERVICE_EXISTS, ++ MD_ERROR_WIN_ALREADY_RUNNING_LKG, ++ MD_ERROR_WIN_SERVICE_DEPENDENCY_DELETED, ++ MD_ERROR_WIN_BOOT_ALREADY_ACCEPTED, ++ MD_ERROR_WIN_SERVICE_NEVER_STARTED, ++ MD_ERROR_WIN_DUPLICATE_SERVICE_NAME, ++ MD_ERROR_WIN_DIFFERENT_SERVICE_ACCOUNT, ++ MD_ERROR_WIN_CANNOT_DETECT_DRIVER_FAILURE, ++ MD_ERROR_WIN_CANNOT_DETECT_PROCESS_ABORT, ++ MD_ERROR_WIN_NO_RECOVERY_PROGRAM, ++ MD_ERROR_WIN_SERVICE_NOT_IN_EXE, ++ MD_ERROR_WIN_NOT_SAFEBOOT_SERVICE, ++ MD_ERROR_WIN_END_OF_MEDIA, ++ MD_ERROR_WIN_FILEMARK_DETECTED, ++ MD_ERROR_WIN_BEGINNING_OF_MEDIA, ++ MD_ERROR_WIN_SETMARK_DETECTED, ++ MD_ERROR_WIN_NO_DATA_DETECTED, ++ MD_ERROR_WIN_PARTITION_FAILURE, ++ MD_ERROR_WIN_INVALID_BLOCK_LENGTH, ++ MD_ERROR_WIN_DEVICE_NOT_PARTITIONED, ++ MD_ERROR_WIN_UNABLE_TO_LOCK_MEDIA, ++ MD_ERROR_WIN_UNABLE_TO_UNLOAD_MEDIA, ++ MD_ERROR_WIN_MEDIA_CHANGED, ++ MD_ERROR_WIN_BUS_RESET, ++ MD_ERROR_WIN_NO_MEDIA_IN_DRIVE, ++ MD_ERROR_WIN_NO_UNICODE_TRANSLATION, ++ MD_ERROR_WIN_DLL_INIT_FAILED, ++ MD_ERROR_WIN_SHUTDOWN_IN_PROGRESS, ++ MD_ERROR_WIN_NO_SHUTDOWN_IN_PROGRESS, ++ MD_ERROR_WIN_IO_DEVICE, ++ MD_ERROR_WIN_SERIAL_NO_DEVICE, ++ MD_ERROR_WIN_IRQ_BUSY, ++ MD_ERROR_WIN_MORE_WRITES, ++ MD_ERROR_WIN_COUNTER_TIMEOUT, ++ MD_ERROR_WIN_FLOPPY_ID_MARK_NOT_FOUND, ++ MD_ERROR_WIN_FLOPPY_WRONG_CYLINDER, ++ MD_ERROR_WIN_FLOPPY_UNKNOWN_ERROR, ++ MD_ERROR_WIN_FLOPPY_BAD_REGISTERS, ++ MD_ERROR_WIN_DISK_RECALIBRATE_FAILED, ++ MD_ERROR_WIN_DISK_OPERATION_FAILED, ++ MD_ERROR_WIN_DISK_RESET_FAILED, ++ MD_ERROR_WIN_EOM_OVERFLOW, ++ MD_ERROR_WIN_NOT_ENOUGH_SERVER_MEMORY, ++ MD_ERROR_WIN_POSSIBLE_DEADLOCK, ++ MD_ERROR_WIN_MAPPED_ALIGNMENT, ++ MD_ERROR_WIN_SET_POWER_STATE_VETOED, ++ MD_ERROR_WIN_SET_POWER_STATE_FAILED, ++ MD_ERROR_WIN_TOO_MANY_LINKS, ++ MD_ERROR_WIN_OLD_WIN_VERSION, ++ MD_ERROR_WIN_APP_WRONG_OS, ++ MD_ERROR_WIN_SINGLE_INSTANCE_APP, ++ MD_ERROR_WIN_RMODE_APP, ++ MD_ERROR_WIN_INVALID_DLL, ++ MD_ERROR_WIN_NO_ASSOCIATION, ++ MD_ERROR_WIN_DDE_FAIL, ++ MD_ERROR_WIN_DLL_NOT_FOUND, ++ MD_ERROR_WIN_NO_MORE_USER_HANDLES, ++ MD_ERROR_WIN_MESSAGE_SYNC_ONLY, ++ MD_ERROR_WIN_SOURCE_ELEMENT_EMPTY, ++ MD_ERROR_WIN_DESTINATION_ELEMENT_FULL, ++ MD_ERROR_WIN_ILLEGAL_ELEMENT_ADDRESS, ++ MD_ERROR_WIN_MAGAZINE_NOT_PRESENT, ++ MD_ERROR_WIN_DEVICE_REINITIALIZATION_NEEDED, ++ MD_ERROR_WIN_DEVICE_REQUIRES_CLEANING, ++ MD_ERROR_WIN_DEVICE_DOOR_OPEN, ++ MD_ERROR_WIN_DEVICE_NOT_CONNECTED, ++ MD_ERROR_WIN_NOT_FOUND, ++ MD_ERROR_WIN_NO_MATCH, ++ MD_ERROR_WIN_SET_NOT_FOUND, ++ MD_ERROR_WIN_POINT_NOT_FOUND, ++ MD_ERROR_WIN_NO_TRACKING_SERVICE, ++ MD_ERROR_WIN_NO_VOLUME_ID, ++ MD_ERROR_WIN_UNABLE_TO_REMOVE_REPLACED, ++ MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT, ++ MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT_2, ++ MD_ERROR_WIN_JOURNAL_DELETE_IN_PROGRESS, ++ MD_ERROR_WIN_JOURNAL_NOT_ACTIVE, ++ MD_ERROR_WIN_POTENTIAL_FILE_FOUND, ++ MD_ERROR_WIN_JOURNAL_ENTRY_DELETED, ++ MD_ERROR_WIN_VRF_CFG_AND_IO_ENABLED, ++ MD_ERROR_WIN_PARTITION_TERMINATING, ++ MD_ERROR_WIN_SHUTDOWN_IS_SCHEDULED, ++ MD_ERROR_WIN_SHUTDOWN_USERS_LOGGED_ON, ++ MD_ERROR_WIN_BAD_DEVICE, ++ MD_ERROR_WIN_CONNECTION_UNAVAIL, ++ MD_ERROR_WIN_DEVICE_ALREADY_REMEMBERED, ++ MD_ERROR_WIN_NO_NET_OR_BAD_PATH, ++ MD_ERROR_WIN_BAD_PROVIDER, ++ MD_ERROR_WIN_CANNOT_OPEN_PROFILE, ++ MD_ERROR_WIN_BAD_PROFILE, ++ MD_ERROR_WIN_NOT_CONTAINER, ++ MD_ERROR_WIN_EXTENDED_ERROR, ++ MD_ERROR_WIN_INVALID_GROUPNAME, ++ MD_ERROR_WIN_INVALID_COMPUTERNAME, ++ MD_ERROR_WIN_INVALID_EVENTNAME, ++ MD_ERROR_WIN_INVALID_DOMAINNAME, ++ MD_ERROR_WIN_INVALID_SERVICENAME, ++ MD_ERROR_WIN_INVALID_NETNAME, ++ MD_ERROR_WIN_INVALID_SHARENAME, ++ MD_ERROR_WIN_INVALID_PASSWORDNAME, ++ MD_ERROR_WIN_INVALID_MESSAGENAME, ++ MD_ERROR_WIN_INVALID_MESSAGEDEST, ++ MD_ERROR_WIN_SESSION_CREDENTIAL_CONFLICT, ++ MD_ERROR_WIN_REMOTE_SESSION_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_DUP_DOMAINNAME, ++ MD_ERROR_WIN_NO_NETWORK, ++ MD_ERROR_WIN_CANCELLED, ++ MD_ERROR_WIN_USER_MAPPED_FILE, ++ MD_ERROR_WIN_CONNECTION_REFUSED, ++ MD_ERROR_WIN_GRACEFUL_DISCONNECT, ++ MD_ERROR_WIN_ADDRESS_ALREADY_ASSOCIATED, ++ MD_ERROR_WIN_ADDRESS_NOT_ASSOCIATED, ++ MD_ERROR_WIN_CONNECTION_INVALID, ++ MD_ERROR_WIN_CONNECTION_ACTIVE, ++ MD_ERROR_WIN_NETWORK_UNREACHABLE, ++ MD_ERROR_WIN_HOST_UNREACHABLE, ++ MD_ERROR_WIN_PROTOCOL_UNREACHABLE, ++ MD_ERROR_WIN_PORT_UNREACHABLE, ++ MD_ERROR_WIN_REQUEST_ABORTED, ++ MD_ERROR_WIN_CONNECTION_ABORTED, ++ MD_ERROR_WIN_RETRY, ++ MD_ERROR_WIN_CONNECTION_COUNT_LIMIT, ++ MD_ERROR_WIN_LOGIN_TIME_RESTRICTION, ++ MD_ERROR_WIN_LOGIN_WKSTA_RESTRICTION, ++ MD_ERROR_WIN_INCORRECT_ADDRESS, ++ MD_ERROR_WIN_ALREADY_REGISTERED, ++ MD_ERROR_WIN_SERVICE_NOT_FOUND, ++ MD_ERROR_WIN_NOT_AUTHENTICATED, ++ MD_ERROR_WIN_NOT_LOGGED_ON, ++ MD_ERROR_WIN_CONTINUE, ++ MD_ERROR_WIN_ALREADY_INITIALIZED, ++ MD_ERROR_WIN_NO_MORE_DEVICES, ++ MD_ERROR_WIN_NO_SUCH_SITE, ++ MD_ERROR_WIN_DOMAIN_CONTROLLER_EXISTS, ++ MD_ERROR_WIN_ONLY_IF_CONNECTED, ++ MD_ERROR_WIN_OVERRIDE_NOCHANGES, ++ MD_ERROR_WIN_BAD_USER_PROFILE, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_SBS, ++ MD_ERROR_WIN_SERVER_SHUTDOWN_IN_PROGRESS, ++ MD_ERROR_WIN_HOST_DOWN, ++ MD_ERROR_WIN_NON_ACCOUNT_SID, ++ MD_ERROR_WIN_NON_DOMAIN_SID, ++ MD_ERROR_WIN_APPHELP_BLOCK, ++ MD_ERROR_WIN_ACCESS_DISABLED_BY_POLICY, ++ MD_ERROR_WIN_REG_NAT_CONSUMPTION, ++ MD_ERROR_WIN_CSCSHARE_OFFLINE, ++ MD_ERROR_WIN_PKINIT_FAILURE, ++ MD_ERROR_WIN_SMARTCARD_SUBSYSTEM_FAILURE, ++ MD_ERROR_WIN_DOWNGRADE_DETECTED, ++ MD_ERROR_WIN_MACHINE_LOCKED, ++ MD_ERROR_WIN_SMB_GUEST_LOGON_BLOCKED, ++ MD_ERROR_WIN_CALLBACK_SUPPLIED_INVALID_DATA, ++ MD_ERROR_WIN_SYNC_FOREGROUND_REFRESH_REQUIRED, ++ MD_ERROR_WIN_DRIVER_BLOCKED, ++ MD_ERROR_WIN_INVALID_IMPORT_OF_NON_DLL, ++ MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE, ++ MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE_TAMPER, ++ MD_ERROR_WIN_RECOVERY_FAILURE, ++ MD_ERROR_WIN_ALREADY_FIBER, ++ MD_ERROR_WIN_ALREADY_THREAD, ++ MD_ERROR_WIN_STACK_BUFFER_OVERRUN, ++ MD_ERROR_WIN_PARAMETER_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_DEBUGGER_INACTIVE, ++ MD_ERROR_WIN_DELAY_LOAD_FAILED, ++ MD_ERROR_WIN_VDM_DISALLOWED, ++ MD_ERROR_WIN_UNIDENTIFIED_ERROR, ++ MD_ERROR_WIN_INVALID_CRUNTIME_PARAMETER, ++ MD_ERROR_WIN_BEYOND_VDL, ++ MD_ERROR_WIN_INCOMPATIBLE_SERVICE_SID_TYPE, ++ MD_ERROR_WIN_DRIVER_PROCESS_TERMINATED, ++ MD_ERROR_WIN_IMPLEMENTATION_LIMIT, ++ MD_ERROR_WIN_PROCESS_IS_PROTECTED, ++ MD_ERROR_WIN_SERVICE_NOTIFY_CLIENT_LAGGING, ++ MD_ERROR_WIN_DISK_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_CONTENT_BLOCKED, ++ MD_ERROR_WIN_INCOMPATIBLE_SERVICE_PRIVILEGE, ++ MD_ERROR_WIN_APP_HANG, ++ MD_ERROR_WIN_INVALID_LABEL, ++ MD_ERROR_WIN_NOT_ALL_ASSIGNED, ++ MD_ERROR_WIN_SOME_NOT_MAPPED, ++ MD_ERROR_WIN_NO_QUOTAS_FOR_ACCOUNT, ++ MD_ERROR_WIN_LOCAL_USER_SESSION_KEY, ++ MD_ERROR_WIN_NULL_LM_PASSWORD, ++ MD_ERROR_WIN_UNKNOWN_REVISION, ++ MD_ERROR_WIN_REVISION_MISMATCH, ++ MD_ERROR_WIN_INVALID_OWNER, ++ MD_ERROR_WIN_INVALID_PRIMARY_GROUP, ++ MD_ERROR_WIN_NO_IMPERSONATION_TOKEN, ++ MD_ERROR_WIN_CANT_DISABLE_MANDATORY, ++ MD_ERROR_WIN_NO_LOGON_SERVERS, ++ MD_ERROR_WIN_NO_SUCH_LOGON_SESSION, ++ MD_ERROR_WIN_NO_SUCH_PRIVILEGE, ++ MD_ERROR_WIN_PRIVILEGE_NOT_HELD, ++ MD_ERROR_WIN_INVALID_ACCOUNT_NAME, ++ MD_ERROR_WIN_USER_EXISTS, ++ MD_ERROR_WIN_NO_SUCH_USER, ++ MD_ERROR_WIN_GROUP_EXISTS, ++ MD_ERROR_WIN_NO_SUCH_GROUP, ++ MD_ERROR_WIN_MEMBER_IN_GROUP, ++ MD_ERROR_WIN_MEMBER_NOT_IN_GROUP, ++ MD_ERROR_WIN_LAST_ADMIN, ++ MD_ERROR_WIN_WRONG_PASSWORD, ++ MD_ERROR_WIN_ILL_FORMED_PASSWORD, ++ MD_ERROR_WIN_PASSWORD_RESTRICTION, ++ MD_ERROR_WIN_LOGON_FAILURE, ++ MD_ERROR_WIN_ACCOUNT_RESTRICTION, ++ MD_ERROR_WIN_INVALID_LOGON_HOURS, ++ MD_ERROR_WIN_INVALID_WORKSTATION, ++ MD_ERROR_WIN_PASSWORD_EXPIRED, ++ MD_ERROR_WIN_ACCOUNT_DISABLED, ++ MD_ERROR_WIN_NONE_MAPPED, ++ MD_ERROR_WIN_TOO_MANY_LUIDS_REQUESTED, ++ MD_ERROR_WIN_LUIDS_EXHAUSTED, ++ MD_ERROR_WIN_INVALID_SUB_AUTHORITY, ++ MD_ERROR_WIN_INVALID_ACL, ++ MD_ERROR_WIN_INVALID_SID, ++ MD_ERROR_WIN_INVALID_SECURITY_DESCR, ++ MD_ERROR_WIN_BAD_INHERITANCE_ACL, ++ MD_ERROR_WIN_SERVER_DISABLED, ++ MD_ERROR_WIN_SERVER_NOT_DISABLED, ++ MD_ERROR_WIN_INVALID_ID_AUTHORITY, ++ MD_ERROR_WIN_ALLOTTED_SPACE_EXCEEDED, ++ MD_ERROR_WIN_INVALID_GROUP_ATTRIBUTES, ++ MD_ERROR_WIN_BAD_IMPERSONATION_LEVEL, ++ MD_ERROR_WIN_CANT_OPEN_ANONYMOUS, ++ MD_ERROR_WIN_BAD_VALIDATION_CLASS, ++ MD_ERROR_WIN_BAD_TOKEN_TYPE, ++ MD_ERROR_WIN_NO_SECURITY_ON_OBJECT, ++ MD_ERROR_WIN_CANT_ACCESS_DOMAIN_INFO, ++ MD_ERROR_WIN_INVALID_SERVER_STATE, ++ MD_ERROR_WIN_INVALID_DOMAIN_STATE, ++ MD_ERROR_WIN_INVALID_DOMAIN_ROLE, ++ MD_ERROR_WIN_NO_SUCH_DOMAIN, ++ MD_ERROR_WIN_DOMAIN_EXISTS, ++ MD_ERROR_WIN_DOMAIN_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_INTERNAL_DB_CORRUPTION, ++ MD_ERROR_WIN_INTERNAL_ERROR, ++ MD_ERROR_WIN_GENERIC_NOT_MAPPED, ++ MD_ERROR_WIN_BAD_DESCRIPTOR_FORMAT, ++ MD_ERROR_WIN_NOT_LOGON_PROCESS, ++ MD_ERROR_WIN_LOGON_SESSION_EXISTS, ++ MD_ERROR_WIN_NO_SUCH_PACKAGE, ++ MD_ERROR_WIN_BAD_LOGON_SESSION_STATE, ++ MD_ERROR_WIN_LOGON_SESSION_COLLISION, ++ MD_ERROR_WIN_INVALID_LOGON_TYPE, ++ MD_ERROR_WIN_CANNOT_IMPERSONATE, ++ MD_ERROR_WIN_RXACT_INVALID_STATE, ++ MD_ERROR_WIN_RXACT_COMMIT_FAILURE, ++ MD_ERROR_WIN_SPECIAL_ACCOUNT, ++ MD_ERROR_WIN_SPECIAL_GROUP, ++ MD_ERROR_WIN_SPECIAL_USER, ++ MD_ERROR_WIN_MEMBERS_PRIMARY_GROUP, ++ MD_ERROR_WIN_TOKEN_ALREADY_IN_USE, ++ MD_ERROR_WIN_NO_SUCH_ALIAS, ++ MD_ERROR_WIN_MEMBER_NOT_IN_ALIAS, ++ MD_ERROR_WIN_MEMBER_IN_ALIAS, ++ MD_ERROR_WIN_ALIAS_EXISTS, ++ MD_ERROR_WIN_LOGON_NOT_GRANTED, ++ MD_ERROR_WIN_TOO_MANY_SECRETS, ++ MD_ERROR_WIN_SECRET_TOO_LONG, ++ MD_ERROR_WIN_INTERNAL_DB_ERROR, ++ MD_ERROR_WIN_TOO_MANY_CONTEXT_IDS, ++ MD_ERROR_WIN_LOGON_TYPE_NOT_GRANTED, ++ MD_ERROR_WIN_NT_CROSS_ENCRYPTION_REQUIRED, ++ MD_ERROR_WIN_NO_SUCH_MEMBER, ++ MD_ERROR_WIN_INVALID_MEMBER, ++ MD_ERROR_WIN_TOO_MANY_SIDS, ++ MD_ERROR_WIN_LM_CROSS_ENCRYPTION_REQUIRED, ++ MD_ERROR_WIN_NO_INHERITANCE, ++ MD_ERROR_WIN_FILE_CORRUPT, ++ MD_ERROR_WIN_DISK_CORRUPT, ++ MD_ERROR_WIN_NO_USER_SESSION_KEY, ++ MD_ERROR_WIN_LICENSE_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_WRONG_TARGET_NAME, ++ MD_ERROR_WIN_MUTUAL_AUTH_FAILED, ++ MD_ERROR_WIN_TIME_SKEW, ++ MD_ERROR_WIN_CURRENT_DOMAIN_NOT_ALLOWED, ++ MD_ERROR_WIN_INVALID_WINDOW_HANDLE, ++ MD_ERROR_WIN_INVALID_MENU_HANDLE, ++ MD_ERROR_WIN_INVALID_CURSOR_HANDLE, ++ MD_ERROR_WIN_INVALID_ACCEL_HANDLE, ++ MD_ERROR_WIN_INVALID_HOOK_HANDLE, ++ MD_ERROR_WIN_INVALID_DWP_HANDLE, ++ MD_ERROR_WIN_TLW_WITH_WSCHILD, ++ MD_ERROR_WIN_CANNOT_FIND_WND_CLASS, ++ MD_ERROR_WIN_WINDOW_OF_OTHER_THREAD, ++ MD_ERROR_WIN_HOTKEY_ALREADY_REGISTERED, ++ MD_ERROR_WIN_CLASS_ALREADY_EXISTS, ++ MD_ERROR_WIN_CLASS_DOES_NOT_EXIST, ++ MD_ERROR_WIN_CLASS_HAS_WINDOWS, ++ MD_ERROR_WIN_INVALID_INDEX, ++ MD_ERROR_WIN_INVALID_ICON_HANDLE, ++ MD_ERROR_WIN_PRIVATE_DIALOG_INDEX, ++ MD_ERROR_WIN_LISTBOX_ID_NOT_FOUND, ++ MD_ERROR_WIN_NO_WILDCARD_CHARACTERS, ++ MD_ERROR_WIN_CLIPBOARD_NOT_OPEN, ++ MD_ERROR_WIN_HOTKEY_NOT_REGISTERED, ++ MD_ERROR_WIN_WINDOW_NOT_DIALOG, ++ MD_ERROR_WIN_CONTROL_ID_NOT_FOUND, ++ MD_ERROR_WIN_INVALID_COMBOBOX_MESSAGE, ++ MD_ERROR_WIN_WINDOW_NOT_COMBOBOX, ++ MD_ERROR_WIN_INVALID_EDIT_HEIGHT, ++ MD_ERROR_WIN_DC_NOT_FOUND, ++ MD_ERROR_WIN_INVALID_HOOK_FILTER, ++ MD_ERROR_WIN_INVALID_FILTER_PROC, ++ MD_ERROR_WIN_HOOK_NEEDS_HMOD, ++ MD_ERROR_WIN_GLOBAL_ONLY_HOOK, ++ MD_ERROR_WIN_JOURNAL_HOOK_SET, ++ MD_ERROR_WIN_HOOK_NOT_INSTALLED, ++ MD_ERROR_WIN_INVALID_LB_MESSAGE, ++ MD_ERROR_WIN_SETCOUNT_ON_BAD_LB, ++ MD_ERROR_WIN_LB_WITHOUT_TABSTOPS, ++ MD_ERROR_WIN_DESTROY_OBJECT_OF_OTHER_THREAD, ++ MD_ERROR_WIN_CHILD_WINDOW_MENU, ++ MD_ERROR_WIN_NO_SYSTEM_MENU, ++ MD_ERROR_WIN_INVALID_MSGBOX_STYLE, ++ MD_ERROR_WIN_INVALID_SPI_VALUE, ++ MD_ERROR_WIN_SCREEN_ALREADY_LOCKED, ++ MD_ERROR_WIN_HWNDS_HAVE_DIFF_PARENT, ++ MD_ERROR_WIN_NOT_CHILD_WINDOW, ++ MD_ERROR_WIN_INVALID_GW_COMMAND, ++ MD_ERROR_WIN_INVALID_THREAD_ID, ++ MD_ERROR_WIN_NON_MDICHILD_WINDOW, ++ MD_ERROR_WIN_POPUP_ALREADY_ACTIVE, ++ MD_ERROR_WIN_NO_SCROLLBARS, ++ MD_ERROR_WIN_INVALID_SCROLLBAR_RANGE, ++ MD_ERROR_WIN_INVALID_SHOWWIN_COMMAND, ++ MD_ERROR_WIN_NO_SYSTEM_RESOURCES, ++ MD_ERROR_WIN_NONPAGED_SYSTEM_RESOURCES, ++ MD_ERROR_WIN_PAGED_SYSTEM_RESOURCES, ++ MD_ERROR_WIN_WORKING_SET_QUOTA, ++ MD_ERROR_WIN_PAGEFILE_QUOTA, ++ MD_ERROR_WIN_COMMITMENT_LIMIT, ++ MD_ERROR_WIN_MENU_ITEM_NOT_FOUND, ++ MD_ERROR_WIN_INVALID_KEYBOARD_HANDLE, ++ MD_ERROR_WIN_HOOK_TYPE_NOT_ALLOWED, ++ MD_ERROR_WIN_REQUIRES_INTERACTIVE_WINDOWSTATION, ++ MD_ERROR_WIN_TIMEOUT, ++ MD_ERROR_WIN_INVALID_MONITOR_HANDLE, ++ MD_ERROR_WIN_INCORRECT_SIZE, ++ MD_ERROR_WIN_SYMLINK_CLASS_DISABLED, ++ MD_ERROR_WIN_SYMLINK_NOT_SUPPORTED, ++ MD_ERROR_WIN_XML_PARSE_ERROR, ++ MD_ERROR_WIN_XMLDSIG_ERROR, ++ MD_ERROR_WIN_RESTART_APPLICATION, ++ MD_ERROR_WIN_WRONG_COMPARTMENT, ++ MD_ERROR_WIN_AUTHIP_FAILURE, ++ MD_ERROR_WIN_NO_NVRAM_RESOURCES, ++ MD_ERROR_WIN_NOT_GUI_PROCESS, ++ MD_ERROR_WIN_EVENTLOG_FILE_CORRUPT, ++ MD_ERROR_WIN_EVENTLOG_CANT_START, ++ MD_ERROR_WIN_LOG_FILE_FULL, ++ MD_ERROR_WIN_EVENTLOG_FILE_CHANGED, ++ MD_ERROR_WIN_CONTAINER_ASSIGNED, ++ MD_ERROR_WIN_JOB_NO_CONTAINER, ++ MD_ERROR_WIN_INVALID_TASK_NAME, ++ MD_ERROR_WIN_INVALID_TASK_INDEX, ++ MD_ERROR_WIN_THREAD_ALREADY_IN_TASK, ++ MD_ERROR_WIN_INSTALL_SERVICE_FAILURE, ++ MD_ERROR_WIN_INSTALL_USEREXIT, ++ MD_ERROR_WIN_INSTALL_FAILURE, ++ MD_ERROR_WIN_INSTALL_SUSPEND, ++ MD_ERROR_WIN_UNKNOWN_PRODUCT, ++ MD_ERROR_WIN_UNKNOWN_FEATURE, ++ MD_ERROR_WIN_UNKNOWN_COMPONENT, ++ MD_ERROR_WIN_UNKNOWN_PROPERTY, ++ MD_ERROR_WIN_INVALID_HANDLE_STATE, ++ MD_ERROR_WIN_BAD_CONFIGURATION, ++ MD_ERROR_WIN_INDEX_ABSENT, ++ MD_ERROR_WIN_INSTALL_SOURCE_ABSENT, ++ MD_ERROR_WIN_INSTALL_PACKAGE_VERSION, ++ MD_ERROR_WIN_PRODUCT_UNINSTALLED, ++ MD_ERROR_WIN_BAD_QUERY_SYNTAX, ++ MD_ERROR_WIN_INVALID_FIELD, ++ MD_ERROR_WIN_DEVICE_REMOVED, ++ MD_ERROR_WIN_INSTALL_ALREADY_RUNNING, ++ MD_ERROR_WIN_INSTALL_PACKAGE_OPEN_FAILED, ++ MD_ERROR_WIN_INSTALL_PACKAGE_INVALID, ++ MD_ERROR_WIN_INSTALL_UI_FAILURE, ++ MD_ERROR_WIN_INSTALL_LOG_FAILURE, ++ MD_ERROR_WIN_INSTALL_LANGUAGE_UNSUPPORTED, ++ MD_ERROR_WIN_INSTALL_TRANSFORM_FAILURE, ++ MD_ERROR_WIN_INSTALL_PACKAGE_REJECTED, ++ MD_ERROR_WIN_FUNCTION_NOT_CALLED, ++ MD_ERROR_WIN_FUNCTION_FAILED, ++ MD_ERROR_WIN_INVALID_TABLE, ++ MD_ERROR_WIN_DATATYPE_MISMATCH, ++ MD_ERROR_WIN_UNSUPPORTED_TYPE, ++ MD_ERROR_WIN_CREATE_FAILED, ++ MD_ERROR_WIN_INSTALL_TEMP_UNWRITABLE, ++ MD_ERROR_WIN_INSTALL_PLATFORM_UNSUPPORTED, ++ MD_ERROR_WIN_INSTALL_NOTUSED, ++ MD_ERROR_WIN_PATCH_PACKAGE_OPEN_FAILED, ++ MD_ERROR_WIN_PATCH_PACKAGE_INVALID, ++ MD_ERROR_WIN_PATCH_PACKAGE_UNSUPPORTED, ++ MD_ERROR_WIN_PRODUCT_VERSION, ++ MD_ERROR_WIN_INVALID_COMMAND_LINE, ++ MD_ERROR_WIN_INSTALL_REMOTE_DISALLOWED, ++ MD_ERROR_WIN_SUCCESS_REBOOT_INITIATED, ++ MD_ERROR_WIN_PATCH_TARGET_NOT_FOUND, ++ MD_ERROR_WIN_PATCH_PACKAGE_REJECTED, ++ MD_ERROR_WIN_INSTALL_TRANSFORM_REJECTED, ++ MD_ERROR_WIN_INSTALL_REMOTE_PROHIBITED, ++ MD_ERROR_WIN_PATCH_REMOVAL_UNSUPPORTED, ++ MD_ERROR_WIN_UNKNOWN_PATCH, ++ MD_ERROR_WIN_PATCH_NO_SEQUENCE, ++ MD_ERROR_WIN_PATCH_REMOVAL_DISALLOWED, ++ MD_ERROR_WIN_INVALID_PATCH_XML, ++ MD_ERROR_WIN_PATCH_MANAGED_ADVERTISED_PRODUCT, ++ MD_ERROR_WIN_INSTALL_SERVICE_SAFEBOOT, ++ MD_ERROR_WIN_FAIL_FAST_EXCEPTION, ++ MD_ERROR_WIN_INSTALL_REJECTED, ++ MD_ERROR_WIN_DYNAMIC_CODE_BLOCKED, ++ MD_ERROR_WIN_NOT_SAME_OBJECT, ++ MD_ERROR_WIN_STRICT_CFG_VIOLATION, ++ MD_ERROR_WIN_SET_CONTEXT_DENIED, ++ MD_ERROR_WIN_CROSS_PARTITION_VIOLATION, ++ MD_ERROR_WIN_RETURN_ADDRESS_HIJACK_ATTEMPT, ++ MD_ERROR_WIN_INVALID_USER_BUFFER, ++ MD_ERROR_WIN_UNRECOGNIZED_MEDIA, ++ MD_ERROR_WIN_NO_TRUST_LSA_SECRET, ++ MD_ERROR_WIN_NO_TRUST_SAM_ACCOUNT, ++ MD_ERROR_WIN_TRUSTED_DOMAIN_FAILURE, ++ MD_ERROR_WIN_TRUSTED_RELATIONSHIP_FAILURE, ++ MD_ERROR_WIN_TRUST_FAILURE, ++ MD_ERROR_WIN_NETLOGON_NOT_STARTED, ++ MD_ERROR_WIN_ACCOUNT_EXPIRED, ++ MD_ERROR_WIN_REDIRECTOR_HAS_OPEN_HANDLES, ++ MD_ERROR_WIN_PRINTER_DRIVER_ALREADY_INSTALLED, ++ MD_ERROR_WIN_UNKNOWN_PORT, ++ MD_ERROR_WIN_UNKNOWN_PRINTER_DRIVER, ++ MD_ERROR_WIN_UNKNOWN_PRINTPROCESSOR, ++ MD_ERROR_WIN_INVALID_SEPARATOR_FILE, ++ MD_ERROR_WIN_INVALID_PRIORITY, ++ MD_ERROR_WIN_INVALID_PRINTER_NAME, ++ MD_ERROR_WIN_PRINTER_ALREADY_EXISTS, ++ MD_ERROR_WIN_INVALID_PRINTER_COMMAND, ++ MD_ERROR_WIN_INVALID_DATATYPE, ++ MD_ERROR_WIN_INVALID_ENVIRONMENT, ++ MD_ERROR_WIN_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, ++ MD_ERROR_WIN_NOLOGON_WORKSTATION_TRUST_ACCOUNT, ++ MD_ERROR_WIN_NOLOGON_SERVER_TRUST_ACCOUNT, ++ MD_ERROR_WIN_DOMAIN_TRUST_INCONSISTENT, ++ MD_ERROR_WIN_SERVER_HAS_OPEN_HANDLES, ++ MD_ERROR_WIN_RESOURCE_DATA_NOT_FOUND, ++ MD_ERROR_WIN_RESOURCE_TYPE_NOT_FOUND, ++ MD_ERROR_WIN_RESOURCE_NAME_NOT_FOUND, ++ MD_ERROR_WIN_RESOURCE_LANG_NOT_FOUND, ++ MD_ERROR_WIN_NOT_ENOUGH_QUOTA, ++ MD_ERROR_WIN_INVALID_TIME, ++ MD_ERROR_WIN_INVALID_FORM_NAME, ++ MD_ERROR_WIN_INVALID_FORM_SIZE, ++ MD_ERROR_WIN_ALREADY_WAITING, ++ MD_ERROR_WIN_PRINTER_DELETED, ++ MD_ERROR_WIN_INVALID_PRINTER_STATE, ++ MD_ERROR_WIN_PASSWORD_MUST_CHANGE, ++ MD_ERROR_WIN_DOMAIN_CONTROLLER_NOT_FOUND, ++ MD_ERROR_WIN_ACCOUNT_LOCKED_OUT, ++ MD_ERROR_WIN_NO_SITENAME, ++ MD_ERROR_WIN_CANT_ACCESS_FILE, ++ MD_ERROR_WIN_CANT_RESOLVE_FILENAME, ++ MD_ERROR_WIN_KM_DRIVER_BLOCKED, ++ MD_ERROR_WIN_CONTEXT_EXPIRED, ++ MD_ERROR_WIN_PER_USER_TRUST_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_ALL_USER_TRUST_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_USER_DELETE_TRUST_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_AUTHENTICATION_FIREWALL_FAILED, ++ MD_ERROR_WIN_REMOTE_PRINT_CONNECTIONS_BLOCKED, ++ MD_ERROR_WIN_NTLM_BLOCKED, ++ MD_ERROR_WIN_PASSWORD_CHANGE_REQUIRED, ++ MD_ERROR_WIN_LOST_MODE_LOGON_RESTRICTION, ++ MD_ERROR_WIN_INVALID_PIXEL_FORMAT, ++ MD_ERROR_WIN_BAD_DRIVER, ++ MD_ERROR_WIN_INVALID_WINDOW_STYLE, ++ MD_ERROR_WIN_METAFILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_TRANSFORM_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLIPPING_NOT_SUPPORTED, ++ MD_ERROR_WIN_INVALID_CMM, ++ MD_ERROR_WIN_INVALID_PROFILE, ++ MD_ERROR_WIN_TAG_NOT_FOUND, ++ MD_ERROR_WIN_TAG_NOT_PRESENT, ++ MD_ERROR_WIN_DUPLICATE_TAG, ++ MD_ERROR_WIN_PROFILE_NOT_ASSOCIATED_WITH_DEVICE, ++ MD_ERROR_WIN_PROFILE_NOT_FOUND, ++ MD_ERROR_WIN_INVALID_COLORSPACE, ++ MD_ERROR_WIN_ICM_NOT_ENABLED, ++ MD_ERROR_WIN_DELETING_ICM_XFORM, ++ MD_ERROR_WIN_INVALID_TRANSFORM, ++ MD_ERROR_WIN_COLORSPACE_MISMATCH, ++ MD_ERROR_WIN_INVALID_COLORINDEX, ++ MD_ERROR_WIN_PROFILE_DOES_NOT_MATCH_DEVICE, ++ MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD, ++ MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD_DEFAULT, ++ MD_ERROR_WIN_BAD_USERNAME, ++ MD_ERROR_WIN_NOT_CONNECTED, ++ MD_ERROR_WIN_OPEN_FILES, ++ MD_ERROR_WIN_ACTIVE_CONNECTIONS, ++ MD_ERROR_WIN_DEVICE_IN_USE, ++ MD_ERROR_WIN_UNKNOWN_PRINT_MONITOR, ++ MD_ERROR_WIN_PRINTER_DRIVER_IN_USE, ++ MD_ERROR_WIN_SPOOL_FILE_NOT_FOUND, ++ MD_ERROR_WIN_SPL_NO_STARTDOC, ++ MD_ERROR_WIN_SPL_NO_ADDJOB, ++ MD_ERROR_WIN_PRINT_PROCESSOR_ALREADY_INSTALLED, ++ MD_ERROR_WIN_PRINT_MONITOR_ALREADY_INSTALLED, ++ MD_ERROR_WIN_INVALID_PRINT_MONITOR, ++ MD_ERROR_WIN_PRINT_MONITOR_IN_USE, ++ MD_ERROR_WIN_PRINTER_HAS_JOBS_QUEUED, ++ MD_ERROR_WIN_SUCCESS_REBOOT_REQUIRED, ++ MD_ERROR_WIN_SUCCESS_RESTART_REQUIRED, ++ MD_ERROR_WIN_PRINTER_NOT_FOUND, ++ MD_ERROR_WIN_PRINTER_DRIVER_WARNED, ++ MD_ERROR_WIN_PRINTER_DRIVER_BLOCKED, ++ MD_ERROR_WIN_PRINTER_DRIVER_PACKAGE_IN_USE, ++ MD_ERROR_WIN_CORE_DRIVER_PACKAGE_NOT_FOUND, ++ MD_ERROR_WIN_FAIL_REBOOT_REQUIRED, ++ MD_ERROR_WIN_FAIL_REBOOT_INITIATED, ++ MD_ERROR_WIN_PRINTER_DRIVER_DOWNLOAD_NEEDED, ++ MD_ERROR_WIN_PRINT_JOB_RESTART_REQUIRED, ++ MD_ERROR_WIN_INVALID_PRINTER_DRIVER_MANIFEST, ++ MD_ERROR_WIN_PRINTER_NOT_SHAREABLE, ++ MD_ERROR_WIN_REQUEST_PAUSED, ++ MD_ERROR_WIN_APPEXEC_CONDITION_NOT_SATISFIED, ++ MD_ERROR_WIN_APPEXEC_HANDLE_INVALIDATED, ++ MD_ERROR_WIN_APPEXEC_INVALID_HOST_GENERATION, ++ MD_ERROR_WIN_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION, ++ MD_ERROR_WIN_APPEXEC_INVALID_HOST_STATE, ++ MD_ERROR_WIN_APPEXEC_NO_DONOR, ++ MD_ERROR_WIN_APPEXEC_HOST_ID_MISMATCH, ++ MD_ERROR_WIN_APPEXEC_UNKNOWN_USER, ++ MD_ERROR_WIN_IO_REISSUE_AS_CACHED, ++ MD_ERROR_WIN_WINS_INTERNAL, ++ MD_ERROR_WIN_CAN_NOT_DEL_LOCAL_WINS, ++ MD_ERROR_WIN_STATIC_INIT, ++ MD_ERROR_WIN_INC_BACKUP, ++ MD_ERROR_WIN_FULL_BACKUP, ++ MD_ERROR_WIN_REC_NON_EXISTENT, ++ MD_ERROR_WIN_RPL_NOT_ALLOWED, ++ MD_ERROR_WIN_DHCP_ADDRESS_CONFLICT, ++ MD_ERROR_WIN_WMI_GUID_NOT_FOUND, ++ MD_ERROR_WIN_WMI_INSTANCE_NOT_FOUND, ++ MD_ERROR_WIN_WMI_ITEMID_NOT_FOUND, ++ MD_ERROR_WIN_WMI_TRY_AGAIN, ++ MD_ERROR_WIN_WMI_DP_NOT_FOUND, ++ MD_ERROR_WIN_WMI_UNRESOLVED_INSTANCE_REF, ++ MD_ERROR_WIN_WMI_ALREADY_ENABLED, ++ MD_ERROR_WIN_WMI_GUID_DISCONNECTED, ++ MD_ERROR_WIN_WMI_SERVER_UNAVAILABLE, ++ MD_ERROR_WIN_WMI_DP_FAILED, ++ MD_ERROR_WIN_WMI_INVALID_MOF, ++ MD_ERROR_WIN_WMI_INVALID_REGINFO, ++ MD_ERROR_WIN_WMI_ALREADY_DISABLED, ++ MD_ERROR_WIN_WMI_READ_ONLY, ++ MD_ERROR_WIN_WMI_SET_FAILURE, ++ MD_ERROR_WIN_NOT_APPCONTAINER, ++ MD_ERROR_WIN_APPCONTAINER_REQUIRED, ++ MD_ERROR_WIN_NOT_SUPPORTED_IN_APPCONTAINER, ++ MD_ERROR_WIN_INVALID_PACKAGE_SID_LENGTH, ++ MD_ERROR_WIN_INVALID_MEDIA, ++ MD_ERROR_WIN_INVALID_LIBRARY, ++ MD_ERROR_WIN_INVALID_MEDIA_POOL, ++ MD_ERROR_WIN_DRIVE_MEDIA_MISMATCH, ++ MD_ERROR_WIN_MEDIA_OFFLINE, ++ MD_ERROR_WIN_LIBRARY_OFFLINE, ++ MD_ERROR_WIN_EMPTY, ++ MD_ERROR_WIN_NOT_EMPTY, ++ MD_ERROR_WIN_MEDIA_UNAVAILABLE, ++ MD_ERROR_WIN_RESOURCE_DISABLED, ++ MD_ERROR_WIN_INVALID_CLEANER, ++ MD_ERROR_WIN_UNABLE_TO_CLEAN, ++ MD_ERROR_WIN_OBJECT_NOT_FOUND, ++ MD_ERROR_WIN_DATABASE_FAILURE, ++ MD_ERROR_WIN_DATABASE_FULL, ++ MD_ERROR_WIN_MEDIA_INCOMPATIBLE, ++ MD_ERROR_WIN_RESOURCE_NOT_PRESENT, ++ MD_ERROR_WIN_INVALID_OPERATION, ++ MD_ERROR_WIN_MEDIA_NOT_AVAILABLE, ++ MD_ERROR_WIN_DEVICE_NOT_AVAILABLE, ++ MD_ERROR_WIN_REQUEST_REFUSED, ++ MD_ERROR_WIN_INVALID_DRIVE_OBJECT, ++ MD_ERROR_WIN_LIBRARY_FULL, ++ MD_ERROR_WIN_MEDIUM_NOT_ACCESSIBLE, ++ MD_ERROR_WIN_UNABLE_TO_LOAD_MEDIUM, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_DRIVE, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_SLOT, ++ MD_ERROR_WIN_UNABLE_TO_INVENTORY_TRANSPORT, ++ MD_ERROR_WIN_TRANSPORT_FULL, ++ MD_ERROR_WIN_CONTROLLING_IEPORT, ++ MD_ERROR_WIN_UNABLE_TO_EJECT_MOUNTED_MEDIA, ++ MD_ERROR_WIN_CLEANER_SLOT_SET, ++ MD_ERROR_WIN_CLEANER_SLOT_NOT_SET, ++ MD_ERROR_WIN_CLEANER_CARTRIDGE_SPENT, ++ MD_ERROR_WIN_UNEXPECTED_OMID, ++ MD_ERROR_WIN_CANT_DELETE_LAST_ITEM, ++ MD_ERROR_WIN_MESSAGE_EXCEEDS_MAX_SIZE, ++ MD_ERROR_WIN_VOLUME_CONTAINS_SYS_FILES, ++ MD_ERROR_WIN_INDIGENOUS_TYPE, ++ MD_ERROR_WIN_NO_SUPPORTING_DRIVES, ++ MD_ERROR_WIN_CLEANER_CARTRIDGE_INSTALLED, ++ MD_ERROR_WIN_IEPORT_FULL, ++ MD_ERROR_WIN_FILE_OFFLINE, ++ MD_ERROR_WIN_REMOTE_STORAGE_NOT_ACTIVE, ++ MD_ERROR_WIN_REMOTE_STORAGE_MEDIA_ERROR, ++ MD_ERROR_WIN_NOT_A_REPARSE_POINT, ++ MD_ERROR_WIN_REPARSE_ATTRIBUTE_CONFLICT, ++ MD_ERROR_WIN_INVALID_REPARSE_DATA, ++ MD_ERROR_WIN_REPARSE_TAG_INVALID, ++ MD_ERROR_WIN_REPARSE_TAG_MISMATCH, ++ MD_ERROR_WIN_REPARSE_POINT_ENCOUNTERED, ++ MD_ERROR_WIN_APP_DATA_NOT_FOUND, ++ MD_ERROR_WIN_APP_DATA_EXPIRED, ++ MD_ERROR_WIN_APP_DATA_CORRUPT, ++ MD_ERROR_WIN_APP_DATA_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_APP_DATA_REBOOT_REQUIRED, ++ MD_ERROR_WIN_SECUREBOOT_ROLLBACK_DETECTED, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_VIOLATION, ++ MD_ERROR_WIN_SECUREBOOT_INVALID_POLICY, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_SIGNED, ++ MD_ERROR_WIN_SECUREBOOT_NOT_ENABLED, ++ MD_ERROR_WIN_SECUREBOOT_FILE_REPLACED, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_AUTHORIZED, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_UNKNOWN, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION, ++ MD_ERROR_WIN_SECUREBOOT_PLATFORM_ID_MISMATCH, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_ROLLBACK_DETECTED, ++ MD_ERROR_WIN_SECUREBOOT_POLICY_UPGRADE_MISMATCH, ++ MD_ERROR_WIN_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING, ++ MD_ERROR_WIN_SECUREBOOT_NOT_BASE_POLICY, ++ MD_ERROR_WIN_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY, ++ MD_ERROR_WIN_OFFLOAD_READ_FLT_NOT_SUPPORTED, ++ MD_ERROR_WIN_OFFLOAD_WRITE_FLT_NOT_SUPPORTED, ++ MD_ERROR_WIN_OFFLOAD_READ_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_OFFLOAD_WRITE_FILE_NOT_SUPPORTED, ++ MD_ERROR_WIN_ALREADY_HAS_STREAM_ID, ++ MD_ERROR_WIN_SMR_GARBAGE_COLLECTION_REQUIRED, ++ MD_ERROR_WIN_WOF_WIM_HEADER_CORRUPT, ++ MD_ERROR_WIN_WOF_WIM_RESOURCE_TABLE_CORRUPT, ++ MD_ERROR_WIN_WOF_FILE_RESOURCE_TABLE_CORRUPT, ++ MD_ERROR_WIN_VOLUME_NOT_SIS_ENABLED, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_ROLLBACK_DETECTED, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_VIOLATION, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_INVALID_POLICY, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_TOO_MANY_POLICIES, ++ MD_ERROR_WIN_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED, ++ MD_ERROR_WIN_VSM_NOT_INITIALIZED, ++ MD_ERROR_WIN_VSM_DMA_PROTECTION_NOT_IN_USE, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_AUTHORIZED, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_INVALID, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_ACTIVE, ++ MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_SIGNED, ++ MD_ERROR_WIN_DEPENDENT_RESOURCE_EXISTS, ++ MD_ERROR_WIN_DEPENDENCY_NOT_FOUND, ++ MD_ERROR_WIN_DEPENDENCY_ALREADY_EXISTS, ++ MD_ERROR_WIN_RESOURCE_NOT_ONLINE, ++ MD_ERROR_WIN_HOST_NODE_NOT_AVAILABLE, ++ MD_ERROR_WIN_RESOURCE_NOT_AVAILABLE, ++ MD_ERROR_WIN_RESOURCE_NOT_FOUND, ++ MD_ERROR_WIN_SHUTDOWN_CLUSTER, ++ MD_ERROR_WIN_CANT_EVICT_ACTIVE_NODE, ++ MD_ERROR_WIN_OBJECT_ALREADY_EXISTS, ++ MD_ERROR_WIN_OBJECT_IN_LIST, ++ MD_ERROR_WIN_GROUP_NOT_AVAILABLE, ++ MD_ERROR_WIN_GROUP_NOT_FOUND, ++ MD_ERROR_WIN_GROUP_NOT_ONLINE, ++ MD_ERROR_WIN_HOST_NODE_NOT_RESOURCE_OWNER, ++ MD_ERROR_WIN_HOST_NODE_NOT_GROUP_OWNER, ++ MD_ERROR_WIN_RESMON_CREATE_FAILED, ++ MD_ERROR_WIN_RESMON_ONLINE_FAILED, ++ MD_ERROR_WIN_RESOURCE_ONLINE, ++ MD_ERROR_WIN_QUORUM_RESOURCE, ++ MD_ERROR_WIN_NOT_QUORUM_CAPABLE, ++ MD_ERROR_WIN_CLUSTER_SHUTTING_DOWN, ++ MD_ERROR_WIN_INVALID_STATE, ++ MD_ERROR_WIN_RESOURCE_PROPERTIES_STORED, ++ MD_ERROR_WIN_NOT_QUORUM_CLASS, ++ MD_ERROR_WIN_CORE_RESOURCE, ++ MD_ERROR_WIN_QUORUM_RESOURCE_ONLINE_FAILED, ++ MD_ERROR_WIN_QUORUMLOG_OPEN_FAILED, ++ MD_ERROR_WIN_CLUSTERLOG_CORRUPT, ++ MD_ERROR_WIN_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE, ++ MD_ERROR_WIN_CLUSTERLOG_EXCEEDS_MAXSIZE, ++ MD_ERROR_WIN_CLUSTERLOG_CHKPOINT_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTERLOG_NOT_ENOUGH_SPACE, ++ MD_ERROR_WIN_QUORUM_OWNER_ALIVE, ++ MD_ERROR_WIN_NETWORK_NOT_AVAILABLE, ++ MD_ERROR_WIN_NODE_NOT_AVAILABLE, ++ MD_ERROR_WIN_ALL_NODES_NOT_AVAILABLE, ++ MD_ERROR_WIN_RESOURCE_FAILED, ++ MD_ERROR_WIN_CLUSTER_INVALID_NODE, ++ MD_ERROR_WIN_CLUSTER_NODE_EXISTS, ++ MD_ERROR_WIN_CLUSTER_JOIN_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_LOCAL_NODE_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_NETWORK_EXISTS, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_NETINTERFACE_EXISTS, ++ MD_ERROR_WIN_CLUSTER_NETINTERFACE_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_INVALID_REQUEST, ++ MD_ERROR_WIN_CLUSTER_INVALID_NETWORK_PROVIDER, ++ MD_ERROR_WIN_CLUSTER_NODE_DOWN, ++ MD_ERROR_WIN_CLUSTER_NODE_UNREACHABLE, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_MEMBER, ++ MD_ERROR_WIN_CLUSTER_JOIN_NOT_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_INVALID_NETWORK, ++ MD_ERROR_WIN_CLUSTER_NODE_UP, ++ MD_ERROR_WIN_CLUSTER_IPADDR_IN_USE, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_PAUSED, ++ MD_ERROR_WIN_CLUSTER_NO_SECURITY_CONTEXT, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_INTERNAL, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_UP, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_DOWN, ++ MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_ONLINE, ++ MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_OFFLINE, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_MEMBER, ++ MD_ERROR_WIN_CLUSTER_LAST_INTERNAL_NETWORK, ++ MD_ERROR_WIN_CLUSTER_NETWORK_HAS_DEPENDENTS, ++ MD_ERROR_WIN_INVALID_OPERATION_ON_QUORUM, ++ MD_ERROR_WIN_DEPENDENCY_NOT_ALLOWED, ++ MD_ERROR_WIN_CLUSTER_NODE_PAUSED, ++ MD_ERROR_WIN_NODE_CANT_HOST_RESOURCE, ++ MD_ERROR_WIN_CLUSTER_NODE_NOT_READY, ++ MD_ERROR_WIN_CLUSTER_NODE_SHUTTING_DOWN, ++ MD_ERROR_WIN_CLUSTER_JOIN_ABORTED, ++ MD_ERROR_WIN_CLUSTER_INCOMPATIBLE_VERSIONS, ++ MD_ERROR_WIN_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED, ++ MD_ERROR_WIN_CLUSTER_SYSTEM_CONFIG_CHANGED, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_RESTYPE_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLUSTER_RESNAME_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_NO_RPC_PACKAGES_REGISTERED, ++ MD_ERROR_WIN_CLUSTER_OWNER_NOT_IN_PREFLIST, ++ MD_ERROR_WIN_CLUSTER_DATABASE_SEQMISMATCH, ++ MD_ERROR_WIN_RESMON_INVALID_STATE, ++ MD_ERROR_WIN_CLUSTER_GUM_NOT_LOCKER, ++ MD_ERROR_WIN_QUORUM_DISK_NOT_FOUND, ++ MD_ERROR_WIN_DATABASE_BACKUP_CORRUPT, ++ MD_ERROR_WIN_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT, ++ MD_ERROR_WIN_RESOURCE_PROPERTY_UNCHANGEABLE, ++ MD_ERROR_WIN_NO_ADMIN_ACCESS_POINT, ++ MD_ERROR_WIN_CLUSTER_MEMBERSHIP_INVALID_STATE, ++ MD_ERROR_WIN_CLUSTER_QUORUMLOG_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_MEMBERSHIP_HALT, ++ MD_ERROR_WIN_CLUSTER_INSTANCE_ID_MISMATCH, ++ MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND_FOR_IP, ++ MD_ERROR_WIN_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH, ++ MD_ERROR_WIN_CLUSTER_EVICT_WITHOUT_CLEANUP, ++ MD_ERROR_WIN_CLUSTER_PARAMETER_MISMATCH, ++ MD_ERROR_WIN_NODE_CANNOT_BE_CLUSTERED, ++ MD_ERROR_WIN_CLUSTER_WRONG_OS_VERSION, ++ MD_ERROR_WIN_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME, ++ MD_ERROR_WIN_CLUSCFG_ALREADY_COMMITTED, ++ MD_ERROR_WIN_CLUSCFG_ROLLBACK_FAILED, ++ MD_ERROR_WIN_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT, ++ MD_ERROR_WIN_CLUSTER_OLD_VERSION, ++ MD_ERROR_WIN_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME, ++ MD_ERROR_WIN_CLUSTER_NO_NET_ADAPTERS, ++ MD_ERROR_WIN_CLUSTER_POISONED, ++ MD_ERROR_WIN_CLUSTER_GROUP_MOVING, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_BUSY, ++ MD_ERROR_WIN_RESOURCE_CALL_TIMED_OUT, ++ MD_ERROR_WIN_INVALID_CLUSTER_IPV6_ADDRESS, ++ MD_ERROR_WIN_CLUSTER_INTERNAL_INVALID_FUNCTION, ++ MD_ERROR_WIN_CLUSTER_PARAMETER_OUT_OF_BOUNDS, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_SEND, ++ MD_ERROR_WIN_CLUSTER_REGISTRY_INVALID_FUNCTION, ++ MD_ERROR_WIN_CLUSTER_INVALID_STRING_TERMINATION, ++ MD_ERROR_WIN_CLUSTER_INVALID_STRING_FORMAT, ++ MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_NULL_DATA, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_READ, ++ MD_ERROR_WIN_CLUSTER_PARTIAL_WRITE, ++ MD_ERROR_WIN_CLUSTER_CANT_DESERIALIZE_DATA, ++ MD_ERROR_WIN_DEPENDENT_RESOURCE_PROPERTY_CONFLICT, ++ MD_ERROR_WIN_CLUSTER_NO_QUORUM, ++ MD_ERROR_WIN_CLUSTER_INVALID_IPV6_NETWORK, ++ MD_ERROR_WIN_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK, ++ MD_ERROR_WIN_QUORUM_NOT_ALLOWED_IN_THIS_GROUP, ++ MD_ERROR_WIN_DEPENDENCY_TREE_TOO_COMPLEX, ++ MD_ERROR_WIN_EXCEPTION_IN_RESOURCE_CALL, ++ MD_ERROR_WIN_CLUSTER_RHS_FAILED_INITIALIZATION, ++ MD_ERROR_WIN_CLUSTER_NOT_INSTALLED, ++ MD_ERROR_WIN_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE, ++ MD_ERROR_WIN_CLUSTER_MAX_NODES_IN_CLUSTER, ++ MD_ERROR_WIN_CLUSTER_TOO_MANY_NODES, ++ MD_ERROR_WIN_CLUSTER_OBJECT_ALREADY_USED, ++ MD_ERROR_WIN_NONCORE_GROUPS_FOUND, ++ MD_ERROR_WIN_FILE_SHARE_RESOURCE_CONFLICT, ++ MD_ERROR_WIN_CLUSTER_EVICT_INVALID_REQUEST, ++ MD_ERROR_WIN_CLUSTER_SINGLETON_RESOURCE, ++ MD_ERROR_WIN_CLUSTER_GROUP_SINGLETON_RESOURCE, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_PROVIDER_FAILED, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_CONFIGURATION_ERROR, ++ MD_ERROR_WIN_CLUSTER_GROUP_BUSY, ++ MD_ERROR_WIN_CLUSTER_NOT_SHARED_VOLUME, ++ MD_ERROR_WIN_CLUSTER_INVALID_SECURITY_DESCRIPTOR, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUMES_IN_USE, ++ MD_ERROR_WIN_CLUSTER_USE_SHARED_VOLUMES_API, ++ MD_ERROR_WIN_CLUSTER_BACKUP_IN_PROGRESS, ++ MD_ERROR_WIN_NON_CSV_PATH, ++ MD_ERROR_WIN_CSV_VOLUME_NOT_LOCAL, ++ MD_ERROR_WIN_CLUSTER_WATCHDOG_TERMINATING, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES, ++ MD_ERROR_WIN_CLUSTER_INVALID_NODE_WEIGHT, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_CALL, ++ MD_ERROR_WIN_RESMON_SYSTEM_RESOURCES_LACKING, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE, ++ MD_ERROR_WIN_CLUSTER_GROUP_QUEUED, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_LOCKED_STATUS, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED, ++ MD_ERROR_WIN_CLUSTER_NODE_DRAIN_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_DISK_NOT_CONNECTED, ++ MD_ERROR_WIN_DISK_NOT_CSV_CAPABLE, ++ MD_ERROR_WIN_RESOURCE_NOT_IN_AVAILABLE_STORAGE, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_REDIRECTED, ++ MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED, ++ MD_ERROR_WIN_CLUSTER_CANNOT_RETURN_PROPERTIES, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE, ++ MD_ERROR_WIN_CLUSTER_AFFINITY_CONFLICT, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_RESTART_REQUIRED, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_IN_PROGRESS, ++ MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPLETE, ++ MD_ERROR_WIN_CLUSTER_NODE_IN_GRACE_PERIOD, ++ MD_ERROR_WIN_CLUSTER_CSV_IO_PAUSE_TIMEOUT, ++ MD_ERROR_WIN_NODE_NOT_ACTIVE_CLUSTER_MEMBER, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_NOT_MONITORED, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED, ++ MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICATED, ++ MD_ERROR_WIN_CLUSTER_NODE_ISOLATED, ++ MD_ERROR_WIN_CLUSTER_NODE_QUARANTINED, ++ MD_ERROR_WIN_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED, ++ MD_ERROR_WIN_CLUSTER_SPACE_DEGRADED, ++ MD_ERROR_WIN_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED, ++ MD_ERROR_WIN_CLUSTER_CSV_INVALID_HANDLE, ++ MD_ERROR_WIN_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR, ++ MD_ERROR_WIN_GROUPSET_NOT_AVAILABLE, ++ MD_ERROR_WIN_GROUPSET_NOT_FOUND, ++ MD_ERROR_WIN_GROUPSET_CANT_PROVIDE, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION, ++ MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS, ++ MD_ERROR_WIN_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME, ++ MD_ERROR_WIN_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE, ++ MD_ERROR_WIN_ENCRYPTION_FAILED, ++ MD_ERROR_WIN_DECRYPTION_FAILED, ++ MD_ERROR_WIN_FILE_ENCRYPTED, ++ MD_ERROR_WIN_NO_RECOVERY_POLICY, ++ MD_ERROR_WIN_NO_EFS, ++ MD_ERROR_WIN_WRONG_EFS, ++ MD_ERROR_WIN_NO_USER_KEYS, ++ MD_ERROR_WIN_FILE_NOT_ENCRYPTED, ++ MD_ERROR_WIN_NOT_EXPORT_FORMAT, ++ MD_ERROR_WIN_FILE_READ_ONLY, ++ MD_ERROR_WIN_DIR_EFS_DISALLOWED, ++ MD_ERROR_WIN_EFS_SERVER_NOT_TRUSTED, ++ MD_ERROR_WIN_BAD_RECOVERY_POLICY, ++ MD_ERROR_WIN_EFS_ALG_BLOB_TOO_BIG, ++ MD_ERROR_WIN_VOLUME_NOT_SUPPORT_EFS, ++ MD_ERROR_WIN_EFS_DISABLED, ++ MD_ERROR_WIN_EFS_VERSION_NOT_SUPPORT, ++ MD_ERROR_WIN_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, ++ MD_ERROR_WIN_CS_ENCRYPTION_UNSUPPORTED_SERVER, ++ MD_ERROR_WIN_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, ++ MD_ERROR_WIN_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, ++ MD_ERROR_WIN_CS_ENCRYPTION_FILE_NOT_CSE, ++ MD_ERROR_WIN_ENCRYPTION_POLICY_DENIES_OPERATION, ++ MD_ERROR_WIN_WIP_ENCRYPTION_FAILED, ++ MD_ERROR_WIN_NO_BROWSER_SERVERS_FOUND, ++ MD_ERROR_WIN_CLUSTER_OBJECT_IS_CLUSTER_SET_VM, ++ MD_ERROR_WIN_LOG_SECTOR_INVALID, ++ MD_ERROR_WIN_LOG_SECTOR_PARITY_INVALID, ++ MD_ERROR_WIN_LOG_SECTOR_REMAPPED, ++ MD_ERROR_WIN_LOG_BLOCK_INCOMPLETE, ++ MD_ERROR_WIN_LOG_INVALID_RANGE, ++ MD_ERROR_WIN_LOG_BLOCKS_EXHAUSTED, ++ MD_ERROR_WIN_LOG_READ_CONTEXT_INVALID, ++ MD_ERROR_WIN_LOG_RESTART_INVALID, ++ MD_ERROR_WIN_LOG_BLOCK_VERSION, ++ MD_ERROR_WIN_LOG_BLOCK_INVALID, ++ MD_ERROR_WIN_LOG_READ_MODE_INVALID, ++ MD_ERROR_WIN_LOG_NO_RESTART, ++ MD_ERROR_WIN_LOG_METADATA_CORRUPT, ++ MD_ERROR_WIN_LOG_METADATA_INVALID, ++ MD_ERROR_WIN_LOG_METADATA_INCONSISTENT, ++ MD_ERROR_WIN_LOG_RESERVATION_INVALID, ++ MD_ERROR_WIN_LOG_CANT_DELETE, ++ MD_ERROR_WIN_LOG_CONTAINER_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_LOG_START_OF_LOG, ++ MD_ERROR_WIN_LOG_POLICY_ALREADY_INSTALLED, ++ MD_ERROR_WIN_LOG_POLICY_NOT_INSTALLED, ++ MD_ERROR_WIN_LOG_POLICY_INVALID, ++ MD_ERROR_WIN_LOG_POLICY_CONFLICT, ++ MD_ERROR_WIN_LOG_PINNED_ARCHIVE_TAIL, ++ MD_ERROR_WIN_LOG_RECORD_NONEXISTENT, ++ MD_ERROR_WIN_LOG_RECORDS_RESERVED_INVALID, ++ MD_ERROR_WIN_LOG_SPACE_RESERVED_INVALID, ++ MD_ERROR_WIN_LOG_TAIL_INVALID, ++ MD_ERROR_WIN_LOG_FULL, ++ MD_ERROR_WIN_COULD_NOT_RESIZE_LOG, ++ MD_ERROR_WIN_LOG_MULTIPLEXED, ++ MD_ERROR_WIN_LOG_DEDICATED, ++ MD_ERROR_WIN_LOG_ARCHIVE_NOT_IN_PROGRESS, ++ MD_ERROR_WIN_LOG_ARCHIVE_IN_PROGRESS, ++ MD_ERROR_WIN_LOG_EPHEMERAL, ++ MD_ERROR_WIN_LOG_NOT_ENOUGH_CONTAINERS, ++ MD_ERROR_WIN_LOG_CLIENT_ALREADY_REGISTERED, ++ MD_ERROR_WIN_LOG_CLIENT_NOT_REGISTERED, ++ MD_ERROR_WIN_LOG_FULL_HANDLER_IN_PROGRESS, ++ MD_ERROR_WIN_LOG_CONTAINER_READ_FAILED, ++ MD_ERROR_WIN_LOG_CONTAINER_WRITE_FAILED, ++ MD_ERROR_WIN_LOG_CONTAINER_OPEN_FAILED, ++ MD_ERROR_WIN_LOG_CONTAINER_STATE_INVALID, ++ MD_ERROR_WIN_LOG_STATE_INVALID, ++ MD_ERROR_WIN_LOG_PINNED, ++ MD_ERROR_WIN_LOG_METADATA_FLUSH_FAILED, ++ MD_ERROR_WIN_LOG_INCONSISTENT_SECURITY, ++ MD_ERROR_WIN_LOG_APPENDED_FLUSH_FAILED, ++ MD_ERROR_WIN_LOG_PINNED_RESERVATION, ++ MD_ERROR_WIN_INVALID_TRANSACTION, ++ MD_ERROR_WIN_TRANSACTION_NOT_ACTIVE, ++ MD_ERROR_WIN_TRANSACTION_REQUEST_NOT_VALID, ++ MD_ERROR_WIN_TRANSACTION_NOT_REQUESTED, ++ MD_ERROR_WIN_TRANSACTION_ALREADY_ABORTED, ++ MD_ERROR_WIN_TRANSACTION_ALREADY_COMMITTED, ++ MD_ERROR_WIN_TM_INITIALIZATION_FAILED, ++ MD_ERROR_WIN_RESOURCEMANAGER_READ_ONLY, ++ MD_ERROR_WIN_TRANSACTION_NOT_JOINED, ++ MD_ERROR_WIN_TRANSACTION_SUPERIOR_EXISTS, ++ MD_ERROR_WIN_CRM_PROTOCOL_ALREADY_EXISTS, ++ MD_ERROR_WIN_TRANSACTION_PROPAGATION_FAILED, ++ MD_ERROR_WIN_CRM_PROTOCOL_NOT_FOUND, ++ MD_ERROR_WIN_TRANSACTION_INVALID_MARSHALL_BUFFER, ++ MD_ERROR_WIN_CURRENT_TRANSACTION_NOT_VALID, ++ MD_ERROR_WIN_TRANSACTION_NOT_FOUND, ++ MD_ERROR_WIN_RESOURCEMANAGER_NOT_FOUND, ++ MD_ERROR_WIN_ENLISTMENT_NOT_FOUND, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_FOUND, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_ONLINE, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, ++ MD_ERROR_WIN_TRANSACTION_NOT_ROOT, ++ MD_ERROR_WIN_TRANSACTION_OBJECT_EXPIRED, ++ MD_ERROR_WIN_TRANSACTION_RESPONSE_NOT_ENLISTED, ++ MD_ERROR_WIN_TRANSACTION_RECORD_TOO_LONG, ++ MD_ERROR_WIN_IMPLICIT_TRANSACTION_NOT_SUPPORTED, ++ MD_ERROR_WIN_TRANSACTION_INTEGRITY_VIOLATED, ++ MD_ERROR_WIN_TRANSACTIONMANAGER_IDENTITY_MISMATCH, ++ MD_ERROR_WIN_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT, ++ MD_ERROR_WIN_TRANSACTION_MUST_WRITETHROUGH, ++ MD_ERROR_WIN_TRANSACTION_NO_SUPERIOR, ++ MD_ERROR_WIN_HEURISTIC_DAMAGE_POSSIBLE, ++ MD_ERROR_WIN_TRANSACTIONAL_CONFLICT, ++ MD_ERROR_WIN_RM_NOT_ACTIVE, ++ MD_ERROR_WIN_RM_METADATA_CORRUPT, ++ MD_ERROR_WIN_DIRECTORY_NOT_RM, ++ MD_ERROR_WIN_TRANSACTIONS_UNSUPPORTED_REMOTE, ++ MD_ERROR_WIN_LOG_RESIZE_INVALID_SIZE, ++ MD_ERROR_WIN_OBJECT_NO_LONGER_EXISTS, ++ MD_ERROR_WIN_STREAM_MINIVERSION_NOT_FOUND, ++ MD_ERROR_WIN_STREAM_MINIVERSION_NOT_VALID, ++ MD_ERROR_WIN_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, ++ MD_ERROR_WIN_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, ++ MD_ERROR_WIN_CANT_CREATE_MORE_STREAM_MINIVERSIONS, ++ MD_ERROR_WIN_REMOTE_FILE_VERSION_MISMATCH, ++ MD_ERROR_WIN_HANDLE_NO_LONGER_VALID, ++ MD_ERROR_WIN_NO_TXF_METADATA, ++ MD_ERROR_WIN_LOG_CORRUPTION_DETECTED, ++ MD_ERROR_WIN_CANT_RECOVER_WITH_HANDLE_OPEN, ++ MD_ERROR_WIN_RM_DISCONNECTED, ++ MD_ERROR_WIN_ENLISTMENT_NOT_SUPERIOR, ++ MD_ERROR_WIN_RECOVERY_NOT_NEEDED, ++ MD_ERROR_WIN_RM_ALREADY_STARTED, ++ MD_ERROR_WIN_FILE_IDENTITY_NOT_PERSISTENT, ++ MD_ERROR_WIN_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, ++ MD_ERROR_WIN_CANT_CROSS_RM_BOUNDARY, ++ MD_ERROR_WIN_TXF_DIR_NOT_EMPTY, ++ MD_ERROR_WIN_INDOUBT_TRANSACTIONS_EXIST, ++ MD_ERROR_WIN_TM_VOLATILE, ++ MD_ERROR_WIN_ROLLBACK_TIMER_EXPIRED, ++ MD_ERROR_WIN_TXF_ATTRIBUTE_CORRUPT, ++ MD_ERROR_WIN_EFS_NOT_ALLOWED_IN_TRANSACTION, ++ MD_ERROR_WIN_TRANSACTIONAL_OPEN_NOT_ALLOWED, ++ MD_ERROR_WIN_LOG_GROWTH_FAILED, ++ MD_ERROR_WIN_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, ++ MD_ERROR_WIN_TXF_METADATA_ALREADY_PRESENT, ++ MD_ERROR_WIN_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, ++ MD_ERROR_WIN_TRANSACTION_REQUIRED_PROMOTION, ++ MD_ERROR_WIN_CANNOT_EXECUTE_FILE_IN_TRANSACTION, ++ MD_ERROR_WIN_TRANSACTIONS_NOT_FROZEN, ++ MD_ERROR_WIN_TRANSACTION_FREEZE_IN_PROGRESS, ++ MD_ERROR_WIN_NOT_SNAPSHOT_VOLUME, ++ MD_ERROR_WIN_NO_SAVEPOINT_WITH_OPEN_FILES, ++ MD_ERROR_WIN_DATA_LOST_REPAIR, ++ MD_ERROR_WIN_SPARSE_NOT_ALLOWED_IN_TRANSACTION, ++ MD_ERROR_WIN_TM_IDENTITY_MISMATCH, ++ MD_ERROR_WIN_FLOATED_SECTION, ++ MD_ERROR_WIN_CANNOT_ACCEPT_TRANSACTED_WORK, ++ MD_ERROR_WIN_CANNOT_ABORT_TRANSACTIONS, ++ MD_ERROR_WIN_BAD_CLUSTERS, ++ MD_ERROR_WIN_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, ++ MD_ERROR_WIN_VOLUME_DIRTY, ++ MD_ERROR_WIN_NO_LINK_TRACKING_IN_TRANSACTION, ++ MD_ERROR_WIN_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, ++ MD_ERROR_WIN_EXPIRED_HANDLE, ++ MD_ERROR_WIN_TRANSACTION_NOT_ENLISTED, ++ MD_ERROR_WIN_CTX_WINSTATION_NAME_INVALID, ++ MD_ERROR_WIN_CTX_INVALID_PD, ++ MD_ERROR_WIN_CTX_PD_NOT_FOUND, ++ MD_ERROR_WIN_CTX_WD_NOT_FOUND, ++ MD_ERROR_WIN_CTX_CANNOT_MAKE_EVENTLOG_ENTRY, ++ MD_ERROR_WIN_CTX_SERVICE_NAME_COLLISION, ++ MD_ERROR_WIN_CTX_CLOSE_PENDING, ++ MD_ERROR_WIN_CTX_NO_OUTBUF, ++ MD_ERROR_WIN_CTX_MODEM_INF_NOT_FOUND, ++ MD_ERROR_WIN_CTX_INVALID_MODEMNAME, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_ERROR, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_TIMEOUT, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_CARRIER, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_DIALTONE, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_BUSY, ++ MD_ERROR_WIN_CTX_MODEM_RESPONSE_VOICE, ++ MD_ERROR_WIN_CTX_TD_ERROR, ++ MD_ERROR_WIN_CTX_WINSTATION_NOT_FOUND, ++ MD_ERROR_WIN_CTX_WINSTATION_ALREADY_EXISTS, ++ MD_ERROR_WIN_CTX_WINSTATION_BUSY, ++ MD_ERROR_WIN_CTX_BAD_VIDEO_MODE, ++ MD_ERROR_WIN_CTX_GRAPHICS_INVALID, ++ MD_ERROR_WIN_CTX_LOGON_DISABLED, ++ MD_ERROR_WIN_CTX_NOT_CONSOLE, ++ MD_ERROR_WIN_CTX_CLIENT_QUERY_TIMEOUT, ++ MD_ERROR_WIN_CTX_CONSOLE_DISCONNECT, ++ MD_ERROR_WIN_CTX_CONSOLE_CONNECT, ++ MD_ERROR_WIN_CTX_SHADOW_DENIED, ++ MD_ERROR_WIN_CTX_WINSTATION_ACCESS_DENIED, ++ MD_ERROR_WIN_CTX_INVALID_WD, ++ MD_ERROR_WIN_CTX_SHADOW_INVALID, ++ MD_ERROR_WIN_CTX_SHADOW_DISABLED, ++ MD_ERROR_WIN_CTX_CLIENT_LICENSE_IN_USE, ++ MD_ERROR_WIN_CTX_CLIENT_LICENSE_NOT_SET, ++ MD_ERROR_WIN_CTX_LICENSE_NOT_AVAILABLE, ++ MD_ERROR_WIN_CTX_LICENSE_CLIENT_INVALID, ++ MD_ERROR_WIN_CTX_LICENSE_EXPIRED, ++ MD_ERROR_WIN_CTX_SHADOW_NOT_RUNNING, ++ MD_ERROR_WIN_CTX_SHADOW_ENDED_BY_MODE_CHANGE, ++ MD_ERROR_WIN_ACTIVATION_COUNT_EXCEEDED, ++ MD_ERROR_WIN_CTX_WINSTATIONS_DISABLED, ++ MD_ERROR_WIN_CTX_ENCRYPTION_LEVEL_REQUIRED, ++ MD_ERROR_WIN_CTX_SESSION_IN_USE, ++ MD_ERROR_WIN_CTX_NO_FORCE_LOGOFF, ++ MD_ERROR_WIN_CTX_ACCOUNT_RESTRICTION, ++ MD_ERROR_WIN_RDP_PROTOCOL_ERROR, ++ MD_ERROR_WIN_CTX_CDM_CONNECT, ++ MD_ERROR_WIN_CTX_CDM_DISCONNECT, ++ MD_ERROR_WIN_CTX_SECURITY_LAYER_ERROR, ++ MD_ERROR_WIN_TS_INCOMPATIBLE_SESSIONS, ++ MD_ERROR_WIN_TS_VIDEO_SUBSYSTEM_ERROR, ++ MD_ERROR_WIN_DS_NOT_INSTALLED, ++ MD_ERROR_WIN_DS_MEMBERSHIP_EVALUATED_LOCALLY, ++ MD_ERROR_WIN_DS_NO_ATTRIBUTE_OR_VALUE, ++ MD_ERROR_WIN_DS_INVALID_ATTRIBUTE_SYNTAX, ++ MD_ERROR_WIN_DS_ATTRIBUTE_TYPE_UNDEFINED, ++ MD_ERROR_WIN_DS_ATTRIBUTE_OR_VALUE_EXISTS, ++ MD_ERROR_WIN_DS_BUSY, ++ MD_ERROR_WIN_DS_UNAVAILABLE, ++ MD_ERROR_WIN_DS_NO_RIDS_ALLOCATED, ++ MD_ERROR_WIN_DS_NO_MORE_RIDS, ++ MD_ERROR_WIN_DS_INCORRECT_ROLE_OWNER, ++ MD_ERROR_WIN_DS_RIDMGR_INIT_ERROR, ++ MD_ERROR_WIN_DS_OBJ_CLASS_VIOLATION, ++ MD_ERROR_WIN_DS_CANT_ON_NON_LEAF, ++ MD_ERROR_WIN_DS_CANT_ON_RDN, ++ MD_ERROR_WIN_DS_CANT_MOD_OBJ_CLASS, ++ MD_ERROR_WIN_DS_CROSS_DOM_MOVE_ERROR, ++ MD_ERROR_WIN_DS_GC_NOT_AVAILABLE, ++ MD_ERROR_WIN_SHARED_POLICY, ++ MD_ERROR_WIN_POLICY_OBJECT_NOT_FOUND, ++ MD_ERROR_WIN_POLICY_ONLY_IN_DS, ++ MD_ERROR_WIN_PROMOTION_ACTIVE, ++ MD_ERROR_WIN_NO_PROMOTION_ACTIVE, ++ MD_ERROR_WIN_DS_OPERATIONS_ERROR, ++ MD_ERROR_WIN_DS_PROTOCOL_ERROR, ++ MD_ERROR_WIN_DS_TIMELIMIT_EXCEEDED, ++ MD_ERROR_WIN_DS_SIZELIMIT_EXCEEDED, ++ MD_ERROR_WIN_DS_ADMIN_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_DS_COMPARE_FALSE, ++ MD_ERROR_WIN_DS_COMPARE_TRUE, ++ MD_ERROR_WIN_DS_AUTH_METHOD_NOT_SUPPORTED, ++ MD_ERROR_WIN_DS_STRONG_AUTH_REQUIRED, ++ MD_ERROR_WIN_DS_INAPPROPRIATE_AUTH, ++ MD_ERROR_WIN_DS_AUTH_UNKNOWN, ++ MD_ERROR_WIN_DS_REFERRAL, ++ MD_ERROR_WIN_DS_UNAVAILABLE_CRIT_EXTENSION, ++ MD_ERROR_WIN_DS_CONFIDENTIALITY_REQUIRED, ++ MD_ERROR_WIN_DS_INAPPROPRIATE_MATCHING, ++ MD_ERROR_WIN_DS_CONSTRAINT_VIOLATION, ++ MD_ERROR_WIN_DS_NO_SUCH_OBJECT, ++ MD_ERROR_WIN_DS_ALIAS_PROBLEM, ++ MD_ERROR_WIN_DS_INVALID_DN_SYNTAX, ++ MD_ERROR_WIN_DS_IS_LEAF, ++ MD_ERROR_WIN_DS_ALIAS_DEREF_PROBLEM, ++ MD_ERROR_WIN_DS_UNWILLING_TO_PERFORM, ++ MD_ERROR_WIN_DS_LOOP_DETECT, ++ MD_ERROR_WIN_DS_NAMING_VIOLATION, ++ MD_ERROR_WIN_DS_OBJECT_RESULTS_TOO_LARGE, ++ MD_ERROR_WIN_DS_AFFECTS_MULTIPLE_DSAS, ++ MD_ERROR_WIN_DS_SERVER_DOWN, ++ MD_ERROR_WIN_DS_LOCAL_ERROR, ++ MD_ERROR_WIN_DS_ENCODING_ERROR, ++ MD_ERROR_WIN_DS_DECODING_ERROR, ++ MD_ERROR_WIN_DS_FILTER_UNKNOWN, ++ MD_ERROR_WIN_DS_PARAM_ERROR, ++ MD_ERROR_WIN_DS_NOT_SUPPORTED, ++ MD_ERROR_WIN_DS_NO_RESULTS_RETURNED, ++ MD_ERROR_WIN_DS_CONTROL_NOT_FOUND, ++ MD_ERROR_WIN_DS_CLIENT_LOOP, ++ MD_ERROR_WIN_DS_REFERRAL_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_DS_SORT_CONTROL_MISSING, ++ MD_ERROR_WIN_DS_OFFSET_RANGE_ERROR, ++ MD_ERROR_WIN_DS_RIDMGR_DISABLED, ++ MD_ERROR_WIN_DS_ROOT_MUST_BE_NC, ++ MD_ERROR_WIN_DS_ADD_REPLICA_INHIBITED, ++ MD_ERROR_WIN_DS_ATT_NOT_DEF_IN_SCHEMA, ++ MD_ERROR_WIN_DS_MAX_OBJ_SIZE_EXCEEDED, ++ MD_ERROR_WIN_DS_OBJ_STRING_NAME_EXISTS, ++ MD_ERROR_WIN_DS_NO_RDN_DEFINED_IN_SCHEMA, ++ MD_ERROR_WIN_DS_RDN_DOESNT_MATCH_SCHEMA, ++ MD_ERROR_WIN_DS_NO_REQUESTED_ATTS_FOUND, ++ MD_ERROR_WIN_DS_USER_BUFFER_TO_SMALL, ++ MD_ERROR_WIN_DS_ATT_IS_NOT_ON_OBJ, ++ MD_ERROR_WIN_DS_ILLEGAL_MOD_OPERATION, ++ MD_ERROR_WIN_DS_OBJ_TOO_LARGE, ++ MD_ERROR_WIN_DS_BAD_INSTANCE_TYPE, ++ MD_ERROR_WIN_DS_MASTERDSA_REQUIRED, ++ MD_ERROR_WIN_DS_OBJECT_CLASS_REQUIRED, ++ MD_ERROR_WIN_DS_MISSING_REQUIRED_ATT, ++ MD_ERROR_WIN_DS_ATT_NOT_DEF_FOR_CLASS, ++ MD_ERROR_WIN_DS_ATT_ALREADY_EXISTS, ++ MD_ERROR_WIN_DS_CANT_ADD_ATT_VALUES, ++ MD_ERROR_WIN_DS_SINGLE_VALUE_CONSTRAINT, ++ MD_ERROR_WIN_DS_RANGE_CONSTRAINT, ++ MD_ERROR_WIN_DS_ATT_VAL_ALREADY_EXISTS, ++ MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT, ++ MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT_VAL, ++ MD_ERROR_WIN_DS_ROOT_CANT_BE_SUBREF, ++ MD_ERROR_WIN_DS_NO_CHAINING, ++ MD_ERROR_WIN_DS_NO_CHAINED_EVAL, ++ MD_ERROR_WIN_DS_NO_PARENT_OBJECT, ++ MD_ERROR_WIN_DS_PARENT_IS_AN_ALIAS, ++ MD_ERROR_WIN_DS_CANT_MIX_MASTER_AND_REPS, ++ MD_ERROR_WIN_DS_CHILDREN_EXIST, ++ MD_ERROR_WIN_DS_OBJ_NOT_FOUND, ++ MD_ERROR_WIN_DS_ALIASED_OBJ_MISSING, ++ MD_ERROR_WIN_DS_BAD_NAME_SYNTAX, ++ MD_ERROR_WIN_DS_ALIAS_POINTS_TO_ALIAS, ++ MD_ERROR_WIN_DS_CANT_DEREF_ALIAS, ++ MD_ERROR_WIN_DS_OUT_OF_SCOPE, ++ MD_ERROR_WIN_DS_OBJECT_BEING_REMOVED, ++ MD_ERROR_WIN_DS_CANT_DELETE_DSA_OBJ, ++ MD_ERROR_WIN_DS_GENERIC_ERROR, ++ MD_ERROR_WIN_DS_DSA_MUST_BE_INT_MASTER, ++ MD_ERROR_WIN_DS_CLASS_NOT_DSA, ++ MD_ERROR_WIN_DS_INSUFF_ACCESS_RIGHTS, ++ MD_ERROR_WIN_DS_ILLEGAL_SUPERIOR, ++ MD_ERROR_WIN_DS_ATTRIBUTE_OWNED_BY_SAM, ++ MD_ERROR_WIN_DS_NAME_TOO_MANY_PARTS, ++ MD_ERROR_WIN_DS_NAME_TOO_LONG, ++ MD_ERROR_WIN_DS_NAME_VALUE_TOO_LONG, ++ MD_ERROR_WIN_DS_NAME_UNPARSEABLE, ++ MD_ERROR_WIN_DS_NAME_TYPE_UNKNOWN, ++ MD_ERROR_WIN_DS_NOT_AN_OBJECT, ++ MD_ERROR_WIN_DS_SEC_DESC_TOO_SHORT, ++ MD_ERROR_WIN_DS_SEC_DESC_INVALID, ++ MD_ERROR_WIN_DS_NO_DELETED_NAME, ++ MD_ERROR_WIN_DS_SUBREF_MUST_HAVE_PARENT, ++ MD_ERROR_WIN_DS_NCNAME_MUST_BE_NC, ++ MD_ERROR_WIN_DS_CANT_ADD_SYSTEM_ONLY, ++ MD_ERROR_WIN_DS_CLASS_MUST_BE_CONCRETE, ++ MD_ERROR_WIN_DS_INVALID_DMD, ++ MD_ERROR_WIN_DS_OBJ_GUID_EXISTS, ++ MD_ERROR_WIN_DS_NOT_ON_BACKLINK, ++ MD_ERROR_WIN_DS_NO_CROSSREF_FOR_NC, ++ MD_ERROR_WIN_DS_SHUTTING_DOWN, ++ MD_ERROR_WIN_DS_UNKNOWN_OPERATION, ++ MD_ERROR_WIN_DS_INVALID_ROLE_OWNER, ++ MD_ERROR_WIN_DS_COULDNT_CONTACT_FSMO, ++ MD_ERROR_WIN_DS_CROSS_NC_DN_RENAME, ++ MD_ERROR_WIN_DS_CANT_MOD_SYSTEM_ONLY, ++ MD_ERROR_WIN_DS_REPLICATOR_ONLY, ++ MD_ERROR_WIN_DS_OBJ_CLASS_NOT_DEFINED, ++ MD_ERROR_WIN_DS_OBJ_CLASS_NOT_SUBCLASS, ++ MD_ERROR_WIN_DS_NAME_REFERENCE_INVALID, ++ MD_ERROR_WIN_DS_CROSS_REF_EXISTS, ++ MD_ERROR_WIN_DS_CANT_DEL_MASTER_CROSSREF, ++ MD_ERROR_WIN_DS_SUBTREE_NOTIFY_NOT_NC_HEAD, ++ MD_ERROR_WIN_DS_NOTIFY_FILTER_TOO_COMPLEX, ++ MD_ERROR_WIN_DS_DUP_RDN, ++ MD_ERROR_WIN_DS_DUP_OID, ++ MD_ERROR_WIN_DS_DUP_MAPI_ID, ++ MD_ERROR_WIN_DS_DUP_SCHEMA_ID_GUID, ++ MD_ERROR_WIN_DS_DUP_LDAP_DISPLAY_NAME, ++ MD_ERROR_WIN_DS_SEMANTIC_ATT_TEST, ++ MD_ERROR_WIN_DS_SYNTAX_MISMATCH, ++ MD_ERROR_WIN_DS_EXISTS_IN_MUST_HAVE, ++ MD_ERROR_WIN_DS_EXISTS_IN_MAY_HAVE, ++ MD_ERROR_WIN_DS_NONEXISTENT_MAY_HAVE, ++ MD_ERROR_WIN_DS_NONEXISTENT_MUST_HAVE, ++ MD_ERROR_WIN_DS_AUX_CLS_TEST_FAIL, ++ MD_ERROR_WIN_DS_NONEXISTENT_POSS_SUP, ++ MD_ERROR_WIN_DS_SUB_CLS_TEST_FAIL, ++ MD_ERROR_WIN_DS_BAD_RDN_ATT_ID_SYNTAX, ++ MD_ERROR_WIN_DS_EXISTS_IN_AUX_CLS, ++ MD_ERROR_WIN_DS_EXISTS_IN_SUB_CLS, ++ MD_ERROR_WIN_DS_EXISTS_IN_POSS_SUP, ++ MD_ERROR_WIN_DS_RECALCSCHEMA_FAILED, ++ MD_ERROR_WIN_DS_TREE_DELETE_NOT_FINISHED, ++ MD_ERROR_WIN_DS_CANT_DELETE, ++ MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_ID, ++ MD_ERROR_WIN_DS_BAD_ATT_SCHEMA_SYNTAX, ++ MD_ERROR_WIN_DS_CANT_CACHE_ATT, ++ MD_ERROR_WIN_DS_CANT_CACHE_CLASS, ++ MD_ERROR_WIN_DS_CANT_REMOVE_ATT_CACHE, ++ MD_ERROR_WIN_DS_CANT_REMOVE_CLASS_CACHE, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_DN, ++ MD_ERROR_WIN_DS_MISSING_SUPREF, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_INSTANCE, ++ MD_ERROR_WIN_DS_CODE_INCONSISTENCY, ++ MD_ERROR_WIN_DS_DATABASE_ERROR, ++ MD_ERROR_WIN_DS_GOVERNSID_MISSING, ++ MD_ERROR_WIN_DS_MISSING_EXPECTED_ATT, ++ MD_ERROR_WIN_DS_NCNAME_MISSING_CR_REF, ++ MD_ERROR_WIN_DS_SECURITY_CHECKING_ERROR, ++ MD_ERROR_WIN_DS_SCHEMA_NOT_LOADED, ++ MD_ERROR_WIN_DS_SCHEMA_ALLOC_FAILED, ++ MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_SYNTAX, ++ MD_ERROR_WIN_DS_GCVERIFY_ERROR, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_MISMATCH, ++ MD_ERROR_WIN_DS_CANT_FIND_DSA_OBJ, ++ MD_ERROR_WIN_DS_CANT_FIND_EXPECTED_NC, ++ MD_ERROR_WIN_DS_CANT_FIND_NC_IN_CACHE, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_CHILD, ++ MD_ERROR_WIN_DS_SECURITY_ILLEGAL_MODIFY, ++ MD_ERROR_WIN_DS_CANT_REPLACE_HIDDEN_REC, ++ MD_ERROR_WIN_DS_BAD_HIERARCHY_FILE, ++ MD_ERROR_WIN_DS_BUILD_HIERARCHY_TABLE_FAILED, ++ MD_ERROR_WIN_DS_CONFIG_PARAM_MISSING, ++ MD_ERROR_WIN_DS_COUNTING_AB_INDICES_FAILED, ++ MD_ERROR_WIN_DS_HIERARCHY_TABLE_MALLOC_FAILED, ++ MD_ERROR_WIN_DS_INTERNAL_FAILURE, ++ MD_ERROR_WIN_DS_UNKNOWN_ERROR, ++ MD_ERROR_WIN_DS_ROOT_REQUIRES_CLASS_TOP, ++ MD_ERROR_WIN_DS_REFUSING_FSMO_ROLES, ++ MD_ERROR_WIN_DS_MISSING_FSMO_SETTINGS, ++ MD_ERROR_WIN_DS_UNABLE_TO_SURRENDER_ROLES, ++ MD_ERROR_WIN_DS_DRA_GENERIC, ++ MD_ERROR_WIN_DS_DRA_INVALID_PARAMETER, ++ MD_ERROR_WIN_DS_DRA_BUSY, ++ MD_ERROR_WIN_DS_DRA_BAD_DN, ++ MD_ERROR_WIN_DS_DRA_BAD_NC, ++ MD_ERROR_WIN_DS_DRA_DN_EXISTS, ++ MD_ERROR_WIN_DS_DRA_INTERNAL_ERROR, ++ MD_ERROR_WIN_DS_DRA_INCONSISTENT_DIT, ++ MD_ERROR_WIN_DS_DRA_CONNECTION_FAILED, ++ MD_ERROR_WIN_DS_DRA_BAD_INSTANCE_TYPE, ++ MD_ERROR_WIN_DS_DRA_OUT_OF_MEM, ++ MD_ERROR_WIN_DS_DRA_MAIL_PROBLEM, ++ MD_ERROR_WIN_DS_DRA_REF_ALREADY_EXISTS, ++ MD_ERROR_WIN_DS_DRA_REF_NOT_FOUND, ++ MD_ERROR_WIN_DS_DRA_OBJ_IS_REP_SOURCE, ++ MD_ERROR_WIN_DS_DRA_DB_ERROR, ++ MD_ERROR_WIN_DS_DRA_NO_REPLICA, ++ MD_ERROR_WIN_DS_DRA_ACCESS_DENIED, ++ MD_ERROR_WIN_DS_DRA_NOT_SUPPORTED, ++ MD_ERROR_WIN_DS_DRA_RPC_CANCELLED, ++ MD_ERROR_WIN_DS_DRA_SOURCE_DISABLED, ++ MD_ERROR_WIN_DS_DRA_SINK_DISABLED, ++ MD_ERROR_WIN_DS_DRA_NAME_COLLISION, ++ MD_ERROR_WIN_DS_DRA_SOURCE_REINSTALLED, ++ MD_ERROR_WIN_DS_DRA_MISSING_PARENT, ++ MD_ERROR_WIN_DS_DRA_PREEMPTED, ++ MD_ERROR_WIN_DS_DRA_ABANDON_SYNC, ++ MD_ERROR_WIN_DS_DRA_SHUTDOWN, ++ MD_ERROR_WIN_DS_DRA_INCOMPATIBLE_PARTIAL_SET, ++ MD_ERROR_WIN_DS_DRA_SOURCE_IS_PARTIAL_REPLICA, ++ MD_ERROR_WIN_DS_DRA_EXTN_CONNECTION_FAILED, ++ MD_ERROR_WIN_DS_INSTALL_SCHEMA_MISMATCH, ++ MD_ERROR_WIN_DS_DUP_LINK_ID, ++ MD_ERROR_WIN_DS_NAME_ERROR_RESOLVING, ++ MD_ERROR_WIN_DS_NAME_ERROR_NOT_FOUND, ++ MD_ERROR_WIN_DS_NAME_ERROR_NOT_UNIQUE, ++ MD_ERROR_WIN_DS_NAME_ERROR_NO_MAPPING, ++ MD_ERROR_WIN_DS_NAME_ERROR_DOMAIN_ONLY, ++ MD_ERROR_WIN_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING, ++ MD_ERROR_WIN_DS_CONSTRUCTED_ATT_MOD, ++ MD_ERROR_WIN_DS_WRONG_OM_OBJ_CLASS, ++ MD_ERROR_WIN_DS_DRA_REPL_PENDING, ++ MD_ERROR_WIN_DS_DS_REQUIRED, ++ MD_ERROR_WIN_DS_INVALID_LDAP_DISPLAY_NAME, ++ MD_ERROR_WIN_DS_NON_BASE_SEARCH, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_ATTS, ++ MD_ERROR_WIN_DS_BACKLINK_WITHOUT_LINK, ++ MD_ERROR_WIN_DS_EPOCH_MISMATCH, ++ MD_ERROR_WIN_DS_SRC_NAME_MISMATCH, ++ MD_ERROR_WIN_DS_SRC_AND_DST_NC_IDENTICAL, ++ MD_ERROR_WIN_DS_DST_NC_MISMATCH, ++ MD_ERROR_WIN_DS_NOT_AUTHORITIVE_FOR_DST_NC, ++ MD_ERROR_WIN_DS_SRC_GUID_MISMATCH, ++ MD_ERROR_WIN_DS_CANT_MOVE_DELETED_OBJECT, ++ MD_ERROR_WIN_DS_PDC_OPERATION_IN_PROGRESS, ++ MD_ERROR_WIN_DS_CROSS_DOMAIN_CLEANUP_REQD, ++ MD_ERROR_WIN_DS_ILLEGAL_XDOM_MOVE_OPERATION, ++ MD_ERROR_WIN_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS, ++ MD_ERROR_WIN_DS_NC_MUST_HAVE_NC_PARENT, ++ MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE, ++ MD_ERROR_WIN_DS_DST_DOMAIN_NOT_NATIVE, ++ MD_ERROR_WIN_DS_MISSING_INFRASTRUCTURE_CONTAINER, ++ MD_ERROR_WIN_DS_CANT_MOVE_ACCOUNT_GROUP, ++ MD_ERROR_WIN_DS_CANT_MOVE_RESOURCE_GROUP, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG, ++ MD_ERROR_WIN_DS_NO_TREE_DELETE_ABOVE_NC, ++ MD_ERROR_WIN_DS_COULDNT_LOCK_TREE_FOR_DELETE, ++ MD_ERROR_WIN_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE, ++ MD_ERROR_WIN_DS_SAM_INIT_FAILURE, ++ MD_ERROR_WIN_DS_SENSITIVE_GROUP_VIOLATION, ++ MD_ERROR_WIN_DS_CANT_MOD_PRIMARYGROUPID, ++ MD_ERROR_WIN_DS_ILLEGAL_BASE_SCHEMA_MOD, ++ MD_ERROR_WIN_DS_NONSAFE_SCHEMA_CHANGE, ++ MD_ERROR_WIN_DS_SCHEMA_UPDATE_DISALLOWED, ++ MD_ERROR_WIN_DS_CANT_CREATE_UNDER_SCHEMA, ++ MD_ERROR_WIN_DS_INSTALL_NO_SRC_SCH_VERSION, ++ MD_ERROR_WIN_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE, ++ MD_ERROR_WIN_DS_INVALID_GROUP_TYPE, ++ MD_ERROR_WIN_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, ++ MD_ERROR_WIN_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, ++ MD_ERROR_WIN_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, ++ MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, ++ MD_ERROR_WIN_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, ++ MD_ERROR_WIN_DS_HAVE_PRIMARY_MEMBERS, ++ MD_ERROR_WIN_DS_STRING_SD_CONVERSION_FAILED, ++ MD_ERROR_WIN_DS_NAMING_MASTER_GC, ++ MD_ERROR_WIN_DS_DNS_LOOKUP_FAILURE, ++ MD_ERROR_WIN_DS_COULDNT_UPDATE_SPNS, ++ MD_ERROR_WIN_DS_CANT_RETRIEVE_SD, ++ MD_ERROR_WIN_DS_KEY_NOT_UNIQUE, ++ MD_ERROR_WIN_DS_WRONG_LINKED_ATT_SYNTAX, ++ MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_PASSWORD, ++ MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_FLOPPY, ++ MD_ERROR_WIN_DS_CANT_START, ++ MD_ERROR_WIN_DS_INIT_FAILURE, ++ MD_ERROR_WIN_DS_NO_PKT_PRIVACY_ON_CONNECTION, ++ MD_ERROR_WIN_DS_SOURCE_DOMAIN_IN_FOREST, ++ MD_ERROR_WIN_DS_DESTINATION_DOMAIN_NOT_IN_FOREST, ++ MD_ERROR_WIN_DS_DESTINATION_AUDITING_NOT_ENABLED, ++ MD_ERROR_WIN_DS_CANT_FIND_DC_FOR_SRC_DOMAIN, ++ MD_ERROR_WIN_DS_SRC_OBJ_NOT_GROUP_OR_USER, ++ MD_ERROR_WIN_DS_SRC_SID_EXISTS_IN_FOREST, ++ MD_ERROR_WIN_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH, ++ MD_ERROR_WIN_SAM_INIT_FAILURE, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_INFO_SHIP, ++ MD_ERROR_WIN_DS_DRA_SCHEMA_CONFLICT, ++ MD_ERROR_WIN_DS_DRA_EARLIER_SCHEMA_CONFLICT, ++ MD_ERROR_WIN_DS_DRA_OBJ_NC_MISMATCH, ++ MD_ERROR_WIN_DS_NC_STILL_HAS_DSAS, ++ MD_ERROR_WIN_DS_GC_REQUIRED, ++ MD_ERROR_WIN_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, ++ MD_ERROR_WIN_DS_NO_FPO_IN_UNIVERSAL_GROUPS, ++ MD_ERROR_WIN_DS_CANT_ADD_TO_GC, ++ MD_ERROR_WIN_DS_NO_CHECKPOINT_WITH_PDC, ++ MD_ERROR_WIN_DS_SOURCE_AUDITING_NOT_ENABLED, ++ MD_ERROR_WIN_DS_CANT_CREATE_IN_NONDOMAIN_NC, ++ MD_ERROR_WIN_DS_INVALID_NAME_FOR_SPN, ++ MD_ERROR_WIN_DS_FILTER_USES_CONTRUCTED_ATTRS, ++ MD_ERROR_WIN_DS_UNICODEPWD_NOT_IN_QUOTES, ++ MD_ERROR_WIN_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, ++ MD_ERROR_WIN_DS_MUST_BE_RUN_ON_DST_DC, ++ MD_ERROR_WIN_DS_SRC_DC_MUST_BE_SP4_OR_GREATER, ++ MD_ERROR_WIN_DS_CANT_TREE_DELETE_CRITICAL_OBJ, ++ MD_ERROR_WIN_DS_INIT_FAILURE_CONSOLE, ++ MD_ERROR_WIN_DS_SAM_INIT_FAILURE_CONSOLE, ++ MD_ERROR_WIN_DS_FOREST_VERSION_TOO_HIGH, ++ MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_HIGH, ++ MD_ERROR_WIN_DS_FOREST_VERSION_TOO_LOW, ++ MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_LOW, ++ MD_ERROR_WIN_DS_INCOMPATIBLE_VERSION, ++ MD_ERROR_WIN_DS_LOW_DSA_VERSION, ++ MD_ERROR_WIN_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN, ++ MD_ERROR_WIN_DS_NOT_SUPPORTED_SORT_ORDER, ++ MD_ERROR_WIN_DS_NAME_NOT_UNIQUE, ++ MD_ERROR_WIN_DS_MACHINE_ACCOUNT_CREATED_PRENT4, ++ MD_ERROR_WIN_DS_OUT_OF_VERSION_STORE, ++ MD_ERROR_WIN_DS_INCOMPATIBLE_CONTROLS_USED, ++ MD_ERROR_WIN_DS_NO_REF_DOMAIN, ++ MD_ERROR_WIN_DS_RESERVED_LINK_ID, ++ MD_ERROR_WIN_DS_LINK_ID_NOT_AVAILABLE, ++ MD_ERROR_WIN_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, ++ MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE, ++ MD_ERROR_WIN_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC, ++ MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_FLAG, ++ MD_ERROR_WIN_DS_MODIFYDN_WRONG_GRANDPARENT, ++ MD_ERROR_WIN_DS_NAME_ERROR_TRUST_REFERRAL, ++ MD_ERROR_WIN_NOT_SUPPORTED_ON_STANDARD_SERVER, ++ MD_ERROR_WIN_DS_CANT_ACCESS_REMOTE_PART_OF_AD, ++ MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2, ++ MD_ERROR_WIN_DS_THREAD_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_DS_NOT_CLOSEST, ++ MD_ERROR_WIN_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF, ++ MD_ERROR_WIN_DS_SINGLE_USER_MODE_FAILED, ++ MD_ERROR_WIN_DS_NTDSCRIPT_SYNTAX_ERROR, ++ MD_ERROR_WIN_DS_NTDSCRIPT_PROCESS_ERROR, ++ MD_ERROR_WIN_DS_DIFFERENT_REPL_EPOCHS, ++ MD_ERROR_WIN_DS_DRS_EXTENSIONS_CHANGED, ++ MD_ERROR_WIN_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR, ++ MD_ERROR_WIN_DS_NO_MSDS_INTID, ++ MD_ERROR_WIN_DS_DUP_MSDS_INTID, ++ MD_ERROR_WIN_DS_EXISTS_IN_RDNATTID, ++ MD_ERROR_WIN_DS_AUTHORIZATION_FAILED, ++ MD_ERROR_WIN_DS_INVALID_SCRIPT, ++ MD_ERROR_WIN_DS_REMOTE_CROSSREF_OP_FAILED, ++ MD_ERROR_WIN_DS_CROSS_REF_BUSY, ++ MD_ERROR_WIN_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN, ++ MD_ERROR_WIN_DS_CANT_DEMOTE_WITH_WRITEABLE_NC, ++ MD_ERROR_WIN_DS_DUPLICATE_ID_FOUND, ++ MD_ERROR_WIN_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT, ++ MD_ERROR_WIN_DS_GROUP_CONVERSION_ERROR, ++ MD_ERROR_WIN_DS_CANT_MOVE_APP_BASIC_GROUP, ++ MD_ERROR_WIN_DS_CANT_MOVE_APP_QUERY_GROUP, ++ MD_ERROR_WIN_DS_ROLE_NOT_VERIFIED, ++ MD_ERROR_WIN_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL, ++ MD_ERROR_WIN_DS_DOMAIN_RENAME_IN_PROGRESS, ++ MD_ERROR_WIN_DS_EXISTING_AD_CHILD_NC, ++ MD_ERROR_WIN_DS_REPL_LIFETIME_EXCEEDED, ++ MD_ERROR_WIN_DS_DISALLOWED_IN_SYSTEM_CONTAINER, ++ MD_ERROR_WIN_DS_LDAP_SEND_QUEUE_FULL, ++ MD_ERROR_WIN_DS_DRA_OUT_SCHEDULE_WINDOW, ++ MD_ERROR_WIN_DS_POLICY_NOT_KNOWN, ++ MD_ERROR_WIN_NO_SITE_SETTINGS_OBJECT, ++ MD_ERROR_WIN_NO_SECRETS, ++ MD_ERROR_WIN_NO_WRITABLE_DC_FOUND, ++ MD_ERROR_WIN_DS_NO_SERVER_OBJECT, ++ MD_ERROR_WIN_DS_NO_NTDSA_OBJECT, ++ MD_ERROR_WIN_DS_NON_ASQ_SEARCH, ++ MD_ERROR_WIN_DS_AUDIT_FAILURE, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_SUBTREE, ++ MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_TUPLE, ++ MD_ERROR_WIN_DS_HIERARCHY_TABLE_TOO_DEEP, ++ MD_ERROR_WIN_DS_DRA_CORRUPT_UTD_VECTOR, ++ MD_ERROR_WIN_DS_DRA_SECRETS_DENIED, ++ MD_ERROR_WIN_DS_RESERVED_MAPI_ID, ++ MD_ERROR_WIN_DS_MAPI_ID_NOT_AVAILABLE, ++ MD_ERROR_WIN_DS_DRA_MISSING_KRBTGT_SECRET, ++ MD_ERROR_WIN_DS_DOMAIN_NAME_EXISTS_IN_FOREST, ++ MD_ERROR_WIN_DS_FLAT_NAME_EXISTS_IN_FOREST, ++ MD_ERROR_WIN_INVALID_USER_PRINCIPAL_NAME, ++ MD_ERROR_WIN_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS, ++ MD_ERROR_WIN_DS_OID_NOT_FOUND, ++ MD_ERROR_WIN_DS_DRA_RECYCLED_TARGET, ++ MD_ERROR_WIN_DS_DISALLOWED_NC_REDIRECT, ++ MD_ERROR_WIN_DS_HIGH_ADLDS_FFL, ++ MD_ERROR_WIN_DS_HIGH_DSA_VERSION, ++ MD_ERROR_WIN_DS_LOW_ADLDS_FFL, ++ MD_ERROR_WIN_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION, ++ MD_ERROR_WIN_DS_UNDELETE_SAM_VALIDATION_FAILED, ++ MD_ERROR_WIN_INCORRECT_ACCOUNT_TYPE, ++ MD_ERROR_WIN_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST, ++ MD_ERROR_WIN_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST, ++ MD_ERROR_WIN_DS_MISSING_FOREST_TRUST, ++ MD_ERROR_WIN_DS_VALUE_KEY_NOT_UNIQUE, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_EXISTS, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_IN_USE, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_EXISTS, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_IN_USE, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_EXISTS, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_EXISTS, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_EXISTS, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_IN_USE, ++ MD_ERROR_WIN_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_EXISTS, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_NOT_FOUND, ++ MD_ERROR_WIN_IPSEC_MM_FILTER_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_MM_POLICY_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_MM_AUTH_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_QM_POLICY_PENDING_DELETION, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_BEGIN, ++ MD_ERROR_WIN_IPSEC_IKE_AUTH_FAIL, ++ MD_ERROR_WIN_IPSEC_IKE_ATTRIB_FAIL, ++ MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_PENDING, ++ MD_ERROR_WIN_IPSEC_IKE_GENERAL_PROCESSING_ERROR, ++ MD_ERROR_WIN_IPSEC_IKE_TIMED_OUT, ++ MD_ERROR_WIN_IPSEC_IKE_NO_CERT, ++ MD_ERROR_WIN_IPSEC_IKE_SA_DELETED, ++ MD_ERROR_WIN_IPSEC_IKE_SA_REAPED, ++ MD_ERROR_WIN_IPSEC_IKE_MM_ACQUIRE_DROP, ++ MD_ERROR_WIN_IPSEC_IKE_QM_ACQUIRE_DROP, ++ MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_MM, ++ MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_NO_MM, ++ MD_ERROR_WIN_IPSEC_IKE_DROP_NO_RESPONSE, ++ MD_ERROR_WIN_IPSEC_IKE_MM_DELAY_DROP, ++ MD_ERROR_WIN_IPSEC_IKE_QM_DELAY_DROP, ++ MD_ERROR_WIN_IPSEC_IKE_ERROR, ++ MD_ERROR_WIN_IPSEC_IKE_CRL_FAILED, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_KEY_USAGE, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_TYPE, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PRIVATE_KEY, ++ MD_ERROR_WIN_IPSEC_IKE_SIMULTANEOUS_REKEY, ++ MD_ERROR_WIN_IPSEC_IKE_DH_FAIL, ++ MD_ERROR_WIN_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HEADER, ++ MD_ERROR_WIN_IPSEC_IKE_NO_POLICY, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SIGNATURE, ++ MD_ERROR_WIN_IPSEC_IKE_KERBEROS_ERROR, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PUBLIC_KEY, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SA, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_PROP, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_TRANS, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_KE, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_ID, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT_REQ, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_HASH, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SIG, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NONCE, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NOTIFY, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_DELETE, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_VENDOR, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_PAYLOAD, ++ MD_ERROR_WIN_IPSEC_IKE_LOAD_SOFT_SA, ++ MD_ERROR_WIN_IPSEC_IKE_SOFT_SA_TORN_DOWN, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_COOKIE, ++ MD_ERROR_WIN_IPSEC_IKE_NO_PEER_CERT, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_CRL_FAILED, ++ MD_ERROR_WIN_IPSEC_IKE_POLICY_CHANGE, ++ MD_ERROR_WIN_IPSEC_IKE_NO_MM_POLICY, ++ MD_ERROR_WIN_IPSEC_IKE_NOTCBPRIV, ++ MD_ERROR_WIN_IPSEC_IKE_SECLOADFAIL, ++ MD_ERROR_WIN_IPSEC_IKE_FAILSSPINIT, ++ MD_ERROR_WIN_IPSEC_IKE_FAILQUERYSSP, ++ MD_ERROR_WIN_IPSEC_IKE_SRVACQFAIL, ++ MD_ERROR_WIN_IPSEC_IKE_SRVQUERYCRED, ++ MD_ERROR_WIN_IPSEC_IKE_GETSPIFAIL, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_FILTER, ++ MD_ERROR_WIN_IPSEC_IKE_OUT_OF_MEMORY, ++ MD_ERROR_WIN_IPSEC_IKE_ADD_UPDATE_KEY_FAILED, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_POLICY, ++ MD_ERROR_WIN_IPSEC_IKE_UNKNOWN_DOI, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SITUATION, ++ MD_ERROR_WIN_IPSEC_IKE_DH_FAILURE, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_GROUP, ++ MD_ERROR_WIN_IPSEC_IKE_ENCRYPT, ++ MD_ERROR_WIN_IPSEC_IKE_DECRYPT, ++ MD_ERROR_WIN_IPSEC_IKE_POLICY_MATCH, ++ MD_ERROR_WIN_IPSEC_IKE_UNSUPPORTED_ID, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_ALG, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_SIZE, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_ENCRYPT_ALG, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_ALG, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_SIG, ++ MD_ERROR_WIN_IPSEC_IKE_LOAD_FAILED, ++ MD_ERROR_WIN_IPSEC_IKE_RPC_DELETE, ++ MD_ERROR_WIN_IPSEC_IKE_BENIGN_REINIT, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_MAJOR_VERSION, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_KEYLEN, ++ MD_ERROR_WIN_IPSEC_IKE_MM_LIMIT, ++ MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_DISABLED, ++ MD_ERROR_WIN_IPSEC_IKE_QM_LIMIT, ++ MD_ERROR_WIN_IPSEC_IKE_MM_EXPIRED, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_MM_ASSUMED_INVALID, ++ MD_ERROR_WIN_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH, ++ MD_ERROR_WIN_IPSEC_IKE_UNEXPECTED_MESSAGE_ID, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_PAYLOAD, ++ MD_ERROR_WIN_IPSEC_IKE_DOS_COOKIE_SENT, ++ MD_ERROR_WIN_IPSEC_IKE_SHUTTING_DOWN, ++ MD_ERROR_WIN_IPSEC_IKE_CGA_AUTH_FAILED, ++ MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NATOA, ++ MD_ERROR_WIN_IPSEC_IKE_INVALID_MM_FOR_QM, ++ MD_ERROR_WIN_IPSEC_IKE_QM_EXPIRED, ++ MD_ERROR_WIN_IPSEC_IKE_TOO_MANY_FILTERS, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_END, ++ MD_ERROR_WIN_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL, ++ MD_ERROR_WIN_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE, ++ MD_ERROR_WIN_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING, ++ MD_ERROR_WIN_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING, ++ MD_ERROR_WIN_IPSEC_IKE_COEXISTENCE_SUPPRESS, ++ MD_ERROR_WIN_IPSEC_IKE_RATELIMIT_DROP, ++ MD_ERROR_WIN_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE, ++ MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE, ++ MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE, ++ MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY, ++ MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE, ++ MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_EXTENDED_END, ++ MD_ERROR_WIN_IPSEC_BAD_SPI, ++ MD_ERROR_WIN_IPSEC_SA_LIFETIME_EXPIRED, ++ MD_ERROR_WIN_IPSEC_WRONG_SA, ++ MD_ERROR_WIN_IPSEC_REPLAY_CHECK_FAILED, ++ MD_ERROR_WIN_IPSEC_INVALID_PACKET, ++ MD_ERROR_WIN_IPSEC_INTEGRITY_CHECK_FAILED, ++ MD_ERROR_WIN_IPSEC_CLEAR_TEXT_DROP, ++ MD_ERROR_WIN_IPSEC_AUTH_FIREWALL_DROP, ++ MD_ERROR_WIN_IPSEC_THROTTLE_DROP, ++ MD_ERROR_WIN_IPSEC_DOSP_BLOCK, ++ MD_ERROR_WIN_IPSEC_DOSP_RECEIVED_MULTICAST, ++ MD_ERROR_WIN_IPSEC_DOSP_INVALID_PACKET, ++ MD_ERROR_WIN_IPSEC_DOSP_STATE_LOOKUP_FAILED, ++ MD_ERROR_WIN_IPSEC_DOSP_MAX_ENTRIES, ++ MD_ERROR_WIN_IPSEC_DOSP_KEYMOD_NOT_ALLOWED, ++ MD_ERROR_WIN_IPSEC_DOSP_NOT_INSTALLED, ++ MD_ERROR_WIN_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES, ++ MD_ERROR_WIN_SXS_SECTION_NOT_FOUND, ++ MD_ERROR_WIN_SXS_CANT_GEN_ACTCTX, ++ MD_ERROR_WIN_SXS_INVALID_ACTCTXDATA_FORMAT, ++ MD_ERROR_WIN_SXS_ASSEMBLY_NOT_FOUND, ++ MD_ERROR_WIN_SXS_MANIFEST_FORMAT_ERROR, ++ MD_ERROR_WIN_SXS_MANIFEST_PARSE_ERROR, ++ MD_ERROR_WIN_SXS_ACTIVATION_CONTEXT_DISABLED, ++ MD_ERROR_WIN_SXS_KEY_NOT_FOUND, ++ MD_ERROR_WIN_SXS_VERSION_CONFLICT, ++ MD_ERROR_WIN_SXS_WRONG_SECTION_TYPE, ++ MD_ERROR_WIN_SXS_THREAD_QUERIES_DISABLED, ++ MD_ERROR_WIN_SXS_PROCESS_DEFAULT_ALREADY_SET, ++ MD_ERROR_WIN_SXS_UNKNOWN_ENCODING_GROUP, ++ MD_ERROR_WIN_SXS_UNKNOWN_ENCODING, ++ MD_ERROR_WIN_SXS_INVALID_XML_NAMESPACE_URI, ++ MD_ERROR_WIN_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED, ++ MD_ERROR_WIN_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED, ++ MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE, ++ MD_ERROR_WIN_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE, ++ MD_ERROR_WIN_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE, ++ MD_ERROR_WIN_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT, ++ MD_ERROR_WIN_SXS_DUPLICATE_DLL_NAME, ++ MD_ERROR_WIN_SXS_DUPLICATE_WINDOWCLASS_NAME, ++ MD_ERROR_WIN_SXS_DUPLICATE_CLSID, ++ MD_ERROR_WIN_SXS_DUPLICATE_IID, ++ MD_ERROR_WIN_SXS_DUPLICATE_TLBID, ++ MD_ERROR_WIN_SXS_DUPLICATE_PROGID, ++ MD_ERROR_WIN_SXS_DUPLICATE_ASSEMBLY_NAME, ++ MD_ERROR_WIN_SXS_FILE_HASH_MISMATCH, ++ MD_ERROR_WIN_SXS_POLICY_PARSE_ERROR, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGQUOTE, ++ MD_ERROR_WIN_SXS_XML_E_COMMENTSYNTAX, ++ MD_ERROR_WIN_SXS_XML_E_BADSTARTNAMECHAR, ++ MD_ERROR_WIN_SXS_XML_E_BADNAMECHAR, ++ MD_ERROR_WIN_SXS_XML_E_BADCHARINSTRING, ++ MD_ERROR_WIN_SXS_XML_E_XMLDECLSYNTAX, ++ MD_ERROR_WIN_SXS_XML_E_BADCHARDATA, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGWHITESPACE, ++ MD_ERROR_WIN_SXS_XML_E_EXPECTINGTAGEND, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGSEMICOLON, ++ MD_ERROR_WIN_SXS_XML_E_UNBALANCEDPAREN, ++ MD_ERROR_WIN_SXS_XML_E_INTERNALERROR, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_WHITESPACE, ++ MD_ERROR_WIN_SXS_XML_E_INCOMPLETE_ENCODING, ++ MD_ERROR_WIN_SXS_XML_E_MISSING_PAREN, ++ MD_ERROR_WIN_SXS_XML_E_EXPECTINGCLOSEQUOTE, ++ MD_ERROR_WIN_SXS_XML_E_MULTIPLE_COLONS, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_DECIMAL, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_HEXIDECIMAL, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_UNICODE, ++ MD_ERROR_WIN_SXS_XML_E_WHITESPACEORQUESTIONMARK, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDENDTAG, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDTAG, ++ MD_ERROR_WIN_SXS_XML_E_DUPLICATEATTRIBUTE, ++ MD_ERROR_WIN_SXS_XML_E_MULTIPLEROOTS, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDATROOTLEVEL, ++ MD_ERROR_WIN_SXS_XML_E_BADXMLDECL, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGROOT, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDEOF, ++ MD_ERROR_WIN_SXS_XML_E_BADPEREFINSUBSET, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTARTTAG, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDENDTAG, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTRING, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCOMMENT, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDDECL, ++ MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCDATA, ++ MD_ERROR_WIN_SXS_XML_E_RESERVEDNAMESPACE, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDENCODING, ++ MD_ERROR_WIN_SXS_XML_E_INVALIDSWITCH, ++ MD_ERROR_WIN_SXS_XML_E_BADXMLCASE, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_STANDALONE, ++ MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_STANDALONE, ++ MD_ERROR_WIN_SXS_XML_E_INVALID_VERSION, ++ MD_ERROR_WIN_SXS_XML_E_MISSINGEQUALS, ++ MD_ERROR_WIN_SXS_PROTECTION_RECOVERY_FAILED, ++ MD_ERROR_WIN_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT, ++ MD_ERROR_WIN_SXS_PROTECTION_CATALOG_NOT_VALID, ++ MD_ERROR_WIN_SXS_UNTRANSLATABLE_HRESULT, ++ MD_ERROR_WIN_SXS_PROTECTION_CATALOG_FILE_MISSING, ++ MD_ERROR_WIN_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE, ++ MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME, ++ MD_ERROR_WIN_SXS_ASSEMBLY_MISSING, ++ MD_ERROR_WIN_SXS_CORRUPT_ACTIVATION_STACK, ++ MD_ERROR_WIN_SXS_CORRUPTION, ++ MD_ERROR_WIN_SXS_EARLY_DEACTIVATION, ++ MD_ERROR_WIN_SXS_INVALID_DEACTIVATION, ++ MD_ERROR_WIN_SXS_MULTIPLE_DEACTIVATION, ++ MD_ERROR_WIN_SXS_PROCESS_TERMINATION_REQUESTED, ++ MD_ERROR_WIN_SXS_RELEASE_ACTIVATION_CONTEXT, ++ MD_ERROR_WIN_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, ++ MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, ++ MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, ++ MD_ERROR_WIN_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, ++ MD_ERROR_WIN_SXS_IDENTITY_PARSE_ERROR, ++ MD_ERROR_WIN_MALFORMED_SUBSTITUTION_STRING, ++ MD_ERROR_WIN_SXS_INCORRECT_PUBLIC_KEY_TOKEN, ++ MD_ERROR_WIN_UNMAPPED_SUBSTITUTION_STRING, ++ MD_ERROR_WIN_SXS_ASSEMBLY_NOT_LOCKED, ++ MD_ERROR_WIN_SXS_COMPONENT_STORE_CORRUPT, ++ MD_ERROR_WIN_ADVANCED_INSTALLER_FAILED, ++ MD_ERROR_WIN_XML_ENCODING_MISMATCH, ++ MD_ERROR_WIN_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, ++ MD_ERROR_WIN_SXS_IDENTITIES_DIFFERENT, ++ MD_ERROR_WIN_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, ++ MD_ERROR_WIN_SXS_FILE_NOT_PART_OF_ASSEMBLY, ++ MD_ERROR_WIN_SXS_MANIFEST_TOO_BIG, ++ MD_ERROR_WIN_SXS_SETTING_NOT_REGISTERED, ++ MD_ERROR_WIN_SXS_TRANSACTION_CLOSURE_INCOMPLETE, ++ MD_ERROR_WIN_SMI_PRIMITIVE_INSTALLER_FAILED, ++ MD_ERROR_WIN_GENERIC_COMMAND_FAILED, ++ MD_ERROR_WIN_SXS_FILE_HASH_MISSING, ++ MD_ERROR_WIN_SXS_DUPLICATE_ACTIVATABLE_CLASS, ++ MD_ERROR_WIN_EVT_INVALID_CHANNEL_PATH, ++ MD_ERROR_WIN_EVT_INVALID_QUERY, ++ MD_ERROR_WIN_EVT_PUBLISHER_METADATA_NOT_FOUND, ++ MD_ERROR_WIN_EVT_EVENT_TEMPLATE_NOT_FOUND, ++ MD_ERROR_WIN_EVT_INVALID_PUBLISHER_NAME, ++ MD_ERROR_WIN_EVT_INVALID_EVENT_DATA, ++ MD_ERROR_WIN_EVT_CHANNEL_NOT_FOUND, ++ MD_ERROR_WIN_EVT_MALFORMED_XML_TEXT, ++ MD_ERROR_WIN_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL, ++ MD_ERROR_WIN_EVT_CONFIGURATION_ERROR, ++ MD_ERROR_WIN_EVT_QUERY_RESULT_STALE, ++ MD_ERROR_WIN_EVT_QUERY_RESULT_INVALID_POSITION, ++ MD_ERROR_WIN_EVT_NON_VALIDATING_MSXML, ++ MD_ERROR_WIN_EVT_FILTER_ALREADYSCOPED, ++ MD_ERROR_WIN_EVT_FILTER_NOTELTSET, ++ MD_ERROR_WIN_EVT_FILTER_INVARG, ++ MD_ERROR_WIN_EVT_FILTER_INVTEST, ++ MD_ERROR_WIN_EVT_FILTER_INVTYPE, ++ MD_ERROR_WIN_EVT_FILTER_PARSEERR, ++ MD_ERROR_WIN_EVT_FILTER_UNSUPPORTEDOP, ++ MD_ERROR_WIN_EVT_FILTER_UNEXPECTEDTOKEN, ++ MD_ERROR_WIN_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL, ++ MD_ERROR_WIN_EVT_INVALID_CHANNEL_PROPERTY_VALUE, ++ MD_ERROR_WIN_EVT_INVALID_PUBLISHER_PROPERTY_VALUE, ++ MD_ERROR_WIN_EVT_CHANNEL_CANNOT_ACTIVATE, ++ MD_ERROR_WIN_EVT_FILTER_TOO_COMPLEX, ++ MD_ERROR_WIN_EVT_MESSAGE_NOT_FOUND, ++ MD_ERROR_WIN_EVT_MESSAGE_ID_NOT_FOUND, ++ MD_ERROR_WIN_EVT_UNRESOLVED_VALUE_INSERT, ++ MD_ERROR_WIN_EVT_UNRESOLVED_PARAMETER_INSERT, ++ MD_ERROR_WIN_EVT_MAX_INSERTS_REACHED, ++ MD_ERROR_WIN_EVT_EVENT_DEFINITION_NOT_FOUND, ++ MD_ERROR_WIN_EVT_MESSAGE_LOCALE_NOT_FOUND, ++ MD_ERROR_WIN_EVT_VERSION_TOO_OLD, ++ MD_ERROR_WIN_EVT_VERSION_TOO_NEW, ++ MD_ERROR_WIN_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY, ++ MD_ERROR_WIN_EVT_PUBLISHER_DISABLED, ++ MD_ERROR_WIN_EVT_FILTER_OUT_OF_RANGE, ++ MD_ERROR_WIN_EC_SUBSCRIPTION_CANNOT_ACTIVATE, ++ MD_ERROR_WIN_EC_LOG_DISABLED, ++ MD_ERROR_WIN_EC_CIRCULAR_FORWARDING, ++ MD_ERROR_WIN_EC_CREDSTORE_FULL, ++ MD_ERROR_WIN_EC_CRED_NOT_FOUND, ++ MD_ERROR_WIN_EC_NO_ACTIVE_CHANNEL, ++ MD_ERROR_WIN_MUI_FILE_NOT_FOUND, ++ MD_ERROR_WIN_MUI_INVALID_FILE, ++ MD_ERROR_WIN_MUI_INVALID_RC_CONFIG, ++ MD_ERROR_WIN_MUI_INVALID_LOCALE_NAME, ++ MD_ERROR_WIN_MUI_INVALID_ULTIMATEFALLBACK_NAME, ++ MD_ERROR_WIN_MUI_FILE_NOT_LOADED, ++ MD_ERROR_WIN_RESOURCE_ENUM_USER_STOP, ++ MD_ERROR_WIN_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED, ++ MD_ERROR_WIN_MUI_INTLSETTINGS_INVALID_LOCALE_NAME, ++ MD_ERROR_WIN_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE, ++ MD_ERROR_WIN_MRM_INVALID_PRICONFIG, ++ MD_ERROR_WIN_MRM_INVALID_FILE_TYPE, ++ MD_ERROR_WIN_MRM_UNKNOWN_QUALIFIER, ++ MD_ERROR_WIN_MRM_INVALID_QUALIFIER_VALUE, ++ MD_ERROR_WIN_MRM_NO_CANDIDATE, ++ MD_ERROR_WIN_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE, ++ MD_ERROR_WIN_MRM_RESOURCE_TYPE_MISMATCH, ++ MD_ERROR_WIN_MRM_DUPLICATE_MAP_NAME, ++ MD_ERROR_WIN_MRM_DUPLICATE_ENTRY, ++ MD_ERROR_WIN_MRM_INVALID_RESOURCE_IDENTIFIER, ++ MD_ERROR_WIN_MRM_FILEPATH_TOO_LONG, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_DIRECTORY_TYPE, ++ MD_ERROR_WIN_MRM_INVALID_PRI_FILE, ++ MD_ERROR_WIN_MRM_NAMED_RESOURCE_NOT_FOUND, ++ MD_ERROR_WIN_MRM_MAP_NOT_FOUND, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_PROFILE_TYPE, ++ MD_ERROR_WIN_MRM_INVALID_QUALIFIER_OPERATOR, ++ MD_ERROR_WIN_MRM_INDETERMINATE_QUALIFIER_VALUE, ++ MD_ERROR_WIN_MRM_AUTOMERGE_ENABLED, ++ MD_ERROR_WIN_MRM_TOO_MANY_RESOURCES, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE, ++ MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE, ++ MD_ERROR_WIN_MRM_NO_CURRENT_VIEW_ON_THREAD, ++ MD_ERROR_WIN_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST, ++ MD_ERROR_WIN_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT, ++ MD_ERROR_WIN_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE, ++ MD_ERROR_WIN_MRM_GENERATION_COUNT_MISMATCH, ++ MD_ERROR_WIN_PRI_MERGE_VERSION_MISMATCH, ++ MD_ERROR_WIN_PRI_MERGE_MISSING_SCHEMA, ++ MD_ERROR_WIN_PRI_MERGE_LOAD_FILE_FAILED, ++ MD_ERROR_WIN_PRI_MERGE_ADD_FILE_FAILED, ++ MD_ERROR_WIN_PRI_MERGE_WRITE_FILE_FAILED, ++ MD_ERROR_WIN_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED, ++ MD_ERROR_WIN_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED, ++ MD_ERROR_WIN_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED, ++ MD_ERROR_WIN_PRI_MERGE_MAIN_PACKAGE_REQUIRED, ++ MD_ERROR_WIN_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED, ++ MD_ERROR_WIN_PRI_MERGE_INVALID_FILE_NAME, ++ MD_ERROR_WIN_MRM_PACKAGE_NOT_FOUND, ++ MD_ERROR_WIN_MRM_MISSING_DEFAULT_LANGUAGE, ++ MD_ERROR_WIN_MCA_INVALID_CAPABILITIES_STRING, ++ MD_ERROR_WIN_MCA_INVALID_VCP_VERSION, ++ MD_ERROR_WIN_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION, ++ MD_ERROR_WIN_MCA_MCCS_VERSION_MISMATCH, ++ MD_ERROR_WIN_MCA_UNSUPPORTED_MCCS_VERSION, ++ MD_ERROR_WIN_MCA_INTERNAL_ERROR, ++ MD_ERROR_WIN_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED, ++ MD_ERROR_WIN_MCA_UNSUPPORTED_COLOR_TEMPERATURE, ++ MD_ERROR_WIN_AMBIGUOUS_SYSTEM_DEVICE, ++ MD_ERROR_WIN_SYSTEM_DEVICE_NOT_FOUND, ++ MD_ERROR_WIN_HASH_NOT_SUPPORTED, ++ MD_ERROR_WIN_HASH_NOT_PRESENT, ++ MD_ERROR_WIN_SECONDARY_IC_PROVIDER_NOT_REGISTERED, ++ MD_ERROR_WIN_GPIO_CLIENT_INFORMATION_INVALID, ++ MD_ERROR_WIN_GPIO_VERSION_NOT_SUPPORTED, ++ MD_ERROR_WIN_GPIO_INVALID_REGISTRATION_PACKET, ++ MD_ERROR_WIN_GPIO_OPERATION_DENIED, ++ MD_ERROR_WIN_GPIO_INCOMPATIBLE_CONNECT_MODE, ++ MD_ERROR_WIN_GPIO_INTERRUPT_ALREADY_UNMASKED, ++ MD_ERROR_WIN_CANNOT_SWITCH_RUNLEVEL, ++ MD_ERROR_WIN_INVALID_RUNLEVEL_SETTING, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_TIMEOUT, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_AGENT_TIMEOUT, ++ MD_ERROR_WIN_RUNLEVEL_SWITCH_IN_PROGRESS, ++ MD_ERROR_WIN_SERVICES_FAILED_AUTOSTART, ++ MD_ERROR_WIN_COM_TASK_STOP_PENDING, ++ MD_ERROR_WIN_INSTALL_OPEN_PACKAGE_FAILED, ++ MD_ERROR_WIN_INSTALL_PACKAGE_NOT_FOUND, ++ MD_ERROR_WIN_INSTALL_INVALID_PACKAGE, ++ MD_ERROR_WIN_INSTALL_RESOLVE_DEPENDENCY_FAILED, ++ MD_ERROR_WIN_INSTALL_OUT_OF_DISK_SPACE, ++ MD_ERROR_WIN_INSTALL_NETWORK_FAILURE, ++ MD_ERROR_WIN_INSTALL_REGISTRATION_FAILURE, ++ MD_ERROR_WIN_INSTALL_DEREGISTRATION_FAILURE, ++ MD_ERROR_WIN_INSTALL_CANCEL, ++ MD_ERROR_WIN_INSTALL_FAILED, ++ MD_ERROR_WIN_REMOVE_FAILED, ++ MD_ERROR_WIN_PACKAGE_ALREADY_EXISTS, ++ MD_ERROR_WIN_NEEDS_REMEDIATION, ++ MD_ERROR_WIN_INSTALL_PREREQUISITE_FAILED, ++ MD_ERROR_WIN_PACKAGE_REPOSITORY_CORRUPTED, ++ MD_ERROR_WIN_INSTALL_POLICY_FAILURE, ++ MD_ERROR_WIN_PACKAGE_UPDATING, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_POLICY, ++ MD_ERROR_WIN_PACKAGES_IN_USE, ++ MD_ERROR_WIN_RECOVERY_FILE_CORRUPT, ++ MD_ERROR_WIN_INVALID_STAGED_SIGNATURE, ++ MD_ERROR_WIN_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED, ++ MD_ERROR_WIN_INSTALL_PACKAGE_DOWNGRADE, ++ MD_ERROR_WIN_SYSTEM_NEEDS_REMEDIATION, ++ MD_ERROR_WIN_APPX_INTEGRITY_FAILURE_CLR_NGEN, ++ MD_ERROR_WIN_RESILIENCY_FILE_CORRUPT, ++ MD_ERROR_WIN_INSTALL_FIREWALL_SERVICE_NOT_RUNNING, ++ MD_ERROR_WIN_PACKAGE_MOVE_FAILED, ++ MD_ERROR_WIN_INSTALL_VOLUME_NOT_EMPTY, ++ MD_ERROR_WIN_INSTALL_VOLUME_OFFLINE, ++ MD_ERROR_WIN_INSTALL_VOLUME_CORRUPT, ++ MD_ERROR_WIN_NEEDS_REGISTRATION, ++ MD_ERROR_WIN_INSTALL_WRONG_PROCESSOR_ARCHITECTURE, ++ MD_ERROR_WIN_DEV_SIDELOAD_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE, ++ MD_ERROR_WIN_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM, ++ MD_ERROR_WIN_PACKAGE_MOVE_BLOCKED_BY_STREAMING, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE, ++ MD_ERROR_WIN_PACKAGE_STAGING_ONHOLD, ++ MD_ERROR_WIN_INSTALL_INVALID_RELATED_SET_UPDATE, ++ MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF, ++ MD_ERROR_WIN_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED, ++ MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_FAILED, ++ MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_TIMEDOUT, ++ MD_ERROR_WIN_DEPLOYMENT_OPTION_NOT_SUPPORTED, ++ MD_ERROR_WIN_APPINSTALLER_ACTIVATION_BLOCKED, ++ MD_ERROR_WIN_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED, ++ MD_ERROR_WIN_APPX_RAW_DATA_WRITE_FAILED, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE, ++ MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY, ++ MD_ERROR_WIN_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY, ++ MD_ERROR_WIN_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER, ++ MD_ERROR_WIN_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED, ++ MD_ERROR_WIN_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE, ++ MD_ERROR_WIN_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES, ++ MD_ERROR_WIN_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED, ++ MD_ERROR_WIN_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST, ++ MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_CONTENT, ++ MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE, ++ MD_ERROR_WIN_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE, ++ MD_ERROR_WIN_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED, ++ MD_ERROR_WIN_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY, ++ MD_ERROR_WIN_STATE_LOAD_STORE_FAILED, ++ MD_ERROR_WIN_STATE_GET_VERSION_FAILED, ++ MD_ERROR_WIN_STATE_SET_VERSION_FAILED, ++ MD_ERROR_WIN_STATE_STRUCTURED_RESET_FAILED, ++ MD_ERROR_WIN_STATE_OPEN_CONTAINER_FAILED, ++ MD_ERROR_WIN_STATE_CREATE_CONTAINER_FAILED, ++ MD_ERROR_WIN_STATE_DELETE_CONTAINER_FAILED, ++ MD_ERROR_WIN_STATE_READ_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_WRITE_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_DELETE_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_QUERY_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_READ_COMPOSITE_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_WRITE_COMPOSITE_SETTING_FAILED, ++ MD_ERROR_WIN_STATE_ENUMERATE_CONTAINER_FAILED, ++ MD_ERROR_WIN_STATE_ENUMERATE_SETTINGS_FAILED, ++ MD_ERROR_WIN_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED, ++ MD_ERROR_WIN_API_UNAVAILABLE, ++}; ++ ++// The content of this array was created from winerror.h in the 10 SDK ++// (version 10.0.19041.0) with the following script: ++// ++// egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h ++// | tr -d '\r' ++// | sed -r 's@#define (ERROR_[A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' ++// | sort -n | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ "\2",@' ++static const char* kWinErrorStrings[] = { ++ "ERROR_SUCCESS", ++ "ERROR_INVALID_FUNCTION", ++ "ERROR_FILE_NOT_FOUND", ++ "ERROR_PATH_NOT_FOUND", ++ "ERROR_TOO_MANY_OPEN_FILES", ++ "ERROR_ACCESS_DENIED", ++ "ERROR_INVALID_HANDLE", ++ "ERROR_ARENA_TRASHED", ++ "ERROR_NOT_ENOUGH_MEMORY", ++ "ERROR_INVALID_BLOCK", ++ "ERROR_BAD_ENVIRONMENT", ++ "ERROR_BAD_FORMAT", ++ "ERROR_INVALID_ACCESS", ++ "ERROR_INVALID_DATA", ++ "ERROR_OUTOFMEMORY", ++ "ERROR_INVALID_DRIVE", ++ "ERROR_CURRENT_DIRECTORY", ++ "ERROR_NOT_SAME_DEVICE", ++ "ERROR_NO_MORE_FILES", ++ "ERROR_WRITE_PROTECT", ++ "ERROR_BAD_UNIT", ++ "ERROR_NOT_READY", ++ "ERROR_BAD_COMMAND", ++ "ERROR_CRC", ++ "ERROR_BAD_LENGTH", ++ "ERROR_SEEK", ++ "ERROR_NOT_DOS_DISK", ++ "ERROR_SECTOR_NOT_FOUND", ++ "ERROR_OUT_OF_PAPER", ++ "ERROR_WRITE_FAULT", ++ "ERROR_READ_FAULT", ++ "ERROR_GEN_FAILURE", ++ "ERROR_SHARING_VIOLATION", ++ "ERROR_LOCK_VIOLATION", ++ "ERROR_WRONG_DISK", ++ "ERROR_SHARING_BUFFER_EXCEEDED", ++ "ERROR_HANDLE_EOF", ++ "ERROR_HANDLE_DISK_FULL", ++ "ERROR_NOT_SUPPORTED", ++ "ERROR_REM_NOT_LIST", ++ "ERROR_DUP_NAME", ++ "ERROR_BAD_NETPATH", ++ "ERROR_NETWORK_BUSY", ++ "ERROR_DEV_NOT_EXIST", ++ "ERROR_TOO_MANY_CMDS", ++ "ERROR_ADAP_HDW_ERR", ++ "ERROR_BAD_NET_RESP", ++ "ERROR_UNEXP_NET_ERR", ++ "ERROR_BAD_REM_ADAP", ++ "ERROR_PRINTQ_FULL", ++ "ERROR_NO_SPOOL_SPACE", ++ "ERROR_PRINT_CANCELLED", ++ "ERROR_NETNAME_DELETED", ++ "ERROR_NETWORK_ACCESS_DENIED", ++ "ERROR_BAD_DEV_TYPE", ++ "ERROR_BAD_NET_NAME", ++ "ERROR_TOO_MANY_NAMES", ++ "ERROR_TOO_MANY_SESS", ++ "ERROR_SHARING_PAUSED", ++ "ERROR_REQ_NOT_ACCEP", ++ "ERROR_REDIR_PAUSED", ++ "ERROR_FILE_EXISTS", ++ "ERROR_CANNOT_MAKE", ++ "ERROR_FAIL_I24", ++ "ERROR_OUT_OF_STRUCTURES", ++ "ERROR_ALREADY_ASSIGNED", ++ "ERROR_INVALID_PASSWORD", ++ "ERROR_INVALID_PARAMETER", ++ "ERROR_NET_WRITE_FAULT", ++ "ERROR_NO_PROC_SLOTS", ++ "ERROR_TOO_MANY_SEMAPHORES", ++ "ERROR_EXCL_SEM_ALREADY_OWNED", ++ "ERROR_SEM_IS_SET", ++ "ERROR_TOO_MANY_SEM_REQUESTS", ++ "ERROR_INVALID_AT_INTERRUPT_TIME", ++ "ERROR_SEM_OWNER_DIED", ++ "ERROR_SEM_USER_LIMIT", ++ "ERROR_DISK_CHANGE", ++ "ERROR_DRIVE_LOCKED", ++ "ERROR_BROKEN_PIPE", ++ "ERROR_OPEN_FAILED", ++ "ERROR_BUFFER_OVERFLOW", ++ "ERROR_DISK_FULL", ++ "ERROR_NO_MORE_SEARCH_HANDLES", ++ "ERROR_INVALID_TARGET_HANDLE", ++ "ERROR_INVALID_CATEGORY", ++ "ERROR_INVALID_VERIFY_SWITCH", ++ "ERROR_BAD_DRIVER_LEVEL", ++ "ERROR_CALL_NOT_IMPLEMENTED", ++ "ERROR_SEM_TIMEOUT", ++ "ERROR_INSUFFICIENT_BUFFER", ++ "ERROR_INVALID_NAME", ++ "ERROR_INVALID_LEVEL", ++ "ERROR_NO_VOLUME_LABEL", ++ "ERROR_MOD_NOT_FOUND", ++ "ERROR_PROC_NOT_FOUND", ++ "ERROR_WAIT_NO_CHILDREN", ++ "ERROR_CHILD_NOT_COMPLETE", ++ "ERROR_DIRECT_ACCESS_HANDLE", ++ "ERROR_NEGATIVE_SEEK", ++ "ERROR_SEEK_ON_DEVICE", ++ "ERROR_IS_JOIN_TARGET", ++ "ERROR_IS_JOINED", ++ "ERROR_IS_SUBSTED", ++ "ERROR_NOT_JOINED", ++ "ERROR_NOT_SUBSTED", ++ "ERROR_JOIN_TO_JOIN", ++ "ERROR_SUBST_TO_SUBST", ++ "ERROR_JOIN_TO_SUBST", ++ "ERROR_SUBST_TO_JOIN", ++ "ERROR_BUSY_DRIVE", ++ "ERROR_SAME_DRIVE", ++ "ERROR_DIR_NOT_ROOT", ++ "ERROR_DIR_NOT_EMPTY", ++ "ERROR_IS_SUBST_PATH", ++ "ERROR_IS_JOIN_PATH", ++ "ERROR_PATH_BUSY", ++ "ERROR_IS_SUBST_TARGET", ++ "ERROR_SYSTEM_TRACE", ++ "ERROR_INVALID_EVENT_COUNT", ++ "ERROR_TOO_MANY_MUXWAITERS", ++ "ERROR_INVALID_LIST_FORMAT", ++ "ERROR_LABEL_TOO_LONG", ++ "ERROR_TOO_MANY_TCBS", ++ "ERROR_SIGNAL_REFUSED", ++ "ERROR_DISCARDED", ++ "ERROR_NOT_LOCKED", ++ "ERROR_BAD_THREADID_ADDR", ++ "ERROR_BAD_ARGUMENTS", ++ "ERROR_BAD_PATHNAME", ++ "ERROR_SIGNAL_PENDING", ++ "ERROR_MAX_THRDS_REACHED", ++ "ERROR_LOCK_FAILED", ++ "ERROR_BUSY", ++ "ERROR_DEVICE_SUPPORT_IN_PROGRESS", ++ "ERROR_CANCEL_VIOLATION", ++ "ERROR_ATOMIC_LOCKS_NOT_SUPPORTED", ++ "ERROR_INVALID_SEGMENT_NUMBER", ++ "ERROR_INVALID_ORDINAL", ++ "ERROR_ALREADY_EXISTS", ++ "ERROR_INVALID_FLAG_NUMBER", ++ "ERROR_SEM_NOT_FOUND", ++ "ERROR_INVALID_STARTING_CODESEG", ++ "ERROR_INVALID_STACKSEG", ++ "ERROR_INVALID_MODULETYPE", ++ "ERROR_INVALID_EXE_SIGNATURE", ++ "ERROR_EXE_MARKED_INVALID", ++ "ERROR_BAD_EXE_FORMAT", ++ "ERROR_INVALID_MINALLOCSIZE", ++ "ERROR_DYNLINK_FROM_INVALID_RING", ++ "ERROR_IOPL_NOT_ENABLED", ++ "ERROR_INVALID_SEGDPL", ++ "ERROR_RING2SEG_MUST_BE_MOVABLE", ++ "ERROR_RELOC_CHAIN_XEEDS_SEGLIM", ++ "ERROR_INFLOOP_IN_RELOC_CHAIN", ++ "ERROR_ENVVAR_NOT_FOUND", ++ "ERROR_NO_SIGNAL_SENT", ++ "ERROR_FILENAME_EXCED_RANGE", ++ "ERROR_RING2_STACK_IN_USE", ++ "ERROR_META_EXPANSION_TOO_LONG", ++ "ERROR_INVALID_SIGNAL_NUMBER", ++ "ERROR_THREAD_1_INACTIVE", ++ "ERROR_LOCKED", ++ "ERROR_TOO_MANY_MODULES", ++ "ERROR_NESTING_NOT_ALLOWED", ++ "ERROR_EXE_MACHINE_TYPE_MISMATCH", ++ "ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY", ++ "ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY", ++ "ERROR_FILE_CHECKED_OUT", ++ "ERROR_CHECKOUT_REQUIRED", ++ "ERROR_BAD_FILE_TYPE", ++ "ERROR_FILE_TOO_LARGE", ++ "ERROR_FORMS_AUTH_REQUIRED", ++ "ERROR_VIRUS_INFECTED", ++ "ERROR_VIRUS_DELETED", ++ "ERROR_PIPE_LOCAL", ++ "ERROR_BAD_PIPE", ++ "ERROR_PIPE_BUSY", ++ "ERROR_NO_DATA", ++ "ERROR_PIPE_NOT_CONNECTED", ++ "ERROR_MORE_DATA", ++ "ERROR_NO_WORK_DONE", ++ "ERROR_VC_DISCONNECTED", ++ "ERROR_INVALID_EA_NAME", ++ "ERROR_EA_LIST_INCONSISTENT", ++ "ERROR_NO_MORE_ITEMS", ++ "ERROR_CANNOT_COPY", ++ "ERROR_DIRECTORY", ++ "ERROR_EAS_DIDNT_FIT", ++ "ERROR_EA_FILE_CORRUPT", ++ "ERROR_EA_TABLE_FULL", ++ "ERROR_INVALID_EA_HANDLE", ++ "ERROR_EAS_NOT_SUPPORTED", ++ "ERROR_NOT_OWNER", ++ "ERROR_TOO_MANY_POSTS", ++ "ERROR_PARTIAL_COPY", ++ "ERROR_OPLOCK_NOT_GRANTED", ++ "ERROR_INVALID_OPLOCK_PROTOCOL", ++ "ERROR_DISK_TOO_FRAGMENTED", ++ "ERROR_DELETE_PENDING", ++ "ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING", ++ "ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME", ++ "ERROR_SECURITY_STREAM_IS_INCONSISTENT", ++ "ERROR_INVALID_LOCK_RANGE", ++ "ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT", ++ "ERROR_NOTIFICATION_GUID_ALREADY_DEFINED", ++ "ERROR_INVALID_EXCEPTION_HANDLER", ++ "ERROR_DUPLICATE_PRIVILEGES", ++ "ERROR_NO_RANGES_PROCESSED", ++ "ERROR_NOT_ALLOWED_ON_SYSTEM_FILE", ++ "ERROR_DISK_RESOURCES_EXHAUSTED", ++ "ERROR_INVALID_TOKEN", ++ "ERROR_DEVICE_FEATURE_NOT_SUPPORTED", ++ "ERROR_MR_MID_NOT_FOUND", ++ "ERROR_SCOPE_NOT_FOUND", ++ "ERROR_UNDEFINED_SCOPE", ++ "ERROR_INVALID_CAP", ++ "ERROR_DEVICE_UNREACHABLE", ++ "ERROR_DEVICE_NO_RESOURCES", ++ "ERROR_DATA_CHECKSUM_ERROR", ++ "ERROR_INTERMIXED_KERNEL_EA_OPERATION", ++ "ERROR_FILE_LEVEL_TRIM_NOT_SUPPORTED", ++ "ERROR_OFFSET_ALIGNMENT_VIOLATION", ++ "ERROR_INVALID_FIELD_IN_PARAMETER_LIST", ++ "ERROR_OPERATION_IN_PROGRESS", ++ "ERROR_BAD_DEVICE_PATH", ++ "ERROR_TOO_MANY_DESCRIPTORS", ++ "ERROR_SCRUB_DATA_DISABLED", ++ "ERROR_NOT_REDUNDANT_STORAGE", ++ "ERROR_RESIDENT_FILE_NOT_SUPPORTED", ++ "ERROR_COMPRESSED_FILE_NOT_SUPPORTED", ++ "ERROR_DIRECTORY_NOT_SUPPORTED", ++ "ERROR_NOT_READ_FROM_COPY", ++ "ERROR_FT_WRITE_FAILURE", ++ "ERROR_FT_DI_SCAN_REQUIRED", ++ "ERROR_INVALID_KERNEL_INFO_VERSION", ++ "ERROR_INVALID_PEP_INFO_VERSION", ++ "ERROR_OBJECT_NOT_EXTERNALLY_BACKED", ++ "ERROR_EXTERNAL_BACKING_PROVIDER_UNKNOWN", ++ "ERROR_COMPRESSION_NOT_BENEFICIAL", ++ "ERROR_STORAGE_TOPOLOGY_ID_MISMATCH", ++ "ERROR_BLOCKED_BY_PARENTAL_CONTROLS", ++ "ERROR_BLOCK_TOO_MANY_REFERENCES", ++ "ERROR_MARKED_TO_DISALLOW_WRITES", ++ "ERROR_ENCLAVE_FAILURE", ++ "ERROR_FAIL_NOACTION_REBOOT", ++ "ERROR_FAIL_SHUTDOWN", ++ "ERROR_FAIL_RESTART", ++ "ERROR_MAX_SESSIONS_REACHED", ++ "ERROR_NETWORK_ACCESS_DENIED_EDP", ++ "ERROR_DEVICE_HINT_NAME_BUFFER_TOO_SMALL", ++ "ERROR_EDP_POLICY_DENIES_OPERATION", ++ "ERROR_EDP_DPL_POLICY_CANT_BE_SATISFIED", ++ "ERROR_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT", ++ "ERROR_DEVICE_IN_MAINTENANCE", ++ "ERROR_NOT_SUPPORTED_ON_DAX", ++ "ERROR_DAX_MAPPING_EXISTS", ++ "ERROR_CLOUD_FILE_PROVIDER_NOT_RUNNING", ++ "ERROR_CLOUD_FILE_METADATA_CORRUPT", ++ "ERROR_CLOUD_FILE_METADATA_TOO_LARGE", ++ "ERROR_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE", ++ "ERROR_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH", ++ "ERROR_CHILD_PROCESS_BLOCKED", ++ "ERROR_STORAGE_LOST_DATA_PERSISTENCE", ++ "ERROR_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE", ++ "ERROR_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT", ++ "ERROR_FILE_SYSTEM_VIRTUALIZATION_BUSY", ++ "ERROR_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN", ++ "ERROR_GDI_HANDLE_LEAK", ++ "ERROR_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS", ++ "ERROR_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED", ++ "ERROR_NOT_A_CLOUD_FILE", ++ "ERROR_CLOUD_FILE_NOT_IN_SYNC", ++ "ERROR_CLOUD_FILE_ALREADY_CONNECTED", ++ "ERROR_CLOUD_FILE_NOT_SUPPORTED", ++ "ERROR_CLOUD_FILE_INVALID_REQUEST", ++ "ERROR_CLOUD_FILE_READ_ONLY_VOLUME", ++ "ERROR_CLOUD_FILE_CONNECTED_PROVIDER_ONLY", ++ "ERROR_CLOUD_FILE_VALIDATION_FAILED", ++ "ERROR_SMB1_NOT_AVAILABLE", ++ "ERROR_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION", ++ "ERROR_CLOUD_FILE_AUTHENTICATION_FAILED", ++ "ERROR_CLOUD_FILE_INSUFFICIENT_RESOURCES", ++ "ERROR_CLOUD_FILE_NETWORK_UNAVAILABLE", ++ "ERROR_CLOUD_FILE_UNSUCCESSFUL", ++ "ERROR_CLOUD_FILE_NOT_UNDER_SYNC_ROOT", ++ "ERROR_CLOUD_FILE_IN_USE", ++ "ERROR_CLOUD_FILE_PINNED", ++ "ERROR_CLOUD_FILE_REQUEST_ABORTED", ++ "ERROR_CLOUD_FILE_PROPERTY_CORRUPT", ++ "ERROR_CLOUD_FILE_ACCESS_DENIED", ++ "ERROR_CLOUD_FILE_INCOMPATIBLE_HARDLINKS", ++ "ERROR_CLOUD_FILE_PROPERTY_LOCK_CONFLICT", ++ "ERROR_CLOUD_FILE_REQUEST_CANCELED", ++ "ERROR_EXTERNAL_SYSKEY_NOT_SUPPORTED", ++ "ERROR_THREAD_MODE_ALREADY_BACKGROUND", ++ "ERROR_THREAD_MODE_NOT_BACKGROUND", ++ "ERROR_PROCESS_MODE_ALREADY_BACKGROUND", ++ "ERROR_PROCESS_MODE_NOT_BACKGROUND", ++ "ERROR_CLOUD_FILE_PROVIDER_TERMINATED", ++ "ERROR_NOT_A_CLOUD_SYNC_ROOT", ++ "ERROR_FILE_PROTECTED_UNDER_DPL", ++ "ERROR_VOLUME_NOT_CLUSTER_ALIGNED", ++ "ERROR_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND", ++ "ERROR_APPX_FILE_NOT_ENCRYPTED", ++ "ERROR_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED", ++ "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET", ++ "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE", ++ "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER", ++ "ERROR_LINUX_SUBSYSTEM_NOT_PRESENT", ++ "ERROR_FT_READ_FAILURE", ++ "ERROR_STORAGE_RESERVE_ID_INVALID", ++ "ERROR_STORAGE_RESERVE_DOES_NOT_EXIST", ++ "ERROR_STORAGE_RESERVE_ALREADY_EXISTS", ++ "ERROR_STORAGE_RESERVE_NOT_EMPTY", ++ "ERROR_NOT_A_DAX_VOLUME", ++ "ERROR_NOT_DAX_MAPPABLE", ++ "ERROR_TIME_SENSITIVE_THREAD", ++ "ERROR_DPL_NOT_SUPPORTED_FOR_USER", ++ "ERROR_CASE_DIFFERING_NAMES_IN_DIR", ++ "ERROR_FILE_NOT_SUPPORTED", ++ "ERROR_CLOUD_FILE_REQUEST_TIMEOUT", ++ "ERROR_NO_TASK_QUEUE", ++ "ERROR_SRC_SRV_DLL_LOAD_FAILED", ++ "ERROR_NOT_SUPPORTED_WITH_BTT", ++ "ERROR_ENCRYPTION_DISABLED", ++ "ERROR_ENCRYPTING_METADATA_DISALLOWED", ++ "ERROR_CANT_CLEAR_ENCRYPTION_FLAG", ++ "ERROR_NO_SUCH_DEVICE", ++ "ERROR_CLOUD_FILE_DEHYDRATION_DISALLOWED", ++ "ERROR_FILE_SNAP_IN_PROGRESS", ++ "ERROR_FILE_SNAP_USER_SECTION_NOT_SUPPORTED", ++ "ERROR_FILE_SNAP_MODIFY_NOT_SUPPORTED", ++ "ERROR_FILE_SNAP_IO_NOT_COORDINATED", ++ "ERROR_FILE_SNAP_UNEXPECTED_ERROR", ++ "ERROR_FILE_SNAP_INVALID_PARAMETER", ++ "ERROR_UNSATISFIED_DEPENDENCIES", ++ "ERROR_CASE_SENSITIVE_PATH", ++ "ERROR_UNEXPECTED_NTCACHEMANAGER_ERROR", ++ "ERROR_LINUX_SUBSYSTEM_UPDATE_REQUIRED", ++ "ERROR_DLP_POLICY_WARNS_AGAINST_OPERATION", ++ "ERROR_DLP_POLICY_DENIES_OPERATION", ++ "ERROR_DLP_POLICY_SILENTLY_FAIL", ++ "ERROR_CAPAUTHZ_NOT_DEVUNLOCKED", ++ "ERROR_CAPAUTHZ_CHANGE_TYPE", ++ "ERROR_CAPAUTHZ_NOT_PROVISIONED", ++ "ERROR_CAPAUTHZ_NOT_AUTHORIZED", ++ "ERROR_CAPAUTHZ_NO_POLICY", ++ "ERROR_CAPAUTHZ_DB_CORRUPTED", ++ "ERROR_CAPAUTHZ_SCCD_INVALID_CATALOG", ++ "ERROR_CAPAUTHZ_SCCD_NO_AUTH_ENTITY", ++ "ERROR_CAPAUTHZ_SCCD_PARSE_ERROR", ++ "ERROR_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED", ++ "ERROR_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH", ++ "ERROR_CIMFS_IMAGE_CORRUPT", ++ "ERROR_PNP_QUERY_REMOVE_DEVICE_TIMEOUT", ++ "ERROR_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT", ++ "ERROR_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT", ++ "ERROR_DEVICE_HARDWARE_ERROR", ++ "ERROR_INVALID_ADDRESS", ++ "ERROR_HAS_SYSTEM_CRITICAL_FILES", ++ "ERROR_USER_PROFILE_LOAD", ++ "ERROR_ARITHMETIC_OVERFLOW", ++ "ERROR_PIPE_CONNECTED", ++ "ERROR_PIPE_LISTENING", ++ "ERROR_VERIFIER_STOP", ++ "ERROR_ABIOS_ERROR", ++ "ERROR_WX86_WARNING", ++ "ERROR_WX86_ERROR", ++ "ERROR_TIMER_NOT_CANCELED", ++ "ERROR_UNWIND", ++ "ERROR_BAD_STACK", ++ "ERROR_INVALID_UNWIND_TARGET", ++ "ERROR_INVALID_PORT_ATTRIBUTES", ++ "ERROR_PORT_MESSAGE_TOO_LONG", ++ "ERROR_INVALID_QUOTA_LOWER", ++ "ERROR_DEVICE_ALREADY_ATTACHED", ++ "ERROR_INSTRUCTION_MISALIGNMENT", ++ "ERROR_PROFILING_NOT_STARTED", ++ "ERROR_PROFILING_NOT_STOPPED", ++ "ERROR_COULD_NOT_INTERPRET", ++ "ERROR_PROFILING_AT_LIMIT", ++ "ERROR_CANT_WAIT", ++ "ERROR_CANT_TERMINATE_SELF", ++ "ERROR_UNEXPECTED_MM_CREATE_ERR", ++ "ERROR_UNEXPECTED_MM_MAP_ERROR", ++ "ERROR_UNEXPECTED_MM_EXTEND_ERR", ++ "ERROR_BAD_FUNCTION_TABLE", ++ "ERROR_NO_GUID_TRANSLATION", ++ "ERROR_INVALID_LDT_SIZE", ++ "ERROR_INVALID_LDT_OFFSET", ++ "ERROR_INVALID_LDT_DESCRIPTOR", ++ "ERROR_TOO_MANY_THREADS", ++ "ERROR_THREAD_NOT_IN_PROCESS", ++ "ERROR_PAGEFILE_QUOTA_EXCEEDED", ++ "ERROR_LOGON_SERVER_CONFLICT", ++ "ERROR_SYNCHRONIZATION_REQUIRED", ++ "ERROR_NET_OPEN_FAILED", ++ "ERROR_IO_PRIVILEGE_FAILED", ++ "ERROR_CONTROL_C_EXIT", ++ "ERROR_MISSING_SYSTEMFILE", ++ "ERROR_UNHANDLED_EXCEPTION", ++ "ERROR_APP_INIT_FAILURE", ++ "ERROR_PAGEFILE_CREATE_FAILED", ++ "ERROR_INVALID_IMAGE_HASH", ++ "ERROR_NO_PAGEFILE", ++ "ERROR_ILLEGAL_FLOAT_CONTEXT", ++ "ERROR_NO_EVENT_PAIR", ++ "ERROR_DOMAIN_CTRLR_CONFIG_ERROR", ++ "ERROR_ILLEGAL_CHARACTER", ++ "ERROR_UNDEFINED_CHARACTER", ++ "ERROR_FLOPPY_VOLUME", ++ "ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT", ++ "ERROR_BACKUP_CONTROLLER", ++ "ERROR_MUTANT_LIMIT_EXCEEDED", ++ "ERROR_FS_DRIVER_REQUIRED", ++ "ERROR_CANNOT_LOAD_REGISTRY_FILE", ++ "ERROR_DEBUG_ATTACH_FAILED", ++ "ERROR_SYSTEM_PROCESS_TERMINATED", ++ "ERROR_DATA_NOT_ACCEPTED", ++ "ERROR_VDM_HARD_ERROR", ++ "ERROR_DRIVER_CANCEL_TIMEOUT", ++ "ERROR_REPLY_MESSAGE_MISMATCH", ++ "ERROR_LOST_WRITEBEHIND_DATA", ++ "ERROR_CLIENT_SERVER_PARAMETERS_INVALID", ++ "ERROR_NOT_TINY_STREAM", ++ "ERROR_STACK_OVERFLOW_READ", ++ "ERROR_CONVERT_TO_LARGE", ++ "ERROR_FOUND_OUT_OF_SCOPE", ++ "ERROR_ALLOCATE_BUCKET", ++ "ERROR_MARSHALL_OVERFLOW", ++ "ERROR_INVALID_VARIANT", ++ "ERROR_BAD_COMPRESSION_BUFFER", ++ "ERROR_AUDIT_FAILED", ++ "ERROR_TIMER_RESOLUTION_NOT_SET", ++ "ERROR_INSUFFICIENT_LOGON_INFO", ++ "ERROR_BAD_DLL_ENTRYPOINT", ++ "ERROR_BAD_SERVICE_ENTRYPOINT", ++ "ERROR_IP_ADDRESS_CONFLICT1", ++ "ERROR_IP_ADDRESS_CONFLICT2", ++ "ERROR_REGISTRY_QUOTA_LIMIT", ++ "ERROR_NO_CALLBACK_ACTIVE", ++ "ERROR_PWD_TOO_SHORT", ++ "ERROR_PWD_TOO_RECENT", ++ "ERROR_PWD_HISTORY_CONFLICT", ++ "ERROR_UNSUPPORTED_COMPRESSION", ++ "ERROR_INVALID_HW_PROFILE", ++ "ERROR_INVALID_PLUGPLAY_DEVICE_PATH", ++ "ERROR_QUOTA_LIST_INCONSISTENT", ++ "ERROR_EVALUATION_EXPIRATION", ++ "ERROR_ILLEGAL_DLL_RELOCATION", ++ "ERROR_DLL_INIT_FAILED_LOGOFF", ++ "ERROR_VALIDATE_CONTINUE", ++ "ERROR_NO_MORE_MATCHES", ++ "ERROR_RANGE_LIST_CONFLICT", ++ "ERROR_SERVER_SID_MISMATCH", ++ "ERROR_CANT_ENABLE_DENY_ONLY", ++ "ERROR_FLOAT_MULTIPLE_FAULTS", ++ "ERROR_FLOAT_MULTIPLE_TRAPS", ++ "ERROR_NOINTERFACE", ++ "ERROR_DRIVER_FAILED_SLEEP", ++ "ERROR_CORRUPT_SYSTEM_FILE", ++ "ERROR_COMMITMENT_MINIMUM", ++ "ERROR_PNP_RESTART_ENUMERATION", ++ "ERROR_SYSTEM_IMAGE_BAD_SIGNATURE", ++ "ERROR_PNP_REBOOT_REQUIRED", ++ "ERROR_INSUFFICIENT_POWER", ++ "ERROR_MULTIPLE_FAULT_VIOLATION", ++ "ERROR_SYSTEM_SHUTDOWN", ++ "ERROR_PORT_NOT_SET", ++ "ERROR_DS_VERSION_CHECK_FAILURE", ++ "ERROR_RANGE_NOT_FOUND", ++ "ERROR_NOT_SAFE_MODE_DRIVER", ++ "ERROR_FAILED_DRIVER_ENTRY", ++ "ERROR_DEVICE_ENUMERATION_ERROR", ++ "ERROR_MOUNT_POINT_NOT_RESOLVED", ++ "ERROR_INVALID_DEVICE_OBJECT_PARAMETER", ++ "ERROR_MCA_OCCURED", ++ "ERROR_DRIVER_DATABASE_ERROR", ++ "ERROR_SYSTEM_HIVE_TOO_LARGE", ++ "ERROR_DRIVER_FAILED_PRIOR_UNLOAD", ++ "ERROR_VOLSNAP_PREPARE_HIBERNATE", ++ "ERROR_HIBERNATION_FAILURE", ++ "ERROR_PWD_TOO_LONG", ++ "ERROR_FILE_SYSTEM_LIMITATION", ++ "ERROR_ASSERTION_FAILURE", ++ "ERROR_ACPI_ERROR", ++ "ERROR_WOW_ASSERTION", ++ "ERROR_PNP_BAD_MPS_TABLE", ++ "ERROR_PNP_TRANSLATION_FAILED", ++ "ERROR_PNP_IRQ_TRANSLATION_FAILED", ++ "ERROR_PNP_INVALID_ID", ++ "ERROR_WAKE_SYSTEM_DEBUGGER", ++ "ERROR_HANDLES_CLOSED", ++ "ERROR_EXTRANEOUS_INFORMATION", ++ "ERROR_RXACT_COMMIT_NECESSARY", ++ "ERROR_MEDIA_CHECK", ++ "ERROR_GUID_SUBSTITUTION_MADE", ++ "ERROR_STOPPED_ON_SYMLINK", ++ "ERROR_LONGJUMP", ++ "ERROR_PLUGPLAY_QUERY_VETOED", ++ "ERROR_UNWIND_CONSOLIDATE", ++ "ERROR_REGISTRY_HIVE_RECOVERED", ++ "ERROR_DLL_MIGHT_BE_INSECURE", ++ "ERROR_DLL_MIGHT_BE_INCOMPATIBLE", ++ "ERROR_DBG_EXCEPTION_NOT_HANDLED", ++ "ERROR_DBG_REPLY_LATER", ++ "ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE", ++ "ERROR_DBG_TERMINATE_THREAD", ++ "ERROR_DBG_TERMINATE_PROCESS", ++ "ERROR_DBG_CONTROL_C", ++ "ERROR_DBG_PRINTEXCEPTION_C", ++ "ERROR_DBG_RIPEXCEPTION", ++ "ERROR_DBG_CONTROL_BREAK", ++ "ERROR_DBG_COMMAND_EXCEPTION", ++ "ERROR_OBJECT_NAME_EXISTS", ++ "ERROR_THREAD_WAS_SUSPENDED", ++ "ERROR_IMAGE_NOT_AT_BASE", ++ "ERROR_RXACT_STATE_CREATED", ++ "ERROR_SEGMENT_NOTIFICATION", ++ "ERROR_BAD_CURRENT_DIRECTORY", ++ "ERROR_FT_READ_RECOVERY_FROM_BACKUP", ++ "ERROR_FT_WRITE_RECOVERY", ++ "ERROR_IMAGE_MACHINE_TYPE_MISMATCH", ++ "ERROR_RECEIVE_PARTIAL", ++ "ERROR_RECEIVE_EXPEDITED", ++ "ERROR_RECEIVE_PARTIAL_EXPEDITED", ++ "ERROR_EVENT_DONE", ++ "ERROR_EVENT_PENDING", ++ "ERROR_CHECKING_FILE_SYSTEM", ++ "ERROR_FATAL_APP_EXIT", ++ "ERROR_PREDEFINED_HANDLE", ++ "ERROR_WAS_UNLOCKED", ++ "ERROR_SERVICE_NOTIFICATION", ++ "ERROR_WAS_LOCKED", ++ "ERROR_LOG_HARD_ERROR", ++ "ERROR_ALREADY_WIN32", ++ "ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE", ++ "ERROR_NO_YIELD_PERFORMED", ++ "ERROR_TIMER_RESUME_IGNORED", ++ "ERROR_ARBITRATION_UNHANDLED", ++ "ERROR_CARDBUS_NOT_SUPPORTED", ++ "ERROR_MP_PROCESSOR_MISMATCH", ++ "ERROR_HIBERNATED", ++ "ERROR_RESUME_HIBERNATION", ++ "ERROR_FIRMWARE_UPDATED", ++ "ERROR_DRIVERS_LEAKING_LOCKED_PAGES", ++ "ERROR_WAKE_SYSTEM", ++ "ERROR_WAIT_1", ++ "ERROR_WAIT_2", ++ "ERROR_WAIT_3", ++ "ERROR_WAIT_63", ++ "ERROR_ABANDONED_WAIT_0", ++ "ERROR_ABANDONED_WAIT_63", ++ "ERROR_USER_APC", ++ "ERROR_KERNEL_APC", ++ "ERROR_ALERTED", ++ "ERROR_ELEVATION_REQUIRED", ++ "ERROR_REPARSE", ++ "ERROR_OPLOCK_BREAK_IN_PROGRESS", ++ "ERROR_VOLUME_MOUNTED", ++ "ERROR_RXACT_COMMITTED", ++ "ERROR_NOTIFY_CLEANUP", ++ "ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED", ++ "ERROR_PAGE_FAULT_TRANSITION", ++ "ERROR_PAGE_FAULT_DEMAND_ZERO", ++ "ERROR_PAGE_FAULT_COPY_ON_WRITE", ++ "ERROR_PAGE_FAULT_GUARD_PAGE", ++ "ERROR_PAGE_FAULT_PAGING_FILE", ++ "ERROR_CACHE_PAGE_LOCKED", ++ "ERROR_CRASH_DUMP", ++ "ERROR_BUFFER_ALL_ZEROS", ++ "ERROR_REPARSE_OBJECT", ++ "ERROR_RESOURCE_REQUIREMENTS_CHANGED", ++ "ERROR_TRANSLATION_COMPLETE", ++ "ERROR_NOTHING_TO_TERMINATE", ++ "ERROR_PROCESS_NOT_IN_JOB", ++ "ERROR_PROCESS_IN_JOB", ++ "ERROR_VOLSNAP_HIBERNATE_READY", ++ "ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY", ++ "ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED", ++ "ERROR_INTERRUPT_STILL_CONNECTED", ++ "ERROR_WAIT_FOR_OPLOCK", ++ "ERROR_DBG_EXCEPTION_HANDLED", ++ "ERROR_DBG_CONTINUE", ++ "ERROR_CALLBACK_POP_STACK", ++ "ERROR_COMPRESSION_DISABLED", ++ "ERROR_CANTFETCHBACKWARDS", ++ "ERROR_CANTSCROLLBACKWARDS", ++ "ERROR_ROWSNOTRELEASED", ++ "ERROR_BAD_ACCESSOR_FLAGS", ++ "ERROR_ERRORS_ENCOUNTERED", ++ "ERROR_NOT_CAPABLE", ++ "ERROR_REQUEST_OUT_OF_SEQUENCE", ++ "ERROR_VERSION_PARSE_ERROR", ++ "ERROR_BADSTARTPOSITION", ++ "ERROR_MEMORY_HARDWARE", ++ "ERROR_DISK_REPAIR_DISABLED", ++ "ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE", ++ "ERROR_SYSTEM_POWERSTATE_TRANSITION", ++ "ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION", ++ "ERROR_MCA_EXCEPTION", ++ "ERROR_ACCESS_AUDIT_BY_POLICY", ++ "ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY", ++ "ERROR_ABANDON_HIBERFILE", ++ "ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED", ++ "ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR", ++ "ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR", ++ "ERROR_BAD_MCFG_TABLE", ++ "ERROR_DISK_REPAIR_REDIRECTED", ++ "ERROR_DISK_REPAIR_UNSUCCESSFUL", ++ "ERROR_CORRUPT_LOG_OVERFULL", ++ "ERROR_CORRUPT_LOG_CORRUPTED", ++ "ERROR_CORRUPT_LOG_UNAVAILABLE", ++ "ERROR_CORRUPT_LOG_DELETED_FULL", ++ "ERROR_CORRUPT_LOG_CLEARED", ++ "ERROR_ORPHAN_NAME_EXHAUSTED", ++ "ERROR_OPLOCK_SWITCHED_TO_NEW_HANDLE", ++ "ERROR_CANNOT_GRANT_REQUESTED_OPLOCK", ++ "ERROR_CANNOT_BREAK_OPLOCK", ++ "ERROR_OPLOCK_HANDLE_CLOSED", ++ "ERROR_NO_ACE_CONDITION", ++ "ERROR_INVALID_ACE_CONDITION", ++ "ERROR_FILE_HANDLE_REVOKED", ++ "ERROR_IMAGE_AT_DIFFERENT_BASE", ++ "ERROR_ENCRYPTED_IO_NOT_POSSIBLE", ++ "ERROR_FILE_METADATA_OPTIMIZATION_IN_PROGRESS", ++ "ERROR_QUOTA_ACTIVITY", ++ "ERROR_HANDLE_REVOKED", ++ "ERROR_CALLBACK_INVOKE_INLINE", ++ "ERROR_CPU_SET_INVALID", ++ "ERROR_ENCLAVE_NOT_TERMINATED", ++ "ERROR_ENCLAVE_VIOLATION", ++ "ERROR_EA_ACCESS_DENIED", ++ "ERROR_OPERATION_ABORTED", ++ "ERROR_IO_INCOMPLETE", ++ "ERROR_IO_PENDING", ++ "ERROR_NOACCESS", ++ "ERROR_SWAPERROR", ++ "ERROR_STACK_OVERFLOW", ++ "ERROR_INVALID_MESSAGE", ++ "ERROR_CAN_NOT_COMPLETE", ++ "ERROR_INVALID_FLAGS", ++ "ERROR_UNRECOGNIZED_VOLUME", ++ "ERROR_FILE_INVALID", ++ "ERROR_FULLSCREEN_MODE", ++ "ERROR_NO_TOKEN", ++ "ERROR_BADDB", ++ "ERROR_BADKEY", ++ "ERROR_CANTOPEN", ++ "ERROR_CANTREAD", ++ "ERROR_CANTWRITE", ++ "ERROR_REGISTRY_RECOVERED", ++ "ERROR_REGISTRY_CORRUPT", ++ "ERROR_REGISTRY_IO_FAILED", ++ "ERROR_NOT_REGISTRY_FILE", ++ "ERROR_KEY_DELETED", ++ "ERROR_NO_LOG_SPACE", ++ "ERROR_KEY_HAS_CHILDREN", ++ "ERROR_CHILD_MUST_BE_VOLATILE", ++ "ERROR_NOTIFY_ENUM_DIR", ++ "ERROR_DEPENDENT_SERVICES_RUNNING", ++ "ERROR_INVALID_SERVICE_CONTROL", ++ "ERROR_SERVICE_REQUEST_TIMEOUT", ++ "ERROR_SERVICE_NO_THREAD", ++ "ERROR_SERVICE_DATABASE_LOCKED", ++ "ERROR_SERVICE_ALREADY_RUNNING", ++ "ERROR_INVALID_SERVICE_ACCOUNT", ++ "ERROR_SERVICE_DISABLED", ++ "ERROR_CIRCULAR_DEPENDENCY", ++ "ERROR_SERVICE_DOES_NOT_EXIST", ++ "ERROR_SERVICE_CANNOT_ACCEPT_CTRL", ++ "ERROR_SERVICE_NOT_ACTIVE", ++ "ERROR_FAILED_SERVICE_CONTROLLER_CONNECT", ++ "ERROR_EXCEPTION_IN_SERVICE", ++ "ERROR_DATABASE_DOES_NOT_EXIST", ++ "ERROR_SERVICE_SPECIFIC_ERROR", ++ "ERROR_PROCESS_ABORTED", ++ "ERROR_SERVICE_DEPENDENCY_FAIL", ++ "ERROR_SERVICE_LOGON_FAILED", ++ "ERROR_SERVICE_START_HANG", ++ "ERROR_INVALID_SERVICE_LOCK", ++ "ERROR_SERVICE_MARKED_FOR_DELETE", ++ "ERROR_SERVICE_EXISTS", ++ "ERROR_ALREADY_RUNNING_LKG", ++ "ERROR_SERVICE_DEPENDENCY_DELETED", ++ "ERROR_BOOT_ALREADY_ACCEPTED", ++ "ERROR_SERVICE_NEVER_STARTED", ++ "ERROR_DUPLICATE_SERVICE_NAME", ++ "ERROR_DIFFERENT_SERVICE_ACCOUNT", ++ "ERROR_CANNOT_DETECT_DRIVER_FAILURE", ++ "ERROR_CANNOT_DETECT_PROCESS_ABORT", ++ "ERROR_NO_RECOVERY_PROGRAM", ++ "ERROR_SERVICE_NOT_IN_EXE", ++ "ERROR_NOT_SAFEBOOT_SERVICE", ++ "ERROR_END_OF_MEDIA", ++ "ERROR_FILEMARK_DETECTED", ++ "ERROR_BEGINNING_OF_MEDIA", ++ "ERROR_SETMARK_DETECTED", ++ "ERROR_NO_DATA_DETECTED", ++ "ERROR_PARTITION_FAILURE", ++ "ERROR_INVALID_BLOCK_LENGTH", ++ "ERROR_DEVICE_NOT_PARTITIONED", ++ "ERROR_UNABLE_TO_LOCK_MEDIA", ++ "ERROR_UNABLE_TO_UNLOAD_MEDIA", ++ "ERROR_MEDIA_CHANGED", ++ "ERROR_BUS_RESET", ++ "ERROR_NO_MEDIA_IN_DRIVE", ++ "ERROR_NO_UNICODE_TRANSLATION", ++ "ERROR_DLL_INIT_FAILED", ++ "ERROR_SHUTDOWN_IN_PROGRESS", ++ "ERROR_NO_SHUTDOWN_IN_PROGRESS", ++ "ERROR_IO_DEVICE", ++ "ERROR_SERIAL_NO_DEVICE", ++ "ERROR_IRQ_BUSY", ++ "ERROR_MORE_WRITES", ++ "ERROR_COUNTER_TIMEOUT", ++ "ERROR_FLOPPY_ID_MARK_NOT_FOUND", ++ "ERROR_FLOPPY_WRONG_CYLINDER", ++ "ERROR_FLOPPY_UNKNOWN_ERROR", ++ "ERROR_FLOPPY_BAD_REGISTERS", ++ "ERROR_DISK_RECALIBRATE_FAILED", ++ "ERROR_DISK_OPERATION_FAILED", ++ "ERROR_DISK_RESET_FAILED", ++ "ERROR_EOM_OVERFLOW", ++ "ERROR_NOT_ENOUGH_SERVER_MEMORY", ++ "ERROR_POSSIBLE_DEADLOCK", ++ "ERROR_MAPPED_ALIGNMENT", ++ "ERROR_SET_POWER_STATE_VETOED", ++ "ERROR_SET_POWER_STATE_FAILED", ++ "ERROR_TOO_MANY_LINKS", ++ "ERROR_OLD_WIN_VERSION", ++ "ERROR_APP_WRONG_OS", ++ "ERROR_SINGLE_INSTANCE_APP", ++ "ERROR_RMODE_APP", ++ "ERROR_INVALID_DLL", ++ "ERROR_NO_ASSOCIATION", ++ "ERROR_DDE_FAIL", ++ "ERROR_DLL_NOT_FOUND", ++ "ERROR_NO_MORE_USER_HANDLES", ++ "ERROR_MESSAGE_SYNC_ONLY", ++ "ERROR_SOURCE_ELEMENT_EMPTY", ++ "ERROR_DESTINATION_ELEMENT_FULL", ++ "ERROR_ILLEGAL_ELEMENT_ADDRESS", ++ "ERROR_MAGAZINE_NOT_PRESENT", ++ "ERROR_DEVICE_REINITIALIZATION_NEEDED", ++ "ERROR_DEVICE_REQUIRES_CLEANING", ++ "ERROR_DEVICE_DOOR_OPEN", ++ "ERROR_DEVICE_NOT_CONNECTED", ++ "ERROR_NOT_FOUND", ++ "ERROR_NO_MATCH", ++ "ERROR_SET_NOT_FOUND", ++ "ERROR_POINT_NOT_FOUND", ++ "ERROR_NO_TRACKING_SERVICE", ++ "ERROR_NO_VOLUME_ID", ++ "ERROR_UNABLE_TO_REMOVE_REPLACED", ++ "ERROR_UNABLE_TO_MOVE_REPLACEMENT", ++ "ERROR_UNABLE_TO_MOVE_REPLACEMENT_2", ++ "ERROR_JOURNAL_DELETE_IN_PROGRESS", ++ "ERROR_JOURNAL_NOT_ACTIVE", ++ "ERROR_POTENTIAL_FILE_FOUND", ++ "ERROR_JOURNAL_ENTRY_DELETED", ++ "ERROR_VRF_CFG_AND_IO_ENABLED", ++ "ERROR_PARTITION_TERMINATING", ++ "ERROR_SHUTDOWN_IS_SCHEDULED", ++ "ERROR_SHUTDOWN_USERS_LOGGED_ON", ++ "ERROR_BAD_DEVICE", ++ "ERROR_CONNECTION_UNAVAIL", ++ "ERROR_DEVICE_ALREADY_REMEMBERED", ++ "ERROR_NO_NET_OR_BAD_PATH", ++ "ERROR_BAD_PROVIDER", ++ "ERROR_CANNOT_OPEN_PROFILE", ++ "ERROR_BAD_PROFILE", ++ "ERROR_NOT_CONTAINER", ++ "ERROR_EXTENDED_ERROR", ++ "ERROR_INVALID_GROUPNAME", ++ "ERROR_INVALID_COMPUTERNAME", ++ "ERROR_INVALID_EVENTNAME", ++ "ERROR_INVALID_DOMAINNAME", ++ "ERROR_INVALID_SERVICENAME", ++ "ERROR_INVALID_NETNAME", ++ "ERROR_INVALID_SHARENAME", ++ "ERROR_INVALID_PASSWORDNAME", ++ "ERROR_INVALID_MESSAGENAME", ++ "ERROR_INVALID_MESSAGEDEST", ++ "ERROR_SESSION_CREDENTIAL_CONFLICT", ++ "ERROR_REMOTE_SESSION_LIMIT_EXCEEDED", ++ "ERROR_DUP_DOMAINNAME", ++ "ERROR_NO_NETWORK", ++ "ERROR_CANCELLED", ++ "ERROR_USER_MAPPED_FILE", ++ "ERROR_CONNECTION_REFUSED", ++ "ERROR_GRACEFUL_DISCONNECT", ++ "ERROR_ADDRESS_ALREADY_ASSOCIATED", ++ "ERROR_ADDRESS_NOT_ASSOCIATED", ++ "ERROR_CONNECTION_INVALID", ++ "ERROR_CONNECTION_ACTIVE", ++ "ERROR_NETWORK_UNREACHABLE", ++ "ERROR_HOST_UNREACHABLE", ++ "ERROR_PROTOCOL_UNREACHABLE", ++ "ERROR_PORT_UNREACHABLE", ++ "ERROR_REQUEST_ABORTED", ++ "ERROR_CONNECTION_ABORTED", ++ "ERROR_RETRY", ++ "ERROR_CONNECTION_COUNT_LIMIT", ++ "ERROR_LOGIN_TIME_RESTRICTION", ++ "ERROR_LOGIN_WKSTA_RESTRICTION", ++ "ERROR_INCORRECT_ADDRESS", ++ "ERROR_ALREADY_REGISTERED", ++ "ERROR_SERVICE_NOT_FOUND", ++ "ERROR_NOT_AUTHENTICATED", ++ "ERROR_NOT_LOGGED_ON", ++ "ERROR_CONTINUE", ++ "ERROR_ALREADY_INITIALIZED", ++ "ERROR_NO_MORE_DEVICES", ++ "ERROR_NO_SUCH_SITE", ++ "ERROR_DOMAIN_CONTROLLER_EXISTS", ++ "ERROR_ONLY_IF_CONNECTED", ++ "ERROR_OVERRIDE_NOCHANGES", ++ "ERROR_BAD_USER_PROFILE", ++ "ERROR_NOT_SUPPORTED_ON_SBS", ++ "ERROR_SERVER_SHUTDOWN_IN_PROGRESS", ++ "ERROR_HOST_DOWN", ++ "ERROR_NON_ACCOUNT_SID", ++ "ERROR_NON_DOMAIN_SID", ++ "ERROR_APPHELP_BLOCK", ++ "ERROR_ACCESS_DISABLED_BY_POLICY", ++ "ERROR_REG_NAT_CONSUMPTION", ++ "ERROR_CSCSHARE_OFFLINE", ++ "ERROR_PKINIT_FAILURE", ++ "ERROR_SMARTCARD_SUBSYSTEM_FAILURE", ++ "ERROR_DOWNGRADE_DETECTED", ++ "ERROR_MACHINE_LOCKED", ++ "ERROR_SMB_GUEST_LOGON_BLOCKED", ++ "ERROR_CALLBACK_SUPPLIED_INVALID_DATA", ++ "ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED", ++ "ERROR_DRIVER_BLOCKED", ++ "ERROR_INVALID_IMPORT_OF_NON_DLL", ++ "ERROR_ACCESS_DISABLED_WEBBLADE", ++ "ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER", ++ "ERROR_RECOVERY_FAILURE", ++ "ERROR_ALREADY_FIBER", ++ "ERROR_ALREADY_THREAD", ++ "ERROR_STACK_BUFFER_OVERRUN", ++ "ERROR_PARAMETER_QUOTA_EXCEEDED", ++ "ERROR_DEBUGGER_INACTIVE", ++ "ERROR_DELAY_LOAD_FAILED", ++ "ERROR_VDM_DISALLOWED", ++ "ERROR_UNIDENTIFIED_ERROR", ++ "ERROR_INVALID_CRUNTIME_PARAMETER", ++ "ERROR_BEYOND_VDL", ++ "ERROR_INCOMPATIBLE_SERVICE_SID_TYPE", ++ "ERROR_DRIVER_PROCESS_TERMINATED", ++ "ERROR_IMPLEMENTATION_LIMIT", ++ "ERROR_PROCESS_IS_PROTECTED", ++ "ERROR_SERVICE_NOTIFY_CLIENT_LAGGING", ++ "ERROR_DISK_QUOTA_EXCEEDED", ++ "ERROR_CONTENT_BLOCKED", ++ "ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE", ++ "ERROR_APP_HANG", ++ "ERROR_INVALID_LABEL", ++ "ERROR_NOT_ALL_ASSIGNED", ++ "ERROR_SOME_NOT_MAPPED", ++ "ERROR_NO_QUOTAS_FOR_ACCOUNT", ++ "ERROR_LOCAL_USER_SESSION_KEY", ++ "ERROR_NULL_LM_PASSWORD", ++ "ERROR_UNKNOWN_REVISION", ++ "ERROR_REVISION_MISMATCH", ++ "ERROR_INVALID_OWNER", ++ "ERROR_INVALID_PRIMARY_GROUP", ++ "ERROR_NO_IMPERSONATION_TOKEN", ++ "ERROR_CANT_DISABLE_MANDATORY", ++ "ERROR_NO_LOGON_SERVERS", ++ "ERROR_NO_SUCH_LOGON_SESSION", ++ "ERROR_NO_SUCH_PRIVILEGE", ++ "ERROR_PRIVILEGE_NOT_HELD", ++ "ERROR_INVALID_ACCOUNT_NAME", ++ "ERROR_USER_EXISTS", ++ "ERROR_NO_SUCH_USER", ++ "ERROR_GROUP_EXISTS", ++ "ERROR_NO_SUCH_GROUP", ++ "ERROR_MEMBER_IN_GROUP", ++ "ERROR_MEMBER_NOT_IN_GROUP", ++ "ERROR_LAST_ADMIN", ++ "ERROR_WRONG_PASSWORD", ++ "ERROR_ILL_FORMED_PASSWORD", ++ "ERROR_PASSWORD_RESTRICTION", ++ "ERROR_LOGON_FAILURE", ++ "ERROR_ACCOUNT_RESTRICTION", ++ "ERROR_INVALID_LOGON_HOURS", ++ "ERROR_INVALID_WORKSTATION", ++ "ERROR_PASSWORD_EXPIRED", ++ "ERROR_ACCOUNT_DISABLED", ++ "ERROR_NONE_MAPPED", ++ "ERROR_TOO_MANY_LUIDS_REQUESTED", ++ "ERROR_LUIDS_EXHAUSTED", ++ "ERROR_INVALID_SUB_AUTHORITY", ++ "ERROR_INVALID_ACL", ++ "ERROR_INVALID_SID", ++ "ERROR_INVALID_SECURITY_DESCR", ++ "ERROR_BAD_INHERITANCE_ACL", ++ "ERROR_SERVER_DISABLED", ++ "ERROR_SERVER_NOT_DISABLED", ++ "ERROR_INVALID_ID_AUTHORITY", ++ "ERROR_ALLOTTED_SPACE_EXCEEDED", ++ "ERROR_INVALID_GROUP_ATTRIBUTES", ++ "ERROR_BAD_IMPERSONATION_LEVEL", ++ "ERROR_CANT_OPEN_ANONYMOUS", ++ "ERROR_BAD_VALIDATION_CLASS", ++ "ERROR_BAD_TOKEN_TYPE", ++ "ERROR_NO_SECURITY_ON_OBJECT", ++ "ERROR_CANT_ACCESS_DOMAIN_INFO", ++ "ERROR_INVALID_SERVER_STATE", ++ "ERROR_INVALID_DOMAIN_STATE", ++ "ERROR_INVALID_DOMAIN_ROLE", ++ "ERROR_NO_SUCH_DOMAIN", ++ "ERROR_DOMAIN_EXISTS", ++ "ERROR_DOMAIN_LIMIT_EXCEEDED", ++ "ERROR_INTERNAL_DB_CORRUPTION", ++ "ERROR_INTERNAL_ERROR", ++ "ERROR_GENERIC_NOT_MAPPED", ++ "ERROR_BAD_DESCRIPTOR_FORMAT", ++ "ERROR_NOT_LOGON_PROCESS", ++ "ERROR_LOGON_SESSION_EXISTS", ++ "ERROR_NO_SUCH_PACKAGE", ++ "ERROR_BAD_LOGON_SESSION_STATE", ++ "ERROR_LOGON_SESSION_COLLISION", ++ "ERROR_INVALID_LOGON_TYPE", ++ "ERROR_CANNOT_IMPERSONATE", ++ "ERROR_RXACT_INVALID_STATE", ++ "ERROR_RXACT_COMMIT_FAILURE", ++ "ERROR_SPECIAL_ACCOUNT", ++ "ERROR_SPECIAL_GROUP", ++ "ERROR_SPECIAL_USER", ++ "ERROR_MEMBERS_PRIMARY_GROUP", ++ "ERROR_TOKEN_ALREADY_IN_USE", ++ "ERROR_NO_SUCH_ALIAS", ++ "ERROR_MEMBER_NOT_IN_ALIAS", ++ "ERROR_MEMBER_IN_ALIAS", ++ "ERROR_ALIAS_EXISTS", ++ "ERROR_LOGON_NOT_GRANTED", ++ "ERROR_TOO_MANY_SECRETS", ++ "ERROR_SECRET_TOO_LONG", ++ "ERROR_INTERNAL_DB_ERROR", ++ "ERROR_TOO_MANY_CONTEXT_IDS", ++ "ERROR_LOGON_TYPE_NOT_GRANTED", ++ "ERROR_NT_CROSS_ENCRYPTION_REQUIRED", ++ "ERROR_NO_SUCH_MEMBER", ++ "ERROR_INVALID_MEMBER", ++ "ERROR_TOO_MANY_SIDS", ++ "ERROR_LM_CROSS_ENCRYPTION_REQUIRED", ++ "ERROR_NO_INHERITANCE", ++ "ERROR_FILE_CORRUPT", ++ "ERROR_DISK_CORRUPT", ++ "ERROR_NO_USER_SESSION_KEY", ++ "ERROR_LICENSE_QUOTA_EXCEEDED", ++ "ERROR_WRONG_TARGET_NAME", ++ "ERROR_MUTUAL_AUTH_FAILED", ++ "ERROR_TIME_SKEW", ++ "ERROR_CURRENT_DOMAIN_NOT_ALLOWED", ++ "ERROR_INVALID_WINDOW_HANDLE", ++ "ERROR_INVALID_MENU_HANDLE", ++ "ERROR_INVALID_CURSOR_HANDLE", ++ "ERROR_INVALID_ACCEL_HANDLE", ++ "ERROR_INVALID_HOOK_HANDLE", ++ "ERROR_INVALID_DWP_HANDLE", ++ "ERROR_TLW_WITH_WSCHILD", ++ "ERROR_CANNOT_FIND_WND_CLASS", ++ "ERROR_WINDOW_OF_OTHER_THREAD", ++ "ERROR_HOTKEY_ALREADY_REGISTERED", ++ "ERROR_CLASS_ALREADY_EXISTS", ++ "ERROR_CLASS_DOES_NOT_EXIST", ++ "ERROR_CLASS_HAS_WINDOWS", ++ "ERROR_INVALID_INDEX", ++ "ERROR_INVALID_ICON_HANDLE", ++ "ERROR_PRIVATE_DIALOG_INDEX", ++ "ERROR_LISTBOX_ID_NOT_FOUND", ++ "ERROR_NO_WILDCARD_CHARACTERS", ++ "ERROR_CLIPBOARD_NOT_OPEN", ++ "ERROR_HOTKEY_NOT_REGISTERED", ++ "ERROR_WINDOW_NOT_DIALOG", ++ "ERROR_CONTROL_ID_NOT_FOUND", ++ "ERROR_INVALID_COMBOBOX_MESSAGE", ++ "ERROR_WINDOW_NOT_COMBOBOX", ++ "ERROR_INVALID_EDIT_HEIGHT", ++ "ERROR_DC_NOT_FOUND", ++ "ERROR_INVALID_HOOK_FILTER", ++ "ERROR_INVALID_FILTER_PROC", ++ "ERROR_HOOK_NEEDS_HMOD", ++ "ERROR_GLOBAL_ONLY_HOOK", ++ "ERROR_JOURNAL_HOOK_SET", ++ "ERROR_HOOK_NOT_INSTALLED", ++ "ERROR_INVALID_LB_MESSAGE", ++ "ERROR_SETCOUNT_ON_BAD_LB", ++ "ERROR_LB_WITHOUT_TABSTOPS", ++ "ERROR_DESTROY_OBJECT_OF_OTHER_THREAD", ++ "ERROR_CHILD_WINDOW_MENU", ++ "ERROR_NO_SYSTEM_MENU", ++ "ERROR_INVALID_MSGBOX_STYLE", ++ "ERROR_INVALID_SPI_VALUE", ++ "ERROR_SCREEN_ALREADY_LOCKED", ++ "ERROR_HWNDS_HAVE_DIFF_PARENT", ++ "ERROR_NOT_CHILD_WINDOW", ++ "ERROR_INVALID_GW_COMMAND", ++ "ERROR_INVALID_THREAD_ID", ++ "ERROR_NON_MDICHILD_WINDOW", ++ "ERROR_POPUP_ALREADY_ACTIVE", ++ "ERROR_NO_SCROLLBARS", ++ "ERROR_INVALID_SCROLLBAR_RANGE", ++ "ERROR_INVALID_SHOWWIN_COMMAND", ++ "ERROR_NO_SYSTEM_RESOURCES", ++ "ERROR_NONPAGED_SYSTEM_RESOURCES", ++ "ERROR_PAGED_SYSTEM_RESOURCES", ++ "ERROR_WORKING_SET_QUOTA", ++ "ERROR_PAGEFILE_QUOTA", ++ "ERROR_COMMITMENT_LIMIT", ++ "ERROR_MENU_ITEM_NOT_FOUND", ++ "ERROR_INVALID_KEYBOARD_HANDLE", ++ "ERROR_HOOK_TYPE_NOT_ALLOWED", ++ "ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION", ++ "ERROR_TIMEOUT", ++ "ERROR_INVALID_MONITOR_HANDLE", ++ "ERROR_INCORRECT_SIZE", ++ "ERROR_SYMLINK_CLASS_DISABLED", ++ "ERROR_SYMLINK_NOT_SUPPORTED", ++ "ERROR_XML_PARSE_ERROR", ++ "ERROR_XMLDSIG_ERROR", ++ "ERROR_RESTART_APPLICATION", ++ "ERROR_WRONG_COMPARTMENT", ++ "ERROR_AUTHIP_FAILURE", ++ "ERROR_NO_NVRAM_RESOURCES", ++ "ERROR_NOT_GUI_PROCESS", ++ "ERROR_EVENTLOG_FILE_CORRUPT", ++ "ERROR_EVENTLOG_CANT_START", ++ "ERROR_LOG_FILE_FULL", ++ "ERROR_EVENTLOG_FILE_CHANGED", ++ "ERROR_CONTAINER_ASSIGNED", ++ "ERROR_JOB_NO_CONTAINER", ++ "ERROR_INVALID_TASK_NAME", ++ "ERROR_INVALID_TASK_INDEX", ++ "ERROR_THREAD_ALREADY_IN_TASK", ++ "ERROR_INSTALL_SERVICE_FAILURE", ++ "ERROR_INSTALL_USEREXIT", ++ "ERROR_INSTALL_FAILURE", ++ "ERROR_INSTALL_SUSPEND", ++ "ERROR_UNKNOWN_PRODUCT", ++ "ERROR_UNKNOWN_FEATURE", ++ "ERROR_UNKNOWN_COMPONENT", ++ "ERROR_UNKNOWN_PROPERTY", ++ "ERROR_INVALID_HANDLE_STATE", ++ "ERROR_BAD_CONFIGURATION", ++ "ERROR_INDEX_ABSENT", ++ "ERROR_INSTALL_SOURCE_ABSENT", ++ "ERROR_INSTALL_PACKAGE_VERSION", ++ "ERROR_PRODUCT_UNINSTALLED", ++ "ERROR_BAD_QUERY_SYNTAX", ++ "ERROR_INVALID_FIELD", ++ "ERROR_DEVICE_REMOVED", ++ "ERROR_INSTALL_ALREADY_RUNNING", ++ "ERROR_INSTALL_PACKAGE_OPEN_FAILED", ++ "ERROR_INSTALL_PACKAGE_INVALID", ++ "ERROR_INSTALL_UI_FAILURE", ++ "ERROR_INSTALL_LOG_FAILURE", ++ "ERROR_INSTALL_LANGUAGE_UNSUPPORTED", ++ "ERROR_INSTALL_TRANSFORM_FAILURE", ++ "ERROR_INSTALL_PACKAGE_REJECTED", ++ "ERROR_FUNCTION_NOT_CALLED", ++ "ERROR_FUNCTION_FAILED", ++ "ERROR_INVALID_TABLE", ++ "ERROR_DATATYPE_MISMATCH", ++ "ERROR_UNSUPPORTED_TYPE", ++ "ERROR_CREATE_FAILED", ++ "ERROR_INSTALL_TEMP_UNWRITABLE", ++ "ERROR_INSTALL_PLATFORM_UNSUPPORTED", ++ "ERROR_INSTALL_NOTUSED", ++ "ERROR_PATCH_PACKAGE_OPEN_FAILED", ++ "ERROR_PATCH_PACKAGE_INVALID", ++ "ERROR_PATCH_PACKAGE_UNSUPPORTED", ++ "ERROR_PRODUCT_VERSION", ++ "ERROR_INVALID_COMMAND_LINE", ++ "ERROR_INSTALL_REMOTE_DISALLOWED", ++ "ERROR_SUCCESS_REBOOT_INITIATED", ++ "ERROR_PATCH_TARGET_NOT_FOUND", ++ "ERROR_PATCH_PACKAGE_REJECTED", ++ "ERROR_INSTALL_TRANSFORM_REJECTED", ++ "ERROR_INSTALL_REMOTE_PROHIBITED", ++ "ERROR_PATCH_REMOVAL_UNSUPPORTED", ++ "ERROR_UNKNOWN_PATCH", ++ "ERROR_PATCH_NO_SEQUENCE", ++ "ERROR_PATCH_REMOVAL_DISALLOWED", ++ "ERROR_INVALID_PATCH_XML", ++ "ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT", ++ "ERROR_INSTALL_SERVICE_SAFEBOOT", ++ "ERROR_FAIL_FAST_EXCEPTION", ++ "ERROR_INSTALL_REJECTED", ++ "ERROR_DYNAMIC_CODE_BLOCKED", ++ "ERROR_NOT_SAME_OBJECT", ++ "ERROR_STRICT_CFG_VIOLATION", ++ "ERROR_SET_CONTEXT_DENIED", ++ "ERROR_CROSS_PARTITION_VIOLATION", ++ "ERROR_RETURN_ADDRESS_HIJACK_ATTEMPT", ++ "ERROR_INVALID_USER_BUFFER", ++ "ERROR_UNRECOGNIZED_MEDIA", ++ "ERROR_NO_TRUST_LSA_SECRET", ++ "ERROR_NO_TRUST_SAM_ACCOUNT", ++ "ERROR_TRUSTED_DOMAIN_FAILURE", ++ "ERROR_TRUSTED_RELATIONSHIP_FAILURE", ++ "ERROR_TRUST_FAILURE", ++ "ERROR_NETLOGON_NOT_STARTED", ++ "ERROR_ACCOUNT_EXPIRED", ++ "ERROR_REDIRECTOR_HAS_OPEN_HANDLES", ++ "ERROR_PRINTER_DRIVER_ALREADY_INSTALLED", ++ "ERROR_UNKNOWN_PORT", ++ "ERROR_UNKNOWN_PRINTER_DRIVER", ++ "ERROR_UNKNOWN_PRINTPROCESSOR", ++ "ERROR_INVALID_SEPARATOR_FILE", ++ "ERROR_INVALID_PRIORITY", ++ "ERROR_INVALID_PRINTER_NAME", ++ "ERROR_PRINTER_ALREADY_EXISTS", ++ "ERROR_INVALID_PRINTER_COMMAND", ++ "ERROR_INVALID_DATATYPE", ++ "ERROR_INVALID_ENVIRONMENT", ++ "ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", ++ "ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT", ++ "ERROR_NOLOGON_SERVER_TRUST_ACCOUNT", ++ "ERROR_DOMAIN_TRUST_INCONSISTENT", ++ "ERROR_SERVER_HAS_OPEN_HANDLES", ++ "ERROR_RESOURCE_DATA_NOT_FOUND", ++ "ERROR_RESOURCE_TYPE_NOT_FOUND", ++ "ERROR_RESOURCE_NAME_NOT_FOUND", ++ "ERROR_RESOURCE_LANG_NOT_FOUND", ++ "ERROR_NOT_ENOUGH_QUOTA", ++ "ERROR_INVALID_TIME", ++ "ERROR_INVALID_FORM_NAME", ++ "ERROR_INVALID_FORM_SIZE", ++ "ERROR_ALREADY_WAITING", ++ "ERROR_PRINTER_DELETED", ++ "ERROR_INVALID_PRINTER_STATE", ++ "ERROR_PASSWORD_MUST_CHANGE", ++ "ERROR_DOMAIN_CONTROLLER_NOT_FOUND", ++ "ERROR_ACCOUNT_LOCKED_OUT", ++ "ERROR_NO_SITENAME", ++ "ERROR_CANT_ACCESS_FILE", ++ "ERROR_CANT_RESOLVE_FILENAME", ++ "ERROR_KM_DRIVER_BLOCKED", ++ "ERROR_CONTEXT_EXPIRED", ++ "ERROR_PER_USER_TRUST_QUOTA_EXCEEDED", ++ "ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED", ++ "ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED", ++ "ERROR_AUTHENTICATION_FIREWALL_FAILED", ++ "ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED", ++ "ERROR_NTLM_BLOCKED", ++ "ERROR_PASSWORD_CHANGE_REQUIRED", ++ "ERROR_LOST_MODE_LOGON_RESTRICTION", ++ "ERROR_INVALID_PIXEL_FORMAT", ++ "ERROR_BAD_DRIVER", ++ "ERROR_INVALID_WINDOW_STYLE", ++ "ERROR_METAFILE_NOT_SUPPORTED", ++ "ERROR_TRANSFORM_NOT_SUPPORTED", ++ "ERROR_CLIPPING_NOT_SUPPORTED", ++ "ERROR_INVALID_CMM", ++ "ERROR_INVALID_PROFILE", ++ "ERROR_TAG_NOT_FOUND", ++ "ERROR_TAG_NOT_PRESENT", ++ "ERROR_DUPLICATE_TAG", ++ "ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE", ++ "ERROR_PROFILE_NOT_FOUND", ++ "ERROR_INVALID_COLORSPACE", ++ "ERROR_ICM_NOT_ENABLED", ++ "ERROR_DELETING_ICM_XFORM", ++ "ERROR_INVALID_TRANSFORM", ++ "ERROR_COLORSPACE_MISMATCH", ++ "ERROR_INVALID_COLORINDEX", ++ "ERROR_PROFILE_DOES_NOT_MATCH_DEVICE", ++ "ERROR_CONNECTED_OTHER_PASSWORD", ++ "ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT", ++ "ERROR_BAD_USERNAME", ++ "ERROR_NOT_CONNECTED", ++ "ERROR_OPEN_FILES", ++ "ERROR_ACTIVE_CONNECTIONS", ++ "ERROR_DEVICE_IN_USE", ++ "ERROR_UNKNOWN_PRINT_MONITOR", ++ "ERROR_PRINTER_DRIVER_IN_USE", ++ "ERROR_SPOOL_FILE_NOT_FOUND", ++ "ERROR_SPL_NO_STARTDOC", ++ "ERROR_SPL_NO_ADDJOB", ++ "ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED", ++ "ERROR_PRINT_MONITOR_ALREADY_INSTALLED", ++ "ERROR_INVALID_PRINT_MONITOR", ++ "ERROR_PRINT_MONITOR_IN_USE", ++ "ERROR_PRINTER_HAS_JOBS_QUEUED", ++ "ERROR_SUCCESS_REBOOT_REQUIRED", ++ "ERROR_SUCCESS_RESTART_REQUIRED", ++ "ERROR_PRINTER_NOT_FOUND", ++ "ERROR_PRINTER_DRIVER_WARNED", ++ "ERROR_PRINTER_DRIVER_BLOCKED", ++ "ERROR_PRINTER_DRIVER_PACKAGE_IN_USE", ++ "ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND", ++ "ERROR_FAIL_REBOOT_REQUIRED", ++ "ERROR_FAIL_REBOOT_INITIATED", ++ "ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED", ++ "ERROR_PRINT_JOB_RESTART_REQUIRED", ++ "ERROR_INVALID_PRINTER_DRIVER_MANIFEST", ++ "ERROR_PRINTER_NOT_SHAREABLE", ++ "ERROR_REQUEST_PAUSED", ++ "ERROR_APPEXEC_CONDITION_NOT_SATISFIED", ++ "ERROR_APPEXEC_HANDLE_INVALIDATED", ++ "ERROR_APPEXEC_INVALID_HOST_GENERATION", ++ "ERROR_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION", ++ "ERROR_APPEXEC_INVALID_HOST_STATE", ++ "ERROR_APPEXEC_NO_DONOR", ++ "ERROR_APPEXEC_HOST_ID_MISMATCH", ++ "ERROR_APPEXEC_UNKNOWN_USER", ++ "ERROR_IO_REISSUE_AS_CACHED", ++ "ERROR_WINS_INTERNAL", ++ "ERROR_CAN_NOT_DEL_LOCAL_WINS", ++ "ERROR_STATIC_INIT", ++ "ERROR_INC_BACKUP", ++ "ERROR_FULL_BACKUP", ++ "ERROR_REC_NON_EXISTENT", ++ "ERROR_RPL_NOT_ALLOWED", ++ "ERROR_DHCP_ADDRESS_CONFLICT", ++ "ERROR_WMI_GUID_NOT_FOUND", ++ "ERROR_WMI_INSTANCE_NOT_FOUND", ++ "ERROR_WMI_ITEMID_NOT_FOUND", ++ "ERROR_WMI_TRY_AGAIN", ++ "ERROR_WMI_DP_NOT_FOUND", ++ "ERROR_WMI_UNRESOLVED_INSTANCE_REF", ++ "ERROR_WMI_ALREADY_ENABLED", ++ "ERROR_WMI_GUID_DISCONNECTED", ++ "ERROR_WMI_SERVER_UNAVAILABLE", ++ "ERROR_WMI_DP_FAILED", ++ "ERROR_WMI_INVALID_MOF", ++ "ERROR_WMI_INVALID_REGINFO", ++ "ERROR_WMI_ALREADY_DISABLED", ++ "ERROR_WMI_READ_ONLY", ++ "ERROR_WMI_SET_FAILURE", ++ "ERROR_NOT_APPCONTAINER", ++ "ERROR_APPCONTAINER_REQUIRED", ++ "ERROR_NOT_SUPPORTED_IN_APPCONTAINER", ++ "ERROR_INVALID_PACKAGE_SID_LENGTH", ++ "ERROR_INVALID_MEDIA", ++ "ERROR_INVALID_LIBRARY", ++ "ERROR_INVALID_MEDIA_POOL", ++ "ERROR_DRIVE_MEDIA_MISMATCH", ++ "ERROR_MEDIA_OFFLINE", ++ "ERROR_LIBRARY_OFFLINE", ++ "ERROR_EMPTY", ++ "ERROR_NOT_EMPTY", ++ "ERROR_MEDIA_UNAVAILABLE", ++ "ERROR_RESOURCE_DISABLED", ++ "ERROR_INVALID_CLEANER", ++ "ERROR_UNABLE_TO_CLEAN", ++ "ERROR_OBJECT_NOT_FOUND", ++ "ERROR_DATABASE_FAILURE", ++ "ERROR_DATABASE_FULL", ++ "ERROR_MEDIA_INCOMPATIBLE", ++ "ERROR_RESOURCE_NOT_PRESENT", ++ "ERROR_INVALID_OPERATION", ++ "ERROR_MEDIA_NOT_AVAILABLE", ++ "ERROR_DEVICE_NOT_AVAILABLE", ++ "ERROR_REQUEST_REFUSED", ++ "ERROR_INVALID_DRIVE_OBJECT", ++ "ERROR_LIBRARY_FULL", ++ "ERROR_MEDIUM_NOT_ACCESSIBLE", ++ "ERROR_UNABLE_TO_LOAD_MEDIUM", ++ "ERROR_UNABLE_TO_INVENTORY_DRIVE", ++ "ERROR_UNABLE_TO_INVENTORY_SLOT", ++ "ERROR_UNABLE_TO_INVENTORY_TRANSPORT", ++ "ERROR_TRANSPORT_FULL", ++ "ERROR_CONTROLLING_IEPORT", ++ "ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA", ++ "ERROR_CLEANER_SLOT_SET", ++ "ERROR_CLEANER_SLOT_NOT_SET", ++ "ERROR_CLEANER_CARTRIDGE_SPENT", ++ "ERROR_UNEXPECTED_OMID", ++ "ERROR_CANT_DELETE_LAST_ITEM", ++ "ERROR_MESSAGE_EXCEEDS_MAX_SIZE", ++ "ERROR_VOLUME_CONTAINS_SYS_FILES", ++ "ERROR_INDIGENOUS_TYPE", ++ "ERROR_NO_SUPPORTING_DRIVES", ++ "ERROR_CLEANER_CARTRIDGE_INSTALLED", ++ "ERROR_IEPORT_FULL", ++ "ERROR_FILE_OFFLINE", ++ "ERROR_REMOTE_STORAGE_NOT_ACTIVE", ++ "ERROR_REMOTE_STORAGE_MEDIA_ERROR", ++ "ERROR_NOT_A_REPARSE_POINT", ++ "ERROR_REPARSE_ATTRIBUTE_CONFLICT", ++ "ERROR_INVALID_REPARSE_DATA", ++ "ERROR_REPARSE_TAG_INVALID", ++ "ERROR_REPARSE_TAG_MISMATCH", ++ "ERROR_REPARSE_POINT_ENCOUNTERED", ++ "ERROR_APP_DATA_NOT_FOUND", ++ "ERROR_APP_DATA_EXPIRED", ++ "ERROR_APP_DATA_CORRUPT", ++ "ERROR_APP_DATA_LIMIT_EXCEEDED", ++ "ERROR_APP_DATA_REBOOT_REQUIRED", ++ "ERROR_SECUREBOOT_ROLLBACK_DETECTED", ++ "ERROR_SECUREBOOT_POLICY_VIOLATION", ++ "ERROR_SECUREBOOT_INVALID_POLICY", ++ "ERROR_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND", ++ "ERROR_SECUREBOOT_POLICY_NOT_SIGNED", ++ "ERROR_SECUREBOOT_NOT_ENABLED", ++ "ERROR_SECUREBOOT_FILE_REPLACED", ++ "ERROR_SECUREBOOT_POLICY_NOT_AUTHORIZED", ++ "ERROR_SECUREBOOT_POLICY_UNKNOWN", ++ "ERROR_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION", ++ "ERROR_SECUREBOOT_PLATFORM_ID_MISMATCH", ++ "ERROR_SECUREBOOT_POLICY_ROLLBACK_DETECTED", ++ "ERROR_SECUREBOOT_POLICY_UPGRADE_MISMATCH", ++ "ERROR_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING", ++ "ERROR_SECUREBOOT_NOT_BASE_POLICY", ++ "ERROR_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY", ++ "ERROR_OFFLOAD_READ_FLT_NOT_SUPPORTED", ++ "ERROR_OFFLOAD_WRITE_FLT_NOT_SUPPORTED", ++ "ERROR_OFFLOAD_READ_FILE_NOT_SUPPORTED", ++ "ERROR_OFFLOAD_WRITE_FILE_NOT_SUPPORTED", ++ "ERROR_ALREADY_HAS_STREAM_ID", ++ "ERROR_SMR_GARBAGE_COLLECTION_REQUIRED", ++ "ERROR_WOF_WIM_HEADER_CORRUPT", ++ "ERROR_WOF_WIM_RESOURCE_TABLE_CORRUPT", ++ "ERROR_WOF_FILE_RESOURCE_TABLE_CORRUPT", ++ "ERROR_VOLUME_NOT_SIS_ENABLED", ++ "ERROR_SYSTEM_INTEGRITY_ROLLBACK_DETECTED", ++ "ERROR_SYSTEM_INTEGRITY_POLICY_VIOLATION", ++ "ERROR_SYSTEM_INTEGRITY_INVALID_POLICY", ++ "ERROR_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED", ++ "ERROR_SYSTEM_INTEGRITY_TOO_MANY_POLICIES", ++ "ERROR_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED", ++ "ERROR_VSM_NOT_INITIALIZED", ++ "ERROR_VSM_DMA_PROTECTION_NOT_IN_USE", ++ "ERROR_PLATFORM_MANIFEST_NOT_AUTHORIZED", ++ "ERROR_PLATFORM_MANIFEST_INVALID", ++ "ERROR_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED", ++ "ERROR_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED", ++ "ERROR_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND", ++ "ERROR_PLATFORM_MANIFEST_NOT_ACTIVE", ++ "ERROR_PLATFORM_MANIFEST_NOT_SIGNED", ++ "ERROR_DEPENDENT_RESOURCE_EXISTS", ++ "ERROR_DEPENDENCY_NOT_FOUND", ++ "ERROR_DEPENDENCY_ALREADY_EXISTS", ++ "ERROR_RESOURCE_NOT_ONLINE", ++ "ERROR_HOST_NODE_NOT_AVAILABLE", ++ "ERROR_RESOURCE_NOT_AVAILABLE", ++ "ERROR_RESOURCE_NOT_FOUND", ++ "ERROR_SHUTDOWN_CLUSTER", ++ "ERROR_CANT_EVICT_ACTIVE_NODE", ++ "ERROR_OBJECT_ALREADY_EXISTS", ++ "ERROR_OBJECT_IN_LIST", ++ "ERROR_GROUP_NOT_AVAILABLE", ++ "ERROR_GROUP_NOT_FOUND", ++ "ERROR_GROUP_NOT_ONLINE", ++ "ERROR_HOST_NODE_NOT_RESOURCE_OWNER", ++ "ERROR_HOST_NODE_NOT_GROUP_OWNER", ++ "ERROR_RESMON_CREATE_FAILED", ++ "ERROR_RESMON_ONLINE_FAILED", ++ "ERROR_RESOURCE_ONLINE", ++ "ERROR_QUORUM_RESOURCE", ++ "ERROR_NOT_QUORUM_CAPABLE", ++ "ERROR_CLUSTER_SHUTTING_DOWN", ++ "ERROR_INVALID_STATE", ++ "ERROR_RESOURCE_PROPERTIES_STORED", ++ "ERROR_NOT_QUORUM_CLASS", ++ "ERROR_CORE_RESOURCE", ++ "ERROR_QUORUM_RESOURCE_ONLINE_FAILED", ++ "ERROR_QUORUMLOG_OPEN_FAILED", ++ "ERROR_CLUSTERLOG_CORRUPT", ++ "ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE", ++ "ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE", ++ "ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND", ++ "ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE", ++ "ERROR_QUORUM_OWNER_ALIVE", ++ "ERROR_NETWORK_NOT_AVAILABLE", ++ "ERROR_NODE_NOT_AVAILABLE", ++ "ERROR_ALL_NODES_NOT_AVAILABLE", ++ "ERROR_RESOURCE_FAILED", ++ "ERROR_CLUSTER_INVALID_NODE", ++ "ERROR_CLUSTER_NODE_EXISTS", ++ "ERROR_CLUSTER_JOIN_IN_PROGRESS", ++ "ERROR_CLUSTER_NODE_NOT_FOUND", ++ "ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND", ++ "ERROR_CLUSTER_NETWORK_EXISTS", ++ "ERROR_CLUSTER_NETWORK_NOT_FOUND", ++ "ERROR_CLUSTER_NETINTERFACE_EXISTS", ++ "ERROR_CLUSTER_NETINTERFACE_NOT_FOUND", ++ "ERROR_CLUSTER_INVALID_REQUEST", ++ "ERROR_CLUSTER_INVALID_NETWORK_PROVIDER", ++ "ERROR_CLUSTER_NODE_DOWN", ++ "ERROR_CLUSTER_NODE_UNREACHABLE", ++ "ERROR_CLUSTER_NODE_NOT_MEMBER", ++ "ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS", ++ "ERROR_CLUSTER_INVALID_NETWORK", ++ "ERROR_CLUSTER_NODE_UP", ++ "ERROR_CLUSTER_IPADDR_IN_USE", ++ "ERROR_CLUSTER_NODE_NOT_PAUSED", ++ "ERROR_CLUSTER_NO_SECURITY_CONTEXT", ++ "ERROR_CLUSTER_NETWORK_NOT_INTERNAL", ++ "ERROR_CLUSTER_NODE_ALREADY_UP", ++ "ERROR_CLUSTER_NODE_ALREADY_DOWN", ++ "ERROR_CLUSTER_NETWORK_ALREADY_ONLINE", ++ "ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE", ++ "ERROR_CLUSTER_NODE_ALREADY_MEMBER", ++ "ERROR_CLUSTER_LAST_INTERNAL_NETWORK", ++ "ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS", ++ "ERROR_INVALID_OPERATION_ON_QUORUM", ++ "ERROR_DEPENDENCY_NOT_ALLOWED", ++ "ERROR_CLUSTER_NODE_PAUSED", ++ "ERROR_NODE_CANT_HOST_RESOURCE", ++ "ERROR_CLUSTER_NODE_NOT_READY", ++ "ERROR_CLUSTER_NODE_SHUTTING_DOWN", ++ "ERROR_CLUSTER_JOIN_ABORTED", ++ "ERROR_CLUSTER_INCOMPATIBLE_VERSIONS", ++ "ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED", ++ "ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED", ++ "ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND", ++ "ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED", ++ "ERROR_CLUSTER_RESNAME_NOT_FOUND", ++ "ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED", ++ "ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST", ++ "ERROR_CLUSTER_DATABASE_SEQMISMATCH", ++ "ERROR_RESMON_INVALID_STATE", ++ "ERROR_CLUSTER_GUM_NOT_LOCKER", ++ "ERROR_QUORUM_DISK_NOT_FOUND", ++ "ERROR_DATABASE_BACKUP_CORRUPT", ++ "ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT", ++ "ERROR_RESOURCE_PROPERTY_UNCHANGEABLE", ++ "ERROR_NO_ADMIN_ACCESS_POINT", ++ "ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE", ++ "ERROR_CLUSTER_QUORUMLOG_NOT_FOUND", ++ "ERROR_CLUSTER_MEMBERSHIP_HALT", ++ "ERROR_CLUSTER_INSTANCE_ID_MISMATCH", ++ "ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP", ++ "ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH", ++ "ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP", ++ "ERROR_CLUSTER_PARAMETER_MISMATCH", ++ "ERROR_NODE_CANNOT_BE_CLUSTERED", ++ "ERROR_CLUSTER_WRONG_OS_VERSION", ++ "ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME", ++ "ERROR_CLUSCFG_ALREADY_COMMITTED", ++ "ERROR_CLUSCFG_ROLLBACK_FAILED", ++ "ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT", ++ "ERROR_CLUSTER_OLD_VERSION", ++ "ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME", ++ "ERROR_CLUSTER_NO_NET_ADAPTERS", ++ "ERROR_CLUSTER_POISONED", ++ "ERROR_CLUSTER_GROUP_MOVING", ++ "ERROR_CLUSTER_RESOURCE_TYPE_BUSY", ++ "ERROR_RESOURCE_CALL_TIMED_OUT", ++ "ERROR_INVALID_CLUSTER_IPV6_ADDRESS", ++ "ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION", ++ "ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS", ++ "ERROR_CLUSTER_PARTIAL_SEND", ++ "ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION", ++ "ERROR_CLUSTER_INVALID_STRING_TERMINATION", ++ "ERROR_CLUSTER_INVALID_STRING_FORMAT", ++ "ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS", ++ "ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS", ++ "ERROR_CLUSTER_NULL_DATA", ++ "ERROR_CLUSTER_PARTIAL_READ", ++ "ERROR_CLUSTER_PARTIAL_WRITE", ++ "ERROR_CLUSTER_CANT_DESERIALIZE_DATA", ++ "ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT", ++ "ERROR_CLUSTER_NO_QUORUM", ++ "ERROR_CLUSTER_INVALID_IPV6_NETWORK", ++ "ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK", ++ "ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP", ++ "ERROR_DEPENDENCY_TREE_TOO_COMPLEX", ++ "ERROR_EXCEPTION_IN_RESOURCE_CALL", ++ "ERROR_CLUSTER_RHS_FAILED_INITIALIZATION", ++ "ERROR_CLUSTER_NOT_INSTALLED", ++ "ERROR_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE", ++ "ERROR_CLUSTER_MAX_NODES_IN_CLUSTER", ++ "ERROR_CLUSTER_TOO_MANY_NODES", ++ "ERROR_CLUSTER_OBJECT_ALREADY_USED", ++ "ERROR_NONCORE_GROUPS_FOUND", ++ "ERROR_FILE_SHARE_RESOURCE_CONFLICT", ++ "ERROR_CLUSTER_EVICT_INVALID_REQUEST", ++ "ERROR_CLUSTER_SINGLETON_RESOURCE", ++ "ERROR_CLUSTER_GROUP_SINGLETON_RESOURCE", ++ "ERROR_CLUSTER_RESOURCE_PROVIDER_FAILED", ++ "ERROR_CLUSTER_RESOURCE_CONFIGURATION_ERROR", ++ "ERROR_CLUSTER_GROUP_BUSY", ++ "ERROR_CLUSTER_NOT_SHARED_VOLUME", ++ "ERROR_CLUSTER_INVALID_SECURITY_DESCRIPTOR", ++ "ERROR_CLUSTER_SHARED_VOLUMES_IN_USE", ++ "ERROR_CLUSTER_USE_SHARED_VOLUMES_API", ++ "ERROR_CLUSTER_BACKUP_IN_PROGRESS", ++ "ERROR_NON_CSV_PATH", ++ "ERROR_CSV_VOLUME_NOT_LOCAL", ++ "ERROR_CLUSTER_WATCHDOG_TERMINATING", ++ "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES", ++ "ERROR_CLUSTER_INVALID_NODE_WEIGHT", ++ "ERROR_CLUSTER_RESOURCE_VETOED_CALL", ++ "ERROR_RESMON_SYSTEM_RESOURCES_LACKING", ++ "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION", ++ "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE", ++ "ERROR_CLUSTER_GROUP_QUEUED", ++ "ERROR_CLUSTER_RESOURCE_LOCKED_STATUS", ++ "ERROR_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED", ++ "ERROR_CLUSTER_NODE_DRAIN_IN_PROGRESS", ++ "ERROR_CLUSTER_DISK_NOT_CONNECTED", ++ "ERROR_DISK_NOT_CSV_CAPABLE", ++ "ERROR_RESOURCE_NOT_IN_AVAILABLE_STORAGE", ++ "ERROR_CLUSTER_SHARED_VOLUME_REDIRECTED", ++ "ERROR_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED", ++ "ERROR_CLUSTER_CANNOT_RETURN_PROPERTIES", ++ "ERROR_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES", ++ "ERROR_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE", ++ "ERROR_CLUSTER_AFFINITY_CONFLICT", ++ "ERROR_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE", ++ "ERROR_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS", ++ "ERROR_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED", ++ "ERROR_CLUSTER_UPGRADE_RESTART_REQUIRED", ++ "ERROR_CLUSTER_UPGRADE_IN_PROGRESS", ++ "ERROR_CLUSTER_UPGRADE_INCOMPLETE", ++ "ERROR_CLUSTER_NODE_IN_GRACE_PERIOD", ++ "ERROR_CLUSTER_CSV_IO_PAUSE_TIMEOUT", ++ "ERROR_NODE_NOT_ACTIVE_CLUSTER_MEMBER", ++ "ERROR_CLUSTER_RESOURCE_NOT_MONITORED", ++ "ERROR_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED", ++ "ERROR_CLUSTER_RESOURCE_IS_REPLICATED", ++ "ERROR_CLUSTER_NODE_ISOLATED", ++ "ERROR_CLUSTER_NODE_QUARANTINED", ++ "ERROR_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED", ++ "ERROR_CLUSTER_SPACE_DEGRADED", ++ "ERROR_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED", ++ "ERROR_CLUSTER_CSV_INVALID_HANDLE", ++ "ERROR_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR", ++ "ERROR_GROUPSET_NOT_AVAILABLE", ++ "ERROR_GROUPSET_NOT_FOUND", ++ "ERROR_GROUPSET_CANT_PROVIDE", ++ "ERROR_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND", ++ "ERROR_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY", ++ "ERROR_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION", ++ "ERROR_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS", ++ "ERROR_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME", ++ "ERROR_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE", ++ "ERROR_ENCRYPTION_FAILED", ++ "ERROR_DECRYPTION_FAILED", ++ "ERROR_FILE_ENCRYPTED", ++ "ERROR_NO_RECOVERY_POLICY", ++ "ERROR_NO_EFS", ++ "ERROR_WRONG_EFS", ++ "ERROR_NO_USER_KEYS", ++ "ERROR_FILE_NOT_ENCRYPTED", ++ "ERROR_NOT_EXPORT_FORMAT", ++ "ERROR_FILE_READ_ONLY", ++ "ERROR_DIR_EFS_DISALLOWED", ++ "ERROR_EFS_SERVER_NOT_TRUSTED", ++ "ERROR_BAD_RECOVERY_POLICY", ++ "ERROR_EFS_ALG_BLOB_TOO_BIG", ++ "ERROR_VOLUME_NOT_SUPPORT_EFS", ++ "ERROR_EFS_DISABLED", ++ "ERROR_EFS_VERSION_NOT_SUPPORT", ++ "ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE", ++ "ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER", ++ "ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE", ++ "ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE", ++ "ERROR_CS_ENCRYPTION_FILE_NOT_CSE", ++ "ERROR_ENCRYPTION_POLICY_DENIES_OPERATION", ++ "ERROR_WIP_ENCRYPTION_FAILED", ++ "ERROR_NO_BROWSER_SERVERS_FOUND", ++ "ERROR_CLUSTER_OBJECT_IS_CLUSTER_SET_VM", ++ "ERROR_LOG_SECTOR_INVALID", ++ "ERROR_LOG_SECTOR_PARITY_INVALID", ++ "ERROR_LOG_SECTOR_REMAPPED", ++ "ERROR_LOG_BLOCK_INCOMPLETE", ++ "ERROR_LOG_INVALID_RANGE", ++ "ERROR_LOG_BLOCKS_EXHAUSTED", ++ "ERROR_LOG_READ_CONTEXT_INVALID", ++ "ERROR_LOG_RESTART_INVALID", ++ "ERROR_LOG_BLOCK_VERSION", ++ "ERROR_LOG_BLOCK_INVALID", ++ "ERROR_LOG_READ_MODE_INVALID", ++ "ERROR_LOG_NO_RESTART", ++ "ERROR_LOG_METADATA_CORRUPT", ++ "ERROR_LOG_METADATA_INVALID", ++ "ERROR_LOG_METADATA_INCONSISTENT", ++ "ERROR_LOG_RESERVATION_INVALID", ++ "ERROR_LOG_CANT_DELETE", ++ "ERROR_LOG_CONTAINER_LIMIT_EXCEEDED", ++ "ERROR_LOG_START_OF_LOG", ++ "ERROR_LOG_POLICY_ALREADY_INSTALLED", ++ "ERROR_LOG_POLICY_NOT_INSTALLED", ++ "ERROR_LOG_POLICY_INVALID", ++ "ERROR_LOG_POLICY_CONFLICT", ++ "ERROR_LOG_PINNED_ARCHIVE_TAIL", ++ "ERROR_LOG_RECORD_NONEXISTENT", ++ "ERROR_LOG_RECORDS_RESERVED_INVALID", ++ "ERROR_LOG_SPACE_RESERVED_INVALID", ++ "ERROR_LOG_TAIL_INVALID", ++ "ERROR_LOG_FULL", ++ "ERROR_COULD_NOT_RESIZE_LOG", ++ "ERROR_LOG_MULTIPLEXED", ++ "ERROR_LOG_DEDICATED", ++ "ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS", ++ "ERROR_LOG_ARCHIVE_IN_PROGRESS", ++ "ERROR_LOG_EPHEMERAL", ++ "ERROR_LOG_NOT_ENOUGH_CONTAINERS", ++ "ERROR_LOG_CLIENT_ALREADY_REGISTERED", ++ "ERROR_LOG_CLIENT_NOT_REGISTERED", ++ "ERROR_LOG_FULL_HANDLER_IN_PROGRESS", ++ "ERROR_LOG_CONTAINER_READ_FAILED", ++ "ERROR_LOG_CONTAINER_WRITE_FAILED", ++ "ERROR_LOG_CONTAINER_OPEN_FAILED", ++ "ERROR_LOG_CONTAINER_STATE_INVALID", ++ "ERROR_LOG_STATE_INVALID", ++ "ERROR_LOG_PINNED", ++ "ERROR_LOG_METADATA_FLUSH_FAILED", ++ "ERROR_LOG_INCONSISTENT_SECURITY", ++ "ERROR_LOG_APPENDED_FLUSH_FAILED", ++ "ERROR_LOG_PINNED_RESERVATION", ++ "ERROR_INVALID_TRANSACTION", ++ "ERROR_TRANSACTION_NOT_ACTIVE", ++ "ERROR_TRANSACTION_REQUEST_NOT_VALID", ++ "ERROR_TRANSACTION_NOT_REQUESTED", ++ "ERROR_TRANSACTION_ALREADY_ABORTED", ++ "ERROR_TRANSACTION_ALREADY_COMMITTED", ++ "ERROR_TM_INITIALIZATION_FAILED", ++ "ERROR_RESOURCEMANAGER_READ_ONLY", ++ "ERROR_TRANSACTION_NOT_JOINED", ++ "ERROR_TRANSACTION_SUPERIOR_EXISTS", ++ "ERROR_CRM_PROTOCOL_ALREADY_EXISTS", ++ "ERROR_TRANSACTION_PROPAGATION_FAILED", ++ "ERROR_CRM_PROTOCOL_NOT_FOUND", ++ "ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER", ++ "ERROR_CURRENT_TRANSACTION_NOT_VALID", ++ "ERROR_TRANSACTION_NOT_FOUND", ++ "ERROR_RESOURCEMANAGER_NOT_FOUND", ++ "ERROR_ENLISTMENT_NOT_FOUND", ++ "ERROR_TRANSACTIONMANAGER_NOT_FOUND", ++ "ERROR_TRANSACTIONMANAGER_NOT_ONLINE", ++ "ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION", ++ "ERROR_TRANSACTION_NOT_ROOT", ++ "ERROR_TRANSACTION_OBJECT_EXPIRED", ++ "ERROR_TRANSACTION_RESPONSE_NOT_ENLISTED", ++ "ERROR_TRANSACTION_RECORD_TOO_LONG", ++ "ERROR_IMPLICIT_TRANSACTION_NOT_SUPPORTED", ++ "ERROR_TRANSACTION_INTEGRITY_VIOLATED", ++ "ERROR_TRANSACTIONMANAGER_IDENTITY_MISMATCH", ++ "ERROR_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT", ++ "ERROR_TRANSACTION_MUST_WRITETHROUGH", ++ "ERROR_TRANSACTION_NO_SUPERIOR", ++ "ERROR_HEURISTIC_DAMAGE_POSSIBLE", ++ "ERROR_TRANSACTIONAL_CONFLICT", ++ "ERROR_RM_NOT_ACTIVE", ++ "ERROR_RM_METADATA_CORRUPT", ++ "ERROR_DIRECTORY_NOT_RM", ++ "ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE", ++ "ERROR_LOG_RESIZE_INVALID_SIZE", ++ "ERROR_OBJECT_NO_LONGER_EXISTS", ++ "ERROR_STREAM_MINIVERSION_NOT_FOUND", ++ "ERROR_STREAM_MINIVERSION_NOT_VALID", ++ "ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION", ++ "ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT", ++ "ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS", ++ "ERROR_REMOTE_FILE_VERSION_MISMATCH", ++ "ERROR_HANDLE_NO_LONGER_VALID", ++ "ERROR_NO_TXF_METADATA", ++ "ERROR_LOG_CORRUPTION_DETECTED", ++ "ERROR_CANT_RECOVER_WITH_HANDLE_OPEN", ++ "ERROR_RM_DISCONNECTED", ++ "ERROR_ENLISTMENT_NOT_SUPERIOR", ++ "ERROR_RECOVERY_NOT_NEEDED", ++ "ERROR_RM_ALREADY_STARTED", ++ "ERROR_FILE_IDENTITY_NOT_PERSISTENT", ++ "ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY", ++ "ERROR_CANT_CROSS_RM_BOUNDARY", ++ "ERROR_TXF_DIR_NOT_EMPTY", ++ "ERROR_INDOUBT_TRANSACTIONS_EXIST", ++ "ERROR_TM_VOLATILE", ++ "ERROR_ROLLBACK_TIMER_EXPIRED", ++ "ERROR_TXF_ATTRIBUTE_CORRUPT", ++ "ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION", ++ "ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED", ++ "ERROR_LOG_GROWTH_FAILED", ++ "ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE", ++ "ERROR_TXF_METADATA_ALREADY_PRESENT", ++ "ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET", ++ "ERROR_TRANSACTION_REQUIRED_PROMOTION", ++ "ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION", ++ "ERROR_TRANSACTIONS_NOT_FROZEN", ++ "ERROR_TRANSACTION_FREEZE_IN_PROGRESS", ++ "ERROR_NOT_SNAPSHOT_VOLUME", ++ "ERROR_NO_SAVEPOINT_WITH_OPEN_FILES", ++ "ERROR_DATA_LOST_REPAIR", ++ "ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION", ++ "ERROR_TM_IDENTITY_MISMATCH", ++ "ERROR_FLOATED_SECTION", ++ "ERROR_CANNOT_ACCEPT_TRANSACTED_WORK", ++ "ERROR_CANNOT_ABORT_TRANSACTIONS", ++ "ERROR_BAD_CLUSTERS", ++ "ERROR_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION", ++ "ERROR_VOLUME_DIRTY", ++ "ERROR_NO_LINK_TRACKING_IN_TRANSACTION", ++ "ERROR_OPERATION_NOT_SUPPORTED_IN_TRANSACTION", ++ "ERROR_EXPIRED_HANDLE", ++ "ERROR_TRANSACTION_NOT_ENLISTED", ++ "ERROR_CTX_WINSTATION_NAME_INVALID", ++ "ERROR_CTX_INVALID_PD", ++ "ERROR_CTX_PD_NOT_FOUND", ++ "ERROR_CTX_WD_NOT_FOUND", ++ "ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY", ++ "ERROR_CTX_SERVICE_NAME_COLLISION", ++ "ERROR_CTX_CLOSE_PENDING", ++ "ERROR_CTX_NO_OUTBUF", ++ "ERROR_CTX_MODEM_INF_NOT_FOUND", ++ "ERROR_CTX_INVALID_MODEMNAME", ++ "ERROR_CTX_MODEM_RESPONSE_ERROR", ++ "ERROR_CTX_MODEM_RESPONSE_TIMEOUT", ++ "ERROR_CTX_MODEM_RESPONSE_NO_CARRIER", ++ "ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE", ++ "ERROR_CTX_MODEM_RESPONSE_BUSY", ++ "ERROR_CTX_MODEM_RESPONSE_VOICE", ++ "ERROR_CTX_TD_ERROR", ++ "ERROR_CTX_WINSTATION_NOT_FOUND", ++ "ERROR_CTX_WINSTATION_ALREADY_EXISTS", ++ "ERROR_CTX_WINSTATION_BUSY", ++ "ERROR_CTX_BAD_VIDEO_MODE", ++ "ERROR_CTX_GRAPHICS_INVALID", ++ "ERROR_CTX_LOGON_DISABLED", ++ "ERROR_CTX_NOT_CONSOLE", ++ "ERROR_CTX_CLIENT_QUERY_TIMEOUT", ++ "ERROR_CTX_CONSOLE_DISCONNECT", ++ "ERROR_CTX_CONSOLE_CONNECT", ++ "ERROR_CTX_SHADOW_DENIED", ++ "ERROR_CTX_WINSTATION_ACCESS_DENIED", ++ "ERROR_CTX_INVALID_WD", ++ "ERROR_CTX_SHADOW_INVALID", ++ "ERROR_CTX_SHADOW_DISABLED", ++ "ERROR_CTX_CLIENT_LICENSE_IN_USE", ++ "ERROR_CTX_CLIENT_LICENSE_NOT_SET", ++ "ERROR_CTX_LICENSE_NOT_AVAILABLE", ++ "ERROR_CTX_LICENSE_CLIENT_INVALID", ++ "ERROR_CTX_LICENSE_EXPIRED", ++ "ERROR_CTX_SHADOW_NOT_RUNNING", ++ "ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE", ++ "ERROR_ACTIVATION_COUNT_EXCEEDED", ++ "ERROR_CTX_WINSTATIONS_DISABLED", ++ "ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED", ++ "ERROR_CTX_SESSION_IN_USE", ++ "ERROR_CTX_NO_FORCE_LOGOFF", ++ "ERROR_CTX_ACCOUNT_RESTRICTION", ++ "ERROR_RDP_PROTOCOL_ERROR", ++ "ERROR_CTX_CDM_CONNECT", ++ "ERROR_CTX_CDM_DISCONNECT", ++ "ERROR_CTX_SECURITY_LAYER_ERROR", ++ "ERROR_TS_INCOMPATIBLE_SESSIONS", ++ "ERROR_TS_VIDEO_SUBSYSTEM_ERROR", ++ "ERROR_DS_NOT_INSTALLED", ++ "ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY", ++ "ERROR_DS_NO_ATTRIBUTE_OR_VALUE", ++ "ERROR_DS_INVALID_ATTRIBUTE_SYNTAX", ++ "ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED", ++ "ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS", ++ "ERROR_DS_BUSY", ++ "ERROR_DS_UNAVAILABLE", ++ "ERROR_DS_NO_RIDS_ALLOCATED", ++ "ERROR_DS_NO_MORE_RIDS", ++ "ERROR_DS_INCORRECT_ROLE_OWNER", ++ "ERROR_DS_RIDMGR_INIT_ERROR", ++ "ERROR_DS_OBJ_CLASS_VIOLATION", ++ "ERROR_DS_CANT_ON_NON_LEAF", ++ "ERROR_DS_CANT_ON_RDN", ++ "ERROR_DS_CANT_MOD_OBJ_CLASS", ++ "ERROR_DS_CROSS_DOM_MOVE_ERROR", ++ "ERROR_DS_GC_NOT_AVAILABLE", ++ "ERROR_SHARED_POLICY", ++ "ERROR_POLICY_OBJECT_NOT_FOUND", ++ "ERROR_POLICY_ONLY_IN_DS", ++ "ERROR_PROMOTION_ACTIVE", ++ "ERROR_NO_PROMOTION_ACTIVE", ++ "ERROR_DS_OPERATIONS_ERROR", ++ "ERROR_DS_PROTOCOL_ERROR", ++ "ERROR_DS_TIMELIMIT_EXCEEDED", ++ "ERROR_DS_SIZELIMIT_EXCEEDED", ++ "ERROR_DS_ADMIN_LIMIT_EXCEEDED", ++ "ERROR_DS_COMPARE_FALSE", ++ "ERROR_DS_COMPARE_TRUE", ++ "ERROR_DS_AUTH_METHOD_NOT_SUPPORTED", ++ "ERROR_DS_STRONG_AUTH_REQUIRED", ++ "ERROR_DS_INAPPROPRIATE_AUTH", ++ "ERROR_DS_AUTH_UNKNOWN", ++ "ERROR_DS_REFERRAL", ++ "ERROR_DS_UNAVAILABLE_CRIT_EXTENSION", ++ "ERROR_DS_CONFIDENTIALITY_REQUIRED", ++ "ERROR_DS_INAPPROPRIATE_MATCHING", ++ "ERROR_DS_CONSTRAINT_VIOLATION", ++ "ERROR_DS_NO_SUCH_OBJECT", ++ "ERROR_DS_ALIAS_PROBLEM", ++ "ERROR_DS_INVALID_DN_SYNTAX", ++ "ERROR_DS_IS_LEAF", ++ "ERROR_DS_ALIAS_DEREF_PROBLEM", ++ "ERROR_DS_UNWILLING_TO_PERFORM", ++ "ERROR_DS_LOOP_DETECT", ++ "ERROR_DS_NAMING_VIOLATION", ++ "ERROR_DS_OBJECT_RESULTS_TOO_LARGE", ++ "ERROR_DS_AFFECTS_MULTIPLE_DSAS", ++ "ERROR_DS_SERVER_DOWN", ++ "ERROR_DS_LOCAL_ERROR", ++ "ERROR_DS_ENCODING_ERROR", ++ "ERROR_DS_DECODING_ERROR", ++ "ERROR_DS_FILTER_UNKNOWN", ++ "ERROR_DS_PARAM_ERROR", ++ "ERROR_DS_NOT_SUPPORTED", ++ "ERROR_DS_NO_RESULTS_RETURNED", ++ "ERROR_DS_CONTROL_NOT_FOUND", ++ "ERROR_DS_CLIENT_LOOP", ++ "ERROR_DS_REFERRAL_LIMIT_EXCEEDED", ++ "ERROR_DS_SORT_CONTROL_MISSING", ++ "ERROR_DS_OFFSET_RANGE_ERROR", ++ "ERROR_DS_RIDMGR_DISABLED", ++ "ERROR_DS_ROOT_MUST_BE_NC", ++ "ERROR_DS_ADD_REPLICA_INHIBITED", ++ "ERROR_DS_ATT_NOT_DEF_IN_SCHEMA", ++ "ERROR_DS_MAX_OBJ_SIZE_EXCEEDED", ++ "ERROR_DS_OBJ_STRING_NAME_EXISTS", ++ "ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA", ++ "ERROR_DS_RDN_DOESNT_MATCH_SCHEMA", ++ "ERROR_DS_NO_REQUESTED_ATTS_FOUND", ++ "ERROR_DS_USER_BUFFER_TO_SMALL", ++ "ERROR_DS_ATT_IS_NOT_ON_OBJ", ++ "ERROR_DS_ILLEGAL_MOD_OPERATION", ++ "ERROR_DS_OBJ_TOO_LARGE", ++ "ERROR_DS_BAD_INSTANCE_TYPE", ++ "ERROR_DS_MASTERDSA_REQUIRED", ++ "ERROR_DS_OBJECT_CLASS_REQUIRED", ++ "ERROR_DS_MISSING_REQUIRED_ATT", ++ "ERROR_DS_ATT_NOT_DEF_FOR_CLASS", ++ "ERROR_DS_ATT_ALREADY_EXISTS", ++ "ERROR_DS_CANT_ADD_ATT_VALUES", ++ "ERROR_DS_SINGLE_VALUE_CONSTRAINT", ++ "ERROR_DS_RANGE_CONSTRAINT", ++ "ERROR_DS_ATT_VAL_ALREADY_EXISTS", ++ "ERROR_DS_CANT_REM_MISSING_ATT", ++ "ERROR_DS_CANT_REM_MISSING_ATT_VAL", ++ "ERROR_DS_ROOT_CANT_BE_SUBREF", ++ "ERROR_DS_NO_CHAINING", ++ "ERROR_DS_NO_CHAINED_EVAL", ++ "ERROR_DS_NO_PARENT_OBJECT", ++ "ERROR_DS_PARENT_IS_AN_ALIAS", ++ "ERROR_DS_CANT_MIX_MASTER_AND_REPS", ++ "ERROR_DS_CHILDREN_EXIST", ++ "ERROR_DS_OBJ_NOT_FOUND", ++ "ERROR_DS_ALIASED_OBJ_MISSING", ++ "ERROR_DS_BAD_NAME_SYNTAX", ++ "ERROR_DS_ALIAS_POINTS_TO_ALIAS", ++ "ERROR_DS_CANT_DEREF_ALIAS", ++ "ERROR_DS_OUT_OF_SCOPE", ++ "ERROR_DS_OBJECT_BEING_REMOVED", ++ "ERROR_DS_CANT_DELETE_DSA_OBJ", ++ "ERROR_DS_GENERIC_ERROR", ++ "ERROR_DS_DSA_MUST_BE_INT_MASTER", ++ "ERROR_DS_CLASS_NOT_DSA", ++ "ERROR_DS_INSUFF_ACCESS_RIGHTS", ++ "ERROR_DS_ILLEGAL_SUPERIOR", ++ "ERROR_DS_ATTRIBUTE_OWNED_BY_SAM", ++ "ERROR_DS_NAME_TOO_MANY_PARTS", ++ "ERROR_DS_NAME_TOO_LONG", ++ "ERROR_DS_NAME_VALUE_TOO_LONG", ++ "ERROR_DS_NAME_UNPARSEABLE", ++ "ERROR_DS_NAME_TYPE_UNKNOWN", ++ "ERROR_DS_NOT_AN_OBJECT", ++ "ERROR_DS_SEC_DESC_TOO_SHORT", ++ "ERROR_DS_SEC_DESC_INVALID", ++ "ERROR_DS_NO_DELETED_NAME", ++ "ERROR_DS_SUBREF_MUST_HAVE_PARENT", ++ "ERROR_DS_NCNAME_MUST_BE_NC", ++ "ERROR_DS_CANT_ADD_SYSTEM_ONLY", ++ "ERROR_DS_CLASS_MUST_BE_CONCRETE", ++ "ERROR_DS_INVALID_DMD", ++ "ERROR_DS_OBJ_GUID_EXISTS", ++ "ERROR_DS_NOT_ON_BACKLINK", ++ "ERROR_DS_NO_CROSSREF_FOR_NC", ++ "ERROR_DS_SHUTTING_DOWN", ++ "ERROR_DS_UNKNOWN_OPERATION", ++ "ERROR_DS_INVALID_ROLE_OWNER", ++ "ERROR_DS_COULDNT_CONTACT_FSMO", ++ "ERROR_DS_CROSS_NC_DN_RENAME", ++ "ERROR_DS_CANT_MOD_SYSTEM_ONLY", ++ "ERROR_DS_REPLICATOR_ONLY", ++ "ERROR_DS_OBJ_CLASS_NOT_DEFINED", ++ "ERROR_DS_OBJ_CLASS_NOT_SUBCLASS", ++ "ERROR_DS_NAME_REFERENCE_INVALID", ++ "ERROR_DS_CROSS_REF_EXISTS", ++ "ERROR_DS_CANT_DEL_MASTER_CROSSREF", ++ "ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD", ++ "ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX", ++ "ERROR_DS_DUP_RDN", ++ "ERROR_DS_DUP_OID", ++ "ERROR_DS_DUP_MAPI_ID", ++ "ERROR_DS_DUP_SCHEMA_ID_GUID", ++ "ERROR_DS_DUP_LDAP_DISPLAY_NAME", ++ "ERROR_DS_SEMANTIC_ATT_TEST", ++ "ERROR_DS_SYNTAX_MISMATCH", ++ "ERROR_DS_EXISTS_IN_MUST_HAVE", ++ "ERROR_DS_EXISTS_IN_MAY_HAVE", ++ "ERROR_DS_NONEXISTENT_MAY_HAVE", ++ "ERROR_DS_NONEXISTENT_MUST_HAVE", ++ "ERROR_DS_AUX_CLS_TEST_FAIL", ++ "ERROR_DS_NONEXISTENT_POSS_SUP", ++ "ERROR_DS_SUB_CLS_TEST_FAIL", ++ "ERROR_DS_BAD_RDN_ATT_ID_SYNTAX", ++ "ERROR_DS_EXISTS_IN_AUX_CLS", ++ "ERROR_DS_EXISTS_IN_SUB_CLS", ++ "ERROR_DS_EXISTS_IN_POSS_SUP", ++ "ERROR_DS_RECALCSCHEMA_FAILED", ++ "ERROR_DS_TREE_DELETE_NOT_FINISHED", ++ "ERROR_DS_CANT_DELETE", ++ "ERROR_DS_ATT_SCHEMA_REQ_ID", ++ "ERROR_DS_BAD_ATT_SCHEMA_SYNTAX", ++ "ERROR_DS_CANT_CACHE_ATT", ++ "ERROR_DS_CANT_CACHE_CLASS", ++ "ERROR_DS_CANT_REMOVE_ATT_CACHE", ++ "ERROR_DS_CANT_REMOVE_CLASS_CACHE", ++ "ERROR_DS_CANT_RETRIEVE_DN", ++ "ERROR_DS_MISSING_SUPREF", ++ "ERROR_DS_CANT_RETRIEVE_INSTANCE", ++ "ERROR_DS_CODE_INCONSISTENCY", ++ "ERROR_DS_DATABASE_ERROR", ++ "ERROR_DS_GOVERNSID_MISSING", ++ "ERROR_DS_MISSING_EXPECTED_ATT", ++ "ERROR_DS_NCNAME_MISSING_CR_REF", ++ "ERROR_DS_SECURITY_CHECKING_ERROR", ++ "ERROR_DS_SCHEMA_NOT_LOADED", ++ "ERROR_DS_SCHEMA_ALLOC_FAILED", ++ "ERROR_DS_ATT_SCHEMA_REQ_SYNTAX", ++ "ERROR_DS_GCVERIFY_ERROR", ++ "ERROR_DS_DRA_SCHEMA_MISMATCH", ++ "ERROR_DS_CANT_FIND_DSA_OBJ", ++ "ERROR_DS_CANT_FIND_EXPECTED_NC", ++ "ERROR_DS_CANT_FIND_NC_IN_CACHE", ++ "ERROR_DS_CANT_RETRIEVE_CHILD", ++ "ERROR_DS_SECURITY_ILLEGAL_MODIFY", ++ "ERROR_DS_CANT_REPLACE_HIDDEN_REC", ++ "ERROR_DS_BAD_HIERARCHY_FILE", ++ "ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED", ++ "ERROR_DS_CONFIG_PARAM_MISSING", ++ "ERROR_DS_COUNTING_AB_INDICES_FAILED", ++ "ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED", ++ "ERROR_DS_INTERNAL_FAILURE", ++ "ERROR_DS_UNKNOWN_ERROR", ++ "ERROR_DS_ROOT_REQUIRES_CLASS_TOP", ++ "ERROR_DS_REFUSING_FSMO_ROLES", ++ "ERROR_DS_MISSING_FSMO_SETTINGS", ++ "ERROR_DS_UNABLE_TO_SURRENDER_ROLES", ++ "ERROR_DS_DRA_GENERIC", ++ "ERROR_DS_DRA_INVALID_PARAMETER", ++ "ERROR_DS_DRA_BUSY", ++ "ERROR_DS_DRA_BAD_DN", ++ "ERROR_DS_DRA_BAD_NC", ++ "ERROR_DS_DRA_DN_EXISTS", ++ "ERROR_DS_DRA_INTERNAL_ERROR", ++ "ERROR_DS_DRA_INCONSISTENT_DIT", ++ "ERROR_DS_DRA_CONNECTION_FAILED", ++ "ERROR_DS_DRA_BAD_INSTANCE_TYPE", ++ "ERROR_DS_DRA_OUT_OF_MEM", ++ "ERROR_DS_DRA_MAIL_PROBLEM", ++ "ERROR_DS_DRA_REF_ALREADY_EXISTS", ++ "ERROR_DS_DRA_REF_NOT_FOUND", ++ "ERROR_DS_DRA_OBJ_IS_REP_SOURCE", ++ "ERROR_DS_DRA_DB_ERROR", ++ "ERROR_DS_DRA_NO_REPLICA", ++ "ERROR_DS_DRA_ACCESS_DENIED", ++ "ERROR_DS_DRA_NOT_SUPPORTED", ++ "ERROR_DS_DRA_RPC_CANCELLED", ++ "ERROR_DS_DRA_SOURCE_DISABLED", ++ "ERROR_DS_DRA_SINK_DISABLED", ++ "ERROR_DS_DRA_NAME_COLLISION", ++ "ERROR_DS_DRA_SOURCE_REINSTALLED", ++ "ERROR_DS_DRA_MISSING_PARENT", ++ "ERROR_DS_DRA_PREEMPTED", ++ "ERROR_DS_DRA_ABANDON_SYNC", ++ "ERROR_DS_DRA_SHUTDOWN", ++ "ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET", ++ "ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA", ++ "ERROR_DS_DRA_EXTN_CONNECTION_FAILED", ++ "ERROR_DS_INSTALL_SCHEMA_MISMATCH", ++ "ERROR_DS_DUP_LINK_ID", ++ "ERROR_DS_NAME_ERROR_RESOLVING", ++ "ERROR_DS_NAME_ERROR_NOT_FOUND", ++ "ERROR_DS_NAME_ERROR_NOT_UNIQUE", ++ "ERROR_DS_NAME_ERROR_NO_MAPPING", ++ "ERROR_DS_NAME_ERROR_DOMAIN_ONLY", ++ "ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING", ++ "ERROR_DS_CONSTRUCTED_ATT_MOD", ++ "ERROR_DS_WRONG_OM_OBJ_CLASS", ++ "ERROR_DS_DRA_REPL_PENDING", ++ "ERROR_DS_DS_REQUIRED", ++ "ERROR_DS_INVALID_LDAP_DISPLAY_NAME", ++ "ERROR_DS_NON_BASE_SEARCH", ++ "ERROR_DS_CANT_RETRIEVE_ATTS", ++ "ERROR_DS_BACKLINK_WITHOUT_LINK", ++ "ERROR_DS_EPOCH_MISMATCH", ++ "ERROR_DS_SRC_NAME_MISMATCH", ++ "ERROR_DS_SRC_AND_DST_NC_IDENTICAL", ++ "ERROR_DS_DST_NC_MISMATCH", ++ "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC", ++ "ERROR_DS_SRC_GUID_MISMATCH", ++ "ERROR_DS_CANT_MOVE_DELETED_OBJECT", ++ "ERROR_DS_PDC_OPERATION_IN_PROGRESS", ++ "ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD", ++ "ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION", ++ "ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS", ++ "ERROR_DS_NC_MUST_HAVE_NC_PARENT", ++ "ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE", ++ "ERROR_DS_DST_DOMAIN_NOT_NATIVE", ++ "ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER", ++ "ERROR_DS_CANT_MOVE_ACCOUNT_GROUP", ++ "ERROR_DS_CANT_MOVE_RESOURCE_GROUP", ++ "ERROR_DS_INVALID_SEARCH_FLAG", ++ "ERROR_DS_NO_TREE_DELETE_ABOVE_NC", ++ "ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE", ++ "ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE", ++ "ERROR_DS_SAM_INIT_FAILURE", ++ "ERROR_DS_SENSITIVE_GROUP_VIOLATION", ++ "ERROR_DS_CANT_MOD_PRIMARYGROUPID", ++ "ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD", ++ "ERROR_DS_NONSAFE_SCHEMA_CHANGE", ++ "ERROR_DS_SCHEMA_UPDATE_DISALLOWED", ++ "ERROR_DS_CANT_CREATE_UNDER_SCHEMA", ++ "ERROR_DS_INSTALL_NO_SRC_SCH_VERSION", ++ "ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE", ++ "ERROR_DS_INVALID_GROUP_TYPE", ++ "ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN", ++ "ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN", ++ "ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER", ++ "ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER", ++ "ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER", ++ "ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER", ++ "ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER", ++ "ERROR_DS_HAVE_PRIMARY_MEMBERS", ++ "ERROR_DS_STRING_SD_CONVERSION_FAILED", ++ "ERROR_DS_NAMING_MASTER_GC", ++ "ERROR_DS_DNS_LOOKUP_FAILURE", ++ "ERROR_DS_COULDNT_UPDATE_SPNS", ++ "ERROR_DS_CANT_RETRIEVE_SD", ++ "ERROR_DS_KEY_NOT_UNIQUE", ++ "ERROR_DS_WRONG_LINKED_ATT_SYNTAX", ++ "ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD", ++ "ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY", ++ "ERROR_DS_CANT_START", ++ "ERROR_DS_INIT_FAILURE", ++ "ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION", ++ "ERROR_DS_SOURCE_DOMAIN_IN_FOREST", ++ "ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST", ++ "ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED", ++ "ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN", ++ "ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER", ++ "ERROR_DS_SRC_SID_EXISTS_IN_FOREST", ++ "ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH", ++ "ERROR_SAM_INIT_FAILURE", ++ "ERROR_DS_DRA_SCHEMA_INFO_SHIP", ++ "ERROR_DS_DRA_SCHEMA_CONFLICT", ++ "ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT", ++ "ERROR_DS_DRA_OBJ_NC_MISMATCH", ++ "ERROR_DS_NC_STILL_HAS_DSAS", ++ "ERROR_DS_GC_REQUIRED", ++ "ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY", ++ "ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS", ++ "ERROR_DS_CANT_ADD_TO_GC", ++ "ERROR_DS_NO_CHECKPOINT_WITH_PDC", ++ "ERROR_DS_SOURCE_AUDITING_NOT_ENABLED", ++ "ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC", ++ "ERROR_DS_INVALID_NAME_FOR_SPN", ++ "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS", ++ "ERROR_DS_UNICODEPWD_NOT_IN_QUOTES", ++ "ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED", ++ "ERROR_DS_MUST_BE_RUN_ON_DST_DC", ++ "ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER", ++ "ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ", ++ "ERROR_DS_INIT_FAILURE_CONSOLE", ++ "ERROR_DS_SAM_INIT_FAILURE_CONSOLE", ++ "ERROR_DS_FOREST_VERSION_TOO_HIGH", ++ "ERROR_DS_DOMAIN_VERSION_TOO_HIGH", ++ "ERROR_DS_FOREST_VERSION_TOO_LOW", ++ "ERROR_DS_DOMAIN_VERSION_TOO_LOW", ++ "ERROR_DS_INCOMPATIBLE_VERSION", ++ "ERROR_DS_LOW_DSA_VERSION", ++ "ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN", ++ "ERROR_DS_NOT_SUPPORTED_SORT_ORDER", ++ "ERROR_DS_NAME_NOT_UNIQUE", ++ "ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4", ++ "ERROR_DS_OUT_OF_VERSION_STORE", ++ "ERROR_DS_INCOMPATIBLE_CONTROLS_USED", ++ "ERROR_DS_NO_REF_DOMAIN", ++ "ERROR_DS_RESERVED_LINK_ID", ++ "ERROR_DS_LINK_ID_NOT_AVAILABLE", ++ "ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER", ++ "ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE", ++ "ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC", ++ "ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG", ++ "ERROR_DS_MODIFYDN_WRONG_GRANDPARENT", ++ "ERROR_DS_NAME_ERROR_TRUST_REFERRAL", ++ "ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER", ++ "ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD", ++ "ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2", ++ "ERROR_DS_THREAD_LIMIT_EXCEEDED", ++ "ERROR_DS_NOT_CLOSEST", ++ "ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF", ++ "ERROR_DS_SINGLE_USER_MODE_FAILED", ++ "ERROR_DS_NTDSCRIPT_SYNTAX_ERROR", ++ "ERROR_DS_NTDSCRIPT_PROCESS_ERROR", ++ "ERROR_DS_DIFFERENT_REPL_EPOCHS", ++ "ERROR_DS_DRS_EXTENSIONS_CHANGED", ++ "ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR", ++ "ERROR_DS_NO_MSDS_INTID", ++ "ERROR_DS_DUP_MSDS_INTID", ++ "ERROR_DS_EXISTS_IN_RDNATTID", ++ "ERROR_DS_AUTHORIZATION_FAILED", ++ "ERROR_DS_INVALID_SCRIPT", ++ "ERROR_DS_REMOTE_CROSSREF_OP_FAILED", ++ "ERROR_DS_CROSS_REF_BUSY", ++ "ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN", ++ "ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC", ++ "ERROR_DS_DUPLICATE_ID_FOUND", ++ "ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT", ++ "ERROR_DS_GROUP_CONVERSION_ERROR", ++ "ERROR_DS_CANT_MOVE_APP_BASIC_GROUP", ++ "ERROR_DS_CANT_MOVE_APP_QUERY_GROUP", ++ "ERROR_DS_ROLE_NOT_VERIFIED", ++ "ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL", ++ "ERROR_DS_DOMAIN_RENAME_IN_PROGRESS", ++ "ERROR_DS_EXISTING_AD_CHILD_NC", ++ "ERROR_DS_REPL_LIFETIME_EXCEEDED", ++ "ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER", ++ "ERROR_DS_LDAP_SEND_QUEUE_FULL", ++ "ERROR_DS_DRA_OUT_SCHEDULE_WINDOW", ++ "ERROR_DS_POLICY_NOT_KNOWN", ++ "ERROR_NO_SITE_SETTINGS_OBJECT", ++ "ERROR_NO_SECRETS", ++ "ERROR_NO_WRITABLE_DC_FOUND", ++ "ERROR_DS_NO_SERVER_OBJECT", ++ "ERROR_DS_NO_NTDSA_OBJECT", ++ "ERROR_DS_NON_ASQ_SEARCH", ++ "ERROR_DS_AUDIT_FAILURE", ++ "ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE", ++ "ERROR_DS_INVALID_SEARCH_FLAG_TUPLE", ++ "ERROR_DS_HIERARCHY_TABLE_TOO_DEEP", ++ "ERROR_DS_DRA_CORRUPT_UTD_VECTOR", ++ "ERROR_DS_DRA_SECRETS_DENIED", ++ "ERROR_DS_RESERVED_MAPI_ID", ++ "ERROR_DS_MAPI_ID_NOT_AVAILABLE", ++ "ERROR_DS_DRA_MISSING_KRBTGT_SECRET", ++ "ERROR_DS_DOMAIN_NAME_EXISTS_IN_FOREST", ++ "ERROR_DS_FLAT_NAME_EXISTS_IN_FOREST", ++ "ERROR_INVALID_USER_PRINCIPAL_NAME", ++ "ERROR_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS", ++ "ERROR_DS_OID_NOT_FOUND", ++ "ERROR_DS_DRA_RECYCLED_TARGET", ++ "ERROR_DS_DISALLOWED_NC_REDIRECT", ++ "ERROR_DS_HIGH_ADLDS_FFL", ++ "ERROR_DS_HIGH_DSA_VERSION", ++ "ERROR_DS_LOW_ADLDS_FFL", ++ "ERROR_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION", ++ "ERROR_DS_UNDELETE_SAM_VALIDATION_FAILED", ++ "ERROR_INCORRECT_ACCOUNT_TYPE", ++ "ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST", ++ "ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST", ++ "ERROR_DS_MISSING_FOREST_TRUST", ++ "ERROR_DS_VALUE_KEY_NOT_UNIQUE", ++ "ERROR_IPSEC_QM_POLICY_EXISTS", ++ "ERROR_IPSEC_QM_POLICY_NOT_FOUND", ++ "ERROR_IPSEC_QM_POLICY_IN_USE", ++ "ERROR_IPSEC_MM_POLICY_EXISTS", ++ "ERROR_IPSEC_MM_POLICY_NOT_FOUND", ++ "ERROR_IPSEC_MM_POLICY_IN_USE", ++ "ERROR_IPSEC_MM_FILTER_EXISTS", ++ "ERROR_IPSEC_MM_FILTER_NOT_FOUND", ++ "ERROR_IPSEC_TRANSPORT_FILTER_EXISTS", ++ "ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND", ++ "ERROR_IPSEC_MM_AUTH_EXISTS", ++ "ERROR_IPSEC_MM_AUTH_NOT_FOUND", ++ "ERROR_IPSEC_MM_AUTH_IN_USE", ++ "ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND", ++ "ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND", ++ "ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND", ++ "ERROR_IPSEC_TUNNEL_FILTER_EXISTS", ++ "ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND", ++ "ERROR_IPSEC_MM_FILTER_PENDING_DELETION", ++ "ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION", ++ "ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION", ++ "ERROR_IPSEC_MM_POLICY_PENDING_DELETION", ++ "ERROR_IPSEC_MM_AUTH_PENDING_DELETION", ++ "ERROR_IPSEC_QM_POLICY_PENDING_DELETION", ++ "ERROR_IPSEC_IKE_NEG_STATUS_BEGIN", ++ "ERROR_IPSEC_IKE_AUTH_FAIL", ++ "ERROR_IPSEC_IKE_ATTRIB_FAIL", ++ "ERROR_IPSEC_IKE_NEGOTIATION_PENDING", ++ "ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR", ++ "ERROR_IPSEC_IKE_TIMED_OUT", ++ "ERROR_IPSEC_IKE_NO_CERT", ++ "ERROR_IPSEC_IKE_SA_DELETED", ++ "ERROR_IPSEC_IKE_SA_REAPED", ++ "ERROR_IPSEC_IKE_MM_ACQUIRE_DROP", ++ "ERROR_IPSEC_IKE_QM_ACQUIRE_DROP", ++ "ERROR_IPSEC_IKE_QUEUE_DROP_MM", ++ "ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM", ++ "ERROR_IPSEC_IKE_DROP_NO_RESPONSE", ++ "ERROR_IPSEC_IKE_MM_DELAY_DROP", ++ "ERROR_IPSEC_IKE_QM_DELAY_DROP", ++ "ERROR_IPSEC_IKE_ERROR", ++ "ERROR_IPSEC_IKE_CRL_FAILED", ++ "ERROR_IPSEC_IKE_INVALID_KEY_USAGE", ++ "ERROR_IPSEC_IKE_INVALID_CERT_TYPE", ++ "ERROR_IPSEC_IKE_NO_PRIVATE_KEY", ++ "ERROR_IPSEC_IKE_SIMULTANEOUS_REKEY", ++ "ERROR_IPSEC_IKE_DH_FAIL", ++ "ERROR_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED", ++ "ERROR_IPSEC_IKE_INVALID_HEADER", ++ "ERROR_IPSEC_IKE_NO_POLICY", ++ "ERROR_IPSEC_IKE_INVALID_SIGNATURE", ++ "ERROR_IPSEC_IKE_KERBEROS_ERROR", ++ "ERROR_IPSEC_IKE_NO_PUBLIC_KEY", ++ "ERROR_IPSEC_IKE_PROCESS_ERR", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_SA", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_PROP", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_TRANS", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_KE", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_ID", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_CERT", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_HASH", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_SIG", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_NONCE", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_DELETE", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR", ++ "ERROR_IPSEC_IKE_INVALID_PAYLOAD", ++ "ERROR_IPSEC_IKE_LOAD_SOFT_SA", ++ "ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN", ++ "ERROR_IPSEC_IKE_INVALID_COOKIE", ++ "ERROR_IPSEC_IKE_NO_PEER_CERT", ++ "ERROR_IPSEC_IKE_PEER_CRL_FAILED", ++ "ERROR_IPSEC_IKE_POLICY_CHANGE", ++ "ERROR_IPSEC_IKE_NO_MM_POLICY", ++ "ERROR_IPSEC_IKE_NOTCBPRIV", ++ "ERROR_IPSEC_IKE_SECLOADFAIL", ++ "ERROR_IPSEC_IKE_FAILSSPINIT", ++ "ERROR_IPSEC_IKE_FAILQUERYSSP", ++ "ERROR_IPSEC_IKE_SRVACQFAIL", ++ "ERROR_IPSEC_IKE_SRVQUERYCRED", ++ "ERROR_IPSEC_IKE_GETSPIFAIL", ++ "ERROR_IPSEC_IKE_INVALID_FILTER", ++ "ERROR_IPSEC_IKE_OUT_OF_MEMORY", ++ "ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED", ++ "ERROR_IPSEC_IKE_INVALID_POLICY", ++ "ERROR_IPSEC_IKE_UNKNOWN_DOI", ++ "ERROR_IPSEC_IKE_INVALID_SITUATION", ++ "ERROR_IPSEC_IKE_DH_FAILURE", ++ "ERROR_IPSEC_IKE_INVALID_GROUP", ++ "ERROR_IPSEC_IKE_ENCRYPT", ++ "ERROR_IPSEC_IKE_DECRYPT", ++ "ERROR_IPSEC_IKE_POLICY_MATCH", ++ "ERROR_IPSEC_IKE_UNSUPPORTED_ID", ++ "ERROR_IPSEC_IKE_INVALID_HASH", ++ "ERROR_IPSEC_IKE_INVALID_HASH_ALG", ++ "ERROR_IPSEC_IKE_INVALID_HASH_SIZE", ++ "ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG", ++ "ERROR_IPSEC_IKE_INVALID_AUTH_ALG", ++ "ERROR_IPSEC_IKE_INVALID_SIG", ++ "ERROR_IPSEC_IKE_LOAD_FAILED", ++ "ERROR_IPSEC_IKE_RPC_DELETE", ++ "ERROR_IPSEC_IKE_BENIGN_REINIT", ++ "ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY", ++ "ERROR_IPSEC_IKE_INVALID_MAJOR_VERSION", ++ "ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN", ++ "ERROR_IPSEC_IKE_MM_LIMIT", ++ "ERROR_IPSEC_IKE_NEGOTIATION_DISABLED", ++ "ERROR_IPSEC_IKE_QM_LIMIT", ++ "ERROR_IPSEC_IKE_MM_EXPIRED", ++ "ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID", ++ "ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH", ++ "ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID", ++ "ERROR_IPSEC_IKE_INVALID_AUTH_PAYLOAD", ++ "ERROR_IPSEC_IKE_DOS_COOKIE_SENT", ++ "ERROR_IPSEC_IKE_SHUTTING_DOWN", ++ "ERROR_IPSEC_IKE_CGA_AUTH_FAILED", ++ "ERROR_IPSEC_IKE_PROCESS_ERR_NATOA", ++ "ERROR_IPSEC_IKE_INVALID_MM_FOR_QM", ++ "ERROR_IPSEC_IKE_QM_EXPIRED", ++ "ERROR_IPSEC_IKE_TOO_MANY_FILTERS", ++ "ERROR_IPSEC_IKE_NEG_STATUS_END", ++ "ERROR_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL", ++ "ERROR_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE", ++ "ERROR_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING", ++ "ERROR_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING", ++ "ERROR_IPSEC_IKE_COEXISTENCE_SUPPRESS", ++ "ERROR_IPSEC_IKE_RATELIMIT_DROP", ++ "ERROR_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE", ++ "ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE", ++ "ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE", ++ "ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY", ++ "ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE", ++ "ERROR_IPSEC_IKE_NEG_STATUS_EXTENDED_END", ++ "ERROR_IPSEC_BAD_SPI", ++ "ERROR_IPSEC_SA_LIFETIME_EXPIRED", ++ "ERROR_IPSEC_WRONG_SA", ++ "ERROR_IPSEC_REPLAY_CHECK_FAILED", ++ "ERROR_IPSEC_INVALID_PACKET", ++ "ERROR_IPSEC_INTEGRITY_CHECK_FAILED", ++ "ERROR_IPSEC_CLEAR_TEXT_DROP", ++ "ERROR_IPSEC_AUTH_FIREWALL_DROP", ++ "ERROR_IPSEC_THROTTLE_DROP", ++ "ERROR_IPSEC_DOSP_BLOCK", ++ "ERROR_IPSEC_DOSP_RECEIVED_MULTICAST", ++ "ERROR_IPSEC_DOSP_INVALID_PACKET", ++ "ERROR_IPSEC_DOSP_STATE_LOOKUP_FAILED", ++ "ERROR_IPSEC_DOSP_MAX_ENTRIES", ++ "ERROR_IPSEC_DOSP_KEYMOD_NOT_ALLOWED", ++ "ERROR_IPSEC_DOSP_NOT_INSTALLED", ++ "ERROR_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES", ++ "ERROR_SXS_SECTION_NOT_FOUND", ++ "ERROR_SXS_CANT_GEN_ACTCTX", ++ "ERROR_SXS_INVALID_ACTCTXDATA_FORMAT", ++ "ERROR_SXS_ASSEMBLY_NOT_FOUND", ++ "ERROR_SXS_MANIFEST_FORMAT_ERROR", ++ "ERROR_SXS_MANIFEST_PARSE_ERROR", ++ "ERROR_SXS_ACTIVATION_CONTEXT_DISABLED", ++ "ERROR_SXS_KEY_NOT_FOUND", ++ "ERROR_SXS_VERSION_CONFLICT", ++ "ERROR_SXS_WRONG_SECTION_TYPE", ++ "ERROR_SXS_THREAD_QUERIES_DISABLED", ++ "ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET", ++ "ERROR_SXS_UNKNOWN_ENCODING_GROUP", ++ "ERROR_SXS_UNKNOWN_ENCODING", ++ "ERROR_SXS_INVALID_XML_NAMESPACE_URI", ++ "ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED", ++ "ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED", ++ "ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE", ++ "ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE", ++ "ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE", ++ "ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT", ++ "ERROR_SXS_DUPLICATE_DLL_NAME", ++ "ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME", ++ "ERROR_SXS_DUPLICATE_CLSID", ++ "ERROR_SXS_DUPLICATE_IID", ++ "ERROR_SXS_DUPLICATE_TLBID", ++ "ERROR_SXS_DUPLICATE_PROGID", ++ "ERROR_SXS_DUPLICATE_ASSEMBLY_NAME", ++ "ERROR_SXS_FILE_HASH_MISMATCH", ++ "ERROR_SXS_POLICY_PARSE_ERROR", ++ "ERROR_SXS_XML_E_MISSINGQUOTE", ++ "ERROR_SXS_XML_E_COMMENTSYNTAX", ++ "ERROR_SXS_XML_E_BADSTARTNAMECHAR", ++ "ERROR_SXS_XML_E_BADNAMECHAR", ++ "ERROR_SXS_XML_E_BADCHARINSTRING", ++ "ERROR_SXS_XML_E_XMLDECLSYNTAX", ++ "ERROR_SXS_XML_E_BADCHARDATA", ++ "ERROR_SXS_XML_E_MISSINGWHITESPACE", ++ "ERROR_SXS_XML_E_EXPECTINGTAGEND", ++ "ERROR_SXS_XML_E_MISSINGSEMICOLON", ++ "ERROR_SXS_XML_E_UNBALANCEDPAREN", ++ "ERROR_SXS_XML_E_INTERNALERROR", ++ "ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE", ++ "ERROR_SXS_XML_E_INCOMPLETE_ENCODING", ++ "ERROR_SXS_XML_E_MISSING_PAREN", ++ "ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE", ++ "ERROR_SXS_XML_E_MULTIPLE_COLONS", ++ "ERROR_SXS_XML_E_INVALID_DECIMAL", ++ "ERROR_SXS_XML_E_INVALID_HEXIDECIMAL", ++ "ERROR_SXS_XML_E_INVALID_UNICODE", ++ "ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK", ++ "ERROR_SXS_XML_E_UNEXPECTEDENDTAG", ++ "ERROR_SXS_XML_E_UNCLOSEDTAG", ++ "ERROR_SXS_XML_E_DUPLICATEATTRIBUTE", ++ "ERROR_SXS_XML_E_MULTIPLEROOTS", ++ "ERROR_SXS_XML_E_INVALIDATROOTLEVEL", ++ "ERROR_SXS_XML_E_BADXMLDECL", ++ "ERROR_SXS_XML_E_MISSINGROOT", ++ "ERROR_SXS_XML_E_UNEXPECTEDEOF", ++ "ERROR_SXS_XML_E_BADPEREFINSUBSET", ++ "ERROR_SXS_XML_E_UNCLOSEDSTARTTAG", ++ "ERROR_SXS_XML_E_UNCLOSEDENDTAG", ++ "ERROR_SXS_XML_E_UNCLOSEDSTRING", ++ "ERROR_SXS_XML_E_UNCLOSEDCOMMENT", ++ "ERROR_SXS_XML_E_UNCLOSEDDECL", ++ "ERROR_SXS_XML_E_UNCLOSEDCDATA", ++ "ERROR_SXS_XML_E_RESERVEDNAMESPACE", ++ "ERROR_SXS_XML_E_INVALIDENCODING", ++ "ERROR_SXS_XML_E_INVALIDSWITCH", ++ "ERROR_SXS_XML_E_BADXMLCASE", ++ "ERROR_SXS_XML_E_INVALID_STANDALONE", ++ "ERROR_SXS_XML_E_UNEXPECTED_STANDALONE", ++ "ERROR_SXS_XML_E_INVALID_VERSION", ++ "ERROR_SXS_XML_E_MISSINGEQUALS", ++ "ERROR_SXS_PROTECTION_RECOVERY_FAILED", ++ "ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT", ++ "ERROR_SXS_PROTECTION_CATALOG_NOT_VALID", ++ "ERROR_SXS_UNTRANSLATABLE_HRESULT", ++ "ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING", ++ "ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE", ++ "ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME", ++ "ERROR_SXS_ASSEMBLY_MISSING", ++ "ERROR_SXS_CORRUPT_ACTIVATION_STACK", ++ "ERROR_SXS_CORRUPTION", ++ "ERROR_SXS_EARLY_DEACTIVATION", ++ "ERROR_SXS_INVALID_DEACTIVATION", ++ "ERROR_SXS_MULTIPLE_DEACTIVATION", ++ "ERROR_SXS_PROCESS_TERMINATION_REQUESTED", ++ "ERROR_SXS_RELEASE_ACTIVATION_CONTEXT", ++ "ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY", ++ "ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE", ++ "ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME", ++ "ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE", ++ "ERROR_SXS_IDENTITY_PARSE_ERROR", ++ "ERROR_MALFORMED_SUBSTITUTION_STRING", ++ "ERROR_SXS_INCORRECT_PUBLIC_KEY_TOKEN", ++ "ERROR_UNMAPPED_SUBSTITUTION_STRING", ++ "ERROR_SXS_ASSEMBLY_NOT_LOCKED", ++ "ERROR_SXS_COMPONENT_STORE_CORRUPT", ++ "ERROR_ADVANCED_INSTALLER_FAILED", ++ "ERROR_XML_ENCODING_MISMATCH", ++ "ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT", ++ "ERROR_SXS_IDENTITIES_DIFFERENT", ++ "ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT", ++ "ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY", ++ "ERROR_SXS_MANIFEST_TOO_BIG", ++ "ERROR_SXS_SETTING_NOT_REGISTERED", ++ "ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE", ++ "ERROR_SMI_PRIMITIVE_INSTALLER_FAILED", ++ "ERROR_GENERIC_COMMAND_FAILED", ++ "ERROR_SXS_FILE_HASH_MISSING", ++ "ERROR_SXS_DUPLICATE_ACTIVATABLE_CLASS", ++ "ERROR_EVT_INVALID_CHANNEL_PATH", ++ "ERROR_EVT_INVALID_QUERY", ++ "ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND", ++ "ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND", ++ "ERROR_EVT_INVALID_PUBLISHER_NAME", ++ "ERROR_EVT_INVALID_EVENT_DATA", ++ "ERROR_EVT_CHANNEL_NOT_FOUND", ++ "ERROR_EVT_MALFORMED_XML_TEXT", ++ "ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL", ++ "ERROR_EVT_CONFIGURATION_ERROR", ++ "ERROR_EVT_QUERY_RESULT_STALE", ++ "ERROR_EVT_QUERY_RESULT_INVALID_POSITION", ++ "ERROR_EVT_NON_VALIDATING_MSXML", ++ "ERROR_EVT_FILTER_ALREADYSCOPED", ++ "ERROR_EVT_FILTER_NOTELTSET", ++ "ERROR_EVT_FILTER_INVARG", ++ "ERROR_EVT_FILTER_INVTEST", ++ "ERROR_EVT_FILTER_INVTYPE", ++ "ERROR_EVT_FILTER_PARSEERR", ++ "ERROR_EVT_FILTER_UNSUPPORTEDOP", ++ "ERROR_EVT_FILTER_UNEXPECTEDTOKEN", ++ "ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL", ++ "ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE", ++ "ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE", ++ "ERROR_EVT_CHANNEL_CANNOT_ACTIVATE", ++ "ERROR_EVT_FILTER_TOO_COMPLEX", ++ "ERROR_EVT_MESSAGE_NOT_FOUND", ++ "ERROR_EVT_MESSAGE_ID_NOT_FOUND", ++ "ERROR_EVT_UNRESOLVED_VALUE_INSERT", ++ "ERROR_EVT_UNRESOLVED_PARAMETER_INSERT", ++ "ERROR_EVT_MAX_INSERTS_REACHED", ++ "ERROR_EVT_EVENT_DEFINITION_NOT_FOUND", ++ "ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND", ++ "ERROR_EVT_VERSION_TOO_OLD", ++ "ERROR_EVT_VERSION_TOO_NEW", ++ "ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY", ++ "ERROR_EVT_PUBLISHER_DISABLED", ++ "ERROR_EVT_FILTER_OUT_OF_RANGE", ++ "ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE", ++ "ERROR_EC_LOG_DISABLED", ++ "ERROR_EC_CIRCULAR_FORWARDING", ++ "ERROR_EC_CREDSTORE_FULL", ++ "ERROR_EC_CRED_NOT_FOUND", ++ "ERROR_EC_NO_ACTIVE_CHANNEL", ++ "ERROR_MUI_FILE_NOT_FOUND", ++ "ERROR_MUI_INVALID_FILE", ++ "ERROR_MUI_INVALID_RC_CONFIG", ++ "ERROR_MUI_INVALID_LOCALE_NAME", ++ "ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME", ++ "ERROR_MUI_FILE_NOT_LOADED", ++ "ERROR_RESOURCE_ENUM_USER_STOP", ++ "ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED", ++ "ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME", ++ "ERROR_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE", ++ "ERROR_MRM_INVALID_PRICONFIG", ++ "ERROR_MRM_INVALID_FILE_TYPE", ++ "ERROR_MRM_UNKNOWN_QUALIFIER", ++ "ERROR_MRM_INVALID_QUALIFIER_VALUE", ++ "ERROR_MRM_NO_CANDIDATE", ++ "ERROR_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE", ++ "ERROR_MRM_RESOURCE_TYPE_MISMATCH", ++ "ERROR_MRM_DUPLICATE_MAP_NAME", ++ "ERROR_MRM_DUPLICATE_ENTRY", ++ "ERROR_MRM_INVALID_RESOURCE_IDENTIFIER", ++ "ERROR_MRM_FILEPATH_TOO_LONG", ++ "ERROR_MRM_UNSUPPORTED_DIRECTORY_TYPE", ++ "ERROR_MRM_INVALID_PRI_FILE", ++ "ERROR_MRM_NAMED_RESOURCE_NOT_FOUND", ++ "ERROR_MRM_MAP_NOT_FOUND", ++ "ERROR_MRM_UNSUPPORTED_PROFILE_TYPE", ++ "ERROR_MRM_INVALID_QUALIFIER_OPERATOR", ++ "ERROR_MRM_INDETERMINATE_QUALIFIER_VALUE", ++ "ERROR_MRM_AUTOMERGE_ENABLED", ++ "ERROR_MRM_TOO_MANY_RESOURCES", ++ "ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE", ++ "ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE", ++ "ERROR_MRM_NO_CURRENT_VIEW_ON_THREAD", ++ "ERROR_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST", ++ "ERROR_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT", ++ "ERROR_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE", ++ "ERROR_MRM_GENERATION_COUNT_MISMATCH", ++ "ERROR_PRI_MERGE_VERSION_MISMATCH", ++ "ERROR_PRI_MERGE_MISSING_SCHEMA", ++ "ERROR_PRI_MERGE_LOAD_FILE_FAILED", ++ "ERROR_PRI_MERGE_ADD_FILE_FAILED", ++ "ERROR_PRI_MERGE_WRITE_FILE_FAILED", ++ "ERROR_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED", ++ "ERROR_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED", ++ "ERROR_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED", ++ "ERROR_PRI_MERGE_MAIN_PACKAGE_REQUIRED", ++ "ERROR_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED", ++ "ERROR_PRI_MERGE_INVALID_FILE_NAME", ++ "ERROR_MRM_PACKAGE_NOT_FOUND", ++ "ERROR_MRM_MISSING_DEFAULT_LANGUAGE", ++ "ERROR_MCA_INVALID_CAPABILITIES_STRING", ++ "ERROR_MCA_INVALID_VCP_VERSION", ++ "ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION", ++ "ERROR_MCA_MCCS_VERSION_MISMATCH", ++ "ERROR_MCA_UNSUPPORTED_MCCS_VERSION", ++ "ERROR_MCA_INTERNAL_ERROR", ++ "ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED", ++ "ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE", ++ "ERROR_AMBIGUOUS_SYSTEM_DEVICE", ++ "ERROR_SYSTEM_DEVICE_NOT_FOUND", ++ "ERROR_HASH_NOT_SUPPORTED", ++ "ERROR_HASH_NOT_PRESENT", ++ "ERROR_SECONDARY_IC_PROVIDER_NOT_REGISTERED", ++ "ERROR_GPIO_CLIENT_INFORMATION_INVALID", ++ "ERROR_GPIO_VERSION_NOT_SUPPORTED", ++ "ERROR_GPIO_INVALID_REGISTRATION_PACKET", ++ "ERROR_GPIO_OPERATION_DENIED", ++ "ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE", ++ "ERROR_GPIO_INTERRUPT_ALREADY_UNMASKED", ++ "ERROR_CANNOT_SWITCH_RUNLEVEL", ++ "ERROR_INVALID_RUNLEVEL_SETTING", ++ "ERROR_RUNLEVEL_SWITCH_TIMEOUT", ++ "ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT", ++ "ERROR_RUNLEVEL_SWITCH_IN_PROGRESS", ++ "ERROR_SERVICES_FAILED_AUTOSTART", ++ "ERROR_COM_TASK_STOP_PENDING", ++ "ERROR_INSTALL_OPEN_PACKAGE_FAILED", ++ "ERROR_INSTALL_PACKAGE_NOT_FOUND", ++ "ERROR_INSTALL_INVALID_PACKAGE", ++ "ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED", ++ "ERROR_INSTALL_OUT_OF_DISK_SPACE", ++ "ERROR_INSTALL_NETWORK_FAILURE", ++ "ERROR_INSTALL_REGISTRATION_FAILURE", ++ "ERROR_INSTALL_DEREGISTRATION_FAILURE", ++ "ERROR_INSTALL_CANCEL", ++ "ERROR_INSTALL_FAILED", ++ "ERROR_REMOVE_FAILED", ++ "ERROR_PACKAGE_ALREADY_EXISTS", ++ "ERROR_NEEDS_REMEDIATION", ++ "ERROR_INSTALL_PREREQUISITE_FAILED", ++ "ERROR_PACKAGE_REPOSITORY_CORRUPTED", ++ "ERROR_INSTALL_POLICY_FAILURE", ++ "ERROR_PACKAGE_UPDATING", ++ "ERROR_DEPLOYMENT_BLOCKED_BY_POLICY", ++ "ERROR_PACKAGES_IN_USE", ++ "ERROR_RECOVERY_FILE_CORRUPT", ++ "ERROR_INVALID_STAGED_SIGNATURE", ++ "ERROR_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED", ++ "ERROR_INSTALL_PACKAGE_DOWNGRADE", ++ "ERROR_SYSTEM_NEEDS_REMEDIATION", ++ "ERROR_APPX_INTEGRITY_FAILURE_CLR_NGEN", ++ "ERROR_RESILIENCY_FILE_CORRUPT", ++ "ERROR_INSTALL_FIREWALL_SERVICE_NOT_RUNNING", ++ "ERROR_PACKAGE_MOVE_FAILED", ++ "ERROR_INSTALL_VOLUME_NOT_EMPTY", ++ "ERROR_INSTALL_VOLUME_OFFLINE", ++ "ERROR_INSTALL_VOLUME_CORRUPT", ++ "ERROR_NEEDS_REGISTRATION", ++ "ERROR_INSTALL_WRONG_PROCESSOR_ARCHITECTURE", ++ "ERROR_DEV_SIDELOAD_LIMIT_EXCEEDED", ++ "ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE", ++ "ERROR_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM", ++ "ERROR_PACKAGE_MOVE_BLOCKED_BY_STREAMING", ++ "ERROR_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE", ++ "ERROR_PACKAGE_STAGING_ONHOLD", ++ "ERROR_INSTALL_INVALID_RELATED_SET_UPDATE", ++ "ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY", ++ "ERROR_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF", ++ "ERROR_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED", ++ "ERROR_PACKAGES_REPUTATION_CHECK_FAILED", ++ "ERROR_PACKAGES_REPUTATION_CHECK_TIMEDOUT", ++ "ERROR_DEPLOYMENT_OPTION_NOT_SUPPORTED", ++ "ERROR_APPINSTALLER_ACTIVATION_BLOCKED", ++ "ERROR_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED", ++ "ERROR_APPX_RAW_DATA_WRITE_FAILED", ++ "ERROR_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE", ++ "ERROR_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE", ++ "ERROR_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY", ++ "ERROR_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY", ++ "ERROR_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER", ++ "ERROR_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED", ++ "ERROR_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE", ++ "ERROR_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES", ++ "ERROR_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED", ++ "ERROR_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST", ++ "ERROR_UNSIGNED_PACKAGE_INVALID_CONTENT", ++ "ERROR_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE", ++ "ERROR_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE", ++ "ERROR_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED", ++ "ERROR_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY", ++ "ERROR_STATE_LOAD_STORE_FAILED", ++ "ERROR_STATE_GET_VERSION_FAILED", ++ "ERROR_STATE_SET_VERSION_FAILED", ++ "ERROR_STATE_STRUCTURED_RESET_FAILED", ++ "ERROR_STATE_OPEN_CONTAINER_FAILED", ++ "ERROR_STATE_CREATE_CONTAINER_FAILED", ++ "ERROR_STATE_DELETE_CONTAINER_FAILED", ++ "ERROR_STATE_READ_SETTING_FAILED", ++ "ERROR_STATE_WRITE_SETTING_FAILED", ++ "ERROR_STATE_DELETE_SETTING_FAILED", ++ "ERROR_STATE_QUERY_SETTING_FAILED", ++ "ERROR_STATE_READ_COMPOSITE_SETTING_FAILED", ++ "ERROR_STATE_WRITE_COMPOSITE_SETTING_FAILED", ++ "ERROR_STATE_ENUMERATE_CONTAINER_FAILED", ++ "ERROR_STATE_ENUMERATE_SETTINGS_FAILED", ++ "ERROR_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED", ++ "ERROR_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED", ++ "ERROR_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED", ++ "ERROR_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED", ++ "ERROR_API_UNAVAILABLE", ++}; ++ ++const char* WinErrorToString(uint16_t error) { ++ auto itr = std::find(std::begin(kWinErrorValues), ++ std::end(kWinErrorValues), ++ error); ++ if (itr == std::end(kWinErrorValues)) { ++ return nullptr; ++ } ++ ++ return kWinErrorStrings[itr - std::begin(kWinErrorValues)]; + } + + } // namespace google_breakpad +diff --git a/src/processor/symbolic_constants_win.h b/src/processor/symbolic_constants_win.h +--- a/src/processor/symbolic_constants_win.h ++++ b/src/processor/symbolic_constants_win.h +@@ -31,24 +31,31 @@ + // + // Provides a means to convert NTSTATUS codes to strings. + // + // Author: Ben Wagner + + #ifndef GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ + #define GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ + ++#include + #include + + #include "common/using_std_string.h" + #include "google_breakpad/common/breakpad_types.h" + + namespace google_breakpad { + +-/* Converts a NTSTATUS code to a reason string. */ +-string NTStatusToString(uint32_t ntstatus); ++/* Converts an NTSTATUS code to its string representation. Returns nullptr if ++ * no entry corresponds to the code. */ ++const char* NTStatusToString(uint32_t ntstatus); + +-/* Converts a FAST_FAIL code to a reason string. */ +-string FastFailToString(uint32_t fast_fail_code); ++/* Converts a FAST_FAIL code to its string representation. Returns nullptr if ++ * no entry corresponds to the code. */ ++const char* FastFailToString(uint32_t fast_fail_code); ++ ++/* Converts an ERROR code to its string representation. Returns nullptr if ++ * no entry corresponds to the code. */ ++const char* WinErrorToString(uint16_t error); + + } // namespace google_breakpad + + #endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ diff --git a/toolkit/crashreporter/breakpad-patches/23-si-user-si-kernel-siginfo.patch b/toolkit/crashreporter/breakpad-patches/23-si-user-si-kernel-siginfo.patch new file mode 100644 index 0000000000..9e779f7dd8 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/23-si-user-si-kernel-siginfo.patch @@ -0,0 +1,76 @@ +diff --git a/src/google_breakpad/common/minidump_exception_linux.h b/src/google_breakpad/common/minidump_exception_linux.h +--- a/src/google_breakpad/common/minidump_exception_linux.h ++++ b/src/google_breakpad/common/minidump_exception_linux.h +@@ -83,16 +83,20 @@ typedef enum { + MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception, + dump requested. */ + } MDExceptionCodeLinux; + + /* For (MDException).exception_flags. These values come from + * asm-generic/siginfo.h. + */ + typedef enum { ++ /* Generic */ ++ MD_EXCEPTION_FLAG_LIN_SI_USER = 0, ++ MD_EXCEPTION_FLAG_LIN_SI_KERNEL = 0x80, ++ + /* SIGILL */ + MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC = 1, + MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN = 2, + MD_EXCEPTION_FLAG_LIN_ILL_ILLADR = 3, + MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP = 4, + MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC = 5, + MD_EXCEPTION_FLAG_LIN_ILL_PRVREG = 6, + MD_EXCEPTION_FLAG_LIN_ILL_COPROC = 7, +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1401,16 +1401,22 @@ string MinidumpProcessor::GetCrashReason + reason = "SIGTRAP"; + break; + case MD_EXCEPTION_CODE_LIN_SIGABRT: + reason = "SIGABRT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGBUS: + reason = "SIGBUS / "; + switch (exception_flags) { ++ case MD_EXCEPTION_FLAG_LIN_SI_USER: ++ reason.append("SI_USER"); ++ break; ++ case MD_EXCEPTION_FLAG_LIN_SI_KERNEL: ++ reason.append("SI_KERNEL"); ++ break; + case MD_EXCEPTION_FLAG_LIN_BUS_ADRALN: + reason.append("BUS_ADRALN"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_ADRERR: + reason.append("BUS_ADRERR"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_OBJERR: + reason.append("BUS_OBJERR"); +@@ -1462,18 +1468,24 @@ string MinidumpProcessor::GetCrashReason + break; + case MD_EXCEPTION_CODE_LIN_SIGKILL: + reason = "SIGKILL"; + break; + case MD_EXCEPTION_CODE_LIN_SIGUSR1: + reason = "SIGUSR1"; + break; + case MD_EXCEPTION_CODE_LIN_SIGSEGV: +- reason = "SIGSEGV /"; ++ reason = "SIGSEGV / "; + switch (exception_flags) { ++ case MD_EXCEPTION_FLAG_LIN_SI_USER: ++ reason.append("SI_USER"); ++ break; ++ case MD_EXCEPTION_FLAG_LIN_SI_KERNEL: ++ reason.append("SI_KERNEL"); ++ break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR: + reason.append("SEGV_MAPERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR: + reason.append("SEGV_ACCERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR: + reason.append("SEGV_BNDERR"); diff --git a/toolkit/crashreporter/breakpad-patches/24-macos-exc-resource.patch b/toolkit/crashreporter/breakpad-patches/24-macos-exc-resource.patch new file mode 100644 index 0000000000..29cf116048 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/24-macos-exc-resource.patch @@ -0,0 +1,155 @@ +diff --git a/src/google_breakpad/common/minidump_exception_mac.h b/src/google_breakpad/common/minidump_exception_mac.h +--- a/src/google_breakpad/common/minidump_exception_mac.h ++++ b/src/google_breakpad/common/minidump_exception_mac.h +@@ -62,16 +62,18 @@ typedef enum { + 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 */ ++ MD_EXCEPTION_MAC_RESOURCE = 11, ++ /* EXC_RESOURCE */ + MD_EXCEPTION_MAC_SIMULATED = 0x43507378 + /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */ + } 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 { +@@ -201,9 +203,42 @@ typedef enum { + /* 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; + ++// The following definitions were taken from Darwin/XNU kernel sources. ++// See https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/exc_resource.h ++ ++typedef enum MDMacExcResourceType { ++ MD_MAC_EXC_RESOURCE_TYPE_CPU = 1, ++ MD_MAC_EXC_RESOURCE_TYPE_WAKEUPS = 2, ++ MD_MAC_EXC_RESOURCE_TYPE_MEMORY = 3, ++ MD_MAC_EXC_RESOURCE_TYPE_IO = 4, ++ MD_MAC_EXC_RESOURCE_TYPE_THREADS = 5 ++} MDMacExcResourceType; ++ ++typedef enum MDMacExcResourceFlavorCpu { ++ MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR = 1, ++ MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR_FATAL = 2 ++} MDMacExcResourceFlavorCpu; ++ ++typedef enum MDMacExcResourceFlavorWakeup { ++ MD_MAC_EXC_RESOURCE_FLAVOR_WAKEUPS_MONITOR = 1, ++} MDMacExcResourceFlavorWakeup; ++ ++typedef enum MDMacExcResourceFlavorMemory { ++ MD_MAC_EXC_RESOURCE_FLAVOR_HIGH_WATERMARK = 1, ++} MDMacExcResourceFlavorMemory; ++ ++typedef enum MDMacExcResourceIOFlavor { ++ MD_MAC_EXC_RESOURCE_FLAVOR_IO_PHYSICAL_WRITES = 1, ++ MD_MAC_EXC_RESOURCE_FLAVOR_IO_LOGICAL_WRITES = 2, ++} MDMacExcResourceIOFlavor; ++ ++typedef enum MDMacExcResourceThreadsFlavor { ++ MD_MAC_EXC_RESOURCE_FLAVOR_THREADS_HIGH_WATERMARK = 1, ++} MDMacExcResourceThreadsFlavor; ++ + #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1143,16 +1143,86 @@ string MinidumpProcessor::GetCrashReason + case MD_EXCEPTION_MAC_MACH_SYSCALL: + reason = "EXC_MACH_SYSCALL / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_RPC_ALERT: + reason = "EXC_RPC_ALERT / "; + reason.append(flags_string); + break; ++ case MD_EXCEPTION_MAC_RESOURCE: ++ reason = "EXC_RESOURCE / "; ++ { ++ uint32_t type = (exception_flags >> 29) & 0x7ULL; ++ uint32_t flavor = (exception_flags >> 26) & 0x7ULL; ++ char flavor_string[6] = {}; ++ switch (type) { ++ case MD_MAC_EXC_RESOURCE_TYPE_CPU: ++ reason.append("RESOURCE_TYPE_CPU / "); ++ switch (flavor) { ++ case MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR: ++ reason.append("FLAVOR_CPU_MONITOR"); ++ break; ++ case MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR_FATAL: ++ reason.append("FLAVOR_CPU_MONITOR_FATAL"); ++ break; ++ default: ++ snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); ++ reason.append(flavor_string); ++ break; ++ } ++ break; ++ case MD_MAC_EXC_RESOURCE_TYPE_WAKEUPS: ++ reason.append("RESOURCE_TYPE_WAKEUPS / "); ++ if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_WAKEUPS_MONITOR) { ++ reason.append("FLAVOR_WAKEUPS_MONITOR"); ++ } else { ++ snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); ++ reason.append(flavor_string); ++ } ++ break; ++ case MD_MAC_EXC_RESOURCE_TYPE_MEMORY: ++ reason.append("RESOURCE_TYPE_MEMORY / "); ++ if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_HIGH_WATERMARK) { ++ reason.append("FLAVOR_HIGH_WATERMARK"); ++ } else { ++ snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); ++ reason.append(flavor_string); ++ } ++ break; ++ case MD_MAC_EXC_RESOURCE_TYPE_IO: ++ reason.append("EXC_RESOURCE_TYPE_IO / "); ++ switch (flavor) { ++ case MD_MAC_EXC_RESOURCE_FLAVOR_IO_PHYSICAL_WRITES: ++ reason.append("FLAVOR_IO_PHYSICAL_WRITES"); ++ break; ++ case MD_MAC_EXC_RESOURCE_FLAVOR_IO_LOGICAL_WRITES: ++ reason.append("FLAVOR_IO_LOGICAL_WRITES"); ++ break; ++ default: ++ snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); ++ reason.append(flavor_string); ++ break; ++ } ++ break; ++ case MD_MAC_EXC_RESOURCE_TYPE_THREADS: ++ reason.append("EXC_RESOURCE_TYPE_THREADS / "); ++ if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_THREADS_HIGH_WATERMARK) { ++ reason.append("FLAVOR_THREADS_HIGH_WATERMARK"); ++ } else { ++ snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); ++ reason.append(flavor_string); ++ } ++ break; ++ default: ++ reason.append(flags_string); ++ break; ++ } ++ } ++ break; + case MD_EXCEPTION_MAC_SIMULATED: + reason = "Simulated Exception"; + break; + } + break; + } + + case MD_OS_WIN32_NT: diff --git a/toolkit/crashreporter/breakpad-patches/25-macos-exc-guard.patch b/toolkit/crashreporter/breakpad-patches/25-macos-exc-guard.patch new file mode 100644 index 0000000000..512c8d8ebd --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/25-macos-exc-guard.patch @@ -0,0 +1,349 @@ +diff --git a/src/google_breakpad/common/minidump_exception_mac.h b/src/google_breakpad/common/minidump_exception_mac.h +--- a/src/google_breakpad/common/minidump_exception_mac.h ++++ b/src/google_breakpad/common/minidump_exception_mac.h +@@ -64,16 +64,18 @@ typedef enum { + 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 */ + MD_EXCEPTION_MAC_RESOURCE = 11, + /* EXC_RESOURCE */ ++ MD_EXCEPTION_MAC_GUARD = 12, ++ /* EXC_GUARD */ + MD_EXCEPTION_MAC_SIMULATED = 0x43507378 + /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */ + } 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 { +@@ -236,9 +238,77 @@ typedef enum MDMacExcResourceIOFlavor { + MD_MAC_EXC_RESOURCE_FLAVOR_IO_PHYSICAL_WRITES = 1, + MD_MAC_EXC_RESOURCE_FLAVOR_IO_LOGICAL_WRITES = 2, + } MDMacExcResourceIOFlavor; + + typedef enum MDMacExcResourceThreadsFlavor { + MD_MAC_EXC_RESOURCE_FLAVOR_THREADS_HIGH_WATERMARK = 1, + } MDMacExcResourceThreadsFlavor; + ++// See https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/exc_guard.h ++ ++typedef enum MDMacExcGuardType { ++ MD_MAC_EXC_GUARD_TYPE_NONE = 0x0, ++ MD_MAC_EXC_GUARD_TYPE_MACH_PORT = 0x1, ++ MD_MAC_EXC_GUARD_TYPE_FD = 0x2, ++ MD_MAC_EXC_GUARD_TYPE_USER = 0x3, ++ MD_MAC_EXC_GUARD_TYPE_VN = 0x4, ++ MD_MAC_EXC_GUARD_TYPE_VIRT_MEMORY = 0x5 ++} MDMacExcGuardType; ++ ++// See https://github.com/apple/darwin-xnu/osfmk/mach/port.h ++ ++typedef enum MDMacExcGuardMachPortFlavor { ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_DESTROY = 1u << 0, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS = 1u << 1, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT = 1u << 2, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_UNGUARDED = 1u << 3, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INCORRECT_GUARD = 1u << 4, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE = 1u << 5, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_STRICT_REPLY = 1u << 6, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MSG_FILTERED = 1u << 7, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_RIGHT = 1u << 8, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_NAME = 1u << 9, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_VALUE = 1u << 10, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_ARGUMENT = 1u << 11, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RIGHT_EXISTS = 1u << 12, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_NO_SPACE = 1u << 13, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_FAILURE = 1u << 14, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_RESOURCE = 1u << 15, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_REPLY = 1u << 16, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_VOUCHER = 1u << 17, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_RIGHT = 1u << 18, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_INVALID_NAME = 1u << 19, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_GUARDED_DESC = 1u << 20, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS_NON_FATAL = 1u << 21, ++ MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE_NON_FATAL = 1u << 22, ++} MDMacExcGuardMachPortFlavor; ++ ++// See https://github.com/apple/darwin-xnu/blob/main/bsd/sys/guarded.h ++ ++typedef enum MDMacExcGuardFDFlavor { ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_CLOSE = 1u << 0, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_DUP = 1u << 1, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_NOCLOEXEC = 1u << 2, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_SOCKET_IPC = 1u << 3, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_FILEPORT = 1u << 4, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_MISMATCH = 1u << 5, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE = 1u << 6 ++} MDMacExcGuardFDFlavor; ++ ++ ++typedef enum MDMacExcGuardVNFlavor { ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_TO = 1u << 0, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_FROM = 1u << 1, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_UNLINK = 1u << 2, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE_OTHER = 1u << 3, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_TRUNC_OTHER = 1u << 4, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_LINK = 1u << 5, ++ MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_EXCHDATA = 1u << 6, ++} MDMacExcGuardVNFlavor; ++ ++// See https://github.com/apple/darwin-xnu/osfmk/mach/vm_statistics.h ++ ++typedef enum MDMacExcGuardVirtMemoryFlavor { ++ MD_MAC_EXC_GUARD_VIRT_MEMORY_FLAVOR_GUARD_EXC_DEALLOC_GAP = 1u << 0 ++} MDMacExcGuardVirtMemoryFlavor; ++ + #endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ +diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc +--- a/src/processor/minidump_processor.cc ++++ b/src/processor/minidump_processor.cc +@@ -1213,16 +1213,245 @@ string MinidumpProcessor::GetCrashReason + } + break; + default: + reason.append(flags_string); + break; + } + } + break; ++ case MD_EXCEPTION_MAC_GUARD: ++ reason = "EXC_GUARD / "; ++ { ++ uint32_t type = (exception_flags >> 29) & 0x7ULL; ++ uint32_t flavor = exception_flags & 0x1FFFFFFFULL; ++ switch (type) { ++ case MD_MAC_EXC_GUARD_TYPE_NONE: ++ reason.append("GUARD_TYPE_NONE"); ++ break; ++ case MD_MAC_EXC_GUARD_TYPE_MACH_PORT: ++ reason.append("GUARD_TYPE_MACH_PORT"); ++ ++ if (flavor) { ++ std::vector flavors; ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_DESTROY) { ++ flavors.push_back("GUARD_EXC_DESTROY"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS) { ++ flavors.push_back("GUARD_EXC_MOD_REFS"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT) { ++ flavors.push_back("GUARD_EXC_SET_CONTEXT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT) { ++ flavors.push_back("GUARD_EXC_SET_CONTEXT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_UNGUARDED) { ++ flavors.push_back("GUARD_EXC_UNGUARDED"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INCORRECT_GUARD) { ++ flavors.push_back("GUARD_EXC_INCORRECT_GUARD"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE) { ++ flavors.push_back("GUARD_EXC_IMMOVABLE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_STRICT_REPLY) { ++ flavors.push_back("GUARD_EXC_STRICT_REPLY"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MSG_FILTERED) { ++ flavors.push_back("GUARD_EXC_MSG_FILTERED"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_RIGHT) { ++ flavors.push_back("GUARD_EXC_INVALID_RIGHT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_NAME) { ++ flavors.push_back("GUARD_EXC_INVALID_NAME"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_VALUE) { ++ flavors.push_back("GUARD_EXC_INVALID_VALUE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_ARGUMENT) { ++ flavors.push_back("GUARD_EXC_INVALID_ARGUMENT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RIGHT_EXISTS) { ++ flavors.push_back("GUARD_EXC_RIGHT_EXISTS"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_NO_SPACE) { ++ flavors.push_back("GUARD_EXC_KERN_NO_SPACE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_FAILURE) { ++ flavors.push_back("GUARD_EXC_KERN_FAILURE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_RESOURCE) { ++ flavors.push_back("GUARD_EXC_KERN_RESOURCE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_REPLY) { ++ flavors.push_back("GUARD_EXC_SEND_INVALID_REPLY"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_VOUCHER) { ++ flavors.push_back("GUARD_EXC_SEND_INVALID_VOUCHER"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_RIGHT) { ++ flavors.push_back("GUARD_EXC_SEND_INVALID_RIGHT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_INVALID_NAME) { ++ flavors.push_back("GUARD_EXC_RCV_INVALID_NAME"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_GUARDED_DESC) { ++ flavors.push_back("GUARD_EXC_RCV_GUARDED_DESC"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS_NON_FATAL) { ++ flavors.push_back("GUARD_EXC_MOD_REFS_NON_FATAL"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE_NON_FATAL) { ++ flavors.push_back("GUARD_EXC_IMMOVABLE_NON_FATAL"); ++ } ++ ++ reason.append(" / "); ++ for (size_t i = 0; i < flavors.size(); i++) { ++ if (i > 0) { ++ reason.append(" | "); ++ } ++ ++ reason.append(flavors[i]); ++ } ++ } ++ ++ break; ++ case MD_MAC_EXC_GUARD_TYPE_FD: ++ reason.append("GUARD_TYPE_FD"); ++ ++ if (flavor) { ++ std::vector flavors; ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_CLOSE) { ++ flavors.push_back("GUARD_EXC_CLOSE"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_DUP) { ++ flavors.push_back("GUARD_EXC_DUP"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_NOCLOEXEC) { ++ flavors.push_back("GUARD_EXC_NOCLOEXEC"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_SOCKET_IPC) { ++ flavors.push_back("GUARD_EXC_SOCKET_IPC"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_FILEPORT) { ++ flavors.push_back("GUARD_EXC_FILEPORT"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_MISMATCH) { ++ flavors.push_back("GUARD_EXC_MISMATCH"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE) { ++ flavors.push_back("GUARD_EXC_WRITE"); ++ } ++ ++ reason.append(" / "); ++ for (size_t i = 0; i < flavors.size(); i++) { ++ if (i > 0) { ++ reason.append(" | "); ++ } ++ ++ reason.append(flavors[i]); ++ } ++ } ++ ++ break; ++ case MD_MAC_EXC_GUARD_TYPE_USER: ++ reason.append("GUARD_TYPE_USER"); ++ break; ++ case MD_MAC_EXC_GUARD_TYPE_VN: ++ reason.append("GUARD_TYPE_VN"); ++ ++ if (flavor) { ++ std::vector flavors; ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_TO) { ++ flavors.push_back("GUARD_EXC_RENAME_TO"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_FROM) { ++ flavors.push_back("GUARD_EXC_RENAME_FROM"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_UNLINK) { ++ flavors.push_back("GUARD_EXC_UNLINK"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE_OTHER) { ++ flavors.push_back("GUARD_EXC_WRITE_OTHER"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_TRUNC_OTHER) { ++ flavors.push_back("GUARD_EXC_TRUNC_OTHER"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_LINK) { ++ flavors.push_back("GUARD_EXC_LINK"); ++ } ++ ++ if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_EXCHDATA) { ++ flavors.push_back("GUARD_EXC_EXCHDATA"); ++ } ++ ++ reason.append(" / "); ++ for (size_t i = 0; i < flavors.size(); i++) { ++ if (i > 0) { ++ reason.append(" | "); ++ } ++ ++ reason.append(flavors[i]); ++ } ++ } ++ ++ break; ++ case MD_MAC_EXC_GUARD_TYPE_VIRT_MEMORY: ++ reason.append("GUARD_TYPE_VIRT_MEMORY"); ++ ++ if (flavor & MD_MAC_EXC_GUARD_VIRT_MEMORY_FLAVOR_GUARD_EXC_DEALLOC_GAP) { ++ reason.append(" / GUARD_EXC_DEALLOC_GAP"); ++ } ++ ++ break; ++ default: ++ reason.append(flags_string); ++ break; ++ } ++ } ++ break; + case MD_EXCEPTION_MAC_SIMULATED: + reason = "Simulated Exception"; + break; + } + break; + } + + case MD_OS_WIN32_NT: diff --git a/toolkit/crashreporter/breakpad-patches/26-print-thread-tid.patch b/toolkit/crashreporter/breakpad-patches/26-print-thread-tid.patch new file mode 100644 index 0000000000..f81ca774bd --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/26-print-thread-tid.patch @@ -0,0 +1,44 @@ +diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc +--- a/src/processor/stackwalk_common.cc ++++ b/src/processor/stackwalk_common.cc +@@ -879,18 +879,19 @@ void PrintProcessState(const ProcessStat + } + + // If the thread that requested the dump is known, print it first. + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { + const CallStack* requesting_thread_callstack = + process_state.threads()->at(requesting_thread); + printf("\n" +- "Thread %d (%s)", ++ "Thread %d tid %u (%s)", + requesting_thread, ++ requesting_thread_callstack->tid(), + process_state.crashed() ? "crashed" : + "requested dump, did not crash"); + if (!requesting_thread_callstack->name().empty()) { + printf(" - %s", requesting_thread_callstack->name().c_str()); + } + PrintStack(requesting_thread_callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(requesting_thread), +@@ -899,17 +900,17 @@ void PrintProcessState(const ProcessStat + + // Print all of the threads in the dump. + int thread_count = process_state.threads()->size(); + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + const CallStack* callstack = process_state.threads()->at(thread_index); + printf("\n" +- "Thread %d", thread_index); ++ "Thread %d tid %u", thread_index, callstack->tid()); + if (!callstack->name().empty()) { + printf(" - %s", callstack->name().c_str()); + } + printf("\n"); + PrintStack(callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(thread_index), + process_state.modules(), resolver); + diff --git a/toolkit/crashreporter/breakpad-patches/27-fix-unified-builds-bug-1733547.patch b/toolkit/crashreporter/breakpad-patches/27-fix-unified-builds-bug-1733547.patch new file mode 100644 index 0000000000..5afc50316e --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/27-fix-unified-builds-bug-1733547.patch @@ -0,0 +1,22 @@ +diff --git a/src/processor/stack_frame_symbolizer.cc b/src/processor/stack_frame_symbolizer.cc +--- a/src/processor/stack_frame_symbolizer.cc ++++ b/src/processor/stack_frame_symbolizer.cc +@@ -124,17 +124,16 @@ StackFrameSymbolizer::SymbolizerResult S + + case SymbolSupplier::INTERRUPT: + return kInterrupt; + + default: + BPLOG(ERROR) << "Unknown SymbolResult enum: " << symbol_result; + return kError; + } +- return kError; + } + + WindowsFrameInfo* StackFrameSymbolizer::FindWindowsFrameInfo( + const StackFrame* frame) { + return resolver_ ? resolver_->FindWindowsFrameInfo(frame) : NULL; + } + + CFIFrameInfo* StackFrameSymbolizer::FindCFIFrameInfo( + diff --git a/toolkit/crashreporter/breakpad-patches/28-no-garbage-in-code-ids.patch b/toolkit/crashreporter/breakpad-patches/28-no-garbage-in-code-ids.patch new file mode 100644 index 0000000000..64f791d01e --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/28-no-garbage-in-code-ids.patch @@ -0,0 +1,34 @@ +diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc +--- a/src/common/linux/file_id.cc ++++ b/src/common/linux/file_id.cc +@@ -115,28 +115,27 @@ static bool FindElfBuildIDNote(const voi + + return false; + } + + // Attempt to locate the .text section of an ELF binary and generate + // a simple hash by XORing the first page worth of bytes into |identifier|. + static bool HashElfTextSection(const void* elf_mapped_base, + wasteful_vector& identifier) { +- identifier.resize(kMDGUIDSize); +- + void* text_section; + size_t text_size; + if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, + (const void**)&text_section, &text_size) || + text_size == 0) { + return false; + } + + // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this + // function backwards-compatible. ++ identifier.resize(kMDGUIDSize); + my_memset(&identifier[0], 0, kMDGUIDSize); + const uint8_t* ptr = reinterpret_cast(text_section); + const uint8_t* ptr_end = ptr + std::min(text_size, static_cast(4096)); + while (ptr < ptr_end) { + for (unsigned i = 0; i < kMDGUIDSize; i++) + identifier[i] ^= ptr[i]; + ptr += kMDGUIDSize; + } + diff --git a/toolkit/crashreporter/breakpad-patches/29-cpu-context-packing.patch b/toolkit/crashreporter/breakpad-patches/29-cpu-context-packing.patch new file mode 100644 index 0000000000..f6ef0c4d29 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/29-cpu-context-packing.patch @@ -0,0 +1,118 @@ +diff --git a/src/google_breakpad/common/minidump_cpu_arm64.h b/src/google_breakpad/common/minidump_cpu_arm64.h +--- a/src/google_breakpad/common/minidump_cpu_arm64.h ++++ b/src/google_breakpad/common/minidump_cpu_arm64.h +@@ -86,16 +86,20 @@ typedef struct { + #define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002) + #define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004) + #define MD_CONTEXT_ARM64_DEBUG (MD_CONTEXT_ARM64 | 0x00000008) + #define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_CONTROL | \ + MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) + #define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_FULL | MD_CONTEXT_ARM64_DEBUG) + ++/* Use the same 32-bit alignment when accessing these structures from 64-bit ++ * code as is used natively in 32-bit code. */ ++#pragma pack(push, 4) ++ + typedef struct { + /* Determines which fields of this struct are populated */ + uint32_t context_flags; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) +@@ -125,20 +129,16 @@ typedef struct { + typedef struct { + uint32_t fpsr; /* FPU status register */ + uint32_t fpcr; /* FPU control register */ + + /* 32 128-bit floating point registers, d0 .. d31. */ + uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT]; + } MDFloatingSaveAreaARM64_Old; + +-/* Use the same 32-bit alignment when accessing this structure from 64-bit code +- * as is used natively in 32-bit code. */ +-#pragma pack(push, 4) +- + typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint64_t context_flags; + + /* 33 64-bit integer registers, x0 .. x31 + the PC + * Note the following fixed uses: +diff --git a/src/google_breakpad/common/minidump_cpu_ppc.h b/src/google_breakpad/common/minidump_cpu_ppc.h +--- a/src/google_breakpad/common/minidump_cpu_ppc.h ++++ b/src/google_breakpad/common/minidump_cpu_ppc.h +@@ -73,16 +73,20 @@ + /* + * 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__ + ++/* Use the same 32-bit alignment when accessing these structures from 64-bit ++ * code as is used natively in 32-bit code. */ ++#pragma pack(push, 4) ++ + #define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32 + + typedef struct { + /* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used + * here for precise sizing. */ + uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT]; + uint32_t fpscr_pad; + uint32_t fpscr; /* Status/control */ +@@ -99,25 +103,16 @@ typedef struct { + uint32_t save_pad5[4]; + uint32_t save_vrvalid; /* Indicates which vector registers are saved */ + uint32_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. */ + uint32_t context_flags; + + uint32_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ +@@ -140,21 +135,17 @@ typedef struct { + MDVectorSaveAreaPPC vector_save; + } MDRawContextPPC; /* Based on ppc_thread_state */ + + /* Indices into gpr for registers with a dedicated or conventional purpose. */ + enum MDPPCRegisterNumbers { + MD_CONTEXT_PPC_REG_SP = 1 + }; + +-#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) + diff --git a/toolkit/crashreporter/breakpad-patches/30-sign-compare.patch b/toolkit/crashreporter/breakpad-patches/30-sign-compare.patch new file mode 100644 index 0000000000..5fbf075810 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/30-sign-compare.patch @@ -0,0 +1,11 @@ +--- a/src/client/windows/crash_generation/crash_generation_server.cc ++++ b/src/client/windows/crash_generation/crash_generation_server.cc +@@ -954,7 +954,7 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client, + } + + // Allocate AppMemory instances for exception context. +- for (int i = 0; i < kExceptionAppMemoryRegions; i++) { ++ for (size_t i = 0; i < kExceptionAppMemoryRegions; i++) { + AppMemory app_memory; + app_memory.ptr = reinterpret_cast(nullptr); + app_memory.length = 0; diff --git a/toolkit/crashreporter/breakpad-patches/README b/toolkit/crashreporter/breakpad-patches/README new file mode 100644 index 0000000000..b3f23b255f --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/README @@ -0,0 +1,4 @@ +Do not land local patches to Breakpad without the approval of +Ted Mielczarek + +All local patches must be in the process of being upstreamed. \ No newline at end of file diff --git a/toolkit/crashreporter/breakpad-windows-libxul/moz.build b/toolkit/crashreporter/breakpad-windows-libxul/moz.build new file mode 100644 index 0000000000..ab517eb5a7 --- /dev/null +++ b/toolkit/crashreporter/breakpad-windows-libxul/moz.build @@ -0,0 +1,29 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Library("google_breakpad_libxul_s") + +FINAL_LIBRARY = "xul" + +for var in ("UNICODE", "UNICODE_", "BREAKPAD_NO_TERMINATE_THREAD"): + DEFINES[var] = True + +LOCAL_INCLUDES += [ + "/toolkit/crashreporter/breakpad-client", + "/toolkit/crashreporter/google-breakpad/src", +] + +include("/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild") + +SOURCES += objs_common +SOURCES += objs_crash_generation +SOURCES += objs_handler +SOURCES += objs_client_common + +DisableStlWrapping() diff --git a/toolkit/crashreporter/breakpad-windows-standalone/moz.build b/toolkit/crashreporter/breakpad-windows-standalone/moz.build new file mode 100644 index 0000000000..8d6033e076 --- /dev/null +++ b/toolkit/crashreporter/breakpad-windows-standalone/moz.build @@ -0,0 +1,29 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FINAL_LIBRARY = "breakpadinjector" + +for var in ("UNICODE", "UNICODE_", "BREAKPAD_NO_TERMINATE_THREAD"): + DEFINES[var] = True + +LOCAL_INCLUDES += [ + "/toolkit/crashreporter/breakpad-client", + "/toolkit/crashreporter/google-breakpad/src", +] + +include("/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/handler/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/crash_generation/objs.mozbuild") +include("/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild") + +SOURCES += objs_common +SOURCES += objs_crash_generation +SOURCES += objs_handler +SOURCES += objs_client_common + +USE_STATIC_LIBS = True + +DisableStlWrapping() diff --git a/toolkit/crashreporter/client/Makefile.in b/toolkit/crashreporter/client/Makefile.in new file mode 100644 index 0000000000..2d3ef1bee9 --- /dev/null +++ b/toolkit/crashreporter/client/Makefile.in @@ -0,0 +1,19 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +ifeq ($(OS_ARCH),WINNT) +MOZ_WINCONSOLE = 0 +endif + +include $(topsrcdir)/config/rules.mk + +ifeq ($(OS_ARCH),Darwin) +libs:: + $(NSINSTALL) -D $(DIST)/bin/crashreporter.app + rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/crashreporter.app + $(call py_action,preprocessor crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings) + $(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS + $(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS +endif diff --git a/toolkit/crashreporter/client/Throbber-small.avi b/toolkit/crashreporter/client/Throbber-small.avi new file mode 100644 index 0000000000..640ea62c0e Binary files /dev/null and b/toolkit/crashreporter/client/Throbber-small.avi differ diff --git a/toolkit/crashreporter/client/Throbber-small.gif b/toolkit/crashreporter/client/Throbber-small.gif new file mode 100644 index 0000000000..cce32f20f4 Binary files /dev/null and b/toolkit/crashreporter/client/Throbber-small.gif differ diff --git a/toolkit/crashreporter/client/crashreporter.cpp b/toolkit/crashreporter/client/crashreporter.cpp new file mode 100644 index 0000000000..2887b16170 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.cpp @@ -0,0 +1,852 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "crashreporter.h" + +#ifdef _MSC_VER +// Disable exception handler warnings. +# pragma warning(disable : 4530) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef XP_LINUX +# include +#endif + +#include "json/json.h" +#include "nss.h" +#include "sechash.h" + +using std::ifstream; +using std::ios; +using std::istream; +using std::istringstream; +using std::ofstream; +using std::ostream; +using std::ostringstream; +using std::string; +using std::unique_ptr; +using std::vector; + +namespace CrashReporter { + +StringTable gStrings; +Json::Value gData; +string gSettingsPath; +string gEventsPath; +string gPingPath; +int gArgc; +char** gArgv; +bool gAutoSubmit; + +enum SubmissionResult { Succeeded, Failed }; + +static unique_ptr gLogStream(nullptr); +static string gReporterDumpFile; +static string gExtraFile; +static string gMemoryFile; + +static const char kExtraDataExtension[] = ".extra"; +static const char kMemoryReportExtension[] = ".memory.json.gz"; + +void UIError(const string& message) { + if (gAutoSubmit) { + return; + } + + string errorMessage; + if (!gStrings[ST_CRASHREPORTERERROR].empty()) { + char buf[2048]; + snprintf(buf, 2048, gStrings[ST_CRASHREPORTERERROR].c_str(), + message.c_str()); + errorMessage = buf; + } else { + errorMessage = message; + } + + UIError_impl(errorMessage); +} + +static string Unescape(const string& str) { + string ret; + for (string::const_iterator iter = str.begin(); iter != str.end(); iter++) { + if (*iter == '\\') { + iter++; + if (*iter == '\\') { + ret.push_back('\\'); + } else if (*iter == 'n') { + ret.push_back('\n'); + } else if (*iter == 't') { + ret.push_back('\t'); + } + } else { + ret.push_back(*iter); + } + } + + return ret; +} + +bool ReadStrings(istream& in, StringTable& strings, bool unescape) { + while (!in.eof()) { + string line; + std::getline(in, line); + int sep = line.find('='); + if (sep >= 0) { + string key, value; + key = line.substr(0, sep); + value = line.substr(sep + 1); + if (unescape) value = Unescape(value); + strings[key] = value; + } + } + + return true; +} + +bool ReadStringsFromFile(const string& path, StringTable& strings, + bool unescape) { + ifstream* f = UIOpenRead(path, ios::in); + bool success = false; + if (f->is_open()) { + success = ReadStrings(*f, strings, unescape); + f->close(); + } + + delete f; + return success; +} + +static bool ReadExtraFile(const string& aExtraDataPath, Json::Value& aExtra) { + bool success = false; + ifstream* f = UIOpenRead(aExtraDataPath, ios::in); + if (f->is_open()) { + Json::CharReaderBuilder builder; + success = parseFromStream(builder, *f, &aExtra, nullptr); + } + + delete f; + return success; +} + +static string Basename(const string& file) { + string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR); + if (slashIndex != string::npos) { + return file.substr(slashIndex + 1); + } + return file; +} + +static bool ReadEventFile(const string& aPath, string& aEventVersion, + string& aTime, string& aUuid, Json::Value& aData) { + bool res = false; + ifstream* f = UIOpenRead(aPath, ios::binary); + + if (f->is_open()) { + std::getline(*f, aEventVersion, '\n'); + res = f->good(); + std::getline(*f, aTime, '\n'); + res &= f->good(); + std::getline(*f, aUuid, '\n'); + res &= f->good(); + + if (res) { + Json::CharReaderBuilder builder; + res = parseFromStream(builder, *f, &aData, nullptr); + } + } + + delete f; + return res; +} + +static void OverwriteEventFile(const string& aPath, const string& aEventVersion, + const string& aTime, const string& aUuid, + const Json::Value& aData) { + ofstream* f = UIOpenWrite(aPath, ios::binary | ios::trunc); + if (f->is_open()) { + f->write(aEventVersion.c_str(), aEventVersion.length()) << '\n'; + f->write(aTime.c_str(), aTime.length()) << '\n'; + f->write(aUuid.c_str(), aUuid.length()) << '\n'; + + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + std::unique_ptr writer(builder.newStreamWriter()); + writer->write(aData, f); + *f << "\n"; + } + + delete f; +} + +static void UpdateEventFile(const Json::Value& aExtraData, const string& aHash, + const string& aPingUuid) { + if (gEventsPath.empty()) { + // If there is no path for finding the crash event, skip this step. + return; + } + + string localId = CrashReporter::GetDumpLocalID(); + string path = gEventsPath + UI_DIR_SEPARATOR + localId; + string eventVersion; + string crashTime; + string crashUuid; + Json::Value eventData; + + if (!ReadEventFile(path, eventVersion, crashTime, crashUuid, eventData)) { + return; + } + + if (!aHash.empty()) { + eventData["MinidumpSha256Hash"] = aHash; + } + + if (!aPingUuid.empty()) { + eventData["CrashPingUUID"] = aPingUuid; + } + + if (aExtraData.isMember("StackTraces")) { + eventData["StackTraces"] = aExtraData["StackTraces"]; + } + + OverwriteEventFile(path, eventVersion, crashTime, crashUuid, eventData); +} + +static void WriteSubmissionEvent(SubmissionResult result, + const string& remoteId) { + if (gEventsPath.empty()) { + // If there is no path for writing the submission event, skip it. + return; + } + + string localId = CrashReporter::GetDumpLocalID(); + string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission"; + ofstream* f = UIOpenWrite(fpath, ios::binary); + time_t tm; + time(&tm); + + if (f->is_open()) { + *f << "crash.submission.1\n"; + *f << tm << "\n"; + *f << localId << "\n"; + *f << (result == Succeeded ? "true" : "false") << "\n"; + *f << remoteId; + + f->close(); + } + + delete f; +} + +void LogMessage(const std::string& message) { + if (gLogStream.get()) { + char date[64]; + time_t tm; + time(&tm); + if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0) + date[0] = '\0'; + (*gLogStream) << "[" << date << "] " << message << '\n'; + } +} + +static void OpenLogFile() { + string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log"; + gLogStream.reset(UIOpenWrite(logPath, ios::app)); +} + +static bool ReadConfig() { + string iniPath; + if (!UIGetIniPath(iniPath)) { + return false; + } + + if (!ReadStringsFromFile(iniPath, gStrings, true)) return false; + + // See if we have a string override file, if so process it + char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE"); + if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv)) + ReadStringsFromFile(overrideEnv, gStrings, true); + + return true; +} + +static string GetAdditionalFilename(const string& dumpfile, + const char* extension) { + string filename(dumpfile); + int dot = filename.rfind('.'); + if (dot < 0) return ""; + + filename.replace(dot, filename.length() - dot, extension); + return filename; +} + +static bool MoveCrashData(const string& toDir, string& dumpfile, + string& extrafile, string& memoryfile) { + if (!UIEnsurePathExists(toDir)) { + UIError(gStrings[ST_ERROR_CREATEDUMPDIR]); + return false; + } + + string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile); + string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile); + string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile); + + if (!UIMoveFile(dumpfile, newDump)) { + UIError(gStrings[ST_ERROR_DUMPFILEMOVE]); + return false; + } + + if (!UIMoveFile(extrafile, newExtra)) { + UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]); + return false; + } + + if (!memoryfile.empty()) { + // Ignore errors from moving the memory file + if (!UIMoveFile(memoryfile, newMemory)) { + UIDeleteFile(memoryfile); + newMemory.erase(); + } + memoryfile = newMemory; + } + + dumpfile = newDump; + extrafile = newExtra; + + return true; +} + +static bool AddSubmittedReport(const string& serverResponse) { + StringTable responseItems; + istringstream in(serverResponse); + ReadStrings(in, responseItems, false); + + if (responseItems.find("StopSendingReportsFor") != responseItems.end()) { + // server wants to tell us to stop sending reports for a certain version + string reportPath = gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + + responseItems["StopSendingReportsFor"]; + + ofstream* reportFile = UIOpenWrite(reportPath, ios::trunc); + if (reportFile->is_open()) { + // don't really care about the contents + *reportFile << 1 << "\n"; + reportFile->close(); + } + delete reportFile; + } + + if (responseItems.find("Discarded") != responseItems.end()) { + // server discarded this report... save it so the user can resubmit it + // manually + return false; + } + + if (responseItems.find("CrashID") == responseItems.end()) return false; + + string submittedDir = gSettingsPath + UI_DIR_SEPARATOR + "submitted"; + if (!UIEnsurePathExists(submittedDir)) { + return false; + } + + string path = + submittedDir + UI_DIR_SEPARATOR + responseItems["CrashID"] + ".txt"; + + ofstream* file = UIOpenWrite(path, ios::trunc); + if (!file->is_open()) { + delete file; + return false; + } + + char buf[1024]; + snprintf(buf, 1024, gStrings["CrashID"].c_str(), + responseItems["CrashID"].c_str()); + *file << buf << "\n"; + + if (responseItems.find("ViewURL") != responseItems.end()) { + snprintf(buf, 1024, gStrings["CrashDetailsURL"].c_str(), + responseItems["ViewURL"].c_str()); + *file << buf << "\n"; + } + + file->close(); + delete file; + + WriteSubmissionEvent(Succeeded, responseItems["CrashID"]); + return true; +} + +void DeleteDump() { + const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP"); + if (!noDelete || *noDelete == '\0') { + if (!gReporterDumpFile.empty()) UIDeleteFile(gReporterDumpFile); + if (!gExtraFile.empty()) UIDeleteFile(gExtraFile); + if (!gMemoryFile.empty()) UIDeleteFile(gMemoryFile); + } +} + +void SendCompleted(bool success, const string& serverResponse) { + if (success) { + if (AddSubmittedReport(serverResponse)) { + DeleteDump(); + } else { + string directory = gReporterDumpFile; + int slashpos = directory.find_last_of("/\\"); + if (slashpos < 2) return; + directory.resize(slashpos); + UIPruneSavedDumps(directory); + WriteSubmissionEvent(Failed, ""); + } + } else { + WriteSubmissionEvent(Failed, ""); + } +} + +static string ComputeDumpHash() { +#ifdef XP_LINUX + // On Linux we rely on the system-provided libcurl which uses nss so we have + // to also use the system-provided nss instead of the ones we have bundled. + const char* libnssNames[] = { + "libnss3.so", +# ifndef HAVE_64BIT_BUILD + // 32-bit versions on 64-bit hosts + "/usr/lib32/libnss3.so", +# endif + }; + void* lib = nullptr; + + for (const char* libname : libnssNames) { + lib = dlopen(libname, RTLD_NOW); + + if (lib) { + break; + } + } + + if (!lib) { + return ""; + } + + SECStatus (*NSS_Initialize)(const char*, const char*, const char*, + const char*, PRUint32); + HASHContext* (*HASH_Create)(HASH_HashType); + void (*HASH_Destroy)(HASHContext*); + void (*HASH_Begin)(HASHContext*); + void (*HASH_Update)(HASHContext*, const unsigned char*, unsigned int); + void (*HASH_End)(HASHContext*, unsigned char*, unsigned int*, unsigned int); + + *(void**)(&NSS_Initialize) = dlsym(lib, "NSS_Initialize"); + *(void**)(&HASH_Create) = dlsym(lib, "HASH_Create"); + *(void**)(&HASH_Destroy) = dlsym(lib, "HASH_Destroy"); + *(void**)(&HASH_Begin) = dlsym(lib, "HASH_Begin"); + *(void**)(&HASH_Update) = dlsym(lib, "HASH_Update"); + *(void**)(&HASH_End) = dlsym(lib, "HASH_End"); + + if (!HASH_Create || !HASH_Destroy || !HASH_Begin || !HASH_Update || + !HASH_End) { + return ""; + } +#endif + // Minimal NSS initialization so we can use the hash functions + const PRUint32 kNssFlags = NSS_INIT_READONLY | NSS_INIT_NOROOTINIT | + NSS_INIT_NOMODDB | NSS_INIT_NOCERTDB; + if (NSS_Initialize(nullptr, "", "", "", kNssFlags) != SECSuccess) { + return ""; + } + + HASHContext* hashContext = HASH_Create(HASH_AlgSHA256); + + if (!hashContext) { + return ""; + } + + HASH_Begin(hashContext); + + ifstream* f = UIOpenRead(gReporterDumpFile, ios::binary); + bool error = false; + + // Read the minidump contents + if (f->is_open()) { + uint8_t buff[4096]; + + do { + f->read((char*)buff, sizeof(buff)); + + if (f->bad()) { + error = true; + break; + } + + HASH_Update(hashContext, buff, f->gcount()); + } while (!f->eof()); + + f->close(); + } else { + error = true; + } + + delete f; + + // Finalize the hash computation + uint8_t result[SHA256_LENGTH]; + uint32_t resultLen = 0; + + HASH_End(hashContext, result, &resultLen, SHA256_LENGTH); + + if (resultLen != SHA256_LENGTH) { + error = true; + } + + HASH_Destroy(hashContext); + + if (!error) { + ostringstream hash; + + for (size_t i = 0; i < SHA256_LENGTH; i++) { + hash << std::setw(2) << std::setfill('0') << std::hex + << static_cast(result[i]); + } + + return hash.str(); + } + return ""; // If we encountered an error, return an empty hash +} + +string GetDumpLocalID() { + string localId = Basename(gReporterDumpFile); + string::size_type dot = localId.rfind('.'); + + if (dot == string::npos) return ""; + + return localId.substr(0, dot); +} + +string GetProgramPath(const string& exename) { + string path = gArgv[0]; + size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX); + path.erase(pos); +#ifdef XP_MACOSX + // On macOS the crash reporter client is shipped as an application bundle + // contained within Firefox' main application bundle. So when it's invoked + // its current working directory looks like: + // Firefox.app/Contents/MacOS/crashreporter.app/Contents/MacOS/ + // The other applications we ship with Firefox are stored in the main bundle + // (Firefox.app/Contents/MacOS/) so we we need to go back three directories + // to reach them. + path.erase(pos - 1); + for (size_t i = 0; i < 3; i++) { + pos = path.rfind(UI_DIR_SEPARATOR, pos - 1); + } + + path.erase(pos + 1); +#endif // XP_MACOSX + path.append(exename + BIN_SUFFIX); + + return path; +} + +} // namespace CrashReporter + +using namespace CrashReporter; + +Json::Value kEmptyJsonString(""); + +void RewriteStrings(Json::Value& aExtraData) { + // rewrite some UI strings with the values from the query parameters + string product = aExtraData.get("ProductName", kEmptyJsonString).asString(); + Json::Value mozilla("Mozilla"); + string vendor = aExtraData.get("Vendor", mozilla).asString(); + + char buf[4096]; + snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(), + vendor.c_str()); + gStrings[ST_CRASHREPORTERTITLE] = buf; + + string str = gStrings[ST_CRASHREPORTERPRODUCTERROR]; + // Only do the replacement here if the string has two + // format specifiers to start. Otherwise + // we assume it has the product name hardcoded. + string::size_type pos = str.find("%s"); + if (pos != string::npos) pos = str.find("%s", pos + 2); + if (pos != string::npos) { + // Leave a format specifier for UIError to fill in + snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(), + product.c_str(), "%s"); + gStrings[ST_CRASHREPORTERERROR] = buf; + } else { + // product name is hardcoded + gStrings[ST_CRASHREPORTERERROR] = str; + } + + snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(), + product.c_str()); + gStrings[ST_CRASHREPORTERDESCRIPTION] = buf; + + snprintf(buf, sizeof(buf), gStrings[ST_CHECKSUBMIT].c_str(), vendor.c_str()); + gStrings[ST_CHECKSUBMIT] = buf; + + snprintf(buf, sizeof(buf), gStrings[ST_RESTART].c_str(), product.c_str()); + gStrings[ST_RESTART] = buf; + + snprintf(buf, sizeof(buf), gStrings[ST_QUIT].c_str(), product.c_str()); + gStrings[ST_QUIT] = buf; + + snprintf(buf, sizeof(buf), gStrings[ST_ERROR_ENDOFLIFE].c_str(), + product.c_str()); + gStrings[ST_ERROR_ENDOFLIFE] = buf; +} + +bool CheckEndOfLifed(const Json::Value& aVersion) { + if (!aVersion.isString()) { + return false; + } + + string reportPath = + gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + aVersion.asString(); + return UIFileExists(reportPath); +} + +int main(int argc, char** argv) { + gArgc = argc; + gArgv = argv; + + string autoSubmitEnv = UIGetEnv("MOZ_CRASHREPORTER_AUTO_SUBMIT"); + gAutoSubmit = !autoSubmitEnv.empty(); + + if (!ReadConfig()) { + UIError("Couldn't read configuration."); + return 0; + } + + if (!UIInit()) { + return 0; + } + + if (argc > 1) { + gReporterDumpFile = argv[1]; + } + + if (gReporterDumpFile.empty()) { + // no dump file specified, run the default UI + if (!gAutoSubmit) { + UIShowDefaultUI(); + } + } else { + // Start by running minidump analyzer to gather stack traces. + string reporterDumpFile = gReporterDumpFile; + vector args = {reporterDumpFile}; + string dumpAllThreadsEnv = UIGetEnv("MOZ_CRASHREPORTER_DUMP_ALL_THREADS"); + if (!dumpAllThreadsEnv.empty()) { + args.insert(args.begin(), "--full"); + } + UIRunProgram(CrashReporter::GetProgramPath(UI_MINIDUMP_ANALYZER_FILENAME), + args, + /* wait */ true); + + // go ahead with the crash reporter + gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension); + if (gExtraFile.empty()) { + UIError(gStrings[ST_ERROR_BADARGUMENTS]); + return 0; + } + + if (!UIFileExists(gExtraFile)) { + UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]); + return 0; + } + + gMemoryFile = + GetAdditionalFilename(gReporterDumpFile, kMemoryReportExtension); + if (!UIFileExists(gMemoryFile)) { + gMemoryFile.erase(); + } + + Json::Value extraData; + if (!ReadExtraFile(gExtraFile, extraData)) { + UIError(gStrings[ST_ERROR_EXTRAFILEREAD]); + return 0; + } + + if (!extraData.isMember("ProductName")) { + UIError(gStrings[ST_ERROR_NOPRODUCTNAME]); + return 0; + } + + // There is enough information in the extra file to rewrite strings + // to be product specific + RewriteStrings(extraData); + + if (!extraData.isMember("ServerURL")) { + UIError(gStrings[ST_ERROR_NOSERVERURL]); + return 0; + } + + // Hopefully the settings path exists in the environment. Try that before + // asking the platform-specific code to guess. + gSettingsPath = UIGetEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY"); + if (gSettingsPath.empty()) { + string product = + extraData.get("ProductName", kEmptyJsonString).asString(); + string vendor = extraData.get("Vendor", kEmptyJsonString).asString(); + + if (!UIGetSettingsPath(vendor, product, gSettingsPath)) { + gSettingsPath.clear(); + } + } + + if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) { + UIError(gStrings[ST_ERROR_NOSETTINGSPATH]); + return 0; + } + + OpenLogFile(); + + gEventsPath = UIGetEnv("MOZ_CRASHREPORTER_EVENTS_DIRECTORY"); + gPingPath = UIGetEnv("MOZ_CRASHREPORTER_PING_DIRECTORY"); + + // Assemble and send the crash ping + string hash = ComputeDumpHash(); + + string pingUuid; + SendCrashPing(extraData, hash, pingUuid, gPingPath); + UpdateEventFile(extraData, hash, pingUuid); + + if (!UIFileExists(gReporterDumpFile)) { + UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]); + return 0; + } + + string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending"; + if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile, + gMemoryFile)) { + return 0; + } + + string sendURL = extraData.get("ServerURL", kEmptyJsonString).asString(); + // we don't need to actually send these + extraData.removeMember("ServerURL"); + extraData.removeMember("StackTraces"); + + extraData["SubmittedFrom"] = "Client"; + extraData["Throttleable"] = "1"; + + // re-set XUL_APP_FILE for xulrunner wrapped apps + const char* appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE"); + if (appfile && *appfile) { + const char prefix[] = "XUL_APP_FILE="; + char* env = (char*)malloc(strlen(appfile) + strlen(prefix) + 1); + if (!env) { + UIError("Out of memory"); + return 0; + } + strcpy(env, prefix); + strcat(env, appfile); + putenv(env); + free(env); + } + + vector restartArgs; + + if (!extraData.isMember("WindowsErrorReporting")) { + // We relaunch the application associated with the client, but only when + // we encountered a crash caught by the exception handler. Crashes handled + // by WER are prevented from directly restarting the application. + string programPath = GetProgramPath(MOZ_APP_NAME); +#ifndef XP_WIN + const char* moz_app_launcher = getenv("MOZ_APP_LAUNCHER"); + if (moz_app_launcher) { + programPath = moz_app_launcher; + } +#endif // XP_WIN + + restartArgs.push_back(programPath); + + ostringstream paramName; + int i = 1; + paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; + const char* param = getenv(paramName.str().c_str()); + while (param && *param) { + restartArgs.push_back(param); + + paramName.str(""); + paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; + param = getenv(paramName.str().c_str()); + } + } + + // allow override of the server url via environment variable + // XXX: remove this in the far future when our robot + // masters force everyone to use XULRunner + char* urlEnv = getenv("MOZ_CRASHREPORTER_URL"); + if (urlEnv && *urlEnv) { + sendURL = urlEnv; + } + + // see if this version has been end-of-lifed + + if (extraData.isMember("Version") && + CheckEndOfLifed(extraData["Version"])) { + UIError(gStrings[ST_ERROR_ENDOFLIFE]); + DeleteDump(); + return 0; + } + + StringTable files; + files["upload_file_minidump"] = gReporterDumpFile; + if (!gMemoryFile.empty()) { + files["memory_report"] = gMemoryFile; + } + + if (!UIShowCrashUI(files, extraData, sendURL, restartArgs)) { + DeleteDump(); + } + } + + UIShutdown(); + + return 0; +} + +#if defined(XP_WIN) && !defined(__GNUC__) +# include + +// We need WinMain in order to not be a console app. This function is unused +// if we are a console application. +int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR args, int) { + // Remove everything except close window from the context menu + { + HKEY hkApp; + RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0, + nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr, + &hkApp, nullptr); + RegCloseKey(hkApp); + if (RegCreateKeyExW(HKEY_CURRENT_USER, + L"Software\\Classes\\Applications\\crashreporter.exe", + 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr, + &hkApp, nullptr) == ERROR_SUCCESS) { + RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0); + RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0); + RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0); + RegCloseKey(hkApp); + } + } + + char** argv = static_cast(malloc(__argc * sizeof(char*))); + for (int i = 0; i < __argc; i++) { + argv[i] = strdup(WideToUTF8(__wargv[i]).c_str()); + } + + // Do the real work. + return main(__argc, argv); +} +#endif diff --git a/toolkit/crashreporter/client/crashreporter.exe.manifest b/toolkit/crashreporter/client/crashreporter.exe.manifest new file mode 100644 index 0000000000..81aa1465c6 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.exe.manifest @@ -0,0 +1,42 @@ + + + +Crash Reporter + + + + + + + + + + + + + + + true + + + + + + + + + + + diff --git a/toolkit/crashreporter/client/crashreporter.h b/toolkit/crashreporter/client/crashreporter.h new file mode 100644 index 0000000000..fa7085da18 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.h @@ -0,0 +1,158 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CRASHREPORTER_H__ +#define CRASHREPORTER_H__ + +#ifdef _MSC_VER +# pragma warning(push) +// Disable exception handler warnings. +# pragma warning(disable : 4530) +#endif + +#include +#include +#include +#include +#include +#include + +#define MAX_COMMENT_LENGTH 10000 + +#if defined(XP_WIN) + +# include + +# define UI_DIR_SEPARATOR "\\" + +std::string WideToUTF8(const std::wstring& wide, bool* success = 0); + +#else + +# define UI_DIR_SEPARATOR "/" + +#endif + +#include "json/json.h" + +#define UI_CRASH_REPORTER_FILENAME "crashreporter" +#define UI_MINIDUMP_ANALYZER_FILENAME "minidump-analyzer" +#define UI_PING_SENDER_FILENAME "pingsender" + +typedef std::map StringTable; + +#define ST_CRASHREPORTERTITLE "CrashReporterTitle" +#define ST_CRASHREPORTERVENDORTITLE "CrashReporterVendorTitle" +#define ST_CRASHREPORTERERROR "CrashReporterErrorText" +#define ST_CRASHREPORTERPRODUCTERROR "CrashReporterProductErrorText2" +#define ST_CRASHREPORTERHEADER "CrashReporterSorry" +#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescriptionText2" +#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault" +#define ST_VIEWREPORT "Details" +#define ST_VIEWREPORTTITLE "ViewReportTitle" +#define ST_COMMENTGRAYTEXT "CommentGrayText" +#define ST_EXTRAREPORTINFO "ExtraReportInfo" +#define ST_CHECKSUBMIT "CheckSendReport" +#define ST_CHECKURL "CheckIncludeURL" +#define ST_REPORTPRESUBMIT "ReportPreSubmit2" +#define ST_REPORTDURINGSUBMIT "ReportDuringSubmit2" +#define ST_REPORTSUBMITSUCCESS "ReportSubmitSuccess" +#define ST_SUBMITFAILED "ReportSubmitFailed" +#define ST_QUIT "Quit2" +#define ST_RESTART "Restart" +#define ST_OK "Ok" +#define ST_CLOSE "Close" + +#define ST_ERROR_BADARGUMENTS "ErrorBadArguments" +#define ST_ERROR_EXTRAFILEEXISTS "ErrorExtraFileExists" +#define ST_ERROR_EXTRAFILEREAD "ErrorExtraFileRead" +#define ST_ERROR_EXTRAFILEMOVE "ErrorExtraFileMove" +#define ST_ERROR_DUMPFILEEXISTS "ErrorDumpFileExists" +#define ST_ERROR_DUMPFILEMOVE "ErrorDumpFileMove" +#define ST_ERROR_NOPRODUCTNAME "ErrorNoProductName" +#define ST_ERROR_NOSERVERURL "ErrorNoServerURL" +#define ST_ERROR_NOSETTINGSPATH "ErrorNoSettingsPath" +#define ST_ERROR_CREATEDUMPDIR "ErrorCreateDumpDir" +#define ST_ERROR_ENDOFLIFE "ErrorEndOfLife" + +//============================================================================= +// implemented in crashreporter.cpp and ping.cpp +//============================================================================= + +namespace CrashReporter { +extern StringTable gStrings; +extern std::string gSettingsPath; +extern std::string gEventsPath; +extern int gArgc; +extern char** gArgv; +extern bool gAutoSubmit; + +void UIError(const std::string& message); + +// The UI finished sending the report +void SendCompleted(bool success, const std::string& serverResponse); + +bool ReadStrings(std::istream& in, StringTable& strings, bool unescape); +bool ReadStringsFromFile(const std::string& path, StringTable& strings, + bool unescape); +void LogMessage(const std::string& message); +void DeleteDump(); + +std::string GetDumpLocalID(); +std::string GetProgramPath(const std::string& exename); + +// Telemetry ping +bool SendCrashPing(Json::Value& extra, const std::string& hash, + std::string& pingUuid, const std::string& pingDir); + +static const unsigned int kSaveCount = 10; +} // namespace CrashReporter + +//============================================================================= +// implemented in the platform-specific files +//============================================================================= + +bool UIInit(); +void UIShutdown(); + +// Run the UI for when the app was launched without a dump file +void UIShowDefaultUI(); + +// Run the UI for when the app was launched with a dump file +// Return true if the user sent (or tried to send) the crash report, +// false if they chose not to, and it should be deleted. +bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, + const std::string& sendURL, + const std::vector& restartArgs); + +void UIError_impl(const std::string& message); + +bool UIGetIniPath(std::string& path); +bool UIGetSettingsPath(const std::string& vendor, const std::string& product, + std::string& settingsPath); +bool UIEnsurePathExists(const std::string& path); +bool UIFileExists(const std::string& path); +bool UIMoveFile(const std::string& oldfile, const std::string& newfile); +bool UIDeleteFile(const std::string& oldfile); +std::ifstream* UIOpenRead(const std::string& filename, + std::ios_base::openmode mode); +std::ofstream* UIOpenWrite(const std::string& filename, + std::ios_base::openmode mode); +void UIPruneSavedDumps(const std::string& directory); + +// Run the program specified by exename, passing it the parameters in arg. +// If wait is true, wait for the program to terminate execution before +// returning. Returns true if the program was launched correctly, false +// otherwise. +bool UIRunProgram(const std::string& exename, + const std::vector& args, bool wait = false); + +// Read the environment variable specified by name +std::string UIGetEnv(const std::string& name); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/toolkit/crashreporter/client/crashreporter.ico b/toolkit/crashreporter/client/crashreporter.ico new file mode 100644 index 0000000000..29ac3c6189 Binary files /dev/null and b/toolkit/crashreporter/client/crashreporter.ico differ diff --git a/toolkit/crashreporter/client/crashreporter.rc b/toolkit/crashreporter/client/crashreporter.rc new file mode 100755 index 0000000000..f6042bf2e5 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter.rc @@ -0,0 +1,143 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winresrc.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winresrc.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAINICON ICON "crashreporter.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// AVI +// + +IDR_THROBBER AVI "Throbber-small.avi" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SENDDIALOG DIALOGEX 0, 0, 241, 187 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Sending Crash Report..." +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_DESCRIPTIONTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY,8,7,226,12,WS_EX_TRANSPARENT + CONTROL "tell mozilla about this crash so they can fix it",IDC_SUBMITREPORTCHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,25,222,10 + CHECKBOX "details...",IDC_VIEWREPORTBUTTON,24,40,54,14,BS_PUSHLIKE + EDITTEXT IDC_COMMENTTEXT,24,59,210,43,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + CONTROL "include the address of the page i was on",IDC_INCLUDEURLCHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,107,210,10 + CONTROL "",IDC_THROBBER,"SysAnimate32",ACS_TRANSPARENT | NOT WS_VISIBLE | WS_TABSTOP,4,152,16,16 + LTEXT "your crash report will be submitted when you restart",IDC_PROGRESSTEXT,24,152,210,10,SS_NOPREFIX + DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,84,166,68,14 + PUSHBUTTON "quit without sending",IDC_CLOSEBUTTON,157,166,77,14 +END + +IDD_VIEWREPORTDIALOG DIALOGEX 0, 0, 208, 126 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "view report" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_VIEWREPORTTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,194,92 + DEFPUSHBUTTON "OK",IDOK,151,105,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_SENDDIALOG, DIALOG + BEGIN + LEFTMARGIN, 8 + RIGHTMARGIN, 234 + TOPMARGIN, 7 + BOTTOMMARGIN, 180 + END + + IDD_VIEWREPORTDIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 201 + TOPMARGIN, 7 + BOTTOMMARGIN, 119 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp new file mode 100644 index 0000000000..b9a957cfd9 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp @@ -0,0 +1,361 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/linux/http_upload.h" +#include "crashreporter.h" +#include "crashreporter_gtk_common.h" + +#ifndef GDK_KEY_Escape +# define GDK_KEY_Escape GDK_Escape +#endif + +using std::string; +using std::vector; + +using namespace CrashReporter; + +GtkWidget* gWindow = 0; +GtkWidget* gSubmitReportCheck = 0; +GtkWidget* gIncludeURLCheck = 0; +GtkWidget* gThrobber = 0; +GtkWidget* gProgressLabel = 0; +GtkWidget* gCloseButton = 0; +GtkWidget* gRestartButton = 0; + +bool gInitialized = false; +bool gDidTrySend = false; +StringTable gFiles; +Json::Value gQueryParameters; +string gHttpProxy; +string gAuth; +string gCACertificateFile; +string gSendURL; +string gURLParameter; +vector gRestartArgs; +GThread* gSendThreadID; + +// From crashreporter_linux.cpp +void SendReport(); +void DisableGUIAndSendReport(); +void TryInitGnome(); +void UpdateSubmit(); + +static bool RestartApplication() { + char** argv = reinterpret_cast( + malloc(sizeof(char*) * (gRestartArgs.size() + 1))); + + if (!argv) return false; + + unsigned int i; + for (i = 0; i < gRestartArgs.size(); i++) { + argv[i] = (char*)gRestartArgs[i].c_str(); + } + argv[i] = 0; + + pid_t pid = fork(); + if (pid == -1) { + free(argv); + return false; + } + + if (pid == 0) { + (void)execv(argv[0], argv); + _exit(1); + } + + free(argv); + + return true; +} + +// Quit the app, used as a timeout callback +gboolean CloseApp(gpointer data) { + if (!gAutoSubmit) { + gtk_main_quit(); + } + g_thread_join(gSendThreadID); + return FALSE; +} + +static gboolean ReportCompleted(gpointer success) { + gtk_widget_hide(gThrobber); + string str = + success ? gStrings[ST_REPORTSUBMITSUCCESS] : gStrings[ST_SUBMITFAILED]; + gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str()); + g_timeout_add(5000, CloseApp, 0); + return FALSE; +} + +#define HTTP_PROXY_DIR "/system/http_proxy" + +void LoadProxyinfo() { + class GConfClient; + typedef GConfClient* (*_gconf_default_fn)(); + typedef gboolean (*_gconf_bool_fn)(GConfClient*, const gchar*, GError**); + typedef gint (*_gconf_int_fn)(GConfClient*, const gchar*, GError**); + typedef gchar* (*_gconf_string_fn)(GConfClient*, const gchar*, GError**); + + if (getenv("http_proxy")) + return; // libcurl can use the value from the environment + + static void* gconfLib = dlopen("libgconf-2.so.4", RTLD_LAZY); + if (!gconfLib) return; + + _gconf_default_fn gconf_client_get_default = + (_gconf_default_fn)dlsym(gconfLib, "gconf_client_get_default"); + _gconf_bool_fn gconf_client_get_bool = + (_gconf_bool_fn)dlsym(gconfLib, "gconf_client_get_bool"); + _gconf_int_fn gconf_client_get_int = + (_gconf_int_fn)dlsym(gconfLib, "gconf_client_get_int"); + _gconf_string_fn gconf_client_get_string = + (_gconf_string_fn)dlsym(gconfLib, "gconf_client_get_string"); + + if (!(gconf_client_get_default && gconf_client_get_bool && + gconf_client_get_int && gconf_client_get_string)) { + dlclose(gconfLib); + return; + } + + GConfClient* conf = gconf_client_get_default(); + + if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_http_proxy", nullptr)) { + gint port; + gchar *host = nullptr, *httpproxy = nullptr; + + host = gconf_client_get_string(conf, HTTP_PROXY_DIR "/host", nullptr); + port = gconf_client_get_int(conf, HTTP_PROXY_DIR "/port", nullptr); + + if (port && host && *host != '\0') { + httpproxy = g_strdup_printf("http://%s:%d/", host, port); + gHttpProxy = httpproxy; + } + + g_free(host); + g_free(httpproxy); + + if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_authentication", + nullptr)) { + gchar *user, *password, *auth = nullptr; + + user = gconf_client_get_string( + conf, HTTP_PROXY_DIR "/authentication_user", nullptr); + password = gconf_client_get_string( + conf, HTTP_PROXY_DIR "/authentication_password", nullptr); + + if (user && password) { + auth = g_strdup_printf("%s:%s", user, password); + gAuth = auth; + } + + g_free(user); + g_free(password); + g_free(auth); + } + } + + g_object_unref(conf); + + // Don't dlclose gconfLib as libORBit-2 uses atexit(). +} + +gpointer SendThread(gpointer args) { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string parameters(writeString(builder, gQueryParameters)); + + string response, error; + long response_code; + + bool success = google_breakpad::HTTPUpload::SendRequest( + gSendURL, parameters, gFiles, gHttpProxy, gAuth, gCACertificateFile, + &response, &response_code, &error); + if (success) { + LogMessage("Crash report submitted successfully"); + } else { + LogMessage("Crash report submission failed: " + error); + } + + SendCompleted(success, response); + + if (!gAutoSubmit) { + // Apparently glib is threadsafe, and will schedule this + // on the main thread, see: + // http://library.gnome.org/devel/gtk-faq/stable/x499.html + g_idle_add(ReportCompleted, (gpointer)success); + } + + return nullptr; +} + +gboolean WindowDeleted(GtkWidget* window, GdkEvent* event, gpointer userData) { + SaveSettings(); + gtk_main_quit(); + return TRUE; +} + +gboolean check_escape(GtkWidget* window, GdkEventKey* event, + gpointer userData) { + if (event->keyval == GDK_KEY_Escape) { + gtk_main_quit(); + return TRUE; + } + return FALSE; +} + +static void MaybeSubmitReport() { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) { + gDidTrySend = true; + DisableGUIAndSendReport(); + } else { + gtk_main_quit(); + } +} + +void CloseClicked(GtkButton* button, gpointer userData) { + SaveSettings(); + MaybeSubmitReport(); +} + +void RestartClicked(GtkButton* button, gpointer userData) { + SaveSettings(); + RestartApplication(); + MaybeSubmitReport(); +} + +static void UpdateURL() { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) { + gQueryParameters["URL"] = gURLParameter; + } else { + gQueryParameters.removeMember("URL"); + } +} + +void SubmitReportChecked(GtkButton* sender, gpointer userData) { + UpdateSubmit(); +} + +void IncludeURLClicked(GtkButton* sender, gpointer userData) { UpdateURL(); } + +/* === Crashreporter UI Functions === */ + +bool UIInit() { + // breakpad probably left us with blocked signals, unblock them here + sigset_t signals, old; + sigfillset(&signals); + sigprocmask(SIG_UNBLOCK, &signals, &old); + + // tell glib we're going to use threads + g_thread_init(nullptr); + + if (gtk_init_check(&gArgc, &gArgv)) { + gInitialized = true; + + if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") + gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL); + + return true; + } + + return false; +} + +void UIShowDefaultUI() { + GtkWidget* errorDialog = gtk_message_dialog_new( + nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", + gStrings[ST_CRASHREPORTERDEFAULT].c_str()); + + gtk_window_set_title(GTK_WINDOW(errorDialog), + gStrings[ST_CRASHREPORTERTITLE].c_str()); + gtk_dialog_run(GTK_DIALOG(errorDialog)); +} + +void UIError_impl(const string& message) { + if (!gInitialized) { + // Didn't initialize, this is the best we can do + printf("Error: %s\n", message.c_str()); + return; + } + + GtkWidget* errorDialog = + gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, "%s", message.c_str()); + + gtk_window_set_title(GTK_WINDOW(errorDialog), + gStrings[ST_CRASHREPORTERTITLE].c_str()); + gtk_dialog_run(GTK_DIALOG(errorDialog)); +} + +bool UIGetIniPath(string& path) { + path = gArgv[0]; + path.append(".ini"); + + return true; +} + +/* + * Settings are stored in ~/.vendor/product, or + * ~/.product if vendor is empty. + */ +bool UIGetSettingsPath(const string& vendor, const string& product, + string& settingsPath) { + char* home = getenv("HOME"); + + if (!home) return false; + + settingsPath = home; + settingsPath += "/."; + if (!vendor.empty()) { + string lc_vendor; + std::transform(vendor.begin(), vendor.end(), back_inserter(lc_vendor), + (int (*)(int))std::tolower); + settingsPath += lc_vendor + "/"; + } + string lc_product; + std::transform(product.begin(), product.end(), back_inserter(lc_product), + (int (*)(int))std::tolower); + settingsPath += lc_product + "/Crash Reports"; + return true; +} + +bool UIMoveFile(const string& file, const string& newfile) { + if (!rename(file.c_str(), newfile.c_str())) return true; + if (errno != EXDEV) return false; + + // use system /bin/mv instead, time to fork + pid_t pID = vfork(); + if (pID < 0) { + // Failed to fork + return false; + } + if (pID == 0) { + char* const args[4] = {const_cast("mv"), strdup(file.c_str()), + strdup(newfile.c_str()), 0}; + if (args[1] && args[2]) execve("/bin/mv", args, 0); + free(args[1]); + free(args[2]); + exit(-1); + } + int status; + waitpid(pID, &status, 0); + return UIFileExists(newfile); +} diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.h b/toolkit/crashreporter/client/crashreporter_gtk_common.h new file mode 100644 index 0000000000..208c7ba6b0 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_gtk_common.h @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CRASHREPORTER_GTK_COMMON_H__ +#define CRASHREPORTER_GTK_COMMON_H__ + +#include +#include + +#include +#include + +#include "json/json.h" + +const char kIniFile[] = "crashreporter.ini"; + +extern GtkWidget* gWindow; +extern GtkWidget* gSubmitReportCheck; +extern GtkWidget* gIncludeURLCheck; +extern GtkWidget* gThrobber; +extern GtkWidget* gProgressLabel; +extern GtkWidget* gCloseButton; +extern GtkWidget* gRestartButton; + +extern std::vector gRestartArgs; +extern GThread* gSendThreadID; + +extern bool gInitialized; +extern bool gDidTrySend; +extern StringTable gFiles; +extern Json::Value gQueryParameters; +extern std::string gHttpProxy; +extern std::string gAuth; +extern std::string gCACertificateFile; +extern std::string gSendURL; +extern std::string gURLParameter; + +void LoadProxyinfo(); +gboolean CloseApp(gpointer data); +gpointer SendThread(gpointer args); +gboolean WindowDeleted(GtkWidget* window, GdkEvent* event, gpointer userData); +gboolean check_escape(GtkWidget* window, GdkEventKey* event, gpointer data); +void SubmitReportChecked(GtkButton* sender, gpointer userData); +void IncludeURLClicked(GtkButton* sender, gpointer userData); +void CloseClicked(GtkButton* button, gpointer userData); +void RestartClicked(GtkButton* button, gpointer userData); +void SaveSettings(void); + +#endif // CRASHREPORTER_GTK_COMMON_H__ diff --git a/toolkit/crashreporter/client/crashreporter_linux.cpp b/toolkit/crashreporter/client/crashreporter_linux.cpp new file mode 100644 index 0000000000..644b34654e --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_linux.cpp @@ -0,0 +1,525 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include +#include + +#include + +#include "crashreporter.h" +#include "crashreporter_gtk_common.h" + +#define LABEL_MAX_CHAR_WIDTH 48 + +using std::ios; +using std::string; +using std::vector; + +using namespace CrashReporter; + +static GtkWidget* gViewReportButton = 0; +static GtkWidget* gCommentTextLabel = 0; +static GtkWidget* gCommentText = 0; + +static bool gCommentFieldHint = true; + +// handle from dlopen'ing libgnome +static void* gnomeLib = nullptr; +// handle from dlopen'ing libgnomeui +static void* gnomeuiLib = nullptr; + +static void LoadSettings() { + /* + * NOTE! This code needs to stay in sync with the preference checking + * code in in nsExceptionHandler.cpp. + */ + + bool includeURL = true; + bool submitReport = true; + StringTable settings; + if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) { + if (settings.find("IncludeURL") != settings.end()) { + includeURL = settings["IncludeURL"][0] != '0'; + } + if (settings.find("SubmitReport") != settings.end()) { + submitReport = settings["SubmitReport"][0] != '0'; + } + } + + if (gIncludeURLCheck) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), + includeURL); + } + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck), + submitReport); +} + +static string Escape(const string& str) { + string ret; + for (auto c : str) { + if (c == '\\') { + ret += "\\\\"; + } else if (c == '\n') { + ret += "\\n"; + } else if (c == '\t') { + ret += "\\t"; + } else { + ret.push_back(c); + } + } + + return ret; +} + +static bool WriteStrings(std::ostream& out, const string& header, + StringTable& strings, bool escape) { + out << "[" << header << "]\n"; + for (const auto& iter : strings) { + out << iter.first << "="; + if (escape) { + out << Escape(iter.second); + } else { + out << iter.second; + } + + out << '\n'; + } + + return true; +} + +static bool WriteStringsToFile(const string& path, const string& header, + StringTable& strings, bool escape) { + std::ofstream* f = UIOpenWrite(path, ios::trunc); + bool success = false; + if (f->is_open()) { + success = WriteStrings(*f, header, strings, escape); + f->close(); + } + + delete f; + return success; +} + +void SaveSettings() { + /* + * NOTE! This code needs to stay in sync with the preference setting + * code in in nsExceptionHandler.cpp. + */ + + StringTable settings; + + ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true); + if (gIncludeURLCheck != 0) + settings["IncludeURL"] = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck)) ? "1" + : "0"; + settings["SubmitReport"] = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck)) ? "1" + : "0"; + + WriteStringsToFile(gSettingsPath + "/" + kIniFile, "Crash Reporter", settings, + true); +} + +void SendReport() { + LoadProxyinfo(); + + // spawn a thread to do the sending + gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, nullptr); +} + +void DisableGUIAndSendReport() { + // disable all our gui controls, show the throbber + change the progress text + gtk_widget_set_sensitive(gSubmitReportCheck, FALSE); + gtk_widget_set_sensitive(gViewReportButton, FALSE); + gtk_widget_set_sensitive(gCommentText, FALSE); + if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, FALSE); + gtk_widget_set_sensitive(gCloseButton, FALSE); + if (gRestartButton) gtk_widget_set_sensitive(gRestartButton, FALSE); + gtk_widget_show_all(gThrobber); + gtk_label_set_text(GTK_LABEL(gProgressLabel), + gStrings[ST_REPORTDURINGSUBMIT].c_str()); + + SendReport(); +} + +static void ShowReportInfo(GtkTextView* viewReportTextView) { + GtkTextBuffer* buffer = gtk_text_view_get_buffer(viewReportTextView); + + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + + gtk_text_buffer_delete(buffer, &start, &end); + + for (Json::ValueConstIterator iter = gQueryParameters.begin(); + iter != gQueryParameters.end(); ++iter) { + gtk_text_buffer_insert(buffer, &end, iter.name().c_str(), + iter.name().length()); + gtk_text_buffer_insert(buffer, &end, ": ", -1); + string value; + if (iter->isString()) { + value = iter->asString(); + } else { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + value = writeString(builder, *iter); + } + gtk_text_buffer_insert(buffer, &end, value.c_str(), value.length()); + gtk_text_buffer_insert(buffer, &end, "\n", -1); + } + + gtk_text_buffer_insert(buffer, &end, "\n", -1); + gtk_text_buffer_insert(buffer, &end, gStrings[ST_EXTRAREPORTINFO].c_str(), + -1); +} + +void UpdateSubmit() { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) { + gtk_widget_set_sensitive(gViewReportButton, TRUE); + gtk_widget_set_sensitive(gCommentText, TRUE); + if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, TRUE); + gtk_label_set_text(GTK_LABEL(gProgressLabel), + gStrings[ST_REPORTPRESUBMIT].c_str()); + } else { + gtk_widget_set_sensitive(gViewReportButton, FALSE); + gtk_widget_set_sensitive(gCommentText, FALSE); + if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, FALSE); + gtk_label_set_text(GTK_LABEL(gProgressLabel), ""); + } +} + +static void ViewReportClicked(GtkButton* button, gpointer userData) { + GtkDialog* dialog = GTK_DIALOG(gtk_dialog_new_with_buttons( + gStrings[ST_VIEWREPORTTITLE].c_str(), GTK_WINDOW(gWindow), + GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, nullptr)); + + GtkWidget* scrolled = gtk_scrolled_window_new(0, 0); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), + scrolled); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), + GTK_SHADOW_IN); + gtk_widget_set_vexpand(scrolled, TRUE); + + GtkWidget* viewReportTextView = gtk_text_view_new(); + gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView); + gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView), GTK_WRAP_WORD); + gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100); + + ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView)); + + gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK); + gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200); + gtk_widget_show_all(GTK_WIDGET(dialog)); + gtk_dialog_run(dialog); + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +static void CommentChanged(GtkTextBuffer* buffer, gpointer userData) { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); + if (comment[0] == '\0' || gCommentFieldHint) { + gQueryParameters.removeMember("Comments"); + } else { + gQueryParameters["Comments"] = comment; + } +} + +static void CommentInsert(GtkTextBuffer* buffer, GtkTextIter* location, + gchar* text, gint len, gpointer userData) { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); + + // limit to 500 bytes in utf-8 + if (strlen(comment) + len > MAX_COMMENT_LENGTH) { + g_signal_stop_emission_by_name(buffer, "insert-text"); + } +} + +static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus, + bool* hintShowing, const char* hintText) { + GtkTextBuffer* buffer = nullptr; + if (GTK_IS_TEXT_VIEW(widget)) + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); + + if (gainedFocus) { + if (*hintShowing) { + if (buffer == nullptr) { // sort of cheating + gtk_entry_set_text(GTK_ENTRY(widget), ""); + } else { // GtkTextView + gtk_text_buffer_set_text(buffer, "", 0); + } + gtk_widget_modify_text(widget, GTK_STATE_NORMAL, nullptr); + *hintShowing = false; + } + } else { + // lost focus + const char* text = nullptr; + if (buffer == nullptr) { + text = gtk_entry_get_text(GTK_ENTRY(widget)); + } else { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); + } + + if (text == nullptr || text[0] == '\0') { + *hintShowing = true; + + if (buffer == nullptr) { + gtk_entry_set_text(GTK_ENTRY(widget), hintText); + } else { + gtk_text_buffer_set_text(buffer, hintText, -1); + } + + gtk_widget_modify_text( + widget, GTK_STATE_NORMAL, + >k_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]); + } + } +} + +static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event, + gpointer userData) { + UpdateHintText(widget, event->in, &gCommentFieldHint, + gStrings[ST_COMMENTGRAYTEXT].c_str()); + + return FALSE; +} + +typedef struct _GnomeProgram GnomeProgram; +typedef struct _GnomeModuleInfo GnomeModuleInfo; +typedef GnomeProgram* (*_gnome_program_init_fn)(const char*, const char*, + const GnomeModuleInfo*, int, + char**, const char*, ...); +typedef const GnomeModuleInfo* (*_libgnomeui_module_info_get_fn)(); + +void TryInitGnome() { + gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY); + if (!gnomeLib) return; + + gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY); + if (!gnomeuiLib) return; + + _gnome_program_init_fn gnome_program_init = + (_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init")); + _libgnomeui_module_info_get_fn libgnomeui_module_info_get = + (_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, + "libgnomeui_module_info_get")); + + if (gnome_program_init && libgnomeui_module_info_get) { + gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(), + gArgc, gArgv, nullptr); + } +} + +/* === Crashreporter UI Functions === */ + +/* + * Anything not listed here is in crashreporter_gtk_common.cpp: + * UIInit + * UIShowDefaultUI + * UIError_impl + * UIGetIniPath + * UIGetSettingsPath + * UIEnsurePathExists + * UIFileExists + * UIMoveFile + * UIDeleteFile + * UIOpenRead + * UIOpenWrite + */ + +void UIShutdown() { + if (gnomeuiLib) dlclose(gnomeuiLib); + // Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit(). +} + +bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, + const string& sendURL, const vector& restartArgs) { + gFiles = files; + gQueryParameters = queryParameters; + gSendURL = sendURL; + gRestartArgs = restartArgs; + if (gQueryParameters.isMember("URL")) { + gURLParameter = gQueryParameters["URL"].asString(); + } + + if (gAutoSubmit) { + SendReport(); + CloseApp(nullptr); + return true; + } + + gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(gWindow), + gStrings[ST_CRASHREPORTERTITLE].c_str()); + gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE); + gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER); + gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12); + g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0); + g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), + nullptr); + + GtkWidget* vbox = gtk_vbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(gWindow), vbox); + + GtkWidget* titleLabel = gtk_label_new(""); + gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0); + gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5); + char* markup = + g_strdup_printf("%s", gStrings[ST_CRASHREPORTERHEADER].c_str()); + gtk_label_set_markup(GTK_LABEL(titleLabel), markup); + g_free(markup); + + GtkWidget* descriptionLabel = + gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str()); + gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0); + // force the label to line wrap + gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), + LABEL_MAX_CHAR_WIDTH); + gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE); + gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE); + gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5); + + // this is honestly how they suggest you indent a section + GtkWidget* indentBox = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6); + + GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0); + + gSubmitReportCheck = + gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str()); + gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0); + g_signal_connect(gSubmitReportCheck, "clicked", + G_CALLBACK(SubmitReportChecked), 0); + + // indent again, below the "submit report" checkbox + GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6); + + GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0); + gtk_box_set_spacing(GTK_BOX(innerVBox), 6); + + GtkWidget* viewReportButtonBox = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0); + gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6); + gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), + GTK_BUTTONBOX_START); + + gViewReportButton = + gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str()); + gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, + FALSE, 0); + g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), + 0); + + GtkWidget* scrolled = gtk_scrolled_window_new(0, 0); + gtk_container_add(GTK_CONTAINER(innerVBox), scrolled); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), + GTK_SHADOW_IN); + gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), + 100); + + gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str()); + gCommentText = gtk_text_view_new(); + gtk_label_set_mnemonic_widget(GTK_LABEL(gCommentTextLabel), gCommentText); + gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE); + g_signal_connect(gCommentText, "focus-in-event", + G_CALLBACK(CommentFocusChange), 0); + g_signal_connect(gCommentText, "focus-out-event", + G_CALLBACK(CommentFocusChange), 0); + + GtkTextBuffer* commentBuffer = + gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText)); + g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0); + g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0); + + gtk_container_add(GTK_CONTAINER(scrolled), gCommentText); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText), GTK_WRAP_WORD_CHAR); + gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100); + + if (gQueryParameters.isMember("URL")) { + gIncludeURLCheck = + gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str()); + gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0); + g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), + 0); + // on by default + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE); + } + + GtkWidget* progressBox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0); + + // Get the throbber image from alongside the executable + char* dir = g_path_get_dirname(gArgv[0]); + char* path = g_build_filename(dir, "Throbber-small.gif", nullptr); + g_free(dir); + gThrobber = gtk_image_new_from_file(path); + gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0); + + gProgressLabel = gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str()); + gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0); + // force the label to line wrap + gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), + LABEL_MAX_CHAR_WIDTH); + gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE); + + GtkWidget* buttonBox = gtk_hbutton_box_new(); + gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0); + gtk_box_set_spacing(GTK_BOX(buttonBox), 6); + gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END); + + gCloseButton = gtk_button_new_with_label(gStrings[ST_QUIT].c_str()); + gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0); + gtk_widget_set_can_default(gCloseButton, TRUE); + g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0); + + gRestartButton = 0; + if (!restartArgs.empty()) { + gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str()); + gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0); + gtk_widget_set_can_default(gRestartButton, TRUE); + g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0); + } + + gtk_widget_grab_focus(gSubmitReportCheck); + + gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton); + + LoadSettings(); + + UpdateSubmit(); + + UpdateHintText(gCommentText, FALSE, &gCommentFieldHint, + gStrings[ST_COMMENTGRAYTEXT].c_str()); + + gtk_widget_show_all(gWindow); + // stick this here to avoid the show_all above... + gtk_widget_hide(gThrobber); + + gtk_main(); + + return gDidTrySend; +} diff --git a/toolkit/crashreporter/client/crashreporter_osx.h b/toolkit/crashreporter/client/crashreporter_osx.h new file mode 100644 index 0000000000..d9aeddb4b0 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_osx.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef CRASHREPORTER_OSX_H__ +#define CRASHREPORTER_OSX_H__ + +#include +#include "HTTPMultipartUpload.h" +#include "crashreporter.h" +#include "json/json.h" + +// Defined below +@class TextViewWithPlaceHolder; + +@interface CrashReporterUI : NSObject { + IBOutlet NSWindow* mWindow; + + /* Crash reporter view */ + IBOutlet NSTextField* mHeaderLabel; + IBOutlet NSTextField* mDescriptionLabel; + IBOutlet NSButton* mViewReportButton; + IBOutlet NSScrollView* mCommentScrollView; + IBOutlet TextViewWithPlaceHolder* mCommentText; + IBOutlet NSButton* mSubmitReportButton; + IBOutlet NSButton* mIncludeURLButton; + IBOutlet NSButton* mEmailMeButton; + IBOutlet NSTextField* mEmailText; + IBOutlet NSButton* mCloseButton; + IBOutlet NSButton* mRestartButton; + IBOutlet NSProgressIndicator* mProgressIndicator; + IBOutlet NSTextField* mProgressText; + + /* Error view */ + IBOutlet NSView* mErrorView; + IBOutlet NSTextField* mErrorHeaderLabel; + IBOutlet NSTextField* mErrorLabel; + IBOutlet NSButton* mErrorCloseButton; + + /* For "show info" alert */ + IBOutlet NSWindow* mViewReportWindow; + IBOutlet NSTextView* mViewReportTextView; + IBOutlet NSButton* mViewReportOkButton; + + HTTPMultipartUpload* mPost; +} + +- (void)showCrashUI:(const StringTable&)files + queryParameters:(const Json::Value&)queryParameters + sendURL:(const std::string&)sendURL; +- (void)showErrorUI:(const std::string&)message; +- (void)showReportInfo; +- (void)maybeSubmitReport; +- (void)closeMeDown:(id)unused; + +- (IBAction)submitReportClicked:(id)sender; +- (IBAction)viewReportClicked:(id)sender; +- (IBAction)viewReportOkClicked:(id)sender; +- (IBAction)closeClicked:(id)sender; +- (IBAction)restartClicked:(id)sender; +- (IBAction)includeURLClicked:(id)sender; + +- (void)textDidChange:(NSNotification*)aNotification; +- (BOOL)textView:(NSTextView*)aTextView + shouldChangeTextInRange:(NSRange)affectedCharRange + replacementString:(NSString*)replacementString; + +- (void)doInitialResizing; +- (float)setStringFitVertically:(NSControl*)control + string:(NSString*)str + resizeWindow:(BOOL)resizeWindow; +- (void)setView:(NSView*)v animate:(BOOL)animate; +- (void)enableControls:(BOOL)enabled; +- (void)updateSubmit; +- (void)updateURL; +- (void)updateEmail; +- (void)sendReport; +- (bool)setupPost; +- (void)uploadThread:(HTTPMultipartUpload*)post; +- (void)uploadComplete:(NSData*)data; + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed: + (NSApplication*)theApplication; +- (void)applicationWillTerminate:(NSNotification*)aNotification; + +@end + +/* + * Subclass NSTextView to provide a text view with placeholder text. + * Also provide a setEnabled implementation. + */ +@interface TextViewWithPlaceHolder : NSTextView { + NSMutableAttributedString* mPlaceHolderString; +} + +- (BOOL)becomeFirstResponder; +- (void)drawRect:(NSRect)rect; +- (BOOL)resignFirstResponder; +- (void)setPlaceholder:(NSString*)placeholder; +- (void)insertTab:(id)sender; +- (void)insertBacktab:(id)sender; +- (void)setEnabled:(BOOL)enabled; +- (void)dealloc; + +@end + +#endif diff --git a/toolkit/crashreporter/client/crashreporter_osx.mm b/toolkit/crashreporter/client/crashreporter_osx.mm new file mode 100644 index 0000000000..b6d5d8ac6f --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_osx.mm @@ -0,0 +1,805 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import +#import +#include "crashreporter.h" +#include "crashreporter_osx.h" +#include +#include +#include +#include +#include +#include + +using std::ostringstream; +using std::string; +using std::vector; + +using namespace CrashReporter; + +static NSAutoreleasePool* gMainPool; +static CrashReporterUI* gUI = 0; +static StringTable gFiles; +static Json::Value gQueryParameters; +static string gURLParameter; +static string gSendURL; +static vector gRestartArgs; +static bool gDidTrySend = false; +static bool gRTLlayout = false; + +static cpu_type_t pref_cpu_types[2] = { +#if defined(__i386__) + CPU_TYPE_X86, +#elif defined(__x86_64__) + CPU_TYPE_X86_64, +#elif defined(__ppc__) + CPU_TYPE_POWERPC, +#elif defined(__aarch64__) + CPU_TYPE_ARM64, +#endif + CPU_TYPE_ANY}; + +#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()] + +static NSString* Str(const char* aName) { + string str = gStrings[aName]; + if (str.empty()) str = "?"; + return NSSTR(str); +} + +static bool RestartApplication() { + vector argv(gRestartArgs.size() + 1); + + posix_spawnattr_t spawnattr; + if (posix_spawnattr_init(&spawnattr) != 0) { + return false; + } + + // Set spawn attributes. + size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]); + size_t attr_ocount = 0; + if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, + &attr_ocount) != 0 || + attr_ocount != attr_count) { + posix_spawnattr_destroy(&spawnattr); + return false; + } + + unsigned int i; + for (i = 0; i < gRestartArgs.size(); i++) { + argv[i] = (char*)gRestartArgs[i].c_str(); + } + argv[i] = 0; + + char** env = NULL; + char*** nsEnv = _NSGetEnviron(); + if (nsEnv) env = *nsEnv; + int result = posix_spawnp(NULL, argv[0], NULL, &spawnattr, &argv[0], env); + + posix_spawnattr_destroy(&spawnattr); + + return result == 0; +} + +@implementation CrashReporterUI + +- (void)awakeFromNib { + gUI = self; + [mWindow center]; + + [mWindow setTitle:[[NSBundle mainBundle] + objectForInfoDictionaryKey:@"CFBundleName"]]; + [NSApp activateIgnoringOtherApps:YES]; +} + +- (void)showCrashUI:(const StringTable&)files + queryParameters:(const Json::Value&)queryParameters + sendURL:(const string&)sendURL { + gFiles = files; + gQueryParameters = queryParameters; + gSendURL = sendURL; + + if (gAutoSubmit) { + gDidTrySend = true; + [self sendReport]; + return; + } + + [mWindow setTitle:Str(ST_CRASHREPORTERTITLE)]; + [mHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)]; + + NSRect viewReportFrame = [mViewReportButton frame]; + [mViewReportButton setTitle:Str(ST_VIEWREPORT)]; + [mViewReportButton sizeToFit]; + if (gRTLlayout) { + // sizeToFit will keep the left side fixed, so realign + float oldWidth = viewReportFrame.size.width; + viewReportFrame = [mViewReportButton frame]; + viewReportFrame.origin.x += oldWidth - viewReportFrame.size.width; + [mViewReportButton setFrame:viewReportFrame]; + } + + [mSubmitReportButton setTitle:Str(ST_CHECKSUBMIT)]; + [mIncludeURLButton setTitle:Str(ST_CHECKURL)]; + [mViewReportOkButton setTitle:Str(ST_OK)]; + + [mCommentText setPlaceholder:Str(ST_COMMENTGRAYTEXT)]; + if (gRTLlayout) [mCommentText toggleBaseWritingDirection:self]; + + if (gQueryParameters.isMember("URL")) { + // save the URL value in case the checkbox gets unchecked + gURLParameter = gQueryParameters["URL"].asString(); + } else { + // no URL specified, hide checkbox + [mIncludeURLButton removeFromSuperview]; + // shrink window to fit + NSRect frame = [mWindow frame]; + NSRect includeURLFrame = [mIncludeURLButton frame]; + NSRect emailFrame = [mEmailMeButton frame]; + int buttonMask = [mViewReportButton autoresizingMask]; + int checkMask = [mSubmitReportButton autoresizingMask]; + int commentScrollMask = [mCommentScrollView autoresizingMask]; + + [mViewReportButton setAutoresizingMask:NSViewMinYMargin]; + [mSubmitReportButton setAutoresizingMask:NSViewMinYMargin]; + [mCommentScrollView setAutoresizingMask:NSViewMinYMargin]; + + // remove all the space in between + frame.size.height -= includeURLFrame.origin.y - emailFrame.origin.y; + [mWindow setFrame:frame display:true animate:NO]; + + [mViewReportButton setAutoresizingMask:buttonMask]; + [mSubmitReportButton setAutoresizingMask:checkMask]; + [mCommentScrollView setAutoresizingMask:commentScrollMask]; + } + + // resize some buttons horizontally and possibly some controls vertically + [self doInitialResizing]; + + // load default state of submit checkbox + // we don't just do this via IB because we want the default to be + // off a certain percentage of the time + BOOL submitChecked = YES; + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + if (nil != [userDefaults objectForKey:@"submitReport"]) { + submitChecked = [userDefaults boolForKey:@"submitReport"]; + } else { + [userDefaults setBool:submitChecked forKey:@"submitReport"]; + } + [mSubmitReportButton setState:(submitChecked ? NSOnState : NSOffState)]; + + // load default state of include URL checkbox + BOOL includeChecked = YES; + if (nil != [userDefaults objectForKey:@"IncludeURL"]) { + includeChecked = [userDefaults boolForKey:@"IncludeURL"]; + } else { + [userDefaults setBool:includeChecked forKey:@"IncludeURL"]; + } + [mIncludeURLButton setState:(includeChecked ? NSOnState : NSOffState)]; + + [self updateSubmit]; + [self updateURL]; + [self updateEmail]; + + [mWindow makeKeyAndOrderFront:nil]; +} + +- (void)showErrorUI:(const string&)message { + [self setView:mErrorView animate:NO]; + + [mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)]; + [self setStringFitVertically:mErrorLabel + string:NSSTR(message) + resizeWindow:YES]; + [mErrorCloseButton setTitle:Str(ST_OK)]; + + [mErrorCloseButton setKeyEquivalent:@"\r"]; + [mWindow makeFirstResponder:mErrorCloseButton]; + [mWindow makeKeyAndOrderFront:nil]; +} + +- (void)showReportInfo { + NSDictionary* boldAttr = @{ + NSFontAttributeName : + [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]], + NSForegroundColorAttributeName : NSColor.textColor, + }; + NSDictionary* normalAttr = @{ + NSFontAttributeName : + [NSFont systemFontOfSize:[NSFont smallSystemFontSize]], + NSForegroundColorAttributeName : NSColor.textColor, + }; + + [mViewReportTextView setString:@""]; + for (Json::ValueConstIterator iter = gQueryParameters.begin(); + iter != gQueryParameters.end(); ++iter) { + NSAttributedString* key = + [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ") + attributes:boldAttr]; + string str; + if (iter->isString()) { + str = iter->asString(); + } else { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + str = writeString(builder, *iter); + } + NSAttributedString* value = + [[NSAttributedString alloc] initWithString:NSSTR(str + "\n") + attributes:normalAttr]; + [[mViewReportTextView textStorage] appendAttributedString:key]; + [[mViewReportTextView textStorage] appendAttributedString:value]; + [key release]; + [value release]; + } + + NSAttributedString* extra = [[NSAttributedString alloc] + initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO]) + attributes:normalAttr]; + [[mViewReportTextView textStorage] appendAttributedString:extra]; + [extra release]; +} + +- (void)maybeSubmitReport { + if ([mSubmitReportButton state] == NSOnState) { + [self setStringFitVertically:mProgressText + string:Str(ST_REPORTDURINGSUBMIT) + resizeWindow:YES]; + // disable all the controls + [self enableControls:NO]; + [mSubmitReportButton setEnabled:NO]; + [mRestartButton setEnabled:NO]; + [mCloseButton setEnabled:NO]; + [mProgressIndicator startAnimation:self]; + gDidTrySend = true; + [self sendReport]; + } else { + [NSApp terminate:self]; + } +} + +- (void)closeMeDown:(id)unused { + [NSApp terminate:self]; +} + +- (IBAction)submitReportClicked:(id)sender { + [self updateSubmit]; + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setBool:([mSubmitReportButton state] == NSOnState) + forKey:@"submitReport"]; + [userDefaults synchronize]; +} + +- (IBAction)viewReportClicked:(id)sender { + [self showReportInfo]; + [NSApp beginSheet:mViewReportWindow + modalForWindow:mWindow + modalDelegate:nil + didEndSelector:nil + contextInfo:nil]; +} + +- (IBAction)viewReportOkClicked:(id)sender { + [mViewReportWindow orderOut:nil]; + [NSApp endSheet:mViewReportWindow]; +} + +- (IBAction)closeClicked:(id)sender { + [self maybeSubmitReport]; +} + +- (IBAction)restartClicked:(id)sender { + RestartApplication(); + [self maybeSubmitReport]; +} + +- (IBAction)includeURLClicked:(id)sender { + [self updateURL]; + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setBool:([mIncludeURLButton state] == NSOnState) + forKey:@"IncludeURL"]; + [userDefaults synchronize]; +} + +- (void)textDidChange:(NSNotification*)aNotification { + // update comment parameter + if ([[[mCommentText textStorage] mutableString] length] > 0) + gQueryParameters["Comments"] = + [[[mCommentText textStorage] mutableString] UTF8String]; + else + gQueryParameters.removeMember("Comments"); +} + +// Limit the comment field to 500 bytes in UTF-8 +- (BOOL)textView:(NSTextView*)aTextView + shouldChangeTextInRange:(NSRange)affectedCharRange + replacementString:(NSString*)replacementString { + // current string length + replacement text length - replaced range length + if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + + [replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] - + [[[aTextView string] substringWithRange:affectedCharRange] + lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) > + MAX_COMMENT_LENGTH) { + return NO; + } + return YES; +} + +- (void)doInitialResizing { + NSRect windowFrame = [mWindow frame]; + NSRect restartFrame = [mRestartButton frame]; + NSRect closeFrame = [mCloseButton frame]; + // resize close button to fit text + float oldCloseWidth = closeFrame.size.width; + [mCloseButton setTitle:Str(ST_QUIT)]; + [mCloseButton sizeToFit]; + closeFrame = [mCloseButton frame]; + // move close button left if it grew + if (!gRTLlayout) { + closeFrame.origin.x -= closeFrame.size.width - oldCloseWidth; + } + + if (gRestartArgs.size() == 0) { + [mRestartButton removeFromSuperview]; + if (!gRTLlayout) { + closeFrame.origin.x = restartFrame.origin.x + + (restartFrame.size.width - closeFrame.size.width); + } else { + closeFrame.origin.x = restartFrame.origin.x; + } + [mCloseButton setFrame:closeFrame]; + [mCloseButton setKeyEquivalent:@"\r"]; + } else { + [mRestartButton setTitle:Str(ST_RESTART)]; + // resize "restart" button + float oldRestartWidth = restartFrame.size.width; + [mRestartButton sizeToFit]; + restartFrame = [mRestartButton frame]; + if (!gRTLlayout) { + // move left by the amount that the button grew + restartFrame.origin.x -= restartFrame.size.width - oldRestartWidth; + closeFrame.origin.x -= restartFrame.size.width - oldRestartWidth; + } else { + // shift the close button right in RTL + closeFrame.origin.x += restartFrame.size.width - oldRestartWidth; + } + [mRestartButton setFrame:restartFrame]; + [mCloseButton setFrame:closeFrame]; + // possibly resize window if both buttons no longer fit + // leave 20 px from either side of the window, and 12 px + // between the buttons + float neededWidth = + closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12; + + if (neededWidth > windowFrame.size.width) { + windowFrame.size.width = neededWidth; + [mWindow setFrame:windowFrame display:true animate:NO]; + } + [mRestartButton setKeyEquivalent:@"\r"]; + } + + NSButton* checkboxes[] = {mSubmitReportButton, mIncludeURLButton}; + + for (auto checkbox : checkboxes) { + NSRect frame = [checkbox frame]; + [checkbox sizeToFit]; + if (gRTLlayout) { + // sizeToFit will keep the left side fixed, so realign + float oldWidth = frame.size.width; + frame = [checkbox frame]; + frame.origin.x += oldWidth - frame.size.width; + [checkbox setFrame:frame]; + } + // keep existing spacing on left side, + 20 px spare on right + float neededWidth = + frame.origin.x + checkbox.intrinsicContentSize.width + 20; + if (neededWidth > windowFrame.size.width) { + windowFrame.size.width = neededWidth; + [mWindow setFrame:windowFrame display:true animate:NO]; + } + } + + // do this down here because we may have made the window wider + // up above + [self setStringFitVertically:mDescriptionLabel + string:Str(ST_CRASHREPORTERDESCRIPTION) + resizeWindow:YES]; + + // now pin all the controls (except quit/submit) in place, + // if we lengthen the window after this, it's just to lengthen + // the progress text, so nothing above that text should move. + NSView* views[] = {mSubmitReportButton, mViewReportButton, + mCommentScrollView, mIncludeURLButton, + mProgressIndicator, mProgressText}; + for (auto view : views) { + [view setAutoresizingMask:NSViewMinYMargin]; + } +} + +- (float)setStringFitVertically:(NSControl*)control + string:(NSString*)str + resizeWindow:(BOOL)resizeWindow { + // hack to make the text field grow vertically + NSRect frame = [control frame]; + float oldHeight = frame.size.height; + + frame.size.height = 10000; + NSSize oldCellSize = [[control cell] cellSizeForBounds:frame]; + [control setStringValue:str]; + NSSize newCellSize = [[control cell] cellSizeForBounds:frame]; + + float delta = newCellSize.height - oldCellSize.height; + frame.origin.y -= delta; + frame.size.height = oldHeight + delta; + [control setFrame:frame]; + + if (resizeWindow) { + NSRect frame = [mWindow frame]; + frame.origin.y -= delta; + frame.size.height += delta; + [mWindow setFrame:frame display:true animate:NO]; + } + + return delta; +} + +- (void)setView:(NSView*)v animate:(BOOL)animate { + NSRect frame = [mWindow frame]; + + NSRect oldViewFrame = [[mWindow contentView] frame]; + NSRect newViewFrame = [v frame]; + + frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height; + frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height; + + frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width; + frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width; + + [mWindow setContentView:v]; + [mWindow setFrame:frame display:true animate:animate]; +} + +- (void)enableControls:(BOOL)enabled { + [mViewReportButton setEnabled:enabled]; + [mIncludeURLButton setEnabled:enabled]; + [mCommentText setEnabled:enabled]; + [mCommentScrollView setHasVerticalScroller:enabled]; +} + +- (void)updateSubmit { + if ([mSubmitReportButton state] == NSOnState) { + [self setStringFitVertically:mProgressText + string:Str(ST_REPORTPRESUBMIT) + resizeWindow:YES]; + [mProgressText setHidden:NO]; + // enable all the controls + [self enableControls:YES]; + } else { + // not submitting, disable all the controls under + // the submit checkbox, and hide the status text + [mProgressText setHidden:YES]; + [self enableControls:NO]; + } +} + +- (void)updateURL { + if ([mIncludeURLButton state] == NSOnState && !gURLParameter.empty()) { + gQueryParameters["URL"] = gURLParameter; + } else { + gQueryParameters.removeMember("URL"); + } +} + +- (void)updateEmail { + // In order to remove the email fields, we have to edit the .nib files which + // we can't do with current xcode so we make them hidden; updating the + // crashreporter interface for mac is covered in bug #1696164 + [mEmailMeButton setHidden:YES]; + [mEmailText setHidden:YES]; +} + +- (void)sendReport { + if (![self setupPost]) { + LogMessage("Crash report submission failed: could not set up POST data"); + + if (gAutoSubmit) { + [NSApp terminate:self]; + } + + [self setStringFitVertically:mProgressText + string:Str(ST_SUBMITFAILED) + resizeWindow:YES]; + // quit after 5 seconds + [self performSelector:@selector(closeMeDown:) + withObject:nil + afterDelay:5.0]; + } + + [NSThread detachNewThreadSelector:@selector(uploadThread:) + toTarget:self + withObject:mPost]; +} + +- (bool)setupPost { + NSURL* url = [NSURL + URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding: + NSUTF8StringEncoding]]; + if (!url) return false; + + mPost = [[HTTPMultipartUpload alloc] initWithURL:url]; + if (!mPost) return false; + + for (StringTable::const_iterator i = gFiles.begin(); i != gFiles.end(); i++) { + [mPost addFileAtPath:NSSTR(i->second) name:NSSTR(i->first)]; + } + + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string output = writeString(builder, gQueryParameters).append("\r\n"); + NSMutableString* parameters = + [[NSMutableString alloc] initWithUTF8String:output.c_str()]; + + [mPost setParameters:parameters]; + [parameters release]; + + return true; +} + +- (void)uploadComplete:(NSData*)data { + NSHTTPURLResponse* response = [mPost response]; + [mPost release]; + + bool success; + string reply; + if (!data || !response || [response statusCode] != 200) { + success = false; + reply = ""; + + // if data is nil, we probably logged an error in uploadThread + if (data != nil && response != nil) { + ostringstream message; + message << "Crash report submission failed: server returned status " + << [response statusCode]; + LogMessage(message.str()); + } + } else { + success = true; + LogMessage("Crash report submitted successfully"); + + NSString* encodingName = [response textEncodingName]; + NSStringEncoding encoding; + if (encodingName) { + encoding = CFStringConvertEncodingToNSStringEncoding( + CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName)); + } else { + encoding = NSISOLatin1StringEncoding; + } + NSString* r = [[NSString alloc] initWithData:data encoding:encoding]; + reply = [r UTF8String]; + [r release]; + } + + SendCompleted(success, reply); + + if (gAutoSubmit) { + [NSApp terminate:self]; + } + + [mProgressIndicator stopAnimation:self]; + if (success) { + [self setStringFitVertically:mProgressText + string:Str(ST_REPORTSUBMITSUCCESS) + resizeWindow:YES]; + } else { + [self setStringFitVertically:mProgressText + string:Str(ST_SUBMITFAILED) + resizeWindow:YES]; + } + // quit after 5 seconds + [self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0]; +} + +- (void)uploadThread:(HTTPMultipartUpload*)post { + NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init]; + NSError* error = nil; + NSData* data = [post send:&error]; + if (error) { + data = nil; + NSString* errorDesc = [error localizedDescription]; + string message = [errorDesc UTF8String]; + LogMessage("Crash report submission failed: " + message); + } + + [self performSelectorOnMainThread:@selector(uploadComplete:) + withObject:data + waitUntilDone:YES]; + + [autoreleasepool release]; +} + +// to get auto-quit when we close the window +- (BOOL)applicationShouldTerminateAfterLastWindowClosed: + (NSApplication*)theApplication { + return YES; +} + +- (void)applicationWillTerminate:(NSNotification*)aNotification { + // since we use [NSApp terminate:] we never return to main, + // so do our cleanup here + if (!gDidTrySend) DeleteDump(); +} + +@end + +@implementation TextViewWithPlaceHolder + +- (BOOL)becomeFirstResponder { + [self setNeedsDisplay:YES]; + return [super becomeFirstResponder]; +} + +- (void)drawRect:(NSRect)rect { + [super drawRect:rect]; + if (mPlaceHolderString && [[self string] isEqualToString:@""] && + self != [[self window] firstResponder]) + [mPlaceHolderString drawInRect:[self frame]]; +} + +- (BOOL)resignFirstResponder { + [self setNeedsDisplay:YES]; + return [super resignFirstResponder]; +} + +- (void)setPlaceholder:(NSString*)placeholder { + NSColor* txtColor = [NSColor disabledControlTextColor]; + NSDictionary* txtDict = [NSDictionary + dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, + nil]; + mPlaceHolderString = + [[NSMutableAttributedString alloc] initWithString:placeholder + attributes:txtDict]; + if (gRTLlayout) + [mPlaceHolderString setAlignment:NSTextAlignmentRight + range:NSMakeRange(0, [placeholder length])]; +} + +- (void)insertTab:(id)sender { + // don't actually want to insert tabs, just tab to next control + [[self window] selectNextKeyView:sender]; +} + +- (void)insertBacktab:(id)sender { + [[self window] selectPreviousKeyView:sender]; +} + +- (void)setEnabled:(BOOL)enabled { + [self setSelectable:enabled]; + [self setEditable:enabled]; + if (![[self string] isEqualToString:@""]) { + NSAttributedString* colorString; + NSColor* txtColor; + if (enabled) + txtColor = [NSColor textColor]; + else + txtColor = [NSColor disabledControlTextColor]; + NSDictionary* txtDict = [NSDictionary + dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, + nil]; + colorString = [[NSAttributedString alloc] initWithString:[self string] + attributes:txtDict]; + [[self textStorage] setAttributedString:colorString]; + [self setInsertionPointColor:txtColor]; + [colorString release]; + } +} + +- (void)dealloc { + [mPlaceHolderString release]; + [super dealloc]; +} + +@end + +/* === Crashreporter UI Functions === */ + +bool UIInit() { + gMainPool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; + + if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") + gRTLlayout = true; + + if (gAutoSubmit) { + gUI = [[CrashReporterUI alloc] init]; + } else { + [[NSBundle mainBundle] + loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu") + owner:NSApp + topLevelObjects:nil]; + } + + return true; +} + +void UIShutdown() { [gMainPool release]; } + +void UIShowDefaultUI() { + [gUI showErrorUI:gStrings[ST_CRASHREPORTERDEFAULT]]; + [NSApp run]; +} + +bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, + const string& sendURL, const vector& restartArgs) { + gRestartArgs = restartArgs; + + [gUI showCrashUI:files queryParameters:queryParameters sendURL:sendURL]; + [NSApp run]; + + return gDidTrySend; +} + +void UIError_impl(const string& message) { + if (!gUI) { + // UI failed to initialize, printing is the best we can do + printf("Error: %s\n", message.c_str()); + return; + } + + [gUI showErrorUI:message]; + [NSApp run]; +} + +bool UIGetIniPath(string& path) { + NSString* tmpPath = [NSString stringWithUTF8String:gArgv[0]]; + NSString* iniName = [tmpPath lastPathComponent]; + iniName = [iniName stringByAppendingPathExtension:@"ini"]; + tmpPath = [tmpPath stringByDeletingLastPathComponent]; + tmpPath = [tmpPath stringByDeletingLastPathComponent]; + tmpPath = [tmpPath stringByAppendingPathComponent:@"Resources"]; + tmpPath = [tmpPath stringByAppendingPathComponent:iniName]; + path = [tmpPath UTF8String]; + return true; +} + +bool UIGetSettingsPath(const string& vendor, const string& product, + string& settingsPath) { + NSArray* paths = NSSearchPathForDirectoriesInDomains( + NSApplicationSupportDirectory, NSUserDomainMask, YES); + NSString* destPath = [paths firstObject]; + + // Note that MacOS ignores the vendor when creating the profile hierarchy - + // all application preferences directories live alongside one another in + // ~/Library/Application Support/ + destPath = [destPath stringByAppendingPathComponent:NSSTR(product)]; + // Thunderbird stores its profile in ~/Library/Thunderbird, + // but we're going to put stuff in ~/Library/Application Support/Thunderbird + // anyway, so we have to ensure that path exists. + string tempPath = [destPath UTF8String]; + if (!UIEnsurePathExists(tempPath)) return false; + + destPath = [destPath stringByAppendingPathComponent:@"Crash Reports"]; + + settingsPath = [destPath UTF8String]; + + return true; +} + +bool UIMoveFile(const string& file, const string& newfile) { + if (!rename(file.c_str(), newfile.c_str())) return true; + if (errno != EXDEV) return false; + + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSString* source = + [fileManager stringWithFileSystemRepresentation:file.c_str() + length:file.length()]; + NSString* dest = + [fileManager stringWithFileSystemRepresentation:newfile.c_str() + length:newfile.length()]; + if (!source || !dest) return false; + + [fileManager moveItemAtPath:source toPath:dest error:NULL]; + return UIFileExists(newfile); +} diff --git a/toolkit/crashreporter/client/crashreporter_unix_common.cpp b/toolkit/crashreporter/client/crashreporter_unix_common.cpp new file mode 100644 index 0000000000..e6514d4423 --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_unix_common.cpp @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "crashreporter.h" + +#include +#include + +#include +#include +#include +#include + +using namespace CrashReporter; +using std::ios_base; +using std::sort; +using std::string; +using std::vector; + +struct FileData { + time_t timestamp; + string path; +}; + +static bool CompareFDTime(const FileData& fd1, const FileData& fd2) { + return fd1.timestamp > fd2.timestamp; +} + +void UIPruneSavedDumps(const string& directory) { + DIR* dirfd = opendir(directory.c_str()); + if (!dirfd) return; + + vector dumpfiles; + + while (dirent* dir = readdir(dirfd)) { + FileData fd; + fd.path = directory + '/' + dir->d_name; + if (fd.path.size() < 5) continue; + + if (fd.path.compare(fd.path.size() - 4, 4, ".dmp") != 0) continue; + + struct stat st; + if (stat(fd.path.c_str(), &st)) { + closedir(dirfd); + return; + } + + fd.timestamp = st.st_mtime; + + dumpfiles.push_back(fd); + } + + closedir(dirfd); + + sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime); + + while (dumpfiles.size() > kSaveCount) { + // get the path of the oldest file + string path = dumpfiles[dumpfiles.size() - 1].path; + UIDeleteFile(path); + + // s/.dmp/.extra/ + path.replace(path.size() - 4, 4, ".extra"); + UIDeleteFile(path); + + dumpfiles.pop_back(); + } +} + +bool UIRunProgram(const string& exename, const vector& args, + bool wait) { + pid_t pid = fork(); + + if (pid == -1) { + return false; + } else if (pid == 0) { + // Child + size_t argvLen = args.size() + 2; + vector argv(argvLen); + + argv[0] = const_cast(exename.c_str()); + + for (size_t i = 0; i < args.size(); i++) { + argv[i + 1] = const_cast(args[i].c_str()); + } + + argv[argvLen - 1] = nullptr; + + // Run the program + int rv = execv(exename.c_str(), argv.data()); + + if (rv == -1) { + exit(EXIT_FAILURE); + } + } else { + // Parent + if (wait) { + waitpid(pid, nullptr, 0); + } + } + + return true; +} + +bool UIEnsurePathExists(const string& path) { + int ret = mkdir(path.c_str(), S_IRWXU); + int e = errno; + if (ret == -1 && e != EEXIST) return false; + + return true; +} + +bool UIFileExists(const string& path) { + struct stat sb; + int ret = stat(path.c_str(), &sb); + if (ret == -1 || !(sb.st_mode & S_IFREG)) return false; + + return true; +} + +bool UIDeleteFile(const string& file) { return (unlink(file.c_str()) != -1); } + +std::ifstream* UIOpenRead(const string& filename, ios_base::openmode mode) { + return new std::ifstream(filename.c_str(), mode); +} + +std::ofstream* UIOpenWrite(const string& filename, ios_base::openmode mode) { + return new std::ofstream(filename.c_str(), mode); +} + +string UIGetEnv(const string& name) { + const char* var = getenv(name.c_str()); + if (var && *var) { + return var; + } + + return ""; +} diff --git a/toolkit/crashreporter/client/crashreporter_win.cpp b/toolkit/crashreporter/client/crashreporter_win.cpp new file mode 100644 index 0000000000..35018bda4a --- /dev/null +++ b/toolkit/crashreporter/client/crashreporter_win.cpp @@ -0,0 +1,1266 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#include "crashreporter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "resource.h" +#include "windows/sender/crash_report_sender.h" +#include "common/windows/string_utils-inl.h" + +#define SUBMIT_REPORT_VALUE L"SubmitCrashReport" +#define INCLUDE_URL_VALUE L"IncludeURL" + +#define WM_UPLOADCOMPLETE WM_APP + +// Thanks, Windows.h :( +#undef min +#undef max + +using std::ifstream; +using std::ios; +using std::ios_base; +using std::map; +using std::ofstream; +using std::set; +using std::string; +using std::vector; +using std::wstring; + +using namespace CrashReporter; + +typedef struct { + HWND hDlg; + Json::Value queryParameters; + map files; + wstring sendURL; + + wstring serverResponse; +} SendThreadData; + +/* + * Per http://msdn2.microsoft.com/en-us/library/ms645398(VS.85).aspx + * "The DLGTEMPLATEEX structure is not defined in any standard header file. + * The structure definition is provided here to explain the format of an + * extended template for a dialog box. + */ +typedef struct { + WORD dlgVer; + WORD signature; + DWORD helpID; + DWORD exStyle; + // There's more to this struct, but it has weird variable-length + // members, and I only actually need to touch exStyle on an existing + // instance, so I've omitted the rest. +} DLGTEMPLATEEX; + +static HANDLE gThreadHandle; +static SendThreadData gSendData = { + 0, +}; +static vector gRestartArgs; +static Json::Value gQueryParameters; +static wstring gCrashReporterKey(L"Software\\Mozilla\\Crash Reporter"); +static string gURLParameter; +static int gCheckboxPadding = 6; +static bool gRTLlayout = false; + +// When vertically resizing the dialog, these items should move down +static set gAttachedBottom; + +// Default set of items for gAttachedBottom +static const UINT kDefaultAttachedBottom[] = { + IDC_SUBMITREPORTCHECK, IDC_VIEWREPORTBUTTON, IDC_COMMENTTEXT, + IDC_INCLUDEURLCHECK, IDC_PROGRESSTEXT, IDC_THROBBER, + IDC_CLOSEBUTTON, IDC_RESTARTBUTTON, +}; + +static wstring UTF8ToWide(const string& utf8, bool* success = 0); +static DWORD WINAPI SendThreadProc(LPVOID param); + +static wstring Str(const char* key) { return UTF8ToWide(gStrings[key]); } + +/* === win32 helper functions === */ + +static void DoInitCommonControls() { + INITCOMMONCONTROLSEX ic; + ic.dwSize = sizeof(INITCOMMONCONTROLSEX); + ic.dwICC = ICC_PROGRESS_CLASS; + InitCommonControlsEx(&ic); + // also get the rich edit control + LoadLibrary(L"Msftedit.dll"); +} + +static bool GetBoolValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value) { + DWORD type, dataSize; + dataSize = sizeof(DWORD); + if (RegQueryValueEx(hRegKey, valueName, nullptr, &type, (LPBYTE)value, + &dataSize) == ERROR_SUCCESS && + type == REG_DWORD) + return true; + + return false; +} + +static bool CheckBoolKey(const wchar_t* key, const wchar_t* valueName, + bool* enabled) { + /* + * NOTE! This code needs to stay in sync with the preference checking + * code in in nsExceptionHandler.cpp. + */ + *enabled = false; + bool found = false; + HKEY hRegKey; + DWORD val; + // see if our reg key is set globally + if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) { + if (GetBoolValue(hRegKey, valueName, &val)) { + *enabled = (val == 1); + found = true; + } + RegCloseKey(hRegKey); + } else { + // look for it in user settings + if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { + if (GetBoolValue(hRegKey, valueName, &val)) { + *enabled = (val == 1); + found = true; + } + RegCloseKey(hRegKey); + } + } + + return found; +} + +static void SetBoolKey(const wchar_t* key, const wchar_t* value, bool enabled) { + /* + * NOTE! This code needs to stay in sync with the preference setting + * code in in nsExceptionHandler.cpp. + */ + HKEY hRegKey; + + if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { + DWORD data = (enabled ? 1 : 0); + RegSetValueEx(hRegKey, value, 0, REG_DWORD, (LPBYTE)&data, sizeof(data)); + RegCloseKey(hRegKey); + } +} + +static string FormatLastError() { + DWORD err = GetLastError(); + LPWSTR s; + string message = "Crash report submission failed: "; + // odds are it's a WinInet error + HANDLE hInetModule = GetModuleHandle(L"WinInet.dll"); + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_FROM_HMODULE, + hInetModule, err, 0, (LPWSTR)&s, 0, nullptr) != 0) { + message += WideToUTF8(s, nullptr); + LocalFree(s); + // strip off any trailing newlines + string::size_type n = message.find_last_not_of("\r\n"); + if (n < message.size() - 1) { + message.erase(n + 1); + } + } else { + char buf[64]; + sprintf(buf, "Unknown error, error code: 0x%08x", + static_cast(err)); + message += buf; + } + return message; +} + +#define TS_DRAW 2 +#define BP_CHECKBOX 3 + +typedef HANDLE(WINAPI* OpenThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList); +typedef HRESULT(WINAPI* CloseThemeDataPtr)(HANDLE hTheme); +typedef HRESULT(WINAPI* GetThemePartSizePtr)(HANDLE hTheme, HDC hdc, + int iPartId, int iStateId, + RECT* prc, int ts, SIZE* psz); +typedef HRESULT(WINAPI* GetThemeContentRectPtr)(HANDLE hTheme, HDC hdc, + int iPartId, int iStateId, + const RECT* pRect, + RECT* pContentRect); + +static void GetThemeSizes(HWND hwnd) { + HMODULE themeDLL = LoadLibrary(L"uxtheme.dll"); + + if (!themeDLL) return; + + OpenThemeDataPtr openTheme = + (OpenThemeDataPtr)GetProcAddress(themeDLL, "OpenThemeData"); + CloseThemeDataPtr closeTheme = + (CloseThemeDataPtr)GetProcAddress(themeDLL, "CloseThemeData"); + GetThemePartSizePtr getThemePartSize = + (GetThemePartSizePtr)GetProcAddress(themeDLL, "GetThemePartSize"); + + if (!openTheme || !closeTheme || !getThemePartSize) { + FreeLibrary(themeDLL); + return; + } + + HANDLE buttonTheme = openTheme(hwnd, L"Button"); + if (!buttonTheme) { + FreeLibrary(themeDLL); + return; + } + HDC hdc = GetDC(hwnd); + SIZE s; + getThemePartSize(buttonTheme, hdc, BP_CHECKBOX, 0, nullptr, TS_DRAW, &s); + gCheckboxPadding = s.cx; + closeTheme(buttonTheme); + FreeLibrary(themeDLL); +} + +// Gets the position of a window relative to another window's client area +static void GetRelativeRect(HWND hwnd, HWND hwndParent, RECT* r) { + GetWindowRect(hwnd, r); + MapWindowPoints(nullptr, hwndParent, (POINT*)r, 2); +} + +static void SetDlgItemVisible(HWND hwndDlg, UINT item, bool visible) { + HWND hwnd = GetDlgItem(hwndDlg, item); + + ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE); +} + +/* === Crash Reporting Dialog === */ + +static void StretchDialog(HWND hwndDlg, int ydiff) { + RECT r; + GetWindowRect(hwndDlg, &r); + r.bottom += ydiff; + MoveWindow(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); +} + +static void ReflowDialog(HWND hwndDlg, int ydiff) { + // Move items attached to the bottom down/up by as much as + // the window resize + for (set::const_iterator item = gAttachedBottom.begin(); + item != gAttachedBottom.end(); item++) { + RECT r; + HWND hwnd = GetDlgItem(hwndDlg, *item); + GetRelativeRect(hwnd, hwndDlg, &r); + r.top += ydiff; + r.bottom += ydiff; + MoveWindow(hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + } +} + +static DWORD WINAPI SendThreadProc(LPVOID param) { + bool finishedOk; + SendThreadData* td = (SendThreadData*)param; + + if (td->sendURL.empty()) { + finishedOk = false; + LogMessage("No server URL, not sending report"); + } else { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string parameters(Json::writeString(builder, td->queryParameters)); + google_breakpad::CrashReportSender sender(L""); + finishedOk = (sender.SendCrashReport(td->sendURL, parameters, td->files, + &td->serverResponse) == + google_breakpad::RESULT_SUCCEEDED); + if (finishedOk) { + LogMessage("Crash report submitted successfully"); + } else { + // get an error string and print it to the log + // XXX: would be nice to get the HTTP status code here, filed: + // http://code.google.com/p/google-breakpad/issues/detail?id=220 + LogMessage(FormatLastError()); + } + } + + if (gAutoSubmit) { + // Ordinarily this is done on the main thread in CrashReporterDialogProc, + // for auto submit we don't run that and it should be safe to finish up + // here as is done on other platforms. + SendCompleted(finishedOk, WideToUTF8(gSendData.serverResponse)); + } else { + PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0); + } + + return 0; +} + +static void EndCrashReporterDialog(HWND hwndDlg, int code) { + // Save the current values to the registry + SetBoolKey(gCrashReporterKey.c_str(), INCLUDE_URL_VALUE, + IsDlgButtonChecked(hwndDlg, IDC_INCLUDEURLCHECK) != 0); + SetBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE, + IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0); + + EndDialog(hwndDlg, code); +} + +static void MaybeResizeProgressText(HWND hwndDlg) { + HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESSTEXT); + HDC hdc = GetDC(hwndProgress); + HFONT hfont = (HFONT)SendMessage(hwndProgress, WM_GETFONT, 0, 0); + if (hfont) SelectObject(hdc, hfont); + SIZE size; + RECT rect; + GetRelativeRect(hwndProgress, hwndDlg, &rect); + + wchar_t text[1024]; + GetWindowText(hwndProgress, text, 1024); + + if (!GetTextExtentPoint32(hdc, text, wcslen(text), &size)) return; + + if (size.cx < (rect.right - rect.left)) return; + + // Figure out how much we need to resize things vertically + // This is sort of a fudge, but it should be good enough. + int wantedHeight = + size.cy * (int)ceil((float)size.cx / (float)(rect.right - rect.left)); + int diff = wantedHeight - (rect.bottom - rect.top); + if (diff <= 0) return; + + MoveWindow(hwndProgress, rect.left, rect.top, rect.right - rect.left, + wantedHeight, TRUE); + + gAttachedBottom.clear(); + gAttachedBottom.insert(IDC_CLOSEBUTTON); + gAttachedBottom.insert(IDC_RESTARTBUTTON); + + StretchDialog(hwndDlg, diff); + + for (size_t i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) { + gAttachedBottom.insert(kDefaultAttachedBottom[i]); + } +} + +static void MaybeSendReport(HWND hwndDlg) { + if (!IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK)) { + EndCrashReporterDialog(hwndDlg, 0); + return; + } + + // disable all the form controls + EnableWindow(GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_COMMENTTEXT), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_CLOSEBUTTON), false); + EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTBUTTON), false); + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, Str(ST_REPORTDURINGSUBMIT).c_str()); + MaybeResizeProgressText(hwndDlg); + // start throbber + // play entire AVI, and loop + Animate_Play(GetDlgItem(hwndDlg, IDC_THROBBER), 0, -1, -1); + SetDlgItemVisible(hwndDlg, IDC_THROBBER, true); + gThreadHandle = nullptr; + gSendData.hDlg = hwndDlg; + gSendData.queryParameters = gQueryParameters; + + gThreadHandle = + CreateThread(nullptr, 0, SendThreadProc, &gSendData, 0, nullptr); +} + +static void RestartApplication() { + wstring cmdLine; + + for (unsigned int i = 0; i < gRestartArgs.size(); i++) { + cmdLine += L"\"" + UTF8ToWide(gRestartArgs[i]) + L"\" "; + } + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOWNORMAL; + ZeroMemory(&pi, sizeof(pi)); + + if (CreateProcess(nullptr, (LPWSTR)cmdLine.c_str(), nullptr, nullptr, FALSE, + 0, nullptr, nullptr, &si, &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } +} + +static void ShowReportInfo(HWND hwndDlg) { + wstring description; + + for (Json::ValueConstIterator iter = gQueryParameters.begin(); + iter != gQueryParameters.end(); ++iter) { + description += UTF8ToWide(iter.name()); + description += L": "; + string value; + if (iter->isString()) { + value = iter->asString(); + } else { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + value = Json::writeString(builder, *iter); + } + description += UTF8ToWide(value); + description += L"\n"; + } + + description += L"\n"; + description += Str(ST_EXTRAREPORTINFO); + + SetDlgItemText(hwndDlg, IDC_VIEWREPORTTEXT, description.c_str()); +} + +static void UpdateURL(HWND hwndDlg) { + if (IsDlgButtonChecked(hwndDlg, IDC_INCLUDEURLCHECK)) { + gQueryParameters["URL"] = gURLParameter; + } else { + gQueryParameters.removeMember("URL"); + } +} + +static void UpdateComment(HWND hwndDlg) { + wchar_t comment[MAX_COMMENT_LENGTH + 1]; + GetDlgItemTextW(hwndDlg, IDC_COMMENTTEXT, comment, + sizeof(comment) / sizeof(comment[0])); + if (wcslen(comment) > 0) + gQueryParameters["Comments"] = WideToUTF8(comment); + else + gQueryParameters.removeMember("Comments"); +} + +/* + * Dialog procedure for the "view report" dialog. + */ +static BOOL CALLBACK ViewReportDialogProc(HWND hwndDlg, UINT message, + WPARAM wParam, LPARAM lParam) { + switch (message) { + case WM_INITDIALOG: { + SetWindowText(hwndDlg, Str(ST_VIEWREPORTTITLE).c_str()); + SetDlgItemText(hwndDlg, IDOK, Str(ST_OK).c_str()); + SendDlgItemMessage(hwndDlg, IDC_VIEWREPORTTEXT, EM_SETTARGETDEVICE, + (WPARAM) nullptr, 0); + ShowReportInfo(hwndDlg); + SetFocus(GetDlgItem(hwndDlg, IDOK)); + return FALSE; + } + + case WM_COMMAND: { + if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK) + EndDialog(hwndDlg, 0); + return FALSE; + } + } + return FALSE; +} + +// Return the number of bytes this string will take encoded +// in UTF-8 +static inline int BytesInUTF8(wchar_t* str) { + // Just count size of buffer for UTF-8, minus one + // (we don't need to count the null terminator) + return WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, + nullptr) - + 1; +} + +// Calculate the length of the text in this edit control (in bytes, +// in the UTF-8 encoding) after replacing the current selection +// with |insert|. +static int NewTextLength(HWND hwndEdit, wchar_t* insert) { + wchar_t current[MAX_COMMENT_LENGTH + 1]; + + GetWindowText(hwndEdit, current, MAX_COMMENT_LENGTH + 1); + DWORD selStart, selEnd; + SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); + + int selectionLength = 0; + if (selEnd - selStart > 0) { + wchar_t selection[MAX_COMMENT_LENGTH + 1]; + google_breakpad::WindowsStringUtils::safe_wcsncpy( + selection, MAX_COMMENT_LENGTH + 1, current + selStart, + selEnd - selStart); + selection[selEnd - selStart] = '\0'; + selectionLength = BytesInUTF8(selection); + } + + // current string length + replacement text length + // - replaced selection length + return BytesInUTF8(current) + BytesInUTF8(insert) - selectionLength; +} + +// Window procedure for subclassing edit controls +static LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) { + static WNDPROC super = nullptr; + + if (super == nullptr) super = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch (uMsg) { + case WM_PAINT: { + HDC hdc; + PAINTSTRUCT ps; + RECT r; + wchar_t windowText[1024]; + + GetWindowText(hwnd, windowText, 1024); + // if the control contains text or is focused, draw it normally + if (GetFocus() == hwnd || windowText[0] != '\0') + return CallWindowProc(super, hwnd, uMsg, wParam, lParam); + + GetClientRect(hwnd, &r); + hdc = BeginPaint(hwnd, &ps); + FillRect(hdc, &r, + GetSysColorBrush(IsWindowEnabled(hwnd) ? COLOR_WINDOW + : COLOR_BTNFACE)); + SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + SelectObject(hdc, (HFONT)GetStockObject(DEFAULT_GUI_FONT)); + SetBkMode(hdc, TRANSPARENT); + wchar_t* txt = (wchar_t*)GetProp(hwnd, L"PROP_GRAYTEXT"); + // Get the actual edit control rect + CallWindowProc(super, hwnd, EM_GETRECT, 0, (LPARAM)&r); + UINT format = DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK | DT_INTERNAL; + if (gRTLlayout) format |= DT_RIGHT; + if (txt) DrawText(hdc, txt, wcslen(txt), &r, format); + EndPaint(hwnd, &ps); + return 0; + } + + // We handle WM_CHAR and WM_PASTE to limit the comment box to 500 + // bytes in UTF-8. + case WM_CHAR: { + // Leave accelerator keys and non-printing chars (except LF) alone + if (wParam & (1 << 24) || wParam & (1 << 29) || + (wParam < ' ' && wParam != '\n')) + break; + + wchar_t ch[2] = {(wchar_t)wParam, 0}; + if (NewTextLength(hwnd, ch) > MAX_COMMENT_LENGTH) return 0; + + break; + } + + case WM_PASTE: { + if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(hwnd)) { + HGLOBAL hg = GetClipboardData(CF_UNICODETEXT); + wchar_t* pastedText = (wchar_t*)GlobalLock(hg); + int newSize = 0; + + if (pastedText) newSize = NewTextLength(hwnd, pastedText); + + GlobalUnlock(hg); + CloseClipboard(); + + if (newSize > MAX_COMMENT_LENGTH) return 0; + } + break; + } + + case WM_SETFOCUS: + case WM_KILLFOCUS: { + RECT r; + GetClientRect(hwnd, &r); + InvalidateRect(hwnd, &r, TRUE); + break; + } + + case WM_DESTROY: { + // cleanup our property + HGLOBAL hData = RemoveProp(hwnd, L"PROP_GRAYTEXT"); + if (hData) GlobalFree(hData); + } + } + + return CallWindowProc(super, hwnd, uMsg, wParam, lParam); +} + +// Resize a control to fit this text +static int ResizeControl(HWND hwndButton, RECT& rect, wstring text, + bool shiftLeft, int userDefinedPadding) { + HDC hdc = GetDC(hwndButton); + HFONT hfont = (HFONT)SendMessage(hwndButton, WM_GETFONT, 0, 0); + if (hfont) SelectObject(hdc, hfont); + SIZE size, oldSize; + int sizeDiff = 0; + + wchar_t oldText[1024]; + GetWindowText(hwndButton, oldText, 1024); + + if (GetTextExtentPoint32(hdc, text.c_str(), text.length(), &size) + // default text on the button + && GetTextExtentPoint32(hdc, oldText, wcslen(oldText), &oldSize)) { + /* + Expand control widths to accomidate wider text strings. For most + controls (including buttons) the text padding is defined by the + dialog's rc file. Some controls (such as checkboxes) have padding + that extends to the end of the dialog, in which case we ignore the + rc padding and rely on a user defined value passed in through + userDefinedPadding. + */ + int textIncrease = size.cx - oldSize.cx; + if (textIncrease < 0) return 0; + int existingTextPadding; + if (userDefinedPadding == 0) + existingTextPadding = (rect.right - rect.left) - oldSize.cx; + else + existingTextPadding = userDefinedPadding; + sizeDiff = textIncrease + existingTextPadding; + + if (shiftLeft) { + // shift left by the amount the button should grow + rect.left -= sizeDiff; + } else { + // grow right instead + rect.right += sizeDiff; + } + MoveWindow(hwndButton, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return sizeDiff; +} + +// The window was resized horizontally, so widen some of our +// controls to make use of the space +static void StretchControlsToFit(HWND hwndDlg) { + int controls[] = {IDC_DESCRIPTIONTEXT, IDC_SUBMITREPORTCHECK, IDC_COMMENTTEXT, + IDC_INCLUDEURLCHECK, IDC_PROGRESSTEXT}; + + RECT dlgRect; + GetClientRect(hwndDlg, &dlgRect); + + for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); i++) { + RECT r; + HWND hwndControl = GetDlgItem(hwndDlg, controls[i]); + GetRelativeRect(hwndControl, hwndDlg, &r); + // 6 pixel spacing on the right + if (r.right + 6 != dlgRect.right) { + r.right = dlgRect.right - 6; + MoveWindow(hwndControl, r.left, r.top, r.right - r.left, r.bottom - r.top, + TRUE); + } + } +} + +static void SubmitReportChecked(HWND hwndDlg) { + bool enabled = (IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON), enabled); + EnableWindow(GetDlgItem(hwndDlg, IDC_COMMENTTEXT), enabled); + EnableWindow(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), enabled); + SetDlgItemVisible(hwndDlg, IDC_PROGRESSTEXT, enabled); +} + +static INT_PTR DialogBoxParamMaybeRTL(UINT idd, HWND hwndParent, + DLGPROC dlgProc, LPARAM param) { + INT_PTR rv = 0; + if (gRTLlayout) { + // We need to toggle the WS_EX_LAYOUTRTL style flag on the dialog + // template. + HRSRC hDialogRC = FindResource(nullptr, MAKEINTRESOURCE(idd), RT_DIALOG); + HGLOBAL hDlgTemplate = LoadResource(nullptr, hDialogRC); + DLGTEMPLATEEX* pDlgTemplate = (DLGTEMPLATEEX*)LockResource(hDlgTemplate); + unsigned long sizeDlg = SizeofResource(nullptr, hDialogRC); + HGLOBAL hMyDlgTemplate = GlobalAlloc(GPTR, sizeDlg); + DLGTEMPLATEEX* pMyDlgTemplate = (DLGTEMPLATEEX*)GlobalLock(hMyDlgTemplate); + memcpy(pMyDlgTemplate, pDlgTemplate, sizeDlg); + + pMyDlgTemplate->exStyle |= WS_EX_LAYOUTRTL; + + rv = DialogBoxIndirectParam(nullptr, (LPCDLGTEMPLATE)pMyDlgTemplate, + hwndParent, dlgProc, param); + GlobalUnlock(hMyDlgTemplate); + GlobalFree(hMyDlgTemplate); + } else { + rv = DialogBoxParam(nullptr, MAKEINTRESOURCE(idd), hwndParent, dlgProc, + param); + } + + return rv; +} + +static BOOL CALLBACK CrashReporterDialogProc(HWND hwndDlg, UINT message, + WPARAM wParam, LPARAM lParam) { + static int sHeight = 0; + + bool success; + bool enabled; + + switch (message) { + case WM_INITDIALOG: { + GetThemeSizes(hwndDlg); + RECT r; + GetClientRect(hwndDlg, &r); + sHeight = r.bottom - r.top; + + SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str()); + HICON hIcon = + LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_MAINICON)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + + // resize the "View Report" button based on the string length + RECT rect; + HWND hwnd = GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON); + GetRelativeRect(hwnd, hwndDlg, &rect); + ResizeControl(hwnd, rect, Str(ST_VIEWREPORT), false, 0); + SetDlgItemText(hwndDlg, IDC_VIEWREPORTBUTTON, Str(ST_VIEWREPORT).c_str()); + + hwnd = GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK); + GetRelativeRect(hwnd, hwndDlg, &rect); + long maxdiff = ResizeControl(hwnd, rect, Str(ST_CHECKSUBMIT), false, + gCheckboxPadding); + SetDlgItemText(hwndDlg, IDC_SUBMITREPORTCHECK, + Str(ST_CHECKSUBMIT).c_str()); + + if (!CheckBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE, + &enabled)) + enabled = true; + + CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, + enabled ? BST_CHECKED : BST_UNCHECKED); + SubmitReportChecked(hwndDlg); + + HWND hwndComment = GetDlgItem(hwndDlg, IDC_COMMENTTEXT); + WNDPROC OldWndProc = (WNDPROC)SetWindowLongPtr( + hwndComment, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); + + // Subclass comment edit control to get placeholder text + SetWindowLongPtr(hwndComment, GWLP_USERDATA, (LONG_PTR)OldWndProc); + wstring commentGrayText = Str(ST_COMMENTGRAYTEXT); + wchar_t* hMem = (wchar_t*)GlobalAlloc( + GPTR, (commentGrayText.length() + 1) * sizeof(wchar_t)); + wcscpy(hMem, commentGrayText.c_str()); + SetProp(hwndComment, L"PROP_GRAYTEXT", hMem); + + hwnd = GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK); + GetRelativeRect(hwnd, hwndDlg, &rect); + long diff = + ResizeControl(hwnd, rect, Str(ST_CHECKURL), false, gCheckboxPadding); + maxdiff = std::max(diff, maxdiff); + SetDlgItemText(hwndDlg, IDC_INCLUDEURLCHECK, Str(ST_CHECKURL).c_str()); + + // want this on by default + if (CheckBoolKey(gCrashReporterKey.c_str(), INCLUDE_URL_VALUE, + &enabled) && + !enabled) { + CheckDlgButton(hwndDlg, IDC_INCLUDEURLCHECK, BST_UNCHECKED); + } else { + CheckDlgButton(hwndDlg, IDC_INCLUDEURLCHECK, BST_CHECKED); + } + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, + Str(ST_REPORTPRESUBMIT).c_str()); + + RECT closeRect; + HWND hwndClose = GetDlgItem(hwndDlg, IDC_CLOSEBUTTON); + GetRelativeRect(hwndClose, hwndDlg, &closeRect); + + RECT restartRect; + HWND hwndRestart = GetDlgItem(hwndDlg, IDC_RESTARTBUTTON); + GetRelativeRect(hwndRestart, hwndDlg, &restartRect); + + // set the close button text and shift the buttons around + // since the size may need to change + int sizeDiff = ResizeControl(hwndClose, closeRect, Str(ST_QUIT), true, 0); + restartRect.left -= sizeDiff; + restartRect.right -= sizeDiff; + SetDlgItemText(hwndDlg, IDC_CLOSEBUTTON, Str(ST_QUIT).c_str()); + + if (gRestartArgs.size() > 0) { + // Resize restart button to fit text + ResizeControl(hwndRestart, restartRect, Str(ST_RESTART), true, 0); + SetDlgItemText(hwndDlg, IDC_RESTARTBUTTON, Str(ST_RESTART).c_str()); + } else { + // No restart arguments, so just hide the restart button + SetDlgItemVisible(hwndDlg, IDC_RESTARTBUTTON, false); + } + // See if we need to widen the window + // Leave 6 pixels on either side + 6 pixels between the buttons + int neededSize = closeRect.right - closeRect.left + restartRect.right - + restartRect.left + 6 * 3; + GetClientRect(hwndDlg, &r); + // We may already have resized one of the checkboxes above + maxdiff = std::max(maxdiff, neededSize - (r.right - r.left)); + + if (maxdiff > 0) { + // widen window + GetWindowRect(hwndDlg, &r); + r.right += maxdiff; + MoveWindow(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, + TRUE); + // shift both buttons right + if (restartRect.left + maxdiff < 6) maxdiff += 6; + closeRect.left += maxdiff; + closeRect.right += maxdiff; + restartRect.left += maxdiff; + restartRect.right += maxdiff; + MoveWindow(hwndClose, closeRect.left, closeRect.top, + closeRect.right - closeRect.left, + closeRect.bottom - closeRect.top, TRUE); + StretchControlsToFit(hwndDlg); + } + // need to move the restart button regardless + MoveWindow(hwndRestart, restartRect.left, restartRect.top, + restartRect.right - restartRect.left, + restartRect.bottom - restartRect.top, TRUE); + + // Resize the description text last, in case the window was resized + // before this. + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETEVENTMASK, + (WPARAM) nullptr, ENM_REQUESTRESIZE); + + wstring description = Str(ST_CRASHREPORTERHEADER); + description += L"\n\n"; + description += Str(ST_CRASHREPORTERDESCRIPTION); + SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, description.c_str()); + + // Make the title bold. + CHARFORMAT fmt = { + 0, + }; + fmt.cbSize = sizeof(fmt); + fmt.dwMask = CFM_BOLD; + fmt.dwEffects = CFE_BOLD; + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, + Str(ST_CRASHREPORTERHEADER).length()); + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETCHARFORMAT, + SCF_SELECTION, (LPARAM)&fmt); + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, 0); + // Force redraw. + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, + (WPARAM) nullptr, 0); + // Force resize. + SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_REQUESTRESIZE, 0, 0); + + // if no URL was given, hide the URL checkbox + if (!gQueryParameters.isMember("URL")) { + RECT urlCheckRect; + GetWindowRect(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), &urlCheckRect); + + SetDlgItemVisible(hwndDlg, IDC_INCLUDEURLCHECK, false); + + gAttachedBottom.erase(IDC_VIEWREPORTBUTTON); + gAttachedBottom.erase(IDC_SUBMITREPORTCHECK); + gAttachedBottom.erase(IDC_COMMENTTEXT); + + StretchDialog(hwndDlg, urlCheckRect.top - urlCheckRect.bottom); + + gAttachedBottom.insert(IDC_VIEWREPORTBUTTON); + gAttachedBottom.insert(IDC_SUBMITREPORTCHECK); + gAttachedBottom.insert(IDC_COMMENTTEXT); + } + + MaybeResizeProgressText(hwndDlg); + + // Open the AVI resource for the throbber + Animate_Open(GetDlgItem(hwndDlg, IDC_THROBBER), + MAKEINTRESOURCE(IDR_THROBBER)); + + UpdateURL(hwndDlg); + + SetFocus(GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK)); + return FALSE; + } + case WM_SIZE: { + ReflowDialog(hwndDlg, HIWORD(lParam) - sHeight); + sHeight = HIWORD(lParam); + InvalidateRect(hwndDlg, nullptr, TRUE); + return FALSE; + } + case WM_NOTIFY: { + NMHDR* notification = reinterpret_cast(lParam); + if (notification->code == EN_REQUESTRESIZE) { + // Resizing the rich edit control to fit the description text. + REQRESIZE* reqresize = reinterpret_cast(lParam); + RECT newSize = reqresize->rc; + RECT oldSize; + GetRelativeRect(notification->hwndFrom, hwndDlg, &oldSize); + + // resize the text box as requested + MoveWindow(notification->hwndFrom, newSize.left, newSize.top, + newSize.right - newSize.left, newSize.bottom - newSize.top, + TRUE); + + // Resize the dialog to fit (the WM_SIZE handler will move the controls) + StretchDialog(hwndDlg, newSize.bottom - oldSize.bottom); + } + return FALSE; + } + case WM_COMMAND: { + if (HIWORD(wParam) == BN_CLICKED) { + switch (LOWORD(wParam)) { + case IDC_VIEWREPORTBUTTON: + DialogBoxParamMaybeRTL(IDD_VIEWREPORTDIALOG, hwndDlg, + (DLGPROC)ViewReportDialogProc, 0); + break; + case IDC_SUBMITREPORTCHECK: + SubmitReportChecked(hwndDlg); + break; + case IDC_INCLUDEURLCHECK: + UpdateURL(hwndDlg); + break; + case IDC_CLOSEBUTTON: + MaybeSendReport(hwndDlg); + break; + case IDC_RESTARTBUTTON: + RestartApplication(); + MaybeSendReport(hwndDlg); + break; + } + } else if (HIWORD(wParam) == EN_CHANGE) { + switch (LOWORD(wParam)) { + case IDC_COMMENTTEXT: + UpdateComment(hwndDlg); + } + } + + return FALSE; + } + case WM_UPLOADCOMPLETE: { + WaitForSingleObject(gThreadHandle, INFINITE); + success = (wParam == 1); + SendCompleted(success, WideToUTF8(gSendData.serverResponse)); + // hide throbber + Animate_Stop(GetDlgItem(hwndDlg, IDC_THROBBER)); + SetDlgItemVisible(hwndDlg, IDC_THROBBER, false); + + SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, + success ? Str(ST_REPORTSUBMITSUCCESS).c_str() + : Str(ST_SUBMITFAILED).c_str()); + MaybeResizeProgressText(hwndDlg); + // close dialog after 5 seconds + SetTimer(hwndDlg, 0, 5000, nullptr); + // + return TRUE; + } + + case WM_TIMER: { + // The "1" gets used down in UIShowCrashUI to indicate that we at least + // tried to send the report. + EndCrashReporterDialog(hwndDlg, 1); + return FALSE; + } + + case WM_CLOSE: { + EndCrashReporterDialog(hwndDlg, 0); + return FALSE; + } + } + return FALSE; +} + +static wstring UTF8ToWide(const string& utf8, bool* success) { + wchar_t* buffer = nullptr; + int buffer_size = + MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0); + if (buffer_size == 0) { + if (success) *success = false; + return L""; + } + + buffer = new wchar_t[buffer_size]; + if (buffer == nullptr) { + if (success) *success = false; + return L""; + } + + MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buffer, buffer_size); + wstring str = buffer; + delete[] buffer; + + if (success) *success = true; + + return str; +} + +static string WideToMBCP(const wstring& wide, unsigned int cp, + bool* success = nullptr) { + char* buffer = nullptr; + int buffer_size = WideCharToMultiByte(cp, 0, wide.c_str(), -1, nullptr, 0, + nullptr, nullptr); + if (buffer_size == 0) { + if (success) *success = false; + return ""; + } + + buffer = new char[buffer_size]; + if (buffer == nullptr) { + if (success) *success = false; + return ""; + } + + WideCharToMultiByte(cp, 0, wide.c_str(), -1, buffer, buffer_size, nullptr, + nullptr); + string mb = buffer; + delete[] buffer; + + if (success) *success = true; + + return mb; +} + +string WideToUTF8(const wstring& wide, bool* success) { + return WideToMBCP(wide, CP_UTF8, success); +} + +/* === Crashreporter UI Functions === */ + +bool UIInit() { + for (size_t i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) { + gAttachedBottom.insert(kDefaultAttachedBottom[i]); + } + + DoInitCommonControls(); + + return true; +} + +void UIShutdown() {} + +void UIShowDefaultUI() { + MessageBox(nullptr, Str(ST_CRASHREPORTERDEFAULT).c_str(), L"Crash Reporter", + MB_OK | MB_ICONSTOP); +} + +bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, + const string& sendURL, const vector& restartArgs) { + gSendData.hDlg = nullptr; + gSendData.sendURL = UTF8ToWide(sendURL); + + for (StringTable::const_iterator i = files.begin(); i != files.end(); i++) { + gSendData.files[UTF8ToWide(i->first)] = UTF8ToWide(i->second); + } + + gQueryParameters = queryParameters; + + if (gQueryParameters.isMember("Vendor")) { + gCrashReporterKey = L"Software\\"; + string vendor = gQueryParameters["Vendor"].asString(); + if (!vendor.empty()) { + gCrashReporterKey += UTF8ToWide(vendor) + L"\\"; + } + string productName = gQueryParameters["ProductName"].asString(); + gCrashReporterKey += UTF8ToWide(productName) + L"\\Crash Reporter"; + } + + if (gQueryParameters.isMember("URL")) { + gURLParameter = gQueryParameters["URL"].asString(); + } + + gRestartArgs = restartArgs; + + if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") + gRTLlayout = true; + + if (gAutoSubmit) { + gSendData.queryParameters = gQueryParameters; + + gThreadHandle = + CreateThread(nullptr, 0, SendThreadProc, &gSendData, 0, nullptr); + WaitForSingleObject(gThreadHandle, INFINITE); + // SendCompleted was called from SendThreadProc + return true; + } + + return 1 == DialogBoxParamMaybeRTL(IDD_SENDDIALOG, nullptr, + (DLGPROC)CrashReporterDialogProc, 0); +} + +void UIError_impl(const string& message) { + wstring title = Str(ST_CRASHREPORTERTITLE); + if (title.empty()) title = L"Crash Reporter Error"; + + MessageBox(nullptr, UTF8ToWide(message).c_str(), title.c_str(), + MB_OK | MB_ICONSTOP); +} + +bool UIGetIniPath(string& path) { + wchar_t fileName[MAX_PATH]; + if (GetModuleFileName(nullptr, fileName, MAX_PATH)) { + // get crashreporter ini + wchar_t* s = wcsrchr(fileName, '.'); + if (s) { + wcscpy(s, L".ini"); + path = WideToUTF8(fileName); + return true; + } + } + + return false; +} + +bool UIGetSettingsPath(const string& vendor, const string& product, + string& settings_path) { + wchar_t path[MAX_PATH] = {}; + HRESULT hRes = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path); + if (FAILED(hRes)) { + // This provides a fallback for getting the path to APPDATA by querying the + // registry when the call to SHGetFolderPath is unable to provide this path + // (Bug 513958). + HKEY key; + DWORD type, dwRes; + DWORD size = sizeof(path) - 1; + dwRes = ::RegOpenKeyExW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Exp" + L"lorer\\Shell Folders", + 0, KEY_READ, &key); + if (dwRes != ERROR_SUCCESS) return false; + + dwRes = + RegQueryValueExW(key, L"AppData", nullptr, &type, (LPBYTE)&path, &size); + ::RegCloseKey(key); + // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the + // buffer size must not equal 0, and the buffer size be a multiple of 2. + if (dwRes != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) + return false; + } + + if (!vendor.empty()) { + PathAppend(path, UTF8ToWide(vendor).c_str()); + } + PathAppend(path, UTF8ToWide(product).c_str()); + PathAppend(path, L"Crash Reports"); + settings_path = WideToUTF8(path); + return true; +} + +bool UIEnsurePathExists(const string& path) { + if (CreateDirectory(UTF8ToWide(path).c_str(), nullptr) == 0) { + if (GetLastError() != ERROR_ALREADY_EXISTS) return false; + } + + return true; +} + +bool UIFileExists(const string& path) { + DWORD attrs = GetFileAttributes(UTF8ToWide(path).c_str()); + return (attrs != INVALID_FILE_ATTRIBUTES); +} + +bool UIMoveFile(const string& oldfile, const string& newfile) { + if (oldfile == newfile) return true; + + return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str()) == + TRUE; +} + +bool UIDeleteFile(const string& oldfile) { + return DeleteFile(UTF8ToWide(oldfile).c_str()) == TRUE; +} + +ifstream* UIOpenRead(const string& filename, ios_base::openmode mode) { +#if defined(_MSC_VER) + ifstream* file = new ifstream(); + file->open(UTF8ToWide(filename).c_str(), mode); +#else // GCC + ifstream* file = + new ifstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(), mode); +#endif // _MSC_VER + + return file; +} + +ofstream* UIOpenWrite(const string& filename, ios_base::openmode mode) { +#if defined(_MSC_VER) + ofstream* file = new ofstream(); + file->open(UTF8ToWide(filename).c_str(), mode); +#else // GCC + ofstream* file = + new ofstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(), mode); +#endif // _MSC_VER + + return file; +} + +struct FileData { + FILETIME timestamp; + wstring path; +}; + +static bool CompareFDTime(const FileData& fd1, const FileData& fd2) { + return CompareFileTime(&fd1.timestamp, &fd2.timestamp) > 0; +} + +void UIPruneSavedDumps(const std::string& directory) { + wstring wdirectory = UTF8ToWide(directory); + + WIN32_FIND_DATA fdata; + wstring findpath = wdirectory + L"\\*.dmp"; + HANDLE dirlist = FindFirstFile(findpath.c_str(), &fdata); + if (dirlist == INVALID_HANDLE_VALUE) return; + + vector dumpfiles; + + for (BOOL ok = true; ok; ok = FindNextFile(dirlist, &fdata)) { + FileData fd = {fdata.ftLastWriteTime, wdirectory + L"\\" + fdata.cFileName}; + dumpfiles.push_back(fd); + } + + sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime); + + while (dumpfiles.size() > kSaveCount) { + // get the path of the oldest file + wstring path = (--dumpfiles.end())->path; + DeleteFile(path.c_str()); + + // s/.dmp/.extra/ + path.replace(path.size() - 4, 4, L".extra"); + DeleteFile(path.c_str()); + + dumpfiles.pop_back(); + } + FindClose(dirlist); +} + +bool UIRunProgram(const string& exename, const std::vector& args, + bool wait) { + wstring cmdLine = L"\"" + UTF8ToWide(exename) + L"\" "; + + for (auto arg : args) { + cmdLine += L"\"" + UTF8ToWide(arg) + L"\" "; + } + + STARTUPINFO si = {}; + si.cb = sizeof(si); + PROCESS_INFORMATION pi = {}; + + if (!CreateProcess(/* lpApplicationName */ nullptr, (LPWSTR)cmdLine.c_str(), + /* lpProcessAttributes */ nullptr, + /* lpThreadAttributes */ nullptr, + /* bInheritHandles */ false, + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, + /* lpEnvironment */ nullptr, + /* lpCurrentDirectory */ nullptr, &si, &pi)) { + return false; + } + + if (wait) { + WaitForSingleObject(pi.hProcess, INFINITE); + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; +} + +string UIGetEnv(const string& name) { + const wchar_t* var = _wgetenv(UTF8ToWide(name).c_str()); + if (var && *var) { + return WideToUTF8(var); + } + + return ""; +} diff --git a/toolkit/crashreporter/client/macbuild/Contents/Info.plist b/toolkit/crashreporter/client/macbuild/Contents/Info.plist new file mode 100644 index 0000000000..51d6c4de37 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + crashreporter + CFBundleExecutable + crashreporter + CFBundleIconFile + crashreporter.icns + CFBundleIdentifier + org.mozilla.crashreporter + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + crashreporter + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSHasLocalizedDisplayName + + NSMainNibFile + MainMenu + NSRequiresAquaSystemAppearance + + NSPrincipalClass + NSApplication + LSUIElement + + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/PkgInfo b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo new file mode 100644 index 0000000000..cae6d0a58f --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo @@ -0,0 +1,2 @@ +APPL???? + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in new file mode 100644 index 0000000000..e08ce59eb6 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Localized versions of Info.plist keys */ + +CFBundleName = "Crash Reporter"; +CFBundleDisplayName = "@APP_NAME@ Crash Reporter"; diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 0000000000..254131e431 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,100 @@ + + + + + IBClasses + + + ACTIONS + + closeClicked + id + includeURLClicked + id + restartClicked + id + submitReportClicked + id + viewReportClicked + id + viewReportOkClicked + id + + CLASS + CrashReporterUI + LANGUAGE + ObjC + OUTLETS + + mCloseButton + NSButton + mCommentScrollView + NSScrollView + mCommentText + TextViewWithPlaceHolder + mDescriptionLabel + NSTextField + mEmailMeButton + NSButton + mEmailText + NSTextField + mErrorCloseButton + NSButton + mErrorHeaderLabel + NSTextField + mErrorLabel + NSTextField + mErrorView + NSView + mHeaderLabel + NSTextField + mIncludeURLButton + NSButton + mProgressIndicator + NSProgressIndicator + mProgressText + NSTextField + mRestartButton + NSButton + mSubmitReportButton + NSButton + mViewReportButton + NSButton + mViewReportOkButton + NSButton + mViewReportTextView + NSTextView + mViewReportWindow + NSWindow + mWindow + NSWindow + + SUPERCLASS + NSObject + + + ACTIONS + + insertTab + id + + CLASS + TextViewWithPlaceHolder + LANGUAGE + ObjC + SUPERCLASS + NSTextView + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + IBVersion + 1 + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 0000000000..517349ffce --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + 2 + + IBSystem Version + 9C7010 + targetFramework + IBCocoaFramework + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000000..bfdcccb74c Binary files /dev/null and b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib new file mode 100644 index 0000000000..254131e431 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib @@ -0,0 +1,100 @@ + + + + + IBClasses + + + ACTIONS + + closeClicked + id + includeURLClicked + id + restartClicked + id + submitReportClicked + id + viewReportClicked + id + viewReportOkClicked + id + + CLASS + CrashReporterUI + LANGUAGE + ObjC + OUTLETS + + mCloseButton + NSButton + mCommentScrollView + NSScrollView + mCommentText + TextViewWithPlaceHolder + mDescriptionLabel + NSTextField + mEmailMeButton + NSButton + mEmailText + NSTextField + mErrorCloseButton + NSButton + mErrorHeaderLabel + NSTextField + mErrorLabel + NSTextField + mErrorView + NSView + mHeaderLabel + NSTextField + mIncludeURLButton + NSButton + mProgressIndicator + NSProgressIndicator + mProgressText + NSTextField + mRestartButton + NSButton + mSubmitReportButton + NSButton + mViewReportButton + NSButton + mViewReportOkButton + NSButton + mViewReportTextView + NSTextView + mViewReportWindow + NSWindow + mWindow + NSWindow + + SUPERCLASS + NSObject + + + ACTIONS + + insertTab + id + + CLASS + TextViewWithPlaceHolder + LANGUAGE + ObjC + SUPERCLASS + NSTextView + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + IBVersion + 1 + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib new file mode 100644 index 0000000000..4a2251aaf5 --- /dev/null +++ b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + 2 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib new file mode 100644 index 0000000000..6c93849b94 Binary files /dev/null and b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib differ diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns b/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns new file mode 100644 index 0000000000..341cd05a4d Binary files /dev/null and b/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns differ diff --git a/toolkit/crashreporter/client/moz.build b/toolkit/crashreporter/client/moz.build new file mode 100644 index 0000000000..82e19b8637 --- /dev/null +++ b/toolkit/crashreporter/client/moz.build @@ -0,0 +1,97 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG["OS_TARGET"] != "Android": + Program("crashreporter") + + UNIFIED_SOURCES += [ + "../CrashAnnotations.cpp", + "crashreporter.cpp", + "ping.cpp", + ] + + LOCAL_INCLUDES += [ + "/toolkit/components/jsoncpp/include", + ] + + USE_LIBS += [ + "jsoncpp", + ] + +if CONFIG["OS_ARCH"] == "WINNT": + UNIFIED_SOURCES += [ + "crashreporter_win.cpp", + ] + include("/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild") + SOURCES += objs_sender + SOURCES += [ + "../google-breakpad/src/common/windows/http_upload.cc", + ] + DEFINES["UNICODE"] = True + DEFINES["_UNICODE"] = True + USE_LIBS += [ + "nss", + ] + OS_LIBS += [ + "advapi32", + "comctl32", + "gdi32", + "ole32", + "shell32", + "wininet", + "shlwapi", + "user32", + ] +elif CONFIG["OS_ARCH"] == "Darwin": + UNIFIED_SOURCES += [ + "../google-breakpad/src/common/mac/HTTPMultipartUpload.m", + "crashreporter_osx.mm", + "crashreporter_unix_common.cpp", + ] + LOCAL_INCLUDES += [ + "../google-breakpad/src/common/mac", + ] + OS_LIBS += ["-framework Cocoa"] + USE_LIBS += [ + "nss", + ] + LDFLAGS += ["-Wl,-rpath,@executable_path/../../../"] +elif CONFIG["OS_ARCH"] == "SunOS": + SOURCES += [ + "crashreporter_linux.cpp", + "crashreporter_unix.cpp", + ] + USE_LIBS += [ + "breakpad_solaris_common_s", + ] + +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": + UNIFIED_SOURCES += [ + "../google-breakpad/src/common/linux/http_upload.cc", + "crashreporter_gtk_common.cpp", + "crashreporter_linux.cpp", + "crashreporter_unix_common.cpp", + ] + OS_LIBS += CONFIG["MOZ_GTK3_LIBS"] + OS_LIBS += CONFIG["MOZ_GTHREAD_LIBS"] + CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] + CXXFLAGS += CONFIG["MOZ_GTHREAD_CFLAGS"] + +if CONFIG["OS_ARCH"] == "Linux" or CONFIG["OS_ARCH"] == "SunOS": + FINAL_TARGET_FILES += [ + "Throbber-small.gif", + ] + +DEFINES["MOZ_APP_NAME"] = '"%s"' % CONFIG["MOZ_APP_NAME"] +DEFINES["BIN_SUFFIX"] = '"%s"' % CONFIG["BIN_SUFFIX"] + +RCINCLUDE = "crashreporter.rc" + +# Don't use the STL wrappers in the crashreporter clients; they don't +# link with -lmozalloc, and it really doesn't matter here anyway. +DisableStlWrapping() + +include("/toolkit/crashreporter/crashreporter.mozbuild") diff --git a/toolkit/crashreporter/client/ping.cpp b/toolkit/crashreporter/client/ping.cpp new file mode 100644 index 0000000000..b49211c9c1 --- /dev/null +++ b/toolkit/crashreporter/client/ping.cpp @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "crashreporter.h" + +#include +#include +#include + +#if defined(XP_LINUX) +# include +# include +# include +#elif defined(XP_MACOSX) +# include +#elif defined(XP_WIN) +# include +#endif + +#include "json/json.h" + +#include "CrashAnnotations.h" + +using std::string; + +namespace CrashReporter { + +struct UUID { + uint32_t m0; + uint16_t m1; + uint16_t m2; + uint8_t m3[8]; +}; + +// Generates an UUID; the code here is mostly copied from nsUUIDGenerator.cpp +static string GenerateUUID() { + UUID id = {}; + +#if defined(XP_WIN) // Windows + HRESULT hr = CoCreateGuid((GUID*)&id); + if (FAILED(hr)) { + return ""; + } +#elif defined(XP_MACOSX) // MacOS X + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); + if (!uuid) { + return ""; + } + + CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid); + memcpy(&id, &bytes, sizeof(UUID)); + + CFRelease(uuid); +#elif defined(HAVE_ARC4RANDOM_BUF) // Android, BSD, ... + arc4random_buf(&id, sizeof(UUID)); +#else // Linux + int fd = open("/dev/urandom", O_RDONLY); + + if (fd == -1) { + return ""; + } + + if (read(fd, &id, sizeof(UUID)) != sizeof(UUID)) { + close(fd); + return ""; + } + + close(fd); +#endif + + /* Put in the version */ + id.m2 &= 0x0fff; + id.m2 |= 0x4000; + + /* Put in the variant */ + id.m3[0] &= 0x3f; + id.m3[0] |= 0x80; + + const char* kUUIDFormatString = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + const size_t kUUIDFormatStringLength = 36; + char str[kUUIDFormatStringLength + 1] = {'\0'}; + + int num = snprintf(str, kUUIDFormatStringLength + 1, kUUIDFormatString, id.m0, + id.m1, id.m2, id.m3[0], id.m3[1], id.m3[2], id.m3[3], + id.m3[4], id.m3[5], id.m3[6], id.m3[7]); + + if (num != kUUIDFormatStringLength) { + return ""; + } + + return str; +} + +const char kISO8601Date[] = "%F"; +const char kISO8601DateHours[] = "%FT%H:00:00.000Z"; + +// Return the current date as a string in the specified format, the following +// constants are provided: +// - kISO8601Date, the ISO 8601 date format, YYYY-MM-DD +// - kISO8601DateHours, the ISO 8601 full date format, YYYY-MM-DDTHH:00:00.000Z +static string CurrentDate(string format) { + time_t now; + time(&now); + char buf[64]; // This should be plenty + strftime(buf, sizeof buf, format.c_str(), gmtime(&now)); + return buf; +} + +const char kTelemetryClientId[] = "TelemetryClientId"; +const char kTelemetryUrl[] = "TelemetryServerURL"; +const char kTelemetrySessionId[] = "TelemetrySessionId"; +const int kTelemetryVersion = 4; + +// Create the payload.metadata node of the crash ping using fields extracted +// from the .extra file +static Json::Value CreateMetadataNode(const Json::Value& aExtra) { + Json::Value node; + + for (Json::ValueConstIterator iter = aExtra.begin(); iter != aExtra.end(); + ++iter) { + Annotation annotation; + + if (AnnotationFromString(annotation, iter.memberName())) { + if (IsAnnotationAllowedForPing(annotation)) { + node[iter.memberName()] = *iter; + } + } + } + + return node; +} + +// Create the payload node of the crash ping +static Json::Value CreatePayloadNode(const Json::Value& aExtra, + const string& aHash, + const string& aSessionId) { + Json::Value payload; + + payload["sessionId"] = aSessionId; + payload["version"] = 1; + payload["crashDate"] = CurrentDate(kISO8601Date); + payload["crashTime"] = CurrentDate(kISO8601DateHours); + payload["hasCrashEnvironment"] = true; + payload["crashId"] = CrashReporter::GetDumpLocalID(); + payload["minidumpSha256Hash"] = aHash; + payload["processType"] = "main"; // This is always a main crash + if (aExtra.isMember("StackTraces")) { + payload["stackTraces"] = aExtra["StackTraces"]; + } + + // Assemble the payload metadata + payload["metadata"] = CreateMetadataNode(aExtra); + + return payload; +} + +// Create the application node of the crash ping +static Json::Value CreateApplicationNode( + const string& aVendor, const string& aName, const string& aVersion, + const string& aDisplayVersion, const string& aPlatformVersion, + const string& aChannel, const string& aBuildId, const string& aArchitecture, + const string& aXpcomAbi) { + Json::Value application; + + application["vendor"] = aVendor; + application["name"] = aName; + application["buildId"] = aBuildId; + application["displayVersion"] = aDisplayVersion; + application["platformVersion"] = aPlatformVersion; + application["version"] = aVersion; + application["channel"] = aChannel; + if (!aArchitecture.empty()) { + application["architecture"] = aArchitecture; + } + if (!aXpcomAbi.empty()) { + application["xpcomAbi"] = aXpcomAbi; + } + + return application; +} + +// Create the root node of the crash ping +static Json::Value CreateRootNode( + const Json::Value& aExtra, const string& aUuid, const string& aHash, + const string& aClientId, const string& aSessionId, const string& aName, + const string& aVersion, const string& aChannel, const string& aBuildId) { + Json::Value root; + root["type"] = "crash"; // This is a crash ping + root["id"] = aUuid; + root["version"] = kTelemetryVersion; + root["creationDate"] = CurrentDate(kISO8601DateHours); + root["clientId"] = aClientId; + + // Parse the telemetry environment + Json::Value environment; + Json::Reader reader; + string architecture; + string xpcomAbi; + string displayVersion; + string platformVersion; + + if (reader.parse(aExtra["TelemetryEnvironment"].asString(), environment, + /* collectComments */ false)) { + if (environment.isMember("build") && environment["build"].isObject()) { + Json::Value build = environment["build"]; + if (build.isMember("architecture") && build["architecture"].isString()) { + architecture = build["architecture"].asString(); + } + if (build.isMember("xpcomAbi") && build["xpcomAbi"].isString()) { + xpcomAbi = build["xpcomAbi"].asString(); + } + if (build.isMember("displayVersion") && + build["displayVersion"].isString()) { + displayVersion = build["displayVersion"].asString(); + } + if (build.isMember("platformVersion") && + build["platformVersion"].isString()) { + platformVersion = build["platformVersion"].asString(); + } + } + + root["environment"] = environment; + } + + root["payload"] = CreatePayloadNode(aExtra, aHash, aSessionId); + root["application"] = CreateApplicationNode( + aExtra["Vendor"].asString(), aName, aVersion, displayVersion, + platformVersion, aChannel, aBuildId, architecture, xpcomAbi); + + return root; +} + +// Generates the URL used to submit the crash ping, see TelemetrySend.sys.mjs +string GenerateSubmissionUrl(const string& aUrl, const string& aId, + const string& aName, const string& aVersion, + const string& aChannel, const string& aBuildId) { + return aUrl + "/submit/telemetry/" + aId + "/crash/" + aName + "/" + + aVersion + "/" + aChannel + "/" + aBuildId + + "?v=" + std::to_string(kTelemetryVersion); +} + +// Write out the ping into the specified file. +// +// Returns true if the ping was written out successfully, false otherwise. +static bool WritePing(const string& aPath, const string& aPing) { + std::ofstream* f = UIOpenWrite(aPath, std::ios::trunc); + bool success = false; + + if (f->is_open()) { + *f << aPing; + f->close(); + success = f->good(); + } + + delete f; + return success; +} + +// Assembles the crash ping using the JSON data extracted from the .extra file +// and sends it using the crash sender. All the telemetry specific data but the +// environment will be stripped from the annotations so that it won't be sent +// together with the crash report. +// +// Note that the crash ping sender is invoked in a fire-and-forget way so this +// won't block waiting for the ping to be delivered. +// +// Returns true if the ping was assembled and handed over to the pingsender +// correctly, also populates the aPingUuid parameter with the ping UUID. Returns +// false otherwise and leaves the aPingUuid parameter unmodified. +bool SendCrashPing(Json::Value& aExtra, const string& aHash, string& aPingUuid, + const string& pingDir) { + // Remove the telemetry-related data from the crash annotations + Json::Value value; + aExtra.removeMember(kTelemetryClientId, &value); + string clientId = value.asString(); + aExtra.removeMember(kTelemetryUrl, &value); + string serverUrl = value.asString(); + aExtra.removeMember(kTelemetrySessionId, &value); + string sessionId = value.asString(); + + if (clientId.empty() || serverUrl.empty() || sessionId.empty()) { + return false; + } + + string buildId = aExtra["BuildID"].asString(); + string channel = aExtra["ReleaseChannel"].asString(); + string name = aExtra["ProductName"].asString(); + string version = aExtra["Version"].asString(); + string uuid = GenerateUUID(); + string url = + GenerateSubmissionUrl(serverUrl, uuid, name, version, channel, buildId); + + if (serverUrl.empty() || uuid.empty()) { + return false; + } + + Json::Value root = CreateRootNode(aExtra, uuid, aHash, clientId, sessionId, + name, version, channel, buildId); + + // Write out the result to the pending pings directory + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string ping = Json::writeString(builder, root); + string pingPath = pingDir + UI_DIR_SEPARATOR + uuid + ".json"; + + if (!WritePing(pingPath, ping)) { + return false; + } + + // Hand over the ping to the sender + std::vector args = {url, pingPath}; + if (UIRunProgram(CrashReporter::GetProgramPath(UI_PING_SENDER_FILENAME), + args)) { + aPingUuid = uuid; + return true; + } else { + return false; + } +} + +} // namespace CrashReporter diff --git a/toolkit/crashreporter/client/resource.h b/toolkit/crashreporter/client/resource.h new file mode 100644 index 0000000000..2e7917daa4 --- /dev/null +++ b/toolkit/crashreporter/client/resource.h @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by crashreporter.rc +// +#define IDD_SENDDIALOG 102 +#define IDR_THROBBER 103 +#define IDD_VIEWREPORTDIALOG 104 +#define IDI_MAINICON 105 +#define IDC_PROGRESS 1003 +#define IDC_DESCRIPTIONTEXT 1004 +#define IDC_CLOSEBUTTON 1005 +#define IDC_VIEWREPORTBUTTON 1006 +#define IDC_SUBMITREPORTCHECK 1007 +#define IDC_INCLUDEURLCHECK 1010 +#define IDC_COMMENTTEXT 1011 +#define IDC_RESTARTBUTTON 1012 +#define IDC_DESCRIPTIONLABEL 1013 +#define IDC_PROGRESSTEXT 1014 +#define IDC_THROBBER 1015 +#define IDC_VIEWREPORTTEXT 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +# ifndef APSTUDIO_READONLY_SYMBOLS +# define _APS_NEXT_RESOURCE_VALUE 106 +# define _APS_NEXT_COMMAND_VALUE 40001 +# define _APS_NEXT_CONTROL_VALUE 1017 +# define _APS_NEXT_SYMED_VALUE 101 +# endif +#endif diff --git a/toolkit/crashreporter/content/crashes.css b/toolkit/crashreporter/content/crashes.css new file mode 100644 index 0000000000..86cc8e3d1d --- /dev/null +++ b/toolkit/crashreporter/content/crashes.css @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +:root { + font-family: sans-serif; + margin: 40px auto; + min-width: 30em; + max-width: 60em; +} + +.hidden { + display: none; +} + +/* Table layout */ + +table { + width: 100%; + padding-bottom: 2em; + border-spacing: 0; +} + +th { + text-align: start; +} + +th, td { + border-bottom: 1px solid var(--in-content-border-color); +} + +th, +#submitted td { + /* Unsubmitted table already gets spacing from button */ + padding-block: 10px; +} + +.submit-button, +.crash-link { + float: inline-end; +} + +/* Other elements */ + +.table-title-container { + align-items: center; + display: flex; + justify-content: space-between; +} + +.submitting { + background-image: image-set( + url(chrome://global/skin/icons/loading.png), + url(chrome://global/skin/icons/loading@2x.png) 2x + ); + background-position: center; + background-repeat: no-repeat; + background-size: 16px; +} + +.submitting .submit-crash-button-label { + display: none; +} + +.failed-to-submit { + color: #ca8695; +} diff --git a/toolkit/crashreporter/content/crashes.html b/toolkit/crashreporter/content/crashes.html new file mode 100644 index 0000000000..088e01762f --- /dev/null +++ b/toolkit/crashreporter/content/crashes.html @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/crashreporter/content/crashes.js b/toolkit/crashreporter/content/crashes.js new file mode 100644 index 0000000000..b8f88f285e --- /dev/null +++ b/toolkit/crashreporter/content/crashes.js @@ -0,0 +1,316 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +let reportURL; + +const { CrashReports } = ChromeUtils.importESModule( + "resource://gre/modules/CrashReports.sys.mjs" +); + +ChromeUtils.defineESModuleGetters(this, { + CrashSubmit: "resource://gre/modules/CrashSubmit.sys.mjs", +}); + +document.addEventListener("DOMContentLoaded", () => { + populateReportLists(); + document + .getElementById("clearUnsubmittedReports") + .addEventListener("click", () => { + clearUnsubmittedReports().catch(console.error); + }); + document + .getElementById("submitAllUnsubmittedReports") + .addEventListener("click", () => { + submitAllUnsubmittedReports().catch(console.error); + }); + document + .getElementById("clearSubmittedReports") + .addEventListener("click", () => { + clearSubmittedReports().catch(console.error); + }); +}); + +const buildID = Services.appinfo.appBuildID; + +/** + * Adds the crash reports with submission buttons and links + * to the unsubmitted and submitted crash report lists. + * If breakpad.reportURL is not set, displays a misconfiguration message + * instead. + */ +function populateReportLists() { + try { + reportURL = Services.prefs.getCharPref("breakpad.reportURL"); + // Ignore any non http/https urls + if (!/^https?:/i.test(reportURL)) { + reportURL = null; + } + } catch (e) { + reportURL = null; + } + if (!reportURL) { + document.getElementById("noConfig").classList.remove("hidden"); + return; + } + + const reports = CrashReports.getReports(); + const dateFormatter = new Services.intl.DateTimeFormat(undefined, { + timeStyle: "short", + dateStyle: "short", + }); + reports.forEach(report => + addReportRow(report.pending, report.id, report.date, dateFormatter) + ); + showAppropriateSections(); +} + +/** + * Adds a crash report with the appropriate submission button + * or viewing link to the unsubmitted or submitted report list + * based on isPending. + * + * @param {Boolean} isPending whether the crash is up for submission + * @param {String} id the unique id of the crash report + * @param {Date} date either the date of crash or date of submission + * @param {Object} dateFormatter formatter for presenting dates to users + */ +function addReportRow(isPending, id, date, dateFormatter) { + const rowTemplate = document.getElementById("crashReportRow"); + const row = document + .importNode(rowTemplate.content, true) + .querySelector("tr"); + row.id = id; + + const cells = row.querySelectorAll("td"); + cells[0].appendChild(document.createTextNode(id)); + cells[1].appendChild(document.createTextNode(dateFormatter.format(date))); + + if (isPending) { + const buttonTemplate = document.getElementById("crashSubmitButton"); + const button = document + .importNode(buttonTemplate.content, true) + .querySelector("button"); + const buttonText = button.querySelector("span"); + button.addEventListener("click", () => + submitPendingReport(id, row, button, buttonText, dateFormatter) + ); + cells[2].appendChild(button); + document.getElementById("unsubmitted").appendChild(row); + } else { + const linkTemplate = document.getElementById("viewCrashLink"); + const link = document + .importNode(linkTemplate.content, true) + .querySelector("a"); + link.href = `${reportURL}${id}`; + cells[2].appendChild(link); + document.getElementById("submitted").appendChild(row); + } +} + +/** + * Shows or hides each of the unsubmitted and submitted report list + * based on whether they contain at least one crash report. + * If hidden, the submitted report list is replaced by a message + * indicating that no crash reports have been submitted. + */ +function showAppropriateSections() { + let hasUnsubmitted = + document.getElementById("unsubmitted").childElementCount > 0; + document + .getElementById("reportListUnsubmitted") + .classList.toggle("hidden", !hasUnsubmitted); + + let hasSubmitted = document.getElementById("submitted").childElementCount > 0; + document + .getElementById("reportListSubmitted") + .classList.toggle("hidden", !hasSubmitted); + document + .getElementById("noSubmittedReports") + .classList.toggle("hidden", hasSubmitted); +} + +/** + * Changes the provided button to display a spinner. Then, tries to submit the + * crash report for the provided id. On success, removes the crash report from + * the list of unsubmitted crash reports and adds a new crash report to the list + * of submitted crash reports. On failure, changes the provided button to display + * a red error message. + * + * @param {String} reportId the unique id of the crash report + * @param {HTMLTableRowElement} row the table row of the crash report + * @param {HTMLButtonElement} button the button pressed to start the submission + * @param {HTMLSpanElement} buttonText the text inside the pressed button + * @param {Object} dateFormatter formatter for presenting dates to users + */ +function submitPendingReport(reportId, row, button, buttonText, dateFormatter) { + button.classList.add("submitting"); + document.getElementById("submitAllUnsubmittedReports").disabled = true; + CrashSubmit.submit(reportId, CrashSubmit.SUBMITTED_FROM_ABOUT_CRASHES, { + noThrottle: true, + }) + .then( + remoteCrashID => { + document.getElementById("unsubmitted").removeChild(row); + const report = CrashReports.getReports().filter( + report => report.id === remoteCrashID + ); + addReportRow(false, remoteCrashID, report.date, dateFormatter); + showAppropriateSections(); + dispatchCustomEvent("CrashSubmitSucceeded"); + }, + () => { + button.classList.remove("submitting"); + button.classList.add("failed-to-submit"); + document.l10n.setAttributes( + buttonText, + "submit-crash-button-failure-label" + ); + dispatchCustomEvent("CrashSubmitFailed"); + } + ) + .finally(() => { + document.getElementById("submitAllUnsubmittedReports").disabled = false; + }); +} + +/** + * Deletes unsubmitted and old crash reports from the user's device. + * Then, hides the list of unsubmitted crash reports. + */ +async function clearUnsubmittedReports() { + const [title, description] = await document.l10n.formatValues([ + { id: "delete-confirm-title" }, + { id: "delete-unsubmitted-description" }, + ]); + if (!Services.prompt.confirm(window, title, description)) { + return; + } + + await enqueueCleanup(() => cleanupFolder(CrashReports.pendingDir.path)); + await enqueueCleanup(clearOldReports); + document.getElementById("reportListUnsubmitted").classList.add("hidden"); +} + +/** + * Submits all the pending crash reports and removes all pending reports from pending reports list + * and add them to submitted crash reports. + */ +async function submitAllUnsubmittedReports() { + for ( + var i = 0; + i < document.getElementById("unsubmitted").childNodes.length; + i++ + ) { + document + .getElementById("unsubmitted") + .childNodes[i].cells[2].childNodes[0].click(); + } +} + +/** + * Deletes submitted and old crash reports from the user's device. + * Then, hides the list of submitted crash reports. + */ +async function clearSubmittedReports() { + const [title, description] = await document.l10n.formatValues([ + { id: "delete-confirm-title" }, + { id: "delete-submitted-description" }, + ]); + if (!Services.prompt.confirm(window, title, description)) { + return; + } + + await enqueueCleanup(async () => + cleanupFolder( + CrashReports.submittedDir.path, + async entry => entry.name.startsWith("bp-") && entry.name.endsWith(".txt") + ) + ); + await enqueueCleanup(clearOldReports); + document.getElementById("reportListSubmitted").classList.add("hidden"); + document.getElementById("noSubmittedReports").classList.remove("hidden"); +} + +/** + * Deletes old crash reports from the user's device. + */ +async function clearOldReports() { + const oneYearAgo = Date.now() - 31586000000; + await cleanupFolder(CrashReports.reportsDir.path, async entry => { + if ( + !entry.name.startsWith("InstallTime") || + entry.name == "InstallTime" + buildID + ) { + return false; + } + + const stat = await IOUtils.stat(entry.path); + return stat.lastModified < oneYearAgo; + }); +} + +/** + * Deletes files from the user's device at the specified path + * that match the provided filter. + * + * @param {String} path the directory location to delete form + * @param {Function} filter function taking in a file entry and + * returning whether to delete the file + */ +async function cleanupFolder(path, filter) { + function entry(path) { + return { + path, + name: PathUtils.filename(path), + }; + } + let children; + try { + children = await IOUtils.getChildren(path); + } catch (e) { + if (DOMException.isInstance(e) || e.name !== "NotFoundError") { + throw e; + } + } + + for (const childPath of children) { + if (!filter || (await filter(entry(childPath)))) { + await IOUtils.remove(childPath); + } + } +} + +/** + * Dispatches an event with the specified name. + * + * @param {String} name the name of the event + */ +function dispatchCustomEvent(name) { + document.dispatchEvent( + new CustomEvent(name, { bubbles: true, cancelable: false }) + ); +} + +let cleanupQueue = Promise.resolve(); + +/** + * Enqueue a cleanup function. + * + * Instead of directly calling cleanup functions as a result of DOM + * interactions, queue them through this function so that we do not have + * overlapping executions of cleanup functions. + * + * Cleanup functions overlapping could cause a race where one function is + * attempting to stat a file while another function is attempting to delete it, + * causing an exception. + * + * @param fn The cleanup function to call. It will be called once the last + * cleanup function has resolved. + * + * @returns A promise to await instead of awaiting the cleanup function. + */ +function enqueueCleanup(fn) { + cleanupQueue = cleanupQueue.then(fn); + return cleanupQueue; +} diff --git a/toolkit/crashreporter/crashreporter.mozbuild b/toolkit/crashreporter/crashreporter.mozbuild new file mode 100644 index 0000000000..56918ae900 --- /dev/null +++ b/toolkit/crashreporter/crashreporter.mozbuild @@ -0,0 +1,34 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +LOCAL_INCLUDES += [ + "/toolkit/crashreporter/breakpad-client", + "/toolkit/crashreporter/google-breakpad/src", +] + +# Suppress warnings in third-party code. +if CONFIG["CC_TYPE"] == "clang-cl": + CXXFLAGS += [ + "-Wno-macro-redefined", + ] +elif CONFIG["CC_TYPE"] in ("clang", "gcc"): + CXXFLAGS += [ + "-Wno-unused-local-typedefs", + "-Wno-deprecated-declarations", + "-Wno-bool-compare", + "-Wno-unused-but-set-variable", + ] + +if CONFIG["CC_TYPE"] in ("clang", "clang-cl"): + CXXFLAGS += [ + "-Wno-c++11-narrowing", + ] + +CXXFLAGS += [ + "-Wno-implicit-fallthrough", +] + +DEFINES["NO_STABS_SUPPORT"] = True diff --git a/toolkit/crashreporter/docs/Using_the_Mozilla_symbol_server.rst b/toolkit/crashreporter/docs/Using_the_Mozilla_symbol_server.rst new file mode 100644 index 0000000000..238daa1225 --- /dev/null +++ b/toolkit/crashreporter/docs/Using_the_Mozilla_symbol_server.rst @@ -0,0 +1,180 @@ +Using the Mozilla symbol server +=============================== + +The Mozilla project runs a symbol server for trunk Firefox nightly and +release builds on Windows. Symbols are available for at least 30 +previous days worth of nightly builds, and Firefox releases from +2.0.0.4. This allows debugging of those builds without forcing all users +to download large debugging files. The server functions like +`Microsoft's symbol server `__ +so the documentation there can be useful. + +Note that because Mozilla release builds are heavily optimized, +debugging is not always easy. The debugger will not be able to show you +the content of all variables and the execution path can seem strange +because of inlining, tail calls, and other compiler optimizations. The +only workaround is to build an unoptimized local build. + +The official symbol server URL for Firefox is ``https://symbols.mozilla.org/``. +You cannot visit this URL directly: you must add it to the symbol path of your +debugging tool. In the examples below, a local cache directory is used to avoid +repeatedly fetching the PDB from the server. Replace +``C:\Users\myname\symbols`` with an appropriate cache directory on your +machine. + +Using the symbol server in Microsoft Visual C++ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +|The Tools menu of Visual C++ with the Options item selected| |The +Visual C++ 2017 Symbols pane of the Options dialog with the Mozilla +symbol server configured| + +Using the symbol server in Windbg +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Windbg symbol path is configured with a string value delimited with +asterisk characters. To use only the Mozilla symbol server, add the +following entry to your symbol path (**note:** you can replace ``C:\symcache\`` +with any writable directory on your computer, if you'd prefer a different +location for downloaded symbols): + +.. code:: + + SRV*c:\symcache\*https://symbols.mozilla.org/ + +Set this string as ``_NT_SYMBOL_PATH`` in the environment, using +the Windbg menus, or by typing the ``.sympath`` command. If you +would like to get symbols from Microsoft's symbol server as well, you +should list that first (**note:** you can replace ``C:\symcache\`` +with any writable directory on your computer, if you'd prefer a different +location for downloaded symbols): + +.. code:: + + SRV*c:\symcache\*http://msdl.microsoft.com/download/symbols;SRV*c:\symcache\*https://symbols.mozilla.org/ + +|Image:symbol-server-windbg-menu.jpg| |The WinDbg Symbol Search Path +dialog with the Mozilla symbol server configured| + +The default symbol server only contains debug information for release builds. +In case you need to debug a minidump which was generated by a try build you'll +need to add the symbol server's `try` URL instead: + +.. code:: + + SRV*c:\symcache\*https://symbols.mozilla.org/try/ + +Note that you do not need _both_ URLs; despite its name, the `try` +endpoint-family will return symbols from both release and try builds +(in that order). + +Downloading symbols using symchk.exe +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also download the symbols using symchk.exe, part of Microsoft's +Debugging Tools for Windows. The command should look like this (again, +you can replace ``C:\symcache\`` with any writable directory on +your computer, if you'd prefer a different location for downloaded +symbols): + +:: + + "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe" /r "C:\Program Files\Mozilla Firefox/*" /s SRV*C:\symcache\*https://symbols.mozilla.org/ + +Note the ``\*`` after the Mozilla directory. The output of this command should +be similar to: + +:: + + SYMCHK: api-ms-win-core-file-l1-2-0.dll FAILED - api-ms-win-core-file-l1-2-0.pdb mismatched or not found + SYMCHK: api-ms-win-core-file-l2-1-0.dll FAILED - api-ms-win-core-file-l2-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-core-localization-l1-2-0.dll FAILED - api-ms-win-core-localization-l1-2-0.pdb mismatched or not found + SYMCHK: api-ms-win-core-processthreads-l1-1-1.dll FAILED - api-ms-win-core-processthreads-l1-1-1.pdb mismatched or not found + SYMCHK: api-ms-win-core-synch-l1-2-0.dll FAILED - api-ms-win-core-synch-l1-2-0.pdb mismatched or not found + SYMCHK: api-ms-win-core-timezone-l1-1-0.dll FAILED - api-ms-win-core-timezone-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-conio-l1-1-0.dll FAILED - api-ms-win-crt-conio-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-convert-l1-1-0.dll FAILED - api-ms-win-crt-convert-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-environment-l1-1-0.dll FAILED - api-ms-win-crt-environment-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-filesystem-l1-1-0.dll FAILED - api-ms-win-crt-filesystem-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-heap-l1-1-0.dll FAILED - api-ms-win-crt-heap-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-locale-l1-1-0.dll FAILED - api-ms-win-crt-locale-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-math-l1-1-0.dll FAILED - api-ms-win-crt-math-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-multibyte-l1-1-0.dll FAILED - api-ms-win-crt-multibyte-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-private-l1-1-0.dll FAILED - api-ms-win-crt-private-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-process-l1-1-0.dll FAILED - api-ms-win-crt-process-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-runtime-l1-1-0.dll FAILED - api-ms-win-crt-runtime-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-stdio-l1-1-0.dll FAILED - api-ms-win-crt-stdio-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-string-l1-1-0.dll FAILED - api-ms-win-crt-string-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-time-l1-1-0.dll FAILED - api-ms-win-crt-time-l1-1-0.pdb mismatched or not found + SYMCHK: api-ms-win-crt-utility-l1-1-0.dll FAILED - api-ms-win-crt-utility-l1-1-0.pdb mismatched or not found + SYMCHK: d3dcompiler_47.dll FAILED - D3DCompiler_47.pdb mismatched or not found + SYMCHK: maintenanceservice_installer.exe FAILED - Built without debugging information. + SYMCHK: msvcp140.dll FAILED - msvcp140.amd64.pdb mismatched or not found + SYMCHK: ucrtbase.dll FAILED - ucrtbase.pdb mismatched or not found + SYMCHK: vcruntime140.dll FAILED - vcruntime140.amd64.pdb mismatched or not found + SYMCHK: helper.exe FAILED - Built without debugging information. + + SYMCHK: FAILED files = 27 + SYMCHK: PASSED + IGNORED files = 60 + +.. _Downloading symbols on Linux / Mac OS X: + +Downloading symbols on Linux / Mac OS X +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are on Linux and running GDB 7.9 or newer, you can use `this GDB +Python script `__ to +automatically fetch symbols. You will need to source this script before +loading symbols (the part where it spends a few seconds loading each .so +when you attach gdb). If you want to reload symbols, you can try: + +:: + + nosharedlibrary + sharedlibrary lib + +On older GDB and Mac OS X there is a `Python script to download symbols +from the Mozilla symbol +server `__ +for :ref:`gdb `, Shark and other software +that uses symbols. Note that the symbol file for the XUL library is very +large and takes some time to download. This may make it appear as if the +script has gotten stuck, but it will continue. + +Symbol indices are named like so: +symbols.mozilla.org/{lowercased:Name}/{lowercased:Name}-{Version}-{Platform}-{BuildID}-symbols.txt. +The Platform is either 'Darwin' (for Mac) or 'Linux'. The rest of values +are based on the contents of the application.ini file under the [App] +heading: For example, the Thunderbird 3.1b2 release with +Name=Thunderbird, Version=3.1b2, BuildID=20100430125415 would have a +filename of "thunderbird-3.1b2-Linux-20100430125415-symbols.txt" under +the thunderbird directory at symbols.mozilla.org. Its contents are a +list of paths to files, all relative to the directory the +BLAH-symbols.txt file is found in. + +The source server +~~~~~~~~~~~~~~~~~ + +In addition to symbols, Mozilla also has a +:ref:`source server `, letting you do +source-level debugging and inspection on demand. + +Troubleshooting: Symbols will not download +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If symbols will not download no matter what you do, the problem may be +that Internet Explorer has been set to the **Work Offline** mode. You +will not receive any warnings of this in Windbg, Visual C++ or Visual +Studio. Even using the command line with symchk.exe to download symbols +will fail. This is because Microsoft uses Internet Explorer's internet & +proxy settings to download the symbol files. Check the File menu of +Internet Explorer to ensure "Work Offline" is unchecked. + +.. |The Tools menu of Visual C++ with the Options item selected| image:: img/vs_tools_options.png + :class: internal +.. |The Visual C++ 2017 Symbols pane of the Options dialog with the Mozilla symbol server configured| image:: img/snip_20170901070042.png + :class: internal +.. |Image:symbol-server-windbg-menu.jpg| image:: img/symbol-server-windbg-menu.jpg + :class: internal +.. |The WinDbg Symbol Search Path dialog with the Mozilla symbol server configured| image:: img/snip_20170901081816.png + :class: internal diff --git a/toolkit/crashreporter/docs/img/snip_20170901070042.png b/toolkit/crashreporter/docs/img/snip_20170901070042.png new file mode 100644 index 0000000000..94f266d91e Binary files /dev/null and b/toolkit/crashreporter/docs/img/snip_20170901070042.png differ diff --git a/toolkit/crashreporter/docs/img/snip_20170901081816.png b/toolkit/crashreporter/docs/img/snip_20170901081816.png new file mode 100644 index 0000000000..550f0d28ea Binary files /dev/null and b/toolkit/crashreporter/docs/img/snip_20170901081816.png differ diff --git a/toolkit/crashreporter/docs/img/symbol-server-windbg-menu.jpg b/toolkit/crashreporter/docs/img/symbol-server-windbg-menu.jpg new file mode 100644 index 0000000000..000bc761d7 Binary files /dev/null and b/toolkit/crashreporter/docs/img/symbol-server-windbg-menu.jpg differ diff --git a/toolkit/crashreporter/docs/img/vs_tools_options.png b/toolkit/crashreporter/docs/img/vs_tools_options.png new file mode 100644 index 0000000000..c16d2094a6 Binary files /dev/null and b/toolkit/crashreporter/docs/img/vs_tools_options.png differ diff --git a/toolkit/crashreporter/docs/index.rst b/toolkit/crashreporter/docs/index.rst new file mode 100644 index 0000000000..f2444a75c6 --- /dev/null +++ b/toolkit/crashreporter/docs/index.rst @@ -0,0 +1,266 @@ +============== +Crash Reporter +============== + +Overview +======== + +The **crash reporter** is a subsystem to record and manage application +crash data. + +While the subsystem is known as *crash reporter*, it helps to think of +it more as a *process dump manager*. This is because the heart of this +subsystem is really managing process dump files and these files are +created not only from process crashes but also from hangs and other +exceptional events. + +The crash reporter subsystem is composed of a number of pieces working +together. + +Breakpad + Breakpad is a library and set of tools to make collecting process + information (notably dumps from crashes) easy. Breakpad is a 3rd + party project (originally developed by Google) that is imported into + the tree. + +Dump files + Breakpad produces files called *dump files* that hold process data + (stacks, heap data, etc). + +Crash Reporter Client + The crash reporter client is a standalone executable that is launched + to handle dump files. This application optionally submits crashes to + Mozilla (or the configured server). + +Minidump Analyzer + The minidump analyzer is a standalone executable that is launched by the + crash reporter client or by the browser itself to extract stack traces from + the dump files generated during a crash. It appends the stack traces to the + .extra file associated with the crash dump. + +Ping Sender + The ping sender is a standalone executable that is launched by the crash + reporter client to deliver a crash ping to our telemetry servers. The ping + sender is used to speed up delivery of the crash ping which would otherwise + have to wait for Firefox to be restarted in order to be sent. + +How Main-Process Crash Handling Works +===================================== + +The crash handler is hooked up very early in the Gecko process lifetime. +It all starts in ``XREMain::XRE_mainInit()`` from ``nsAppRunner.cpp``. +Assuming crash reporting is enabled, this startup function registers an +exception handler for the process and tells the crash reporter subsystem +about basic metadata such as the application name and version. + +The registration of the crash reporter exception handler doubles as +initialization of the crash reporter itself. This happens in +``CrashReporter::SetExceptionHandler()`` from ``nsExceptionHandler.cpp``. +The crash reporter figures out what application to use for reporting +dumped crashes and where to store these dump files on disk. The Breakpad +exception handler (really just a mechanism for dumping process state) is +initialized as part of this function. The Breakpad exception handler is +a ``google_breakpad::ExceptionHandler`` instance and it's stored as +``gExceptionHandler``. + +As the application runs, various other systems may write *annotations* +or *notes* to the crash reporter to indicate state of the application, +help with possible reasons for a current or future crash, etc. These are +performed via ``CrashReporter::AnnotateCrashReport()`` and +``CrashReporter::AppendAppNotesToCrashReport()`` from +``nsExceptionHandler.h``. + +For well running applications, this is all that happens. However, if a +crash or similar exceptional event occurs (such as a hang), we need to +write a crash report. + +When an event worthy of writing a dump occurs, the Breakpad exception +handler is invoked and Breakpad does its thing. When Breakpad has +finished, it calls back into ``CrashReporter::MinidumpCallback()`` from +``nsExceptionHandler.cpp`` to tell the crash reporter about what was +written. + +``MinidumpCallback()`` performs a number of actions once a dump has been +written. It writes a file with the time of the crash so other systems can +easily determine the time of the last crash. It supplements the dump +file with an *extra* file containing Mozilla-specific metadata. This data +includes the annotations set via ``CrashReporter::AnnotateCrashReport()`` +as well as time since last crash, whether garbage collection was active at +the time of the crash, memory statistics, etc. + +If the *crash reporter client* is enabled, ``MinidumpCallback()`` invokes +it. It simply tries to create a new *crash reporter client* process (e.g. +*crashreporter.exe*) with the path to the written minidump file as an +argument. + +The *crash reporter client* performs a number of roles. There's a lot going +on, so you may want to look at ``main()`` in ``crashreporter.cpp``. First, +stack traces are extracted from the dump via the *minidump analyzer* tool. +The resulting traces are appended to the .extra file of the crash together with +the SHA256 hash of the minidump file. Once this +is done a crash ping is assembled holding the same information as the one +generated by the ```CrashManager``` and it's sent to the telemetry servers via +the *ping sender* program. The UUID of the ping is then stored in the extra +file; the ```CrashManager``` will later pick it up and generate a new ping +with the same UUID so that the telemetry server can deduplicate both pings. +Then, the +*crash reporter client* verifies that the dump data is sane. If it isn't +(e.g. required metadata is missing), the dump data is ignored. If dump data +looks sane, the dump data +is moved into the *pending* directory for the configured data directory +(defined via the ``MOZ_CRASHREPORTER_DATA_DIRECTORY`` environment variable +or from the UI). Once this is done, the main crash reporter UI is displayed +via ``UIShowCrashUI()``. The crash reporter UI is platform specific: there +are separate versions for Windows, OS X, and various \*NIX presentation +flavors (such as GTK). The basic gist is a dialog is displayed to the user +and the user has the opportunity to submit this dump data to a remote +server. + +If a dump is submitted via the crash reporter, the raw dump files are +removed from the *pending* directory and a file containing the +crash ID from the remote server for the submitted dump is created in the +*submitted* directory. + +If the user chooses not to submit a dump in the crash reporter UI, the dump +files are deleted. + +And that's pretty much what happens when a crash/dump is written! + +Plugin and Child Process Crashes +================================ + +Crashes in plugin and child processes are also managed by the crash +reporting subsystem. + +Child process crashes are handled by the ``mozilla::dom::CrashReporterParent`` +class defined in ``dom/ipc``. When a child process crashes, the toplevel IPDL +actor should check for it by calling TakeMinidump in its ``ActorDestroy`` +Method: see ``mozilla::plugins::PluginModuleParent::ActorDestroy`` and +``mozilla::plugins::PluginModuleParent::ProcessFirstMinidump``. That method +is responsible for calling +``mozilla::dom::CrashReporterParent::GenerateCrashReportForMinidump`` with +appropriate crash annotations specific to the crash. All child-process +crashes are annotated with a ``ProcessType`` annotation, such as "content" or +"plugin". + +Once the minidump file has been generated the +``mozilla::dom::CrashReporterHost`` is notified of the crash. It will first +try to extract the stack traces from the minidump file using the +*minidump analyzer*. Then the stack traces will be stored in the extra file +together with the rest of the crash annotations and finally the crash will be +recorded by calling ```CrashService.addCrash()```. This last step adds the +crash to the ```CrashManager``` database and automatically sends a crash ping +with information about the crash. + +Submission of child process crashes is handled by application code. This +code prompts the user to submit crashes in context-appropriate UI and then +submits the crashes using ``CrashSubmit.jsm``. + +Memory Reports +============== + +When a process detects that it is running low on memory, a memory report is +saved. If the process crashes, the memory report will be included with the crash +report. ``nsThread::SaveMemoryReportNearOOM()`` checks to see if the process is +low on memory every 30 seconds at most and saves a report every 3 minutes at +most. Since a child process cannot actually save to the hard drive, it instead +notifies its parent process, which saves the report for it. If a crash does +occur, the memory report is moved to the *pending* directory with the other dump +data and an annotation is added to indicate the presence of the report. This +happens in ``nsExceptionHandler.cpp``, but occurs in different functions +depending on what process crashed. When the main process crashes, this happens +in ``MinidumpCallback()``. When a child process crashes, it happens in +``OnChildProcessDumpRequested()``, with the annotation being added in +``WriteExtraData()``. + +Plugin Hangs +============ + +Plugin hangs are handled as crash reports. If a plugin doesn't respond to an +IPC message after 60 seconds, the plugin IPC code will take minidumps of all +of the processes involved and then kill the plugin. + +In this case, there will be only one .extra file with the crash report metadata, +but there will be multiple dump files: at least one for the browser process and +one for the plugin process. All of these files are submitted together as a +unit. Before submission, the filenames of the files are linked: + +- **uuid.extra** - *annotations, includes the `additional_minidumps` annotation + holding a comma-separated list of the additional minidumps* +- **uuid.dmp** - *plugin process dump file* +- **uuid-.dmp** - *other process dump file as listed in + additional_minidumps* + +about:crashes +============= + +If the crash reporter subsystem is enabled, the *about:crashes* +page will be registered with the application. This page provides +information about previous and submitted crashes. + +It is also possible to submit crashes from *about:crashes*. + +Environment variables affecting crash reporting +=============================================== + +The exception handler and crash reporter client behavior can be altered by +setting certain environment variables, some of these variables are used for +testing but quite a few have only internal users. + +User-specified environment variables +------------------------------------ + +- ``MOZ_CRASHREPORTER`` - The opposite of MOZ_CRASHREPORTER_DISABLE, force + crash reporting on even if disabled in application.ini. You must use this to + enable crash reporting on debug builds. +- ``MOZ_CRASHREPORTER_DISABLE`` - Disable Breakpad crash reporting completely + in non-debug builds. You can use this if you would rather use the JIT + debugger on Windows with the symbol server, for example. +- ``MOZ_CRASHREPORTER_FULLDUMP`` - Store full application memory in the + minidump, so you can open it in a Microsoft debugger. Don't submit it to the + server. (Windows only.) +- ``MOZ_CRASHREPORTER_NO_DELETE_DUMP`` - Don't delete the crash report dump + file after submitting it to the server. Minidumps will still be moved to the + "Crash Reports/pending" directory. +- ``MOZ_CRASHREPORTER_NO_REPORT`` - Save the minidump file but don't launch the + crash reporting UI or send the report to the server. Minidumps will be stored + in the user's profile directory, in a subdirectory named "minidumps". +- ``MOZ_CRASHREPORTER_SHUTDOWN`` - Save the minidump and then force the + application to close. This is useful for content crashes that don't normally + close the chrome (main application) processes. This variable would cause the + application to close as well. +- ``MOZ_CRASHREPORTER_URL`` - Sets the URL that the crash reporter will submit + reports to. + +Environment variables used internally +------------------------------------- + +- ``MOZ_CRASHREPORTER_AUTO_SUBMIT`` - When set causes the crash reporter client + to skip the UI flow and submit the crash report directly. +- ``MOZ_CRASHREPORTER_DATA_DIRECTORY`` - Platform dependent data directory, the + pending crash reports will be stored in a subdirectory of this path. This + overrides the default one generated by the client's code. +- ``MOZ_CRASHREPORTER_DUMP_ALL_THREADS`` - When set to 1 stack traces for + all threads are generated and sent in the crash ping, when not set only the + trace for the crashing thread will be generated instead. +- ``MOZ_CRASHREPORTER_EVENTS_DIRECTORY`` - Path of the directory holding the + crash event files. +- ``MOZ_CRASHREPORTER_PING_DIRECTORY`` - Path of the directory holding the + pending crash ping files. +- ``MOZ_CRASHREPORTER_RESTART_ARG_`` - Each of these variable specifies one + of the arguments that had been passed to the application, starting with the + first after the executable, the crash reporter client uses them for restarting + it. +- ``MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE`` - If a XUL app file was specified + when starting the app it has to be stored in this variable so that the crash + reporter client can restart the application. +- ``MOZ_CRASHREPORTER_STRINGS_OVERRIDE`` - Overrides the path used to load the + .ini file holding the strings used in the crash reporter client UI. + +Other topics +============ + +.. toctree:: + :titlesonly: + + Using_the_Mozilla_symbol_server diff --git a/toolkit/crashreporter/generate_crash_reporter_sources.py b/toolkit/crashreporter/generate_crash_reporter_sources.py new file mode 100644 index 0000000000..b8c3333557 --- /dev/null +++ b/toolkit/crashreporter/generate_crash_reporter_sources.py @@ -0,0 +1,259 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import string +import sys +import textwrap + +import yaml + +############################################################################### +# Language-agnostic functionality # +############################################################################### + +template_header = ( + "/* This file was autogenerated by " + "toolkit/crashreporter/generate_crash_reporter_sources.py. DO NOT EDIT */\n\n" +) + + +def validate_annotations(annotations): + """Ensure that the annotations have all the required fields""" + + for name, data in sorted(annotations.items()): + if "description" not in data: + print("Annotation " + name + " does not have a description\n") + sys.exit(1) + if "type" not in data: + print("Annotation " + name + " does not have a type\n") + sys.exit(1) + else: + annotation_type = data.get("type") + valid_types = ["string", "boolean", "u32", "u64", "usize"] + if not any(annotation_type == t for t in valid_types): + print( + "Annotation " + + name + + " has an unknown type: " + + annotation_type + + "\n" + ) + sys.exit(1) + + +def read_annotations(annotations_filename): + """Read the annotations from a YAML file. + If an error is encountered quit the program.""" + + try: + with open(annotations_filename, "r") as annotations_file: + annotations = yaml.safe_load(annotations_file) + except (IOError, ValueError) as e: + print("Error parsing " + annotations_filename + ":\n" + str(e) + "\n") + sys.exit(1) + + validate_annotations(annotations) + + return annotations + + +def read_template(template_filename): + """Read the contents of the template. + If an error is encountered quit the program.""" + + try: + with open(template_filename, "r") as template_file: + template = template_file.read() + except IOError as ex: + print("Error when reading " + template_filename + ":\n" + str(ex) + "\n") + sys.exit(1) + + return template + + +def extract_crash_ping_allowedlist(annotations): + """Extract an array holding the names of the annotations allowed for + inclusion in the crash ping.""" + + return [ + name for (name, data) in sorted(annotations.items()) if data.get("ping", False) + ] + + +def extract_skiplist(annotations): + """Extract an array holding the names of the annotations that should be + skipped and the values which will cause them to be skipped.""" + + return [ + (name, data.get("skip_if")) + for (name, data) in sorted(annotations.items()) + if len(data.get("skip_if", "")) > 0 + ] + + +def type_to_enum(annotation_type): + """Emit the enum value corresponding to each annotation type.""" + + if annotation_type == "string": + return "String" + elif annotation_type == "boolean": + return "Boolean" + elif annotation_type == "u32": + return "U32" + elif annotation_type == "u64": + return "U64" + elif annotation_type == "usize": + return "USize" + + +def extract_types(annotations): + """Extract an array holding the type of each annotation.""" + + return [type_to_enum(data.get("type")) for (_, data) in sorted(annotations.items())] + + +############################################################################### +# C++ code generation # +############################################################################### + + +def generate_strings(annotations): + """Generate strings corresponding to every annotation.""" + + names = [ + ' "' + data.get("altname", name) + '"' + for (name, data) in sorted(annotations.items()) + ] + + return ",\n".join(names) + + +def generate_enum(annotations): + """Generate the C++ typed enum holding all the annotations and return it + as a string.""" + + enum = "" + + for i, (name, _) in enumerate(sorted(annotations.items())): + enum += " " + name + " = " + str(i) + ",\n" + + enum += " Count = " + str(len(annotations)) + + return enum + + +def generate_annotations_array_initializer(contents): + """Generates the initializer for a C++ array of annotations.""" + + initializer = [" Annotation::" + name for name in contents] + + return ",\n".join(initializer) + + +def generate_skiplist_initializer(contents): + """Generates the initializer for a C++ array of AnnotationSkipValue structs.""" + + initializer = [ + " { Annotation::" + name + ', "' + value + '" }' for (name, value) in contents + ] + + return ",\n".join(initializer) + + +def generate_types_initializer(contents): + """Generates the initializer for a C++ array of AnnotationType values.""" + + initializer = [" AnnotationType::" + typename for typename in contents] + + return ",\n".join(initializer) + + +def generate_header(template, annotations): + """Generate a header by filling the template with the the list of + annotations and return it as a string.""" + + allowedlist = extract_crash_ping_allowedlist(annotations) + skiplist = extract_skiplist(annotations) + typelist = extract_types(annotations) + + return template_header + string.Template(template).substitute( + { + "enum": generate_enum(annotations), + "strings": generate_strings(annotations), + "allowedlist": generate_annotations_array_initializer(allowedlist), + "skiplist": generate_skiplist_initializer(skiplist), + "types": generate_types_initializer(typelist), + } + ) + + +def emit_header(output, template_filename, annotations_filename): + """Generate the C++ header from the template and write it out.""" + + annotations = read_annotations(annotations_filename) + template = read_template(template_filename) + generated_header = generate_header(template, annotations) + + try: + output.write(generated_header) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) + + +############################################################################### +# Java code generation # +############################################################################### + + +def generate_java_array_initializer(contents): + """Generates the initializer for an array of strings. + Effectively turns `["a", "b"]` into ' \"a\",\n \"b\"\n'.""" + + initializer = "" + + for name in contents: + initializer += ' "' + name + '",\n' + + return initializer.strip(",\n") + + +def generate_class(template, annotations): + """Fill the class template from the list of annotations.""" + + allowedlist = extract_crash_ping_allowedlist(annotations) + + return template_header + string.Template(template).substitute( + { + "allowedlist": generate_java_array_initializer(allowedlist), + } + ) + + +def emit_class(output, annotations_filename): + """Generate the CrashReporterConstants.java file.""" + + template = textwrap.dedent( + """\ + package org.mozilla.gecko; + + /** + * Constants used by the crash reporter. These are generated so that they + * are kept in sync with the other C++ and JS users. + */ + public class CrashReporterConstants { + public static final String[] ANNOTATION_ALLOWEDLIST = { + ${allowedlist} + }; + }""" + ) + + annotations = read_annotations(annotations_filename) + generated_class = generate_class(template, annotations) + + try: + output.write(generated_class) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) diff --git a/toolkit/crashreporter/google-breakpad/.gitignore b/toolkit/crashreporter/google-breakpad/.gitignore new file mode 100644 index 0000000000..058e18361b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/.gitignore @@ -0,0 +1,90 @@ +# Copyright 2014 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. + +# Ignore other VCSs. +.repo/ +.svn/ + +# Ignore common compiled artifacts. +*~ +*.dwo +*.o +lib*.a +/breakpad.pc +/breakpad-client.pc +/src/client/linux/linux_client_unittest_shlib +/src/client/linux/linux_dumper_unittest_helper +/src/common/linux/google_crashdump_uploader_test +/src/processor/microdump_stackwalk +/src/processor/minidump_dump +/src/processor/minidump_stackwalk +/src/tools/linux/core2md/core2md +/src/tools/linux/dump_syms/dump_syms +/src/tools/linux/md2core/minidump-2-core +/src/tools/linux/symupload/minidump_upload +/src/tools/linux/symupload/sym_upload +/src/tools/mac/dump_syms/dump_syms +/src/tools/mac/dump_syms/dump_syms_mac + +# Ignore unit test artifacts. +*_unittest +*.log +*.trs + +# Ignore autotools generated artifacts. +.deps +.dirstamp +autom4te.cache/ +/config.cache +config.h +/config.log +/config.status +/Makefile +stamp-h1 + +# Ignore GYP generated Visual Studio artifacts. +*.filters +*.sdf +*.sln +*.suo +*.vcproj +*.vcxproj + +# Ignore GYP generated Makefiles +src/Makefile +*.Makefile +*.target.mk + +# Ignore compiled Python files. +*.pyc + +# Ignore directories gclient syncs. +src/testing +src/third_party/lss +src/third_party/protobuf +src/tools/gyp diff --git a/toolkit/crashreporter/google-breakpad/AUTHORS b/toolkit/crashreporter/google-breakpad/AUTHORS new file mode 100644 index 0000000000..4858b377c7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/AUTHORS @@ -0,0 +1 @@ +opensource@google.com diff --git a/toolkit/crashreporter/google-breakpad/ChangeLog b/toolkit/crashreporter/google-breakpad/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/toolkit/crashreporter/google-breakpad/DEPS b/toolkit/crashreporter/google-breakpad/DEPS new file mode 100644 index 0000000000..3ddaf4e3a7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/DEPS @@ -0,0 +1,84 @@ +# Copyright 2010 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. + +# This is used to mimic the svn:externals mechanism for gclient (both Git and +# SVN) based checkouts of Breakpad. As such, its use is entirely optional. If +# using a manually managed SVN checkout as opposed to a gclient managed checkout +# you can still use the hooks mechanism for generating project files by calling +# 'gclient runhooks' rather than 'gclient sync'. + +deps = { + # Testing libraries and utilities. + "src/src/testing": + "https://github.com/google/googletest.git" + + "@5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081", + + # Protobuf. + "src/src/third_party/protobuf/protobuf": + "https://github.com/google/protobuf.git" + + "@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac", + + # GYP project generator. + "src/src/tools/gyp": + "https://chromium.googlesource.com/external/gyp/" + + "@324dd166b7c0b39d513026fa52d6280ac6d56770", + + # Linux syscall support. + "src/src/third_party/lss": + "https://chromium.googlesource.com/linux-syscall-support/" + + "@fd00dbbd0c06a309c657d89e9430143b179ff6db", +} + +hooks = [ + { + # Keep the manifest up to date. + "action": ["python", "src/src/tools/python/deps-to-manifest.py", + "src/DEPS", "src/default.xml"], + }, +] + +hooks_os = { + 'win': [ + { + # TODO(chrisha): Fix the GYP files so that they work without + # --no-circular-check. + "pattern": ".", + "action": ["python", + "src/src/tools/gyp/gyp_main.py", + "--no-circular-check", + "src/src/client/windows/breakpad_client.gyp"], + }, + { + # XXX: this and above should all be wired into build/all.gyp ? + "action": ["python", + "src/src/tools/gyp/gyp_main.py", + "--no-circular-check", + "src/src/tools/windows/tools_windows.gyp"], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/GIT-INFO b/toolkit/crashreporter/google-breakpad/GIT-INFO new file mode 100644 index 0000000000..44c344fb8b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/GIT-INFO @@ -0,0 +1 @@ +5bba75bfd6ec386b8e3af0b91332388a378135bf diff --git a/toolkit/crashreporter/google-breakpad/INSTALL b/toolkit/crashreporter/google-breakpad/INSTALL new file mode 100644 index 0000000000..007e9396d0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/toolkit/crashreporter/google-breakpad/LICENSE b/toolkit/crashreporter/google-breakpad/LICENSE new file mode 100644 index 0000000000..95207bdf6f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/LICENSE @@ -0,0 +1,50 @@ +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. + +-------------------------------------------------------------------- + +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. diff --git a/toolkit/crashreporter/google-breakpad/Makefile.am b/toolkit/crashreporter/google-breakpad/Makefile.am new file mode 100644 index 0000000000..9a25d9d415 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/Makefile.am @@ -0,0 +1,1576 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (c) 2011, 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. + + +# This allows #includes to be relative to src/ +AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CFLAGS = +AM_CXXFLAGS = + +if ANDROID_HOST +# This allows using fixed NDK headers when building for Android. +AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/include +# This is only necessary for building the unit tests until GTest is upgraded +# to a future version. +AM_CXXFLAGS += -I$(top_srcdir)/src/common/android/testing/include +endif + +AM_CXXFLAGS += $(WARN_CXXFLAGS) + +if LINUX_HOST +# Build as PIC on Linux, for linux_client_unittest_shlib +AM_CFLAGS += -fPIC +AM_CXXFLAGS += -fPIC +endif + +# Specify include paths for ac macros +ACLOCAL_AMFLAGS = -I m4 + +# License file is called LICENSE not COPYING +AUTOMAKE_OPTIONS = foreign + +## Documentation +docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) + +dist_doc_DATA = \ + AUTHORS \ + ChangeLog \ + INSTALL \ + LICENSE \ + NEWS \ + README.md + +## Headers +if LINUX_HOST +includeclhdir = $(includedir)/$(PACKAGE)/client/linux/handler +includeclh_HEADERS = $(top_srcdir)/src/client/linux/handler/*.h + +includecldwcdir = $(includedir)/$(PACKAGE)/client/linux/dump_writer_common +includecldwc_HEADERS = $(top_srcdir)/src/client/linux/dump_writer_common/*.h + +includeclmdir = $(includedir)/$(PACKAGE)/client/linux/minidump_writer +includeclm_HEADERS = $(top_srcdir)/src/client/linux/minidump_writer/*.h + +includeclcdir = $(includedir)/$(PACKAGE)/client/linux/crash_generation +includeclc_HEADERS = $(top_srcdir)/src/client/linux/crash_generation/*.h + +includelssdir = $(includedir)/$(PACKAGE)/third_party/lss +includelss_HEADERS = $(top_srcdir)/src/third_party/lss/*.h + +includecldir = $(includedir)/$(PACKAGE)/common/linux +includecl_HEADERS = $(top_srcdir)/src/common/linux/*.h +endif + +includegbcdir = $(includedir)/$(PACKAGE)/google_breakpad/common +includegbc_HEADERS = $(top_srcdir)/src/google_breakpad/common/*.h + +includecdir = $(includedir)/$(PACKAGE)/common +includec_HEADERS = $(top_srcdir)/src/common/*.h + +includepdir = $(includedir)/$(PACKAGE)/processor +includep_HEADERS = $(top_srcdir)/src/processor/*.h + +## pkgconfig files +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = + +## Common test logic +if SYSTEM_TEST_LIBS +TEST_CFLAGS = $(GTEST_CFLAGS) $(GMOCK_CFLAGS) +TEST_LIBS = $(GTEST_LIBS) -lgtest_main $(GMOCK_LIBS) +TEST_DEPS = +else +TEST_CFLAGS = \ + -I$(top_srcdir)/src/testing/include \ + -I$(top_srcdir)/src/testing/googletest/include \ + -I$(top_srcdir)/src/testing/googletest \ + -I$(top_srcdir)/src/testing/googlemock/include \ + -I$(top_srcdir)/src/testing/googlemock \ + -I$(top_srcdir)/src/testing +TEST_LIBS = src/testing/libtesting.a +TEST_DEPS = $(TEST_LIBS) +endif + +## Libraries +check_LIBRARIES = +noinst_LIBRARIES = +lib_LIBRARIES = +bin_PROGRAMS = +check_PROGRAMS = +EXTRA_PROGRAMS = +CLEANFILES = + +check_LIBRARIES += src/testing/libtesting.a + +if !SYSTEM_TEST_LIBS +src_testing_libtesting_a_SOURCES = \ + src/breakpad_googletest_includes.h \ + src/testing/googletest/src/gtest-all.cc \ + src/testing/googletest/src/gtest_main.cc \ + src/testing/googlemock/src/gmock-all.cc +src_testing_libtesting_a_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +endif + +if !DISABLE_PROCESSOR +lib_LIBRARIES += src/libbreakpad.a +pkgconfig_DATA += breakpad.pc +noinst_LIBRARIES += src/third_party/libdisasm/libdisasm.a +endif + +if LINUX_HOST +lib_LIBRARIES += src/client/linux/libbreakpad_client.a +pkgconfig_DATA += breakpad-client.pc + +src_client_linux_libbreakpad_client_a_SOURCES = \ + src/client/linux/crash_generation/crash_generation_client.cc \ + src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ + src/client/linux/handler/exception_handler.cc \ + src/client/linux/handler/exception_handler.h \ + src/client/linux/handler/minidump_descriptor.cc \ + src/client/linux/handler/minidump_descriptor.h \ + src/client/linux/log/log.cc \ + src/client/linux/log/log.h \ + src/client/linux/microdump_writer/microdump_writer.cc \ + src/client/linux/microdump_writer/microdump_writer.h \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_dumper.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ + src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/minidump_file_writer-inl.h \ + src/client/minidump_file_writer.cc \ + src/client/minidump_file_writer.h \ + src/common/convert_UTF.cc \ + src/common/convert_UTF.h \ + src/common/md5.cc \ + src/common/md5.h \ + src/common/string_conversion.cc \ + src/common/string_conversion.h \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/elfutils.cc \ + src/common/linux/elfutils.h \ + src/common/linux/file_id.cc \ + src/common/linux/file_id.h \ + src/common/linux/guid_creator.cc \ + src/common/linux/guid_creator.h \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc +if !HAVE_GETCONTEXT +src_client_linux_libbreakpad_client_a_SOURCES += \ + src/common/linux/breakpad_getcontext.S +endif +endif LINUX_HOST + +if !DISABLE_PROCESSOR +src_libbreakpad_a_SOURCES = \ + src/google_breakpad/common/breakpad_types.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/dump_context.h \ + src/google_breakpad/processor/dump_object.h \ + src/google_breakpad/processor/exploitability.h \ + src/google_breakpad/processor/fast_source_line_resolver.h \ + src/google_breakpad/processor/memory_region.h \ + src/google_breakpad/processor/microdump.h \ + src/google_breakpad/processor/microdump_processor.h \ + src/google_breakpad/processor/minidump.h \ + src/google_breakpad/processor/minidump_processor.h \ + src/google_breakpad/processor/process_result.h \ + src/google_breakpad/processor/process_state.h \ + src/google_breakpad/processor/proc_maps_linux.h \ + src/google_breakpad/processor/source_line_resolver_base.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/stack_frame_symbolizer.h \ + src/google_breakpad/processor/stackwalker.h \ + src/google_breakpad/processor/symbol_supplier.h \ + src/google_breakpad/processor/system_info.h \ + src/processor/address_map-inl.h \ + src/processor/address_map.h \ + src/processor/basic_code_module.h \ + src/processor/basic_code_modules.cc \ + src/processor/basic_code_modules.h \ + src/processor/basic_source_line_resolver_types.h \ + src/processor/basic_source_line_resolver.cc \ + src/processor/call_stack.cc \ + src/processor/cfi_frame_info.cc \ + src/processor/cfi_frame_info.h \ + src/processor/contained_range_map-inl.h \ + src/processor/contained_range_map.h \ + src/processor/convert_old_arm64_context.cc \ + src/processor/convert_old_arm64_context.h \ + src/processor/disassembler_x86.h \ + src/processor/disassembler_x86.cc \ + src/processor/dump_context.cc \ + src/processor/dump_object.cc \ + src/processor/exploitability.cc \ + src/processor/exploitability_linux.h \ + src/processor/exploitability_linux.cc \ + src/processor/exploitability_win.h \ + src/processor/exploitability_win.cc \ + src/processor/fast_source_line_resolver_types.h \ + src/processor/fast_source_line_resolver.cc \ + src/processor/linked_ptr.h \ + src/processor/logging.h \ + src/processor/logging.cc \ + src/processor/map_serializers-inl.h \ + src/processor/map_serializers.h \ + src/processor/microdump.cc \ + src/processor/microdump_processor.cc \ + src/processor/minidump.cc \ + src/processor/minidump_processor.cc \ + src/processor/module_comparer.cc \ + src/processor/module_comparer.h \ + src/processor/module_factory.h \ + src/processor/module_serializer.cc \ + src/processor/module_serializer.h \ + src/processor/pathname_stripper.cc \ + src/processor/pathname_stripper.h \ + src/processor/postfix_evaluator-inl.h \ + src/processor/postfix_evaluator.h \ + src/processor/process_state.cc \ + src/processor/proc_maps_linux.cc \ + src/processor/range_map-inl.h \ + src/processor/range_map.h \ + src/processor/simple_serializer-inl.h \ + src/processor/simple_serializer.h \ + src/processor/simple_symbol_supplier.cc \ + src/processor/simple_symbol_supplier.h \ + src/processor/windows_frame_info.h \ + src/processor/source_line_resolver_base_types.h \ + src/processor/source_line_resolver_base.cc \ + src/processor/stack_frame_cpu.cc \ + src/processor/stack_frame_symbolizer.cc \ + src/processor/stackwalker.cc \ + src/processor/stackwalker_amd64.cc \ + src/processor/stackwalker_amd64.h \ + src/processor/stackwalker_arm.cc \ + src/processor/stackwalker_arm.h \ + src/processor/stackwalker_arm64.cc \ + src/processor/stackwalker_arm64.h \ + src/processor/stackwalker_address_list.cc \ + src/processor/stackwalker_address_list.h \ + src/processor/stackwalker_mips.cc \ + src/processor/stackwalker_mips.h \ + src/processor/stackwalker_ppc.cc \ + src/processor/stackwalker_ppc.h \ + src/processor/stackwalker_ppc64.cc \ + src/processor/stackwalker_ppc64.h \ + src/processor/stackwalker_sparc.cc \ + src/processor/stackwalker_sparc.h \ + src/processor/stackwalker_x86.cc \ + src/processor/stackwalker_x86.h \ + src/processor/static_address_map-inl.h \ + src/processor/static_address_map.h \ + src/processor/static_contained_range_map-inl.h \ + src/processor/static_contained_range_map.h \ + src/processor/static_map_iterator-inl.h \ + src/processor/static_map_iterator.h \ + src/processor/static_map-inl.h \ + src/processor/static_map.h \ + src/processor/static_range_map-inl.h \ + src/processor/static_range_map.h \ + src/processor/symbolic_constants_win.cc \ + src/processor/symbolic_constants_win.h \ + src/processor/tokenize.cc \ + src/processor/tokenize.h + +src_third_party_libdisasm_libdisasm_a_SOURCES = \ + src/third_party/libdisasm/ia32_implicit.c \ + src/third_party/libdisasm/ia32_implicit.h \ + src/third_party/libdisasm/ia32_insn.c \ + src/third_party/libdisasm/ia32_insn.h \ + src/third_party/libdisasm/ia32_invariant.c \ + src/third_party/libdisasm/ia32_invariant.h \ + src/third_party/libdisasm/ia32_modrm.c \ + src/third_party/libdisasm/ia32_modrm.h \ + src/third_party/libdisasm/ia32_opcode_tables.c \ + src/third_party/libdisasm/ia32_opcode_tables.h \ + src/third_party/libdisasm/ia32_operand.c \ + src/third_party/libdisasm/ia32_operand.h \ + src/third_party/libdisasm/ia32_reg.c \ + src/third_party/libdisasm/ia32_reg.h \ + src/third_party/libdisasm/ia32_settings.c \ + src/third_party/libdisasm/ia32_settings.h \ + src/third_party/libdisasm/libdis.h \ + src/third_party/libdisasm/qword.h \ + src/third_party/libdisasm/x86_disasm.c \ + src/third_party/libdisasm/x86_format.c \ + src/third_party/libdisasm/x86_imm.c \ + src/third_party/libdisasm/x86_imm.h \ + src/third_party/libdisasm/x86_insn.c \ + src/third_party/libdisasm/x86_misc.c \ + src/third_party/libdisasm/x86_operand_list.c \ + src/third_party/libdisasm/x86_operand_list.h + +## Programs +bin_PROGRAMS += \ + src/processor/microdump_stackwalk \ + src/processor/minidump_dump \ + src/processor/minidump_stackwalk +endif !DISABLE_PROCESSOR + +if LINUX_HOST +EXTRA_PROGRAMS += \ + src/client/linux/linux_dumper_unittest_helper +CLEANFILES += \ + src/client/linux/linux_dumper_unittest_helper + +if !DISABLE_TOOLS +bin_PROGRAMS += \ + src/tools/linux/core2md/core2md \ + src/tools/linux/dump_syms/dump_syms \ + src/tools/linux/md2core/minidump-2-core \ + src/tools/linux/symupload/minidump_upload \ + src/tools/linux/symupload/sym_upload +if X86_HOST +bin_PROGRAMS += \ + src/tools/mac/dump_syms/dump_syms_mac +endif +endif +endif LINUX_HOST + + +## Tests +if !DISABLE_PROCESSOR +check_PROGRAMS += \ + src/common/test_assembler_unittest \ + src/processor/address_map_unittest \ + src/processor/basic_source_line_resolver_unittest \ + src/processor/cfi_frame_info_unittest \ + src/processor/contained_range_map_unittest \ + src/processor/disassembler_x86_unittest \ + src/processor/exploitability_unittest \ + src/processor/fast_source_line_resolver_unittest \ + src/processor/map_serializers_unittest \ + src/processor/microdump_processor_unittest \ + src/processor/minidump_processor_unittest \ + src/processor/minidump_unittest \ + src/processor/static_address_map_unittest \ + src/processor/static_contained_range_map_unittest \ + src/processor/static_map_unittest \ + src/processor/static_range_map_unittest \ + src/processor/pathname_stripper_unittest \ + src/processor/postfix_evaluator_unittest \ + src/processor/proc_maps_linux_unittest \ + src/processor/range_map_truncate_lower_unittest \ + src/processor/range_map_truncate_upper_unittest \ + src/processor/range_map_unittest \ + src/processor/stackwalker_amd64_unittest \ + src/processor/stackwalker_arm_unittest \ + src/processor/stackwalker_arm64_unittest \ + src/processor/stackwalker_address_list_unittest \ + src/processor/stackwalker_mips_unittest \ + src/processor/stackwalker_mips64_unittest \ + src/processor/stackwalker_x86_unittest \ + src/processor/synth_minidump_unittest +endif + +if LINUX_HOST +EXTRA_PROGRAMS += \ + src/client/linux/linux_client_unittest_shlib +CLEANFILES += \ + src/client/linux/linux_client_unittest_shlib + +check_PROGRAMS += \ + src/client/linux/linux_client_unittest \ + src/common/linux/google_crashdump_uploader_test + +if !DISABLE_TOOLS +check_PROGRAMS += \ + src/common/dumper_unittest \ + src/tools/linux/md2core/minidump_2_core_unittest +if X86_HOST +check_PROGRAMS += \ + src/common/mac/macho_reader_unittest +endif +endif +endif LINUX_HOST + +if !DISABLE_PROCESSOR +if SELFTEST +check_PROGRAMS += \ + src/processor/stackwalker_selftest +endif SELFTEST +endif !DISABLE_PROCESSOR + +if !DISABLE_PROCESSOR +check_SCRIPTS = \ + src/processor/microdump_stackwalk_test \ + src/processor/microdump_stackwalk_machine_readable_test \ + src/processor/minidump_dump_test \ + src/processor/minidump_stackwalk_test \ + src/processor/minidump_stackwalk_machine_readable_test +endif + +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) + +if ANDROID_HOST +# Since Autotools 1.2, tests are run through a special "test driver" script. +# Unfortunately, it's not possible anymore to specify an alternative shell to +# run them on connected devices, so use a slightly modified version of the +# driver for Android. +LOG_DRIVER = $(top_srcdir)/android/test-driver +else +# The default Autotools test driver script. +if TESTS_AS_ROOT +LOG_DRIVER = $(top_srcdir)/autotools/root-test-driver $(top_srcdir)/autotools/test-driver +else +LOG_DRIVER = $(top_srcdir)/autotools/test-driver +endif !TESTS_AS_ROOT +endif !ANDROID_HOST + +if LINUX_HOST +src_client_linux_linux_dumper_unittest_helper_SOURCES = \ + src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +src_client_linux_linux_dumper_unittest_helper_LDFLAGS=$(PTHREAD_CFLAGS) +src_client_linux_linux_dumper_unittest_helper_CC=$(PTHREAD_CC) +if ANDROID_HOST +# On Android PTHREAD_CFLAGS is empty, and adding src/common/android/include +# to the include path is necessary to build this program. +src_client_linux_linux_dumper_unittest_helper_CXXFLAGS=$(AM_CXXFLAGS) +else +src_client_linux_linux_dumper_unittest_helper_CXXFLAGS=$(PTHREAD_CFLAGS) +endif + +src_client_linux_linux_client_unittest_shlib_SOURCES = \ + $(src_testing_libtesting_a_SOURCES) \ + src/client/linux/handler/exception_handler_unittest.cc \ + src/client/linux/microdump_writer/microdump_writer_unittest.cc \ + src/client/linux/minidump_writer/directory_reader_unittest.cc \ + src/client/linux/minidump_writer/cpu_set_unittest.cc \ + src/client/linux/minidump_writer/line_reader_unittest.cc \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/linux_libc_support_unittest.cc \ + src/common/linux/tests/auto_testfile.h \ + src/common/linux/tests/crash_generator.cc \ + src/common/memory_allocator_unittest.cc \ + src/common/tests/auto_tempdir.h \ + src/common/tests/file_utils.cc \ + src/common/tests/file_utils.h \ + src/processor/basic_code_modules.cc \ + src/processor/convert_old_arm64_context.cc \ + src/processor/dump_context.cc \ + src/processor/dump_object.cc \ + src/processor/logging.cc \ + src/processor/minidump.cc \ + src/processor/pathname_stripper.cc \ + src/processor/proc_maps_linux.cc +if !HAVE_GETCONTEXT +src_client_linux_linux_client_unittest_shlib_SOURCES += \ + src/common/linux/breakpad_getcontext.S +endif + +src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_client_linux_linux_client_unittest_shlib_LDFLAGS = \ + -shared \ + -Wl,-h,linux_client_unittest_shlib +src_client_linux_linux_client_unittest_shlib_LDADD = \ + src/client/linux/crash_generation/crash_generation_client.o \ + src/client/linux/dump_writer_common/thread_info.o \ + src/client/linux/dump_writer_common/ucontext_reader.o \ + src/client/linux/handler/exception_handler.o \ + src/client/linux/handler/minidump_descriptor.o \ + src/client/linux/log/log.o \ + src/client/linux/microdump_writer/microdump_writer.o \ + src/client/linux/minidump_writer/linux_dumper.o \ + src/client/linux/minidump_writer/linux_ptrace_dumper.o \ + src/client/linux/minidump_writer/minidump_writer.o \ + src/client/minidump_file_writer.o \ + src/common/convert_UTF.o \ + src/common/md5.o \ + src/common/linux/elfutils.o \ + src/common/linux/file_id.o \ + src/common/linux/guid_creator.o \ + src/common/linux/linux_libc_support.o \ + src/common/linux/memory_mapped_file.o \ + src/common/linux/safe_readlink.o \ + src/common/string_conversion.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +if !HAVE_GETCONTEXT +src_client_linux_linux_client_unittest_shlib_SOURCES += \ + src/common/linux/breakpad_getcontext_unittest.cc +endif +if ANDROID_HOST +src_client_linux_linux_client_unittest_shlib_LDFLAGS += \ + -llog -lm +endif + +src_client_linux_linux_client_unittest_shlib_DEPENDENCIES = \ + src/client/linux/linux_dumper_unittest_helper \ + src/client/linux/libbreakpad_client.a \ + $(TEST_DEPS) \ + src/libbreakpad.a + +src_client_linux_linux_client_unittest_SOURCES = +# The extra-long build id is for a test in minidump_writer_unittest.cc. +src_client_linux_linux_client_unittest_LDFLAGS = \ + -Wl,-rpath,'$$ORIGIN' \ + -Wl,--build-id=0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +if ANDROID_HOST +src_client_linux_linux_client_unittest_LDFLAGS += \ + -llog +endif + +src_client_linux_linux_client_unittest_LDADD = \ + src/client/linux/linux_client_unittest_shlib \ + $(TEST_LIBS) + +src_client_linux_linux_client_unittest_DEPENDENCIES = \ + src/client/linux/linux_client_unittest_shlib + +if !DISABLE_TOOLS +src_tools_linux_core2md_core2md_SOURCES = \ + src/tools/linux/core2md/core2md.cc + +src_tools_linux_core2md_core2md_LDADD = \ + src/client/linux/libbreakpad_client.a + +src_tools_linux_dump_syms_dump_syms_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols.h \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module.h \ + src/common/linux/elfutils.cc \ + src/common/linux/file_id.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc \ + src/tools/linux/dump_syms/dump_syms.cc +src_tools_linux_dump_syms_dump_syms_CXXFLAGS = \ + $(RUST_DEMANGLE_CFLAGS) +src_tools_linux_dump_syms_dump_syms_LDADD = \ + $(RUST_DEMANGLE_LIBS) + +src_tools_linux_md2core_minidump_2_core_SOURCES = \ + src/common/linux/memory_mapped_file.cc \ + src/common/path_helper.cc \ + src/tools/linux/md2core/minidump-2-core.cc \ + src/tools/linux/md2core/minidump_memory_range.h + +src_tools_linux_symupload_minidump_upload_SOURCES = \ + src/common/linux/http_upload.cc \ + src/tools/linux/symupload/minidump_upload.cc +src_tools_linux_symupload_minidump_upload_LDADD = -ldl + +src_tools_linux_symupload_sym_upload_SOURCES = \ + src/common/linux/http_upload.cc \ + src/common/linux/http_upload.h \ + src/common/linux/libcurl_wrapper.cc \ + src/common/linux/libcurl_wrapper.h \ + src/common/linux/symbol_collector_client.cc \ + src/common/linux/symbol_collector_client.h \ + src/common/linux/symbol_upload.cc \ + src/common/linux/symbol_upload.h \ + src/tools/linux/symupload/sym_upload.cc +src_tools_linux_symupload_sym_upload_LDADD = -ldl + +src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/md5.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc \ + src/common/mac/dump_syms.cc \ + src/common/mac/dump_syms.h \ + src/common/mac/file_id.cc \ + src/common/mac/file_id.h \ + src/common/mac/macho_id.cc \ + src/common/mac/macho_id.h \ + src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader.h \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_utilities.h \ + src/common/mac/macho_walker.cc \ + src/common/mac/macho_walker.h \ + src/tools/mac/dump_syms/dump_syms_tool.cc +src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS= \ + -I$(top_srcdir)/src/third_party/mac_headers \ + $(RUST_DEMANGLE_CFLAGS) \ + -DHAVE_MACH_O_NLIST_H +src_tools_mac_dump_syms_dump_syms_mac_LDADD= \ + $(RUST_DEMANGLE_LIBS) + +src_common_dumper_unittest_SOURCES = \ + src/common/byte_cursor_unittest.cc \ + src/common/convert_UTF.cc \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cfi_to_module_unittest.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_cu_to_module_unittest.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_line_to_module_unittest.cc \ + src/common/dwarf_range_list_handler.cc \ + src/common/language.cc \ + src/common/memory_range_unittest.cc \ + src/common/module.cc \ + src/common/module_unittest.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_reader_unittest.cc \ + src/common/stabs_to_module.cc \ + src/common/stabs_to_module_unittest.cc \ + src/common/string_conversion.cc \ + src/common/string_conversion_unittest.cc \ + src/common/test_assembler.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/bytereader.h \ + src/common/dwarf/bytereader-inl.h \ + src/common/dwarf/bytereader_unittest.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/cfi_assembler.h \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2diehandler_unittest.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/dwarf2reader.h \ + src/common/dwarf/elf_reader.cc \ + src/common/dwarf/elf_reader.h \ + src/common/dwarf/dwarf2reader_cfi_unittest.cc \ + src/common/dwarf/dwarf2reader_die_unittest.cc \ + src/common/dwarf/dwarf2reader_test_common.h \ + src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/elf_core_dump_unittest.cc \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module_unittest.cc \ + src/common/linux/elfutils.cc \ + src/common/linux/file_id.cc \ + src/common/linux/file_id_unittest.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/memory_mapped_file_unittest.cc \ + src/common/linux/safe_readlink.cc \ + src/common/linux/safe_readlink_unittest.cc \ + src/common/linux/synth_elf.cc \ + src/common/linux/synth_elf_unittest.cc \ + src/common/linux/tests/crash_generator.cc \ + src/common/linux/tests/crash_generator.h \ + src/common/testdata/func-line-pairing.h \ + src/common/tests/file_utils.cc +src_common_dumper_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) \ + $(RUST_DEMANGLE_CFLAGS) \ + $(PTHREAD_CFLAGS) +src_common_dumper_unittest_LDADD = \ + $(TEST_LIBS) \ + $(RUST_DEMANGLE_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_mac_macho_reader_unittest_SOURCES = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/language.cc \ + src/common/md5.cc \ + src/common/module.cc \ + src/common/path_helper.cc \ + src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc \ + src/common/test_assembler.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc \ + src/common/mac/file_id.cc \ + src/common/mac/macho_id.cc \ + src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader_unittest.cc \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_walker.cc \ + src/common/tests/file_utils.cc +src_common_mac_macho_reader_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) \ + -I$(top_srcdir)/src/third_party/mac_headers \ + -DHAVE_MACH_O_NLIST_H \ + $(PTHREAD_CFLAGS) +src_common_mac_macho_reader_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +endif + +src_common_linux_google_crashdump_uploader_test_SOURCES = \ + src/common/linux/google_crashdump_uploader.cc \ + src/common/linux/google_crashdump_uploader_test.cc \ + src/common/linux/libcurl_wrapper.cc +src_common_linux_google_crashdump_uploader_test_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_common_linux_google_crashdump_uploader_test_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) \ + -ldl + +src_tools_linux_md2core_minidump_2_core_unittest_SOURCES = \ + src/tools/linux/md2core/minidump_memory_range_unittest.cc +src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_tools_linux_md2core_minidump_2_core_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +endif LINUX_HOST + +if !DISABLE_PROCESSOR +src_processor_address_map_unittest_SOURCES = \ + src/processor/address_map_unittest.cc +src_processor_address_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o + +src_processor_basic_source_line_resolver_unittest_SOURCES = \ + src/processor/basic_source_line_resolver_unittest.cc +src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_basic_source_line_resolver_unittest_LDADD = \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o \ + src/processor/pathname_stripper.o \ + src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_cfi_frame_info_unittest_SOURCES = \ + src/processor/cfi_frame_info_unittest.cc +src_processor_cfi_frame_info_unittest_LDADD = \ + src/processor/cfi_frame_info.o \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_cfi_frame_info_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_contained_range_map_unittest_SOURCES = \ + src/processor/contained_range_map_unittest.cc +src_processor_contained_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o + +src_processor_exploitability_unittest_SOURCES = \ + src/processor/exploitability_unittest.cc +src_processor_exploitability_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_exploitability_unittest_LDADD = \ + src/processor/convert_old_arm64_context.o \ + src/processor/minidump_processor.o \ + src/processor/process_state.o \ + src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/cfi_frame_info.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_disassembler_x86_unittest_SOURCES = \ + src/processor/disassembler_x86_unittest.cc +src_processor_disassembler_x86_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_disassembler_x86_unittest_LDADD = \ + src/processor/disassembler_x86.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_fast_source_line_resolver_unittest_SOURCES = \ + src/processor/fast_source_line_resolver_unittest.cc +src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_fast_source_line_resolver_unittest_LDADD = \ + src/processor/fast_source_line_resolver.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/cfi_frame_info.o \ + src/processor/module_comparer.o \ + src/processor/module_serializer.o \ + src/processor/pathname_stripper.o \ + src/processor/logging.o \ + src/processor/source_line_resolver_base.o \ + src/processor/tokenize.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_map_serializers_unittest_SOURCES = \ + src/processor/map_serializers_unittest.cc +src_processor_map_serializers_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_map_serializers_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_microdump_processor_unittest_SOURCES = \ + src/processor/microdump_processor_unittest.cc +src_processor_microdump_processor_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_microdump_processor_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/microdump.o \ + src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/tokenize.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_minidump_processor_unittest_SOURCES = \ + src/processor/minidump_processor_unittest.cc +src_processor_minidump_processor_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_minidump_processor_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/logging.o \ + src/processor/minidump_processor.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_minidump_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/minidump_unittest.cc \ + src/processor/synth_minidump.cc +src_processor_minidump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_minidump_unittest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_proc_maps_linux_unittest_SOURCES = \ + src/processor/proc_maps_linux.cc \ + src/processor/proc_maps_linux_unittest.cc +src_processor_proc_maps_linux_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_proc_maps_linux_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + src/third_party/libdisasm/libdisasm.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_address_map_unittest_SOURCES = \ + src/processor/static_address_map_unittest.cc +src_processor_static_address_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_static_address_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_contained_range_map_unittest_SOURCES = \ + src/processor/static_contained_range_map_unittest.cc +src_processor_static_contained_range_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_static_contained_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_map_unittest_SOURCES = \ + src/processor/static_map_unittest.cc +src_processor_static_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_static_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_static_range_map_unittest_SOURCES = \ + src/processor/static_range_map_unittest.cc +src_processor_static_range_map_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_static_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_pathname_stripper_unittest_SOURCES = \ + src/processor/pathname_stripper_unittest.cc +src_processor_pathname_stripper_unittest_LDADD = \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_postfix_evaluator_unittest_SOURCES = \ + src/processor/postfix_evaluator_unittest.cc +src_processor_postfix_evaluator_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_range_map_truncate_lower_unittest_SOURCES = \ + src/processor/range_map_truncate_lower_unittest.cc +src_processor_range_map_truncate_lower_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_range_map_truncate_lower_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_range_map_truncate_upper_unittest_SOURCES = \ + src/processor/range_map_truncate_upper_unittest.cc +src_processor_range_map_truncate_upper_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_range_map_truncate_upper_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_range_map_unittest_SOURCES = \ + src/processor/range_map_unittest.cc +src_processor_range_map_unittest_LDADD = \ + src/processor/logging.o \ + src/processor/pathname_stripper.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_selftest_SOURCES = \ + src/processor/stackwalker_selftest.cc +src_processor_stackwalker_selftest_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/disassembler_x86.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/tokenize.o \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_processor_stackwalker_amd64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_amd64_unittest.cc +src_processor_stackwalker_amd64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_amd64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_arm_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm_unittest.cc +src_processor_stackwalker_arm_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_arm_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_arm64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm64_unittest.cc +src_processor_stackwalker_arm64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_arm64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_address_list_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_address_list_unittest.cc +src_processor_stackwalker_address_list_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_address_list_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_mips_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips_unittest.cc +src_processor_stackwalker_mips_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_mips_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_mips64_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips64_unittest.cc +src_processor_stackwalker_mips64_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_mips64_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_stackwalker_x86_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_x86_unittest.cc +src_processor_stackwalker_x86_unittest_LDADD = \ + src/libbreakpad.a \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) +src_processor_stackwalker_x86_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) + +src_processor_synth_minidump_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/common/test_assembler.h \ + src/processor/synth_minidump_unittest.cc \ + src/processor/synth_minidump.cc \ + src/processor/synth_minidump.h +src_processor_synth_minidump_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_processor_synth_minidump_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +src_common_test_assembler_unittest_SOURCES = \ + src/common/test_assembler.cc \ + src/common/test_assembler.h \ + src/common/test_assembler_unittest.cc +src_common_test_assembler_unittest_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CFLAGS) +src_common_test_assembler_unittest_LDADD = \ + $(TEST_LIBS) \ + $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +## Non-installables +noinst_PROGRAMS = +noinst_SCRIPTS = $(check_SCRIPTS) + +src_processor_minidump_dump_SOURCES = \ + src/processor/minidump_dump.cc +src_processor_minidump_dump_LDADD = \ + src/processor/basic_code_modules.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/pathname_stripper.o \ + src/processor/proc_maps_linux.o + +src_processor_microdump_stackwalk_SOURCES = \ + src/processor/microdump_stackwalk.cc +src_processor_microdump_stackwalk_LDADD = \ + src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/cfi_frame_info.o \ + src/processor/disassembler_x86.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/logging.o \ + src/processor/microdump.o \ + src/processor/microdump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a + +src_processor_minidump_stackwalk_SOURCES = \ + src/processor/minidump_stackwalk.cc +src_processor_minidump_stackwalk_LDADD = \ + src/common/path_helper.o \ + src/processor/basic_code_modules.o \ + src/processor/basic_source_line_resolver.o \ + src/processor/call_stack.o \ + src/processor/cfi_frame_info.o \ + src/processor/convert_old_arm64_context.o \ + src/processor/disassembler_x86.o \ + src/processor/dump_context.o \ + src/processor/dump_object.o \ + src/processor/exploitability.o \ + src/processor/exploitability_linux.o \ + src/processor/exploitability_win.o \ + src/processor/logging.o \ + src/processor/minidump.o \ + src/processor/minidump_processor.o \ + src/processor/pathname_stripper.o \ + src/processor/process_state.o \ + src/processor/proc_maps_linux.o \ + src/processor/simple_symbol_supplier.o \ + src/processor/source_line_resolver_base.o \ + src/processor/stack_frame_cpu.o \ + src/processor/stack_frame_symbolizer.o \ + src/processor/stackwalk_common.o \ + src/processor/stackwalker.o \ + src/processor/stackwalker_address_list.o \ + src/processor/stackwalker_amd64.o \ + src/processor/stackwalker_arm.o \ + src/processor/stackwalker_arm64.o \ + src/processor/stackwalker_mips.o \ + src/processor/stackwalker_ppc.o \ + src/processor/stackwalker_ppc64.o \ + src/processor/stackwalker_sparc.o \ + src/processor/stackwalker_x86.o \ + src/processor/symbolic_constants_win.o \ + src/processor/tokenize.o \ + src/third_party/libdisasm/libdisasm.a + +endif !DISABLE_PROCESSOR + +## Additional files to be included in a source distribution +## +## find src/client src/common src/processor/testdata src/tools \ +## -type f \! -path '*/.svn/*' -print | sort | \ +## sed -e s/'^\(.*\)$'/'\t\1 \\'/ +EXTRA_DIST = \ + $(SCRIPTS) \ + src/client/linux/data/linux-gate-amd.sym \ + src/client/linux/data/linux-gate-intel.sym \ + src/client/mac/handler/breakpad_nlist_64.cc \ + src/client/mac/handler/breakpad_nlist_64.h \ + src/client/mac/handler/dynamic_images.cc \ + src/client/mac/handler/dynamic_images.h \ + src/client/mac/handler/exception_handler.cc \ + src/client/mac/handler/exception_handler.h \ + src/client/mac/handler/mach_vm_compat.h \ + src/client/mac/handler/minidump_generator.cc \ + src/client/mac/handler/minidump_generator.h \ + src/client/mac/handler/minidump_test.xcodeproj/project.pbxproj \ + src/client/mac/handler/minidump_tests32-Info.plist \ + src/client/mac/handler/minidump_tests64-Info.plist \ + src/client/mac/handler/obj-cTestCases-Info.plist \ + src/client/mac/handler/protected_memory_allocator.cc \ + src/client/mac/handler/protected_memory_allocator.h \ + src/client/mac/handler/ucontext_compat.h \ + src/client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym \ + src/client/mac/tests/BreakpadFramework_Test.mm \ + src/client/mac/tests/crash_generation_server_test.cc \ + src/client/mac/tests/exception_handler_test.cc \ + src/client/mac/tests/minidump_generator_test.cc \ + src/client/mac/tests/minidump_generator_test_helper.cc \ + src/client/mac/tests/spawn_child_process.h \ + src/client/mac/tests/testlogging.h \ + src/client/minidump_file_writer_unittest.cc \ + src/client/solaris/handler/Makefile \ + src/client/solaris/handler/exception_handler.cc \ + src/client/solaris/handler/exception_handler.h \ + src/client/solaris/handler/exception_handler_test.cc \ + src/client/solaris/handler/minidump_generator.cc \ + src/client/solaris/handler/minidump_generator.h \ + src/client/solaris/handler/minidump_test.cc \ + src/client/solaris/handler/solaris_lwp.cc \ + src/client/solaris/handler/solaris_lwp.h \ + src/client/windows/breakpad_client.gyp \ + src/client/windows/handler/exception_handler.cc \ + src/client/windows/handler/exception_handler.h \ + src/client/windows/handler/exception_handler.gyp \ + src/client/windows/sender/crash_report_sender.cc \ + src/client/windows/sender/crash_report_sender.h \ + src/client/windows/sender/crash_report_sender.gyp \ + src/common/dwarf/dwarf2diehandler.h \ + src/common/dwarf/dwarf2enums.h \ + src/common/dwarf/line_state_machine.h \ + src/common/dwarf/types.h \ + src/common/mac/arch_utilities.h \ + src/common/mac/byteswap.h \ + src/common/mac/HTTPMultipartUpload.h \ + src/common/mac/HTTPMultipartUpload.m \ + src/common/mac/string_utilities.cc \ + src/common/mac/string_utilities.h \ + src/common/mac/super_fat_arch.h \ + src/common/scoped_ptr.h \ + src/common/solaris/dump_symbols.cc \ + src/common/solaris/dump_symbols.h \ + src/common/solaris/file_id.cc \ + src/common/solaris/file_id.h \ + src/common/solaris/guid_creator.cc \ + src/common/solaris/guid_creator.h \ + src/common/solaris/message_output.h \ + src/common/windows/guid_string.cc \ + src/common/windows/guid_string.h \ + src/common/windows/http_upload.cc \ + src/common/windows/http_upload.h \ + src/common/windows/pdb_source_line_writer.cc \ + src/common/windows/pdb_source_line_writer.h \ + src/common/windows/string_utils-inl.h \ + src/common/windows/string_utils.cc \ + src/processor/microdump_stackwalk_test_vars \ + src/processor/stackwalk_common.cc \ + src/processor/stackwalk_common.h \ + src/processor/stackwalker_selftest_sol.s \ + src/processor/testdata/ascii_read_av_block_write.dmp \ + src/processor/testdata/ascii_read_av_clobber_write.dmp \ + src/processor/testdata/ascii_read_av_conditional.dmp \ + src/processor/testdata/ascii_read_av.dmp \ + src/processor/testdata/ascii_read_av_then_jmp.dmp \ + src/processor/testdata/ascii_read_av_xchg_write.dmp \ + src/processor/testdata/ascii_write_av_arg_to_call.dmp \ + src/processor/testdata/ascii_write_av.dmp \ + src/processor/testdata/exec_av_on_stack.dmp \ + src/processor/testdata/linux_divide_by_zero.dmp \ + src/processor/testdata/linux_executable_heap.dmp \ + src/processor/testdata/linux_executable_stack.dmp \ + src/processor/testdata/linux_inside_module_exe_region1.dmp \ + src/processor/testdata/linux_inside_module_exe_region2.dmp \ + src/processor/testdata/linux_jmp_to_0.dmp \ + src/processor/testdata/linux_jmp_to_module_not_exe_region.dmp \ + src/processor/testdata/linux_null_dereference.dmp \ + src/processor/testdata/linux_null_read_av.dmp \ + src/processor/testdata/linux_outside_module.dmp \ + src/processor/testdata/linux_overflow.dmp \ + src/processor/testdata/linux_raise_sigabrt.dmp \ + src/processor/testdata/linux_stack_pointer_in_module.dmp \ + src/processor/testdata/linux_stack_pointer_in_stack.dmp \ + src/processor/testdata/linux_stack_pointer_in_stack_alt_name.dmp \ + src/processor/testdata/linux_stacksmash.dmp \ + src/processor/testdata/linux_write_to_nonwritable_module.dmp \ + src/processor/testdata/linux_write_to_nonwritable_region_math.dmp \ + src/processor/testdata/linux_write_to_outside_module.dmp \ + src/processor/testdata/linux_write_to_outside_module_via_math.dmp \ + src/processor/testdata/linux_write_to_under_4k.dmp \ + src/processor/testdata/microdump-arm64.dmp \ + src/processor/testdata/microdump-arm.dmp \ + src/processor/testdata/microdump-mips32.dmp \ + src/processor/testdata/microdump-mips64.dmp \ + src/processor/testdata/microdump-multiple.dmp \ + src/processor/testdata/microdump.stackwalk-arm64.out \ + src/processor/testdata/microdump.stackwalk-arm.out \ + src/processor/testdata/microdump.stackwalk.machine_readable-arm64.out \ + src/processor/testdata/microdump.stackwalk.machine_readable-arm.out \ + src/processor/testdata/microdump-withcrashreason.dmp \ + src/processor/testdata/microdump-x86.dmp \ + src/processor/testdata/minidump_32bit_crash_addr.dmp \ + src/processor/testdata/minidump2.dmp \ + src/processor/testdata/minidump2.dump.out \ + src/processor/testdata/minidump2.stackwalk.machine_readable.out \ + src/processor/testdata/minidump2.stackwalk.out \ + src/processor/testdata/module0.out \ + src/processor/testdata/module1.out \ + src/processor/testdata/module2.out \ + src/processor/testdata/module3_bad.out \ + src/processor/testdata/module4_bad.out \ + src/processor/testdata/null_read_av.dmp \ + src/processor/testdata/null_write_av.dmp \ + src/processor/testdata/read_av_clobber_write.dmp \ + src/processor/testdata/read_av_conditional.dmp \ + src/processor/testdata/read_av_non_null.dmp \ + src/processor/testdata/stack_exhaustion.dmp \ + src/processor/testdata/write_av_non_null.dmp \ + src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym \ + src/processor/testdata/symbols/ld-2.13.so/C32AD7E235EA6112E02A5B9D6219C4850/ld-2.13.so.sym \ + src/processor/testdata/symbols/libc-2.13.so/F4F8DFCD5A5FB5A7CE64717E9E6AE3890/libc-2.13.so.sym \ + src/processor/testdata/symbols/libgcc_s.so.1/18B180F90887D8F8B5C35D185444AF4C0/libgcc_s.so.1.sym \ + src/processor/testdata/symbols/microdump/breakpad_unittests/D6D1FEC9A15DE7F38A236898871A2E770/breakpad_unittests.sym \ + src/processor/testdata/symbols/microdump/breakpad_unittests/DA7778FB66018A4E9B4110ED06E730D00/breakpad_unittests.sym \ + src/processor/testdata/symbols/microdump/crash_example/6E72E2F1A5F59AB3D51356FDFE394D490/crash_example.sym \ + src/processor/testdata/symbols/microdump/crash_example/8F36148CC4647A8116CAF2A25F591F570/crash_example.sym \ + src/processor/testdata/symbols/null_read_av/7B7D1968FF0D47AE4366E9C3A7E1B6750/null_read_av.sym \ + src/processor/testdata/symbols/overflow/B0E1FC01EF48E39CAF5C881D2DF0C3840/overflow.sym \ + src/processor/testdata/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym \ + src/processor/testdata/test_app.cc \ + src/testing/googletest/include/gtest/gtest.h \ + src/testing/googletest/include/gtest/gtest-death-test.h \ + src/testing/googletest/include/gtest/gtest-matchers.h \ + src/testing/googletest/include/gtest/gtest-message.h \ + src/testing/googletest/include/gtest/gtest-param-test.h \ + src/testing/googletest/include/gtest/gtest-printers.h \ + src/testing/googletest/include/gtest/gtest-spi.h \ + src/testing/googletest/include/gtest/gtest-test-part.h \ + src/testing/googletest/include/gtest/gtest-typed-test.h \ + src/testing/googletest/include/gtest/gtest_pred_impl.h \ + src/testing/googletest/include/gtest/gtest_prod.h \ + src/testing/googletest/include/gtest/internal/custom/gtest-port.h \ + src/testing/googletest/include/gtest/internal/custom/gtest-printers.h \ + src/testing/googletest/include/gtest/internal/custom/gtest.h \ + src/testing/googletest/include/gtest/internal/gtest-death-test-internal.h \ + src/testing/googletest/include/gtest/internal/gtest-filepath.h \ + src/testing/googletest/include/gtest/internal/gtest-internal.h \ + src/testing/googletest/include/gtest/internal/gtest-param-util-generated.h \ + src/testing/googletest/include/gtest/internal/gtest-param-util.h \ + src/testing/googletest/include/gtest/internal/gtest-port-arch.h \ + src/testing/googletest/include/gtest/internal/gtest-port.h \ + src/testing/googletest/include/gtest/internal/gtest-string.h \ + src/testing/googletest/include/gtest/internal/gtest-type-util.h \ + src/testing/googletest/src/gtest.cc \ + src/testing/googletest/src/gtest-death-test.cc \ + src/testing/googletest/src/gtest-filepath.cc \ + src/testing/googletest/src/gtest-internal-inl.h \ + src/testing/googletest/src/gtest-matchers.cc \ + src/testing/googletest/src/gtest-port.cc \ + src/testing/googletest/src/gtest-printers.cc \ + src/testing/googletest/src/gtest-test-part.cc \ + src/testing/googletest/src/gtest-typed-test.cc \ + src/testing/googlemock/include/gmock/gmock.h \ + src/testing/googlemock/include/gmock/gmock-actions.h \ + src/testing/googlemock/include/gmock/gmock-cardinalities.h \ + src/testing/googlemock/include/gmock/gmock-function-mocker.h \ + src/testing/googlemock/include/gmock/gmock-generated-actions.h \ + src/testing/googlemock/include/gmock/gmock-generated-function-mockers.h \ + src/testing/googlemock/include/gmock/gmock-generated-matchers.h \ + src/testing/googlemock/include/gmock/gmock-matchers.h \ + src/testing/googlemock/include/gmock/gmock-more-actions.h \ + src/testing/googlemock/include/gmock/gmock-more-matchers.h \ + src/testing/googlemock/include/gmock/gmock-nice-strict.h \ + src/testing/googlemock/include/gmock/gmock-spec-builders.h \ + src/testing/googlemock/include/gmock/internal/custom/gmock-generated-actions.h \ + src/testing/googlemock/include/gmock/internal/custom/gmock-matchers.h \ + src/testing/googlemock/include/gmock/internal/custom/gmock-port.h \ + src/testing/googlemock/include/gmock/internal/gmock-internal-utils.h \ + src/testing/googlemock/include/gmock/internal/gmock-port.h \ + src/testing/googlemock/include/gmock/internal/gmock-pp.h \ + src/testing/googlemock/src/gmock.cc \ + src/testing/googlemock/src/gmock-cardinalities.cc \ + src/testing/googlemock/src/gmock-internal-utils.cc \ + src/testing/googlemock/src/gmock-matchers.cc \ + src/testing/googlemock/src/gmock-spec-builders.cc \ + src/testing/googlemock/src/gmock_main.cc \ + src/third_party/curl/COPYING \ + src/third_party/curl/curlbuild.h \ + src/third_party/curl/curl.h \ + src/third_party/curl/curlrules.h \ + src/third_party/curl/curlver.h \ + src/third_party/curl/easy.h \ + src/third_party/curl/mprintf.h \ + src/third_party/curl/multi.h \ + src/third_party/curl/stdcheaders.h \ + src/third_party/curl/typecheck-gcc.h \ + src/third_party/curl/types.h \ + src/third_party/mac_headers/architecture/byte_order.h \ + src/third_party/mac_headers/i386/_types.h \ + src/third_party/mac_headers/mach/boolean.h \ + src/third_party/mac_headers/mach/i386/boolean.h \ + src/third_party/mac_headers/mach/i386/vm_param.h \ + src/third_party/mac_headers/mach/i386/vm_types.h \ + src/third_party/mac_headers/mach/machine/boolean.h \ + src/third_party/mac_headers/mach/machine.h \ + src/third_party/mac_headers/mach/machine/thread_state.h \ + src/third_party/mac_headers/mach/machine/thread_status.h \ + src/third_party/mac_headers/mach/machine/vm_types.h \ + src/third_party/mac_headers/mach-o/arch.h \ + src/third_party/mac_headers/mach-o/fat.h \ + src/third_party/mac_headers/mach-o/loader.h \ + src/third_party/mac_headers/mach-o/nlist.h \ + src/third_party/mac_headers/mach/thread_status.h \ + src/third_party/mac_headers/mach/vm_prot.h \ + src/third_party/mac_headers/README \ + src/third_party/musl/README \ + src/third_party/musl/COPYRIGHT \ + src/third_party/musl/README.breakpad \ + src/third_party/musl/VERSION \ + src/third_party/musl/include/elf.h \ + src/tools/mac/crash_report/crash_report.mm \ + src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj \ + src/tools/mac/crash_report/on_demand_symbol_supplier.h \ + src/tools/mac/crash_report/on_demand_symbol_supplier.mm \ + src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj \ + src/tools/mac/dump_syms/dump_syms_tool.cc \ + src/tools/mac/symupload/minidump_upload.m \ + src/tools/mac/symupload/symupload.m \ + src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj \ + src/tools/solaris/dump_syms/Makefile \ + src/tools/solaris/dump_syms/dump_syms.cc \ + src/tools/solaris/dump_syms/run_regtest.sh \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym \ + src/tools/windows/converter/ms_symbol_server_converter.cc \ + src/tools/windows/converter/ms_symbol_server_converter.h \ + src/tools/windows/converter/ms_symbol_server_converter.gyp \ + src/tools/windows/dump_syms/dump_syms.cc \ + src/tools/windows/dump_syms/dump_syms.gyp \ + src/tools/windows/dump_syms/run_regtest.sh \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.sym \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest64.sym \ + src/tools/windows/dump_syms/testdata/omap_reorder_bbs.sym \ + src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym \ + src/tools/windows/dump_syms/testdata/omap_stretched.sym \ + src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym \ + src/tools/windows/symupload/symupload.cc \ + src/tools/windows/symupload/symupload.gyp + +mostlyclean-local: + -find src -name '*.dwo' -exec rm -f {} + diff --git a/toolkit/crashreporter/google-breakpad/Makefile.in b/toolkit/crashreporter/google-breakpad/Makefile.in new file mode 100644 index 0000000000..2bdd83b043 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/Makefile.in @@ -0,0 +1,8223 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (c) 2011, 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. + + + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ + +# This allows using fixed NDK headers when building for Android. +# This is only necessary for building the unit tests until GTest is upgraded +# to a future version. +@ANDROID_HOST_TRUE@am__append_1 = \ +@ANDROID_HOST_TRUE@ -I$(top_srcdir)/src/common/android/include \ +@ANDROID_HOST_TRUE@ -I$(top_srcdir)/src/common/android/testing/include + +# These are good warnings to be treated as errors +@GCC_TRUE@am__append_2 = \ +@GCC_TRUE@ -Werror=missing-braces \ +@GCC_TRUE@ -Werror=non-virtual-dtor \ +@GCC_TRUE@ -Werror=overloaded-virtual \ +@GCC_TRUE@ -Werror=reorder \ +@GCC_TRUE@ -Werror=sign-compare \ +@GCC_TRUE@ -Werror=unused-variable \ +@GCC_TRUE@ -Werror=vla + + +# Build as PIC on Linux, for linux_client_unittest_shlib +@LINUX_HOST_TRUE@am__append_3 = -fPIC +@LINUX_HOST_TRUE@am__append_4 = -fPIC +bin_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) +check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) \ + $(am__EXEEXT_8) $(am__EXEEXT_9) +EXTRA_PROGRAMS = $(am__EXEEXT_1) +@DISABLE_PROCESSOR_FALSE@am__append_5 = src/libbreakpad.a +@DISABLE_PROCESSOR_FALSE@am__append_6 = breakpad.pc +@DISABLE_PROCESSOR_FALSE@am__append_7 = src/third_party/libdisasm/libdisasm.a +@LINUX_HOST_TRUE@am__append_8 = src/client/linux/libbreakpad_client.a +@LINUX_HOST_TRUE@am__append_9 = breakpad-client.pc +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_10 = \ +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext.S + +@DISABLE_PROCESSOR_FALSE@am__append_11 = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk + +@LINUX_HOST_TRUE@am__append_12 = src/client/linux/linux_dumper_unittest_helper \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib +@LINUX_HOST_TRUE@am__append_13 = src/client/linux/linux_dumper_unittest_helper \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_14 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_15 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_mac + +@DISABLE_PROCESSOR_FALSE@am__append_16 = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/address_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_shrink_down_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest + +@LINUX_HOST_TRUE@am__append_17 = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__append_18 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dumper_unittest \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_2_core_unittest + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__append_19 = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@ src/common/mac/macho_reader_unittest + +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__append_20 = \ +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@ src/processor/stackwalker_selftest + +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_21 = \ +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext.S + +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_22 = \ +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ src/common/android/breakpad_getcontext_unittest.cc + +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_23 = \ +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog -lm + +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__append_24 = \ +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@ -llog + +noinst_PROGRAMS = +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(dist_doc_DATA) $(includec_HEADERS) \ + $(am__includecl_HEADERS_DIST) $(am__includeclc_HEADERS_DIST) \ + $(am__includecldwc_HEADERS_DIST) \ + $(am__includeclh_HEADERS_DIST) $(am__includeclm_HEADERS_DIST) \ + $(includegbc_HEADERS) $(am__includelss_HEADERS_DIST) \ + $(includep_HEADERS) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = breakpad.pc breakpad-client.pc +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" \ + "$(DESTDIR)$(includecdir)" "$(DESTDIR)$(includecldir)" \ + "$(DESTDIR)$(includeclcdir)" "$(DESTDIR)$(includecldwcdir)" \ + "$(DESTDIR)$(includeclhdir)" "$(DESTDIR)$(includeclmdir)" \ + "$(DESTDIR)$(includegbcdir)" "$(DESTDIR)$(includelssdir)" \ + "$(DESTDIR)$(includepdir)" +LIBRARIES = $(lib_LIBRARIES) $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +src_client_linux_libbreakpad_client_a_AR = $(AR) $(ARFLAGS) +src_client_linux_libbreakpad_client_a_LIBADD = +am__src_client_linux_libbreakpad_client_a_SOURCES_DIST = \ + src/client/linux/crash_generation/crash_generation_client.cc \ + src/client/linux/crash_generation/crash_generation_server.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ + src/client/linux/handler/exception_handler.cc \ + src/client/linux/handler/exception_handler.h \ + src/client/linux/handler/minidump_descriptor.cc \ + src/client/linux/handler/minidump_descriptor.h \ + src/client/linux/log/log.cc src/client/linux/log/log.h \ + src/client/linux/microdump_writer/microdump_writer.cc \ + src/client/linux/microdump_writer/microdump_writer.h \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_dumper.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ + src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/minidump_file_writer-inl.h \ + src/client/minidump_file_writer.cc \ + src/client/minidump_file_writer.h src/common/convert_UTF.c \ + src/common/convert_UTF.h src/common/md5.cc src/common/md5.h \ + src/common/string_conversion.cc src/common/string_conversion.h \ + src/common/linux/elf_core_dump.cc src/common/linux/elfutils.cc \ + src/common/linux/elfutils.h src/common/linux/file_id.cc \ + src/common/linux/file_id.h src/common/linux/guid_creator.cc \ + src/common/linux/guid_creator.h \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc \ + src/common/android/breakpad_getcontext.S +am__dirstamp = $(am__leading_dot)dirstamp +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_1 = src/common/android/breakpad_getcontext.$(OBJEXT) +@LINUX_HOST_TRUE@am_src_client_linux_libbreakpad_client_a_OBJECTS = src/client/linux/crash_generation/crash_generation_client.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/log/log.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/minidump_file_writer.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/convert_UTF.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/md5.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/string_conversion.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/elfutils.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/file_id.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/guid_creator.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.$(OBJEXT) \ +@LINUX_HOST_TRUE@ $(am__objects_1) +src_client_linux_libbreakpad_client_a_OBJECTS = \ + $(am_src_client_linux_libbreakpad_client_a_OBJECTS) +src_libbreakpad_a_AR = $(AR) $(ARFLAGS) +src_libbreakpad_a_LIBADD = +am__src_libbreakpad_a_SOURCES_DIST = \ + src/google_breakpad/common/breakpad_types.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/dump_context.h \ + src/google_breakpad/processor/dump_object.h \ + src/google_breakpad/processor/exploitability.h \ + src/google_breakpad/processor/fast_source_line_resolver.h \ + src/google_breakpad/processor/memory_region.h \ + src/google_breakpad/processor/microdump.h \ + src/google_breakpad/processor/microdump_processor.h \ + src/google_breakpad/processor/minidump.h \ + src/google_breakpad/processor/minidump_processor.h \ + src/google_breakpad/processor/process_result.h \ + src/google_breakpad/processor/process_state.h \ + src/google_breakpad/processor/proc_maps_linux.h \ + src/google_breakpad/processor/source_line_resolver_base.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/stack_frame_symbolizer.h \ + src/google_breakpad/processor/stackwalker.h \ + src/google_breakpad/processor/symbol_supplier.h \ + src/google_breakpad/processor/system_info.h \ + src/processor/address_map-inl.h src/processor/address_map.h \ + src/processor/basic_code_module.h \ + src/processor/basic_code_modules.cc \ + src/processor/basic_code_modules.h \ + src/processor/basic_source_line_resolver_types.h \ + src/processor/basic_source_line_resolver.cc \ + src/processor/call_stack.cc src/processor/cfi_frame_info.cc \ + src/processor/cfi_frame_info.h \ + src/processor/contained_range_map-inl.h \ + src/processor/contained_range_map.h \ + src/processor/disassembler_x86.h \ + src/processor/disassembler_x86.cc \ + src/processor/dump_context.cc src/processor/dump_object.cc \ + src/processor/exploitability.cc \ + src/processor/exploitability_linux.h \ + src/processor/exploitability_linux.cc \ + src/processor/exploitability_win.h \ + src/processor/exploitability_win.cc \ + src/processor/fast_source_line_resolver_types.h \ + src/processor/fast_source_line_resolver.cc \ + src/processor/linked_ptr.h src/processor/logging.h \ + src/processor/logging.cc src/processor/map_serializers-inl.h \ + src/processor/map_serializers.h src/processor/microdump.cc \ + src/processor/microdump_processor.cc src/processor/minidump.cc \ + src/processor/minidump_processor.cc \ + src/processor/module_comparer.cc \ + src/processor/module_comparer.h src/processor/module_factory.h \ + src/processor/module_serializer.cc \ + src/processor/module_serializer.h \ + src/processor/pathname_stripper.cc \ + src/processor/pathname_stripper.h \ + src/processor/postfix_evaluator-inl.h \ + src/processor/postfix_evaluator.h \ + src/processor/process_state.cc \ + src/processor/proc_maps_linux.cc src/processor/range_map-inl.h \ + src/processor/range_map.h \ + src/processor/simple_serializer-inl.h \ + src/processor/simple_serializer.h \ + src/processor/simple_symbol_supplier.cc \ + src/processor/simple_symbol_supplier.h \ + src/processor/windows_frame_info.h \ + src/processor/source_line_resolver_base_types.h \ + src/processor/source_line_resolver_base.cc \ + src/processor/stack_frame_cpu.cc \ + src/processor/stack_frame_symbolizer.cc \ + src/processor/stackwalker.cc \ + src/processor/stackwalker_amd64.cc \ + src/processor/stackwalker_amd64.h \ + src/processor/stackwalker_arm.cc \ + src/processor/stackwalker_arm.h \ + src/processor/stackwalker_arm64.cc \ + src/processor/stackwalker_arm64.h \ + src/processor/stackwalker_address_list.cc \ + src/processor/stackwalker_address_list.h \ + src/processor/stackwalker_mips.cc \ + src/processor/stackwalker_mips.h \ + src/processor/stackwalker_ppc.cc \ + src/processor/stackwalker_ppc.h \ + src/processor/stackwalker_ppc64.cc \ + src/processor/stackwalker_ppc64.h \ + src/processor/stackwalker_sparc.cc \ + src/processor/stackwalker_sparc.h \ + src/processor/stackwalker_x86.cc \ + src/processor/stackwalker_x86.h \ + src/processor/static_address_map-inl.h \ + src/processor/static_address_map.h \ + src/processor/static_contained_range_map-inl.h \ + src/processor/static_contained_range_map.h \ + src/processor/static_map_iterator-inl.h \ + src/processor/static_map_iterator.h \ + src/processor/static_map-inl.h src/processor/static_map.h \ + src/processor/static_range_map-inl.h \ + src/processor/static_range_map.h \ + src/processor/symbolic_constants_win.cc \ + src/processor/symbolic_constants_win.h \ + src/processor/tokenize.cc src/processor/tokenize.h +@DISABLE_PROCESSOR_FALSE@am_src_libbreakpad_a_OBJECTS = src/processor/basic_code_modules.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.$(OBJEXT) +src_libbreakpad_a_OBJECTS = $(am_src_libbreakpad_a_OBJECTS) +src_testing_libtesting_a_AR = $(AR) $(ARFLAGS) +src_testing_libtesting_a_LIBADD = +am__src_testing_libtesting_a_SOURCES_DIST = \ + src/breakpad_googletest_includes.h \ + src/testing/gtest/src/gtest-all.cc \ + src/testing/gtest/src/gtest_main.cc \ + src/testing/src/gmock-all.cc +@SYSTEM_TEST_LIBS_FALSE@am_src_testing_libtesting_a_OBJECTS = src/testing/gtest/src/src_testing_libtesting_a-gtest-all.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/gtest/src/src_testing_libtesting_a-gtest_main.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/src/src_testing_libtesting_a-gmock-all.$(OBJEXT) +src_testing_libtesting_a_OBJECTS = \ + $(am_src_testing_libtesting_a_OBJECTS) +src_third_party_libdisasm_libdisasm_a_AR = $(AR) $(ARFLAGS) +src_third_party_libdisasm_libdisasm_a_LIBADD = +am__src_third_party_libdisasm_libdisasm_a_SOURCES_DIST = \ + src/third_party/libdisasm/ia32_implicit.c \ + src/third_party/libdisasm/ia32_implicit.h \ + src/third_party/libdisasm/ia32_insn.c \ + src/third_party/libdisasm/ia32_insn.h \ + src/third_party/libdisasm/ia32_invariant.c \ + src/third_party/libdisasm/ia32_invariant.h \ + src/third_party/libdisasm/ia32_modrm.c \ + src/third_party/libdisasm/ia32_modrm.h \ + src/third_party/libdisasm/ia32_opcode_tables.c \ + src/third_party/libdisasm/ia32_opcode_tables.h \ + src/third_party/libdisasm/ia32_operand.c \ + src/third_party/libdisasm/ia32_operand.h \ + src/third_party/libdisasm/ia32_reg.c \ + src/third_party/libdisasm/ia32_reg.h \ + src/third_party/libdisasm/ia32_settings.c \ + src/third_party/libdisasm/ia32_settings.h \ + src/third_party/libdisasm/libdis.h \ + src/third_party/libdisasm/qword.h \ + src/third_party/libdisasm/x86_disasm.c \ + src/third_party/libdisasm/x86_format.c \ + src/third_party/libdisasm/x86_imm.c \ + src/third_party/libdisasm/x86_imm.h \ + src/third_party/libdisasm/x86_insn.c \ + src/third_party/libdisasm/x86_misc.c \ + src/third_party/libdisasm/x86_operand_list.c \ + src/third_party/libdisasm/x86_operand_list.h +@DISABLE_PROCESSOR_FALSE@am_src_third_party_libdisasm_libdisasm_a_OBJECTS = src/third_party/libdisasm/ia32_implicit.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_disasm.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_format.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_insn.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_misc.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.$(OBJEXT) +src_third_party_libdisasm_libdisasm_a_OBJECTS = \ + $(am_src_third_party_libdisasm_libdisasm_a_OBJECTS) +@LINUX_HOST_TRUE@am__EXEEXT_1 = src/client/linux/linux_dumper_unittest_helper$(EXEEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib$(EXEEXT) +@DISABLE_PROCESSOR_FALSE@am__EXEEXT_2 = src/processor/microdump_stackwalk$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk$(EXEEXT) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_3 = src/tools/linux/core2md/core2md$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload$(EXEEXT) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__EXEEXT_4 = src/tools/mac/dump_syms/dump_syms_mac$(EXEEXT) +@DISABLE_PROCESSOR_FALSE@am__EXEEXT_5 = src/common/test_assembler_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/address_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_shrink_down_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest$(EXEEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest$(EXEEXT) +@LINUX_HOST_TRUE@am__EXEEXT_6 = src/client/linux/linux_client_unittest$(EXEEXT) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am__EXEEXT_7 = src/common/dumper_unittest$(EXEEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@@X86_HOST_TRUE@am__EXEEXT_8 = src/common/mac/macho_reader_unittest$(EXEEXT) +@DISABLE_PROCESSOR_FALSE@@SELFTEST_TRUE@am__EXEEXT_9 = src/processor/stackwalker_selftest$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_src_client_linux_linux_client_unittest_OBJECTS = +src_client_linux_linux_client_unittest_OBJECTS = \ + $(am_src_client_linux_linux_client_unittest_OBJECTS) +am__DEPENDENCIES_1 = +@SYSTEM_TEST_LIBS_FALSE@am__DEPENDENCIES_2 = src/testing/libtesting.a +@SYSTEM_TEST_LIBS_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ +@SYSTEM_TEST_LIBS_TRUE@ $(am__DEPENDENCIES_1) +src_client_linux_linux_client_unittest_LINK = $(CCLD) $(AM_CFLAGS) \ + $(CFLAGS) $(src_client_linux_linux_client_unittest_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST = \ + src/breakpad_googletest_includes.h \ + src/testing/gtest/src/gtest-all.cc \ + src/testing/gtest/src/gtest_main.cc \ + src/testing/src/gmock-all.cc \ + src/client/linux/handler/exception_handler_unittest.cc \ + src/client/linux/minidump_writer/directory_reader_unittest.cc \ + src/client/linux/minidump_writer/cpu_set_unittest.cc \ + src/client/linux/minidump_writer/line_reader_unittest.cc \ + src/client/linux/minidump_writer/linux_core_dumper.cc \ + src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest.cc \ + src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ + src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/linux_libc_support_unittest.cc \ + src/common/linux/tests/auto_testfile.h \ + src/common/linux/tests/crash_generator.cc \ + src/common/memory_allocator_unittest.cc \ + src/common/tests/auto_tempdir.h src/common/tests/file_utils.cc \ + src/common/tests/file_utils.h \ + src/processor/basic_code_modules.cc \ + src/processor/dump_context.cc src/processor/dump_object.cc \ + src/processor/logging.cc src/processor/minidump.cc \ + src/processor/pathname_stripper.cc \ + src/processor/proc_maps_linux.cc \ + src/common/android/breakpad_getcontext.S \ + src/client/linux/microdump_writer/microdump_writer_unittest.cc \ + src/common/android/breakpad_getcontext_unittest.cc +@SYSTEM_TEST_LIBS_FALSE@am__objects_2 = src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.$(OBJEXT) \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.$(OBJEXT) +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_3 = src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT) +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@am__objects_4 = src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT) +@LINUX_HOST_TRUE@am_src_client_linux_linux_client_unittest_shlib_OBJECTS = \ +@LINUX_HOST_TRUE@ $(am__objects_2) \ +@LINUX_HOST_TRUE@ src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-logging.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-minidump.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.$(OBJEXT) \ +@LINUX_HOST_TRUE@ src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.$(OBJEXT) \ +@LINUX_HOST_TRUE@ $(am__objects_3) \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT) \ +@LINUX_HOST_TRUE@ $(am__objects_4) +src_client_linux_linux_client_unittest_shlib_OBJECTS = \ + $(am_src_client_linux_linux_client_unittest_shlib_OBJECTS) +src_client_linux_linux_client_unittest_shlib_LINK = $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(src_client_linux_linux_client_unittest_shlib_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__src_client_linux_linux_dumper_unittest_helper_SOURCES_DIST = src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +@LINUX_HOST_TRUE@am_src_client_linux_linux_dumper_unittest_helper_OBJECTS = src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT) +src_client_linux_linux_dumper_unittest_helper_OBJECTS = \ + $(am_src_client_linux_linux_dumper_unittest_helper_OBJECTS) +src_client_linux_linux_dumper_unittest_helper_LDADD = $(LDADD) +src_client_linux_linux_dumper_unittest_helper_LINK = $(CXXLD) \ + $(src_client_linux_linux_dumper_unittest_helper_CXXFLAGS) \ + $(CXXFLAGS) \ + $(src_client_linux_linux_dumper_unittest_helper_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__src_common_dumper_unittest_SOURCES_DIST = \ + src/common/byte_cursor_unittest.cc \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cfi_to_module_unittest.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_cu_to_module_unittest.cc \ + src/common/dwarf_line_to_module.cc \ + src/common/dwarf_line_to_module_unittest.cc \ + src/common/language.cc src/common/memory_range_unittest.cc \ + src/common/module.cc src/common/module_unittest.cc \ + src/common/stabs_reader.cc src/common/stabs_reader_unittest.cc \ + src/common/stabs_to_module.cc \ + src/common/stabs_to_module_unittest.cc \ + src/common/test_assembler.cc src/common/dwarf/bytereader.cc \ + src/common/dwarf/bytereader.h \ + src/common/dwarf/bytereader-inl.h \ + src/common/dwarf/bytereader_unittest.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/cfi_assembler.h \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2diehandler_unittest.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/dwarf2reader.h src/common/dwarf/elf_reader.cc \ + src/common/dwarf/elf_reader.h \ + src/common/dwarf/dwarf2reader_cfi_unittest.cc \ + src/common/dwarf/dwarf2reader_die_unittest.cc \ + src/common/dwarf/dwarf2reader_test_common.h \ + src/common/linux/crc32.cc src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols_unittest.cc \ + src/common/linux/elf_core_dump.cc \ + src/common/linux/elf_core_dump_unittest.cc \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module_unittest.cc \ + src/common/linux/elfutils.cc src/common/linux/file_id.cc \ + src/common/linux/file_id_unittest.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/memory_mapped_file_unittest.cc \ + src/common/linux/safe_readlink.cc \ + src/common/linux/safe_readlink_unittest.cc \ + src/common/linux/synth_elf.cc \ + src/common/linux/synth_elf_unittest.cc \ + src/common/linux/tests/crash_generator.cc \ + src/common/linux/tests/crash_generator.h \ + src/common/testdata/func-line-pairing.h \ + src/common/tests/file_utils.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_common_dumper_unittest_OBJECTS = src/common/src_common_dumper_unittest-byte_cursor_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_cfi_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_cu_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_line_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-language.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-cfi_assembler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-elf_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-crc32.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_core_dump.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elfutils.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-file_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-file_id_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-linux_libc_support.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-memory_mapped_file.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-safe_readlink.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/src_common_dumper_unittest-crash_generator.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT) +src_common_dumper_unittest_OBJECTS = \ + $(am_src_common_dumper_unittest_OBJECTS) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_DEPENDENCIES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) +am__src_common_mac_macho_reader_unittest_SOURCES_DIST = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc src/common/language.cc \ + src/common/md5.cc src/common/module.cc \ + src/common/stabs_reader.cc src/common/stabs_to_module.cc \ + src/common/test_assembler.cc src/common/dwarf/bytereader.cc \ + src/common/dwarf/cfi_assembler.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc src/common/mac/file_id.cc \ + src/common/mac/macho_id.cc src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader_unittest.cc \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_walker.cc src/common/tests/file_utils.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_common_mac_macho_reader_unittest_OBJECTS = src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-language.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-md5.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-stabs_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-stabs_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_common_mac_macho_reader_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-file_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/src_common_mac_macho_reader_unittest-file_utils.$(OBJEXT) +src_common_mac_macho_reader_unittest_OBJECTS = \ + $(am_src_common_mac_macho_reader_unittest_OBJECTS) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_DEPENDENCIES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) +am__src_common_test_assembler_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc src/common/test_assembler.h \ + src/common/test_assembler_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_common_test_assembler_unittest_OBJECTS = src/common/src_common_test_assembler_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/common/src_common_test_assembler_unittest-test_assembler_unittest.$(OBJEXT) +src_common_test_assembler_unittest_OBJECTS = \ + $(am_src_common_test_assembler_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_address_map_unittest_SOURCES_DIST = \ + src/processor/address_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_address_map_unittest_OBJECTS = src/processor/address_map_unittest.$(OBJEXT) +src_processor_address_map_unittest_OBJECTS = \ + $(am_src_processor_address_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o +am__src_processor_basic_source_line_resolver_unittest_SOURCES_DIST = \ + src/processor/basic_source_line_resolver_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_basic_source_line_resolver_unittest_OBJECTS = src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.$(OBJEXT) +src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_cfi_frame_info_unittest_SOURCES_DIST = \ + src/processor/cfi_frame_info_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_cfi_frame_info_unittest_OBJECTS = src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT) +src_processor_cfi_frame_info_unittest_OBJECTS = \ + $(am_src_processor_cfi_frame_info_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_contained_range_map_unittest_SOURCES_DIST = \ + src/processor/contained_range_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_contained_range_map_unittest_OBJECTS = src/processor/contained_range_map_unittest.$(OBJEXT) +src_processor_contained_range_map_unittest_OBJECTS = \ + $(am_src_processor_contained_range_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o +am__src_processor_disassembler_x86_unittest_SOURCES_DIST = \ + src/processor/disassembler_x86_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_disassembler_x86_unittest_OBJECTS = src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.$(OBJEXT) +src_processor_disassembler_x86_unittest_OBJECTS = \ + $(am_src_processor_disassembler_x86_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_exploitability_unittest_SOURCES_DIST = \ + src/processor/exploitability_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_exploitability_unittest_OBJECTS = src/processor/src_processor_exploitability_unittest-exploitability_unittest.$(OBJEXT) +src_processor_exploitability_unittest_OBJECTS = \ + $(am_src_processor_exploitability_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_fast_source_line_resolver_unittest_SOURCES_DIST = \ + src/processor/fast_source_line_resolver_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_fast_source_line_resolver_unittest_OBJECTS = src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.$(OBJEXT) +src_processor_fast_source_line_resolver_unittest_OBJECTS = $(am_src_processor_fast_source_line_resolver_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_DEPENDENCIES = src/processor/fast_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_map_serializers_unittest_SOURCES_DIST = \ + src/processor/map_serializers_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_map_serializers_unittest_OBJECTS = src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.$(OBJEXT) +src_processor_map_serializers_unittest_OBJECTS = \ + $(am_src_processor_map_serializers_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_microdump_processor_unittest_SOURCES_DIST = \ + src/processor/microdump_processor_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_microdump_processor_unittest_OBJECTS = src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.$(OBJEXT) +src_processor_microdump_processor_unittest_OBJECTS = \ + $(am_src_processor_microdump_processor_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_microdump_stackwalk_SOURCES_DIST = \ + src/processor/microdump_stackwalk.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_microdump_stackwalk_OBJECTS = src/processor/microdump_stackwalk.$(OBJEXT) +src_processor_microdump_stackwalk_OBJECTS = \ + $(am_src_processor_microdump_stackwalk_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a +am__src_processor_minidump_dump_SOURCES_DIST = \ + src/processor/minidump_dump.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_dump_OBJECTS = src/processor/minidump_dump.$(OBJEXT) +src_processor_minidump_dump_OBJECTS = \ + $(am_src_processor_minidump_dump_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o +am__src_processor_minidump_processor_unittest_SOURCES_DIST = \ + src/processor/minidump_processor_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_processor_unittest_OBJECTS = src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT) +src_processor_minidump_processor_unittest_OBJECTS = \ + $(am_src_processor_minidump_processor_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_minidump_stackwalk_SOURCES_DIST = \ + src/processor/minidump_stackwalk.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_stackwalk_OBJECTS = src/processor/minidump_stackwalk.$(OBJEXT) +src_processor_minidump_stackwalk_OBJECTS = \ + $(am_src_processor_minidump_stackwalk_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a +am__src_processor_minidump_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/minidump_unittest.cc \ + src/processor/synth_minidump.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_minidump_unittest_OBJECTS = src/common/src_processor_minidump_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_minidump_unittest-minidump_unittest.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_minidump_unittest-synth_minidump.$(OBJEXT) +src_processor_minidump_unittest_OBJECTS = \ + $(am_src_processor_minidump_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_pathname_stripper_unittest_SOURCES_DIST = \ + src/processor/pathname_stripper_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_pathname_stripper_unittest_OBJECTS = src/processor/pathname_stripper_unittest.$(OBJEXT) +src_processor_pathname_stripper_unittest_OBJECTS = \ + $(am_src_processor_pathname_stripper_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_postfix_evaluator_unittest_SOURCES_DIST = \ + src/processor/postfix_evaluator_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_postfix_evaluator_unittest_OBJECTS = src/processor/postfix_evaluator_unittest.$(OBJEXT) +src_processor_postfix_evaluator_unittest_OBJECTS = \ + $(am_src_processor_postfix_evaluator_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_proc_maps_linux_unittest_SOURCES_DIST = \ + src/processor/proc_maps_linux.cc \ + src/processor/proc_maps_linux_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_proc_maps_linux_unittest_OBJECTS = src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.$(OBJEXT) +src_processor_proc_maps_linux_unittest_OBJECTS = \ + $(am_src_processor_proc_maps_linux_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_range_map_shrink_down_unittest_SOURCES_DIST = \ + src/processor/range_map_shrink_down_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_shrink_down_unittest_OBJECTS = src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.$(OBJEXT) +src_processor_range_map_shrink_down_unittest_OBJECTS = \ + $(am_src_processor_range_map_shrink_down_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_shrink_down_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_range_map_unittest_SOURCES_DIST = \ + src/processor/range_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_range_map_unittest_OBJECTS = src/processor/range_map_unittest.$(OBJEXT) +src_processor_range_map_unittest_OBJECTS = \ + $(am_src_processor_range_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_address_list_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_address_list_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_address_list_unittest_OBJECTS = src/common/src_processor_stackwalker_address_list_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.$(OBJEXT) +src_processor_stackwalker_address_list_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_address_list_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_amd64_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_amd64_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_amd64_unittest_OBJECTS = src/common/src_processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.$(OBJEXT) +src_processor_stackwalker_amd64_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_amd64_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_arm64_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm64_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_arm64_unittest_OBJECTS = src/common/src_processor_stackwalker_arm64_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.$(OBJEXT) +src_processor_stackwalker_arm64_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_arm64_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_arm_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_arm_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_arm_unittest_OBJECTS = src/common/src_processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.$(OBJEXT) +src_processor_stackwalker_arm_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_arm_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_mips64_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips64_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_mips64_unittest_OBJECTS = src/common/src_processor_stackwalker_mips64_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.$(OBJEXT) +src_processor_stackwalker_mips64_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_mips64_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_mips_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_mips_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_mips_unittest_OBJECTS = src/common/src_processor_stackwalker_mips_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.$(OBJEXT) +src_processor_stackwalker_mips_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_mips_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_selftest_SOURCES_DIST = \ + src/processor/stackwalker_selftest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_selftest_OBJECTS = src/processor/stackwalker_selftest.$(OBJEXT) +src_processor_stackwalker_selftest_OBJECTS = \ + $(am_src_processor_stackwalker_selftest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_stackwalker_x86_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc \ + src/processor/stackwalker_x86_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_stackwalker_x86_unittest_OBJECTS = src/common/src_processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.$(OBJEXT) +src_processor_stackwalker_x86_unittest_OBJECTS = \ + $(am_src_processor_stackwalker_x86_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_static_address_map_unittest_SOURCES_DIST = \ + src/processor/static_address_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_static_address_map_unittest_OBJECTS = src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.$(OBJEXT) +src_processor_static_address_map_unittest_OBJECTS = \ + $(am_src_processor_static_address_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_static_contained_range_map_unittest_SOURCES_DIST = \ + src/processor/static_contained_range_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_static_contained_range_map_unittest_OBJECTS = src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.$(OBJEXT) +src_processor_static_contained_range_map_unittest_OBJECTS = $(am_src_processor_static_contained_range_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_static_map_unittest_SOURCES_DIST = \ + src/processor/static_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_static_map_unittest_OBJECTS = src/processor/src_processor_static_map_unittest-static_map_unittest.$(OBJEXT) +src_processor_static_map_unittest_OBJECTS = \ + $(am_src_processor_static_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_static_range_map_unittest_SOURCES_DIST = \ + src/processor/static_range_map_unittest.cc +@DISABLE_PROCESSOR_FALSE@am_src_processor_static_range_map_unittest_OBJECTS = src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.$(OBJEXT) +src_processor_static_range_map_unittest_OBJECTS = \ + $(am_src_processor_static_range_map_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_processor_synth_minidump_unittest_SOURCES_DIST = \ + src/common/test_assembler.cc src/common/test_assembler.h \ + src/processor/synth_minidump_unittest.cc \ + src/processor/synth_minidump.cc src/processor/synth_minidump.h +@DISABLE_PROCESSOR_FALSE@am_src_processor_synth_minidump_unittest_OBJECTS = src/common/src_processor_synth_minidump_unittest-test_assembler.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.$(OBJEXT) \ +@DISABLE_PROCESSOR_FALSE@ src/processor/src_processor_synth_minidump_unittest-synth_minidump.$(OBJEXT) +src_processor_synth_minidump_unittest_OBJECTS = \ + $(am_src_processor_synth_minidump_unittest_OBJECTS) +@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_DEPENDENCIES = \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_2) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) \ +@DISABLE_PROCESSOR_FALSE@ $(am__DEPENDENCIES_1) +am__src_tools_linux_core2md_core2md_SOURCES_DIST = \ + src/tools/linux/core2md/core2md.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_core2md_core2md_OBJECTS = src/tools/linux/core2md/core2md.$(OBJEXT) +src_tools_linux_core2md_core2md_OBJECTS = \ + $(am_src_tools_linux_core2md_core2md_OBJECTS) +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_DEPENDENCIES = src/client/linux/libbreakpad_client.a +am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc src/common/language.cc \ + src/common/module.cc src/common/stabs_reader.cc \ + src/common/stabs_to_module.cc src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc src/common/linux/crc32.cc \ + src/common/linux/dump_symbols.cc \ + src/common/linux/dump_symbols.h \ + src/common/linux/elf_symbols_to_module.cc \ + src/common/linux/elf_symbols_to_module.h \ + src/common/linux/elfutils.cc src/common/linux/file_id.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc \ + src/tools/linux/dump_syms/dump_syms.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_dump_syms_dump_syms_OBJECTS = src/common/dwarf_cfi_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms.$(OBJEXT) +src_tools_linux_dump_syms_dump_syms_OBJECTS = \ + $(am_src_tools_linux_dump_syms_dump_syms_OBJECTS) +src_tools_linux_dump_syms_dump_syms_LDADD = $(LDADD) +am__src_tools_linux_md2core_minidump_2_core_SOURCES_DIST = \ + src/common/linux/memory_mapped_file.cc \ + src/tools/linux/md2core/minidump-2-core.cc \ + src/tools/linux/md2core/minidump_memory_range.h +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_md2core_minidump_2_core_OBJECTS = src/common/linux/memory_mapped_file.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core.$(OBJEXT) +src_tools_linux_md2core_minidump_2_core_OBJECTS = \ + $(am_src_tools_linux_md2core_minidump_2_core_OBJECTS) +src_tools_linux_md2core_minidump_2_core_LDADD = $(LDADD) +am__src_tools_linux_md2core_minidump_2_core_unittest_SOURCES_DIST = \ + src/tools/linux/md2core/minidump_memory_range_unittest.cc +@LINUX_HOST_TRUE@am_src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS = src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.$(OBJEXT) +src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS = $(am_src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) +@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES = \ +@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ +@LINUX_HOST_TRUE@ $(am__DEPENDENCIES_1) +am__src_tools_linux_symupload_minidump_upload_SOURCES_DIST = \ + src/common/linux/http_upload.cc \ + src/tools/linux/symupload/minidump_upload.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_symupload_minidump_upload_OBJECTS = src/common/linux/http_upload.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload.$(OBJEXT) +src_tools_linux_symupload_minidump_upload_OBJECTS = \ + $(am_src_tools_linux_symupload_minidump_upload_OBJECTS) +src_tools_linux_symupload_minidump_upload_DEPENDENCIES = +am__src_tools_linux_symupload_sym_upload_SOURCES_DIST = \ + src/common/linux/http_upload.cc src/common/linux/http_upload.h \ + src/common/linux/symbol_upload.cc \ + src/common/linux/symbol_upload.h \ + src/tools/linux/symupload/sym_upload.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_linux_symupload_sym_upload_OBJECTS = src/common/linux/http_upload.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload.$(OBJEXT) +src_tools_linux_symupload_sym_upload_OBJECTS = \ + $(am_src_tools_linux_symupload_sym_upload_OBJECTS) +src_tools_linux_symupload_sym_upload_DEPENDENCIES = +am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST = \ + src/common/dwarf_cfi_to_module.cc \ + src/common/dwarf_cu_to_module.cc \ + src/common/dwarf_line_to_module.cc src/common/language.cc \ + src/common/md5.cc src/common/module.cc \ + src/common/stabs_reader.cc src/common/stabs_to_module.cc \ + src/common/dwarf/bytereader.cc \ + src/common/dwarf/dwarf2diehandler.cc \ + src/common/dwarf/dwarf2reader.cc \ + src/common/dwarf/elf_reader.cc \ + src/common/mac/arch_utilities.cc src/common/mac/dump_syms.cc \ + src/common/mac/dump_syms.h src/common/mac/file_id.cc \ + src/common/mac/file_id.h src/common/mac/macho_id.cc \ + src/common/mac/macho_id.h src/common/mac/macho_reader.cc \ + src/common/mac/macho_reader.h \ + src/common/mac/macho_utilities.cc \ + src/common/mac/macho_utilities.h \ + src/common/mac/macho_walker.cc src/common/mac/macho_walker.h \ + src/tools/mac/dump_syms/dump_syms_tool.cc +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.$(OBJEXT) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.$(OBJEXT) +src_tools_mac_dump_syms_dump_syms_mac_OBJECTS = \ + $(am_src_tools_mac_dump_syms_dump_syms_mac_OBJECTS) +src_tools_mac_dump_syms_dump_syms_mac_LDADD = $(LDADD) +src_tools_mac_dump_syms_dump_syms_mac_LINK = $(CXXLD) \ + $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SCRIPTS = $(noinst_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src +depcomp = $(SHELL) $(top_srcdir)/autotools/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +AM_V_CPPAS = $(am__v_CPPAS_@AM_V@) +am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@) +am__v_CPPAS_0 = @echo " CPPAS " $@; +am__v_CPPAS_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(src_client_linux_libbreakpad_client_a_SOURCES) \ + $(src_libbreakpad_a_SOURCES) \ + $(src_testing_libtesting_a_SOURCES) \ + $(src_third_party_libdisasm_libdisasm_a_SOURCES) \ + $(src_client_linux_linux_client_unittest_SOURCES) \ + $(src_client_linux_linux_client_unittest_shlib_SOURCES) \ + $(src_client_linux_linux_dumper_unittest_helper_SOURCES) \ + $(src_common_dumper_unittest_SOURCES) \ + $(src_common_mac_macho_reader_unittest_SOURCES) \ + $(src_common_test_assembler_unittest_SOURCES) \ + $(src_processor_address_map_unittest_SOURCES) \ + $(src_processor_basic_source_line_resolver_unittest_SOURCES) \ + $(src_processor_cfi_frame_info_unittest_SOURCES) \ + $(src_processor_contained_range_map_unittest_SOURCES) \ + $(src_processor_disassembler_x86_unittest_SOURCES) \ + $(src_processor_exploitability_unittest_SOURCES) \ + $(src_processor_fast_source_line_resolver_unittest_SOURCES) \ + $(src_processor_map_serializers_unittest_SOURCES) \ + $(src_processor_microdump_processor_unittest_SOURCES) \ + $(src_processor_microdump_stackwalk_SOURCES) \ + $(src_processor_minidump_dump_SOURCES) \ + $(src_processor_minidump_processor_unittest_SOURCES) \ + $(src_processor_minidump_stackwalk_SOURCES) \ + $(src_processor_minidump_unittest_SOURCES) \ + $(src_processor_pathname_stripper_unittest_SOURCES) \ + $(src_processor_postfix_evaluator_unittest_SOURCES) \ + $(src_processor_proc_maps_linux_unittest_SOURCES) \ + $(src_processor_range_map_shrink_down_unittest_SOURCES) \ + $(src_processor_range_map_unittest_SOURCES) \ + $(src_processor_stackwalker_address_list_unittest_SOURCES) \ + $(src_processor_stackwalker_amd64_unittest_SOURCES) \ + $(src_processor_stackwalker_arm64_unittest_SOURCES) \ + $(src_processor_stackwalker_arm_unittest_SOURCES) \ + $(src_processor_stackwalker_mips64_unittest_SOURCES) \ + $(src_processor_stackwalker_mips_unittest_SOURCES) \ + $(src_processor_stackwalker_selftest_SOURCES) \ + $(src_processor_stackwalker_x86_unittest_SOURCES) \ + $(src_processor_static_address_map_unittest_SOURCES) \ + $(src_processor_static_contained_range_map_unittest_SOURCES) \ + $(src_processor_static_map_unittest_SOURCES) \ + $(src_processor_static_range_map_unittest_SOURCES) \ + $(src_processor_synth_minidump_unittest_SOURCES) \ + $(src_tools_linux_core2md_core2md_SOURCES) \ + $(src_tools_linux_dump_syms_dump_syms_SOURCES) \ + $(src_tools_linux_md2core_minidump_2_core_SOURCES) \ + $(src_tools_linux_md2core_minidump_2_core_unittest_SOURCES) \ + $(src_tools_linux_symupload_minidump_upload_SOURCES) \ + $(src_tools_linux_symupload_sym_upload_SOURCES) \ + $(src_tools_mac_dump_syms_dump_syms_mac_SOURCES) +DIST_SOURCES = \ + $(am__src_client_linux_libbreakpad_client_a_SOURCES_DIST) \ + $(am__src_libbreakpad_a_SOURCES_DIST) \ + $(am__src_testing_libtesting_a_SOURCES_DIST) \ + $(am__src_third_party_libdisasm_libdisasm_a_SOURCES_DIST) \ + $(src_client_linux_linux_client_unittest_SOURCES) \ + $(am__src_client_linux_linux_client_unittest_shlib_SOURCES_DIST) \ + $(am__src_client_linux_linux_dumper_unittest_helper_SOURCES_DIST) \ + $(am__src_common_dumper_unittest_SOURCES_DIST) \ + $(am__src_common_mac_macho_reader_unittest_SOURCES_DIST) \ + $(am__src_common_test_assembler_unittest_SOURCES_DIST) \ + $(am__src_processor_address_map_unittest_SOURCES_DIST) \ + $(am__src_processor_basic_source_line_resolver_unittest_SOURCES_DIST) \ + $(am__src_processor_cfi_frame_info_unittest_SOURCES_DIST) \ + $(am__src_processor_contained_range_map_unittest_SOURCES_DIST) \ + $(am__src_processor_disassembler_x86_unittest_SOURCES_DIST) \ + $(am__src_processor_exploitability_unittest_SOURCES_DIST) \ + $(am__src_processor_fast_source_line_resolver_unittest_SOURCES_DIST) \ + $(am__src_processor_map_serializers_unittest_SOURCES_DIST) \ + $(am__src_processor_microdump_processor_unittest_SOURCES_DIST) \ + $(am__src_processor_microdump_stackwalk_SOURCES_DIST) \ + $(am__src_processor_minidump_dump_SOURCES_DIST) \ + $(am__src_processor_minidump_processor_unittest_SOURCES_DIST) \ + $(am__src_processor_minidump_stackwalk_SOURCES_DIST) \ + $(am__src_processor_minidump_unittest_SOURCES_DIST) \ + $(am__src_processor_pathname_stripper_unittest_SOURCES_DIST) \ + $(am__src_processor_postfix_evaluator_unittest_SOURCES_DIST) \ + $(am__src_processor_proc_maps_linux_unittest_SOURCES_DIST) \ + $(am__src_processor_range_map_shrink_down_unittest_SOURCES_DIST) \ + $(am__src_processor_range_map_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_address_list_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_amd64_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_arm64_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_arm_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_mips64_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_mips_unittest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_selftest_SOURCES_DIST) \ + $(am__src_processor_stackwalker_x86_unittest_SOURCES_DIST) \ + $(am__src_processor_static_address_map_unittest_SOURCES_DIST) \ + $(am__src_processor_static_contained_range_map_unittest_SOURCES_DIST) \ + $(am__src_processor_static_map_unittest_SOURCES_DIST) \ + $(am__src_processor_static_range_map_unittest_SOURCES_DIST) \ + $(am__src_processor_synth_minidump_unittest_SOURCES_DIST) \ + $(am__src_tools_linux_core2md_core2md_SOURCES_DIST) \ + $(am__src_tools_linux_dump_syms_dump_syms_SOURCES_DIST) \ + $(am__src_tools_linux_md2core_minidump_2_core_SOURCES_DIST) \ + $(am__src_tools_linux_md2core_minidump_2_core_unittest_SOURCES_DIST) \ + $(am__src_tools_linux_symupload_minidump_upload_SOURCES_DIST) \ + $(am__src_tools_linux_symupload_sym_upload_SOURCES_DIST) \ + $(am__src_tools_mac_dump_syms_dump_syms_mac_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(dist_doc_DATA) $(pkgconfig_DATA) +am__includecl_HEADERS_DIST = $(top_srcdir)/src/common/linux/*.h +am__includeclc_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/crash_generation/*.h +am__includecldwc_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/dump_writer_common/*.h +am__includeclh_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/handler/*.h +am__includeclm_HEADERS_DIST = \ + $(top_srcdir)/src/client/linux/minidump_writer/*.h +am__includelss_HEADERS_DIST = $(top_srcdir)/src/third_party/lss/*.h +HEADERS = $(includec_HEADERS) $(includecl_HEADERS) \ + $(includeclc_HEADERS) $(includecldwc_HEADERS) \ + $(includeclh_HEADERS) $(includeclm_HEADERS) \ + $(includegbc_HEADERS) $(includelss_HEADERS) \ + $(includep_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +AM_RECURSIVE_TARGETS = cscope check recheck +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/autotools/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(srcdir)/breakpad-client.pc.in $(srcdir)/breakpad.pc.in \ + $(top_srcdir)/autotools/ar-lib $(top_srcdir)/autotools/compile \ + $(top_srcdir)/autotools/config.guess \ + $(top_srcdir)/autotools/config.sub \ + $(top_srcdir)/autotools/depcomp \ + $(top_srcdir)/autotools/install-sh \ + $(top_srcdir)/autotools/missing \ + $(top_srcdir)/autotools/test-driver \ + $(top_srcdir)/src/config.h.in AUTHORS ChangeLog INSTALL NEWS \ + autotools/ar-lib autotools/compile autotools/config.guess \ + autotools/config.sub autotools/depcomp autotools/install-sh \ + autotools/ltmain.sh autotools/missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GMOCK_CFLAGS = @GMOCK_CFLAGS@ +GMOCK_CONFIG = @GMOCK_CONFIG@ +GMOCK_LIBS = @GMOCK_LIBS@ +GREP = @GREP@ +GTEST_CFLAGS = @GTEST_CFLAGS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_LIBS = @GTEST_LIBS@ +HAVE_CXX11 = @HAVE_CXX11@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# This allows #includes to be relative to src/ +AM_CPPFLAGS = -I$(top_srcdir)/src +AM_CFLAGS = $(am__append_3) +AM_CXXFLAGS = $(am__append_1) $(am__append_2) $(am__append_4) + +# Specify include paths for ac macros +ACLOCAL_AMFLAGS = -I m4 + +# License file is called LICENSE not COPYING +AUTOMAKE_OPTIONS = foreign +dist_doc_DATA = \ + AUTHORS \ + ChangeLog \ + INSTALL \ + LICENSE \ + NEWS \ + README.md + +@LINUX_HOST_TRUE@includeclhdir = $(includedir)/$(PACKAGE)/client/linux/handler +@LINUX_HOST_TRUE@includeclh_HEADERS = $(top_srcdir)/src/client/linux/handler/*.h +@LINUX_HOST_TRUE@includecldwcdir = $(includedir)/$(PACKAGE)/client/linux/dump_writer_common +@LINUX_HOST_TRUE@includecldwc_HEADERS = $(top_srcdir)/src/client/linux/dump_writer_common/*.h +@LINUX_HOST_TRUE@includeclmdir = $(includedir)/$(PACKAGE)/client/linux/minidump_writer +@LINUX_HOST_TRUE@includeclm_HEADERS = $(top_srcdir)/src/client/linux/minidump_writer/*.h +@LINUX_HOST_TRUE@includeclcdir = $(includedir)/$(PACKAGE)/client/linux/crash_generation +@LINUX_HOST_TRUE@includeclc_HEADERS = $(top_srcdir)/src/client/linux/crash_generation/*.h +@LINUX_HOST_TRUE@includelssdir = $(includedir)/$(PACKAGE)/third_party/lss +@LINUX_HOST_TRUE@includelss_HEADERS = $(top_srcdir)/src/third_party/lss/*.h +@LINUX_HOST_TRUE@includecldir = $(includedir)/$(PACKAGE)/common/linux +@LINUX_HOST_TRUE@includecl_HEADERS = $(top_srcdir)/src/common/linux/*.h +includegbcdir = $(includedir)/$(PACKAGE)/google_breakpad/common +includegbc_HEADERS = $(top_srcdir)/src/google_breakpad/common/*.h +includecdir = $(includedir)/$(PACKAGE)/common +includec_HEADERS = $(top_srcdir)/src/common/*.h +includepdir = $(includedir)/$(PACKAGE)/processor +includep_HEADERS = $(top_srcdir)/src/processor/*.h +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(am__append_6) $(am__append_9) +@SYSTEM_TEST_LIBS_FALSE@TEST_CFLAGS = \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/include \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/gtest/include \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing/gtest \ +@SYSTEM_TEST_LIBS_FALSE@ -I$(top_srcdir)/src/testing + +@SYSTEM_TEST_LIBS_TRUE@TEST_CFLAGS = $(GTEST_CFLAGS) $(GMOCK_CFLAGS) +@SYSTEM_TEST_LIBS_FALSE@TEST_LIBS = src/testing/libtesting.a +@SYSTEM_TEST_LIBS_TRUE@TEST_LIBS = $(GTEST_LIBS) -lgtest_main $(GMOCK_LIBS) +@SYSTEM_TEST_LIBS_FALSE@TEST_DEPS = $(TEST_LIBS) +@SYSTEM_TEST_LIBS_TRUE@TEST_DEPS = +check_LIBRARIES = src/testing/libtesting.a +noinst_LIBRARIES = $(am__append_7) +lib_LIBRARIES = $(am__append_5) $(am__append_8) +CLEANFILES = $(am__append_13) +@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_SOURCES = \ +@SYSTEM_TEST_LIBS_FALSE@ src/breakpad_googletest_includes.h \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/gtest/src/gtest-all.cc \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/gtest/src/gtest_main.cc \ +@SYSTEM_TEST_LIBS_FALSE@ src/testing/src/gmock-all.cc + +@SYSTEM_TEST_LIBS_FALSE@src_testing_libtesting_a_CPPFLAGS = \ +@SYSTEM_TEST_LIBS_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@LINUX_HOST_TRUE@src_client_linux_libbreakpad_client_a_SOURCES = src/client/linux/crash_generation/crash_generation_client.cc \ +@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_server.cc \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.cc \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.cc \ +@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.cc \ +@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.h \ +@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.cc \ +@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.h \ +@LINUX_HOST_TRUE@ src/client/linux/log/log.cc \ +@LINUX_HOST_TRUE@ src/client/linux/log/log.h \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.cc \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.h \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.cc \ +@LINUX_HOST_TRUE@ src/client/minidump_file_writer-inl.h \ +@LINUX_HOST_TRUE@ src/client/minidump_file_writer.cc \ +@LINUX_HOST_TRUE@ src/client/minidump_file_writer.h \ +@LINUX_HOST_TRUE@ src/common/convert_UTF.c \ +@LINUX_HOST_TRUE@ src/common/convert_UTF.h src/common/md5.cc \ +@LINUX_HOST_TRUE@ src/common/md5.h \ +@LINUX_HOST_TRUE@ src/common/string_conversion.cc \ +@LINUX_HOST_TRUE@ src/common/string_conversion.h \ +@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ +@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ +@LINUX_HOST_TRUE@ src/common/linux/elfutils.h \ +@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ +@LINUX_HOST_TRUE@ src/common/linux/file_id.h \ +@LINUX_HOST_TRUE@ src/common/linux/guid_creator.cc \ +@LINUX_HOST_TRUE@ src/common/linux/guid_creator.h \ +@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ +@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ +@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ +@LINUX_HOST_TRUE@ $(am__append_10) +@DISABLE_PROCESSOR_FALSE@src_libbreakpad_a_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/breakpad_types.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/minidump_format.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/common/minidump_size.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/basic_source_line_resolver.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/call_stack.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/code_module.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/code_modules.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/dump_context.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/dump_object.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/exploitability.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/fast_source_line_resolver.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/memory_region.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/microdump_processor.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/minidump_processor.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/process_result.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/process_state.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/proc_maps_linux.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_base.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/source_line_resolver_interface.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_cpu.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stack_frame_symbolizer.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/stackwalker.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/symbol_supplier.h \ +@DISABLE_PROCESSOR_FALSE@ src/google_breakpad/processor/system_info.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/address_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/address_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_module.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_types.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_types.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/linked_ptr.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_factory.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_serializer-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_serializer.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/windows_frame_info.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base_types.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_iterator-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_iterator.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map-inl.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.h + +@DISABLE_PROCESSOR_FALSE@src_third_party_libdisasm_libdisasm_a_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_implicit.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_implicit.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_insn.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_invariant.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_modrm.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_opcode_tables.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_operand.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_reg.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/ia32_settings.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdis.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/qword.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_disasm.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_format.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_imm.h \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_insn.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_misc.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.c \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/x86_operand_list.h + +@DISABLE_PROCESSOR_FALSE@check_SCRIPTS = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk_machine_readable_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_test \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk_machine_readable_test + +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +# The default Autotools test driver script. +@ANDROID_HOST_FALSE@LOG_DRIVER = $(top_srcdir)/autotools/test-driver + +# Since Autotools 1.2, tests are run through a special "test driver" script. +# Unfortunately, it's not possible anymore to specify an alternative shell to +# run them on connected devices, so use a slightly modified version of the +# driver for Android. +@ANDROID_HOST_TRUE@LOG_DRIVER = $(top_srcdir)/android/test-driver +@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_SOURCES = \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc + +@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_LDFLAGS = $(PTHREAD_CFLAGS) +@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CC = $(PTHREAD_CC) +@ANDROID_HOST_FALSE@@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(PTHREAD_CFLAGS) +# On Android PTHREAD_CFLAGS is empty, and adding src/common/android/include +# to the include path is necessary to build this program. +@ANDROID_HOST_TRUE@@LINUX_HOST_TRUE@src_client_linux_linux_dumper_unittest_helper_CXXFLAGS = $(AM_CXXFLAGS) +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_SOURCES = \ +@LINUX_HOST_TRUE@ $(src_testing_libtesting_a_SOURCES) \ +@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/directory_reader_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/cpu_set_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/line_reader_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_core_dumper_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer_unittest.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc \ +@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ +@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support_unittest.cc \ +@LINUX_HOST_TRUE@ src/common/linux/tests/auto_testfile.h \ +@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.cc \ +@LINUX_HOST_TRUE@ src/common/memory_allocator_unittest.cc \ +@LINUX_HOST_TRUE@ src/common/tests/auto_tempdir.h \ +@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc \ +@LINUX_HOST_TRUE@ src/common/tests/file_utils.h \ +@LINUX_HOST_TRUE@ src/processor/basic_code_modules.cc \ +@LINUX_HOST_TRUE@ src/processor/dump_context.cc \ +@LINUX_HOST_TRUE@ src/processor/dump_object.cc \ +@LINUX_HOST_TRUE@ src/processor/logging.cc \ +@LINUX_HOST_TRUE@ src/processor/minidump.cc \ +@LINUX_HOST_TRUE@ src/processor/pathname_stripper.cc \ +@LINUX_HOST_TRUE@ src/processor/proc_maps_linux.cc \ +@LINUX_HOST_TRUE@ $(am__append_21) \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer_unittest.cc \ +@LINUX_HOST_TRUE@ $(am__append_22) +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_CPPFLAGS = \ +@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDFLAGS = \ +@LINUX_HOST_TRUE@ -shared -Wl,-h,linux_client_unittest_shlib \ +@LINUX_HOST_TRUE@ $(am__append_23) +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_LDADD = \ +@LINUX_HOST_TRUE@ src/client/linux/crash_generation/crash_generation_client.o \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/thread_info.o \ +@LINUX_HOST_TRUE@ src/client/linux/dump_writer_common/ucontext_reader.o \ +@LINUX_HOST_TRUE@ src/client/linux/handler/exception_handler.o \ +@LINUX_HOST_TRUE@ src/client/linux/handler/minidump_descriptor.o \ +@LINUX_HOST_TRUE@ src/client/linux/log/log.o \ +@LINUX_HOST_TRUE@ src/client/linux/microdump_writer/microdump_writer.o \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_dumper.o \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/linux_ptrace_dumper.o \ +@LINUX_HOST_TRUE@ src/client/linux/minidump_writer/minidump_writer.o \ +@LINUX_HOST_TRUE@ src/client/minidump_file_writer.o \ +@LINUX_HOST_TRUE@ src/common/convert_UTF.o \ +@LINUX_HOST_TRUE@ src/common/md5.o \ +@LINUX_HOST_TRUE@ src/common/linux/elfutils.o \ +@LINUX_HOST_TRUE@ src/common/linux/file_id.o \ +@LINUX_HOST_TRUE@ src/common/linux/guid_creator.o \ +@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.o \ +@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.o \ +@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.o \ +@LINUX_HOST_TRUE@ src/common/string_conversion.o \ +@LINUX_HOST_TRUE@ $(TEST_LIBS) \ +@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_shlib_DEPENDENCIES = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_dumper_unittest_helper \ +@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a \ +@LINUX_HOST_TRUE@ $(TEST_DEPS) \ +@LINUX_HOST_TRUE@ src/libbreakpad.a + +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_SOURCES = +# The extra-long build id is for a test in minidump_writer_unittest.cc. +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDFLAGS = \ +@LINUX_HOST_TRUE@ -Wl,-rpath,'$$ORIGIN' \ +@LINUX_HOST_TRUE@ -Wl,--build-id=0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \ +@LINUX_HOST_TRUE@ $(am__append_24) +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_LDADD = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib \ +@LINUX_HOST_TRUE@ $(TEST_LIBS) + +@LINUX_HOST_TRUE@src_client_linux_linux_client_unittest_DEPENDENCIES = \ +@LINUX_HOST_TRUE@ src/client/linux/linux_client_unittest_shlib + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/core2md/core2md.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_core2md_core2md_LDADD = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/client/linux/libbreakpad_client.a + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_dump_syms_dump_syms_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/dump_syms/dump_syms.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump-2-core.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_memory_range.h + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_minidump_upload_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/minidump_upload.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_minidump_upload_LDADD = -ldl +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_sym_upload_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/http_upload.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/symbol_upload.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/linux/symupload/sym_upload.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_linux_symupload_sym_upload_LDADD = -ldl +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/md5.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/dump_syms.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/dump_syms.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/tools/mac/dump_syms/dump_syms_tool.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -I$(top_srcdir)/src/third_party/mac_headers \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -DHAVE_MACH_O_NLIST_H + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/byte_cursor_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/memory_range_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/test_assembler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader-inl.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_cfi_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_die_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_test_common.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/crc32.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_core_dump_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elfutils.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/linux_libc_support.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/memory_mapped_file_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/safe_readlink_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/tests/crash_generator.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/testdata/func-line-pairing.h \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_CPPFLAGS = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_dumper_unittest_LDADD = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(TEST_LIBS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_SOURCES = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cfi_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_cu_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf_line_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/language.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/md5.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/stabs_to_module.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/test_assembler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/bytereader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/cfi_assembler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2diehandler.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/elf_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/arch_utilities.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/file_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_id.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_reader_unittest.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_utilities.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/mac/macho_walker.cc \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/tests/file_utils.cc + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_CPPFLAGS = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -I$(top_srcdir)/src/third_party/mac_headers \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ -DHAVE_MACH_O_NLIST_H \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) + +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@src_common_mac_macho_reader_unittest_LDADD = \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(TEST_LIBS) \ +@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_SOURCES = \ +@LINUX_HOST_TRUE@ src/tools/linux/md2core/minidump_memory_range_unittest.cc + +@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS = \ +@LINUX_HOST_TRUE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@LINUX_HOST_TRUE@src_tools_linux_md2core_minidump_2_core_unittest_LDADD = \ +@LINUX_HOST_TRUE@ $(TEST_LIBS) \ +@LINUX_HOST_TRUE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/address_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_address_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o + +@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_basic_source_line_resolver_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_cfi_frame_info_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/contained_range_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_contained_range_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o + +@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_exploitability_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_disassembler_x86_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_fast_source_line_resolver_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/fast_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_comparer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/module_serializer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/map_serializers_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_map_serializers_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_processor_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_processor_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_unittest.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_proc_maps_linux_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_address_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_address_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_contained_range_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_contained_range_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/static_range_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_static_range_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_pathname_stripper_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/postfix_evaluator_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_postfix_evaluator_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_shrink_down_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_shrink_down_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_shrink_down_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_shrink_down_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/range_map_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_range_map_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_selftest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_selftest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_amd64_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_arm64_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_address_list_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips64_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_mips64_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/libbreakpad.a \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_processor_stackwalker_x86_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.h \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump_unittest.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.cc \ +@DISABLE_PROCESSOR_FALSE@ src/processor/synth_minidump.h + +@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_processor_synth_minidump_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.cc \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler.h \ +@DISABLE_PROCESSOR_FALSE@ src/common/test_assembler_unittest.cc + +@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_CPPFLAGS = \ +@DISABLE_PROCESSOR_FALSE@ $(AM_CPPFLAGS) $(TEST_CFLAGS) + +@DISABLE_PROCESSOR_FALSE@src_common_test_assembler_unittest_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ $(TEST_LIBS) \ +@DISABLE_PROCESSOR_FALSE@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) + +@DISABLE_PROCESSOR_FALSE@noinst_SCRIPTS = $(check_SCRIPTS) +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_dump.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_dump_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o + +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_stackwalk.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_microdump_stackwalk_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/microdump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_SOURCES = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_stackwalk.cc + +@DISABLE_PROCESSOR_FALSE@src_processor_minidump_stackwalk_LDADD = \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_code_modules.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/basic_source_line_resolver.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/call_stack.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/cfi_frame_info.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/disassembler_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_context.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/dump_object.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/exploitability_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/logging.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/minidump_processor.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/pathname_stripper.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/process_state.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/proc_maps_linux.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/simple_symbol_supplier.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/source_line_resolver_base.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_cpu.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stack_frame_symbolizer.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalk_common.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_address_list.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_amd64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_arm64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_mips.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_ppc64.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_sparc.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/stackwalker_x86.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/symbolic_constants_win.o \ +@DISABLE_PROCESSOR_FALSE@ src/processor/tokenize.o \ +@DISABLE_PROCESSOR_FALSE@ src/third_party/libdisasm/libdisasm.a + +EXTRA_DIST = \ + $(SCRIPTS) \ + src/client/linux/data/linux-gate-amd.sym \ + src/client/linux/data/linux-gate-intel.sym \ + src/client/mac/handler/breakpad_nlist_64.cc \ + src/client/mac/handler/breakpad_nlist_64.h \ + src/client/mac/handler/dynamic_images.cc \ + src/client/mac/handler/dynamic_images.h \ + src/client/mac/handler/exception_handler.cc \ + src/client/mac/handler/exception_handler.h \ + src/client/mac/handler/mach_vm_compat.h \ + src/client/mac/handler/minidump_generator.cc \ + src/client/mac/handler/minidump_generator.h \ + src/client/mac/handler/minidump_test.xcodeproj/project.pbxproj \ + src/client/mac/handler/minidump_tests32-Info.plist \ + src/client/mac/handler/minidump_tests64-Info.plist \ + src/client/mac/handler/obj-cTestCases-Info.plist \ + src/client/mac/handler/protected_memory_allocator.cc \ + src/client/mac/handler/protected_memory_allocator.h \ + src/client/mac/handler/ucontext_compat.h \ + src/client/mac/handler/testcases/testdata/dump_syms_i386_breakpad.sym \ + src/client/mac/tests/BreakpadFramework_Test.mm \ + src/client/mac/tests/crash_generation_server_test.cc \ + src/client/mac/tests/exception_handler_test.cc \ + src/client/mac/tests/minidump_generator_test.cc \ + src/client/mac/tests/minidump_generator_test_helper.cc \ + src/client/mac/tests/spawn_child_process.h \ + src/client/mac/tests/testlogging.h \ + src/client/minidump_file_writer_unittest.cc \ + src/client/solaris/handler/Makefile \ + src/client/solaris/handler/exception_handler.cc \ + src/client/solaris/handler/exception_handler.h \ + src/client/solaris/handler/exception_handler_test.cc \ + src/client/solaris/handler/minidump_generator.cc \ + src/client/solaris/handler/minidump_generator.h \ + src/client/solaris/handler/minidump_test.cc \ + src/client/solaris/handler/solaris_lwp.cc \ + src/client/solaris/handler/solaris_lwp.h \ + src/client/windows/breakpad_client.gyp \ + src/client/windows/handler/exception_handler.cc \ + src/client/windows/handler/exception_handler.h \ + src/client/windows/handler/exception_handler.gyp \ + src/client/windows/sender/crash_report_sender.cc \ + src/client/windows/sender/crash_report_sender.h \ + src/client/windows/sender/crash_report_sender.gyp \ + src/common/dwarf/dwarf2diehandler.h \ + src/common/dwarf/dwarf2enums.h \ + src/common/dwarf/line_state_machine.h \ + src/common/dwarf/types.h \ + src/common/mac/arch_utilities.h \ + src/common/mac/byteswap.h \ + src/common/mac/HTTPMultipartUpload.h \ + src/common/mac/HTTPMultipartUpload.m \ + src/common/mac/string_utilities.cc \ + src/common/mac/string_utilities.h \ + src/common/mac/super_fat_arch.h \ + src/common/scoped_ptr.h \ + src/common/solaris/dump_symbols.cc \ + src/common/solaris/dump_symbols.h \ + src/common/solaris/file_id.cc \ + src/common/solaris/file_id.h \ + src/common/solaris/guid_creator.cc \ + src/common/solaris/guid_creator.h \ + src/common/solaris/message_output.h \ + src/common/windows/guid_string.cc \ + src/common/windows/guid_string.h \ + src/common/windows/http_upload.cc \ + src/common/windows/http_upload.h \ + src/common/windows/pdb_source_line_writer.cc \ + src/common/windows/pdb_source_line_writer.h \ + src/common/windows/string_utils-inl.h \ + src/common/windows/string_utils.cc \ + src/processor/stackwalk_common.cc \ + src/processor/stackwalk_common.h \ + src/processor/stackwalker_selftest_sol.s \ + src/processor/testdata/ascii_read_av_block_write.dmp \ + src/processor/testdata/ascii_read_av_clobber_write.dmp \ + src/processor/testdata/ascii_read_av_conditional.dmp \ + src/processor/testdata/ascii_read_av.dmp \ + src/processor/testdata/ascii_read_av_then_jmp.dmp \ + src/processor/testdata/ascii_read_av_xchg_write.dmp \ + src/processor/testdata/ascii_write_av_arg_to_call.dmp \ + src/processor/testdata/ascii_write_av.dmp \ + src/processor/testdata/exec_av_on_stack.dmp \ + src/processor/testdata/linux_divide_by_zero.dmp \ + src/processor/testdata/linux_executable_heap.dmp \ + src/processor/testdata/linux_executable_stack.dmp \ + src/processor/testdata/linux_inside_module_exe_region1.dmp \ + src/processor/testdata/linux_inside_module_exe_region2.dmp \ + src/processor/testdata/linux_jmp_to_0.dmp \ + src/processor/testdata/linux_jmp_to_module_not_exe_region.dmp \ + src/processor/testdata/linux_null_dereference.dmp \ + src/processor/testdata/linux_null_read_av.dmp \ + src/processor/testdata/linux_outside_module.dmp \ + src/processor/testdata/linux_overflow.dmp \ + src/processor/testdata/linux_raise_sigabrt.dmp \ + src/processor/testdata/linux_stack_pointer_in_module.dmp \ + src/processor/testdata/linux_stack_pointer_in_stack.dmp \ + src/processor/testdata/linux_stacksmash.dmp \ + src/processor/testdata/linux_write_to_nonwritable_module.dmp \ + src/processor/testdata/linux_write_to_nonwritable_region_math.dmp \ + src/processor/testdata/linux_write_to_outside_module.dmp \ + src/processor/testdata/linux_write_to_outside_module_via_math.dmp \ + src/processor/testdata/linux_write_to_under_4k.dmp \ + src/processor/testdata/microdump-arm64.dmp \ + src/processor/testdata/microdump-arm.dmp \ + src/processor/testdata/microdump-mips32.dmp \ + src/processor/testdata/microdump-mips64.dmp \ + src/processor/testdata/microdump-multiple.dmp \ + src/processor/testdata/microdump.stackwalk-arm64.out \ + src/processor/testdata/microdump.stackwalk-arm.out \ + src/processor/testdata/microdump.stackwalk.machine_readable-arm64.out \ + src/processor/testdata/microdump.stackwalk.machine_readable-arm.out \ + src/processor/testdata/microdump-x86.dmp \ + src/processor/testdata/minidump2.dmp \ + src/processor/testdata/minidump2.dump.out \ + src/processor/testdata/minidump2.stackwalk.machine_readable.out \ + src/processor/testdata/minidump2.stackwalk.out \ + src/processor/testdata/module0.out \ + src/processor/testdata/module1.out \ + src/processor/testdata/module2.out \ + src/processor/testdata/module3_bad.out \ + src/processor/testdata/module4_bad.out \ + src/processor/testdata/null_read_av.dmp \ + src/processor/testdata/null_write_av.dmp \ + src/processor/testdata/read_av_clobber_write.dmp \ + src/processor/testdata/read_av_conditional.dmp \ + src/processor/testdata/read_av_non_null.dmp \ + src/processor/testdata/stack_exhaustion.dmp \ + src/processor/testdata/write_av_non_null.dmp \ + src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym \ + src/processor/testdata/symbols/ld-2.13.so/C32AD7E235EA6112E02A5B9D6219C4850/ld-2.13.so.sym \ + src/processor/testdata/symbols/libc-2.13.so/F4F8DFCD5A5FB5A7CE64717E9E6AE3890/libc-2.13.so.sym \ + src/processor/testdata/symbols/libgcc_s.so.1/18B180F90887D8F8B5C35D185444AF4C0/libgcc_s.so.1.sym \ + src/processor/testdata/symbols/microdump/breakpad_unittests/D6D1FEC9A15DE7F38A236898871A2E770/breakpad_unittests.sym \ + src/processor/testdata/symbols/microdump/breakpad_unittests/DA7778FB66018A4E9B4110ED06E730D00/breakpad_unittests.sym \ + src/processor/testdata/symbols/microdump/crash_example/6E72E2F1A5F59AB3D51356FDFE394D490/crash_example.sym \ + src/processor/testdata/symbols/microdump/crash_example/8F36148CC4647A8116CAF2A25F591F570/crash_example.sym \ + src/processor/testdata/symbols/null_read_av/7B7D1968FF0D47AE4366E9C3A7E1B6750/null_read_av.sym \ + src/processor/testdata/symbols/overflow/B0E1FC01EF48E39CAF5C881D2DF0C3840/overflow.sym \ + src/processor/testdata/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym \ + src/processor/testdata/test_app.cc \ + src/testing/gtest/include/gtest/gtest.h \ + src/testing/gtest/include/gtest/gtest-death-test.h \ + src/testing/gtest/include/gtest/gtest-message.h \ + src/testing/gtest/include/gtest/gtest-param-test.h \ + src/testing/gtest/include/gtest/gtest-printers.h \ + src/testing/gtest/include/gtest/gtest-spi.h \ + src/testing/gtest/include/gtest/gtest-test-part.h \ + src/testing/gtest/include/gtest/gtest-typed-test.h \ + src/testing/gtest/include/gtest/gtest_pred_impl.h \ + src/testing/gtest/include/gtest/gtest_prod.h \ + src/testing/gtest/include/gtest/internal/gtest-death-test-internal.h \ + src/testing/gtest/include/gtest/internal/gtest-filepath.h \ + src/testing/gtest/include/gtest/internal/gtest-internal.h \ + src/testing/gtest/include/gtest/internal/gtest-linked_ptr.h \ + src/testing/gtest/include/gtest/internal/gtest-param-util-generated.h \ + src/testing/gtest/include/gtest/internal/gtest-param-util.h \ + src/testing/gtest/include/gtest/internal/gtest-port.h \ + src/testing/gtest/include/gtest/internal/gtest-string.h \ + src/testing/gtest/include/gtest/internal/gtest-tuple.h \ + src/testing/gtest/include/gtest/internal/gtest-type-util.h \ + src/testing/gtest/src/gtest.cc \ + src/testing/gtest/src/gtest-death-test.cc \ + src/testing/gtest/src/gtest-filepath.cc \ + src/testing/gtest/src/gtest-internal-inl.h \ + src/testing/gtest/src/gtest-port.cc \ + src/testing/gtest/src/gtest-printers.cc \ + src/testing/gtest/src/gtest-test-part.cc \ + src/testing/gtest/src/gtest-typed-test.cc \ + src/testing/include/gmock/gmock.h \ + src/testing/include/gmock/gmock-actions.h \ + src/testing/include/gmock/gmock-cardinalities.h \ + src/testing/include/gmock/gmock-generated-actions.h \ + src/testing/include/gmock/gmock-generated-function-mockers.h \ + src/testing/include/gmock/gmock-generated-matchers.h \ + src/testing/include/gmock/gmock-generated-nice-strict.h \ + src/testing/include/gmock/gmock-matchers.h \ + src/testing/include/gmock/gmock-more-actions.h \ + src/testing/include/gmock/gmock-more-matchers.h \ + src/testing/include/gmock/gmock-spec-builders.h \ + src/testing/include/gmock/internal/gmock-generated-internal-utils.h \ + src/testing/include/gmock/internal/gmock-internal-utils.h \ + src/testing/include/gmock/internal/gmock-port.h \ + src/testing/src/gmock.cc \ + src/testing/src/gmock-cardinalities.cc \ + src/testing/src/gmock-internal-utils.cc \ + src/testing/src/gmock-matchers.cc \ + src/testing/src/gmock-spec-builders.cc \ + src/testing/src/gmock_main.cc \ + src/third_party/curl/COPYING \ + src/third_party/curl/curlbuild.h \ + src/third_party/curl/curl.h \ + src/third_party/curl/curlrules.h \ + src/third_party/curl/curlver.h \ + src/third_party/curl/easy.h \ + src/third_party/curl/mprintf.h \ + src/third_party/curl/multi.h \ + src/third_party/curl/stdcheaders.h \ + src/third_party/curl/typecheck-gcc.h \ + src/third_party/curl/types.h \ + src/third_party/mac_headers/architecture/byte_order.h \ + src/third_party/mac_headers/i386/_types.h \ + src/third_party/mac_headers/mach/boolean.h \ + src/third_party/mac_headers/mach/i386/boolean.h \ + src/third_party/mac_headers/mach/i386/vm_param.h \ + src/third_party/mac_headers/mach/i386/vm_types.h \ + src/third_party/mac_headers/mach/machine/boolean.h \ + src/third_party/mac_headers/mach/machine.h \ + src/third_party/mac_headers/mach/machine/thread_state.h \ + src/third_party/mac_headers/mach/machine/thread_status.h \ + src/third_party/mac_headers/mach/machine/vm_types.h \ + src/third_party/mac_headers/mach-o/arch.h \ + src/third_party/mac_headers/mach-o/fat.h \ + src/third_party/mac_headers/mach-o/loader.h \ + src/third_party/mac_headers/mach-o/nlist.h \ + src/third_party/mac_headers/mach/thread_status.h \ + src/third_party/mac_headers/mach/vm_prot.h \ + src/third_party/mac_headers/README \ + src/third_party/musl/README \ + src/third_party/musl/COPYRIGHT \ + src/third_party/musl/README.breakpad \ + src/third_party/musl/VERSION \ + src/third_party/musl/include/elf.h \ + src/tools/mac/crash_report/crash_report.mm \ + src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj \ + src/tools/mac/crash_report/on_demand_symbol_supplier.h \ + src/tools/mac/crash_report/on_demand_symbol_supplier.mm \ + src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj \ + src/tools/mac/dump_syms/dump_syms_tool.cc \ + src/tools/mac/symupload/minidump_upload.m \ + src/tools/mac/symupload/symupload.m \ + src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj \ + src/tools/solaris/dump_syms/Makefile \ + src/tools/solaris/dump_syms/dump_syms.cc \ + src/tools/solaris/dump_syms/run_regtest.sh \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs \ + src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym \ + src/tools/windows/converter/ms_symbol_server_converter.cc \ + src/tools/windows/converter/ms_symbol_server_converter.h \ + src/tools/windows/converter/ms_symbol_server_converter.gyp \ + src/tools/windows/dump_syms/dump_syms.cc \ + src/tools/windows/dump_syms/dump_syms.gyp \ + src/tools/windows/dump_syms/run_regtest.sh \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.cc \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest.sym \ + src/tools/windows/dump_syms/testdata/dump_syms_regtest64.sym \ + src/tools/windows/dump_syms/testdata/omap_reorder_bbs.sym \ + src/tools/windows/dump_syms/testdata/omap_reorder_funcs.sym \ + src/tools/windows/dump_syms/testdata/omap_stretched.sym \ + src/tools/windows/dump_syms/testdata/omap_stretched_filled.sym \ + src/tools/windows/symupload/symupload.cc \ + src/tools/windows/symupload/symupload.gyp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .S .c .cc .log .o .obj .test .test$(EXEEXT) .trs +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +src/config.h: src/stamp-h1 + @test -f $@ || rm -f src/stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) src/stamp-h1 + +src/stamp-h1: $(top_srcdir)/src/config.h.in $(top_builddir)/config.status + @rm -f src/stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status src/config.h +$(top_srcdir)/src/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f src/stamp-h1 + touch $@ + +distclean-hdr: + -rm -f src/config.h src/stamp-h1 +breakpad.pc: $(top_builddir)/config.status $(srcdir)/breakpad.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +breakpad-client.pc: $(top_builddir)/config.status $(srcdir)/breakpad-client.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-checkLIBRARIES: + -test -z "$(check_LIBRARIES)" || rm -f $(check_LIBRARIES) +install-libLIBRARIES: $(lib_LIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(INSTALL_DATA) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(INSTALL_DATA) $$list2 "$(DESTDIR)$(libdir)" || exit $$?; } + @$(POST_INSTALL) + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + if test -f $$p; then \ + $(am__strip_dir) \ + echo " ( cd '$(DESTDIR)$(libdir)' && $(RANLIB) $$f )"; \ + ( cd "$(DESTDIR)$(libdir)" && $(RANLIB) $$f ) || exit $$?; \ + else :; fi; \ + done + +uninstall-libLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LIBRARIES)'; test -n "$(libdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(libdir)'; $(am__uninstall_files_from_dir) + +clean-libLIBRARIES: + -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +src/client/linux/crash_generation/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/crash_generation + @: > src/client/linux/crash_generation/$(am__dirstamp) +src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/crash_generation/$(DEPDIR) + @: > src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) +src/client/linux/crash_generation/crash_generation_client.$(OBJEXT): \ + src/client/linux/crash_generation/$(am__dirstamp) \ + src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) +src/client/linux/crash_generation/crash_generation_server.$(OBJEXT): \ + src/client/linux/crash_generation/$(am__dirstamp) \ + src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/dump_writer_common + @: > src/client/linux/dump_writer_common/$(am__dirstamp) +src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/dump_writer_common/$(DEPDIR) + @: > src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/thread_info.$(OBJEXT): \ + src/client/linux/dump_writer_common/$(am__dirstamp) \ + src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/dump_writer_common/ucontext_reader.$(OBJEXT): \ + src/client/linux/dump_writer_common/$(am__dirstamp) \ + src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) +src/client/linux/handler/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/handler + @: > src/client/linux/handler/$(am__dirstamp) +src/client/linux/handler/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/handler/$(DEPDIR) + @: > src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) +src/client/linux/handler/exception_handler.$(OBJEXT): \ + src/client/linux/handler/$(am__dirstamp) \ + src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) +src/client/linux/handler/minidump_descriptor.$(OBJEXT): \ + src/client/linux/handler/$(am__dirstamp) \ + src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) +src/client/linux/log/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/log + @: > src/client/linux/log/$(am__dirstamp) +src/client/linux/log/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/log/$(DEPDIR) + @: > src/client/linux/log/$(DEPDIR)/$(am__dirstamp) +src/client/linux/log/log.$(OBJEXT): \ + src/client/linux/log/$(am__dirstamp) \ + src/client/linux/log/$(DEPDIR)/$(am__dirstamp) +src/client/linux/microdump_writer/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/microdump_writer + @: > src/client/linux/microdump_writer/$(am__dirstamp) +src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/microdump_writer/$(DEPDIR) + @: > src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/microdump_writer/microdump_writer.$(OBJEXT): \ + src/client/linux/microdump_writer/$(am__dirstamp) \ + src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/minidump_writer + @: > src/client/linux/minidump_writer/$(am__dirstamp) +src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/linux/minidump_writer/$(DEPDIR) + @: > src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/linux_core_dumper.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/linux_dumper.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/linux_ptrace_dumper.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/minidump_writer.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/$(am__dirstamp): + @$(MKDIR_P) src/client + @: > src/client/$(am__dirstamp) +src/client/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/client/$(DEPDIR) + @: > src/client/$(DEPDIR)/$(am__dirstamp) +src/client/minidump_file_writer.$(OBJEXT): src/client/$(am__dirstamp) \ + src/client/$(DEPDIR)/$(am__dirstamp) +src/common/$(am__dirstamp): + @$(MKDIR_P) src/common + @: > src/common/$(am__dirstamp) +src/common/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/$(DEPDIR) + @: > src/common/$(DEPDIR)/$(am__dirstamp) +src/common/convert_UTF.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/md5.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/string_conversion.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/linux/$(am__dirstamp): + @$(MKDIR_P) src/common/linux + @: > src/common/linux/$(am__dirstamp) +src/common/linux/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/linux/$(DEPDIR) + @: > src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/elf_core_dump.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/elfutils.$(OBJEXT): src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/file_id.$(OBJEXT): src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/guid_creator.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/linux_libc_support.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/memory_mapped_file.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/safe_readlink.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/android/$(am__dirstamp): + @$(MKDIR_P) src/common/android + @: > src/common/android/$(am__dirstamp) +src/common/android/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/android/$(DEPDIR) + @: > src/common/android/$(DEPDIR)/$(am__dirstamp) +src/common/android/breakpad_getcontext.$(OBJEXT): \ + src/common/android/$(am__dirstamp) \ + src/common/android/$(DEPDIR)/$(am__dirstamp) +src/client/linux/$(am__dirstamp): + @$(MKDIR_P) src/client/linux + @: > src/client/linux/$(am__dirstamp) + +src/client/linux/libbreakpad_client.a: $(src_client_linux_libbreakpad_client_a_OBJECTS) $(src_client_linux_libbreakpad_client_a_DEPENDENCIES) $(EXTRA_src_client_linux_libbreakpad_client_a_DEPENDENCIES) src/client/linux/$(am__dirstamp) + $(AM_V_at)-rm -f src/client/linux/libbreakpad_client.a + $(AM_V_AR)$(src_client_linux_libbreakpad_client_a_AR) src/client/linux/libbreakpad_client.a $(src_client_linux_libbreakpad_client_a_OBJECTS) $(src_client_linux_libbreakpad_client_a_LIBADD) + $(AM_V_at)$(RANLIB) src/client/linux/libbreakpad_client.a +src/processor/$(am__dirstamp): + @$(MKDIR_P) src/processor + @: > src/processor/$(am__dirstamp) +src/processor/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/processor/$(DEPDIR) + @: > src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/basic_code_modules.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/basic_source_line_resolver.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/call_stack.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/cfi_frame_info.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/disassembler_x86.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/dump_context.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/dump_object.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/exploitability.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/exploitability_linux.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/exploitability_win.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/fast_source_line_resolver.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/logging.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/microdump.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/microdump_processor.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/minidump.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/minidump_processor.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/module_comparer.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/module_serializer.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/pathname_stripper.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/process_state.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/proc_maps_linux.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/simple_symbol_supplier.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/source_line_resolver_base.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stack_frame_cpu.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stack_frame_symbolizer.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_amd64.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_arm.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_arm64.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_address_list.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_mips.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_ppc.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_ppc64.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_sparc.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/stackwalker_x86.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/symbolic_constants_win.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/tokenize.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) + +src/libbreakpad.a: $(src_libbreakpad_a_OBJECTS) $(src_libbreakpad_a_DEPENDENCIES) $(EXTRA_src_libbreakpad_a_DEPENDENCIES) src/$(am__dirstamp) + $(AM_V_at)-rm -f src/libbreakpad.a + $(AM_V_AR)$(src_libbreakpad_a_AR) src/libbreakpad.a $(src_libbreakpad_a_OBJECTS) $(src_libbreakpad_a_LIBADD) + $(AM_V_at)$(RANLIB) src/libbreakpad.a +src/testing/gtest/src/$(am__dirstamp): + @$(MKDIR_P) src/testing/gtest/src + @: > src/testing/gtest/src/$(am__dirstamp) +src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/testing/gtest/src/$(DEPDIR) + @: > src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) +src/testing/gtest/src/src_testing_libtesting_a-gtest-all.$(OBJEXT): \ + src/testing/gtest/src/$(am__dirstamp) \ + src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) +src/testing/gtest/src/src_testing_libtesting_a-gtest_main.$(OBJEXT): \ + src/testing/gtest/src/$(am__dirstamp) \ + src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) +src/testing/src/$(am__dirstamp): + @$(MKDIR_P) src/testing/src + @: > src/testing/src/$(am__dirstamp) +src/testing/src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/testing/src/$(DEPDIR) + @: > src/testing/src/$(DEPDIR)/$(am__dirstamp) +src/testing/src/src_testing_libtesting_a-gmock-all.$(OBJEXT): \ + src/testing/src/$(am__dirstamp) \ + src/testing/src/$(DEPDIR)/$(am__dirstamp) +src/testing/$(am__dirstamp): + @$(MKDIR_P) src/testing + @: > src/testing/$(am__dirstamp) + +src/testing/libtesting.a: $(src_testing_libtesting_a_OBJECTS) $(src_testing_libtesting_a_DEPENDENCIES) $(EXTRA_src_testing_libtesting_a_DEPENDENCIES) src/testing/$(am__dirstamp) + $(AM_V_at)-rm -f src/testing/libtesting.a + $(AM_V_AR)$(src_testing_libtesting_a_AR) src/testing/libtesting.a $(src_testing_libtesting_a_OBJECTS) $(src_testing_libtesting_a_LIBADD) + $(AM_V_at)$(RANLIB) src/testing/libtesting.a +src/third_party/libdisasm/$(am__dirstamp): + @$(MKDIR_P) src/third_party/libdisasm + @: > src/third_party/libdisasm/$(am__dirstamp) +src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/third_party/libdisasm/$(DEPDIR) + @: > src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_implicit.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_insn.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_invariant.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_modrm.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_opcode_tables.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_operand.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_reg.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/ia32_settings.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_disasm.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_format.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_imm.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_insn.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_misc.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) +src/third_party/libdisasm/x86_operand_list.$(OBJEXT): \ + src/third_party/libdisasm/$(am__dirstamp) \ + src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) + +src/third_party/libdisasm/libdisasm.a: $(src_third_party_libdisasm_libdisasm_a_OBJECTS) $(src_third_party_libdisasm_libdisasm_a_DEPENDENCIES) $(EXTRA_src_third_party_libdisasm_libdisasm_a_DEPENDENCIES) src/third_party/libdisasm/$(am__dirstamp) + $(AM_V_at)-rm -f src/third_party/libdisasm/libdisasm.a + $(AM_V_AR)$(src_third_party_libdisasm_libdisasm_a_AR) src/third_party/libdisasm/libdisasm.a $(src_third_party_libdisasm_libdisasm_a_OBJECTS) $(src_third_party_libdisasm_libdisasm_a_LIBADD) + $(AM_V_at)$(RANLIB) src/third_party/libdisasm/libdisasm.a +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +src/client/linux/linux_client_unittest$(EXEEXT): $(src_client_linux_linux_client_unittest_OBJECTS) $(src_client_linux_linux_client_unittest_DEPENDENCIES) $(EXTRA_src_client_linux_linux_client_unittest_DEPENDENCIES) src/client/linux/$(am__dirstamp) + @rm -f src/client/linux/linux_client_unittest$(EXEEXT) + $(AM_V_CCLD)$(src_client_linux_linux_client_unittest_LINK) $(src_client_linux_linux_client_unittest_OBJECTS) $(src_client_linux_linux_client_unittest_LDADD) $(LIBS) +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.$(OBJEXT): \ + src/testing/gtest/src/$(am__dirstamp) \ + src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.$(OBJEXT): \ + src/testing/gtest/src/$(am__dirstamp) \ + src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) +src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.$(OBJEXT): \ + src/testing/src/$(am__dirstamp) \ + src/testing/src/$(DEPDIR)/$(am__dirstamp) +src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.$(OBJEXT): \ + src/client/linux/handler/$(am__dirstamp) \ + src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/tests/$(am__dirstamp): + @$(MKDIR_P) src/common/linux/tests + @: > src/common/linux/tests/$(am__dirstamp) +src/common/linux/tests/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/linux/tests/$(DEPDIR) + @: > src/common/linux/tests/$(DEPDIR)/$(am__dirstamp) +src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.$(OBJEXT): \ + src/common/linux/tests/$(am__dirstamp) \ + src/common/linux/tests/$(DEPDIR)/$(am__dirstamp) +src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/tests/$(am__dirstamp): + @$(MKDIR_P) src/common/tests + @: > src/common/tests/$(am__dirstamp) +src/common/tests/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/tests/$(DEPDIR) + @: > src/common/tests/$(DEPDIR)/$(am__dirstamp) +src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.$(OBJEXT): \ + src/common/tests/$(am__dirstamp) \ + src/common/tests/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-logging.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-minidump.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.$(OBJEXT): \ + src/common/android/$(am__dirstamp) \ + src/common/android/$(DEPDIR)/$(am__dirstamp) +src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.$(OBJEXT): \ + src/client/linux/microdump_writer/$(am__dirstamp) \ + src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp) +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.$(OBJEXT): \ + src/common/android/$(am__dirstamp) \ + src/common/android/$(DEPDIR)/$(am__dirstamp) + +src/client/linux/linux_client_unittest_shlib$(EXEEXT): $(src_client_linux_linux_client_unittest_shlib_OBJECTS) $(src_client_linux_linux_client_unittest_shlib_DEPENDENCIES) $(EXTRA_src_client_linux_linux_client_unittest_shlib_DEPENDENCIES) src/client/linux/$(am__dirstamp) + @rm -f src/client/linux/linux_client_unittest_shlib$(EXEEXT) + $(AM_V_CXXLD)$(src_client_linux_linux_client_unittest_shlib_LINK) $(src_client_linux_linux_client_unittest_shlib_OBJECTS) $(src_client_linux_linux_client_unittest_shlib_LDADD) $(LIBS) +src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.$(OBJEXT): \ + src/client/linux/minidump_writer/$(am__dirstamp) \ + src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) + +src/client/linux/linux_dumper_unittest_helper$(EXEEXT): $(src_client_linux_linux_dumper_unittest_helper_OBJECTS) $(src_client_linux_linux_dumper_unittest_helper_DEPENDENCIES) $(EXTRA_src_client_linux_linux_dumper_unittest_helper_DEPENDENCIES) src/client/linux/$(am__dirstamp) + @rm -f src/client/linux/linux_dumper_unittest_helper$(EXEEXT) + $(AM_V_CXXLD)$(src_client_linux_linux_dumper_unittest_helper_LINK) $(src_client_linux_linux_dumper_unittest_helper_OBJECTS) $(src_client_linux_linux_dumper_unittest_helper_LDADD) $(LIBS) +src/common/src_common_dumper_unittest-byte_cursor_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_cfi_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_cu_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_line_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-language.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-memory_range_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-module_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-stabs_reader.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-stabs_reader_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-stabs_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-stabs_to_module_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_dumper_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/$(am__dirstamp): + @$(MKDIR_P) src/common/dwarf + @: > src/common/dwarf/$(am__dirstamp) +src/common/dwarf/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/dwarf/$(DEPDIR) + @: > src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-bytereader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-cfi_assembler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-elf_reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-crc32.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-elf_core_dump.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-elfutils.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-file_id.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-file_id_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-linux_libc_support.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-memory_mapped_file.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-safe_readlink.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/tests/src_common_dumper_unittest-crash_generator.$(OBJEXT): \ + src/common/linux/tests/$(am__dirstamp) \ + src/common/linux/tests/$(DEPDIR)/$(am__dirstamp) +src/common/tests/src_common_dumper_unittest-file_utils.$(OBJEXT): \ + src/common/tests/$(am__dirstamp) \ + src/common/tests/$(DEPDIR)/$(am__dirstamp) + +src/common/dumper_unittest$(EXEEXT): $(src_common_dumper_unittest_OBJECTS) $(src_common_dumper_unittest_DEPENDENCIES) $(EXTRA_src_common_dumper_unittest_DEPENDENCIES) src/common/$(am__dirstamp) + @rm -f src/common/dumper_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_dumper_unittest_OBJECTS) $(src_common_dumper_unittest_LDADD) $(LIBS) +src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-language.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-md5.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-stabs_reader.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-stabs_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_mac_macho_reader_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/mac/$(am__dirstamp): + @$(MKDIR_P) src/common/mac + @: > src/common/mac/$(am__dirstamp) +src/common/mac/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/common/mac/$(DEPDIR) + @: > src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-file_id.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-macho_id.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/tests/src_common_mac_macho_reader_unittest-file_utils.$(OBJEXT): \ + src/common/tests/$(am__dirstamp) \ + src/common/tests/$(DEPDIR)/$(am__dirstamp) + +src/common/mac/macho_reader_unittest$(EXEEXT): $(src_common_mac_macho_reader_unittest_OBJECTS) $(src_common_mac_macho_reader_unittest_DEPENDENCIES) $(EXTRA_src_common_mac_macho_reader_unittest_DEPENDENCIES) src/common/mac/$(am__dirstamp) + @rm -f src/common/mac/macho_reader_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_mac_macho_reader_unittest_OBJECTS) $(src_common_mac_macho_reader_unittest_LDADD) $(LIBS) +src/common/src_common_test_assembler_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_common_test_assembler_unittest-test_assembler_unittest.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) + +src/common/test_assembler_unittest$(EXEEXT): $(src_common_test_assembler_unittest_OBJECTS) $(src_common_test_assembler_unittest_DEPENDENCIES) $(EXTRA_src_common_test_assembler_unittest_DEPENDENCIES) src/common/$(am__dirstamp) + @rm -f src/common/test_assembler_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_common_test_assembler_unittest_OBJECTS) $(src_common_test_assembler_unittest_LDADD) $(LIBS) +src/processor/address_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/address_map_unittest$(EXEEXT): $(src_processor_address_map_unittest_OBJECTS) $(src_processor_address_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_address_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/address_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_address_map_unittest_OBJECTS) $(src_processor_address_map_unittest_LDADD) $(LIBS) +src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/basic_source_line_resolver_unittest$(EXEEXT): $(src_processor_basic_source_line_resolver_unittest_OBJECTS) $(src_processor_basic_source_line_resolver_unittest_DEPENDENCIES) $(EXTRA_src_processor_basic_source_line_resolver_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/basic_source_line_resolver_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_basic_source_line_resolver_unittest_OBJECTS) $(src_processor_basic_source_line_resolver_unittest_LDADD) $(LIBS) +src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/cfi_frame_info_unittest$(EXEEXT): $(src_processor_cfi_frame_info_unittest_OBJECTS) $(src_processor_cfi_frame_info_unittest_DEPENDENCIES) $(EXTRA_src_processor_cfi_frame_info_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/cfi_frame_info_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_cfi_frame_info_unittest_OBJECTS) $(src_processor_cfi_frame_info_unittest_LDADD) $(LIBS) +src/processor/contained_range_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/contained_range_map_unittest$(EXEEXT): $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_contained_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/contained_range_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_LDADD) $(LIBS) +src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/disassembler_x86_unittest$(EXEEXT): $(src_processor_disassembler_x86_unittest_OBJECTS) $(src_processor_disassembler_x86_unittest_DEPENDENCIES) $(EXTRA_src_processor_disassembler_x86_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/disassembler_x86_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_disassembler_x86_unittest_OBJECTS) $(src_processor_disassembler_x86_unittest_LDADD) $(LIBS) +src/processor/src_processor_exploitability_unittest-exploitability_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/exploitability_unittest$(EXEEXT): $(src_processor_exploitability_unittest_OBJECTS) $(src_processor_exploitability_unittest_DEPENDENCIES) $(EXTRA_src_processor_exploitability_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/exploitability_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_exploitability_unittest_OBJECTS) $(src_processor_exploitability_unittest_LDADD) $(LIBS) +src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/fast_source_line_resolver_unittest$(EXEEXT): $(src_processor_fast_source_line_resolver_unittest_OBJECTS) $(src_processor_fast_source_line_resolver_unittest_DEPENDENCIES) $(EXTRA_src_processor_fast_source_line_resolver_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/fast_source_line_resolver_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_fast_source_line_resolver_unittest_OBJECTS) $(src_processor_fast_source_line_resolver_unittest_LDADD) $(LIBS) +src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/map_serializers_unittest$(EXEEXT): $(src_processor_map_serializers_unittest_OBJECTS) $(src_processor_map_serializers_unittest_DEPENDENCIES) $(EXTRA_src_processor_map_serializers_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/map_serializers_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_map_serializers_unittest_OBJECTS) $(src_processor_map_serializers_unittest_LDADD) $(LIBS) +src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/microdump_processor_unittest$(EXEEXT): $(src_processor_microdump_processor_unittest_OBJECTS) $(src_processor_microdump_processor_unittest_DEPENDENCIES) $(EXTRA_src_processor_microdump_processor_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/microdump_processor_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_microdump_processor_unittest_OBJECTS) $(src_processor_microdump_processor_unittest_LDADD) $(LIBS) +src/processor/microdump_stackwalk.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/microdump_stackwalk$(EXEEXT): $(src_processor_microdump_stackwalk_OBJECTS) $(src_processor_microdump_stackwalk_DEPENDENCIES) $(EXTRA_src_processor_microdump_stackwalk_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/microdump_stackwalk$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_microdump_stackwalk_OBJECTS) $(src_processor_microdump_stackwalk_LDADD) $(LIBS) +src/processor/minidump_dump.$(OBJEXT): src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/minidump_dump$(EXEEXT): $(src_processor_minidump_dump_OBJECTS) $(src_processor_minidump_dump_DEPENDENCIES) $(EXTRA_src_processor_minidump_dump_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/minidump_dump$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_minidump_dump_OBJECTS) $(src_processor_minidump_dump_LDADD) $(LIBS) +src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/minidump_processor_unittest$(EXEEXT): $(src_processor_minidump_processor_unittest_OBJECTS) $(src_processor_minidump_processor_unittest_DEPENDENCIES) $(EXTRA_src_processor_minidump_processor_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/minidump_processor_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_minidump_processor_unittest_OBJECTS) $(src_processor_minidump_processor_unittest_LDADD) $(LIBS) +src/processor/minidump_stackwalk.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/minidump_stackwalk$(EXEEXT): $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_DEPENDENCIES) $(EXTRA_src_processor_minidump_stackwalk_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/minidump_stackwalk$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_minidump_stackwalk_OBJECTS) $(src_processor_minidump_stackwalk_LDADD) $(LIBS) +src/common/src_processor_minidump_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_minidump_unittest-minidump_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_minidump_unittest-synth_minidump.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/minidump_unittest$(EXEEXT): $(src_processor_minidump_unittest_OBJECTS) $(src_processor_minidump_unittest_DEPENDENCIES) $(EXTRA_src_processor_minidump_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/minidump_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_minidump_unittest_OBJECTS) $(src_processor_minidump_unittest_LDADD) $(LIBS) +src/processor/pathname_stripper_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/pathname_stripper_unittest$(EXEEXT): $(src_processor_pathname_stripper_unittest_OBJECTS) $(src_processor_pathname_stripper_unittest_DEPENDENCIES) $(EXTRA_src_processor_pathname_stripper_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/pathname_stripper_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_pathname_stripper_unittest_OBJECTS) $(src_processor_pathname_stripper_unittest_LDADD) $(LIBS) +src/processor/postfix_evaluator_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/postfix_evaluator_unittest$(EXEEXT): $(src_processor_postfix_evaluator_unittest_OBJECTS) $(src_processor_postfix_evaluator_unittest_DEPENDENCIES) $(EXTRA_src_processor_postfix_evaluator_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/postfix_evaluator_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_postfix_evaluator_unittest_OBJECTS) $(src_processor_postfix_evaluator_unittest_LDADD) $(LIBS) +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/proc_maps_linux_unittest$(EXEEXT): $(src_processor_proc_maps_linux_unittest_OBJECTS) $(src_processor_proc_maps_linux_unittest_DEPENDENCIES) $(EXTRA_src_processor_proc_maps_linux_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/proc_maps_linux_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_proc_maps_linux_unittest_OBJECTS) $(src_processor_proc_maps_linux_unittest_LDADD) $(LIBS) +src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/range_map_shrink_down_unittest$(EXEEXT): $(src_processor_range_map_shrink_down_unittest_OBJECTS) $(src_processor_range_map_shrink_down_unittest_DEPENDENCIES) $(EXTRA_src_processor_range_map_shrink_down_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/range_map_shrink_down_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_range_map_shrink_down_unittest_OBJECTS) $(src_processor_range_map_shrink_down_unittest_LDADD) $(LIBS) +src/processor/range_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/range_map_unittest$(EXEEXT): $(src_processor_range_map_unittest_OBJECTS) $(src_processor_range_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/range_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_range_map_unittest_OBJECTS) $(src_processor_range_map_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_address_list_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_address_list_unittest$(EXEEXT): $(src_processor_stackwalker_address_list_unittest_OBJECTS) $(src_processor_stackwalker_address_list_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_address_list_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_address_list_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_address_list_unittest_OBJECTS) $(src_processor_stackwalker_address_list_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_amd64_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_amd64_unittest$(EXEEXT): $(src_processor_stackwalker_amd64_unittest_OBJECTS) $(src_processor_stackwalker_amd64_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_amd64_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_amd64_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_amd64_unittest_OBJECTS) $(src_processor_stackwalker_amd64_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_arm64_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_arm64_unittest$(EXEEXT): $(src_processor_stackwalker_arm64_unittest_OBJECTS) $(src_processor_stackwalker_arm64_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_arm64_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_arm64_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_arm64_unittest_OBJECTS) $(src_processor_stackwalker_arm64_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_arm_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_arm_unittest$(EXEEXT): $(src_processor_stackwalker_arm_unittest_OBJECTS) $(src_processor_stackwalker_arm_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_arm_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_arm_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_arm_unittest_OBJECTS) $(src_processor_stackwalker_arm_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_mips64_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_mips64_unittest$(EXEEXT): $(src_processor_stackwalker_mips64_unittest_OBJECTS) $(src_processor_stackwalker_mips64_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_mips64_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_mips64_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_mips64_unittest_OBJECTS) $(src_processor_stackwalker_mips64_unittest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_mips_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_mips_unittest$(EXEEXT): $(src_processor_stackwalker_mips_unittest_OBJECTS) $(src_processor_stackwalker_mips_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_mips_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_mips_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_mips_unittest_OBJECTS) $(src_processor_stackwalker_mips_unittest_LDADD) $(LIBS) +src/processor/stackwalker_selftest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_selftest$(EXEEXT): $(src_processor_stackwalker_selftest_OBJECTS) $(src_processor_stackwalker_selftest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_selftest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_selftest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_selftest_OBJECTS) $(src_processor_stackwalker_selftest_LDADD) $(LIBS) +src/common/src_processor_stackwalker_x86_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/stackwalker_x86_unittest$(EXEEXT): $(src_processor_stackwalker_x86_unittest_OBJECTS) $(src_processor_stackwalker_x86_unittest_DEPENDENCIES) $(EXTRA_src_processor_stackwalker_x86_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/stackwalker_x86_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_stackwalker_x86_unittest_OBJECTS) $(src_processor_stackwalker_x86_unittest_LDADD) $(LIBS) +src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/static_address_map_unittest$(EXEEXT): $(src_processor_static_address_map_unittest_OBJECTS) $(src_processor_static_address_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_static_address_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/static_address_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_static_address_map_unittest_OBJECTS) $(src_processor_static_address_map_unittest_LDADD) $(LIBS) +src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/static_contained_range_map_unittest$(EXEEXT): $(src_processor_static_contained_range_map_unittest_OBJECTS) $(src_processor_static_contained_range_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_static_contained_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/static_contained_range_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_static_contained_range_map_unittest_OBJECTS) $(src_processor_static_contained_range_map_unittest_LDADD) $(LIBS) +src/processor/src_processor_static_map_unittest-static_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/static_map_unittest$(EXEEXT): $(src_processor_static_map_unittest_OBJECTS) $(src_processor_static_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_static_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/static_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_static_map_unittest_OBJECTS) $(src_processor_static_map_unittest_LDADD) $(LIBS) +src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/static_range_map_unittest$(EXEEXT): $(src_processor_static_range_map_unittest_OBJECTS) $(src_processor_static_range_map_unittest_DEPENDENCIES) $(EXTRA_src_processor_static_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/static_range_map_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_static_range_map_unittest_OBJECTS) $(src_processor_static_range_map_unittest_LDADD) $(LIBS) +src/common/src_processor_synth_minidump_unittest-test_assembler.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/src_processor_synth_minidump_unittest-synth_minidump.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) + +src/processor/synth_minidump_unittest$(EXEEXT): $(src_processor_synth_minidump_unittest_OBJECTS) $(src_processor_synth_minidump_unittest_DEPENDENCIES) $(EXTRA_src_processor_synth_minidump_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/synth_minidump_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_processor_synth_minidump_unittest_OBJECTS) $(src_processor_synth_minidump_unittest_LDADD) $(LIBS) +src/tools/linux/core2md/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/core2md + @: > src/tools/linux/core2md/$(am__dirstamp) +src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/core2md/$(DEPDIR) + @: > src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/core2md/core2md.$(OBJEXT): \ + src/tools/linux/core2md/$(am__dirstamp) \ + src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/core2md/core2md$(EXEEXT): $(src_tools_linux_core2md_core2md_OBJECTS) $(src_tools_linux_core2md_core2md_DEPENDENCIES) $(EXTRA_src_tools_linux_core2md_core2md_DEPENDENCIES) src/tools/linux/core2md/$(am__dirstamp) + @rm -f src/tools/linux/core2md/core2md$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_core2md_core2md_OBJECTS) $(src_tools_linux_core2md_core2md_LDADD) $(LIBS) +src/common/dwarf_cfi_to_module.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf_cu_to_module.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf_line_to_module.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/language.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/module.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/stabs_reader.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/stabs_to_module.$(OBJEXT): src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/bytereader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/dwarf2diehandler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/dwarf2reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/elf_reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/linux/crc32.$(OBJEXT): src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/dump_symbols.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/common/linux/elf_symbols_to_module.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/dump_syms/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/dump_syms + @: > src/tools/linux/dump_syms/$(am__dirstamp) +src/tools/linux/dump_syms/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/dump_syms/$(DEPDIR) + @: > src/tools/linux/dump_syms/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/dump_syms/dump_syms.$(OBJEXT): \ + src/tools/linux/dump_syms/$(am__dirstamp) \ + src/tools/linux/dump_syms/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/dump_syms/dump_syms$(EXEEXT): $(src_tools_linux_dump_syms_dump_syms_OBJECTS) $(src_tools_linux_dump_syms_dump_syms_DEPENDENCIES) $(EXTRA_src_tools_linux_dump_syms_dump_syms_DEPENDENCIES) src/tools/linux/dump_syms/$(am__dirstamp) + @rm -f src/tools/linux/dump_syms/dump_syms$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_dump_syms_dump_syms_OBJECTS) $(src_tools_linux_dump_syms_dump_syms_LDADD) $(LIBS) +src/tools/linux/md2core/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/md2core + @: > src/tools/linux/md2core/$(am__dirstamp) +src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/md2core/$(DEPDIR) + @: > src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/md2core/minidump-2-core.$(OBJEXT): \ + src/tools/linux/md2core/$(am__dirstamp) \ + src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/md2core/minidump-2-core$(EXEEXT): $(src_tools_linux_md2core_minidump_2_core_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_DEPENDENCIES) $(EXTRA_src_tools_linux_md2core_minidump_2_core_DEPENDENCIES) src/tools/linux/md2core/$(am__dirstamp) + @rm -f src/tools/linux/md2core/minidump-2-core$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_md2core_minidump_2_core_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_LDADD) $(LIBS) +src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.$(OBJEXT): \ + src/tools/linux/md2core/$(am__dirstamp) \ + src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT): $(src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES) $(EXTRA_src_tools_linux_md2core_minidump_2_core_unittest_DEPENDENCIES) src/tools/linux/md2core/$(am__dirstamp) + @rm -f src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_md2core_minidump_2_core_unittest_OBJECTS) $(src_tools_linux_md2core_minidump_2_core_unittest_LDADD) $(LIBS) +src/common/linux/http_upload.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/symupload/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/symupload + @: > src/tools/linux/symupload/$(am__dirstamp) +src/tools/linux/symupload/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/tools/linux/symupload/$(DEPDIR) + @: > src/tools/linux/symupload/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/symupload/minidump_upload.$(OBJEXT): \ + src/tools/linux/symupload/$(am__dirstamp) \ + src/tools/linux/symupload/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/symupload/minidump_upload$(EXEEXT): $(src_tools_linux_symupload_minidump_upload_OBJECTS) $(src_tools_linux_symupload_minidump_upload_DEPENDENCIES) $(EXTRA_src_tools_linux_symupload_minidump_upload_DEPENDENCIES) src/tools/linux/symupload/$(am__dirstamp) + @rm -f src/tools/linux/symupload/minidump_upload$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_symupload_minidump_upload_OBJECTS) $(src_tools_linux_symupload_minidump_upload_LDADD) $(LIBS) +src/common/linux/symbol_upload.$(OBJEXT): \ + src/common/linux/$(am__dirstamp) \ + src/common/linux/$(DEPDIR)/$(am__dirstamp) +src/tools/linux/symupload/sym_upload.$(OBJEXT): \ + src/tools/linux/symupload/$(am__dirstamp) \ + src/tools/linux/symupload/$(DEPDIR)/$(am__dirstamp) + +src/tools/linux/symupload/sym_upload$(EXEEXT): $(src_tools_linux_symupload_sym_upload_OBJECTS) $(src_tools_linux_symupload_sym_upload_DEPENDENCIES) $(EXTRA_src_tools_linux_symupload_sym_upload_DEPENDENCIES) src/tools/linux/symupload/$(am__dirstamp) + @rm -f src/tools/linux/symupload/sym_upload$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(src_tools_linux_symupload_sym_upload_OBJECTS) $(src_tools_linux_symupload_sym_upload_LDADD) $(LIBS) +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-language.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.$(OBJEXT): \ + src/common/$(am__dirstamp) \ + src/common/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.$(OBJEXT): \ + src/common/dwarf/$(am__dirstamp) \ + src/common/dwarf/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.$(OBJEXT): \ + src/common/mac/$(am__dirstamp) \ + src/common/mac/$(DEPDIR)/$(am__dirstamp) +src/tools/mac/dump_syms/$(am__dirstamp): + @$(MKDIR_P) src/tools/mac/dump_syms + @: > src/tools/mac/dump_syms/$(am__dirstamp) +src/tools/mac/dump_syms/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/tools/mac/dump_syms/$(DEPDIR) + @: > src/tools/mac/dump_syms/$(DEPDIR)/$(am__dirstamp) +src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.$(OBJEXT): \ + src/tools/mac/dump_syms/$(am__dirstamp) \ + src/tools/mac/dump_syms/$(DEPDIR)/$(am__dirstamp) + +src/tools/mac/dump_syms/dump_syms_mac$(EXEEXT): $(src_tools_mac_dump_syms_dump_syms_mac_OBJECTS) $(src_tools_mac_dump_syms_dump_syms_mac_DEPENDENCIES) $(EXTRA_src_tools_mac_dump_syms_dump_syms_mac_DEPENDENCIES) src/tools/mac/dump_syms/$(am__dirstamp) + @rm -f src/tools/mac/dump_syms/dump_syms_mac$(EXEEXT) + $(AM_V_CXXLD)$(src_tools_mac_dump_syms_dump_syms_mac_LINK) $(src_tools_mac_dump_syms_dump_syms_mac_OBJECTS) $(src_tools_mac_dump_syms_dump_syms_mac_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f src/client/*.$(OBJEXT) + -rm -f src/client/linux/crash_generation/*.$(OBJEXT) + -rm -f src/client/linux/dump_writer_common/*.$(OBJEXT) + -rm -f src/client/linux/handler/*.$(OBJEXT) + -rm -f src/client/linux/log/*.$(OBJEXT) + -rm -f src/client/linux/microdump_writer/*.$(OBJEXT) + -rm -f src/client/linux/minidump_writer/*.$(OBJEXT) + -rm -f src/common/*.$(OBJEXT) + -rm -f src/common/android/*.$(OBJEXT) + -rm -f src/common/dwarf/*.$(OBJEXT) + -rm -f src/common/linux/*.$(OBJEXT) + -rm -f src/common/linux/tests/*.$(OBJEXT) + -rm -f src/common/mac/*.$(OBJEXT) + -rm -f src/common/tests/*.$(OBJEXT) + -rm -f src/processor/*.$(OBJEXT) + -rm -f src/testing/gtest/src/*.$(OBJEXT) + -rm -f src/testing/src/*.$(OBJEXT) + -rm -f src/third_party/libdisasm/*.$(OBJEXT) + -rm -f src/tools/linux/core2md/*.$(OBJEXT) + -rm -f src/tools/linux/dump_syms/*.$(OBJEXT) + -rm -f src/tools/linux/md2core/*.$(OBJEXT) + -rm -f src/tools/linux/symupload/*.$(OBJEXT) + -rm -f src/tools/mac/dump_syms/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@src/client/$(DEPDIR)/minidump_file_writer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/crash_generation/$(DEPDIR)/crash_generation_client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/crash_generation/$(DEPDIR)/crash_generation_server.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/dump_writer_common/$(DEPDIR)/thread_info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/dump_writer_common/$(DEPDIR)/ucontext_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/exception_handler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/minidump_descriptor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/log/$(DEPDIR)/log.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/microdump_writer/$(DEPDIR)/microdump_writer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_core_dumper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_dumper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/linux_ptrace_dumper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/minidump_writer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/convert_UTF.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/dwarf_cfi_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/dwarf_cu_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/dwarf_line_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/language.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-language.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/stabs_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/$(DEPDIR)/string_conversion.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/breakpad_getcontext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/bytereader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2diehandler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/dwarf2reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/elf_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/crc32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/dump_symbols.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/elf_core_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/elf_symbols_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/elfutils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/file_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/guid_creator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/http_upload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/linux_libc_support.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/memory_mapped_file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/safe_readlink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/symbol_upload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/address_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_code_modules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_source_line_resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/call_stack.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/cfi_frame_info.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/contained_range_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/disassembler_x86.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/dump_context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/dump_object.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/exploitability.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/exploitability_linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/exploitability_win.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/fast_source_line_resolver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/logging.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump_processor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/microdump_stackwalk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_stackwalk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/module_comparer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/module_serializer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/pathname_stripper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/pathname_stripper_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/postfix_evaluator_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/proc_maps_linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/process_state.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/simple_symbol_supplier.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_base.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stack_frame_cpu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stack_frame_symbolizer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_address_list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_amd64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_arm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_arm64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_mips.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_selftest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_sparc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_x86.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/symbolic_constants_win.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/tokenize.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_implicit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_insn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_invariant.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_modrm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_opcode_tables.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_operand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_reg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/ia32_settings.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_disasm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_format.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_imm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_insn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_misc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/third_party/libdisasm/$(DEPDIR)/x86_operand_list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/core2md/$(DEPDIR)/core2md.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/dump_syms/$(DEPDIR)/dump_syms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/md2core/$(DEPDIR)/minidump-2-core.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/symupload/$(DEPDIR)/minidump_upload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/linux/symupload/$(DEPDIR)/sym_upload.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Po@am__quote@ + +.S.o: +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $< + +.S.obj: +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCCAS_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.o: src/common/android/breakpad_getcontext.S +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -MT src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.o -MD -MP -MF src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Tpo -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.o `test -f 'src/common/android/breakpad_getcontext.S' || echo '$(srcdir)/'`src/common/android/breakpad_getcontext.S +@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Tpo src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='src/common/android/breakpad_getcontext.S' object='src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.o `test -f 'src/common/android/breakpad_getcontext.S' || echo '$(srcdir)/'`src/common/android/breakpad_getcontext.S + +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.obj: src/common/android/breakpad_getcontext.S +@am__fastdepCCAS_TRUE@ $(AM_V_CPPAS)$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -MT src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.obj -MD -MP -MF src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Tpo -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.obj `if test -f 'src/common/android/breakpad_getcontext.S'; then $(CYGPATH_W) 'src/common/android/breakpad_getcontext.S'; else $(CYGPATH_W) '$(srcdir)/src/common/android/breakpad_getcontext.S'; fi` +@am__fastdepCCAS_TRUE@ $(AM_V_at)$(am__mv) src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Tpo src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS)source='src/common/android/breakpad_getcontext.S' object='src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(AM_V_CPPAS@am__nodep@)$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext.obj `if test -f 'src/common/android/breakpad_getcontext.S'; then $(CYGPATH_W) 'src/common/android/breakpad_getcontext.S'; else $(CYGPATH_W) '$(srcdir)/src/common/android/breakpad_getcontext.S'; fi` + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +src/testing/gtest/src/src_testing_libtesting_a-gtest-all.o: src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_testing_libtesting_a-gtest-all.o -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Tpo -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest-all.o `test -f 'src/testing/gtest/src/gtest-all.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Tpo src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest-all.cc' object='src/testing/gtest/src/src_testing_libtesting_a-gtest-all.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest-all.o `test -f 'src/testing/gtest/src/gtest-all.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest-all.cc + +src/testing/gtest/src/src_testing_libtesting_a-gtest-all.obj: src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_testing_libtesting_a-gtest-all.obj -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Tpo -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest-all.obj `if test -f 'src/testing/gtest/src/gtest-all.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest-all.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Tpo src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest-all.cc' object='src/testing/gtest/src/src_testing_libtesting_a-gtest-all.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest-all.obj `if test -f 'src/testing/gtest/src/gtest-all.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest-all.cc'; fi` + +src/testing/gtest/src/src_testing_libtesting_a-gtest_main.o: src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_testing_libtesting_a-gtest_main.o -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Tpo -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest_main.o `test -f 'src/testing/gtest/src/gtest_main.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Tpo src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest_main.cc' object='src/testing/gtest/src/src_testing_libtesting_a-gtest_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest_main.o `test -f 'src/testing/gtest/src/gtest_main.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest_main.cc + +src/testing/gtest/src/src_testing_libtesting_a-gtest_main.obj: src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_testing_libtesting_a-gtest_main.obj -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Tpo -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest_main.obj `if test -f 'src/testing/gtest/src/gtest_main.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest_main.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Tpo src/testing/gtest/src/$(DEPDIR)/src_testing_libtesting_a-gtest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest_main.cc' object='src/testing/gtest/src/src_testing_libtesting_a-gtest_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_testing_libtesting_a-gtest_main.obj `if test -f 'src/testing/gtest/src/gtest_main.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest_main.cc'; fi` + +src/testing/src/src_testing_libtesting_a-gmock-all.o: src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/src/src_testing_libtesting_a-gmock-all.o -MD -MP -MF src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Tpo -c -o src/testing/src/src_testing_libtesting_a-gmock-all.o `test -f 'src/testing/src/gmock-all.cc' || echo '$(srcdir)/'`src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Tpo src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/src/gmock-all.cc' object='src/testing/src/src_testing_libtesting_a-gmock-all.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/src/src_testing_libtesting_a-gmock-all.o `test -f 'src/testing/src/gmock-all.cc' || echo '$(srcdir)/'`src/testing/src/gmock-all.cc + +src/testing/src/src_testing_libtesting_a-gmock-all.obj: src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/src/src_testing_libtesting_a-gmock-all.obj -MD -MP -MF src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Tpo -c -o src/testing/src/src_testing_libtesting_a-gmock-all.obj `if test -f 'src/testing/src/gmock-all.cc'; then $(CYGPATH_W) 'src/testing/src/gmock-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/src/gmock-all.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Tpo src/testing/src/$(DEPDIR)/src_testing_libtesting_a-gmock-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/src/gmock-all.cc' object='src/testing/src/src_testing_libtesting_a-gmock-all.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_testing_libtesting_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/src/src_testing_libtesting_a-gmock-all.obj `if test -f 'src/testing/src/gmock-all.cc'; then $(CYGPATH_W) 'src/testing/src/gmock-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/src/gmock-all.cc'; fi` + +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.o: src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.o -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Tpo -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.o `test -f 'src/testing/gtest/src/gtest-all.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Tpo src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest-all.cc' object='src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.o `test -f 'src/testing/gtest/src/gtest-all.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest-all.cc + +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.obj: src/testing/gtest/src/gtest-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.obj -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Tpo -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.obj `if test -f 'src/testing/gtest/src/gtest-all.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest-all.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Tpo src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest-all.cc' object='src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest-all.obj `if test -f 'src/testing/gtest/src/gtest-all.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest-all.cc'; fi` + +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.o: src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.o -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Tpo -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.o `test -f 'src/testing/gtest/src/gtest_main.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Tpo src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest_main.cc' object='src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.o `test -f 'src/testing/gtest/src/gtest_main.cc' || echo '$(srcdir)/'`src/testing/gtest/src/gtest_main.cc + +src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.obj: src/testing/gtest/src/gtest_main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.obj -MD -MP -MF src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Tpo -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.obj `if test -f 'src/testing/gtest/src/gtest_main.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest_main.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Tpo src/testing/gtest/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gtest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/gtest/src/gtest_main.cc' object='src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/gtest/src/src_client_linux_linux_client_unittest_shlib-gtest_main.obj `if test -f 'src/testing/gtest/src/gtest_main.cc'; then $(CYGPATH_W) 'src/testing/gtest/src/gtest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/gtest/src/gtest_main.cc'; fi` + +src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.o: src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.o -MD -MP -MF src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Tpo -c -o src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.o `test -f 'src/testing/src/gmock-all.cc' || echo '$(srcdir)/'`src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Tpo src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/src/gmock-all.cc' object='src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.o `test -f 'src/testing/src/gmock-all.cc' || echo '$(srcdir)/'`src/testing/src/gmock-all.cc + +src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.obj: src/testing/src/gmock-all.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.obj -MD -MP -MF src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Tpo -c -o src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.obj `if test -f 'src/testing/src/gmock-all.cc'; then $(CYGPATH_W) 'src/testing/src/gmock-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/src/gmock-all.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Tpo src/testing/src/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-gmock-all.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/testing/src/gmock-all.cc' object='src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/testing/src/src_client_linux_linux_client_unittest_shlib-gmock-all.obj `if test -f 'src/testing/src/gmock-all.cc'; then $(CYGPATH_W) 'src/testing/src/gmock-all.cc'; else $(CYGPATH_W) '$(srcdir)/src/testing/src/gmock-all.cc'; fi` + +src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.o: src/client/linux/handler/exception_handler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.o -MD -MP -MF src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Tpo -c -o src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.o `test -f 'src/client/linux/handler/exception_handler_unittest.cc' || echo '$(srcdir)/'`src/client/linux/handler/exception_handler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Tpo src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/handler/exception_handler_unittest.cc' object='src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.o `test -f 'src/client/linux/handler/exception_handler_unittest.cc' || echo '$(srcdir)/'`src/client/linux/handler/exception_handler_unittest.cc + +src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.obj: src/client/linux/handler/exception_handler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.obj -MD -MP -MF src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Tpo -c -o src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.obj `if test -f 'src/client/linux/handler/exception_handler_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/handler/exception_handler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/handler/exception_handler_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Tpo src/client/linux/handler/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/handler/exception_handler_unittest.cc' object='src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/handler/src_client_linux_linux_client_unittest_shlib-exception_handler_unittest.obj `if test -f 'src/client/linux/handler/exception_handler_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/handler/exception_handler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/handler/exception_handler_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.o: src/client/linux/minidump_writer/directory_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.o `test -f 'src/client/linux/minidump_writer/directory_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/directory_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/directory_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.o `test -f 'src/client/linux/minidump_writer/directory_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/directory_reader_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.obj: src/client/linux/minidump_writer/directory_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/directory_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/directory_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/directory_reader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/directory_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-directory_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/directory_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/directory_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/directory_reader_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.o: src/client/linux/minidump_writer/cpu_set_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.o `test -f 'src/client/linux/minidump_writer/cpu_set_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/cpu_set_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/cpu_set_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.o `test -f 'src/client/linux/minidump_writer/cpu_set_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/cpu_set_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.obj: src/client/linux/minidump_writer/cpu_set_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.obj `if test -f 'src/client/linux/minidump_writer/cpu_set_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/cpu_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/cpu_set_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/cpu_set_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-cpu_set_unittest.obj `if test -f 'src/client/linux/minidump_writer/cpu_set_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/cpu_set_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/cpu_set_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.o: src/client/linux/minidump_writer/line_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.o `test -f 'src/client/linux/minidump_writer/line_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/line_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/line_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.o `test -f 'src/client/linux/minidump_writer/line_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/line_reader_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.obj: src/client/linux/minidump_writer/line_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/line_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/line_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/line_reader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/line_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-line_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/line_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/line_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/line_reader_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.o: src/client/linux/minidump_writer/linux_core_dumper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_core_dumper.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.obj: src/client/linux/minidump_writer/linux_core_dumper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_core_dumper.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.o: src/client/linux/minidump_writer/linux_core_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_core_dumper_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.obj: src/client/linux/minidump_writer/linux_core_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_core_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_core_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.o: src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.o `test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.obj: src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-linux_ptrace_dumper_unittest.obj `if test -f 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.o: src/client/linux/minidump_writer/minidump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.o `test -f 'src/client/linux/minidump_writer/minidump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/minidump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/minidump_writer_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.o `test -f 'src/client/linux/minidump_writer/minidump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/minidump_writer_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.obj: src/client/linux/minidump_writer/minidump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/minidump_writer_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.o: src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.o `test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.o `test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.obj: src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-minidump_writer_unittest_utils.obj `if test -f 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o: src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o `test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.o `test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc + +src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.obj: src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_client_unittest_shlib-proc_cpuinfo_reader_unittest.obj `if test -f 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc'; fi` + +src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.o: src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Tpo -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.o `test -f 'src/common/linux/elf_core_dump.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Tpo src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump.cc' object='src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.o `test -f 'src/common/linux/elf_core_dump.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump.cc + +src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.obj: src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Tpo -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.obj `if test -f 'src/common/linux/elf_core_dump.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Tpo src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-elf_core_dump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump.cc' object='src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-elf_core_dump.obj `if test -f 'src/common/linux/elf_core_dump.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump.cc'; fi` + +src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.o: src/common/linux/linux_libc_support_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Tpo -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.o `test -f 'src/common/linux/linux_libc_support_unittest.cc' || echo '$(srcdir)/'`src/common/linux/linux_libc_support_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Tpo src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/linux_libc_support_unittest.cc' object='src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.o `test -f 'src/common/linux/linux_libc_support_unittest.cc' || echo '$(srcdir)/'`src/common/linux/linux_libc_support_unittest.cc + +src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj: src/common/linux/linux_libc_support_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Tpo -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj `if test -f 'src/common/linux/linux_libc_support_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Tpo src/common/linux/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/linux_libc_support_unittest.cc' object='src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_client_linux_linux_client_unittest_shlib-linux_libc_support_unittest.obj `if test -f 'src/common/linux/linux_libc_support_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support_unittest.cc'; fi` + +src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.o: src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.o -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Tpo -c -o src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc + +src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.obj: src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.obj -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Tpo -c -o src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-crash_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_client_linux_linux_client_unittest_shlib-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi` + +src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.o: src/common/memory_allocator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Tpo -c -o src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.o `test -f 'src/common/memory_allocator_unittest.cc' || echo '$(srcdir)/'`src/common/memory_allocator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Tpo src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/memory_allocator_unittest.cc' object='src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.o `test -f 'src/common/memory_allocator_unittest.cc' || echo '$(srcdir)/'`src/common/memory_allocator_unittest.cc + +src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.obj: src/common/memory_allocator_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Tpo -c -o src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.obj `if test -f 'src/common/memory_allocator_unittest.cc'; then $(CYGPATH_W) 'src/common/memory_allocator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/memory_allocator_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Tpo src/common/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/memory_allocator_unittest.cc' object='src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_client_linux_linux_client_unittest_shlib-memory_allocator_unittest.obj `if test -f 'src/common/memory_allocator_unittest.cc'; then $(CYGPATH_W) 'src/common/memory_allocator_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/memory_allocator_unittest.cc'; fi` + +src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.o: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.o -MD -MP -MF src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Tpo -c -o src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Tpo src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc + +src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.obj: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.obj -MD -MP -MF src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Tpo -c -o src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Tpo src/common/tests/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_client_linux_linux_client_unittest_shlib-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.o: src/processor/basic_code_modules.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.o `test -f 'src/processor/basic_code_modules.cc' || echo '$(srcdir)/'`src/processor/basic_code_modules.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/basic_code_modules.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.o `test -f 'src/processor/basic_code_modules.cc' || echo '$(srcdir)/'`src/processor/basic_code_modules.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.obj: src/processor/basic_code_modules.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.obj `if test -f 'src/processor/basic_code_modules.cc'; then $(CYGPATH_W) 'src/processor/basic_code_modules.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/basic_code_modules.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-basic_code_modules.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/basic_code_modules.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-basic_code_modules.obj `if test -f 'src/processor/basic_code_modules.cc'; then $(CYGPATH_W) 'src/processor/basic_code_modules.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/basic_code_modules.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.o: src/processor/dump_context.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.o `test -f 'src/processor/dump_context.cc' || echo '$(srcdir)/'`src/processor/dump_context.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/dump_context.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.o `test -f 'src/processor/dump_context.cc' || echo '$(srcdir)/'`src/processor/dump_context.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.obj: src/processor/dump_context.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.obj `if test -f 'src/processor/dump_context.cc'; then $(CYGPATH_W) 'src/processor/dump_context.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/dump_context.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_context.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/dump_context.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_context.obj `if test -f 'src/processor/dump_context.cc'; then $(CYGPATH_W) 'src/processor/dump_context.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/dump_context.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.o: src/processor/dump_object.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.o `test -f 'src/processor/dump_object.cc' || echo '$(srcdir)/'`src/processor/dump_object.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/dump_object.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.o `test -f 'src/processor/dump_object.cc' || echo '$(srcdir)/'`src/processor/dump_object.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.obj: src/processor/dump_object.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.obj `if test -f 'src/processor/dump_object.cc'; then $(CYGPATH_W) 'src/processor/dump_object.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/dump_object.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-dump_object.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/dump_object.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-dump_object.obj `if test -f 'src/processor/dump_object.cc'; then $(CYGPATH_W) 'src/processor/dump_object.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/dump_object.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-logging.o: src/processor/logging.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-logging.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-logging.o `test -f 'src/processor/logging.cc' || echo '$(srcdir)/'`src/processor/logging.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/logging.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-logging.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-logging.o `test -f 'src/processor/logging.cc' || echo '$(srcdir)/'`src/processor/logging.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-logging.obj: src/processor/logging.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-logging.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-logging.obj `if test -f 'src/processor/logging.cc'; then $(CYGPATH_W) 'src/processor/logging.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/logging.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-logging.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/logging.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-logging.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-logging.obj `if test -f 'src/processor/logging.cc'; then $(CYGPATH_W) 'src/processor/logging.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/logging.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-minidump.o: src/processor/minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-minidump.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-minidump.o `test -f 'src/processor/minidump.cc' || echo '$(srcdir)/'`src/processor/minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-minidump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-minidump.o `test -f 'src/processor/minidump.cc' || echo '$(srcdir)/'`src/processor/minidump.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-minidump.obj: src/processor/minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-minidump.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-minidump.obj `if test -f 'src/processor/minidump.cc'; then $(CYGPATH_W) 'src/processor/minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-minidump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-minidump.obj `if test -f 'src/processor/minidump.cc'; then $(CYGPATH_W) 'src/processor/minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.o: src/processor/pathname_stripper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.o `test -f 'src/processor/pathname_stripper.cc' || echo '$(srcdir)/'`src/processor/pathname_stripper.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/pathname_stripper.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.o `test -f 'src/processor/pathname_stripper.cc' || echo '$(srcdir)/'`src/processor/pathname_stripper.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj: src/processor/pathname_stripper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj `if test -f 'src/processor/pathname_stripper.cc'; then $(CYGPATH_W) 'src/processor/pathname_stripper.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/pathname_stripper.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-pathname_stripper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/pathname_stripper.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-pathname_stripper.obj `if test -f 'src/processor/pathname_stripper.cc'; then $(CYGPATH_W) 'src/processor/pathname_stripper.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/pathname_stripper.cc'; fi` + +src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.o: src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.o -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.o `test -f 'src/processor/proc_maps_linux.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.o `test -f 'src/processor/proc_maps_linux.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux.cc + +src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.obj: src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.obj -MD -MP -MF src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Tpo -c -o src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.obj `if test -f 'src/processor/proc_maps_linux.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Tpo src/processor/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux.cc' object='src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_client_linux_linux_client_unittest_shlib-proc_maps_linux.obj `if test -f 'src/processor/proc_maps_linux.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux.cc'; fi` + +src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o: src/client/linux/microdump_writer/microdump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o -MD -MP -MF src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o `test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/microdump_writer/microdump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/microdump_writer/microdump_writer_unittest.cc' object='src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.o `test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc' || echo '$(srcdir)/'`src/client/linux/microdump_writer/microdump_writer_unittest.cc + +src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj: src/client/linux/microdump_writer/microdump_writer_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj -MD -MP -MF src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj `if test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/microdump_writer/microdump_writer_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Tpo src/client/linux/microdump_writer/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/microdump_writer/microdump_writer_unittest.cc' object='src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/microdump_writer/src_client_linux_linux_client_unittest_shlib-microdump_writer_unittest.obj `if test -f 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; then $(CYGPATH_W) 'src/client/linux/microdump_writer/microdump_writer_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/microdump_writer/microdump_writer_unittest.cc'; fi` + +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o: src/common/android/breakpad_getcontext_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o -MD -MP -MF src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o `test -f 'src/common/android/breakpad_getcontext_unittest.cc' || echo '$(srcdir)/'`src/common/android/breakpad_getcontext_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/android/breakpad_getcontext_unittest.cc' object='src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.o `test -f 'src/common/android/breakpad_getcontext_unittest.cc' || echo '$(srcdir)/'`src/common/android/breakpad_getcontext_unittest.cc + +src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.obj: src/common/android/breakpad_getcontext_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.obj -MD -MP -MF src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.obj `if test -f 'src/common/android/breakpad_getcontext_unittest.cc'; then $(CYGPATH_W) 'src/common/android/breakpad_getcontext_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/android/breakpad_getcontext_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Tpo src/common/android/$(DEPDIR)/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/android/breakpad_getcontext_unittest.cc' object='src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_client_linux_linux_client_unittest_shlib_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/android/src_client_linux_linux_client_unittest_shlib-breakpad_getcontext_unittest.obj `if test -f 'src/common/android/breakpad_getcontext_unittest.cc'; then $(CYGPATH_W) 'src/common/android/breakpad_getcontext_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/android/breakpad_getcontext_unittest.cc'; fi` + +src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.o: src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_client_linux_linux_dumper_unittest_helper_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.o -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.o `test -f 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_client_linux_linux_dumper_unittest_helper_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.o `test -f 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc' || echo '$(srcdir)/'`src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc + +src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.obj: src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_client_linux_linux_dumper_unittest_helper_CXXFLAGS) $(CXXFLAGS) -MT src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.obj -MD -MP -MF src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Tpo -c -o src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.obj `if test -f 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Tpo src/client/linux/minidump_writer/$(DEPDIR)/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc' object='src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_client_linux_linux_dumper_unittest_helper_CXXFLAGS) $(CXXFLAGS) -c -o src/client/linux/minidump_writer/src_client_linux_linux_dumper_unittest_helper-linux_dumper_unittest_helper.obj `if test -f 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; then $(CYGPATH_W) 'src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; else $(CYGPATH_W) '$(srcdir)/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc'; fi` + +src/common/src_common_dumper_unittest-byte_cursor_unittest.o: src/common/byte_cursor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-byte_cursor_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Tpo -c -o src/common/src_common_dumper_unittest-byte_cursor_unittest.o `test -f 'src/common/byte_cursor_unittest.cc' || echo '$(srcdir)/'`src/common/byte_cursor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/byte_cursor_unittest.cc' object='src/common/src_common_dumper_unittest-byte_cursor_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-byte_cursor_unittest.o `test -f 'src/common/byte_cursor_unittest.cc' || echo '$(srcdir)/'`src/common/byte_cursor_unittest.cc + +src/common/src_common_dumper_unittest-byte_cursor_unittest.obj: src/common/byte_cursor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-byte_cursor_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Tpo -c -o src/common/src_common_dumper_unittest-byte_cursor_unittest.obj `if test -f 'src/common/byte_cursor_unittest.cc'; then $(CYGPATH_W) 'src/common/byte_cursor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/byte_cursor_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-byte_cursor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/byte_cursor_unittest.cc' object='src/common/src_common_dumper_unittest-byte_cursor_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-byte_cursor_unittest.obj `if test -f 'src/common/byte_cursor_unittest.cc'; then $(CYGPATH_W) 'src/common/byte_cursor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/byte_cursor_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_cfi_to_module.o: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cfi_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_cfi_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc + +src/common/src_common_dumper_unittest-dwarf_cfi_to_module.obj: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cfi_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_cfi_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.o: src/common/dwarf_cfi_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.o `test -f 'src/common/dwarf_cfi_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.o `test -f 'src/common/dwarf_cfi_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module_unittest.cc + +src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.obj: src/common/dwarf_cfi_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.obj `if test -f 'src/common/dwarf_cfi_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cfi_to_module_unittest.obj `if test -f 'src/common/dwarf_cfi_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_cu_to_module.o: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cu_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_cu_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc + +src/common/src_common_dumper_unittest-dwarf_cu_to_module.obj: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cu_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_cu_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.o: src/common/dwarf_cu_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.o `test -f 'src/common/dwarf_cu_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.o `test -f 'src/common/dwarf_cu_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module_unittest.cc + +src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.obj: src/common/dwarf_cu_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.obj `if test -f 'src/common/dwarf_cu_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_cu_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_cu_to_module_unittest.obj `if test -f 'src/common/dwarf_cu_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_line_to_module.o: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_line_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_line_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc + +src/common/src_common_dumper_unittest-dwarf_line_to_module.obj: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_line_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_common_dumper_unittest-dwarf_line_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` + +src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.o: src/common/dwarf_line_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.o `test -f 'src/common/dwarf_line_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.o `test -f 'src/common/dwarf_line_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module_unittest.cc + +src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj: src/common/dwarf_line_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj `if test -f 'src/common/dwarf_line_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-dwarf_line_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-dwarf_line_to_module_unittest.obj `if test -f 'src/common/dwarf_line_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-language.o: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-language.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo -c -o src/common/src_common_dumper_unittest-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_common_dumper_unittest-language.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc + +src/common/src_common_dumper_unittest-language.obj: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-language.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo -c -o src/common/src_common_dumper_unittest-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-language.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_common_dumper_unittest-language.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` + +src/common/src_common_dumper_unittest-memory_range_unittest.o: src/common/memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-memory_range_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Tpo -c -o src/common/src_common_dumper_unittest-memory_range_unittest.o `test -f 'src/common/memory_range_unittest.cc' || echo '$(srcdir)/'`src/common/memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/memory_range_unittest.cc' object='src/common/src_common_dumper_unittest-memory_range_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-memory_range_unittest.o `test -f 'src/common/memory_range_unittest.cc' || echo '$(srcdir)/'`src/common/memory_range_unittest.cc + +src/common/src_common_dumper_unittest-memory_range_unittest.obj: src/common/memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-memory_range_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Tpo -c -o src/common/src_common_dumper_unittest-memory_range_unittest.obj `if test -f 'src/common/memory_range_unittest.cc'; then $(CYGPATH_W) 'src/common/memory_range_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/memory_range_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-memory_range_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/memory_range_unittest.cc' object='src/common/src_common_dumper_unittest-memory_range_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-memory_range_unittest.obj `if test -f 'src/common/memory_range_unittest.cc'; then $(CYGPATH_W) 'src/common/memory_range_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/memory_range_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-module.o: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-module.Tpo -c -o src/common/src_common_dumper_unittest-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_common_dumper_unittest-module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc + +src/common/src_common_dumper_unittest-module.obj: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-module.Tpo -c -o src/common/src_common_dumper_unittest-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_common_dumper_unittest-module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` + +src/common/src_common_dumper_unittest-module_unittest.o: src/common/module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-module_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-module_unittest.o `test -f 'src/common/module_unittest.cc' || echo '$(srcdir)/'`src/common/module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module_unittest.cc' object='src/common/src_common_dumper_unittest-module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-module_unittest.o `test -f 'src/common/module_unittest.cc' || echo '$(srcdir)/'`src/common/module_unittest.cc + +src/common/src_common_dumper_unittest-module_unittest.obj: src/common/module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-module_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-module_unittest.obj `if test -f 'src/common/module_unittest.cc'; then $(CYGPATH_W) 'src/common/module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module_unittest.cc' object='src/common/src_common_dumper_unittest-module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-module_unittest.obj `if test -f 'src/common/module_unittest.cc'; then $(CYGPATH_W) 'src/common/module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-stabs_reader.o: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_reader.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Tpo -c -o src/common/src_common_dumper_unittest-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_common_dumper_unittest-stabs_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc + +src/common/src_common_dumper_unittest-stabs_reader.obj: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_reader.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Tpo -c -o src/common/src_common_dumper_unittest-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_common_dumper_unittest-stabs_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` + +src/common/src_common_dumper_unittest-stabs_reader_unittest.o: src/common/stabs_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_reader_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Tpo -c -o src/common/src_common_dumper_unittest-stabs_reader_unittest.o `test -f 'src/common/stabs_reader_unittest.cc' || echo '$(srcdir)/'`src/common/stabs_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader_unittest.cc' object='src/common/src_common_dumper_unittest-stabs_reader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_reader_unittest.o `test -f 'src/common/stabs_reader_unittest.cc' || echo '$(srcdir)/'`src/common/stabs_reader_unittest.cc + +src/common/src_common_dumper_unittest-stabs_reader_unittest.obj: src/common/stabs_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_reader_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Tpo -c -o src/common/src_common_dumper_unittest-stabs_reader_unittest.obj `if test -f 'src/common/stabs_reader_unittest.cc'; then $(CYGPATH_W) 'src/common/stabs_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader_unittest.cc' object='src/common/src_common_dumper_unittest-stabs_reader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_reader_unittest.obj `if test -f 'src/common/stabs_reader_unittest.cc'; then $(CYGPATH_W) 'src/common/stabs_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-stabs_to_module.o: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Tpo -c -o src/common/src_common_dumper_unittest-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_common_dumper_unittest-stabs_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc + +src/common/src_common_dumper_unittest-stabs_to_module.obj: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Tpo -c -o src/common/src_common_dumper_unittest-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_common_dumper_unittest-stabs_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` + +src/common/src_common_dumper_unittest-stabs_to_module_unittest.o: src/common/stabs_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_to_module_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-stabs_to_module_unittest.o `test -f 'src/common/stabs_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/stabs_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-stabs_to_module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_to_module_unittest.o `test -f 'src/common/stabs_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/stabs_to_module_unittest.cc + +src/common/src_common_dumper_unittest-stabs_to_module_unittest.obj: src/common/stabs_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-stabs_to_module_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Tpo -c -o src/common/src_common_dumper_unittest-stabs_to_module_unittest.obj `if test -f 'src/common/stabs_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-stabs_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module_unittest.cc' object='src/common/src_common_dumper_unittest-stabs_to_module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-stabs_to_module_unittest.obj `if test -f 'src/common/stabs_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module_unittest.cc'; fi` + +src/common/src_common_dumper_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo -c -o src/common/src_common_dumper_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_dumper_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_common_dumper_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_dumper_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo -c -o src/common/src_common_dumper_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_dumper_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_dumper_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_dumper_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-bytereader.o: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-bytereader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc + +src/common/dwarf/src_common_dumper_unittest-bytereader.obj: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-bytereader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.o: src/common/dwarf/bytereader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.o `test -f 'src/common/dwarf/bytereader_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.o `test -f 'src/common/dwarf/bytereader_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader_unittest.cc + +src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.obj: src/common/dwarf/bytereader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.obj `if test -f 'src/common/dwarf/bytereader_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-bytereader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-bytereader_unittest.obj `if test -f 'src/common/dwarf/bytereader_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader_unittest.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-cfi_assembler.o: src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-cfi_assembler.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-cfi_assembler.o `test -f 'src/common/dwarf/cfi_assembler.cc' || echo '$(srcdir)/'`src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/cfi_assembler.cc' object='src/common/dwarf/src_common_dumper_unittest-cfi_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-cfi_assembler.o `test -f 'src/common/dwarf/cfi_assembler.cc' || echo '$(srcdir)/'`src/common/dwarf/cfi_assembler.cc + +src/common/dwarf/src_common_dumper_unittest-cfi_assembler.obj: src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-cfi_assembler.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-cfi_assembler.obj `if test -f 'src/common/dwarf/cfi_assembler.cc'; then $(CYGPATH_W) 'src/common/dwarf/cfi_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/cfi_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-cfi_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/cfi_assembler.cc' object='src/common/dwarf/src_common_dumper_unittest-cfi_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-cfi_assembler.obj `if test -f 'src/common/dwarf/cfi_assembler.cc'; then $(CYGPATH_W) 'src/common/dwarf/cfi_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/cfi_assembler.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.o: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc + +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.obj: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.o: src/common/dwarf/dwarf2diehandler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.o `test -f 'src/common/dwarf/dwarf2diehandler_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.o `test -f 'src/common/dwarf/dwarf2diehandler_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler_unittest.cc + +src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.obj: src/common/dwarf/dwarf2diehandler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.obj `if test -f 'src/common/dwarf/dwarf2diehandler_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2diehandler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2diehandler_unittest.obj `if test -f 'src/common/dwarf/dwarf2diehandler_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler_unittest.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader.o: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader.obj: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-elf_reader.o: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-elf_reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_common_dumper_unittest-elf_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc + +src/common/dwarf/src_common_dumper_unittest-elf_reader.obj: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-elf_reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_common_dumper_unittest-elf_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.o: src/common/dwarf/dwarf2reader_cfi_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.o `test -f 'src/common/dwarf/dwarf2reader_cfi_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader_cfi_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader_cfi_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.o `test -f 'src/common/dwarf/dwarf2reader_cfi_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader_cfi_unittest.cc + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.obj: src/common/dwarf/dwarf2reader_cfi_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.obj `if test -f 'src/common/dwarf/dwarf2reader_cfi_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader_cfi_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader_cfi_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_cfi_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader_cfi_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.obj `if test -f 'src/common/dwarf/dwarf2reader_cfi_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader_cfi_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader_cfi_unittest.cc'; fi` + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.o: src/common/dwarf/dwarf2reader_die_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.o `test -f 'src/common/dwarf/dwarf2reader_die_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader_die_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader_die_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.o `test -f 'src/common/dwarf/dwarf2reader_die_unittest.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader_die_unittest.cc + +src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.obj: src/common/dwarf/dwarf2reader_die_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Tpo -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.obj `if test -f 'src/common/dwarf/dwarf2reader_die_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader_die_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader_die_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Tpo src/common/dwarf/$(DEPDIR)/src_common_dumper_unittest-dwarf2reader_die_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader_die_unittest.cc' object='src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_dumper_unittest-dwarf2reader_die_unittest.obj `if test -f 'src/common/dwarf/dwarf2reader_die_unittest.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader_die_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader_die_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-crc32.o: src/common/linux/crc32.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-crc32.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Tpo -c -o src/common/linux/src_common_dumper_unittest-crc32.o `test -f 'src/common/linux/crc32.cc' || echo '$(srcdir)/'`src/common/linux/crc32.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/crc32.cc' object='src/common/linux/src_common_dumper_unittest-crc32.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-crc32.o `test -f 'src/common/linux/crc32.cc' || echo '$(srcdir)/'`src/common/linux/crc32.cc + +src/common/linux/src_common_dumper_unittest-crc32.obj: src/common/linux/crc32.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-crc32.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Tpo -c -o src/common/linux/src_common_dumper_unittest-crc32.obj `if test -f 'src/common/linux/crc32.cc'; then $(CYGPATH_W) 'src/common/linux/crc32.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/crc32.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-crc32.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/crc32.cc' object='src/common/linux/src_common_dumper_unittest-crc32.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-crc32.obj `if test -f 'src/common/linux/crc32.cc'; then $(CYGPATH_W) 'src/common/linux/crc32.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/crc32.cc'; fi` + +src/common/linux/src_common_dumper_unittest-dump_symbols.o: src/common/linux/dump_symbols.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols.o `test -f 'src/common/linux/dump_symbols.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/dump_symbols.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols.o `test -f 'src/common/linux/dump_symbols.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols.cc + +src/common/linux/src_common_dumper_unittest-dump_symbols.obj: src/common/linux/dump_symbols.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols.obj `if test -f 'src/common/linux/dump_symbols.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/dump_symbols.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols.obj `if test -f 'src/common/linux/dump_symbols.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols.cc'; fi` + +src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o: src/common/linux/dump_symbols_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o `test -f 'src/common/linux/dump_symbols_unittest.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/dump_symbols_unittest.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o `test -f 'src/common/linux/dump_symbols_unittest.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols_unittest.cc + +src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj: src/common/linux/dump_symbols_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj `if test -f 'src/common/linux/dump_symbols_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/dump_symbols_unittest.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj `if test -f 'src/common/linux/dump_symbols_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-elf_core_dump.o: src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_core_dump.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump.o `test -f 'src/common/linux/elf_core_dump.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump.cc' object='src/common/linux/src_common_dumper_unittest-elf_core_dump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump.o `test -f 'src/common/linux/elf_core_dump.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump.cc + +src/common/linux/src_common_dumper_unittest-elf_core_dump.obj: src/common/linux/elf_core_dump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_core_dump.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump.obj `if test -f 'src/common/linux/elf_core_dump.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump.cc' object='src/common/linux/src_common_dumper_unittest-elf_core_dump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump.obj `if test -f 'src/common/linux/elf_core_dump.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump.cc'; fi` + +src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.o: src/common/linux/elf_core_dump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.o `test -f 'src/common/linux/elf_core_dump_unittest.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump_unittest.cc' object='src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.o `test -f 'src/common/linux/elf_core_dump_unittest.cc' || echo '$(srcdir)/'`src/common/linux/elf_core_dump_unittest.cc + +src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.obj: src/common/linux/elf_core_dump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.obj `if test -f 'src/common/linux/elf_core_dump_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_core_dump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_core_dump_unittest.cc' object='src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_core_dump_unittest.obj `if test -f 'src/common/linux/elf_core_dump_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/elf_core_dump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_core_dump_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o: src/common/linux/elf_symbols_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o `test -f 'src/common/linux/elf_symbols_to_module.cc' || echo '$(srcdir)/'`src/common/linux/elf_symbols_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_symbols_to_module.cc' object='src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o `test -f 'src/common/linux/elf_symbols_to_module.cc' || echo '$(srcdir)/'`src/common/linux/elf_symbols_to_module.cc + +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.obj: src/common/linux/elf_symbols_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.obj `if test -f 'src/common/linux/elf_symbols_to_module.cc'; then $(CYGPATH_W) 'src/common/linux/elf_symbols_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_symbols_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_symbols_to_module.cc' object='src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.obj `if test -f 'src/common/linux/elf_symbols_to_module.cc'; then $(CYGPATH_W) 'src/common/linux/elf_symbols_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_symbols_to_module.cc'; fi` + +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.o: src/common/linux/elf_symbols_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.o `test -f 'src/common/linux/elf_symbols_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/linux/elf_symbols_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_symbols_to_module_unittest.cc' object='src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.o `test -f 'src/common/linux/elf_symbols_to_module_unittest.cc' || echo '$(srcdir)/'`src/common/linux/elf_symbols_to_module_unittest.cc + +src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj: src/common/linux/elf_symbols_to_module_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj `if test -f 'src/common/linux/elf_symbols_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/elf_symbols_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_symbols_to_module_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elf_symbols_to_module_unittest.cc' object='src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj `if test -f 'src/common/linux/elf_symbols_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/elf_symbols_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_symbols_to_module_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-elfutils.o: src/common/linux/elfutils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elfutils.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Tpo -c -o src/common/linux/src_common_dumper_unittest-elfutils.o `test -f 'src/common/linux/elfutils.cc' || echo '$(srcdir)/'`src/common/linux/elfutils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elfutils.cc' object='src/common/linux/src_common_dumper_unittest-elfutils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elfutils.o `test -f 'src/common/linux/elfutils.cc' || echo '$(srcdir)/'`src/common/linux/elfutils.cc + +src/common/linux/src_common_dumper_unittest-elfutils.obj: src/common/linux/elfutils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elfutils.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Tpo -c -o src/common/linux/src_common_dumper_unittest-elfutils.obj `if test -f 'src/common/linux/elfutils.cc'; then $(CYGPATH_W) 'src/common/linux/elfutils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elfutils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elfutils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/elfutils.cc' object='src/common/linux/src_common_dumper_unittest-elfutils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elfutils.obj `if test -f 'src/common/linux/elfutils.cc'; then $(CYGPATH_W) 'src/common/linux/elfutils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elfutils.cc'; fi` + +src/common/linux/src_common_dumper_unittest-file_id.o: src/common/linux/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-file_id.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo -c -o src/common/linux/src_common_dumper_unittest-file_id.o `test -f 'src/common/linux/file_id.cc' || echo '$(srcdir)/'`src/common/linux/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/file_id.cc' object='src/common/linux/src_common_dumper_unittest-file_id.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-file_id.o `test -f 'src/common/linux/file_id.cc' || echo '$(srcdir)/'`src/common/linux/file_id.cc + +src/common/linux/src_common_dumper_unittest-file_id.obj: src/common/linux/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-file_id.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo -c -o src/common/linux/src_common_dumper_unittest-file_id.obj `if test -f 'src/common/linux/file_id.cc'; then $(CYGPATH_W) 'src/common/linux/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/file_id.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/file_id.cc' object='src/common/linux/src_common_dumper_unittest-file_id.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-file_id.obj `if test -f 'src/common/linux/file_id.cc'; then $(CYGPATH_W) 'src/common/linux/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/file_id.cc'; fi` + +src/common/linux/src_common_dumper_unittest-file_id_unittest.o: src/common/linux/file_id_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-file_id_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-file_id_unittest.o `test -f 'src/common/linux/file_id_unittest.cc' || echo '$(srcdir)/'`src/common/linux/file_id_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/file_id_unittest.cc' object='src/common/linux/src_common_dumper_unittest-file_id_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-file_id_unittest.o `test -f 'src/common/linux/file_id_unittest.cc' || echo '$(srcdir)/'`src/common/linux/file_id_unittest.cc + +src/common/linux/src_common_dumper_unittest-file_id_unittest.obj: src/common/linux/file_id_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-file_id_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-file_id_unittest.obj `if test -f 'src/common/linux/file_id_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/file_id_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/file_id_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/file_id_unittest.cc' object='src/common/linux/src_common_dumper_unittest-file_id_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-file_id_unittest.obj `if test -f 'src/common/linux/file_id_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/file_id_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/file_id_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-linux_libc_support.o: src/common/linux/linux_libc_support.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-linux_libc_support.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Tpo -c -o src/common/linux/src_common_dumper_unittest-linux_libc_support.o `test -f 'src/common/linux/linux_libc_support.cc' || echo '$(srcdir)/'`src/common/linux/linux_libc_support.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/linux_libc_support.cc' object='src/common/linux/src_common_dumper_unittest-linux_libc_support.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-linux_libc_support.o `test -f 'src/common/linux/linux_libc_support.cc' || echo '$(srcdir)/'`src/common/linux/linux_libc_support.cc + +src/common/linux/src_common_dumper_unittest-linux_libc_support.obj: src/common/linux/linux_libc_support.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-linux_libc_support.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Tpo -c -o src/common/linux/src_common_dumper_unittest-linux_libc_support.obj `if test -f 'src/common/linux/linux_libc_support.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-linux_libc_support.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/linux_libc_support.cc' object='src/common/linux/src_common_dumper_unittest-linux_libc_support.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-linux_libc_support.obj `if test -f 'src/common/linux/linux_libc_support.cc'; then $(CYGPATH_W) 'src/common/linux/linux_libc_support.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/linux_libc_support.cc'; fi` + +src/common/linux/src_common_dumper_unittest-memory_mapped_file.o: src/common/linux/memory_mapped_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-memory_mapped_file.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Tpo -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file.o `test -f 'src/common/linux/memory_mapped_file.cc' || echo '$(srcdir)/'`src/common/linux/memory_mapped_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/memory_mapped_file.cc' object='src/common/linux/src_common_dumper_unittest-memory_mapped_file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file.o `test -f 'src/common/linux/memory_mapped_file.cc' || echo '$(srcdir)/'`src/common/linux/memory_mapped_file.cc + +src/common/linux/src_common_dumper_unittest-memory_mapped_file.obj: src/common/linux/memory_mapped_file.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-memory_mapped_file.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Tpo -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file.obj `if test -f 'src/common/linux/memory_mapped_file.cc'; then $(CYGPATH_W) 'src/common/linux/memory_mapped_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/memory_mapped_file.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/memory_mapped_file.cc' object='src/common/linux/src_common_dumper_unittest-memory_mapped_file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file.obj `if test -f 'src/common/linux/memory_mapped_file.cc'; then $(CYGPATH_W) 'src/common/linux/memory_mapped_file.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/memory_mapped_file.cc'; fi` + +src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.o: src/common/linux/memory_mapped_file_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.o `test -f 'src/common/linux/memory_mapped_file_unittest.cc' || echo '$(srcdir)/'`src/common/linux/memory_mapped_file_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/memory_mapped_file_unittest.cc' object='src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.o `test -f 'src/common/linux/memory_mapped_file_unittest.cc' || echo '$(srcdir)/'`src/common/linux/memory_mapped_file_unittest.cc + +src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.obj: src/common/linux/memory_mapped_file_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.obj `if test -f 'src/common/linux/memory_mapped_file_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/memory_mapped_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/memory_mapped_file_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-memory_mapped_file_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/memory_mapped_file_unittest.cc' object='src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-memory_mapped_file_unittest.obj `if test -f 'src/common/linux/memory_mapped_file_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/memory_mapped_file_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/memory_mapped_file_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-safe_readlink.o: src/common/linux/safe_readlink.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-safe_readlink.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Tpo -c -o src/common/linux/src_common_dumper_unittest-safe_readlink.o `test -f 'src/common/linux/safe_readlink.cc' || echo '$(srcdir)/'`src/common/linux/safe_readlink.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/safe_readlink.cc' object='src/common/linux/src_common_dumper_unittest-safe_readlink.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-safe_readlink.o `test -f 'src/common/linux/safe_readlink.cc' || echo '$(srcdir)/'`src/common/linux/safe_readlink.cc + +src/common/linux/src_common_dumper_unittest-safe_readlink.obj: src/common/linux/safe_readlink.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-safe_readlink.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Tpo -c -o src/common/linux/src_common_dumper_unittest-safe_readlink.obj `if test -f 'src/common/linux/safe_readlink.cc'; then $(CYGPATH_W) 'src/common/linux/safe_readlink.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/safe_readlink.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/safe_readlink.cc' object='src/common/linux/src_common_dumper_unittest-safe_readlink.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-safe_readlink.obj `if test -f 'src/common/linux/safe_readlink.cc'; then $(CYGPATH_W) 'src/common/linux/safe_readlink.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/safe_readlink.cc'; fi` + +src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.o: src/common/linux/safe_readlink_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.o `test -f 'src/common/linux/safe_readlink_unittest.cc' || echo '$(srcdir)/'`src/common/linux/safe_readlink_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/safe_readlink_unittest.cc' object='src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.o `test -f 'src/common/linux/safe_readlink_unittest.cc' || echo '$(srcdir)/'`src/common/linux/safe_readlink_unittest.cc + +src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.obj: src/common/linux/safe_readlink_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.obj `if test -f 'src/common/linux/safe_readlink_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/safe_readlink_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/safe_readlink_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-safe_readlink_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/safe_readlink_unittest.cc' object='src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-safe_readlink_unittest.obj `if test -f 'src/common/linux/safe_readlink_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/safe_readlink_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/safe_readlink_unittest.cc'; fi` + +src/common/linux/src_common_dumper_unittest-synth_elf.o: src/common/linux/synth_elf.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf.o `test -f 'src/common/linux/synth_elf.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/synth_elf.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf.o `test -f 'src/common/linux/synth_elf.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf.cc + +src/common/linux/src_common_dumper_unittest-synth_elf.obj: src/common/linux/synth_elf.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf.obj `if test -f 'src/common/linux/synth_elf.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/synth_elf.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf.obj `if test -f 'src/common/linux/synth_elf.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf.cc'; fi` + +src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o: src/common/linux/synth_elf_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o `test -f 'src/common/linux/synth_elf_unittest.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/synth_elf_unittest.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o `test -f 'src/common/linux/synth_elf_unittest.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf_unittest.cc + +src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj: src/common/linux/synth_elf_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj `if test -f 'src/common/linux/synth_elf_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/synth_elf_unittest.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj `if test -f 'src/common/linux/synth_elf_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf_unittest.cc'; fi` + +src/common/linux/tests/src_common_dumper_unittest-crash_generator.o: src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_common_dumper_unittest-crash_generator.o -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Tpo -c -o src/common/linux/tests/src_common_dumper_unittest-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_common_dumper_unittest-crash_generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_common_dumper_unittest-crash_generator.o `test -f 'src/common/linux/tests/crash_generator.cc' || echo '$(srcdir)/'`src/common/linux/tests/crash_generator.cc + +src/common/linux/tests/src_common_dumper_unittest-crash_generator.obj: src/common/linux/tests/crash_generator.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/tests/src_common_dumper_unittest-crash_generator.obj -MD -MP -MF src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Tpo -c -o src/common/linux/tests/src_common_dumper_unittest-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Tpo src/common/linux/tests/$(DEPDIR)/src_common_dumper_unittest-crash_generator.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/linux/tests/crash_generator.cc' object='src/common/linux/tests/src_common_dumper_unittest-crash_generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/tests/src_common_dumper_unittest-crash_generator.obj `if test -f 'src/common/linux/tests/crash_generator.cc'; then $(CYGPATH_W) 'src/common/linux/tests/crash_generator.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/tests/crash_generator.cc'; fi` + +src/common/tests/src_common_dumper_unittest-file_utils.o: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_common_dumper_unittest-file_utils.o -MD -MP -MF src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Tpo -c -o src/common/tests/src_common_dumper_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_common_dumper_unittest-file_utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_common_dumper_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc + +src/common/tests/src_common_dumper_unittest-file_utils.obj: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_common_dumper_unittest-file_utils.obj -MD -MP -MF src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Tpo -c -o src/common/tests/src_common_dumper_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_common_dumper_unittest-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_common_dumper_unittest-file_utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_common_dumper_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.o: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc + +src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.obj: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.o: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc + +src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.obj: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.o: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc + +src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.obj: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-language.o: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-language.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_common_mac_macho_reader_unittest-language.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc + +src/common/src_common_mac_macho_reader_unittest-language.obj: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-language.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_common_mac_macho_reader_unittest-language.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-md5.o: src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-md5.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-md5.o `test -f 'src/common/md5.cc' || echo '$(srcdir)/'`src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/md5.cc' object='src/common/src_common_mac_macho_reader_unittest-md5.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-md5.o `test -f 'src/common/md5.cc' || echo '$(srcdir)/'`src/common/md5.cc + +src/common/src_common_mac_macho_reader_unittest-md5.obj: src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-md5.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-md5.obj `if test -f 'src/common/md5.cc'; then $(CYGPATH_W) 'src/common/md5.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/md5.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-md5.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/md5.cc' object='src/common/src_common_mac_macho_reader_unittest-md5.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-md5.obj `if test -f 'src/common/md5.cc'; then $(CYGPATH_W) 'src/common/md5.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/md5.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-module.o: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_common_mac_macho_reader_unittest-module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc + +src/common/src_common_mac_macho_reader_unittest-module.obj: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_common_mac_macho_reader_unittest-module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-stabs_reader.o: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-stabs_reader.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_common_mac_macho_reader_unittest-stabs_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc + +src/common/src_common_mac_macho_reader_unittest-stabs_reader.obj: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-stabs_reader.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_common_mac_macho_reader_unittest-stabs_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-stabs_to_module.o: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-stabs_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-stabs_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc + +src/common/src_common_mac_macho_reader_unittest-stabs_to_module.obj: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-stabs_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_common_mac_macho_reader_unittest-stabs_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` + +src/common/src_common_mac_macho_reader_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_mac_macho_reader_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_common_mac_macho_reader_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_mac_macho_reader_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Tpo -c -o src/common/src_common_mac_macho_reader_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_mac_macho_reader_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_mac_macho_reader_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_mac_macho_reader_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.o: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc + +src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.obj: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` + +src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.o: src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.o `test -f 'src/common/dwarf/cfi_assembler.cc' || echo '$(srcdir)/'`src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/cfi_assembler.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.o `test -f 'src/common/dwarf/cfi_assembler.cc' || echo '$(srcdir)/'`src/common/dwarf/cfi_assembler.cc + +src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.obj: src/common/dwarf/cfi_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.obj `if test -f 'src/common/dwarf/cfi_assembler.cc'; then $(CYGPATH_W) 'src/common/dwarf/cfi_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/cfi_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-cfi_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/cfi_assembler.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-cfi_assembler.obj `if test -f 'src/common/dwarf/cfi_assembler.cc'; then $(CYGPATH_W) 'src/common/dwarf/cfi_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/cfi_assembler.cc'; fi` + +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.o: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc + +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.obj: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` + +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.o: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc + +src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.obj: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` + +src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.o: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc + +src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.obj: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Tpo -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_common_mac_macho_reader_unittest-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_common_mac_macho_reader_unittest-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.o: src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.o `test -f 'src/common/mac/arch_utilities.cc' || echo '$(srcdir)/'`src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/arch_utilities.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.o `test -f 'src/common/mac/arch_utilities.cc' || echo '$(srcdir)/'`src/common/mac/arch_utilities.cc + +src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.obj: src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.obj `if test -f 'src/common/mac/arch_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/arch_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/arch_utilities.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-arch_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/arch_utilities.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-arch_utilities.obj `if test -f 'src/common/mac/arch_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/arch_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/arch_utilities.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-file_id.o: src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-file_id.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-file_id.o `test -f 'src/common/mac/file_id.cc' || echo '$(srcdir)/'`src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/file_id.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-file_id.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-file_id.o `test -f 'src/common/mac/file_id.cc' || echo '$(srcdir)/'`src/common/mac/file_id.cc + +src/common/mac/src_common_mac_macho_reader_unittest-file_id.obj: src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-file_id.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-file_id.obj `if test -f 'src/common/mac/file_id.cc'; then $(CYGPATH_W) 'src/common/mac/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/file_id.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/file_id.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-file_id.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-file_id.obj `if test -f 'src/common/mac/file_id.cc'; then $(CYGPATH_W) 'src/common/mac/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/file_id.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-macho_id.o: src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_id.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_id.o `test -f 'src/common/mac/macho_id.cc' || echo '$(srcdir)/'`src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_id.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_id.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_id.o `test -f 'src/common/mac/macho_id.cc' || echo '$(srcdir)/'`src/common/mac/macho_id.cc + +src/common/mac/src_common_mac_macho_reader_unittest-macho_id.obj: src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_id.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_id.obj `if test -f 'src/common/mac/macho_id.cc'; then $(CYGPATH_W) 'src/common/mac/macho_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_id.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_id.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_id.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_id.obj `if test -f 'src/common/mac/macho_id.cc'; then $(CYGPATH_W) 'src/common/mac/macho_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_id.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.o: src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.o `test -f 'src/common/mac/macho_reader.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.o `test -f 'src/common/mac/macho_reader.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader.cc + +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.obj: src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.obj `if test -f 'src/common/mac/macho_reader.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader.obj `if test -f 'src/common/mac/macho_reader.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.o: src/common/mac/macho_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.o `test -f 'src/common/mac/macho_reader_unittest.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader_unittest.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.o `test -f 'src/common/mac/macho_reader_unittest.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader_unittest.cc + +src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.obj: src/common/mac/macho_reader_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.obj `if test -f 'src/common/mac/macho_reader_unittest.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_reader_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader_unittest.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_reader_unittest.obj `if test -f 'src/common/mac/macho_reader_unittest.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader_unittest.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.o: src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.o `test -f 'src/common/mac/macho_utilities.cc' || echo '$(srcdir)/'`src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_utilities.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.o `test -f 'src/common/mac/macho_utilities.cc' || echo '$(srcdir)/'`src/common/mac/macho_utilities.cc + +src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.obj: src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.obj `if test -f 'src/common/mac/macho_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/macho_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_utilities.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_utilities.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_utilities.obj `if test -f 'src/common/mac/macho_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/macho_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_utilities.cc'; fi` + +src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.o: src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.o `test -f 'src/common/mac/macho_walker.cc' || echo '$(srcdir)/'`src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_walker.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.o `test -f 'src/common/mac/macho_walker.cc' || echo '$(srcdir)/'`src/common/mac/macho_walker.cc + +src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.obj: src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Tpo -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.obj `if test -f 'src/common/mac/macho_walker.cc'; then $(CYGPATH_W) 'src/common/mac/macho_walker.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_walker.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Tpo src/common/mac/$(DEPDIR)/src_common_mac_macho_reader_unittest-macho_walker.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_walker.cc' object='src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_common_mac_macho_reader_unittest-macho_walker.obj `if test -f 'src/common/mac/macho_walker.cc'; then $(CYGPATH_W) 'src/common/mac/macho_walker.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_walker.cc'; fi` + +src/common/tests/src_common_mac_macho_reader_unittest-file_utils.o: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_common_mac_macho_reader_unittest-file_utils.o -MD -MP -MF src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Tpo -c -o src/common/tests/src_common_mac_macho_reader_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_common_mac_macho_reader_unittest-file_utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_common_mac_macho_reader_unittest-file_utils.o `test -f 'src/common/tests/file_utils.cc' || echo '$(srcdir)/'`src/common/tests/file_utils.cc + +src/common/tests/src_common_mac_macho_reader_unittest-file_utils.obj: src/common/tests/file_utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/tests/src_common_mac_macho_reader_unittest-file_utils.obj -MD -MP -MF src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Tpo -c -o src/common/tests/src_common_mac_macho_reader_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Tpo src/common/tests/$(DEPDIR)/src_common_mac_macho_reader_unittest-file_utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/tests/file_utils.cc' object='src/common/tests/src_common_mac_macho_reader_unittest-file_utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_mac_macho_reader_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/tests/src_common_mac_macho_reader_unittest-file_utils.obj `if test -f 'src/common/tests/file_utils.cc'; then $(CYGPATH_W) 'src/common/tests/file_utils.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/tests/file_utils.cc'; fi` + +src/common/src_common_test_assembler_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_test_assembler_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Tpo -c -o src/common/src_common_test_assembler_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_test_assembler_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_test_assembler_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_common_test_assembler_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_test_assembler_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Tpo -c -o src/common/src_common_test_assembler_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_common_test_assembler_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_test_assembler_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/common/src_common_test_assembler_unittest-test_assembler_unittest.o: src/common/test_assembler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_test_assembler_unittest-test_assembler_unittest.o -MD -MP -MF src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Tpo -c -o src/common/src_common_test_assembler_unittest-test_assembler_unittest.o `test -f 'src/common/test_assembler_unittest.cc' || echo '$(srcdir)/'`src/common/test_assembler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Tpo src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler_unittest.cc' object='src/common/src_common_test_assembler_unittest-test_assembler_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_test_assembler_unittest-test_assembler_unittest.o `test -f 'src/common/test_assembler_unittest.cc' || echo '$(srcdir)/'`src/common/test_assembler_unittest.cc + +src/common/src_common_test_assembler_unittest-test_assembler_unittest.obj: src/common/test_assembler_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_common_test_assembler_unittest-test_assembler_unittest.obj -MD -MP -MF src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Tpo -c -o src/common/src_common_test_assembler_unittest-test_assembler_unittest.obj `if test -f 'src/common/test_assembler_unittest.cc'; then $(CYGPATH_W) 'src/common/test_assembler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Tpo src/common/$(DEPDIR)/src_common_test_assembler_unittest-test_assembler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler_unittest.cc' object='src/common/src_common_test_assembler_unittest-test_assembler_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_test_assembler_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_common_test_assembler_unittest-test_assembler_unittest.obj `if test -f 'src/common/test_assembler_unittest.cc'; then $(CYGPATH_W) 'src/common/test_assembler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler_unittest.cc'; fi` + +src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.o: src/processor/basic_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_basic_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Tpo -c -o src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.o `test -f 'src/processor/basic_source_line_resolver_unittest.cc' || echo '$(srcdir)/'`src/processor/basic_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Tpo src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/basic_source_line_resolver_unittest.cc' object='src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_basic_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.o `test -f 'src/processor/basic_source_line_resolver_unittest.cc' || echo '$(srcdir)/'`src/processor/basic_source_line_resolver_unittest.cc + +src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.obj: src/processor/basic_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_basic_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Tpo -c -o src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.obj `if test -f 'src/processor/basic_source_line_resolver_unittest.cc'; then $(CYGPATH_W) 'src/processor/basic_source_line_resolver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/basic_source_line_resolver_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Tpo src/processor/$(DEPDIR)/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/basic_source_line_resolver_unittest.cc' object='src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_basic_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_basic_source_line_resolver_unittest-basic_source_line_resolver_unittest.obj `if test -f 'src/processor/basic_source_line_resolver_unittest.cc'; then $(CYGPATH_W) 'src/processor/basic_source_line_resolver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/basic_source_line_resolver_unittest.cc'; fi` + +src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.o: src/processor/cfi_frame_info_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_cfi_frame_info_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Tpo -c -o src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.o `test -f 'src/processor/cfi_frame_info_unittest.cc' || echo '$(srcdir)/'`src/processor/cfi_frame_info_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Tpo src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/cfi_frame_info_unittest.cc' object='src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_cfi_frame_info_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.o `test -f 'src/processor/cfi_frame_info_unittest.cc' || echo '$(srcdir)/'`src/processor/cfi_frame_info_unittest.cc + +src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.obj: src/processor/cfi_frame_info_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_cfi_frame_info_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Tpo -c -o src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.obj `if test -f 'src/processor/cfi_frame_info_unittest.cc'; then $(CYGPATH_W) 'src/processor/cfi_frame_info_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/cfi_frame_info_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Tpo src/processor/$(DEPDIR)/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/cfi_frame_info_unittest.cc' object='src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_cfi_frame_info_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_cfi_frame_info_unittest-cfi_frame_info_unittest.obj `if test -f 'src/processor/cfi_frame_info_unittest.cc'; then $(CYGPATH_W) 'src/processor/cfi_frame_info_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/cfi_frame_info_unittest.cc'; fi` + +src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.o: src/processor/disassembler_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Tpo -c -o src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.o `test -f 'src/processor/disassembler_x86_unittest.cc' || echo '$(srcdir)/'`src/processor/disassembler_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Tpo src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/disassembler_x86_unittest.cc' object='src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.o `test -f 'src/processor/disassembler_x86_unittest.cc' || echo '$(srcdir)/'`src/processor/disassembler_x86_unittest.cc + +src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.obj: src/processor/disassembler_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Tpo -c -o src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.obj `if test -f 'src/processor/disassembler_x86_unittest.cc'; then $(CYGPATH_W) 'src/processor/disassembler_x86_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/disassembler_x86_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Tpo src/processor/$(DEPDIR)/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/disassembler_x86_unittest.cc' object='src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_disassembler_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_disassembler_x86_unittest-disassembler_x86_unittest.obj `if test -f 'src/processor/disassembler_x86_unittest.cc'; then $(CYGPATH_W) 'src/processor/disassembler_x86_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/disassembler_x86_unittest.cc'; fi` + +src/processor/src_processor_exploitability_unittest-exploitability_unittest.o: src/processor/exploitability_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_exploitability_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_exploitability_unittest-exploitability_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Tpo -c -o src/processor/src_processor_exploitability_unittest-exploitability_unittest.o `test -f 'src/processor/exploitability_unittest.cc' || echo '$(srcdir)/'`src/processor/exploitability_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Tpo src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/exploitability_unittest.cc' object='src/processor/src_processor_exploitability_unittest-exploitability_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_exploitability_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_exploitability_unittest-exploitability_unittest.o `test -f 'src/processor/exploitability_unittest.cc' || echo '$(srcdir)/'`src/processor/exploitability_unittest.cc + +src/processor/src_processor_exploitability_unittest-exploitability_unittest.obj: src/processor/exploitability_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_exploitability_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_exploitability_unittest-exploitability_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Tpo -c -o src/processor/src_processor_exploitability_unittest-exploitability_unittest.obj `if test -f 'src/processor/exploitability_unittest.cc'; then $(CYGPATH_W) 'src/processor/exploitability_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/exploitability_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Tpo src/processor/$(DEPDIR)/src_processor_exploitability_unittest-exploitability_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/exploitability_unittest.cc' object='src/processor/src_processor_exploitability_unittest-exploitability_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_exploitability_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_exploitability_unittest-exploitability_unittest.obj `if test -f 'src/processor/exploitability_unittest.cc'; then $(CYGPATH_W) 'src/processor/exploitability_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/exploitability_unittest.cc'; fi` + +src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.o: src/processor/fast_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_fast_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Tpo -c -o src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.o `test -f 'src/processor/fast_source_line_resolver_unittest.cc' || echo '$(srcdir)/'`src/processor/fast_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Tpo src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/fast_source_line_resolver_unittest.cc' object='src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_fast_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.o `test -f 'src/processor/fast_source_line_resolver_unittest.cc' || echo '$(srcdir)/'`src/processor/fast_source_line_resolver_unittest.cc + +src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.obj: src/processor/fast_source_line_resolver_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_fast_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Tpo -c -o src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.obj `if test -f 'src/processor/fast_source_line_resolver_unittest.cc'; then $(CYGPATH_W) 'src/processor/fast_source_line_resolver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/fast_source_line_resolver_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Tpo src/processor/$(DEPDIR)/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/fast_source_line_resolver_unittest.cc' object='src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_fast_source_line_resolver_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_fast_source_line_resolver_unittest-fast_source_line_resolver_unittest.obj `if test -f 'src/processor/fast_source_line_resolver_unittest.cc'; then $(CYGPATH_W) 'src/processor/fast_source_line_resolver_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/fast_source_line_resolver_unittest.cc'; fi` + +src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.o: src/processor/map_serializers_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_map_serializers_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Tpo -c -o src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.o `test -f 'src/processor/map_serializers_unittest.cc' || echo '$(srcdir)/'`src/processor/map_serializers_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Tpo src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/map_serializers_unittest.cc' object='src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_map_serializers_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.o `test -f 'src/processor/map_serializers_unittest.cc' || echo '$(srcdir)/'`src/processor/map_serializers_unittest.cc + +src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.obj: src/processor/map_serializers_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_map_serializers_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Tpo -c -o src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.obj `if test -f 'src/processor/map_serializers_unittest.cc'; then $(CYGPATH_W) 'src/processor/map_serializers_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/map_serializers_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Tpo src/processor/$(DEPDIR)/src_processor_map_serializers_unittest-map_serializers_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/map_serializers_unittest.cc' object='src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_map_serializers_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_map_serializers_unittest-map_serializers_unittest.obj `if test -f 'src/processor/map_serializers_unittest.cc'; then $(CYGPATH_W) 'src/processor/map_serializers_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/map_serializers_unittest.cc'; fi` + +src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.o: src/processor/microdump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_microdump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Tpo -c -o src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.o `test -f 'src/processor/microdump_processor_unittest.cc' || echo '$(srcdir)/'`src/processor/microdump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Tpo src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/microdump_processor_unittest.cc' object='src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_microdump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.o `test -f 'src/processor/microdump_processor_unittest.cc' || echo '$(srcdir)/'`src/processor/microdump_processor_unittest.cc + +src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.obj: src/processor/microdump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_microdump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Tpo -c -o src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.obj `if test -f 'src/processor/microdump_processor_unittest.cc'; then $(CYGPATH_W) 'src/processor/microdump_processor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/microdump_processor_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Tpo src/processor/$(DEPDIR)/src_processor_microdump_processor_unittest-microdump_processor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/microdump_processor_unittest.cc' object='src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_microdump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_microdump_processor_unittest-microdump_processor_unittest.obj `if test -f 'src/processor/microdump_processor_unittest.cc'; then $(CYGPATH_W) 'src/processor/microdump_processor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/microdump_processor_unittest.cc'; fi` + +src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.o: src/processor/minidump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Tpo -c -o src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.o `test -f 'src/processor/minidump_processor_unittest.cc' || echo '$(srcdir)/'`src/processor/minidump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Tpo src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump_processor_unittest.cc' object='src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.o `test -f 'src/processor/minidump_processor_unittest.cc' || echo '$(srcdir)/'`src/processor/minidump_processor_unittest.cc + +src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.obj: src/processor/minidump_processor_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Tpo -c -o src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.obj `if test -f 'src/processor/minidump_processor_unittest.cc'; then $(CYGPATH_W) 'src/processor/minidump_processor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump_processor_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Tpo src/processor/$(DEPDIR)/src_processor_minidump_processor_unittest-minidump_processor_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump_processor_unittest.cc' object='src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_processor_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_processor_unittest-minidump_processor_unittest.obj `if test -f 'src/processor/minidump_processor_unittest.cc'; then $(CYGPATH_W) 'src/processor/minidump_processor_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump_processor_unittest.cc'; fi` + +src/common/src_processor_minidump_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_minidump_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Tpo -c -o src/common/src_processor_minidump_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_minidump_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_minidump_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_minidump_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_minidump_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Tpo -c -o src/common/src_processor_minidump_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_minidump_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_minidump_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_minidump_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_minidump_unittest-minidump_unittest.o: src/processor/minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_unittest-minidump_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Tpo -c -o src/processor/src_processor_minidump_unittest-minidump_unittest.o `test -f 'src/processor/minidump_unittest.cc' || echo '$(srcdir)/'`src/processor/minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Tpo src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump_unittest.cc' object='src/processor/src_processor_minidump_unittest-minidump_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_unittest-minidump_unittest.o `test -f 'src/processor/minidump_unittest.cc' || echo '$(srcdir)/'`src/processor/minidump_unittest.cc + +src/processor/src_processor_minidump_unittest-minidump_unittest.obj: src/processor/minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_unittest-minidump_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Tpo -c -o src/processor/src_processor_minidump_unittest-minidump_unittest.obj `if test -f 'src/processor/minidump_unittest.cc'; then $(CYGPATH_W) 'src/processor/minidump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Tpo src/processor/$(DEPDIR)/src_processor_minidump_unittest-minidump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/minidump_unittest.cc' object='src/processor/src_processor_minidump_unittest-minidump_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_unittest-minidump_unittest.obj `if test -f 'src/processor/minidump_unittest.cc'; then $(CYGPATH_W) 'src/processor/minidump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/minidump_unittest.cc'; fi` + +src/processor/src_processor_minidump_unittest-synth_minidump.o: src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_unittest-synth_minidump.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Tpo -c -o src/processor/src_processor_minidump_unittest-synth_minidump.o `test -f 'src/processor/synth_minidump.cc' || echo '$(srcdir)/'`src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Tpo src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump.cc' object='src/processor/src_processor_minidump_unittest-synth_minidump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_unittest-synth_minidump.o `test -f 'src/processor/synth_minidump.cc' || echo '$(srcdir)/'`src/processor/synth_minidump.cc + +src/processor/src_processor_minidump_unittest-synth_minidump.obj: src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_minidump_unittest-synth_minidump.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Tpo -c -o src/processor/src_processor_minidump_unittest-synth_minidump.obj `if test -f 'src/processor/synth_minidump.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Tpo src/processor/$(DEPDIR)/src_processor_minidump_unittest-synth_minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump.cc' object='src/processor/src_processor_minidump_unittest-synth_minidump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_minidump_unittest-synth_minidump.obj `if test -f 'src/processor/synth_minidump.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump.cc'; fi` + +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.o: src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Tpo -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.o `test -f 'src/processor/proc_maps_linux.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Tpo src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux.cc' object='src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.o `test -f 'src/processor/proc_maps_linux.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux.cc + +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.obj: src/processor/proc_maps_linux.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Tpo -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.obj `if test -f 'src/processor/proc_maps_linux.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Tpo src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux.cc' object='src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux.obj `if test -f 'src/processor/proc_maps_linux.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux.cc'; fi` + +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.o: src/processor/proc_maps_linux_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Tpo -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.o `test -f 'src/processor/proc_maps_linux_unittest.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Tpo src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux_unittest.cc' object='src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.o `test -f 'src/processor/proc_maps_linux_unittest.cc' || echo '$(srcdir)/'`src/processor/proc_maps_linux_unittest.cc + +src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.obj: src/processor/proc_maps_linux_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Tpo -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.obj `if test -f 'src/processor/proc_maps_linux_unittest.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Tpo src/processor/$(DEPDIR)/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/proc_maps_linux_unittest.cc' object='src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_proc_maps_linux_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_proc_maps_linux_unittest-proc_maps_linux_unittest.obj `if test -f 'src/processor/proc_maps_linux_unittest.cc'; then $(CYGPATH_W) 'src/processor/proc_maps_linux_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/proc_maps_linux_unittest.cc'; fi` + +src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.o: src/processor/range_map_shrink_down_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_range_map_shrink_down_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Tpo -c -o src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.o `test -f 'src/processor/range_map_shrink_down_unittest.cc' || echo '$(srcdir)/'`src/processor/range_map_shrink_down_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Tpo src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/range_map_shrink_down_unittest.cc' object='src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_range_map_shrink_down_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.o `test -f 'src/processor/range_map_shrink_down_unittest.cc' || echo '$(srcdir)/'`src/processor/range_map_shrink_down_unittest.cc + +src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.obj: src/processor/range_map_shrink_down_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_range_map_shrink_down_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Tpo -c -o src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.obj `if test -f 'src/processor/range_map_shrink_down_unittest.cc'; then $(CYGPATH_W) 'src/processor/range_map_shrink_down_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/range_map_shrink_down_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Tpo src/processor/$(DEPDIR)/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/range_map_shrink_down_unittest.cc' object='src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_range_map_shrink_down_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_range_map_shrink_down_unittest-range_map_shrink_down_unittest.obj `if test -f 'src/processor/range_map_shrink_down_unittest.cc'; then $(CYGPATH_W) 'src/processor/range_map_shrink_down_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/range_map_shrink_down_unittest.cc'; fi` + +src/common/src_processor_stackwalker_address_list_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_address_list_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_address_list_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_address_list_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_address_list_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_address_list_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_address_list_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_address_list_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_address_list_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_address_list_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.o: src/processor/stackwalker_address_list_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Tpo -c -o src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.o `test -f 'src/processor/stackwalker_address_list_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_address_list_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_address_list_unittest.cc' object='src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.o `test -f 'src/processor/stackwalker_address_list_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_address_list_unittest.cc + +src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.obj: src/processor/stackwalker_address_list_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Tpo -c -o src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.obj `if test -f 'src/processor/stackwalker_address_list_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_address_list_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_address_list_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_address_list_unittest.cc' object='src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_address_list_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_address_list_unittest-stackwalker_address_list_unittest.obj `if test -f 'src/processor/stackwalker_address_list_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_address_list_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_address_list_unittest.cc'; fi` + +src/common/src_processor_stackwalker_amd64_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_amd64_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_amd64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_amd64_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_amd64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_amd64_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_amd64_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_amd64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_amd64_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_amd64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.o: src/processor/stackwalker_amd64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.o `test -f 'src/processor/stackwalker_amd64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_amd64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_amd64_unittest.cc' object='src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.o `test -f 'src/processor/stackwalker_amd64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_amd64_unittest.cc + +src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.obj: src/processor/stackwalker_amd64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.obj `if test -f 'src/processor/stackwalker_amd64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_amd64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_amd64_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_amd64_unittest.cc' object='src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_amd64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_amd64_unittest-stackwalker_amd64_unittest.obj `if test -f 'src/processor/stackwalker_amd64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_amd64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_amd64_unittest.cc'; fi` + +src/common/src_processor_stackwalker_arm64_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_arm64_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_arm64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_arm64_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_arm64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_arm64_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_arm64_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_arm64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_arm64_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_arm64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.o: src/processor/stackwalker_arm64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.o `test -f 'src/processor/stackwalker_arm64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_arm64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_arm64_unittest.cc' object='src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.o `test -f 'src/processor/stackwalker_arm64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_arm64_unittest.cc + +src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.obj: src/processor/stackwalker_arm64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.obj `if test -f 'src/processor/stackwalker_arm64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_arm64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_arm64_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_arm64_unittest.cc' object='src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_arm64_unittest-stackwalker_arm64_unittest.obj `if test -f 'src/processor/stackwalker_arm64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_arm64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_arm64_unittest.cc'; fi` + +src/common/src_processor_stackwalker_arm_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_arm_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_arm_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_arm_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_arm_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_arm_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_arm_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_arm_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_arm_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_arm_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_arm_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.o: src/processor/stackwalker_arm_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Tpo -c -o src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.o `test -f 'src/processor/stackwalker_arm_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_arm_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_arm_unittest.cc' object='src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.o `test -f 'src/processor/stackwalker_arm_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_arm_unittest.cc + +src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.obj: src/processor/stackwalker_arm_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Tpo -c -o src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.obj `if test -f 'src/processor/stackwalker_arm_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_arm_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_arm_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_arm_unittest.cc' object='src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_arm_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_arm_unittest-stackwalker_arm_unittest.obj `if test -f 'src/processor/stackwalker_arm_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_arm_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_arm_unittest.cc'; fi` + +src/common/src_processor_stackwalker_mips64_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_mips64_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_mips64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_mips64_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_mips64_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_mips64_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_mips64_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_mips64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_mips64_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_mips64_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.o: src/processor/stackwalker_mips64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.o `test -f 'src/processor/stackwalker_mips64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_mips64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_mips64_unittest.cc' object='src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.o `test -f 'src/processor/stackwalker_mips64_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_mips64_unittest.cc + +src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.obj: src/processor/stackwalker_mips64_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Tpo -c -o src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.obj `if test -f 'src/processor/stackwalker_mips64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_mips64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_mips64_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_mips64_unittest.cc' object='src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips64_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_mips64_unittest-stackwalker_mips64_unittest.obj `if test -f 'src/processor/stackwalker_mips64_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_mips64_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_mips64_unittest.cc'; fi` + +src/common/src_processor_stackwalker_mips_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_mips_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_mips_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_mips_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_mips_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_mips_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_mips_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_mips_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_mips_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_mips_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_mips_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.o: src/processor/stackwalker_mips_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Tpo -c -o src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.o `test -f 'src/processor/stackwalker_mips_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_mips_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_mips_unittest.cc' object='src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.o `test -f 'src/processor/stackwalker_mips_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_mips_unittest.cc + +src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.obj: src/processor/stackwalker_mips_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Tpo -c -o src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.obj `if test -f 'src/processor/stackwalker_mips_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_mips_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_mips_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_mips_unittest.cc' object='src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_mips_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_mips_unittest-stackwalker_mips_unittest.obj `if test -f 'src/processor/stackwalker_mips_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_mips_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_mips_unittest.cc'; fi` + +src/common/src_processor_stackwalker_x86_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_x86_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_x86_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_x86_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_x86_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_stackwalker_x86_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_stackwalker_x86_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Tpo -c -o src/common/src_processor_stackwalker_x86_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_stackwalker_x86_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_stackwalker_x86_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_stackwalker_x86_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.o: src/processor/stackwalker_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Tpo -c -o src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.o `test -f 'src/processor/stackwalker_x86_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_x86_unittest.cc' object='src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.o `test -f 'src/processor/stackwalker_x86_unittest.cc' || echo '$(srcdir)/'`src/processor/stackwalker_x86_unittest.cc + +src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.obj: src/processor/stackwalker_x86_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Tpo -c -o src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.obj `if test -f 'src/processor/stackwalker_x86_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_x86_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_x86_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Tpo src/processor/$(DEPDIR)/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/stackwalker_x86_unittest.cc' object='src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_stackwalker_x86_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_stackwalker_x86_unittest-stackwalker_x86_unittest.obj `if test -f 'src/processor/stackwalker_x86_unittest.cc'; then $(CYGPATH_W) 'src/processor/stackwalker_x86_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/stackwalker_x86_unittest.cc'; fi` + +src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.o: src/processor/static_address_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_address_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Tpo -c -o src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.o `test -f 'src/processor/static_address_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_address_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_address_map_unittest.cc' object='src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_address_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.o `test -f 'src/processor/static_address_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_address_map_unittest.cc + +src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.obj: src/processor/static_address_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_address_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Tpo -c -o src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.obj `if test -f 'src/processor/static_address_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_address_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_address_map_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_address_map_unittest-static_address_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_address_map_unittest.cc' object='src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_address_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_address_map_unittest-static_address_map_unittest.obj `if test -f 'src/processor/static_address_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_address_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_address_map_unittest.cc'; fi` + +src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.o: src/processor/static_contained_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_contained_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Tpo -c -o src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.o `test -f 'src/processor/static_contained_range_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_contained_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_contained_range_map_unittest.cc' object='src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_contained_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.o `test -f 'src/processor/static_contained_range_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_contained_range_map_unittest.cc + +src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.obj: src/processor/static_contained_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_contained_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Tpo -c -o src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.obj `if test -f 'src/processor/static_contained_range_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_contained_range_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_contained_range_map_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_contained_range_map_unittest.cc' object='src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_contained_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_contained_range_map_unittest-static_contained_range_map_unittest.obj `if test -f 'src/processor/static_contained_range_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_contained_range_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_contained_range_map_unittest.cc'; fi` + +src/processor/src_processor_static_map_unittest-static_map_unittest.o: src/processor/static_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_map_unittest-static_map_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Tpo -c -o src/processor/src_processor_static_map_unittest-static_map_unittest.o `test -f 'src/processor/static_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_map_unittest.cc' object='src/processor/src_processor_static_map_unittest-static_map_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_map_unittest-static_map_unittest.o `test -f 'src/processor/static_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_map_unittest.cc + +src/processor/src_processor_static_map_unittest-static_map_unittest.obj: src/processor/static_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_map_unittest-static_map_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Tpo -c -o src/processor/src_processor_static_map_unittest-static_map_unittest.obj `if test -f 'src/processor/static_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_map_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_map_unittest-static_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_map_unittest.cc' object='src/processor/src_processor_static_map_unittest-static_map_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_map_unittest-static_map_unittest.obj `if test -f 'src/processor/static_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_map_unittest.cc'; fi` + +src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.o: src/processor/static_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Tpo -c -o src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.o `test -f 'src/processor/static_range_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_range_map_unittest.cc' object='src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.o `test -f 'src/processor/static_range_map_unittest.cc' || echo '$(srcdir)/'`src/processor/static_range_map_unittest.cc + +src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.obj: src/processor/static_range_map_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Tpo -c -o src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.obj `if test -f 'src/processor/static_range_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_range_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_range_map_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Tpo src/processor/$(DEPDIR)/src_processor_static_range_map_unittest-static_range_map_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/static_range_map_unittest.cc' object='src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_static_range_map_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_static_range_map_unittest-static_range_map_unittest.obj `if test -f 'src/processor/static_range_map_unittest.cc'; then $(CYGPATH_W) 'src/processor/static_range_map_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/static_range_map_unittest.cc'; fi` + +src/common/src_processor_synth_minidump_unittest-test_assembler.o: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_synth_minidump_unittest-test_assembler.o -MD -MP -MF src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Tpo -c -o src/common/src_processor_synth_minidump_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_synth_minidump_unittest-test_assembler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_synth_minidump_unittest-test_assembler.o `test -f 'src/common/test_assembler.cc' || echo '$(srcdir)/'`src/common/test_assembler.cc + +src/common/src_processor_synth_minidump_unittest-test_assembler.obj: src/common/test_assembler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_processor_synth_minidump_unittest-test_assembler.obj -MD -MP -MF src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Tpo -c -o src/common/src_processor_synth_minidump_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Tpo src/common/$(DEPDIR)/src_processor_synth_minidump_unittest-test_assembler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/test_assembler.cc' object='src/common/src_processor_synth_minidump_unittest-test_assembler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_processor_synth_minidump_unittest-test_assembler.obj `if test -f 'src/common/test_assembler.cc'; then $(CYGPATH_W) 'src/common/test_assembler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/test_assembler.cc'; fi` + +src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.o: src/processor/synth_minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Tpo -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.o `test -f 'src/processor/synth_minidump_unittest.cc' || echo '$(srcdir)/'`src/processor/synth_minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Tpo src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump_unittest.cc' object='src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.o `test -f 'src/processor/synth_minidump_unittest.cc' || echo '$(srcdir)/'`src/processor/synth_minidump_unittest.cc + +src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.obj: src/processor/synth_minidump_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Tpo -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.obj `if test -f 'src/processor/synth_minidump_unittest.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Tpo src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump_unittest.cc' object='src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump_unittest.obj `if test -f 'src/processor/synth_minidump_unittest.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump_unittest.cc'; fi` + +src/processor/src_processor_synth_minidump_unittest-synth_minidump.o: src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_synth_minidump_unittest-synth_minidump.o -MD -MP -MF src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Tpo -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump.o `test -f 'src/processor/synth_minidump.cc' || echo '$(srcdir)/'`src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Tpo src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump.cc' object='src/processor/src_processor_synth_minidump_unittest-synth_minidump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump.o `test -f 'src/processor/synth_minidump.cc' || echo '$(srcdir)/'`src/processor/synth_minidump.cc + +src/processor/src_processor_synth_minidump_unittest-synth_minidump.obj: src/processor/synth_minidump.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/processor/src_processor_synth_minidump_unittest-synth_minidump.obj -MD -MP -MF src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Tpo -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump.obj `if test -f 'src/processor/synth_minidump.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Tpo src/processor/$(DEPDIR)/src_processor_synth_minidump_unittest-synth_minidump.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/processor/synth_minidump.cc' object='src/processor/src_processor_synth_minidump_unittest-synth_minidump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_processor_synth_minidump_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/processor/src_processor_synth_minidump_unittest-synth_minidump.obj `if test -f 'src/processor/synth_minidump.cc'; then $(CYGPATH_W) 'src/processor/synth_minidump.cc'; else $(CYGPATH_W) '$(srcdir)/src/processor/synth_minidump.cc'; fi` + +src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.o: src/tools/linux/md2core/minidump_memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.o -MD -MP -MF src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Tpo -c -o src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.o `test -f 'src/tools/linux/md2core/minidump_memory_range_unittest.cc' || echo '$(srcdir)/'`src/tools/linux/md2core/minidump_memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Tpo src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/tools/linux/md2core/minidump_memory_range_unittest.cc' object='src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.o `test -f 'src/tools/linux/md2core/minidump_memory_range_unittest.cc' || echo '$(srcdir)/'`src/tools/linux/md2core/minidump_memory_range_unittest.cc + +src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.obj: src/tools/linux/md2core/minidump_memory_range_unittest.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.obj -MD -MP -MF src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Tpo -c -o src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.obj `if test -f 'src/tools/linux/md2core/minidump_memory_range_unittest.cc'; then $(CYGPATH_W) 'src/tools/linux/md2core/minidump_memory_range_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tools/linux/md2core/minidump_memory_range_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Tpo src/tools/linux/md2core/$(DEPDIR)/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/tools/linux/md2core/minidump_memory_range_unittest.cc' object='src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_tools_linux_md2core_minidump_2_core_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/tools/linux/md2core/src_tools_linux_md2core_minidump_2_core_unittest-minidump_memory_range_unittest.obj `if test -f 'src/tools/linux/md2core/minidump_memory_range_unittest.cc'; then $(CYGPATH_W) 'src/tools/linux/md2core/minidump_memory_range_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/tools/linux/md2core/minidump_memory_range_unittest.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.o: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.o `test -f 'src/common/dwarf_cfi_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cfi_to_module.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.obj: src/common/dwarf_cfi_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cfi_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cfi_to_module.obj `if test -f 'src/common/dwarf_cfi_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cfi_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cfi_to_module.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.o: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.o `test -f 'src/common/dwarf_cu_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_cu_to_module.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.obj: src/common/dwarf_cu_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_cu_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_cu_to_module.obj `if test -f 'src/common/dwarf_cu_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_cu_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_cu_to_module.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.o: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.o `test -f 'src/common/dwarf_line_to_module.cc' || echo '$(srcdir)/'`src/common/dwarf_line_to_module.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj: src/common/dwarf_line_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf_line_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-dwarf_line_to_module.obj `if test -f 'src/common/dwarf_line_to_module.cc'; then $(CYGPATH_W) 'src/common/dwarf_line_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf_line_to_module.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-language.o `test -f 'src/common/language.cc' || echo '$(srcdir)/'`src/common/language.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-language.obj: src/common/language.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-language.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-language.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/language.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-language.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-language.obj `if test -f 'src/common/language.cc'; then $(CYGPATH_W) 'src/common/language.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/language.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.o: src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.o `test -f 'src/common/md5.cc' || echo '$(srcdir)/'`src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/md5.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.o `test -f 'src/common/md5.cc' || echo '$(srcdir)/'`src/common/md5.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.obj: src/common/md5.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.obj `if test -f 'src/common/md5.cc'; then $(CYGPATH_W) 'src/common/md5.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/md5.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-md5.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/md5.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-md5.obj `if test -f 'src/common/md5.cc'; then $(CYGPATH_W) 'src/common/md5.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/md5.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-module.o: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-module.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-module.o `test -f 'src/common/module.cc' || echo '$(srcdir)/'`src/common/module.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-module.obj: src/common/module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-module.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-module.obj `if test -f 'src/common/module.cc'; then $(CYGPATH_W) 'src/common/module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/module.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.o: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.o `test -f 'src/common/stabs_reader.cc' || echo '$(srcdir)/'`src/common/stabs_reader.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.obj: src/common/stabs_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_reader.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_reader.obj `if test -f 'src/common/stabs_reader.cc'; then $(CYGPATH_W) 'src/common/stabs_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_reader.cc'; fi` + +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.o: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.o -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.o `test -f 'src/common/stabs_to_module.cc' || echo '$(srcdir)/'`src/common/stabs_to_module.cc + +src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.obj: src/common/stabs_to_module.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.obj -MD -MP -MF src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Tpo -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Tpo src/common/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/stabs_to_module.cc' object='src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/src_tools_mac_dump_syms_dump_syms_mac-stabs_to_module.obj `if test -f 'src/common/stabs_to_module.cc'; then $(CYGPATH_W) 'src/common/stabs_to_module.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/stabs_to_module.cc'; fi` + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.o: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.o `test -f 'src/common/dwarf/bytereader.cc' || echo '$(srcdir)/'`src/common/dwarf/bytereader.cc + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.obj: src/common/dwarf/bytereader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-bytereader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/bytereader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-bytereader.obj `if test -f 'src/common/dwarf/bytereader.cc'; then $(CYGPATH_W) 'src/common/dwarf/bytereader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/bytereader.cc'; fi` + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.o: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.o `test -f 'src/common/dwarf/dwarf2diehandler.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2diehandler.cc + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.obj: src/common/dwarf/dwarf2diehandler.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2diehandler.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2diehandler.obj `if test -f 'src/common/dwarf/dwarf2diehandler.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2diehandler.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2diehandler.cc'; fi` + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.o: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.o `test -f 'src/common/dwarf/dwarf2reader.cc' || echo '$(srcdir)/'`src/common/dwarf/dwarf2reader.cc + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj: src/common/dwarf/dwarf2reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/dwarf2reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-dwarf2reader.obj `if test -f 'src/common/dwarf/dwarf2reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/dwarf2reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/dwarf2reader.cc'; fi` + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.o `test -f 'src/common/dwarf/elf_reader.cc' || echo '$(srcdir)/'`src/common/dwarf/elf_reader.cc + +src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj: src/common/dwarf/elf_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj -MD -MP -MF src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Tpo src/common/dwarf/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/dwarf/elf_reader.cc' object='src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/dwarf/src_tools_mac_dump_syms_dump_syms_mac-elf_reader.obj `if test -f 'src/common/dwarf/elf_reader.cc'; then $(CYGPATH_W) 'src/common/dwarf/elf_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/dwarf/elf_reader.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o: src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o `test -f 'src/common/mac/arch_utilities.cc' || echo '$(srcdir)/'`src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/arch_utilities.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.o `test -f 'src/common/mac/arch_utilities.cc' || echo '$(srcdir)/'`src/common/mac/arch_utilities.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.obj: src/common/mac/arch_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.obj `if test -f 'src/common/mac/arch_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/arch_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/arch_utilities.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/arch_utilities.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-arch_utilities.obj `if test -f 'src/common/mac/arch_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/arch_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/arch_utilities.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.o: src/common/mac/dump_syms.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.o `test -f 'src/common/mac/dump_syms.cc' || echo '$(srcdir)/'`src/common/mac/dump_syms.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/dump_syms.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.o `test -f 'src/common/mac/dump_syms.cc' || echo '$(srcdir)/'`src/common/mac/dump_syms.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.obj: src/common/mac/dump_syms.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.obj `if test -f 'src/common/mac/dump_syms.cc'; then $(CYGPATH_W) 'src/common/mac/dump_syms.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/dump_syms.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/dump_syms.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-dump_syms.obj `if test -f 'src/common/mac/dump_syms.cc'; then $(CYGPATH_W) 'src/common/mac/dump_syms.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/dump_syms.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.o: src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.o `test -f 'src/common/mac/file_id.cc' || echo '$(srcdir)/'`src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/file_id.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.o `test -f 'src/common/mac/file_id.cc' || echo '$(srcdir)/'`src/common/mac/file_id.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.obj: src/common/mac/file_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.obj `if test -f 'src/common/mac/file_id.cc'; then $(CYGPATH_W) 'src/common/mac/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/file_id.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-file_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/file_id.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-file_id.obj `if test -f 'src/common/mac/file_id.cc'; then $(CYGPATH_W) 'src/common/mac/file_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/file_id.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.o: src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.o `test -f 'src/common/mac/macho_id.cc' || echo '$(srcdir)/'`src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_id.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.o `test -f 'src/common/mac/macho_id.cc' || echo '$(srcdir)/'`src/common/mac/macho_id.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.obj: src/common/mac/macho_id.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.obj `if test -f 'src/common/mac/macho_id.cc'; then $(CYGPATH_W) 'src/common/mac/macho_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_id.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_id.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_id.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_id.obj `if test -f 'src/common/mac/macho_id.cc'; then $(CYGPATH_W) 'src/common/mac/macho_id.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_id.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.o: src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.o `test -f 'src/common/mac/macho_reader.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.o `test -f 'src/common/mac/macho_reader.cc' || echo '$(srcdir)/'`src/common/mac/macho_reader.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.obj: src/common/mac/macho_reader.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.obj `if test -f 'src/common/mac/macho_reader.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_reader.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_reader.obj `if test -f 'src/common/mac/macho_reader.cc'; then $(CYGPATH_W) 'src/common/mac/macho_reader.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_reader.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.o: src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.o `test -f 'src/common/mac/macho_utilities.cc' || echo '$(srcdir)/'`src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_utilities.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.o `test -f 'src/common/mac/macho_utilities.cc' || echo '$(srcdir)/'`src/common/mac/macho_utilities.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.obj: src/common/mac/macho_utilities.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.obj `if test -f 'src/common/mac/macho_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/macho_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_utilities.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_utilities.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_utilities.obj `if test -f 'src/common/mac/macho_utilities.cc'; then $(CYGPATH_W) 'src/common/mac/macho_utilities.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_utilities.cc'; fi` + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.o: src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.o -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.o `test -f 'src/common/mac/macho_walker.cc' || echo '$(srcdir)/'`src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_walker.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.o `test -f 'src/common/mac/macho_walker.cc' || echo '$(srcdir)/'`src/common/mac/macho_walker.cc + +src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.obj: src/common/mac/macho_walker.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.obj -MD -MP -MF src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Tpo -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.obj `if test -f 'src/common/mac/macho_walker.cc'; then $(CYGPATH_W) 'src/common/mac/macho_walker.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_walker.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Tpo src/common/mac/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/common/mac/macho_walker.cc' object='src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/common/mac/src_tools_mac_dump_syms_dump_syms_mac-macho_walker.obj `if test -f 'src/common/mac/macho_walker.cc'; then $(CYGPATH_W) 'src/common/mac/macho_walker.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/mac/macho_walker.cc'; fi` + +src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.o: src/tools/mac/dump_syms/dump_syms_tool.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.o -MD -MP -MF src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Tpo -c -o src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.o `test -f 'src/tools/mac/dump_syms/dump_syms_tool.cc' || echo '$(srcdir)/'`src/tools/mac/dump_syms/dump_syms_tool.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Tpo src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/tools/mac/dump_syms/dump_syms_tool.cc' object='src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.o `test -f 'src/tools/mac/dump_syms/dump_syms_tool.cc' || echo '$(srcdir)/'`src/tools/mac/dump_syms/dump_syms_tool.cc + +src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.obj: src/tools/mac/dump_syms/dump_syms_tool.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -MT src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.obj -MD -MP -MF src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Tpo -c -o src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.obj `if test -f 'src/tools/mac/dump_syms/dump_syms_tool.cc'; then $(CYGPATH_W) 'src/tools/mac/dump_syms/dump_syms_tool.cc'; else $(CYGPATH_W) '$(srcdir)/src/tools/mac/dump_syms/dump_syms_tool.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Tpo src/tools/mac/dump_syms/$(DEPDIR)/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='src/tools/mac/dump_syms/dump_syms_tool.cc' object='src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_tools_mac_dump_syms_dump_syms_mac_CXXFLAGS) $(CXXFLAGS) -c -o src/tools/mac/dump_syms/src_tools_mac_dump_syms_dump_syms_mac-dump_syms_tool.obj `if test -f 'src/tools/mac/dump_syms/dump_syms_tool.cc'; then $(CYGPATH_W) 'src/tools/mac/dump_syms/dump_syms_tool.cc'; else $(CYGPATH_W) '$(srcdir)/src/tools/mac/dump_syms/dump_syms_tool.cc'; fi` +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +install-includecHEADERS: $(includec_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includec_HEADERS)'; test -n "$(includecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includecdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includecdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includecdir)" || exit $$?; \ + done + +uninstall-includecHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includec_HEADERS)'; test -n "$(includecdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includecdir)'; $(am__uninstall_files_from_dir) +install-includeclHEADERS: $(includecl_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includecl_HEADERS)'; test -n "$(includecldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includecldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includecldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includecldir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includecldir)" || exit $$?; \ + done + +uninstall-includeclHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includecl_HEADERS)'; test -n "$(includecldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includecldir)'; $(am__uninstall_files_from_dir) +install-includeclcHEADERS: $(includeclc_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includeclc_HEADERS)'; test -n "$(includeclcdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includeclcdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includeclcdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includeclcdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includeclcdir)" || exit $$?; \ + done + +uninstall-includeclcHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includeclc_HEADERS)'; test -n "$(includeclcdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includeclcdir)'; $(am__uninstall_files_from_dir) +install-includecldwcHEADERS: $(includecldwc_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includecldwc_HEADERS)'; test -n "$(includecldwcdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includecldwcdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includecldwcdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includecldwcdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includecldwcdir)" || exit $$?; \ + done + +uninstall-includecldwcHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includecldwc_HEADERS)'; test -n "$(includecldwcdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includecldwcdir)'; $(am__uninstall_files_from_dir) +install-includeclhHEADERS: $(includeclh_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includeclh_HEADERS)'; test -n "$(includeclhdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includeclhdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includeclhdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includeclhdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includeclhdir)" || exit $$?; \ + done + +uninstall-includeclhHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includeclh_HEADERS)'; test -n "$(includeclhdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includeclhdir)'; $(am__uninstall_files_from_dir) +install-includeclmHEADERS: $(includeclm_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includeclm_HEADERS)'; test -n "$(includeclmdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includeclmdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includeclmdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includeclmdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includeclmdir)" || exit $$?; \ + done + +uninstall-includeclmHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includeclm_HEADERS)'; test -n "$(includeclmdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includeclmdir)'; $(am__uninstall_files_from_dir) +install-includegbcHEADERS: $(includegbc_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includegbc_HEADERS)'; test -n "$(includegbcdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includegbcdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includegbcdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includegbcdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includegbcdir)" || exit $$?; \ + done + +uninstall-includegbcHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includegbc_HEADERS)'; test -n "$(includegbcdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includegbcdir)'; $(am__uninstall_files_from_dir) +install-includelssHEADERS: $(includelss_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includelss_HEADERS)'; test -n "$(includelssdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includelssdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includelssdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includelssdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includelssdir)" || exit $$?; \ + done + +uninstall-includelssHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includelss_HEADERS)'; test -n "$(includelssdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includelssdir)'; $(am__uninstall_files_from_dir) +install-includepHEADERS: $(includep_HEADERS) + @$(NORMAL_INSTALL) + @list='$(includep_HEADERS)'; test -n "$(includepdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includepdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includepdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includepdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includepdir)" || exit $$?; \ + done + +uninstall-includepHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includep_HEADERS)'; test -n "$(includepdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includepdir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all $(check_LIBRARIES) $(check_PROGRAMS) $(check_SCRIPTS) + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +src/common/test_assembler_unittest.log: src/common/test_assembler_unittest$(EXEEXT) + @p='src/common/test_assembler_unittest$(EXEEXT)'; \ + b='src/common/test_assembler_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/address_map_unittest.log: src/processor/address_map_unittest$(EXEEXT) + @p='src/processor/address_map_unittest$(EXEEXT)'; \ + b='src/processor/address_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/basic_source_line_resolver_unittest.log: src/processor/basic_source_line_resolver_unittest$(EXEEXT) + @p='src/processor/basic_source_line_resolver_unittest$(EXEEXT)'; \ + b='src/processor/basic_source_line_resolver_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/cfi_frame_info_unittest.log: src/processor/cfi_frame_info_unittest$(EXEEXT) + @p='src/processor/cfi_frame_info_unittest$(EXEEXT)'; \ + b='src/processor/cfi_frame_info_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/contained_range_map_unittest.log: src/processor/contained_range_map_unittest$(EXEEXT) + @p='src/processor/contained_range_map_unittest$(EXEEXT)'; \ + b='src/processor/contained_range_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/disassembler_x86_unittest.log: src/processor/disassembler_x86_unittest$(EXEEXT) + @p='src/processor/disassembler_x86_unittest$(EXEEXT)'; \ + b='src/processor/disassembler_x86_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/exploitability_unittest.log: src/processor/exploitability_unittest$(EXEEXT) + @p='src/processor/exploitability_unittest$(EXEEXT)'; \ + b='src/processor/exploitability_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/fast_source_line_resolver_unittest.log: src/processor/fast_source_line_resolver_unittest$(EXEEXT) + @p='src/processor/fast_source_line_resolver_unittest$(EXEEXT)'; \ + b='src/processor/fast_source_line_resolver_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/map_serializers_unittest.log: src/processor/map_serializers_unittest$(EXEEXT) + @p='src/processor/map_serializers_unittest$(EXEEXT)'; \ + b='src/processor/map_serializers_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/microdump_processor_unittest.log: src/processor/microdump_processor_unittest$(EXEEXT) + @p='src/processor/microdump_processor_unittest$(EXEEXT)'; \ + b='src/processor/microdump_processor_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/minidump_processor_unittest.log: src/processor/minidump_processor_unittest$(EXEEXT) + @p='src/processor/minidump_processor_unittest$(EXEEXT)'; \ + b='src/processor/minidump_processor_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/minidump_unittest.log: src/processor/minidump_unittest$(EXEEXT) + @p='src/processor/minidump_unittest$(EXEEXT)'; \ + b='src/processor/minidump_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/static_address_map_unittest.log: src/processor/static_address_map_unittest$(EXEEXT) + @p='src/processor/static_address_map_unittest$(EXEEXT)'; \ + b='src/processor/static_address_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/static_contained_range_map_unittest.log: src/processor/static_contained_range_map_unittest$(EXEEXT) + @p='src/processor/static_contained_range_map_unittest$(EXEEXT)'; \ + b='src/processor/static_contained_range_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/static_map_unittest.log: src/processor/static_map_unittest$(EXEEXT) + @p='src/processor/static_map_unittest$(EXEEXT)'; \ + b='src/processor/static_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/static_range_map_unittest.log: src/processor/static_range_map_unittest$(EXEEXT) + @p='src/processor/static_range_map_unittest$(EXEEXT)'; \ + b='src/processor/static_range_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/pathname_stripper_unittest.log: src/processor/pathname_stripper_unittest$(EXEEXT) + @p='src/processor/pathname_stripper_unittest$(EXEEXT)'; \ + b='src/processor/pathname_stripper_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/postfix_evaluator_unittest.log: src/processor/postfix_evaluator_unittest$(EXEEXT) + @p='src/processor/postfix_evaluator_unittest$(EXEEXT)'; \ + b='src/processor/postfix_evaluator_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/proc_maps_linux_unittest.log: src/processor/proc_maps_linux_unittest$(EXEEXT) + @p='src/processor/proc_maps_linux_unittest$(EXEEXT)'; \ + b='src/processor/proc_maps_linux_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/range_map_shrink_down_unittest.log: src/processor/range_map_shrink_down_unittest$(EXEEXT) + @p='src/processor/range_map_shrink_down_unittest$(EXEEXT)'; \ + b='src/processor/range_map_shrink_down_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/range_map_unittest.log: src/processor/range_map_unittest$(EXEEXT) + @p='src/processor/range_map_unittest$(EXEEXT)'; \ + b='src/processor/range_map_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_amd64_unittest.log: src/processor/stackwalker_amd64_unittest$(EXEEXT) + @p='src/processor/stackwalker_amd64_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_amd64_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_arm_unittest.log: src/processor/stackwalker_arm_unittest$(EXEEXT) + @p='src/processor/stackwalker_arm_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_arm_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_arm64_unittest.log: src/processor/stackwalker_arm64_unittest$(EXEEXT) + @p='src/processor/stackwalker_arm64_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_arm64_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_address_list_unittest.log: src/processor/stackwalker_address_list_unittest$(EXEEXT) + @p='src/processor/stackwalker_address_list_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_address_list_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_mips_unittest.log: src/processor/stackwalker_mips_unittest$(EXEEXT) + @p='src/processor/stackwalker_mips_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_mips_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_mips64_unittest.log: src/processor/stackwalker_mips64_unittest$(EXEEXT) + @p='src/processor/stackwalker_mips64_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_mips64_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_x86_unittest.log: src/processor/stackwalker_x86_unittest$(EXEEXT) + @p='src/processor/stackwalker_x86_unittest$(EXEEXT)'; \ + b='src/processor/stackwalker_x86_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/synth_minidump_unittest.log: src/processor/synth_minidump_unittest$(EXEEXT) + @p='src/processor/synth_minidump_unittest$(EXEEXT)'; \ + b='src/processor/synth_minidump_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/client/linux/linux_client_unittest.log: src/client/linux/linux_client_unittest$(EXEEXT) + @p='src/client/linux/linux_client_unittest$(EXEEXT)'; \ + b='src/client/linux/linux_client_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/common/dumper_unittest.log: src/common/dumper_unittest$(EXEEXT) + @p='src/common/dumper_unittest$(EXEEXT)'; \ + b='src/common/dumper_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/tools/linux/md2core/minidump_2_core_unittest.log: src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT) + @p='src/tools/linux/md2core/minidump_2_core_unittest$(EXEEXT)'; \ + b='src/tools/linux/md2core/minidump_2_core_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/common/mac/macho_reader_unittest.log: src/common/mac/macho_reader_unittest$(EXEEXT) + @p='src/common/mac/macho_reader_unittest$(EXEEXT)'; \ + b='src/common/mac/macho_reader_unittest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/stackwalker_selftest.log: src/processor/stackwalker_selftest$(EXEEXT) + @p='src/processor/stackwalker_selftest$(EXEEXT)'; \ + b='src/processor/stackwalker_selftest'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/microdump_stackwalk_test.log: src/processor/microdump_stackwalk_test + @p='src/processor/microdump_stackwalk_test'; \ + b='src/processor/microdump_stackwalk_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/microdump_stackwalk_machine_readable_test.log: src/processor/microdump_stackwalk_machine_readable_test + @p='src/processor/microdump_stackwalk_machine_readable_test'; \ + b='src/processor/microdump_stackwalk_machine_readable_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/minidump_dump_test.log: src/processor/minidump_dump_test + @p='src/processor/minidump_dump_test'; \ + b='src/processor/minidump_dump_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/minidump_stackwalk_test.log: src/processor/minidump_stackwalk_test + @p='src/processor/minidump_stackwalk_test'; \ + b='src/processor/minidump_stackwalk_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +src/processor/minidump_stackwalk_machine_readable_test.log: src/processor/minidump_stackwalk_machine_readable_test + @p='src/processor/minidump_stackwalk_machine_readable_test'; \ + b='src/processor/minidump_stackwalk_machine_readable_test'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_LIBRARIES) $(check_PROGRAMS) \ + $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(SCRIPTS) $(DATA) \ + $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includecdir)" "$(DESTDIR)$(includecldir)" "$(DESTDIR)$(includeclcdir)" "$(DESTDIR)$(includecldwcdir)" "$(DESTDIR)$(includeclhdir)" "$(DESTDIR)$(includeclmdir)" "$(DESTDIR)$(includegbcdir)" "$(DESTDIR)$(includelssdir)" "$(DESTDIR)$(includepdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f src/$(am__dirstamp) + -rm -f src/client/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/$(am__dirstamp) + -rm -f src/client/linux/$(am__dirstamp) + -rm -f src/client/linux/crash_generation/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/crash_generation/$(am__dirstamp) + -rm -f src/client/linux/dump_writer_common/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/dump_writer_common/$(am__dirstamp) + -rm -f src/client/linux/handler/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/handler/$(am__dirstamp) + -rm -f src/client/linux/log/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/log/$(am__dirstamp) + -rm -f src/client/linux/microdump_writer/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/microdump_writer/$(am__dirstamp) + -rm -f src/client/linux/minidump_writer/$(DEPDIR)/$(am__dirstamp) + -rm -f src/client/linux/minidump_writer/$(am__dirstamp) + -rm -f src/common/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/$(am__dirstamp) + -rm -f src/common/android/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/android/$(am__dirstamp) + -rm -f src/common/dwarf/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/dwarf/$(am__dirstamp) + -rm -f src/common/linux/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/linux/$(am__dirstamp) + -rm -f src/common/linux/tests/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/linux/tests/$(am__dirstamp) + -rm -f src/common/mac/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/mac/$(am__dirstamp) + -rm -f src/common/tests/$(DEPDIR)/$(am__dirstamp) + -rm -f src/common/tests/$(am__dirstamp) + -rm -f src/processor/$(DEPDIR)/$(am__dirstamp) + -rm -f src/processor/$(am__dirstamp) + -rm -f src/testing/$(am__dirstamp) + -rm -f src/testing/gtest/src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/testing/gtest/src/$(am__dirstamp) + -rm -f src/testing/src/$(DEPDIR)/$(am__dirstamp) + -rm -f src/testing/src/$(am__dirstamp) + -rm -f src/third_party/libdisasm/$(DEPDIR)/$(am__dirstamp) + -rm -f src/third_party/libdisasm/$(am__dirstamp) + -rm -f src/tools/linux/core2md/$(DEPDIR)/$(am__dirstamp) + -rm -f src/tools/linux/core2md/$(am__dirstamp) + -rm -f src/tools/linux/dump_syms/$(DEPDIR)/$(am__dirstamp) + -rm -f src/tools/linux/dump_syms/$(am__dirstamp) + -rm -f src/tools/linux/md2core/$(DEPDIR)/$(am__dirstamp) + -rm -f src/tools/linux/md2core/$(am__dirstamp) + -rm -f src/tools/linux/symupload/$(DEPDIR)/$(am__dirstamp) + -rm -f src/tools/linux/symupload/$(am__dirstamp) + -rm -f src/tools/mac/dump_syms/$(DEPDIR)/$(am__dirstamp) + -rm -f src/tools/mac/dump_syms/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkLIBRARIES clean-checkPROGRAMS \ + clean-generic clean-libLIBRARIES clean-noinstLIBRARIES \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/dump_writer_common/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/microdump_writer/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/mac/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) src/tools/mac/dump_syms/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-includecHEADERS \ + install-includeclHEADERS install-includeclcHEADERS \ + install-includecldwcHEADERS install-includeclhHEADERS \ + install-includeclmHEADERS install-includegbcHEADERS \ + install-includelssHEADERS install-includepHEADERS \ + install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf src/client/$(DEPDIR) src/client/linux/crash_generation/$(DEPDIR) src/client/linux/dump_writer_common/$(DEPDIR) src/client/linux/handler/$(DEPDIR) src/client/linux/log/$(DEPDIR) src/client/linux/microdump_writer/$(DEPDIR) src/client/linux/minidump_writer/$(DEPDIR) src/common/$(DEPDIR) src/common/android/$(DEPDIR) src/common/dwarf/$(DEPDIR) src/common/linux/$(DEPDIR) src/common/linux/tests/$(DEPDIR) src/common/mac/$(DEPDIR) src/common/tests/$(DEPDIR) src/processor/$(DEPDIR) src/testing/gtest/src/$(DEPDIR) src/testing/src/$(DEPDIR) src/third_party/libdisasm/$(DEPDIR) src/tools/linux/core2md/$(DEPDIR) src/tools/linux/dump_syms/$(DEPDIR) src/tools/linux/md2core/$(DEPDIR) src/tools/linux/symupload/$(DEPDIR) src/tools/mac/dump_syms/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-local + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \ + uninstall-includecHEADERS uninstall-includeclHEADERS \ + uninstall-includeclcHEADERS uninstall-includecldwcHEADERS \ + uninstall-includeclhHEADERS uninstall-includeclmHEADERS \ + uninstall-includegbcHEADERS uninstall-includelssHEADERS \ + uninstall-includepHEADERS uninstall-libLIBRARIES \ + uninstall-pkgconfigDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \ + check-am clean clean-binPROGRAMS clean-checkLIBRARIES \ + clean-checkPROGRAMS clean-cscope clean-generic \ + clean-libLIBRARIES clean-noinstLIBRARIES clean-noinstPROGRAMS \ + cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-compile distclean-generic \ + distclean-hdr distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dist_docDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-includecHEADERS \ + install-includeclHEADERS install-includeclcHEADERS \ + install-includecldwcHEADERS install-includeclhHEADERS \ + install-includeclmHEADERS install-includegbcHEADERS \ + install-includelssHEADERS install-includepHEADERS install-info \ + install-info-am install-libLIBRARIES install-man install-pdf \ + install-pdf-am install-pkgconfigDATA install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-local pdf \ + pdf-am ps ps-am recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-dist_docDATA \ + uninstall-includecHEADERS uninstall-includeclHEADERS \ + uninstall-includeclcHEADERS uninstall-includecldwcHEADERS \ + uninstall-includeclhHEADERS uninstall-includeclmHEADERS \ + uninstall-includegbcHEADERS uninstall-includelssHEADERS \ + uninstall-includepHEADERS uninstall-libLIBRARIES \ + uninstall-pkgconfigDATA + +.PRECIOUS: Makefile + + +mostlyclean-local: + -find src -name '*.dwo' -exec rm -f {} + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/toolkit/crashreporter/google-breakpad/NEWS b/toolkit/crashreporter/google-breakpad/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/toolkit/crashreporter/google-breakpad/README.ANDROID b/toolkit/crashreporter/google-breakpad/README.ANDROID new file mode 100644 index 0000000000..30959ed3a2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/README.ANDROID @@ -0,0 +1,139 @@ +Google Breakpad for Android +=========================== + +This document explains how to use the Google Breakpad client library +on Android, and later generate valid stack traces from the minidumps +it generates. + +This release supports ARM, x86 and MIPS based Android systems. +This release requires NDK release r11c or higher. + +I. Building the client library: +=============================== + +The Android client is built as a static library that you can +link into your own Android native code. There are two ways to +build it: + +I.1. Building with ndk-build: +----------------------------- + +If you're using the ndk-build build system, you can follow +these simple steps: + + 1/ Include android/google_breakpad/Android.mk from your own + project's Android.mk + + This can be done either directly, or using ndk-build's + import-module feature. + + 2/ Link the library to one of your modules by using: + + LOCAL_STATIC_LIBRARIES += breakpad_client + +NOTE: The client library requires a C++ STL implementation, + which you can select with APP_STL in your Application.mk + + It has been tested succesfully with both STLport and GNU libstdc++ + + +I.2. Building with a standalone Android toolchain: +-------------------------------------------------- + +All you need to do is configure your build with the right 'host' +value, and disable the processor and tools, as in: + + $GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \ + --disable-processor \ + --disable-tools + make -j4 + +The library will be under src/client/linux/libbreakpad_client.a + +You can also use 'make check' to run the test suite on a connected +Android device. This requires the Android 'adb' tool to be in your +path. + +II. Using the client library in Android: +======================================== + +The usage instructions are very similar to the Linux ones that are +found at https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md + +1/ You need to include "client/linux/handler/exception_handler.h" from a C++ + source file. + +2/ If you're not using ndk-build, you also need to: + + - add the following to your compiler include search paths: + $GOOGLE_BREAKPAD_PATH/src + $GOOGLE_BREAKPAD_PATH/src/common/android/include + + - add -llog to your linker flags + + Note that ndk-build does that for your automatically. + +3/ Keep in mind that there is no /tmp directory on Android. + + If you use the library from a regular Android applications, specify a + path under your app-specific storage directory. An alternative is to + store them on the SDCard, but this requires a specific permission. + +For a concrete example, see the sample test application under +android/sample_app. See its README for more information. + + +III. Getting a stack trace on the host: +======================================= + +This process is similar to other platforms, but here's a quick example: + +1/ Retrieve the minidumps on your development machine. + +2/ Dump the symbols for your native libraries with the 'dump_syms' tool. + This first requires building the host version of Google Breakpad, then + calling: + + dump_syms $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym + +3/ Create the symbol directory hierarchy. + + The first line of the generated libfoo.so.sym will have a "MODULE" + entry that carries a hexadecimal version number, e.g.: + + MODULE Linux arm D51B4A5504974FA6ECC1869CAEE3603B0 test_google_breakpad + + Note: The second field could be either 'Linux' or 'Android'. + + Extract the version number, and a 'symbol' directory, for example: + + $PROJECT_PATH/symbols/libfoo.so/$VERSION/ + + Copy/Move your libfoo.sym file there. + +4/ Invoke minidump_stackwalk to create the stack trace: + + minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols + +Note that various helper scripts can be found on the web to automate these +steps. + +IV. Verifying the Android build library: +======================================== + +If you modify Google Breakpad and want to check that it still works correctly +on Android, please run the android/run-checks.sh script which will do all +necessary verifications for you. This includes: + + - Rebuilding the full host binaries. + - Rebuilding the full Android binaries with configure/make. + - Rebuilding the client library unit tests, and running them on a device. + - Rebuilding the client library with ndk-build. + - Building, installing and running a test crasher program on a device. + - Extracting the corresponding minidump, dumping the test program symbols + and generating a stack trace. + - Checking the generated stack trace for valid source locations. + +For more details, please run: + + android/run-checks.sh --help-all diff --git a/toolkit/crashreporter/google-breakpad/README.md b/toolkit/crashreporter/google-breakpad/README.md new file mode 100644 index 0000000000..caefdd28c3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/README.md @@ -0,0 +1,82 @@ +# Breakpad + +Breakpad is a set of client and server components which implement a +crash-reporting system. + +* [Homepage](https://chromium.googlesource.com/breakpad/breakpad/) +* [Documentation](https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/) +* [Bugs](https://bugs.chromium.org/p/google-breakpad/) +* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss) +* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev) +* Tests: [![Build Status](https://travis-ci.org/google/breakpad.svg?branch=master)](https://travis-ci.org/google/breakpad) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad) +* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad) + +## Getting started (from master) + +1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools) + and ensure that they’re in your `PATH`. + +2. Create a new directory for checking out the source code (it must be named + breakpad). + + ```sh + mkdir breakpad && cd breakpad + ``` + +3. Run the `fetch` tool from depot_tools to download all the source repos. + + ```sh + fetch breakpad + cd src + ``` + +4. Build the source. + + ```sh + ./configure && make + ``` + + You can also cd to another directory and run configure from there to build + outside the source tree. + + This will build the processor tools (`src/processor/minidump_stackwalk`, + `src/processor/minidump_dump`, etc), and when building on Linux it will + also build the client libraries and some tools + (`src/tools/linux/dump_syms/dump_syms`, + `src/tools/linux/md2core/minidump-2-core`, etc). + +5. Optionally, run tests. + + ```sh + make check + ``` + +6. Optionally, install the built libraries + + ```sh + make install + ``` + +If you need to reconfigure your build be sure to run `make distclean` first. + +To update an existing checkout to a newer revision, you can +`git pull` as usual, but then you should run `gclient sync` to ensure that the +dependent repos are up-to-date. + +## To request change review + +1. Follow the steps above to get the source and build it. + +2. Make changes. Build and test your changes. + For core code like processor use methods above. + For linux/mac/windows, there are test targets in each project file. + +3. Commit your changes to your local repo and upload them to the server. + http://dev.chromium.org/developers/contributing-code + e.g. `git commit ... && git cl upload ...` + You will be prompted for credential and a description. + +4. At https://chromium-review.googlesource.com/ you'll find your issue listed; + click on it, then “Add reviewer”, and enter in the code reviewer. Depending + on your settings, you may not see an email, but the reviewer has been + notified with google-breakpad-dev@googlegroups.com always CC’d. diff --git a/toolkit/crashreporter/google-breakpad/aclocal.m4 b/toolkit/crashreporter/google-breakpad/aclocal.m4 new file mode 100644 index 0000000000..b6aeaa4498 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/aclocal.m4 @@ -0,0 +1,1304 @@ +# generated automatically by aclocal 1.15.1 -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.15' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.15.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.15.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Copyright (C) 2011-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AR([ACT-IF-FAIL]) +# ------------------------- +# Try to determine the archiver interface, and trigger the ar-lib wrapper +# if it is needed. If the detection of archiver interface fails, run +# ACT-IF-FAIL (default is to abort configure with a proper error message). +AC_DEFUN([AM_PROG_AR], +[AC_BEFORE([$0], [LT_INIT])dnl +AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([ar-lib])dnl +AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) +: ${AR=ar} + +AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], + [AC_LANG_PUSH([C]) + am_cv_ar_interface=ar + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], + [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + ]) + AC_LANG_POP([C])]) + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + m4_default([$1], + [AC_MSG_ERROR([could not determine $AR interface])]) + ;; +esac +AC_SUBST([AR])dnl +]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# -*- Autoconf -*- +# Obsolete and "removed" macros, that must however still report explicit +# error messages when used, to smooth transition. +# +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl +AC_CONFIG_HEADERS($@)]) + +AC_DEFUN([AM_PROG_CC_STDC], +[AC_PROG_CC +am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc +AC_DIAGNOSE([obsolete], +['$0': this macro is obsolete. +You should simply use the 'AC][_PROG_CC' macro instead. +Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', +but upon 'ac_cv_prog_cc_stdc'.])]) + +AC_DEFUN([AM_C_PROTOTYPES], + [AC_FATAL([automatic de-ANSI-fication support has been removed])]) +AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2017 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/ax_append_compile_flags.m4]) +m4_include([m4/ax_append_flag.m4]) +m4_include([m4/ax_check_compile_flag.m4]) +m4_include([m4/ax_check_define.m4]) +m4_include([m4/ax_cxx_compile_stdcxx.m4]) +m4_include([m4/ax_pthread.m4]) +m4_include([m4/ax_require_defined.m4]) diff --git a/toolkit/crashreporter/google-breakpad/android/common-functions.sh b/toolkit/crashreporter/google-breakpad/android/common-functions.sh new file mode 100755 index 0000000000..c00e34f997 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/common-functions.sh @@ -0,0 +1,372 @@ +# Copyright (c) 2012 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. + +# Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh' + +# All internal variables and functions use an underscore as a prefix +# (e.g. _VERBOSE, _ALL_CLEANUPS, etc..). + +# Sanitize the environment +export LANG=C +export LC_ALL=C + +if [ "$BASH_VERSION" ]; then + set -o posix +fi + +# Utility functions + +_ALL_CLEANUPS= + +# Register a function to be called when the script exits, even in case of +# Ctrl-C, logout, etc. +# $1: function name. +atexit () { + if [ -z "$_ALL_CLEANUPS" ]; then + _ALL_CLEANUPS=$1 + # Ensure a clean exit when the script is: + # - Exiting normally (EXIT) + # - Interrupted by Ctrl-C (INT) + # - Interrupted by log out (HUP) + # - Being asked to quit nicely (TERM) + # - Being asked to quit and dump core (QUIT) + trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM + else + _ALL_CLEANUPS="$_ALL_CLEANUPS $1" + fi +} + +# Called on exit if at least one function was registered with atexit +# $1: final exit status code +_exit_cleanups () { + local CLEANUP CLEANUPS + # Ignore calls to atexit during cleanups + CLEANUPS=$_ALL_CLEANUPS + _ALL_CLEANUPS= + for CLEANUP in $CLEANUPS; do + ($CLEANUP) + done + exit "$@" +} + + + + +# Dump a panic message then exit. +# $1+: message +panic () { + echo "ERROR: $@" >&2 + exit 1 +} + +# If the previous command failed, dump a panic message then exit. +# $1+: message. +fail_panic () { + if [ $? != 0 ]; then + panic "$@" + fi; +} + +_VERBOSE=0 + +# Increase verbosity for dump/log/run/run2 functions +increase_verbosity () { + _VERBOSE=$(( $_VERBOSE + 1 )) +} + +# Decrease verbosity +decrease_verbosity () { + _VERBOSE=$(( $_VERBOSE - 1 )) +} + +# Returns success iff verbosity level is higher than a specific value +# $1: verbosity level +verbosity_is_higher_than () { + [ "$_VERBOSE" -gt "$1" ] +} + +# Returns success iff verbosity level is lower than a specific value +# $1: verbosity level +verbosity_is_lower_than () { + [ "$_VERBOSE" -le "$1" ] +} + +# Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called +# $1+: message +dump () { + if [ "$_VERBOSE" -ge 0 ]; then + printf "%s\n" "$*" + fi +} + +# If --verbose was used, dump a message to stdout. +# $1+: message +log () { + if [ "$_VERBOSE" -ge 1 ]; then + printf "%s\n" "$*" + fi +} + +_RUN_LOG= + +# Set a run log file that can be used to collect the output of commands that +# are not displayed. +set_run_log () { + _RUN_LOG=$1 +} + +# Run a command. Output depends on $_VERBOSE: +# $_VERBOSE <= 0: Run command, store output into the run log +# $_VERBOSE >= 1: Dump command, run it, output goest to stdout +# Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1 +# but the 'tee' tool doesn't preserve the status code of its input pipe +# in case of error. +run () { + local LOGILE + if [ "$_RUN_LOG" ]; then + LOGFILE=$_RUN_LOG + else + LOGFILE=/dev/null + fi + + if [ "$_VERBOSE" -ge 1 ]; then + echo "COMMAND: $@" + "$@" + else + "$@" >>$LOGFILE 2>&1 + fi +} + +# Same as run(), but only dump command output for $_VERBOSE >= 2 +run2 () { + local LOGILE + if [ "$_RUN_LOG" ]; then + LOGFILE=$_RUN_LOG + else + LOGFILE=/dev/null + fi + + if [ "$_VERBOSE" -ge 1 ]; then + echo "COMMAND: $@" + fi + if [ "$_VERBOSE" -ge 2 ]; then + "$@" + else + "$@" >>$LOGFILE 2>&1 + fi +} + +# Extract number of cores to speed up the builds +# Out: number of CPU cores +get_core_count () { + case $(uname -s) in + Linux) + grep -c -e '^processor' /proc/cpuinfo + ;; + Darwin) + sysctl -n hw.ncpu + ;; + CYGWIN*|*_NT-*) + echo $NUMBER_OF_PROCESSORS + ;; + *) + echo 1 + ;; + esac +} + + +# Check for the Android ADB program. +# +# On success, return nothing, but updates internal variables so later calls to +# adb_shell, adb_push, etc.. will work. You can get the path to the ADB program +# with adb_get_program if needed. +# +# On failure, returns 1, and updates the internal adb error message, which can +# be retrieved with adb_get_error. +# +# $1: optional ADB program path. +# Return: success or failure. +_ADB= +_ADB_STATUS= +_ADB_ERROR= + +adb_check () { + # First, try to find the executable in the path, or the SDK install dir. + _ADB=$1 + if [ -z "$_ADB" ]; then + _ADB=$(which adb 2>/dev/null) + if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then + _ADB=$ANDROID_SDK_ROOT/platform-tools/adb + if [ ! -f "$_ADB" ]; then + _ADB= + fi + fi + if [ -z "$_ADB" ]; then + _ADB_STATUS=1 + _ADB_ERROR="The Android 'adb' tool is not in your path." + return 1 + fi + fi + + log "Found ADB program: $_ADB" + + # Check that it works correctly + local ADB_VERSION + ADB_VERSION=$("$_ADB" version 2>/dev/null) + case $ADB_VERSION in + "Android Debug Bridge "*) # Pass + log "Found ADB version: $ADB_VERSION" + ;; + *) # Fail + _ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB" + _ADB_STATUS=1 + return 1 + esac + + _ADB_STATUS=0 + return 0 +} + + +# Return the path to the Android ADB program, if correctly detected. +# On failure, return the empty string. +# Out: ADB program path (or empty on failure) +# Return: success or failure. +adb_get_program () { + # Return cached value as soon as possible. + if [ -z "$_ADB_STATUS" ]; then + adb_check $1 + fi + echo "$_ADB" + return $_ADB_STATUS +} + +# Return the error corresponding to the last ADB function failure. +adb_get_error () { + echo "$_ADB_ERROR" +} + +# Check that there is one device connected through ADB. +# In case of failure, use adb_get_error to know why this failed. +# $1: Optional adb program path +# Return: success or failure. +_ADB_DEVICE= +_ADB_DEVICE_STATUS= +adb_check_device () { + if [ "$_ADB_DEVICE_STATUS" ]; then + return $_ADB_DEVICE_STATUS + fi + + # Check for ADB. + if ! adb_check $1; then + _ADB_DEVICE_STATUS=$_ADB_STATUS + return 1 + fi + + local ADB_DEVICES NUM_DEVICES FINGERPRINT + + # Count the number of connected devices. + ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }') + NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l) + case $NUM_DEVICES in + 0) + _ADB_ERROR="No Android device connected. Please connect one to your machine." + _ADB_DEVICE_STATUS=1 + return 1 + ;; + 1) # Pass + # Ensure the same device will be called in later adb_shell calls. + export ANDROID_SERIAL=$ADB_DEVICES + ;; + *) # 2 or more devices. + if [ "$ANDROID_SERIAL" ]; then + ADB_DEVICES=$ANDROID_SERIAL + NUM_DEVICES=1 + else + _ADB_ERROR="More than one Android device connected. \ +Please define ANDROID_SERIAL in your environment" + _ADB_DEVICE_STATUS=1 + return 1 + fi + ;; + esac + + _ADB_DEVICE_STATUS=0 + _ADB_DEVICE=$ADB_DEVICES + + FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) + log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)" + return 0 +} + +# The 'adb shell' command is pretty hopeless, try to make sense of it by: +# 1/ Removing trailing \r from line endings. +# 2/ Ensuring the function returns the command's status code. +# +# $1+: Command +# Out: command output (stdout + stderr combined) +# Return: command exit status +adb_shell () { + local RET ADB_LOG + # Check for ADB device. + adb_check_device || return 1 + ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX") + "$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1 + sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r. + RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code. + sed -e '$d' "$ADB_LOG" # Print everything except last line. + rm -f "$ADB_LOG" + return $RET +} + +# Push a file to a device. +# $1: source file path +# $2: device target file path +# Return: success or failure. +adb_push () { + adb_check_device || return 1 + run "$_ADB" push "$1" "$2" +} + +# Pull a file from a device +# $1: device file path +# $2: target host file path +# Return: success or failure. +adb_pull () { + adb_check_device || return 1 + run "$_ADB" pull "$1" "$2" +} + +# Same as adb_push, but will panic if the operations didn't succeed. +adb_install () { + adb_push "$@" + fail_panic "Failed to install $1 to the Android device at $2" +} + diff --git a/toolkit/crashreporter/google-breakpad/android/google_breakpad/Android.mk b/toolkit/crashreporter/google-breakpad/android/google_breakpad/Android.mk new file mode 100644 index 0000000000..8618492774 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/google_breakpad/Android.mk @@ -0,0 +1,104 @@ +# Copyright (c) 2012, 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. + +# ndk-build module definition for the Google Breakpad client library +# +# To use this file, do the following: +# +# 1/ Include this file from your own Android.mk, either directly +# or with through the NDK's import-module function. +# +# 2/ Use the client static library in your project with: +# +# LOCAL_STATIC_LIBRARIES += breakpad_client +# +# 3/ In your source code, include "src/client/linux/exception_handler.h" +# and use the Linux instructions to use it. +# +# This module works with either the STLport or GNU libstdc++, but you need +# to select one in your Application.mk +# + +# The top Google Breakpad directory. +# We assume this Android.mk to be under 'android/google_breakpad' + +LOCAL_PATH := $(call my-dir)/../.. + +# Defube the client library module, as a simple static library that +# exports the right include path / linker flags to its users. + +include $(CLEAR_VARS) + +LOCAL_MODULE := breakpad_client + +LOCAL_CPP_EXTENSION := .cc + +# Breakpad uses inline ARM assembly that requires the library +# to be built in ARM mode. Otherwise, the build will fail with +# cryptic assembler messages like: +# Compile++ thumb : google_breakpad_client <= crash_generation_client.cc +# /tmp/cc8aMSoD.s: Assembler messages: +# /tmp/cc8aMSoD.s:132: Error: invalid immediate: 288 is out of range +# /tmp/cc8aMSoD.s:244: Error: invalid immediate: 296 is out of range +LOCAL_ARM_MODE := arm + +# List of client source files, directly taken from Makefile.am +LOCAL_SRC_FILES := \ + src/client/linux/crash_generation/crash_generation_client.cc \ + src/client/linux/dump_writer_common/thread_info.cc \ + src/client/linux/dump_writer_common/ucontext_reader.cc \ + src/client/linux/handler/exception_handler.cc \ + src/client/linux/handler/minidump_descriptor.cc \ + src/client/linux/log/log.cc \ + src/client/linux/microdump_writer/microdump_writer.cc \ + src/client/linux/minidump_writer/linux_dumper.cc \ + src/client/linux/minidump_writer/linux_ptrace_dumper.cc \ + src/client/linux/minidump_writer/minidump_writer.cc \ + src/client/minidump_file_writer.cc \ + src/common/convert_UTF.cc \ + src/common/md5.cc \ + src/common/string_conversion.cc \ + src/common/linux/breakpad_getcontext.S \ + src/common/linux/elfutils.cc \ + src/common/linux/file_id.cc \ + src/common/linux/guid_creator.cc \ + src/common/linux/linux_libc_support.cc \ + src/common/linux/memory_mapped_file.cc \ + src/common/linux/safe_readlink.cc + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/common/android/include \ + $(LOCAL_PATH)/src \ + $(LSS_PATH) + +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_EXPORT_LDLIBS := -llog + +include $(BUILD_STATIC_LIBRARY) + +# Done. diff --git a/toolkit/crashreporter/google-breakpad/android/run-checks.sh b/toolkit/crashreporter/google-breakpad/android/run-checks.sh new file mode 100755 index 0000000000..51d2d50231 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/run-checks.sh @@ -0,0 +1,555 @@ +#!/bin/sh +# Copyright (c) 2012 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. + +# Sanitize the environment +export LANG=C +export LC_ALL=C + +if [ "$BASH_VERSION" ]; then + set -o posix +fi + +PROGDIR=$(dirname "$0") +PROGDIR=$(cd "$PROGDIR" && pwd) +PROGNAME=$(basename "$0") + +. $PROGDIR/common-functions.sh + +DEFAULT_ABI="armeabi" +VALID_ABIS="armeabi armeabi-v7a x86 mips" + +ABI= +ADB= +ALL_TESTS= +ENABLE_M32= +HELP= +HELP_ALL= +NDK_DIR= +NO_CLEANUP= +NO_DEVICE= +NUM_JOBS=$(get_core_count) +TMPDIR= + +for opt do + # The following extracts the value if the option is like --name=. + optarg=$(expr -- $opt : '^--[^=]*=\(.*\)$') + case $opt in + --abi=*) ABI=$optarg;; + --adb=*) ADB=$optarg;; + --all-tests) ALL_TESTS=true;; + --enable-m32) ENABLE_M32=true;; + --help|-h|-?) HELP=TRUE;; + --help-all) HELP_ALL=true;; + --jobs=*) NUM_JOBS=$optarg;; + --ndk-dir=*) NDK_DIR=$optarg;; + --tmp-dir=*) TMPDIR=$optarg;; + --no-cleanup) NO_CLEANUP=true;; + --no-device) NO_DEVICE=true;; + --quiet) decrease_verbosity;; + --verbose) increase_verbosity;; + -*) panic "Invalid option '$opt', see --help for details.";; + *) panic "This script doesn't take any parameters. See --help for details." + ;; + esac +done + +if [ "$HELP" -o "$HELP_ALL" ]; then + echo "\ + Usage: $PROGNAME [options] + + This script is used to check that your Google Breakpad source tree can + be properly built for Android, and that the client library and host tools + work properly together. +" + if [ "$HELP_ALL" ]; then + echo "\ + In more details, this script will: + + - Rebuild the host version of Google Breakpad in a temporary + directory (with the Auto-tools based build system). + + - Rebuild the Android client library with the Google Breakpad build + system (using autotools/configure). This requires that you define + ANDROID_NDK_ROOT in your environment to point to a valid Android NDK + installation directory, or use the --ndk-dir= option. + + - Rebuild the Android client library and a test crashing program with the + Android NDK build system (ndk-build). + + - Require an Android device connected to your machine, and the 'adb' + tool in your path. They are used to: + + - Install and run a test crashing program. + - Extract the corresponding minidump from the device. + - Dump the symbols from the test program on the host with 'dump_syms' + - Generate a stack trace with 'minidump_stackwalk' + - Check the stack trace content for valid source file locations. + + You can however skip this requirement and only test the builds by using + the --no-device flag. + + By default, all generated files will be created in a temporary directory + that is removed when the script completion. If you want to inspect the + files, use the --no-cleanup option. + + Finally, use --verbose to increase the verbosity level, this will help + you see which exact commands are being issues and their result. Use the + flag twice for even more output. Use --quiet to decrease verbosity + instead and run the script silently. + + If you have a device connected, the script will probe it to determine + its primary CPU ABI, and build the test program for it. You can however + use the --abi= option to override this (this can be useful to check + the secondary ABI, e.g. using --abi=armeabi to check that such a program + works correctly on an ARMv7-A device). + + If you don't have a device connected, the test program will be built (but + not run) with the default '$DEFAULT_ABI' ABI. Again, you can use + --abi= to override this. Valid ABI names are: + + $VALID_ABIS + + The script will only run the client library unit test on the device + by default. You can use --all-tests to also build and run the unit + tests for the Breakpad tools and processor, but be warned that this + adds several minutes of testing time. --all-tests will also run the + host unit tests suite. +" + + fi # HELP_ALL + + echo "\ + Valid options: + + --help|-h|-? Display this message. + --help-all Display extended help. + --enable-m32 Build 32-bit version of host tools. + --abi= Specify target CPU ABI [auto-detected]. + --jobs= Run build tasks in parallel [$NUM_JOBS]. + --ndk-dir= Specify NDK installation directory. + --tmp-dir= Specify temporary directory (will be wiped-out). + --adb= Specify adb program path. + --no-cleanup Don't remove temporary directory after completion. + --no-device Do not try to detect devices, nor run crash test. + --all-tests Run all unit tests (i.e. tools and processor ones too). + --verbose Increase verbosity. + --quiet Decrease verbosity." + + exit 0 +fi + +TESTAPP_DIR=$PROGDIR/sample_app + +# Select NDK install directory. +if [ -z "$NDK_DIR" ]; then + if [ -z "$ANDROID_NDK_ROOT" ]; then + panic "Please define ANDROID_NDK_ROOT in your environment, or use \ +--ndk-dir=." + fi + NDK_DIR="$ANDROID_NDK_ROOT" + log "Found NDK directory: $NDK_DIR" +else + log "Using NDK directory: $NDK_DIR" +fi +# Small sanity check. +NDK_BUILD="$NDK_DIR/ndk-build" +if [ ! -f "$NDK_BUILD" ]; then + panic "Your NDK directory is not valid (missing ndk-build): $NDK_DIR" +fi + +# Ensure the temporary directory is deleted on exit, except if the --no-cleanup +# option is used. + +clean_tmpdir () { + if [ "$TMPDIR" ]; then + if [ -z "$NO_CLEANUP" ]; then + log "Cleaning up: $TMPDIR" + rm -rf "$TMPDIR" + else + dump "Temporary directory contents preserved: $TMPDIR" + fi + fi + exit "$@" +} + +atexit clean_tmpdir + +# If --tmp-dir= is not used, create a temporary directory. +# Otherwise, start by cleaning up the user-provided path. +if [ -z "$TMPDIR" ]; then + TMPDIR=$(mktemp -d /tmp/$PROGNAME.XXXXXXXX) + fail_panic "Can't create temporary directory!" + log "Using temporary directory: $TMPDIR" +else + if [ ! -d "$TMPDIR" ]; then + mkdir -p "$TMPDIR" + fail_panic "Can't create temporary directory: $TMPDIR" + else + log "Cleaning up temporary directory: $TMPDIR" + rm -rf "$TMPDIR"/* + fail_panic "Cannot cleanup temporary directory!" + fi +fi + +if [ -z "$NO_DEVICE" ]; then + if ! adb_check_device $ADB; then + echo "$(adb_get_error)" + echo "Use --no-device to build the code without running any tests." + exit 1 + fi +fi + +BUILD_LOG="$TMPDIR/build.log" +RUN_LOG="$TMPDIR/run.log" +CRASH_LOG="$TMPDIR/crash.log" + +set_run_log "$RUN_LOG" + +TMPHOST="$TMPDIR/host-local" + +cd "$TMPDIR" + +# Build host version of the tools +dump "Building host binaries." +CONFIGURE_FLAGS= +if [ "$ENABLE_M32" ]; then + CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-m32" +fi +( + run mkdir "$TMPDIR/build-host" && + run cd "$TMPDIR/build-host" && + run2 "$PROGDIR/../configure" --prefix="$TMPHOST" $CONFIGURE_FLAGS && + run2 make -j$NUM_JOBS install +) +fail_panic "Can't build host binaries!" + +if [ "$ALL_TESTS" ]; then + dump "Running host unit tests." + ( + run cd "$TMPDIR/build-host" && + run2 make -j$NUM_JOBS check + ) + fail_panic "Host unit tests failed!!" +fi + +TMPBIN=$TMPHOST/bin + +# Generate a stand-alone NDK toolchain + +# Extract CPU ABI and architecture from device, if any. +if adb_check_device; then + DEVICE_ABI=$(adb_shell getprop ro.product.cpu.abi) + DEVICE_ABI2=$(adb_shell getprop ro.product.cpu.abi2) + if [ -z "$DEVICE_ABI" ]; then + panic "Can't extract ABI from connected device!" + fi + if [ "$DEVICE_ABI2" ]; then + dump "Found device ABIs: $DEVICE_ABI $DEVICE_ABI2" + else + dump "Found device ABI: $DEVICE_ABI" + DEVICE_ABI2=$DEVICE_ABI + fi + + # If --abi= is used, check that the device supports it. + if [ "$ABI" -a "$DEVICE_ABI" != "$ABI" -a "$DEVICE_ABI2" != "$ABI" ]; then + dump "ERROR: Device ABI(s) do not match --abi command-line value ($ABI)!" + panic "Please use --no-device to skip device tests." + fi + + if [ -z "$ABI" ]; then + ABI=$DEVICE_ABI + dump "Using CPU ABI: $ABI (device)" + else + dump "Using CPU ABI: $ABI (command-line)" + fi +else + if [ -z "$ABI" ]; then + # No device connected, choose default ABI + ABI=$DEFAULT_ABI + dump "Using CPU ABI: $ABI (default)" + else + dump "Using CPU ABI: $ABI (command-line)" + fi +fi + +# Check the ABI value +VALID= +for VALID_ABI in $VALID_ABIS; do + if [ "$ABI" = "$VALID_ABI" ]; then + VALID=true + break + fi +done + +if [ -z "$VALID" ]; then + panic "Unknown CPU ABI '$ABI'. Valid values are: $VALID_ABIS" +fi + +# Extract architecture name from ABI +case $ABI in + armeabi*) ARCH=arm;; + *) ARCH=$ABI;; +esac + +# Extract GNU configuration name +case $ARCH in + arm) + GNU_CONFIG=arm-linux-androideabi + ;; + x86) + GNU_CONFIG=i686-linux-android + ;; + mips) + GNU_CONFIG=mipsel-linux-android + ;; + *) + GNU_CONFIG="$ARCH-linux-android" + ;; +esac + +# Generate standalone NDK toolchain installation +NDK_STANDALONE="$TMPDIR/ndk-$ARCH-toolchain" +echo "Generating NDK standalone toolchain installation" +mkdir -p "$NDK_STANDALONE" +# NOTE: The --platform=android-9 is required to provide for GTest. +run "$NDK_DIR/build/tools/make-standalone-toolchain.sh" \ + --arch="$ARCH" \ + --platform=android-9 \ + --install-dir="$NDK_STANDALONE" +fail_panic "Can't generate standalone NDK toolchain installation!" + +# Rebuild the client library, processor and tools with the auto-tools based +# build system. Even though it's not going to be used, this checks that this +# still works correctly. +echo "Building full Android binaries with configure/make" +TMPTARGET="$TMPDIR/target-local" +( + PATH="$NDK_STANDALONE/bin:$PATH" + run mkdir "$TMPTARGET" && + run mkdir "$TMPDIR"/build-target && + run cd "$TMPDIR"/build-target && + run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ + --host="$GNU_CONFIG" && + run2 make -j$NUM_JOBS install +) +fail_panic "Could not rebuild Android binaries!" + +# Build and/or run unit test suite. +# If --no-device is used, only rebuild it, otherwise, run in on the +# connected device. +if [ "$NO_DEVICE" ]; then + ACTION="Building" + # This is a trick to force the Makefile to ignore running the scripts. + TESTS_ENVIRONMENT="TESTS_ENVIRONMENT=true" +else + ACTION="Running" + TESTS_ENVIRONMENT= +fi + +( + PATH="$NDK_STANDALONE/bin:$PATH" + run cd "$TMPDIR"/build-target && + # Reconfigure to only run the client unit test suite. + # This one should _never_ fail. + dump "$ACTION Android client library unit tests." + run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ + --host="$GNU_CONFIG" \ + --disable-tools \ + --disable-processor && + run make -j$NUM_JOBS check $TESTS_ENVIRONMENT || exit $? + + if [ "$ALL_TESTS" ]; then + dump "$ACTION Tools and processor unit tests." + # Reconfigure to run the processor and tools tests. + # Most of these fail for now, so do not worry about it. + run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \ + --host="$GNU_CONFIG" && + run make -j$NUM_JOBS check $TESTS_ENVIRONMENT + if [ $? != 0 ]; then + dump "Tools and processor unit tests failed as expected. \ +Use --verbose for results." + fi + fi +) +fail_panic "Client library unit test suite failed!" + +# Copy sources to temporary directory +PROJECT_DIR=$TMPDIR/project +dump "Copying test program sources to: $PROJECT_DIR" +run cp -r "$TESTAPP_DIR" "$PROJECT_DIR" && +run rm -rf "$PROJECT_DIR/obj" && +run rm -rf "$PROJECT_DIR/libs" +fail_panic "Could not copy test program sources to: $PROJECT_DIR" + +# Build the test program with ndk-build. +dump "Building test program with ndk-build" +export NDK_MODULE_PATH="$PROGDIR" +NDK_BUILD_FLAGS="-j$NUM_JOBS" +if verbosity_is_higher_than 1; then + NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS NDK_LOG=1 V=1" +fi +run "$NDK_DIR/ndk-build" -C "$PROJECT_DIR" $NDK_BUILD_FLAGS APP_ABI=$ABI +fail_panic "Can't build test program!" + +# Unless --no-device was used, stop right here if ADB isn't in the path, +# or there is no connected device. +if [ "$NO_DEVICE" ]; then + dump "Done. Please connect a device to run all tests!" + clean_exit 0 +fi + +# Push the program to the device. +TESTAPP=test_google_breakpad +TESTAPP_FILE="$PROJECT_DIR/libs/$ABI/test_google_breakpad" +if [ ! -f "$TESTAPP_FILE" ]; then + panic "Device requires '$ABI' binaries. None found!" +fi + +# Run the program there +dump "Installing test program on device" +DEVICE_TMP=/data/local/tmp +adb_push "$TESTAPP_FILE" "$DEVICE_TMP/" +fail_panic "Cannot push test program to device!" + +dump "Running test program on device" +adb_shell cd "$DEVICE_TMP" "&&" ./$TESTAPP > "$CRASH_LOG" 2>/dev/null +if [ $? = 0 ]; then + panic "Test program did *not* crash as expected!" +fi +if verbosity_is_higher_than 0; then + echo -n "Crash log: " + cat "$CRASH_LOG" +fi + +# Extract minidump from device +MINIDUMP_NAME=$(awk '$1 == "Dump" && $2 == "path:" { print $3; }' "$CRASH_LOG") +MINIDUMP_NAME=$(basename "$MINIDUMP_NAME") +if [ -z "$MINIDUMP_NAME" ]; then + panic "Test program didn't write minidump properly!" +fi + +dump "Extracting minidump: $MINIDUMP_NAME" +adb_pull "$DEVICE_TMP/$MINIDUMP_NAME" . +fail_panic "Can't extract minidump!" + +dump "Parsing test program symbols" +if verbosity_is_higher_than 1; then + log "COMMAND: $TMPBIN/dump_syms \ + $PROJECT_DIR/obj/local/$ABI/$TESTAPP >$TESTAPP.sym" +fi +"$TMPBIN/dump_syms" "$PROJECT_DIR/obj/local/$ABI/$TESTAPP" > $TESTAPP.sym +fail_panic "dump_syms doesn't work!" + +VERSION=$(awk '$1 == "MODULE" { print $4; }' $TESTAPP.sym) +dump "Found module version: $VERSION" +if [ -z "$VERSION" ]; then + echo "ERROR: Can't find proper module version from symbol dump!" + head -n5 $TESTAPP.sym + clean_exit 1 +fi + +run mkdir -p "$TMPDIR/symbols/$TESTAPP/$VERSION" +run mv $TESTAPP.sym "$TMPDIR/symbols/$TESTAPP/$VERSION/" + +dump "Generating stack trace" +# Don't use 'run' to be able to send stdout and stderr to two different files. +log "COMMAND: $TMPBIN/minidump_stackwalk $MINIDUMP_NAME symbols" +"$TMPBIN/minidump_stackwalk" $MINIDUMP_NAME \ + "$TMPDIR/symbols" \ + > "$BUILD_LOG" 2>>"$RUN_LOG" +fail_panic "minidump_stackwalk doesn't work!" + +dump "Checking stack trace content" + +if verbosity_is_higher_than 1; then + cat "$BUILD_LOG" +fi + +# The generated stack trace should look like the following: +# +# Thread 0 (crashed) +# 0 test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4] +# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c +# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 +# sp = 0xbea2cb50 lr = 0x00009025 pc = 0x00008f84 +# Found by: given as instruction pointer in context +# 1 test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3] +# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c +# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 +# sp = 0xbea2cb50 pc = 0x00009025 +# Found by: call frame info +# 2 libc.so + 0x164e5 +# r4 = 0x00008f64 r5 = 0xbea2cc34 r6 = 0x00000001 r7 = 0xbea2cc3c +# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000 +# sp = 0xbea2cc18 pc = 0x400c34e7 +# Found by: call frame info +# ... +# +# The most important part for us is ensuring that the source location could +# be extracted, so look at the 'test_breakpad.cpp' references here. +# +# First, extract all the lines with test_google_breakpad! in them, and +# dump the corresponding crash location. +# +# Note that if the source location can't be extracted, the second field +# will only be 'test_google_breakpad' without the exclamation mark. +# +LOCATIONS=$(awk '$2 ~ "^test_google_breakpad!.*" { print $3; }' "$BUILD_LOG") + +if [ -z "$LOCATIONS" ]; then + if verbosity_is_lower_than 1; then + cat "$BUILD_LOG" + fi + panic "No source location found in stack trace!" +fi + +# Now check that they all match "[" +BAD_LOCATIONS= +for LOCATION in $LOCATIONS; do + case $LOCATION in + # Escape the opening bracket, or some shells like Dash will not + # match them properly. + \[*.cpp|\[*.cc|\[*.h) # These are valid source locations in our executable + ;; + *) # Everything else is not! + BAD_LOCATIONS="$BAD_LOCATIONS $LOCATION" + ;; + esac +done + +if [ "$BAD_LOCATIONS" ]; then + dump "ERROR: Generated stack trace doesn't contain valid source locations:" + cat "$BUILD_LOG" + echo "Bad locations are: $BAD_LOCATIONS" + exit 1 +fi + +echo "All clear! Congratulations." + diff --git a/toolkit/crashreporter/google-breakpad/android/sample_app/README b/toolkit/crashreporter/google-breakpad/android/sample_app/README new file mode 100644 index 0000000000..aa19dbb447 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/sample_app/README @@ -0,0 +1,32 @@ +This is a sample Android executable that can be used to test the +Google Breakpad client library on Android. + +Its purpose is simply to crash and generate a minidump under /data/local/tmp. + +Build instructions: + + cd android/sample_app + $NDK/ndk-build + + Where $NDK points to a valid Android NDK installation. + +Usage instructions: + + After buildind the test program, send it to a device, then run it as + the shell UID: + + adb push libs/armeabi/test_google_breakpad /data/local/tmp + adb shell /data/local/tmp/test_google_breakpad + + This will simply crash after dumping the name of the generated minidump + file. + + See jni/test_breakpad.cpp for details. + + Use 'armeabi-v7a' instead of 'armeabi' above to test the ARMv7-A version + of the binary. + +Note: + If you plan to use the library in a regular Android application, store + the minidump files either to your app-specific directory, or to the SDCard + (the latter requiring a specific permission). diff --git a/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Android.mk b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Android.mk new file mode 100644 index 0000000000..61487b52c1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Android.mk @@ -0,0 +1,44 @@ +# Copyright (c) 2012, 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := test_google_breakpad +LOCAL_SRC_FILES := test_breakpad.cpp +LOCAL_STATIC_LIBRARIES += breakpad_client +include $(BUILD_EXECUTABLE) + +# If NDK_MODULE_PATH is defined, import the module, otherwise do a direct +# includes. This allows us to build in all scenarios easily. +ifneq ($(NDK_MODULE_PATH),) + $(call import-module,google_breakpad) +else + include $(LOCAL_PATH)/../../google_breakpad/Android.mk +endif diff --git a/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Application.mk b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Application.mk new file mode 100644 index 0000000000..9728017d3f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/Application.mk @@ -0,0 +1,32 @@ +# Copyright (c) 2012, 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. + +APP_STL := stlport_static +APP_ABI := all +APP_CXXFLAGS := -std=c++11 -D__STDC_LIMIT_MACROS diff --git a/toolkit/crashreporter/google-breakpad/android/sample_app/jni/test_breakpad.cpp b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/test_breakpad.cpp new file mode 100644 index 0000000000..9c4ebbb148 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/sample_app/jni/test_breakpad.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2012, 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 + +#include "client/linux/handler/exception_handler.h" +#include "client/linux/handler/minidump_descriptor.h" + +namespace { + +bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + printf("Dump path: %s\n", descriptor.path()); + return succeeded; +} + +void Crash() { + volatile int* a = reinterpret_cast(NULL); + *a = 1; +} + +} // namespace + +int main(int argc, char* argv[]) { + google_breakpad::MinidumpDescriptor descriptor("."); + google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback, + NULL, true, -1); + Crash(); + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/android/test-driver b/toolkit/crashreporter/google-breakpad/android/test-driver new file mode 100755 index 0000000000..eaaac6b295 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/test-driver @@ -0,0 +1,131 @@ +#! /bin/sh +# test-driver - basic testsuite driver script. + +# Slightly modified for Android, see ANDROID comment below. + +scriptversion=2012-06-27.10; # UTC + +# Copyright (C) 2011-2013 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +usage_error () +{ + echo "$0: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat < $log_file 2>&1 +progdir=$(dirname "$0") +"$progdir/test-shell.sh" "$@" > $log_file 2>&1 +estatus=$? +if test $enable_hard_errors = no && test $estatus -eq 99; then + estatus=1 +fi + +case $estatus:$expect_failure in + 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; + 0:*) col=$grn res=PASS recheck=no gcopy=no;; + 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; + 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; + *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; + *:*) col=$red res=FAIL recheck=yes gcopy=yes;; +esac + +# Report outcome to console. +echo "${col}${res}${std}: $test_name" + +# Register the test result, and other relevant metadata. +echo ":test-result: $res" > $trs_file +echo ":global-test-result: $res" >> $trs_file +echo ":recheck: $recheck" >> $trs_file +echo ":copy-in-global-log: $gcopy" >> $trs_file + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/toolkit/crashreporter/google-breakpad/android/test-shell.sh b/toolkit/crashreporter/google-breakpad/android/test-shell.sh new file mode 100755 index 0000000000..3677d8755a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/android/test-shell.sh @@ -0,0 +1,131 @@ +#!/bin/sh +# +# Copyright (c) 2012 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 special shell wrapper that can be used to run the Google Breakpad unit +# tests on a connected Android device. +# +# This is designed to be called from the Makefile during 'make check' +# + +PROGDIR=$(dirname "$0") +PROGNAME=$(basename "$0") +. $PROGDIR/common-functions.sh + +# Extract test program name first. +TEST_PROGRAM=$1 +shift + +if [ -z "$TEST_PROGRAM" ]; then + panic "No test program/script name on the command-line!" +fi + +if [ ! -f "$TEST_PROGRAM" ]; then + panic "Can't find test program/script: $TEST_PROGRAM" +fi + +# Create test directory on the device +TEST_DIR=/data/local/tmp/test-google-breakpad-$$ +adb_shell mkdir "$TEST_DIR" || + panic "Can't create test directory on device: $TEST_DIR" + +# Ensure that it is always removed when the script exits. +clean_test_dir () { + # Don't care about success/failure, use '$ADB shell' directly. + adb_shell rm -r "$TEST_DIR" +} + +atexit clean_test_dir + +TEST_PROGRAM_NAME=$(basename "$TEST_PROGRAM") +TEST_PROGRAM_DIR=$(dirname "$TEST_PROGRAM") + +# Handle special case(s) here. +DATA_FILES= +case $TEST_PROGRAM_NAME in + linux_client_unittest) + # linux_client_unittest will call another executable at runtime, ensure + # it is installed too. + adb_install "$TEST_PROGRAM_DIR/linux_dumper_unittest_helper" "$TEST_DIR" + # linux_client_unittest loads a shared library at runtime, ensure it is + # installed too. + adb_install "$TEST_PROGRAM_DIR/linux_client_unittest_shlib" "$TEST_DIR" + ;; + basic_source_line_resolver_unittest) + DATA_FILES="module1.out \ + module2.out \ + module3_bad.out \ + module4_bad.out" + ;; + exploitability_unittest) + DATA_FILES="scii_read_av.dmp \ + ascii_read_av_block_write.dmp \ + ascii_read_av_clobber_write.dmp \ + ascii_read_av_conditional.dmp \ + ascii_read_av_non_null.dmp \ + ascii_read_av_then_jmp.dmp \ + ascii_read_av_xchg_write.dmp \ + ascii_write_av.dmp \ + ascii_write_av_arg_to_call.dmp \ + exec_av_on_stack.dmp \ + null_read_av.dmp \ + null_write_av.dmp \ + read_av.dmp \ + null_read_av.dmp \ + write_av_non_null.dmp" + ;; + fast_source_line_resolver_unittest) + DATA_FILES="module0.out \ + module1.out \ + module2.out \ + module3_bad.out \ + module4_bad.out" + ;; + minidump_processor_unittest|minidump_unittest) + DATA_FILES="src/processor/testdata/minidump2.dmp" + ;; +esac + +# Install the data files, their path is relative to the environment +# variable 'srcdir' +for FILE in $DATA_FILES; do + FILEDIR=src/processor/testdata/$(dirname "$FILE") + adb_shell mkdir -p "$TEST_DIR/$FILEDIR" + adb_install "${srcdir:-.}/$FILE" "$TEST_DIR"/"$FILE" +done + +# Copy test program to device +adb_install "$TEST_PROGRAM" "$TEST_DIR" + +# Run it +adb_shell "cd $TEST_DIR && LD_LIBRARY_PATH=. ./$TEST_PROGRAM_NAME $@" + +# Note: exiting here will call cleanup_exit which will remove the temporary +# files from the device. diff --git a/toolkit/crashreporter/google-breakpad/breakpad-client.pc.in b/toolkit/crashreporter/google-breakpad/breakpad-client.pc.in new file mode 100644 index 0000000000..fcd2fa27e7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/breakpad-client.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/@PACKAGE_NAME@ + +Name: google-breakpad-client +Description: An open-source multi-platform crash reporting system +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbreakpad_client @PTHREAD_LIBS@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ diff --git a/toolkit/crashreporter/google-breakpad/breakpad.pc.in b/toolkit/crashreporter/google-breakpad/breakpad.pc.in new file mode 100644 index 0000000000..9aec9f8cb4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/breakpad.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/@PACKAGE_NAME@ + +Name: google-breakpad +Description: An open-source multi-platform crash reporting system +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbreakpad @PTHREAD_LIBS@ +Cflags: -I${includedir} @PTHREAD_CFLAGS@ diff --git a/toolkit/crashreporter/google-breakpad/codereview.settings b/toolkit/crashreporter/google-breakpad/codereview.settings new file mode 100644 index 0000000000..3f93733e4a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/codereview.settings @@ -0,0 +1,3 @@ +GERRIT_HOST: True +CODE_REVIEW_SERVER: chromium-review.googlesource.com +VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/ diff --git a/toolkit/crashreporter/google-breakpad/configure b/toolkit/crashreporter/google-breakpad/configure new file mode 100755 index 0000000000..5e4b3d2e80 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/configure @@ -0,0 +1,9231 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for breakpad 0.1. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: google-breakpad-dev@googlegroups.com about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='breakpad' +PACKAGE_TARNAME='breakpad' +PACKAGE_VERSION='0.1' +PACKAGE_STRING='breakpad 0.1' +PACKAGE_BUGREPORT='google-breakpad-dev@googlegroups.com' +PACKAGE_URL='' + +ac_unique_file="README.md" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +TESTS_AS_ROOT_FALSE +TESTS_AS_ROOT_TRUE +RUST_DEMANGLE_LIBS +RUST_DEMANGLE_CFLAGS +SELFTEST_FALSE +SELFTEST_TRUE +GTEST_LIBS +GTEST_CFLAGS +GMOCK_LIBS +GMOCK_CFLAGS +SYSTEM_TEST_LIBS_FALSE +SYSTEM_TEST_LIBS_TRUE +DISABLE_TOOLS_FALSE +DISABLE_TOOLS_TRUE +DISABLE_PROCESSOR_FALSE +DISABLE_PROCESSOR_TRUE +X86_HOST_FALSE +X86_HOST_TRUE +ANDROID_HOST_FALSE +ANDROID_HOST_TRUE +LINUX_HOST_FALSE +LINUX_HOST_TRUE +WARN_CXXFLAGS +HAVE_CXX11 +HAVE_GETCONTEXT_FALSE +HAVE_GETCONTEXT_TRUE +PTHREAD_CFLAGS +PTHREAD_LIBS +PTHREAD_CC +ax_pthread_config +EGREP +GREP +RANLIB +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +CPP +am__fastdepCCAS_FALSE +am__fastdepCCAS_TRUE +CCASDEPMODE +CCASFLAGS +CCAS +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +ac_ct_AR +AR +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_m32 +enable_largefile +enable_processor +enable_tools +enable_system_test_libs +enable_selftest +with_rust_demangle +with_tests_as_root +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCAS +CCASFLAGS +CPP +CXX +CXXFLAGS +CCC +GMOCK_CFLAGS +GMOCK_LIBS +GTEST_CFLAGS +GTEST_LIBS +RUST_DEMANGLE_CFLAGS +RUST_DEMANGLE_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures breakpad 0.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/breakpad] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of breakpad 0.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-m32 Compile/build with -m32 (default is no) + --disable-largefile omit support for large files + --disable-processor Don't build processor library (default is no) + --disable-tools Don't build tool binaries (default is no) + --enable-system-test-libs + Use gtest/gmock/etc... from the system instead of + the local copies (default is local) + --enable-selftest Run extra tests with "make check" (may conflict with + optimizations) (default is no) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-rust-demangle=/path/to/rust-demangle-capi + Link against the rust-demangle library to demangle + Rust language symbols during symbol dumping (default + is no) Pass the path to the crate root. + --with-tests-as-root Run the tests as root. Use this on platforms like + travis-ci.org that require root privileges to use + ptrace (default is no) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CCAS assembler compiler command (defaults to CC) + CCASFLAGS assembler compiler flags (defaults to CFLAGS) + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + GMOCK_CFLAGS + Compiler flags for gmock + GMOCK_LIBS Linker flags for gmock + GTEST_CFLAGS + Compiler flags for gtest + GTEST_LIBS Linker flags for gtest + RUST_DEMANGLE_CFLAGS + Compiler flags for rust-demangle + RUST_DEMANGLE_LIBS + Linker flags for rust-demangle + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +breakpad configure 0.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## --------------------------------------------------- ## +## Report this to google-breakpad-dev@googlegroups.com ## +## --------------------------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by breakpad $as_me 0.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in autotools "$srcdir"/autotools; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in autotools \"$srcdir\"/autotools" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +am__api_version='1.15' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='breakpad' + VERSION='0.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' + +# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + if test $am_uid -le $am_max_uid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + if test $am_gid -le $am_max_gid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_ustar-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if ${am_cv_prog_tar_ustar+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +ac_config_headers="$ac_config_headers src/config.h" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar lib "link -lib" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar lib "link -lib" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 +$as_echo_n "checking the archiver ($AR) interface... " >&6; } +if ${am_cv_ar_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + am_cv_ar_interface=ar + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int some_variable = 0; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 + (eval $am_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 +$as_echo "$am_cv_ar_interface" >&6; } + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + as_fn_error $? "could not determine $AR interface" "$LINENO" 5 + ;; +esac + +# By default we simply use the C compiler to build assembly code. + +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS + + + +depcc="$CCAS" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CCAS_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CCAS_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CCAS_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CCAS_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } +CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then + am__fastdepCCAS_TRUE= + am__fastdepCCAS_FALSE='#' +else + am__fastdepCCAS_TRUE='#' + am__fastdepCCAS_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +# Check whether --enable-m32 was given. +if test "${enable_m32+set}" = set; then : + enableval=$enable_m32; case "${enableval}" in + yes) + CFLAGS="${CFLAGS} -m32" + CXXFLAGS="${CXXFLAGS} -m32" + usem32=true + ;; + no) + usem32=false + ;; + *) + as_fn_error $? "bad value ${enableval} for --enable-m32" "$LINENO" 5 + ;; + esac +else + usem32=false +fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 +$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_join (); +int +main () +{ +return pthread_join (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test x"$ax_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" + ;; + + *-darwin*) + acx_pthread_flags="-pthread $acx_pthread_flags" + ;; +esac + +if test x"$ax_pthread_ok" = xno; then +for flag in $ax_pthread_flags; do + + case $flag in + none) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 +$as_echo_n "checking whether pthreads work without any flags... " >&6; } + ;; + + -*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 +$as_echo_n "checking whether pthreads work with $flag... " >&6; } + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. +set dummy pthread-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ax_pthread_config+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ax_pthread_config"; then + ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ax_pthread_config="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" +fi +fi +ax_pthread_config=$ac_cv_prog_ax_pthread_config +if test -n "$ax_pthread_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +$as_echo "$ax_pthread_config" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test x"$ax_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 +$as_echo_n "checking for the pthreads library -l$flag... " >&6; } + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + static void routine(void* a) {a=0;} + static void* start_routine(void* a) {return a;} +int +main () +{ +pthread_t th; pthread_attr_t attr; + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_create(&th,0,start_routine,0); + pthread_cleanup_pop(0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_pthread_ok=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 +$as_echo_n "checking for joinable pthread attribute... " >&6; } + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +int attr=$attr; return attr; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + attr_name=$attr; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 +$as_echo "$attr_name" >&6; } + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + +cat >>confdefs.h <<_ACEOF +#define PTHREAD_CREATE_JOINABLE $attr_name +_ACEOF + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 +$as_echo_n "checking if more special flags are required for pthreads... " >&6; } + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 +$as_echo "${flag}" >&6; } + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + for ac_prog in xlc_r cc_r +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PTHREAD_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PTHREAD_CC"; then + ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_PTHREAD_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PTHREAD_CC=$ac_cv_prog_PTHREAD_CC +if test -n "$PTHREAD_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 +$as_echo "$PTHREAD_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$PTHREAD_CC" && break +done +test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" + + else + PTHREAD_CC=$CC + fi +else + PTHREAD_CC="$CC" +fi + + + + + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$ax_pthread_ok" = xyes; then + +$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h + + : +else + ax_pthread_ok=no + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in a.out.h sys/random.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_func in arc4random getcontext getrandom +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + if test "x$ac_cv_func_getcontext" = xyes; then + HAVE_GETCONTEXT_TRUE= + HAVE_GETCONTEXT_FALSE='#' +else + HAVE_GETCONTEXT_TRUE='#' + HAVE_GETCONTEXT_FALSE= +fi + + + + ax_cxx_compile_cxx11_required=true + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + ac_success=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 +$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; } +if ${ax_cv_cxx_compile_cxx11+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_cxx_compile_cxx11=yes +else + ax_cv_cxx_compile_cxx11=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 +$as_echo "$ax_cv_cxx_compile_cxx11" >&6; } + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + + + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x +std=c++11 "-h std=c++11"; do + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval \${$cachevar+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval $cachevar=yes +else + eval $cachevar=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="$ac_save_CXXFLAGS" +fi +eval ac_res=\$$cachevar + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 +$as_echo "$as_me: No compiler with C++11 support was found" >&6;} + else + HAVE_CXX11=1 + +$as_echo "#define HAVE_CXX11 1" >>confdefs.h + + fi + + + fi + + +WARN_CXXFLAGS= +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5 +$as_echo_n "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; } +if ${ax_cv_check_cxxflags___Werror_unknown_warning_option+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CXXFLAGS + CXXFLAGS="$CXXFLAGS -Werror=unknown-warning-option" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_check_cxxflags___Werror_unknown_warning_option=yes +else + ax_cv_check_cxxflags___Werror_unknown_warning_option=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS=$ax_check_save_flags +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___Werror_unknown_warning_option" >&5 +$as_echo "$ax_cv_check_cxxflags___Werror_unknown_warning_option" >&6; } +if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes; then : + + ax_compiler_flags_test="-Werror=unknown-warning-option" + +else + + ax_compiler_flags_test="" + +fi + + + + + +for flag in -Wmissing-braces -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-compare -Wunused-local-typedefs -Wunused-variable -Wvla ; do + as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags_${ax_compiler_flags_test}_$flag" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5 +$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; } +if eval \${$as_CACHEVAR+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ax_check_save_flags=$CXXFLAGS + CXXFLAGS="$CXXFLAGS ${ax_compiler_flags_test} $flag" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$as_CACHEVAR=yes" +else + eval "$as_CACHEVAR=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS=$ax_check_save_flags +fi +eval ac_res=\$$as_CACHEVAR + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then : + +if ${WARN_CXXFLAGS+:} false; then : + + case " $WARN_CXXFLAGS " in #( + *" $flag "*) : + { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS already contains \$flag"; } >&5 + (: WARN_CXXFLAGS already contains $flag) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } ;; #( + *) : + + as_fn_append WARN_CXXFLAGS " $flag" + { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 + (: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + ;; +esac + +else + + WARN_CXXFLAGS=$flag + { { $as_echo "$as_me:${as_lineno-$LINENO}: : WARN_CXXFLAGS=\"\$WARN_CXXFLAGS\""; } >&5 + (: WARN_CXXFLAGS="$WARN_CXXFLAGS") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + +fi + +else + : +fi + +done + +as_fn_append WARN_CXXFLAGS " -Werror" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC defined in fcntl.h" >&5 +$as_echo_n "checking for O_CLOEXEC defined in fcntl.h... " >&6; } +if ${ac_cv_defined_O_CLOEXEC_fcntl_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ + + #ifdef O_CLOEXEC + int ok; + #else + choke me + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_defined_O_CLOEXEC_fcntl_h=yes +else + ac_cv_defined_O_CLOEXEC_fcntl_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined_O_CLOEXEC_fcntl_h" >&5 +$as_echo "$ac_cv_defined_O_CLOEXEC_fcntl_h" >&6; } +if test $ac_cv_defined_O_CLOEXEC_fcntl_h != "no"; then : + +else + +$as_echo "#define O_CLOEXEC 0" >>confdefs.h + +fi + +# Only build Linux client libs when compiling for Linux +case $host in + *-*-linux* | *-android* ) + LINUX_HOST=true + ;; +esac + if test x$LINUX_HOST = xtrue; then + LINUX_HOST_TRUE= + LINUX_HOST_FALSE='#' +else + LINUX_HOST_TRUE='#' + LINUX_HOST_FALSE= +fi + + +# Only use Android support headers when compiling for Android +case $host in + *-android*) + ANDROID_HOST=true + ;; +esac + if test x$ANDROID_HOST = xtrue; then + ANDROID_HOST_TRUE= + ANDROID_HOST_FALSE='#' +else + ANDROID_HOST_TRUE='#' + ANDROID_HOST_FALSE= +fi + + +# Some tools (like mac ones) only support x86 currently. +case $host_cpu in + i?86|x86_64) + X86_HOST=true + ;; +esac + if test x$X86_HOST = xtrue; then + X86_HOST_TRUE= + X86_HOST_FALSE='#' +else + X86_HOST_TRUE='#' + X86_HOST_FALSE= +fi + + +# Check whether --enable-processor was given. +if test "${enable_processor+set}" = set; then : + enableval=$enable_processor; case "${enableval}" in + yes) + disable_processor=false + ;; + no) + disable_processor=true + ;; + *) + as_fn_error $? "bad value ${enableval} for --disable-processor" "$LINENO" 5 + ;; + esac +else + disable_processor=false +fi + + if test x$disable_processor = xtrue; then + DISABLE_PROCESSOR_TRUE= + DISABLE_PROCESSOR_FALSE='#' +else + DISABLE_PROCESSOR_TRUE='#' + DISABLE_PROCESSOR_FALSE= +fi + + +# Check whether --enable-tools was given. +if test "${enable_tools+set}" = set; then : + enableval=$enable_tools; case "${enableval}" in + yes) + disable_tools=false + ;; + no) + disable_tools=true + ;; + *) + as_fn_error $? "bad value ${enableval} for --disable-tools" "$LINENO" 5 + ;; + esac +else + disable_tools=false +fi + + if test x$disable_tools = xtrue; then + DISABLE_TOOLS_TRUE= + DISABLE_TOOLS_FALSE='#' +else + DISABLE_TOOLS_TRUE='#' + DISABLE_TOOLS_FALSE= +fi + + +if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then + as_fn_error $? "--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!" "$LINENO" 5 +fi + +# Check whether --enable-system-test-libs was given. +if test "${enable_system_test_libs+set}" = set; then : + enableval=$enable_system_test_libs; case "${enableval}" in + yes) + system_test_libs=true + ;; + no) + system_test_libs=false + ;; + *) + as_fn_error $? "bad value ${enableval} for --enable-system-test-libs" "$LINENO" 5 + ;; + esac +else + system_test_libs=false +fi + + if test x$system_test_libs = xtrue; then + SYSTEM_TEST_LIBS_TRUE= + SYSTEM_TEST_LIBS_FALSE='#' +else + SYSTEM_TEST_LIBS_TRUE='#' + SYSTEM_TEST_LIBS_FALSE= +fi + + + + + + +if test x$system_test_libs = xtrue; then + : "${GMOCK_CFLAGS:=-pthread}" + : "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}" + : "${GTEST_CFLAGS:=-pthread}" + : "${GTEST_LIBS:=-lgtest -pthread -lpthread}" +fi + +# Check whether --enable-selftest was given. +if test "${enable_selftest+set}" = set; then : + enableval=$enable_selftest; case "${enableval}" in + yes) + selftest=true + ;; + no) + selftest=false + ;; + *) + as_fn_error $? "bad value ${enableval} for --enable-selftest" "$LINENO" 5 + ;; + esac +else + selftest=false +fi + + if test x$selftest = xtrue; then + SELFTEST_TRUE= + SELFTEST_FALSE='#' +else + SELFTEST_TRUE='#' + SELFTEST_FALSE= +fi + + + +# Check whether --with-rust-demangle was given. +if test "${with_rust_demangle+set}" = set; then : + withval=$with_rust_demangle; case "${withval}" in + yes) + as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5 + ;; + no) + rust_demangle=false + ;; + *) + if ! test -f "${withval}/Cargo.toml"; then + as_fn_error $? "You must pass the path to the rust-demangle-capi crate for --with-rust-demangle" "$LINENO" 5 + fi + RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include" + RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl" + ;; + esac +else + rust_demangle=false +fi + + + + + +# Check whether --with-tests-as-root was given. +if test "${with_tests_as_root+set}" = set; then : + withval=$with_tests_as_root; case "${withval}" in + yes) + tests_as_root=true + ;; + no) + tests_as_root=false + ;; + *) + as_fn_error $? "--with-tests-as-root can only be \"yes\" or \"no\"" "$LINENO" 5 + ;; + esac +else + tests_as_root=false +fi + + if test x$tests_as_root = xtrue; then + TESTS_AS_ROOT_TRUE= + TESTS_AS_ROOT_FALSE='#' +else + TESTS_AS_ROOT_TRUE='#' + TESTS_AS_ROOT_FALSE= +fi + + +ac_config_files="$ac_config_files breakpad.pc breakpad-client.pc Makefile" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_GETCONTEXT_TRUE}" && test -z "${HAVE_GETCONTEXT_FALSE}"; then + as_fn_error $? "conditional \"HAVE_GETCONTEXT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LINUX_HOST_TRUE}" && test -z "${LINUX_HOST_FALSE}"; then + as_fn_error $? "conditional \"LINUX_HOST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ANDROID_HOST_TRUE}" && test -z "${ANDROID_HOST_FALSE}"; then + as_fn_error $? "conditional \"ANDROID_HOST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${X86_HOST_TRUE}" && test -z "${X86_HOST_FALSE}"; then + as_fn_error $? "conditional \"X86_HOST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DISABLE_PROCESSOR_TRUE}" && test -z "${DISABLE_PROCESSOR_FALSE}"; then + as_fn_error $? "conditional \"DISABLE_PROCESSOR\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DISABLE_TOOLS_TRUE}" && test -z "${DISABLE_TOOLS_FALSE}"; then + as_fn_error $? "conditional \"DISABLE_TOOLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SYSTEM_TEST_LIBS_TRUE}" && test -z "${SYSTEM_TEST_LIBS_FALSE}"; then + as_fn_error $? "conditional \"SYSTEM_TEST_LIBS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${SELFTEST_TRUE}" && test -z "${SELFTEST_FALSE}"; then + as_fn_error $? "conditional \"SELFTEST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TESTS_AS_ROOT_TRUE}" && test -z "${TESTS_AS_ROOT_FALSE}"; then + as_fn_error $? "conditional \"TESTS_AS_ROOT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by breakpad $as_me 0.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +breakpad config.status 0.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "breakpad.pc") CONFIG_FILES="$CONFIG_FILES breakpad.pc" ;; + "breakpad-client.pc") CONFIG_FILES="$CONFIG_FILES breakpad-client.pc" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/toolkit/crashreporter/google-breakpad/configure.ac b/toolkit/crashreporter/google-breakpad/configure.ac new file mode 100644 index 0000000000..08513687f3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/configure.ac @@ -0,0 +1,271 @@ +# 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. + + +AC_PREREQ(2.64) + +AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com) +dnl Sanity check: the argument is just a file that should exist. +AC_CONFIG_SRCDIR(README.md) +AC_CONFIG_AUX_DIR(autotools) +AC_CONFIG_MACRO_DIR([m4]) +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1) +AM_CONFIG_HEADER(src/config.h) +AM_MAINTAINER_MODE + +AM_PROG_AR +AM_PROG_AS +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CPP +AC_PROG_CXX +AC_PROG_RANLIB + +dnl This must come before all the feature tests below. +AC_ARG_ENABLE(m32, + AS_HELP_STRING([--enable-m32], + [Compile/build with -m32] + [(default is no)]), + [case "${enableval}" in + yes) + CFLAGS="${CFLAGS} -m32" + CXXFLAGS="${CXXFLAGS} -m32" + usem32=true + ;; + no) + usem32=false + ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --enable-m32) + ;; + esac], + [usem32=false]) + +AC_HEADER_STDC +AC_SYS_LARGEFILE +AX_PTHREAD +AC_CHECK_HEADERS([a.out.h sys/random.h]) +AC_CHECK_FUNCS([arc4random getcontext getrandom]) +AM_CONDITIONAL([HAVE_GETCONTEXT], [test "x$ac_cv_func_getcontext" = xyes]) + +AX_CXX_COMPILE_STDCXX(11, noext, mandatory) + +dnl Test supported warning flags. +WARN_CXXFLAGS= +dnl This warning flag is used by clang. Its default behavior is to warn when +dnl given an unknown flag rather than error out. +AC_LANG_PUSH([C++]) +AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[ + ax_compiler_flags_test="-Werror=unknown-warning-option" +],[ + ax_compiler_flags_test="" +]) +AX_APPEND_COMPILE_FLAGS(m4_flatten([ + -Wmissing-braces + -Wnon-virtual-dtor + -Woverloaded-virtual + -Wreorder + -Wsign-compare + -Wunused-local-typedefs + -Wunused-variable + -Wvla +]), [WARN_CXXFLAGS], [${ax_compiler_flags_test}]) +AS_VAR_APPEND([WARN_CXXFLAGS], " -Werror") +AC_LANG_POP([C++]) +AC_SUBST([WARN_CXXFLAGS]) + +dnl Test support for O_CLOEXEC +AX_CHECK_DEFINE([fcntl.h], [O_CLOEXEC], [], + [AC_DEFINE([O_CLOEXEC], [0], [Fallback definition for old systems])]) + +# Only build Linux client libs when compiling for Linux +case $host in + *-*-linux* | *-android* ) + LINUX_HOST=true + ;; +esac +AM_CONDITIONAL(LINUX_HOST, test x$LINUX_HOST = xtrue) + +# Only use Android support headers when compiling for Android +case $host in + *-android*) + ANDROID_HOST=true + ;; +esac +AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue) + +# Some tools (like mac ones) only support x86 currently. +case $host_cpu in + i?86|x86_64) + X86_HOST=true + ;; +esac +AM_CONDITIONAL(X86_HOST, test x$X86_HOST = xtrue) + +AC_ARG_ENABLE(processor, + AS_HELP_STRING([--disable-processor], + [Don't build processor library] + [(default is no)]), + [case "${enableval}" in + yes) + disable_processor=false + ;; + no) + disable_processor=true + ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --disable-processor) + ;; + esac], + [disable_processor=false]) +AM_CONDITIONAL(DISABLE_PROCESSOR, test x$disable_processor = xtrue) + +AC_ARG_ENABLE(tools, + AS_HELP_STRING([--disable-tools], + [Don't build tool binaries] + [(default is no)]), + [case "${enableval}" in + yes) + disable_tools=false + ;; + no) + disable_tools=true + ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --disable-tools) + ;; + esac], + [disable_tools=false]) +AM_CONDITIONAL(DISABLE_TOOLS, test x$disable_tools = xtrue) + +if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then + AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!]) +fi + +AC_ARG_ENABLE(system-test-libs, + AS_HELP_STRING([--enable-system-test-libs], + [Use gtest/gmock/etc... from the system instead ] + [of the local copies (default is local)]), + [case "${enableval}" in + yes) + system_test_libs=true + ;; + no) + system_test_libs=false + ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --enable-system-test-libs) + ;; + esac], + [system_test_libs=false]) +AM_CONDITIONAL(SYSTEM_TEST_LIBS, test x$system_test_libs = xtrue) + +AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock]) +AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock]) +AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest]) +AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest]) +if test x$system_test_libs = xtrue; then + : "${GMOCK_CFLAGS:=-pthread}" + : "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}" + : "${GTEST_CFLAGS:=-pthread}" + : "${GTEST_LIBS:=-lgtest -pthread -lpthread}" +fi + +AC_ARG_ENABLE(selftest, + AS_HELP_STRING([--enable-selftest], + [Run extra tests with "make check" ] + [(may conflict with optimizations) ] + [(default is no)]), + [case "${enableval}" in + yes) + selftest=true + ;; + no) + selftest=false + ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --enable-selftest) + ;; + esac], + [selftest=false]) +AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue) + +AC_ARG_WITH(rust-demangle, + AS_HELP_STRING([--with-rust-demangle=/path/to/rust-demangle-capi], + [Link against the rust-demangle library] + [to demangle Rust language symbols during] + [symbol dumping (default is no)] + [Pass the path to the crate root.]), + [case "${withval}" in + yes) + AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle) + ;; + no) + rust_demangle=false + ;; + *) + if ! test -f "${withval}/Cargo.toml"; then + AC_MSG_ERROR(You must pass the path to the rust-demangle-capi crate for --with-rust-demangle) + fi + RUST_DEMANGLE_CFLAGS="-DHAVE_RUST_DEMANGLE -I${withval}/target/include" + RUST_DEMANGLE_LIBS="-L${withval}/target/release -lrust_demangle -lpthread -ldl" + ;; + esac], + [rust_demangle=false]) +AC_ARG_VAR([RUST_DEMANGLE_CFLAGS], [Compiler flags for rust-demangle]) +AC_ARG_VAR([RUST_DEMANGLE_LIBS], [Linker flags for rust-demangle]) + +AC_ARG_WITH(tests-as-root, + AS_HELP_STRING([--with-tests-as-root], + [Run the tests as root. Use this on platforms] + [like travis-ci.org that require root privileges] + [to use ptrace (default is no)]), + [case "${withval}" in + yes) + tests_as_root=true + ;; + no) + tests_as_root=false + ;; + *) + AC_MSG_ERROR(--with-tests-as-root can only be "yes" or "no") + ;; + esac], + [tests_as_root=false]) +AM_CONDITIONAL(TESTS_AS_ROOT, test x$tests_as_root = xtrue) + +AC_CONFIG_FILES(m4_flatten([ + breakpad.pc + breakpad-client.pc + Makefile +])) + +AC_OUTPUT diff --git a/toolkit/crashreporter/google-breakpad/default.xml b/toolkit/crashreporter/google-breakpad/default.xml new file mode 100644 index 0000000000..195bbb592e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/default.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/crashreporter/google-breakpad/src/breakpad_googletest_includes.h b/toolkit/crashreporter/google-breakpad/src/breakpad_googletest_includes.h new file mode 100644 index 0000000000..19a3e98077 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/breakpad_googletest_includes.h @@ -0,0 +1,57 @@ +// Copyright (c) 2009, 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 BREAKPAD_GOOGLETEST_INCLUDES_H__ +#define BREAKPAD_GOOGLETEST_INCLUDES_H__ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL +// (illegal instruction) instead of SIGSEGV (segmentation fault). Also, +// the number of memory regions differs, so there is no point in running +// this test if AddressSanitizer is used. +// +// Ideally we'd use this attribute to disable ASAN on a per-func basis, +// but this doesn't seem to actually work, and it's changed names over +// time. So just stick with disabling the actual tests. +// http://crbug.com/304575 +//#define NO_ASAN __attribute__((no_sanitize_address)) +#if defined(__clang__) && defined(__has_feature) +// Have to keep this check sep from above as newer gcc will barf on it. +# if __has_feature(address_sanitizer) +# define ADDRESS_SANITIZER +# endif +#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__) +# define ADDRESS_SANITIZER +#else +# undef ADDRESS_SANITIZER +#endif + +#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/build/all.gyp b/toolkit/crashreporter/google-breakpad/src/build/all.gyp new file mode 100644 index 0000000000..4b59d917bb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/build/all.gyp @@ -0,0 +1,41 @@ +# Copyright 2014 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. + +{ + 'targets': [ + { + 'target_name': 'All', + 'type': 'none', + 'dependencies': [ + '../common/common.gyp:*', + '../processor/processor.gyp:*', + '../tools/tools.gyp:*', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/build/common.gypi b/toolkit/crashreporter/google-breakpad/src/build/common.gypi new file mode 100644 index 0000000000..29990c6591 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/build/common.gypi @@ -0,0 +1,1045 @@ +# Copyright 2010 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. + +# IMPORTANT: +# Please don't directly include this file if you are building via gyp_chromium, +# since gyp_chromium is automatically forcing its inclusion. +{ + 'variables': { + # Variables expected to be overriden on the GYP command line (-D) or by + # ~/.gyp/include.gypi. + + # Putting a variables dict inside another variables dict looks kind of + # weird. This is necessary to get these variables defined for the conditions + # within this variables dict that operate on these variables. + 'variables': { + 'variables': { + # Compute the architecture that we're building on. + 'conditions': [ + [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + # This handles the Linux platforms we generally deal with. Anything + # else gets passed through, which probably won't work very well; such + # hosts should pass an explicit target_arch to gyp. + 'host_arch%': + '. + # Additional documentation on these macros is available at + # http://developer.apple.com/mac/library/technotes/tn2002/tn2064.html#SECTION3 + # Chrome normally builds with the Mac OS X 10.5 SDK and sets the + # deployment target to 10.5. Other projects, such as O3D, may override + # these defaults. + 'mac_sdk%': '10.5', + 'mac_deployment_target%': '10.5', + + # Set to 1 to enable code coverage. In addition to build changes + # (e.g. extra CFLAGS), also creates a new target in the src/chrome + # project file called "coverage". + # Currently ignored on Windows. + 'coverage%': 0, + + # Although base/allocator lets you select a heap library via an + # environment variable, the libcmt shim it uses sometimes gets in + # the way. To disable it entirely, and switch to normal msvcrt, do e.g. + # 'win_use_allocator_shim': 0, + # 'win_release_RuntimeLibrary': 2 + # to ~/.gyp/include.gypi, gclient runhooks --force, and do a release build. + 'win_use_allocator_shim%': 1, # 0 = shim allocator via libcmt; 1 = msvcrt + + # Whether usage of OpenMAX is enabled. + 'enable_openmax%': 0, + + # TODO(bradnelson): eliminate this when possible. + # To allow local gyp files to prevent release.vsprops from being included. + # Yes(1) means include release.vsprops. + # Once all vsprops settings are migrated into gyp, this can go away. + 'msvs_use_common_release%': 1, + + # TODO(bradnelson): eliminate this when possible. + # To allow local gyp files to override additional linker options for msvs. + # Yes(1) means set use the common linker options. + 'msvs_use_common_linker_extras%': 1, + + # TODO(sgk): eliminate this if possible. + # It would be nicer to support this via a setting in 'target_defaults' + # in chrome/app/locales/locales.gypi overriding the setting in the + # 'Debug' configuration in the 'target_defaults' dict below, + # but that doesn't work as we'd like. + 'msvs_debug_link_incremental%': '2', + + # This is the location of the sandbox binary. Chrome looks for this before + # running the zygote process. If found, and SUID, it will be used to + # sandbox the zygote process and, thus, all renderer processes. + 'linux_sandbox_path%': '', + + # Set this to true to enable SELinux support. + 'selinux%': 0, + + # Strip the binary after dumping symbols. + 'linux_strip_binary%': 0, + + # Enable TCMalloc. + 'linux_use_tcmalloc%': 1, + + # Disable TCMalloc's debugallocation. + 'linux_use_debugallocation%': 0, + + # Disable TCMalloc's heapchecker. + 'linux_use_heapchecker%': 0, + + # Set to 1 to turn on seccomp sandbox by default. + # (Note: this is ignored for official builds.) + 'linux_use_seccomp_sandbox%': 0, + + # Set to select the Title Case versions of strings in GRD files. + 'use_titlecase_in_grd%': 0, + + # Used to disable Native Client at compile time, for platforms where it + # isn't supported + 'disable_nacl%': 0, + + # Set Thumb compilation flags. + 'arm_thumb%': 0, + + # Set ARM fpu compilation flags (only meaningful if arm_version==7 and + # arm_neon==0). + 'arm_fpu%': 'vfpv3', + + # Enable new NPDevice API. + 'enable_new_npdevice_api%': 0, + + 'conditions': [ + # Whether to use multiple cores to compile with visual studio. This is + # optional because it sometimes causes corruption on VS 2005. + # It is on by default on VS 2008 and off on VS 2005. + ['OS=="win"', { + 'conditions': [ + ['MSVS_VERSION=="2005"', { + 'msvs_multi_core_compile%': 0, + },{ + 'msvs_multi_core_compile%': 1, + }], + # Don't do incremental linking for large modules on 32-bit. + ['MSVS_OS_BITS==32', { + 'msvs_large_module_debug_link_mode%': '1', # No + },{ + 'msvs_large_module_debug_link_mode%': '2', # Yes + }], + ], + 'nacl_win64_defines': [ + # This flag is used to minimize dependencies when building + # Native Client loader for 64-bit Windows. + 'NACL_WIN64', + ], + }], + ], + + # NOTE: When these end up in the Mac bundle, we need to replace '-' for '_' + # so Cocoa is happy (http://crbug.com/20441). + 'locales': [ + 'am', 'ar', 'bg', 'bn', 'ca', 'cs', 'da', 'de', 'el', 'en-GB', + 'en-US', 'es-419', 'es', 'et', 'fi', 'fil', 'fr', 'gu', 'he', + 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'kn', 'ko', 'lt', 'lv', + 'ml', 'mr', 'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', + 'sk', 'sl', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tr', 'uk', + 'vi', 'zh-CN', 'zh-TW', + ], + }, + 'target_defaults': { + 'includes': [ + 'filename_rules.gypi', + ], + 'variables': { + # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html + 'mac_release_optimization%': '3', # Use -O3 unless overridden + 'mac_debug_optimization%': '0', # Use -O0 unless overridden + # See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx + 'win_release_Optimization%': '2', # 2 = /Os + 'win_debug_Optimization%': '0', # 0 = /Od + # See http://msdn.microsoft.com/en-us/library/aa652367(VS.71).aspx + 'win_release_RuntimeLibrary%': '0', # 0 = /MT (nondebug static) + 'win_debug_RuntimeLibrary%': '1', # 1 = /MTd (debug static) + + 'release_extra_cflags%': '', + 'debug_extra_cflags%': '', + 'release_valgrind_build%': 0, + }, + 'conditions': [ + ['selinux==1', { + 'defines': ['CHROMIUM_SELINUX=1'], + }], + ['win_use_allocator_shim==0', { + 'conditions': [ + ['OS=="win"', { + 'defines': ['NO_TCMALLOC'], + }], + ], + }], + ['coverage!=0', { + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': 'YES', # -fprofile-arcs + 'GCC_GENERATE_TEST_COVERAGE_FILES': 'YES', # -ftest-coverage + }, + # Add -lgcov for types executable, shared_library, and + # loadable_module; not for static_library. + # This is a delayed conditional. + 'target_conditions': [ + ['_type!="static_library"', { + 'xcode_settings': { 'OTHER_LDFLAGS': [ '-lgcov' ] }, + }], + ], + }], + # Linux gyp (into scons) doesn't like target_conditions? + # TODO(???): track down why 'target_conditions' doesn't work + # on Linux gyp into scons like it does on Mac gyp into xcodeproj. + ['OS=="linux"', { + 'cflags': [ '-ftest-coverage', + '-fprofile-arcs' ], + 'link_settings': { 'libraries': [ '-lgcov' ] }, + }], + # Finally, for Windows, we simply turn on profiling. + ['OS=="win"', { + 'msvs_settings': { + 'VCLinkerTool': { + 'Profile': 'true', + }, + 'VCCLCompilerTool': { + # /Z7, not /Zi, so coverage is happyb + 'DebugInformationFormat': '1', + 'AdditionalOptions': ['/Yd'], + } + } + }], # OS==win + ], # conditions for coverage + }], # coverage!=0 + ], # conditions for 'target_defaults' + 'target_conditions': [ + [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', { + 'cflags!': [ + '-Wall', + '-Wextra', + '-Werror', + ], + }], + [ 'OS=="win"', { + 'defines': [ + '_CRT_SECURE_NO_DEPRECATE', + '_CRT_NONSTDC_NO_WARNINGS', + '_CRT_NONSTDC_NO_DEPRECATE', + # This is required for ATL to use XP-safe versions of its functions. + '_USING_V110_SDK71_', + ], + 'msvs_disabled_warnings': [4800], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'WarnAsError': 'true', + 'Detect64BitPortabilityProblems': 'false', + }, + }, + }], + [ 'OS=="mac"', { + 'xcode_settings': { + 'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO', + 'WARNING_CFLAGS!': ['-Wall'], + }, + }], + ], # target_conditions for 'target_defaults' + 'default_configuration': 'Debug', + 'configurations': { + # VCLinkerTool LinkIncremental values below: + # 0 == default + # 1 == /INCREMENTAL:NO + # 2 == /INCREMENTAL + # Debug links incremental, Release does not. + # + # Abstract base configurations to cover common + # attributes. + # + 'Common_Base': { + 'abstract': 1, + 'msvs_configuration_attributes': { + 'OutputDirectory': '$(SolutionDir)$(ConfigurationName)', + 'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)', + 'CharacterSet': '1', + }, + }, + 'x86_Base': { + 'abstract': 1, + 'msvs_settings': { + 'VCLinkerTool': { + 'MinimumRequiredVersion': '5.01', # XP. + 'TargetMachine': '1', + }, + }, + 'msvs_configuration_platform': 'Win32', + }, + 'x64_Base': { + 'abstract': 1, + 'msvs_configuration_platform': 'x64', + 'msvs_settings': { + 'VCLinkerTool': { + 'TargetMachine': '17', # x86 - 64 + 'AdditionalLibraryDirectories!': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], + 'AdditionalLibraryDirectories': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'], + }, + 'VCLibrarianTool': { + 'AdditionalLibraryDirectories!': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], + 'AdditionalLibraryDirectories': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib/x64'], + }, + }, + 'defines': [ + # Not sure if tcmalloc works on 64-bit Windows. + 'NO_TCMALLOC', + ], + }, + 'Debug_Base': { + 'abstract': 1, + 'xcode_settings': { + 'COPY_PHASE_STRIP': 'NO', + 'GCC_OPTIMIZATION_LEVEL': '<(mac_debug_optimization)', + 'OTHER_CFLAGS': [ '<@(debug_extra_cflags)', ], + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '<(win_debug_Optimization)', + 'PreprocessorDefinitions': ['_DEBUG'], + 'BasicRuntimeChecks': '3', + 'RuntimeLibrary': '<(win_debug_RuntimeLibrary)', + }, + 'VCLinkerTool': { + 'LinkIncremental': '<(msvs_debug_link_incremental)', + }, + 'VCResourceCompilerTool': { + 'PreprocessorDefinitions': ['_DEBUG'], + }, + }, + 'conditions': [ + ['OS=="linux"', { + 'cflags': [ + '<@(debug_extra_cflags)', + ], + }], + ], + }, + 'Release_Base': { + 'abstract': 1, + 'defines': [ + 'NDEBUG', + ], + 'xcode_settings': { + 'DEAD_CODE_STRIPPING': 'YES', # -Wl,-dead_strip + 'GCC_OPTIMIZATION_LEVEL': '<(mac_release_optimization)', + 'OTHER_CFLAGS': [ '<@(release_extra_cflags)', ], + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '<(win_release_Optimization)', + 'RuntimeLibrary': '<(win_release_RuntimeLibrary)', + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + }, + }, + 'conditions': [ + ['release_valgrind_build==0', { + 'defines': ['NVALGRIND'], + }], + ['win_use_allocator_shim==0', { + 'defines': ['NO_TCMALLOC'], + }], + ['win_release_RuntimeLibrary==2', { + # Visual C++ 2008 barfs when building anything with /MD (msvcrt): + # VC\include\typeinfo(139) : warning C4275: non dll-interface + # class 'stdext::exception' used as base for dll-interface + # class 'std::bad_cast' + 'msvs_disabled_warnings': [4275], + }], + ['OS=="linux"', { + 'cflags': [ + '<@(release_extra_cflags)', + ], + }], + ], + }, + 'Purify_Base': { + 'abstract': 1, + 'defines': [ + 'PURIFY', + 'NO_TCMALLOC', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '0', + 'RuntimeLibrary': '0', + 'BufferSecurityCheck': 'false', + }, + 'VCLinkerTool': { + 'EnableCOMDATFolding': '1', + 'LinkIncremental': '1', + }, + }, + }, + # + # Concrete configurations + # + 'Debug': { + 'inherit_from': ['Common_Base', 'x86_Base', 'Debug_Base'], + }, + 'Release': { + 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'], + 'conditions': [ + ['msvs_use_common_release', { + 'defines': ['OFFICIAL_BUILD'], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '3', + 'StringPooling': 'true', + 'OmitFramePointers': 'true', + 'InlineFunctionExpansion': '2', + 'EnableIntrinsicFunctions': 'true', + 'FavorSizeOrSpeed': '2', + 'OmitFramePointers': 'true', + 'EnableFiberSafeOptimizations': 'true', + 'WholeProgramOptimization': 'true', + }, + 'VCLibrarianTool': { + 'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'], + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + 'OptimizeReferences': '2', + 'EnableCOMDATFolding': '2', + 'OptimizeForWindows98': '1', + 'LinkTimeCodeGeneration': '1', + }, + }, + }], + ] + }, + 'conditions': [ + [ 'OS=="win"', { + # TODO(bradnelson): add a gyp mechanism to make this more graceful. + 'Purify': { + 'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base', 'Purify'], + }, + 'Debug_x64': { + 'inherit_from': ['Common_Base', 'x64_Base', 'Debug_Base'], + }, + 'Release_x64': { + 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base'], + }, + 'Purify_x64': { + 'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base', 'Purify_Base'], + }, + }], + ], + }, + }, + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { + 'target_defaults': { + # Enable -Werror by default, but put it in a variable so it can + # be disabled in ~/.gyp/include.gypi on the valgrind builders. + 'variables': { + # Use -fno-strict-aliasing by default since gcc 4.4 has periodic + # issues that slip through the cracks. We could do this just for + # gcc 4.4 but it makes more sense to be consistent on all + # compilers in use. TODO(Craig): turn this off again when + # there is some 4.4 test infrastructure in place and existing + # aliasing issues have been fixed. + 'no_strict_aliasing%': 1, + 'conditions': [['OS=="linux"', {'werror%': '-Werror',}], + ['OS=="freebsd"', {'werror%': '',}], + ['OS=="openbsd"', {'werror%': '',}], + ], + }, + 'cflags': [ + '<(werror)', # See note above about the werror variable. + '-pthread', + '-fno-exceptions', + '-Wall', + # TODO(evan): turn this back on once all the builds work. + # '-Wextra', + # Don't warn about unused function params. We use those everywhere. + '-Wno-unused-parameter', + # Don't warn about the "struct foo f = {0};" initialization pattern. + '-Wno-missing-field-initializers', + '-D_FILE_OFFSET_BITS=64', + # Don't export any symbols (for example, to plugins we dlopen()). + # Note: this is *required* to make some plugins work. + '-fvisibility=hidden', + ], + 'cflags_cc': [ + '-frtti', + '-fno-threadsafe-statics', + # Make inline functions have hidden visiblity by default. + # Surprisingly, not covered by -fvisibility=hidden. + '-fvisibility-inlines-hidden', + ], + 'ldflags': [ + '-pthread', '-Wl,-z,noexecstack', + ], + 'scons_variable_settings': { + 'LIBPATH': ['$LIB_DIR'], + # Linking of large files uses lots of RAM, so serialize links + # using the handy flock command from util-linux. + 'FLOCK_LINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$LINK'], + 'FLOCK_SHLINK': ['flock', '$TOP_BUILDDIR/linker.lock', '$SHLINK'], + 'FLOCK_LDMODULE': ['flock', '$TOP_BUILDDIR/linker.lock', '$LDMODULE'], + + # We have several cases where archives depend on each other in + # a cyclic fashion. Since the GNU linker does only a single + # pass over the archives we surround the libraries with + # --start-group and --end-group (aka -( and -) ). That causes + # ld to loop over the group until no more undefined symbols + # are found. In an ideal world we would only make groups from + # those libraries which we knew to be in cycles. However, + # that's tough with SCons, so we bodge it by making all the + # archives a group by redefining the linking command here. + # + # TODO: investigate whether we still have cycles that + # require --{start,end}-group. There has been a lot of + # refactoring since this was first coded, which might have + # eliminated the circular dependencies. + # + # Note: $_LIBDIRFLAGS comes before ${LINK,SHLINK,LDMODULE}FLAGS + # so that we prefer our own built libraries (e.g. -lpng) to + # system versions of libraries that pkg-config might turn up. + # TODO(sgk): investigate handling this not by re-ordering the + # flags this way, but by adding a hook to use the SCons + # ParseFlags() option on the output from pkg-config. + 'LINKCOM': [['$FLOCK_LINK', '-o', '$TARGET', + '$_LIBDIRFLAGS', '$LINKFLAGS', '$SOURCES', + '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], + 'SHLINKCOM': [['$FLOCK_SHLINK', '-o', '$TARGET', + '$_LIBDIRFLAGS', '$SHLINKFLAGS', '$SOURCES', + '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], + 'LDMODULECOM': [['$FLOCK_LDMODULE', '-o', '$TARGET', + '$_LIBDIRFLAGS', '$LDMODULEFLAGS', '$SOURCES', + '-Wl,--start-group', '$_LIBFLAGS', '-Wl,--end-group']], + 'IMPLICIT_COMMAND_DEPENDENCIES': 0, + }, + 'scons_import_variables': [ + 'AS', + 'CC', + 'CXX', + 'LINK', + ], + 'scons_propagate_variables': [ + 'AS', + 'CC', + 'CCACHE_DIR', + 'CXX', + 'DISTCC_DIR', + 'DISTCC_HOSTS', + 'HOME', + 'INCLUDE_SERVER_ARGS', + 'INCLUDE_SERVER_PORT', + 'LINK', + 'CHROME_BUILD_TYPE', + 'CHROMIUM_BUILD', + 'OFFICIAL_BUILD', + ], + 'configurations': { + 'Debug_Base': { + 'variables': { + 'debug_optimize%': '0', + }, + 'defines': [ + '_DEBUG', + ], + 'cflags': [ + '-O>(debug_optimize)', + '-g', + # One can use '-gstabs' to enable building the debugging + # information in STABS format for breakpad's dumpsyms. + ], + 'ldflags': [ + '-rdynamic', # Allows backtrace to resolve symbols. + ], + }, + 'Release_Base': { + 'variables': { + 'release_optimize%': '2', + }, + 'cflags': [ + '-O>(release_optimize)', + # Don't emit the GCC version ident directives, they just end up + # in the .comment section taking up binary size. + '-fno-ident', + # Put data and code in their own sections, so that unused symbols + # can be removed at link time with --gc-sections. + '-fdata-sections', + '-ffunction-sections', + ], + 'ldflags': [ + '-Wl,--gc-sections', + ], + }, + }, + 'variants': { + 'coverage': { + 'cflags': ['-fprofile-arcs', '-ftest-coverage'], + 'ldflags': ['-fprofile-arcs'], + }, + 'profile': { + 'cflags': ['-pg', '-g'], + 'ldflags': ['-pg'], + }, + 'symbols': { + 'cflags': ['-g'], + }, + }, + 'conditions': [ + [ 'target_arch=="ia32"', { + 'asflags': [ + # Needed so that libs with .s files (e.g. libicudata.a) + # are compatible with the general 32-bit-ness. + '-32', + ], + # All floating-point computations on x87 happens in 80-bit + # precision. Because the C and C++ language standards allow + # the compiler to keep the floating-point values in higher + # precision than what's specified in the source and doing so + # is more efficient than constantly rounding up to 64-bit or + # 32-bit precision as specified in the source, the compiler, + # especially in the optimized mode, tries very hard to keep + # values in x87 floating-point stack (in 80-bit precision) + # as long as possible. This has important side effects, that + # the real value used in computation may change depending on + # how the compiler did the optimization - that is, the value + # kept in 80-bit is different than the value rounded down to + # 64-bit or 32-bit. There are possible compiler options to make + # this behavior consistent (e.g. -ffloat-store would keep all + # floating-values in the memory, thus force them to be rounded + # to its original precision) but they have significant runtime + # performance penalty. + # + # -mfpmath=sse -msse2 makes the compiler use SSE instructions + # which keep floating-point values in SSE registers in its + # native precision (32-bit for single precision, and 64-bit for + # double precision values). This means the floating-point value + # used during computation does not change depending on how the + # compiler optimized the code, since the value is always kept + # in its specified precision. + 'conditions': [ + ['disable_sse2==0', { + 'cflags': [ + '-march=pentium4', + '-msse2', + '-mfpmath=sse', + ], + }], + ], + # -mmmx allows mmintrin.h to be used for mmx intrinsics. + # video playback is mmx and sse2 optimized. + 'cflags': [ + '-m32', + '-mmmx', + ], + 'ldflags': [ + '-m32', + ], + }], + ['target_arch=="arm"', { + 'target_conditions': [ + ['_toolset=="target"', { + 'cflags_cc': [ + # The codesourcery arm-2009q3 toolchain warns at that the ABI + # has changed whenever it encounters a varargs function. This + # silences those warnings, as they are not helpful and + # clutter legitimate warnings. + '-Wno-abi', + ], + 'conditions': [ + ['arm_thumb == 1', { + 'cflags': [ + '-mthumb', + # TODO(piman): -Wa,-mimplicit-it=thumb is needed for + # inline assembly that uses condition codes but it's + # suboptimal. Better would be to #ifdef __thumb__ at the + # right place and have a separate thumb path. + '-Wa,-mimplicit-it=thumb', + ] + }], + ['arm_version==7', { + 'cflags': [ + '-march=armv7-a', + '-mtune=cortex-a8', + '-mfloat-abi=softfp', + ], + 'conditions': [ + ['arm_neon==1', { + 'cflags': [ '-mfpu=neon', ], + }, { + 'cflags': [ '-mfpu=<(arm_fpu)', ], + }] + ], + }], + ], + }], + ], + }], + ['linux_fpic==1', { + 'cflags': [ + '-fPIC', + ], + }], + ['sysroot!=""', { + 'target_conditions': [ + ['_toolset=="target"', { + 'cflags': [ + '--sysroot=<(sysroot)', + ], + 'ldflags': [ + '--sysroot=<(sysroot)', + ], + }]] + }], + ['no_strict_aliasing==1', { + 'cflags': [ + '-fno-strict-aliasing', + ], + }], + ['linux_use_heapchecker==1', { + 'variables': {'linux_use_tcmalloc%': 1}, + }], + ['linux_use_tcmalloc==0', { + 'defines': ['NO_TCMALLOC'], + }], + ['linux_use_heapchecker==0', { + 'defines': ['NO_HEAPCHECKER'], + }], + ], + }, + }], + # FreeBSD-specific options; note that most FreeBSD options are set above, + # with Linux. + ['OS=="freebsd"', { + 'target_defaults': { + 'ldflags': [ + '-Wl,--no-keep-memory', + ], + }, + }], + ['OS=="solaris"', { + 'cflags!': ['-fvisibility=hidden'], + 'cflags_cc!': ['-fvisibility-inlines-hidden'], + }], + ['OS=="mac"', { + 'target_defaults': { + 'variables': { + # This should be 'mac_real_dsym%', but there seems to be a bug + # with % in variables that are intended to be set to different + # values in different targets, like this one. + 'mac_real_dsym': 0, # Fake .dSYMs are fine in most cases. + }, + 'mac_bundle': 0, + 'xcode_settings': { + 'ALWAYS_SEARCH_USER_PATHS': 'NO', + 'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99 + 'GCC_CW_ASM_SYNTAX': 'NO', # No -fasm-blocks + 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic + # (Equivalent to -fPIC) + 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions + 'GCC_ENABLE_CPP_RTTI': 'YES', # -frtti + 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings + # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden + 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', + 'GCC_OBJC_CALL_CXX_CDTORS': 'YES', # -fobjc-call-cxx-cdtors + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics + 'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES', # -Werror + 'GCC_VERSION': '4.2', + 'GCC_WARN_ABOUT_MISSING_NEWLINE': 'YES', # -Wnewline-eof + # MACOSX_DEPLOYMENT_TARGET maps to -mmacosx-version-min + 'MACOSX_DEPLOYMENT_TARGET': '<(mac_deployment_target)', + 'PREBINDING': 'NO', # No -Wl,-prebind + 'USE_HEADERMAP': 'NO', + 'WARNING_CFLAGS': ['-Wall', '-Wendif-labels'], + 'conditions': [ + ['chromium_mac_pch', {'GCC_PRECOMPILE_PREFIX_HEADER': 'YES'}, + {'GCC_PRECOMPILE_PREFIX_HEADER': 'NO'} + ], + ], + }, + 'target_conditions': [ + ['_type!="static_library"', { + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-search_paths_first']}, + }], + ['_mac_bundle', { + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, + }], + ], # target_conditions + }, # target_defaults + }], # OS=="mac" + ['OS=="win"', { + 'target_defaults': { + 'defines': [ + '_WIN32_WINNT=0x0600', + 'WINVER=0x0600', + 'WIN32', + '_WINDOWS', + '_HAS_EXCEPTIONS=0', + 'NOMINMAX', + '_CRT_RAND_S', + 'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS', + 'WIN32_LEAN_AND_MEAN', + '_SECURE_ATL', + '_HAS_TR1=0', + ], + 'msvs_system_include_dirs': [ + '<(DEPTH)/third_party/platformsdk_win7/files/Include', + '$(VSInstallDir)/VC/atlmfc/include', + ], + 'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'], + 'msvs_disabled_warnings': [ + 4091, 4100, 4127, 4366, 4396, 4503, 4512, 4819, 4995, 4702 + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'MinimalRebuild': 'false', + 'ExceptionHandling': '0', + 'BufferSecurityCheck': 'true', + 'EnableFunctionLevelLinking': 'true', + 'RuntimeTypeInfo': 'false', + 'WarningLevel': '4', + 'WarnAsError': 'true', + 'DebugInformationFormat': '3', + 'conditions': [ + [ 'msvs_multi_core_compile', { + 'AdditionalOptions': ['/MP'], + }], + ], + }, + 'VCLibrarianTool': { + 'AdditionalOptions': ['/ignore:4221'], + 'AdditionalLibraryDirectories': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], + }, + 'VCLinkerTool': { + 'AdditionalDependencies': [ + 'wininet.lib', + 'version.lib', + 'msimg32.lib', + 'ws2_32.lib', + 'usp10.lib', + 'psapi.lib', + 'dbghelp.lib', + ], + 'AdditionalLibraryDirectories': + ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'], + 'GenerateDebugInformation': 'true', + 'MapFileName': '$(OutDir)\\$(TargetName).map', + 'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib', + 'FixedBaseAddress': '1', + # SubSystem values: + # 0 == not set + # 1 == /SUBSYSTEM:CONSOLE + # 2 == /SUBSYSTEM:WINDOWS + # Most of the executables we'll ever create are tests + # and utilities with console output. + 'SubSystem': '1', + }, + 'VCMIDLTool': { + 'GenerateStublessProxies': 'true', + 'TypeLibraryName': '$(InputName).tlb', + 'OutputDirectory': '$(IntDir)', + 'HeaderFileName': '$(InputName).h', + 'DLLDataFileName': 'dlldata.c', + 'InterfaceIdentifierFileName': '$(InputName)_i.c', + 'ProxyFileName': '$(InputName)_p.c', + }, + 'VCResourceCompilerTool': { + 'Culture' : '1033', + 'AdditionalIncludeDirectories': ['<(DEPTH)'], + }, + }, + }, + }], + ['disable_nacl==1 or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { + 'target_defaults': { + 'defines': [ + 'DISABLE_NACL', + ], + }, + }], + ['OS=="win" and msvs_use_common_linker_extras', { + 'target_defaults': { + 'msvs_settings': { + 'VCLinkerTool': { + 'DelayLoadDLLs': [ + 'dbghelp.dll', + 'dwmapi.dll', + 'uxtheme.dll', + ], + }, + }, + 'configurations': { + 'x86_Base': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalOptions': [ + '/safeseh', + '/dynamicbase', + '/ignore:4199', + '/ignore:4221', + '/nxcompat', + ], + }, + }, + }, + 'x64_Base': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalOptions': [ + # safeseh is not compatible with x64 + '/dynamicbase', + '/ignore:4199', + '/ignore:4221', + '/nxcompat', + ], + }, + }, + }, + }, + }, + }], + ['enable_new_npdevice_api==1', { + 'target_defaults': { + 'defines': [ + 'ENABLE_NEW_NPDEVICE_API', + ], + }, + }], + ], + 'scons_settings': { + 'sconsbuild_dir': '<(DEPTH)/sconsbuild', + 'tools': ['ar', 'as', 'gcc', 'g++', 'gnulink', 'chromium_builders'], + }, + 'xcode_settings': { + # DON'T ADD ANYTHING NEW TO THIS BLOCK UNLESS YOU REALLY REALLY NEED IT! + # This block adds *project-wide* configuration settings to each project + # file. It's almost always wrong to put things here. Specify your + # custom xcode_settings in target_defaults to add them to targets instead. + + # In an Xcode Project Info window, the "Base SDK for All Configurations" + # setting sets the SDK on a project-wide basis. In order to get the + # configured SDK to show properly in the Xcode UI, SDKROOT must be set + # here at the project level. + 'SDKROOT': 'macosx<(mac_sdk)', # -isysroot + + # The Xcode generator will look for an xcode_settings section at the root + # of each dict and use it to apply settings on a file-wide basis. Most + # settings should not be here, they should be in target-specific + # xcode_settings sections, or better yet, should use non-Xcode-specific + # settings in target dicts. SYMROOT is a special case, because many other + # Xcode variables depend on it, including variables such as + # PROJECT_DERIVED_FILE_DIR. When a source group corresponding to something + # like PROJECT_DERIVED_FILE_DIR is added to a project, in order for the + # files to appear (when present) in the UI as actual files and not red + # red "missing file" proxies, the correct path to PROJECT_DERIVED_FILE_DIR, + # and therefore SYMROOT, needs to be set at the project level. + 'SYMROOT': '<(DEPTH)/xcodebuild', + }, +} diff --git a/toolkit/crashreporter/google-breakpad/src/build/filename_rules.gypi b/toolkit/crashreporter/google-breakpad/src/build/filename_rules.gypi new file mode 100644 index 0000000000..78cd1808a9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/build/filename_rules.gypi @@ -0,0 +1,57 @@ +# Copyright 2014 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. + +{ + 'target_conditions': [ + ['OS!="win"', { + 'sources/': [ + ['exclude', '(^|/)windows/'], + ], + }], + ['OS!="linux"', { + 'sources/': [ + ['exclude', '(^|/)linux/'], + ], + }], + ['OS!="mac"', { + 'sources/': [ + ['exclude', '(^|/)mac/'], + ], + }], + ['OS!="android"', { + 'sources/': [ + ['exclude', '(^|/)android/'], + ], + }], + ['OS!="solaris"', { + 'sources/': [ + ['exclude', '(^|/)solaris/'], + ], + }], + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/build/gyp_breakpad b/toolkit/crashreporter/google-breakpad/src/build/gyp_breakpad new file mode 100755 index 0000000000..0b8077d2f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/build/gyp_breakpad @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright 2014 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. + +import os +import platform +import sys + +script_dir = os.path.dirname(os.path.realpath(__file__)) +breakpad_root = os.path.abspath(os.path.join(script_dir, os.pardir)) + +sys.path.insert(0, os.path.join(breakpad_root, 'tools', 'gyp', 'pylib')) +import gyp + +def run_gyp(args): + rc = gyp.main(args) + if rc != 0: + print 'Error running GYP' + sys.exit(rc) + + +def main(): + args = sys.argv[1:] + args.append(os.path.join(script_dir, 'all.gyp')) + + args.append('-I') + args.append(os.path.join(breakpad_root, 'build', 'common.gypi')) + + args.extend(['-D', 'gyp_output_dir=out']) + + # Set the GYP DEPTH variable to the root of the project. + args.append('--depth=' + os.path.relpath(breakpad_root)) + + print 'Updating projects from gyp files...' + sys.stdout.flush() + + run_gyp(args) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/toolkit/crashreporter/google-breakpad/src/build/testing.gyp b/toolkit/crashreporter/google-breakpad/src/build/testing.gyp new file mode 100644 index 0000000000..6a459a646f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/build/testing.gyp @@ -0,0 +1,90 @@ +# Copyright 2014 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. + +{ + 'targets': [ + { + 'target_name': 'gtest', + 'type': 'static_library', + 'sources': [ + '../testing/googletest/src/gtest-all.cc', + ], + 'include_dirs': [ + '../testing/googletest', + '../testing/googletest/include', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../testing/googletest/include', + ], + }, + }, + { + 'target_name': 'gtest_main', + 'type': 'static_library', + 'dependencies': [ + 'gtest', + ], + 'sources': [ + '../testing/googletest/src/gtest_main.cc', + ], + }, + { + 'target_name': 'gmock', + 'type': 'static_library', + 'dependencies': [ + 'gtest', + ], + 'sources': [ + '../testing/googlemock/src/gmock-all.cc', + ], + 'include_dirs': [ + '../testing/googlemock', + '../testing/googlemock/include', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../testing/googlemock/include', + ], + }, + 'export_dependent_settings': [ + 'gtest', + ], + }, + { + 'target_name': 'gmock_main', + 'type': 'static_library', + 'dependencies': [ + 'gmock', + ], + 'sources': [ + '../testing/googlemock/src/gmock_main.cc', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/README.md b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/README.md new file mode 100644 index 0000000000..b56ee60f13 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/README.md @@ -0,0 +1,9 @@ +# asm-mips + +The files in this directory are almost direct copies from Android NDK r12, with +the exception of changing the include guards to Breakpad ones. They are copied +from the MIPS asm/ directory, but are meant to be used as replacements for both +asm/ and machine/ includes since the files in each are largely duplicates. + +Some MIPS asm/ and all machine/ headers were removed in the move to unified NDK +headers, so Breakpad fails to compile on newer NDK versions without these files. \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/asm.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/asm.h new file mode 100644 index 0000000000..8f086e7566 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/asm.h @@ -0,0 +1,270 @@ +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H + +#if defined(__has_include_next) && __has_include_next() +#include_next +#else + +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ + +#include +#ifndef CAT +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#ifdef __STDC__ +#define __CAT(str1, str2) str1##str2 +#else +#define __CAT(str1, str2) str1 str2 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#define CAT(str1, str2) __CAT(str1, str2) +#endif +#ifdef __PIC__ +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define CPRESTORE(register) .cprestore register +#define CPADD(register) .cpadd register +#define CPLOAD(register) .cpload register +#else +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define CPRESTORE(register) +#define CPADD(register) +#define CPLOAD(register) +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LEAF(symbol) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, 0, ra +#define NESTED(symbol, framesize, rpc) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, framesize, rpc +#define END(function) .end function; .size function, .-function +#define EXPORT(symbol) .globl symbol; symbol: +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define FEXPORT(symbol) .globl symbol; .type symbol, @function; symbol: +#define ABS(symbol,value) .globl symbol; symbol = value +#define PANIC(msg) .set push; .set reorder; PTR_LA a0, 8f; jal panic; 9: b 9b; .set pop; TEXT(msg) +#define PRINT(string) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define TEXT(msg) .pushsection .data; 8: .asciiz msg; .popsection; +#define TTABLE(string) .pushsection .text; .word 1f; .popsection .pushsection .data; 1: .asciiz string; .popsection +#define PREF(hint, addr) +#define PREFX(hint, addr) +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#if _MIPS_ISA == _MIPS_ISA_MIPS1 +#define MOVN(rd, rs, rt) .set push; .set reorder; beqz rt, 9f; move rd, rs; .set pop; 9: +#define MOVZ(rd, rs, rt) .set push; .set reorder; bnez rt, 9f; move rd, rs; .set pop; 9: +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#if _MIPS_ISA == _MIPS_ISA_MIPS2 || _MIPS_ISA == _MIPS_ISA_MIPS3 +#define MOVN(rd, rs, rt) .set push; .set noreorder; bnezl rt, 9f; move rd, rs; .set pop; 9: +#define MOVZ(rd, rs, rt) .set push; .set noreorder; beqzl rt, 9f; move rd, rs; .set pop; 9: +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#if _MIPS_ISA == _MIPS_ISA_MIPS4 || _MIPS_ISA == _MIPS_ISA_MIPS5 || _MIPS_ISA == _MIPS_ISA_MIPS32 || _MIPS_ISA == _MIPS_ISA_MIPS64 +#define MOVN(rd, rs, rt) movn rd, rs, rt +#define MOVZ(rd, rs, rt) movz rd, rs, rt +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#define ALSZ 7 +#define ALMASK ~7 +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64 +#define ALSZ 15 +#define ALMASK ~15 +#endif +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#ifdef __mips64 +#define SZREG 8 +#else +#define SZREG 4 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#define REG_S sw +#define REG_L lw +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define REG_SUBU subu +#define REG_ADDU addu +#endif +#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define REG_S sd +#define REG_L ld +#define REG_SUBU dsubu +#define REG_ADDU daddu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SZINT == 32 +#define INT_ADD add +#define INT_ADDU addu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_ADDI addi +#define INT_ADDIU addiu +#define INT_SUB sub +#define INT_SUBU subu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_L lw +#define INT_S sw +#define INT_SLL sll +#define INT_SLLV sllv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_SRL srl +#define INT_SRLV srlv +#define INT_SRA sra +#define INT_SRAV srav +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SZINT == 64 +#define INT_ADD dadd +#define INT_ADDU daddu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_ADDI daddi +#define INT_ADDIU daddiu +#define INT_SUB dsub +#define INT_SUBU dsubu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_L ld +#define INT_S sd +#define INT_SLL dsll +#define INT_SLLV dsllv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define INT_SRL dsrl +#define INT_SRLV dsrlv +#define INT_SRA dsra +#define INT_SRAV dsrav +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SZLONG == 32 +#define LONG_ADD add +#define LONG_ADDU addu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_ADDI addi +#define LONG_ADDIU addiu +#define LONG_SUB sub +#define LONG_SUBU subu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_L lw +#define LONG_S sw +#define LONG_SLL sll +#define LONG_SLLV sllv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_SRL srl +#define LONG_SRLV srlv +#define LONG_SRA sra +#define LONG_SRAV srav +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG .word +#define LONGSIZE 4 +#define LONGMASK 3 +#define LONGLOG 2 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SZLONG == 64 +#define LONG_ADD dadd +#define LONG_ADDU daddu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_ADDI daddi +#define LONG_ADDIU daddiu +#define LONG_SUB dsub +#define LONG_SUBU dsubu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_L ld +#define LONG_S sd +#define LONG_SLL dsll +#define LONG_SLLV dsllv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG_SRL dsrl +#define LONG_SRLV dsrlv +#define LONG_SRA dsra +#define LONG_SRAV dsrav +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define LONG .dword +#define LONGSIZE 8 +#define LONGMASK 7 +#define LONGLOG 3 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SZPTR == 32 +#define PTR_ADD add +#define PTR_ADDU addu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_ADDI addi +#define PTR_ADDIU addiu +#define PTR_SUB sub +#define PTR_SUBU subu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_L lw +#define PTR_S sw +#define PTR_LA la +#define PTR_LI li +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_SLL sll +#define PTR_SLLV sllv +#define PTR_SRL srl +#define PTR_SRLV srlv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_SRA sra +#define PTR_SRAV srav +#define PTR_SCALESHIFT 2 +#define PTR .word +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTRSIZE 4 +#define PTRLOG 2 +#endif +#if _MIPS_SZPTR == 64 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_ADD dadd +#define PTR_ADDU daddu +#define PTR_ADDI daddi +#define PTR_ADDIU daddiu +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_SUB dsub +#define PTR_SUBU dsubu +#define PTR_L ld +#define PTR_S sd +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_LA dla +#define PTR_LI dli +#define PTR_SLL dsll +#define PTR_SLLV dsllv +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_SRL dsrl +#define PTR_SRLV dsrlv +#define PTR_SRA dsra +#define PTR_SRAV dsrav +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define PTR_SCALESHIFT 3 +#define PTR .dword +#define PTRSIZE 8 +#define PTRLOG 3 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#define MFC0 mfc0 +#define MTC0 mtc0 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64 +#define MFC0 dmfc0 +#define MTC0 dmtc0 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#define SSNOP sll zero, zero, 1 +#define R10KCBARRIER(addr) +#endif // defined(__has_include_next) && __has_include_next() +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/fpregdef.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/fpregdef.h new file mode 100644 index 0000000000..a6eedc0e98 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/fpregdef.h @@ -0,0 +1,117 @@ +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H + +#if defined(__has_include_next) && __has_include_next() +#include_next +#else + +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ + +#include +#if _MIPS_SIM == _MIPS_SIM_ABI32 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fv0 $f0 +#define fv0f $f1 +#define fv1 $f2 +#define fv1f $f3 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fa0 $f12 +#define fa0f $f13 +#define fa1 $f14 +#define fa1f $f15 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft0 $f4 +#define ft0f $f5 +#define ft1 $f6 +#define ft1f $f7 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft2 $f8 +#define ft2f $f9 +#define ft3 $f10 +#define ft3f $f11 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft4 $f16 +#define ft4f $f17 +#define ft5 $f18 +#define ft5f $f19 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fs0 $f20 +#define fs0f $f21 +#define fs1 $f22 +#define fs1f $f23 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fs2 $f24 +#define fs2f $f25 +#define fs3 $f26 +#define fs3f $f27 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fs4 $f28 +#define fs4f $f29 +#define fs5 $f30 +#define fs5f $f31 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fcr31 $31 +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 +#define fv0 $f0 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fv1 $f2 +#define fa0 $f12 +#define fa1 $f13 +#define fa2 $f14 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fa3 $f15 +#define fa4 $f16 +#define fa5 $f17 +#define fa6 $f18 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fa7 $f19 +#define ft0 $f4 +#define ft1 $f5 +#define ft2 $f6 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft3 $f7 +#define ft4 $f8 +#define ft5 $f9 +#define ft6 $f10 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft7 $f11 +#define ft8 $f20 +#define ft9 $f21 +#define ft10 $f22 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define ft11 $f23 +#define ft12 $f1 +#define ft13 $f3 +#define fs0 $f24 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fs1 $f25 +#define fs2 $f26 +#define fs3 $f27 +#define fs4 $f28 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define fs5 $f29 +#define fs6 $f30 +#define fs7 $f31 +#define fcr31 $31 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#endif +#endif // defined(__has_include_next) && __has_include_next() +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/regdef.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/regdef.h new file mode 100644 index 0000000000..a7fd769059 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/asm-mips/regdef.h @@ -0,0 +1,125 @@ +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H + +#if defined(__has_include_next) && __has_include_next() +#include_next +#else + +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ + +#include +#if _MIPS_SIM == _MIPS_SIM_ABI32 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define zero $0 +#define AT $1 +#define v0 $2 +#define v1 $3 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define t8 $24 +#define t9 $25 +#define jp $25 +#define k0 $26 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s8 $30 +#define ra $31 +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define zero $0 +#define AT $at +#define v0 $2 +#define v1 $3 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define a4 $8 +#define ta0 $8 +#define a5 $9 +#define ta1 $9 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define a6 $10 +#define ta2 $10 +#define a7 $11 +#define ta3 $11 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define t0 $12 +#define t1 $13 +#define t2 $14 +#define t3 $15 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define t8 $24 +#define t9 $25 +#define jp $25 +#define k0 $26 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ +#define s8 $30 +#define ra $31 +#endif +#endif // defined(__has_include_next) && __has_include_next() +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H +/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h new file mode 100644 index 0000000000..e6f0c672f9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h @@ -0,0 +1,157 @@ +// Copyright (c) 2012, 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_COMMON_ANDROID_INCLUDE_ELF_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The Android provides BSD-based definitions for the ElfXX_Nhdr +// types +// always source-compatible with the GLibc/kernel ones. To overcome this +// issue without modifying a lot of code in Breakpad, use an ugly macro +// renaming trick with #include_next + +// Avoid conflict with BSD-based definition of ElfXX_Nhdr. +// Unfortunately, their field member names do not use a 'n_' prefix. +#define Elf32_Nhdr __bsd_Elf32_Nhdr +#define Elf64_Nhdr __bsd_Elf64_Nhdr + +// In case they are defined by the NDK version +#define Elf32_auxv_t __bionic_Elf32_auxv_t +#define Elf64_auxv_t __bionic_Elf64_auxv_t + +#define Elf32_Dyn __bionic_Elf32_Dyn +#define Elf64_Dyn __bionic_Elf64_Dyn + +#include_next + +#undef Elf32_Nhdr +#undef Elf64_Nhdr + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +#undef Elf32_auxv_t +#undef Elf64_auxv_t + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +#undef Elf32_Dyn +#undef Elf64_Dyn + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + + +// The Android headers don't always define this constant. +#ifndef EM_X86_64 +#define EM_X86_64 62 +#endif + +#ifndef EM_PPC64 +#define EM_PPC64 21 +#endif + +#ifndef EM_S390 +#define EM_S390 22 +#endif + +#if !defined(AT_SYSINFO_EHDR) +#define AT_SYSINFO_EHDR 33 +#endif + +#if !defined(NT_PRSTATUS) +#define NT_PRSTATUS 1 +#endif + +#if !defined(NT_PRPSINFO) +#define NT_PRPSINFO 3 +#endif + +#if !defined(NT_AUXV) +#define NT_AUXV 6 +#endif + +#if !defined(NT_PRXFPREG) +#define NT_PRXFPREG 0x46e62b7f +#endif + +#if !defined(NT_FPREGSET) +#define NT_FPREGSET 2 +#endif + +#if !defined(SHT_MIPS_DWARF) +#define SHT_MIPS_DWARF 0x7000001e +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h new file mode 100644 index 0000000000..4324629df7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h @@ -0,0 +1,77 @@ +// Copyright (c) 2012, 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_ANDROID_INCLUDE_LINK_H +#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H + +/* Android doesn't provide all the data-structures required in its . + Provide custom version here. */ +#include_next + +#include + +// TODO(rmcilroy): Remove this file once the NDK API level is updated to at +// least 21 for all architectures. https://crbug.com/358831 + +// These structures are only present in traditional headers at API level 21 and +// above. Unified headers define these structures regardless of the chosen API +// level. __ANDROID_API_N__ is a proxy for determining whether unified headers +// are in use. It’s only defined by unified headers. +#if __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct r_debug { + int r_version; + struct link_map* r_map; + ElfW(Addr) r_brk; + enum { + RT_CONSISTENT, + RT_ADD, + RT_DELETE } r_state; + ElfW(Addr) r_ldbase; +}; + +struct link_map { + ElfW(Addr) l_addr; + char* l_name; + ElfW(Dyn)* l_ld; + struct link_map* l_next; + struct link_map* l_prev; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__) + +#endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h new file mode 100644 index 0000000000..cd92902151 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012, 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_COMMON_ANDROID_INCLUDE_STAB_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H + +#include + +#ifdef __BIONIC_HAVE_STAB_H +#include +#else + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define _STAB_CODE_LIST \ + _STAB_CODE_DEF(UNDF,0x00) \ + _STAB_CODE_DEF(GSYM,0x20) \ + _STAB_CODE_DEF(FNAME,0x22) \ + _STAB_CODE_DEF(FUN,0x24) \ + _STAB_CODE_DEF(STSYM,0x26) \ + _STAB_CODE_DEF(LCSYM,0x28) \ + _STAB_CODE_DEF(MAIN,0x2a) \ + _STAB_CODE_DEF(PC,0x30) \ + _STAB_CODE_DEF(NSYMS,0x32) \ + _STAB_CODE_DEF(NOMAP,0x34) \ + _STAB_CODE_DEF(OBJ,0x38) \ + _STAB_CODE_DEF(OPT,0x3c) \ + _STAB_CODE_DEF(RSYM,0x40) \ + _STAB_CODE_DEF(M2C,0x42) \ + _STAB_CODE_DEF(SLINE,0x44) \ + _STAB_CODE_DEF(DSLINE,0x46) \ + _STAB_CODE_DEF(BSLINE,0x48) \ + _STAB_CODE_DEF(BROWS,0x48) \ + _STAB_CODE_DEF(DEFD,0x4a) \ + _STAB_CODE_DEF(EHDECL,0x50) \ + _STAB_CODE_DEF(MOD2,0x50) \ + _STAB_CODE_DEF(CATCH,0x54) \ + _STAB_CODE_DEF(SSYM,0x60) \ + _STAB_CODE_DEF(SO,0x64) \ + _STAB_CODE_DEF(LSYM,0x80) \ + _STAB_CODE_DEF(BINCL,0x82) \ + _STAB_CODE_DEF(SOL,0x84) \ + _STAB_CODE_DEF(PSYM,0xa0) \ + _STAB_CODE_DEF(EINCL,0xa2) \ + _STAB_CODE_DEF(ENTRY,0xa4) \ + _STAB_CODE_DEF(LBRAC,0xc0) \ + _STAB_CODE_DEF(EXCL,0xc2) \ + _STAB_CODE_DEF(SCOPE,0xc4) \ + _STAB_CODE_DEF(RBRAC,0xe0) \ + _STAB_CODE_DEF(BCOMM,0xe2) \ + _STAB_CODE_DEF(ECOMM,0xe4) \ + _STAB_CODE_DEF(ECOML,0xe8) \ + _STAB_CODE_DEF(NBTEXT,0xf0) \ + _STAB_CODE_DEF(NBDATA,0xf2) \ + _STAB_CODE_DEF(NBBSS,0xf4) \ + _STAB_CODE_DEF(NBSTS,0xf6) \ + _STAB_CODE_DEF(NBLCS,0xf8) \ + _STAB_CODE_DEF(LENG,0xfe) + +enum __stab_debug_code { +#define _STAB_CODE_DEF(x,y) N_##x = y, +_STAB_CODE_LIST +#undef _STAB_CODE_DEF +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __BIONIC_HAVE_STAB_H + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h new file mode 100644 index 0000000000..185124364e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h @@ -0,0 +1,124 @@ +// Copyright (c) 2012, 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_COMMON_ANDROID_SYS_PROCFS_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H + +#ifdef __BIONIC_HAVE_SYS_PROCFS_H + +#include_next + +#else + +#include +#include +#if defined (__mips__) +#include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(__x86_64__) || defined(__aarch64__) +typedef unsigned long long elf_greg_t; +#else +typedef unsigned long elf_greg_t; +#endif + +#ifdef __arm__ +#define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t)) +#elif defined(__aarch64__) +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) +#elif defined(__mips__) +#define ELF_NGREG 45 +#else +#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) +#endif + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short pr_cursig; + unsigned long pr_sigpend; + unsigned long pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pd_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +#define ELF_PRARGSZ 80 + +struct elf_prpsinfo { + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + unsigned long pr_flags; +#ifdef __x86_64__ + unsigned int pr_uid; + unsigned int pr_gid; +#elif defined(__mips__) + __kernel_uid_t pr_uid; + __kernel_gid_t pr_gid; +#else + unsigned short pr_uid; + unsigned short pr_gid; +#endif + int pr_pid; + int pr_ppid; + int pr_pgrp; + int pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __BIONIC_HAVE_SYS_PROCFS_H + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h new file mode 100644 index 0000000000..9c27ef0225 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012, 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_COMMON_ANDROID_INCLUDE_SYS_USER_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H + +// The purpose of this file is to glue the mismatching headers (Android NDK vs +// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code. +// The following quirks are currently handled by this file: +// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct. + +// TODO(primiano): remove these changes after Chromium has stably rolled to +// an NDK with the appropriate fixes. https://crbug.com/358831 + +// With traditional headers, forgot to do this. Unified headers get +// it right. +#include + +#include_next + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(__i386__) +#if __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__) + +// user_fpxregs_struct was called user_fxsr_struct in traditional headers before +// API level 21. Unified headers call it user_fpxregs_struct regardless of the +// chosen API level. __ANDROID_API_N__ is a proxy for determining whether +// unified headers are in use. It’s only defined by unified headers. +typedef struct user_fxsr_struct user_fpxregs_struct; + +#endif // __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__) +#endif // defined(__i386__) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h new file mode 100644 index 0000000000..85373fd2a0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h @@ -0,0 +1,76 @@ +// Copyright (c) 2012, 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. + +// Android doesn't provide wcscasecmp(), so provide an alternative here. +// +// Note that this header is not needed when Breakpad is compiled against +// a recent version of Googletest. It shall be considered for removal once +// src/testing/ is updated to an appropriate revision in the future. + +#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H +#define GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H + +#include_next + +#if !defined(__aarch64__) && !defined(__x86_64__) && \ + !(defined(__mips__) && _MIPS_SIM == _ABI64) + +// This needs to be in an extern "C" namespace, or Googletest will not +// compile against it. +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +static wchar_t inline wcstolower(wchar_t ch) { + if (ch >= L'a' && ch <= L'A') + ch -= L'a' - L'A'; + return ch; +} + +static int inline wcscasecmp(const wchar_t* s1, const wchar_t* s2) { + for (;;) { + wchar_t c1 = wcstolower(*s1); + wchar_t c2 = wcstolower(*s2); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (c1 == L'0') + return 0; + s1++; + s2++; + } +} + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif + +#endif // GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h new file mode 100644 index 0000000000..b86e2cd783 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h @@ -0,0 +1,110 @@ +// Copyright (c) 2012, 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. + +// mkdtemp() wasn't declared in until NDK r9b due to a simple +// packaging bug (the function has always been implemented in all versions +// of the C library). This header is provided to build Breakpad with earlier +// NDK revisions (e.g. the one used by Chromium). It may be removed in the +// future once all major projects upgrade to use a more recent NDK. +// +// The reason this is inlined here is to avoid linking a new object file +// into each unit test program (i.e. keep build files simple). + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H + +#include +#include +#include +#include +#include +#include + +// Using a macro renaming trick here is necessary when building against +// NDK r9b. Otherwise the compiler will complain that calls to mkdtemp() +// are ambiguous. +#define mkdtemp breakpad_mkdtemp + +namespace { + +char* breakpad_mkdtemp(char* path) { + if (path == NULL) { + errno = EINVAL; + return NULL; + } + + // 'path' must be terminated with six 'X' + const char kSuffix[] = "XXXXXX"; + const size_t kSuffixLen = strlen(kSuffix); + char* path_end = path + strlen(path); + + if (static_cast(path_end - path) < kSuffixLen || + memcmp(path_end - kSuffixLen, kSuffix, kSuffixLen) != 0) { + errno = EINVAL; + return NULL; + } + + // If 'path' contains a directory separator, check that it exists to + // avoid looping later. + char* sep = strrchr(path, '/'); + if (sep != NULL) { + struct stat st; + int ret; + *sep = '\0'; // temporarily zero-terminate the dirname. + ret = stat(path, &st); + *sep = '/'; // restore full path. + if (ret < 0) + return NULL; + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + return NULL; + } + } + + // Loop. On each iteration, replace the XXXXXX suffix with a random + // number. + int tries; + for (tries = 128; tries > 0; tries--) { + int random = rand() % 1000000; + + snprintf(path_end - kSuffixLen, kSuffixLen + 1, "%0d", random); + if (mkdir(path, 0700) == 0) + return path; // Success + + if (errno != EEXIST) + return NULL; + } + + assert(errno == EEXIST); + return NULL; +} + +} // namespace + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h new file mode 100644 index 0000000000..20c1208480 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h @@ -0,0 +1,94 @@ +// Copyright (c) 2012, 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. + +// This contains Pthread-related functions not provided by the Android NDK +// but required by the Breakpad unit test. The functions are inlined here +// in a C++ anonymous namespace in order to keep the build files simples. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H + +#include + +namespace { + +// Android doesn't provide pthread_barrier_t for now. +#ifndef PTHREAD_BARRIER_SERIAL_THREAD + +// Anything except 0 will do here. +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned count; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* /* barrier_attr */, + unsigned count) { + barrier->count = count; + pthread_mutex_init(&barrier->mutex, NULL); + pthread_cond_init(&barrier->cond, NULL); + return 0; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + // Lock the mutex + pthread_mutex_lock(&barrier->mutex); + // Decrement the count. If this is the first thread to reach 0, wake up + // waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD. + if (--barrier->count == 0) { + // First thread to reach the barrier + pthread_cond_broadcast(&barrier->cond); + pthread_mutex_unlock(&barrier->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + // Otherwise, wait for other threads until the count reaches 0, then + // return 0 to indicate this is not the first thread. + do { + pthread_cond_wait(&barrier->cond, &barrier->mutex); + } while (barrier->count > 0); + + pthread_mutex_unlock(&barrier->mutex); + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *barrier) { + barrier->count = 0; + pthread_cond_destroy(&barrier->cond); + pthread_mutex_destroy(&barrier->mutex); + return 0; +} + +#endif // defined(PTHREAD_BARRIER_SERIAL_THREAD) + +} // namespace + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc new file mode 100644 index 0000000000..2d1ed983dc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc @@ -0,0 +1,487 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 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. + + +// Derived from libunwind, with extensive modifications. + + +#include "common/arm_ex_reader.h" + +#include +#include + +// This file, in conjunction with arm_ex_to_module.cc, translates +// EXIDX unwind information into the same format that Breakpad uses +// for CFI information. Hence Breakpad's CFI unwinding abilities +// also become usable for EXIDX. +// +// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf + +// EXIDX data is presented in two parts: +// +// * an index table. This contains two words per routine, +// the first of which identifies the routine, and the second +// of which is a reference to the unwind bytecode. If the +// bytecode is very compact -- 3 bytes or less -- it can be +// stored directly in the second word. +// +// * an area containing the unwind bytecodes. + +// General flow is: ExceptionTableInfo::Start iterates over all +// of the index table entries (pairs). For each entry, it: +// +// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode +// out into an intermediate buffer. + +// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate +// buffer. Each bytecode instruction is bundled into a +// arm_ex_to_module::extab_data structure, and handed to .. +// +// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to +// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI +// records that Breakpad stores. + +#define ARM_EXIDX_CANT_UNWIND 0x00000001 +#define ARM_EXIDX_COMPACT 0x80000000 +#define ARM_EXTBL_OP_FINISH 0xb0 +#define ARM_EXIDX_TABLE_LIMIT (255*4) + +namespace arm_ex_reader { + +using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; +using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; +using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; +using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; +using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; +using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; +using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; +using arm_ex_to_module::exidx_entry; +using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; +using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; +using google_breakpad::MemoryRange; + + +static void* Prel31ToAddr(const void* addr) { + uint32_t offset32 = *reinterpret_cast(addr); + // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions + // 63:31 inclusive. + uint64_t offset64 = offset32; + if (offset64 & (1ULL << 30)) + offset64 |= 0xFFFFFFFF80000000ULL; + else + offset64 &= 0x000000007FFFFFFFULL; + return ((char*)addr) + (uintptr_t)offset64; +} + + +// Extract unwind bytecode for the function denoted by |entry| into |buf|, +// and return the number of bytes of |buf| written, along with a code +// indicating the outcome. + +ExceptionTableInfo::ExExtractResult ExceptionTableInfo::ExtabEntryExtract( + const struct exidx_entry* entry, + uint8_t* buf, size_t buf_size, + size_t* buf_used) { + MemoryRange mr_out(buf, buf_size); + + *buf_used = 0; + +# define PUT_BUF_U8(_byte) \ + do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ + buf[(*buf_used)++] = (_byte); } while (0) + +# define GET_EX_U32(_lval, _addr, _sec_mr) \ + do { if (!(_sec_mr).Covers(reinterpret_cast(_addr) \ + - (_sec_mr).data(), 4)) \ + return ExInBufOverflow; \ + (_lval) = *(reinterpret_cast(_addr)); } while (0) + +# define GET_EXIDX_U32(_lval, _addr) \ + GET_EX_U32(_lval, _addr, mr_exidx_) +# define GET_EXTAB_U32(_lval, _addr) \ + GET_EX_U32(_lval, _addr, mr_extab_) + + uint32_t data; + GET_EXIDX_U32(data, &entry->data); + + // A function can be marked CANT_UNWIND if (eg) it is known to be + // at the bottom of the stack. + if (data == ARM_EXIDX_CANT_UNWIND) + return ExCantUnwind; + + uint32_t pers; // personality number + uint32_t extra; // number of extra data words required + uint32_t extra_allowed; // number of extra data words allowed + uint32_t* extbl_data; // the handler entry, if not inlined + + if (data & ARM_EXIDX_COMPACT) { + // The handler table entry has been inlined into the index table entry. + // In this case it can only be an ARM-defined compact model, since + // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the + // ARM compact model, but 1 and 2 are "Long format" and may require + // extra data words. Hence the allowable personalities here are: + // personality 0, in which case 'extra' has no meaning + // personality 1, with zero extra words + // personality 2, with zero extra words + extbl_data = NULL; + pers = (data >> 24) & 0x0F; + extra = (data >> 16) & 0xFF; + extra_allowed = 0; + } + else { + // The index table entry is a pointer to the handler entry. Note + // that Prel31ToAddr will read the given address, but we already + // range-checked above. + extbl_data = reinterpret_cast(Prel31ToAddr(&entry->data)); + GET_EXTAB_U32(data, extbl_data); + if (!(data & ARM_EXIDX_COMPACT)) { + // This denotes a "generic model" handler. That will involve + // executing arbitary machine code, which is something we + // can't represent here; hence reject it. + return ExCantRepresent; + } + // So we have a compact model representation. Again, 3 possible + // personalities, but this time up to 255 allowable extra words. + pers = (data >> 24) & 0x0F; + extra = (data >> 16) & 0xFF; + extra_allowed = 255; + extbl_data++; + } + + // Now look at the the handler table entry. The first word is + // |data| and subsequent words start at |*extbl_data|. The number + // of extra words to use is |extra|, provided that the personality + // allows extra words. Even if it does, none may be available -- + // extra_allowed is the maximum number of extra words allowed. */ + if (pers == 0) { + // "Su16" in the documentation -- 3 unwinding insn bytes + // |extra| has no meaning here; instead that byte is an unwind-info byte + PUT_BUF_U8(data >> 16); + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data); + } + else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { + // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, + // and up to 255 extra words. + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data); + for (uint32_t j = 0; j < extra; j++) { + GET_EXTAB_U32(data, extbl_data); + extbl_data++; + PUT_BUF_U8(data >> 24); + PUT_BUF_U8(data >> 16); + PUT_BUF_U8(data >> 8); + PUT_BUF_U8(data >> 0); + } + } + else { + // The entry is invalid. + return ExInvalid; + } + + // Make sure the entry is terminated with "FINISH" + if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) + PUT_BUF_U8(ARM_EXTBL_OP_FINISH); + + return ExSuccess; + +# undef GET_EXTAB_U32 +# undef GET_EXIDX_U32 +# undef GET_U32 +# undef PUT_BUF_U8 +} + + +// Take the unwind information extracted by ExtabEntryExtract +// and parse it into frame-unwind instructions. These are as +// specified in "Table 4, ARM-defined frame-unwinding instructions" +// in the specification document detailed in comments at the top +// of this file. +// +// This reads from |buf[0, +data_size)|. It checks for overruns of +// the input buffer and returns a negative value if that happens, or +// for any other failure cases. It returns zero in case of success. +int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) { + if (buf == NULL || buf_size == 0) + return -1; + + MemoryRange mr_in(buf, buf_size); + const uint8_t* buf_initially = buf; + +# define GET_BUF_U8(_lval) \ + do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ + (_lval) = *(buf++); } while (0) + + const uint8_t* end = buf + buf_size; + + while (buf < end) { + struct arm_ex_to_module::extab_data edata; + memset(&edata, 0, sizeof(edata)); + + uint8_t op; + GET_BUF_U8(op); + if ((op & 0xc0) == 0x00) { + // vsp = vsp + (xxxxxx << 2) + 4 + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; + edata.data = (((int)op & 0x3f) << 2) + 4; + } else if ((op & 0xc0) == 0x40) { + // vsp = vsp - (xxxxxx << 2) - 4 + edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; + edata.data = (((int)op & 0x3f) << 2) + 4; + } else if ((op & 0xf0) == 0x80) { + uint8_t op2; + GET_BUF_U8(op2); + if (op == 0x80 && op2 == 0x00) { + // Refuse to unwind + edata.cmd = ARM_EXIDX_CMD_REFUSED; + } else { + // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = ((op & 0xf) << 8) | op2; + edata.data = edata.data << 4; + } + } else if ((op & 0xf0) == 0x90) { + if (op == 0x9d || op == 0x9f) { + // 9d: Reserved as prefix for ARM register to register moves + // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Set vsp = r[nnnn] + edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; + edata.data = op & 0x0f; + } + } else if ((op & 0xf0) == 0xa0) { + // Pop r4 to r[4+nnn], or + // Pop r4 to r[4+nnn] and r14 or + unsigned end = (op & 0x07); + edata.data = (1 << (end + 1)) - 1; + edata.data = edata.data << 4; + if (op & 0x08) edata.data |= 1 << 14; + edata.cmd = ARM_EXIDX_CMD_REG_POP; + } else if (op == ARM_EXTBL_OP_FINISH) { + // Finish + edata.cmd = ARM_EXIDX_CMD_FINISH; + buf = end; + } else if (op == 0xb1) { + uint8_t op2; + GET_BUF_U8(op2); + if (op2 == 0 || (op2 & 0xf0)) { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Pop integer registers under mask {r3,r2,r1,r0} + edata.cmd = ARM_EXIDX_CMD_REG_POP; + edata.data = op2 & 0x0f; + } + } else if (op == 0xb2) { + // vsp = vsp + 0x204 + (uleb128 << 2) + uint64_t offset = 0; + uint8_t byte, shift = 0; + do { + GET_BUF_U8(byte); + offset |= (byte & 0x7f) << shift; + shift += 7; + } while ((byte & 0x80) && buf < end); + edata.data = offset * 4 + 0x204; + edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; + } else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { + // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly + // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly + // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + GET_BUF_U8(edata.data); + if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; + if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; + } else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { + // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly + // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly + edata.cmd = ARM_EXIDX_CMD_VFP_POP; + edata.data = 0x80 | (op & 0x07); + if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; + } else if (op >= 0xc0 && op <= 0xc5) { + // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + edata.data = 0xa0 | (op & 0x07); + } else if (op == 0xc6) { + // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] + edata.cmd = ARM_EXIDX_CMD_WREG_POP; + GET_BUF_U8(edata.data); + } else if (op == 0xc7) { + uint8_t op2; + GET_BUF_U8(op2); + if (op2 == 0 || (op2 & 0xf0)) { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } else { + // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} + edata.cmd = ARM_EXIDX_CMD_WCGR_POP; + edata.data = op2 & 0x0f; + } + } else { + // Spare + edata.cmd = ARM_EXIDX_CMD_RESERVED; + } + + int ret = handler_->ImproveStackFrame(&edata); + if (ret < 0) + return ret; + } + return 0; + +# undef GET_BUF_U8 +} + +void ExceptionTableInfo::Start() { + const struct exidx_entry* start + = reinterpret_cast(mr_exidx_.data()); + const struct exidx_entry* end + = reinterpret_cast(mr_exidx_.data() + + mr_exidx_.length()); + + // Iterate over each of the EXIDX entries (pairs of 32-bit words). + // These occupy the entire .exidx section. + for (const struct exidx_entry* entry = start; entry < end; ++entry) { + // Figure out the code address range that this table entry is + // associated with. + uint32_t addr = (reinterpret_cast(Prel31ToAddr(&entry->addr)) + - mapping_addr_ + loading_addr_) & 0x7fffffff; + uint32_t next_addr; + if (entry < end - 1) { + next_addr = (reinterpret_cast(Prel31ToAddr(&((entry + 1)->addr))) + - mapping_addr_ + loading_addr_) & 0x7fffffff; + } else { + // This is the last EXIDX entry in the sequence, so we don't + // have an address for the start of the next function, to limit + // this one. Instead use the address of the last byte of the + // text section associated with this .exidx section, that we + // have been given. So as to avoid junking up the CFI unwind + // tables with absurdly large address ranges in the case where + // text_last_svma_ is wrong, only use the value if it is nonzero + // and within one page of |addr|. Otherwise assume a length of 1. + // + // In some cases, gcc has been observed to finish the exidx + // section with an entry of length 1 marked CANT_UNWIND, + // presumably exactly for the purpose of giving a definite + // length for the last real entry, without having to look at + // text segment boundaries. + bool plausible = false; + next_addr = addr + 1; + if (text_last_svma_ != 0) { + uint32_t maybe_next_addr = text_last_svma_ + 1; + if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { + next_addr = maybe_next_addr; + plausible = true; + } + } + if (!plausible) { + fprintf(stderr, "ExceptionTableInfo: implausible EXIDX last entry size " + "%d, using 1 instead.", (int32_t)(text_last_svma_ - addr)); + } + } + + // Extract the unwind info into |buf|. This might fail for + // various reasons. It involves reading both the .exidx and + // .extab sections. All accesses to those sections are + // bounds-checked. + uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; + size_t buf_used = 0; + ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); + if (res != ExSuccess) { + // Couldn't extract the unwind info, for some reason. Move on. + switch (res) { + case ExInBufOverflow: + fprintf(stderr, "ExtabEntryExtract: .exidx/.extab section overrun"); + break; + case ExOutBufOverflow: + fprintf(stderr, "ExtabEntryExtract: bytecode buffer overflow"); + break; + case ExCantUnwind: + fprintf(stderr, "ExtabEntryExtract: function is marked CANT_UNWIND"); + break; + case ExCantRepresent: + fprintf(stderr, "ExtabEntryExtract: bytecode can't be represented"); + break; + case ExInvalid: + fprintf(stderr, "ExtabEntryExtract: index table entry is invalid"); + break; + default: + fprintf(stderr, "ExtabEntryExtract: unknown error: %d", (int)res); + break; + } + continue; + } + + // Finally, work through the unwind instructions in |buf| and + // create CFI entries that Breakpad can use. This can also fail. + // First, add a new stack frame entry, into which ExtabEntryDecode + // will write the CFI entries. + if (!handler_->HasStackFrame(addr, next_addr - addr)) { + handler_->AddStackFrame(addr, next_addr - addr); + int ret = ExtabEntryDecode(buf, buf_used); + if (ret < 0) { + handler_->DeleteStackFrame(); + fprintf(stderr, "ExtabEntryDecode: failed with error code: %d", ret); + continue; + } + handler_->SubmitStackFrame(); + } + + } /* iterating over .exidx */ +} + +} // namespace arm_ex_reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h new file mode 100644 index 0000000000..9b54e8a0be --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h @@ -0,0 +1,114 @@ +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 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. + + +// Derived from libunwind, with extensive modifications. + +#ifndef COMMON_ARM_EX_READER_H__ +#define COMMON_ARM_EX_READER_H__ + +#include "common/arm_ex_to_module.h" +#include "common/memory_range.h" + +namespace arm_ex_reader { + +// This class is a reader for ARM unwind information +// from .ARM.exidx and .ARM.extab sections. +class ExceptionTableInfo { + public: + ExceptionTableInfo(const char* exidx, size_t exidx_size, + const char* extab, size_t extab_size, + uint32_t text_last_svma, + arm_ex_to_module::ARMExToModule* handler, + const char* mapping_addr, + uint32_t loading_addr) + : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)), + mr_extab_(google_breakpad::MemoryRange(extab, extab_size)), + text_last_svma_(text_last_svma), + handler_(handler), mapping_addr_(mapping_addr), + loading_addr_(loading_addr) { } + + ~ExceptionTableInfo() { } + + // Parses the entries in .ARM.exidx and possibly + // in .ARM.extab tables, reports what we find to + // arm_ex_to_module::ARMExToModule. + void Start(); + + private: + google_breakpad::MemoryRange mr_exidx_; + google_breakpad::MemoryRange mr_extab_; + uint32_t text_last_svma_; + arm_ex_to_module::ARMExToModule* handler_; + const char* mapping_addr_; + uint32_t loading_addr_; + + enum ExExtractResult { + ExSuccess, // success + ExInBufOverflow, // out-of-range while reading .exidx + ExOutBufOverflow, // output buffer is too small + ExCantUnwind, // this function is marked CANT_UNWIND + ExCantRepresent, // entry valid, but we can't represent it + ExInvalid // entry is invalid + }; + ExExtractResult + ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry, + uint8_t* buf, size_t buf_size, + size_t* buf_used); + + int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); +}; + +} // namespace arm_ex_reader + +#endif // COMMON_ARM_EX_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc new file mode 100644 index 0000000000..c326744f64 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc @@ -0,0 +1,209 @@ + +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 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. + + +// Derived from libunwind, with extensive modifications. + +#include "common/arm_ex_to_module.h" + +#include +#include + +// For big-picture comments on how the EXIDX reader works, +// see arm_ex_reader.cc. + +#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) +#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) +#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) + +using google_breakpad::Module; + +namespace arm_ex_to_module { + +static const char* const regnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "fps", "cpsr" +}; + +// Translate command from extab_data to command for Module. +int ARMExToModule::TranslateCmd(const struct extab_data* edata, + Module::StackFrameEntry* entry, string& vsp) { + int ret = 0; + switch (edata->cmd) { + case ARM_EXIDX_CMD_FINISH: + /* Copy LR to PC if there isn't currently a rule for PC in force. */ + if (entry->initial_rules.find("pc") + == entry->initial_rules.end()) { + if (entry->initial_rules.find("lr") + == entry->initial_rules.end()) { + entry->initial_rules["pc"] = "lr"; + } else { + entry->initial_rules["pc"] = entry->initial_rules["lr"]; + } + } + break; + case ARM_EXIDX_CMD_SUB_FROM_VSP: + { + char c[16]; + sprintf(c, " %d -", edata->data); + vsp += c; + } + break; + case ARM_EXIDX_CMD_ADD_TO_VSP: + { + char c[16]; + sprintf(c, " %d +", edata->data); + vsp += c; + } + break; + case ARM_EXIDX_CMD_REG_POP: + for (unsigned int i = 0; i < 16; i++) { + if (edata->data & (1 << i)) { + entry->initial_rules[regnames[i]] + = vsp + " ^"; + vsp += " 4 +"; + } + } + /* Set cfa in case the SP got popped. */ + if (edata->data & (1 << 13)) { + vsp = entry->initial_rules["sp"]; + } + break; + case ARM_EXIDX_CMD_REG_TO_SP: { + assert (edata->data < 16); + const char* const regname = regnames[edata->data]; + if (entry->initial_rules.find(regname) == entry->initial_rules.end()) { + entry->initial_rules["sp"] = regname; + } else { + entry->initial_rules["sp"] = entry->initial_rules[regname]; + } + vsp = entry->initial_rules["sp"]; + break; + } + case ARM_EXIDX_CMD_VFP_POP: + /* Don't recover VFP registers, but be sure to adjust the stack + pointer. */ + for (unsigned int i = ARM_EXBUF_START(edata->data); + i <= ARM_EXBUF_END(edata->data); i++) { + vsp += " 8 +"; + } + if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { + vsp += " 4 +"; + } + break; + case ARM_EXIDX_CMD_WREG_POP: + for (unsigned int i = ARM_EXBUF_START(edata->data); + i <= ARM_EXBUF_END(edata->data); i++) { + vsp += " 8 +"; + } + break; + case ARM_EXIDX_CMD_WCGR_POP: + // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" + for (unsigned int i = 0; i < 4; i++) { + if (edata->data & (1 << i)) { + vsp += " 4 +"; + } + } + break; + case ARM_EXIDX_CMD_REFUSED: + case ARM_EXIDX_CMD_RESERVED: + ret = -1; + break; + } + return ret; +} + +bool ARMExToModule::HasStackFrame(uintptr_t addr, size_t size) { + // Invariant: the range [addr,covered) is covered by existing stack + // frame entries. + uintptr_t covered = addr; + while (covered < addr + size) { + const Module::StackFrameEntry *old_entry = + module_->FindStackFrameEntryByAddress(covered); + if (!old_entry) { + return false; + } + covered = old_entry->address + old_entry->size; + } + return true; +} + +void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { + stack_frame_entry_ = new Module::StackFrameEntry; + stack_frame_entry_->address = addr; + stack_frame_entry_->size = size; + stack_frame_entry_->initial_rules[".cfa"] = "sp"; + vsp_ = "sp"; +} + +int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { + return TranslateCmd(edata, stack_frame_entry_, vsp_) ; +} + +void ARMExToModule::DeleteStackFrame() { + delete stack_frame_entry_; +} + +void ARMExToModule::SubmitStackFrame() { + // return address always winds up in pc + stack_frame_entry_->initial_rules[".ra"] + = stack_frame_entry_->initial_rules["pc"]; + // the final value of vsp is the new value of sp + stack_frame_entry_->initial_rules["sp"] = vsp_; + module_->AddStackFrameEntry(stack_frame_entry_); +} + +} // namespace arm_ex_to_module diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h new file mode 100644 index 0000000000..f413a16a93 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h @@ -0,0 +1,119 @@ +/* libunwind - a platform-independent unwind library + Copyright 2011 Linaro Limited + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +// Copyright (c) 2010 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. + + +// Derived from libunwind, with extensive modifications. + +#ifndef COMMON_ARM_EX_TO_MODULE__ +#define COMMON_ARM_EX_TO_MODULE__ + +#include "common/module.h" + +#include + +namespace arm_ex_to_module { + +using google_breakpad::Module; + +typedef enum extab_cmd { + ARM_EXIDX_CMD_FINISH, + ARM_EXIDX_CMD_SUB_FROM_VSP, + ARM_EXIDX_CMD_ADD_TO_VSP, + ARM_EXIDX_CMD_REG_POP, + ARM_EXIDX_CMD_REG_TO_SP, + ARM_EXIDX_CMD_VFP_POP, + ARM_EXIDX_CMD_WREG_POP, + ARM_EXIDX_CMD_WCGR_POP, + ARM_EXIDX_CMD_RESERVED, + ARM_EXIDX_CMD_REFUSED, +} extab_cmd_t; + +struct exidx_entry { + uint32_t addr; + uint32_t data; +}; + +struct extab_data { + extab_cmd_t cmd; + uint32_t data; +}; + +enum extab_cmd_flags { + ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, + ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX +}; + +// Receives information from arm_ex_reader::ExceptionTableInfo +// and adds it to the Module object +class ARMExToModule { + public: + ARMExToModule(Module* module) + : module_(module) { } + ~ARMExToModule() { } + bool HasStackFrame(uintptr_t addr, size_t size); + void AddStackFrame(uintptr_t addr, size_t size); + int ImproveStackFrame(const struct extab_data* edata); + void DeleteStackFrame(); + void SubmitStackFrame(); + private: + Module* module_; + Module::StackFrameEntry* stack_frame_entry_; + string vsp_; + int TranslateCmd(const struct extab_data* edata, + Module::StackFrameEntry* entry, + string& vsp); +}; + +} // namespace arm_ex_to_module + +#endif // COMMON_ARM_EX_TO_MODULE__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/basictypes.h b/toolkit/crashreporter/google-breakpad/src/common/basictypes.h new file mode 100644 index 0000000000..9426c1f6c2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/basictypes.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 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 COMMON_BASICTYPES_H_ +#define COMMON_BASICTYPES_H_ + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif // DISALLOW_COPY_AND_ASSIGN + +namespace google_breakpad { + +// Used to explicitly mark the return value of a function as unused. If you are +// really sure you don't want to do anything with the return value of a function +// that has been marked with __attribute__((warn_unused_result)), wrap it with +// this. Example: +// +// scoped_ptr my_var = ...; +// if (TakeOwnership(my_var.get()) == SUCCESS) +// ignore_result(my_var.release()); +// +template +inline void ignore_result(const T&) { +} + +} // namespace google_breakpad + +#endif // COMMON_BASICTYPES_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h new file mode 100644 index 0000000000..accd54e0a4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h @@ -0,0 +1,265 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// byte_cursor.h: Classes for parsing values from a buffer of bytes. +// The ByteCursor class provides a convenient interface for reading +// fixed-size integers of arbitrary endianness, being thorough about +// checking for buffer overruns. + +#ifndef COMMON_BYTE_CURSOR_H_ +#define COMMON_BYTE_CURSOR_H_ + +#include +#include +#include +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A buffer holding a series of bytes. +struct ByteBuffer { + ByteBuffer() : start(0), end(0) { } + ByteBuffer(const uint8_t *set_start, size_t set_size) + : start(set_start), end(set_start + set_size) { } + ~ByteBuffer() { }; + + // Equality operators. Useful in unit tests, and when we're using + // ByteBuffers to refer to regions of a larger buffer. + bool operator==(const ByteBuffer &that) const { + return start == that.start && end == that.end; + } + bool operator!=(const ByteBuffer &that) const { + return start != that.start || end != that.end; + } + + // Not C++ style guide compliant, but this definitely belongs here. + size_t Size() const { + assert(start <= end); + return end - start; + } + + const uint8_t *start, *end; +}; + +// A cursor pointing into a ByteBuffer that can parse numbers of various +// widths and representations, strings, and data blocks, advancing through +// the buffer as it goes. All ByteCursor operations check that accesses +// haven't gone beyond the end of the enclosing ByteBuffer. +class ByteCursor { + public: + // Create a cursor reading bytes from the start of BUFFER. By default, the + // cursor reads multi-byte values in little-endian form. + ByteCursor(const ByteBuffer *buffer, bool big_endian = false) + : buffer_(buffer), here_(buffer->start), + big_endian_(big_endian), complete_(true) { } + + // Accessor and setter for this cursor's endianness flag. + bool big_endian() const { return big_endian_; } + void set_big_endian(bool big_endian) { big_endian_ = big_endian; } + + // Accessor and setter for this cursor's current position. The setter + // returns a reference to this cursor. + const uint8_t *here() const { return here_; } + ByteCursor &set_here(const uint8_t *here) { + assert(buffer_->start <= here && here <= buffer_->end); + here_ = here; + return *this; + } + + // Return the number of bytes available to read at the cursor. + size_t Available() const { return size_t(buffer_->end - here_); } + + // Return true if this cursor is at the end of its buffer. + bool AtEnd() const { return Available() == 0; } + + // When used as a boolean value this cursor converts to true if all + // prior reads have been completed, or false if we ran off the end + // of the buffer. + operator bool() const { return complete_; } + + // Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true, + // unsigned otherwise, using the cursor's established endianness, and set + // *RESULT to the number. If we read off the end of our buffer, clear + // this cursor's complete_ flag, and store a dummy value in *RESULT. + // Return a reference to this cursor. + template + ByteCursor &Read(size_t size, bool is_signed, T *result) { + if (CheckAvailable(size)) { + T v = 0; + if (big_endian_) { + for (size_t i = 0; i < size; i++) + v = (v << 8) + here_[i]; + } else { + // This loop condition looks weird, but size_t is unsigned, so + // decrementing i after it is zero yields the largest size_t value. + for (size_t i = size - 1; i < size; i--) + v = (v << 8) + here_[i]; + } + if (is_signed && size < sizeof(T)) { + size_t sign_bit = (T)1 << (size * 8 - 1); + v = (v ^ sign_bit) - sign_bit; + } + here_ += size; + *result = v; + } else { + *result = (T) 0xdeadbeef; + } + return *this; + } + + // Read an integer, using the cursor's established endianness and + // *RESULT's size and signedness, and set *RESULT to the number. If we + // read off the end of our buffer, clear this cursor's complete_ flag. + // Return a reference to this cursor. + template + ByteCursor &operator>>(T &result) { + bool T_is_signed = (T)-1 < 0; + return Read(sizeof(T), T_is_signed, &result); + } + + // Copy the SIZE bytes at the cursor to BUFFER, and advance this + // cursor to the end of them. If we read off the end of our buffer, + // clear this cursor's complete_ flag, and set *POINTER to NULL. + // Return a reference to this cursor. + ByteCursor &Read(uint8_t *buffer, size_t size) { + if (CheckAvailable(size)) { + memcpy(buffer, here_, size); + here_ += size; + } + return *this; + } + + // Set STR to a copy of the '\0'-terminated string at the cursor. If the + // byte buffer does not contain a terminating zero, clear this cursor's + // complete_ flag, and set STR to the empty string. Return a reference to + // this cursor. + ByteCursor &CString(string *str) { + const uint8_t *end + = static_cast(memchr(here_, '\0', Available())); + if (end) { + str->assign(reinterpret_cast(here_), end - here_); + here_ = end + 1; + } else { + str->clear(); + here_ = buffer_->end; + complete_ = false; + } + return *this; + } + + // Like CString(STR), but extract the string from a fixed-width buffer + // LIMIT bytes long, which may or may not contain a terminating '\0' + // byte. Specifically: + // + // - If there are not LIMIT bytes available at the cursor, clear the + // cursor's complete_ flag and set STR to the empty string. + // + // - Otherwise, if the LIMIT bytes at the cursor contain any '\0' + // characters, set *STR to a copy of the bytes before the first '\0', + // and advance the cursor by LIMIT bytes. + // + // - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the + // cursor by LIMIT bytes. + ByteCursor &CString(string *str, size_t limit) { + if (CheckAvailable(limit)) { + const uint8_t *end + = static_cast(memchr(here_, '\0', limit)); + if (end) + str->assign(reinterpret_cast(here_), end - here_); + else + str->assign(reinterpret_cast(here_), limit); + here_ += limit; + } else { + str->clear(); + } + return *this; + } + + // Set *POINTER to point to the SIZE bytes at the cursor, and advance + // this cursor to the end of them. If SIZE is omitted, don't move the + // cursor. If we read off the end of our buffer, clear this cursor's + // complete_ flag, and set *POINTER to NULL. Return a reference to this + // cursor. + ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) { + if (CheckAvailable(size)) { + *pointer = here_; + here_ += size; + } else { + *pointer = NULL; + } + return *this; + } + + // Skip SIZE bytes at the cursor. If doing so would advance us off + // the end of our buffer, clear this cursor's complete_ flag, and + // set *POINTER to NULL. Return a reference to this cursor. + ByteCursor &Skip(size_t size) { + if (CheckAvailable(size)) + here_ += size; + return *this; + } + + private: + // If there are at least SIZE bytes available to read from the buffer, + // return true. Otherwise, set here_ to the end of the buffer, set + // complete_ to false, and return false. + bool CheckAvailable(size_t size) { + if (Available() >= size) { + return true; + } else { + here_ = buffer_->end; + complete_ = false; + return false; + } + } + + // The buffer we're reading bytes from. + const ByteBuffer *buffer_; + + // The next byte within buffer_ that we'll read. + const uint8_t *here_; + + // True if we should read numbers in big-endian form; false if we + // should read in little-endian form. + bool big_endian_; + + // True if we've been able to read all we've been asked to. + bool complete_; +}; + +} // namespace google_breakpad + +#endif // COMMON_BYTE_CURSOR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc new file mode 100644 index 0000000000..06bfd89d73 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc @@ -0,0 +1,776 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer +// and google_breakpad::ByteCursor. + +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/byte_cursor.h" +#include "common/using_std_string.h" + +using google_breakpad::ByteBuffer; +using google_breakpad::ByteCursor; + +TEST(Buffer, SizeOfNothing) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + EXPECT_EQ(0U, buffer.Size()); +} + +TEST(Buffer, SizeOfSomething) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + EXPECT_EQ(10U, buffer.Size()); +} + +TEST(Extent, AvailableEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_EQ(0U, cursor.Available()); +} + +TEST(Extent, AtEndEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor.AtEnd()); +} + +TEST(Extent, AsBoolEmpty) { + uint8_t data[1]; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor); +} + +TEST(Extent, AvailableSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_EQ(10U, cursor.Available()); +} + +TEST(Extent, AtEndSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_FALSE(cursor.AtEnd()); + EXPECT_TRUE(cursor.Skip(sizeof(data)).AtEnd()); +} + +TEST(Extent, AsBoolSome) { + uint8_t data[10]; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + EXPECT_TRUE(cursor); + EXPECT_TRUE(cursor.Skip(sizeof(data))); + EXPECT_FALSE(cursor.Skip(1)); +} + +TEST(Extent, Cursor) { + uint8_t data[] = { 0xf7, + 0x9f, 0xbe, + 0x67, 0xfb, 0xd3, 0x58, + 0x6f, 0x36, 0xde, 0xd1, + 0x2a, 0x2a, 0x2a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t a; + uint16_t b; + uint32_t c; + uint32_t d; + uint8_t stars[3]; + + EXPECT_EQ(data + 0U, cursor.here()); + + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(data + 1U, cursor.here()); + + EXPECT_TRUE(cursor >> b); + EXPECT_EQ(data + 3U, cursor.here()); + + EXPECT_TRUE(cursor >> c); + EXPECT_EQ(data + 7U, cursor.here()); + + EXPECT_TRUE(cursor.Skip(4)); + EXPECT_EQ(data + 11U, cursor.here()); + + EXPECT_TRUE(cursor.Read(stars, 3)); + EXPECT_EQ(data + 14U, cursor.here()); + + EXPECT_FALSE(cursor >> d); + EXPECT_EQ(data + 14U, cursor.here()); +} + +TEST(Extent, SetOffset) { + uint8_t data[] = { 0x5c, 0x79, 0x8c, 0xd5 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t a, b, c, d, e; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0x5cU, a); + EXPECT_EQ(data + 1U, cursor.here()); + EXPECT_TRUE(((cursor >> b).set_here(data + 3) >> c).set_here(data + 1) + >> d >> e); + EXPECT_EQ(0x79U, b); + EXPECT_EQ(0xd5U, c); + EXPECT_EQ(0x79U, d); + EXPECT_EQ(0x8cU, e); + EXPECT_EQ(data + 3U, cursor.here()); +} + +TEST(BigEndian, Signed1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, true, &a) + .Read(1, true, &b) + .Read(1, true, &c) + .Read(1, true, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(-0x80, c); + EXPECT_EQ(-1, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, true, &e)); +} + +TEST(BigEndian, Signed2) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, + 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, + 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, true, &a) + .Read(2, true, &b) + .Read(2, true, &c) + .Read(2, true, &d) + .Read(2, true, &e) + .Read(2, true, &f) + .Read(2, true, &g) + .Read(2, true, &h) + .Read(2, true, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(-0x8000, d); + EXPECT_EQ(-0x7f80, e); + EXPECT_EQ(-1, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(-0x7544, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, true, &j)); +} + +TEST(BigEndian, Signed4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0xb6, 0xb1, 0xff, 0xef, + 0x19, 0x6a, 0xca, 0x46 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, true, &a) + .Read(4, true, &b) + .Read(4, true, &c) + .Read(4, true, &d) + .Read(4, true, &e) + .Read(4, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(-0x80000000LL, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int32_t) 0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, true, &g)); +} + +TEST(BigEndian, Signed8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, + 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, true, &a) + .Read(8, true, &b) + .Read(8, true, &c) + .Read(8, true, &d) + .Read(8, true, &e) + .Read(8, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffffffffffffLL, b); + EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4LL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, true, &g)); +} + +TEST(BigEndian, Unsigned1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, false, &a) + .Read(1, false, &b) + .Read(1, false, &c) + .Read(1, false, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(0x80, c); + EXPECT_EQ(0xff, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, false, &e)); +} + +TEST(BigEndian, Unsigned2) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, + 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, + 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + int64_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, false, &a) + .Read(2, false, &b) + .Read(2, false, &c) + .Read(2, false, &d) + .Read(2, false, &e) + .Read(2, false, &f) + .Read(2, false, &g) + .Read(2, false, &h) + .Read(2, false, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(0x8000, d); + EXPECT_EQ(0x8080, e); + EXPECT_EQ(0xffff, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(0x8abc, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, false, &j)); +} + +TEST(BigEndian, Unsigned4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + 0xb6, 0xb1, 0xff, 0xef, + 0x19, 0x6a, 0xca, 0x46 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, false, &a) + .Read(4, false, &b) + .Read(4, false, &c) + .Read(4, false, &d) + .Read(4, false, &e) + .Read(4, false, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(0x80000000, c); + EXPECT_EQ(0xffffffff, d); + EXPECT_EQ(0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, false, &g)); +} + +TEST(BigEndian, Unsigned8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, + 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, true); + uint64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, false, &a) + .Read(8, false, &b) + .Read(8, false, &c) + .Read(8, false, &d) + .Read(8, false, &e) + .Read(8, false, &f)); + EXPECT_EQ(0U, a); + EXPECT_EQ(0x7fffffffffffffffULL, b); + EXPECT_EQ(0x8000000000000000ULL, c); + EXPECT_EQ(0xffffffffffffffffULL, d); + EXPECT_EQ(0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4ULL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, false, &g)); +} + +TEST(LittleEndian, Signed1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, true, &a) + .Read(1, true, &b) + .Read(1, true, &c) + .Read(1, true, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(-0x80, c); + EXPECT_EQ(-1, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, true, &e)); +} + +TEST(LittleEndian, Signed2) { + uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, + 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, + 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, false); + int32_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, true, &a) + .Read(2, true, &b) + .Read(2, true, &c) + .Read(2, true, &d) + .Read(2, true, &e) + .Read(2, true, &f) + .Read(2, true, &g) + .Read(2, true, &h) + .Read(2, true, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(-0x8000, d); + EXPECT_EQ(-0x7f80, e); + EXPECT_EQ(-1, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(-0x7544, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, true, &j)); +} + +TEST(LittleEndian, Signed4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xb1, 0xb6, + 0x46, 0xca, 0x6a, 0x19 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, true, &a) + .Read(4, true, &b) + .Read(4, true, &c) + .Read(4, true, &d) + .Read(4, true, &e) + .Read(4, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(-0x80000000LL, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int32_t) 0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, true, &g)); +} + +TEST(LittleEndian, Signed8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, + 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer, false); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, true, &a) + .Read(8, true, &b) + .Read(8, true, &c) + .Read(8, true, &d) + .Read(8, true, &e) + .Read(8, true, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffffffffffffLL, b); + EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); + EXPECT_EQ(-1, d); + EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4LL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, true, &g)); +} + +TEST(LittleEndian, Unsigned1) { + uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e; + ASSERT_TRUE(cursor + .Read(1, false, &a) + .Read(1, false, &b) + .Read(1, false, &c) + .Read(1, false, &d)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7f, b); + EXPECT_EQ(0x80, c); + EXPECT_EQ(0xff, d); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(1, false, &e)); +} + +TEST(LittleEndian, Unsigned2) { + uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, + 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, + 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a, b, c, d, e, f, g, h, i, j; + ASSERT_TRUE(cursor + .Read(2, false, &a) + .Read(2, false, &b) + .Read(2, false, &c) + .Read(2, false, &d) + .Read(2, false, &e) + .Read(2, false, &f) + .Read(2, false, &g) + .Read(2, false, &h) + .Read(2, false, &i)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x80, b); + EXPECT_EQ(0x7fff, c); + EXPECT_EQ(0x8000, d); + EXPECT_EQ(0x8080, e); + EXPECT_EQ(0xffff, f); + EXPECT_EQ(0x39f1, g); + EXPECT_EQ(0x8abc, h); + EXPECT_EQ(0x5aec, i); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(2, false, &j)); +} + +TEST(LittleEndian, Unsigned4) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, + 0xef, 0xff, 0xb1, 0xb6, + 0x46, 0xca, 0x6a, 0x19 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(4, false, &a) + .Read(4, false, &b) + .Read(4, false, &c) + .Read(4, false, &d) + .Read(4, false, &e) + .Read(4, false, &f)); + EXPECT_EQ(0, a); + EXPECT_EQ(0x7fffffff, b); + EXPECT_EQ(0x80000000, c); + EXPECT_EQ(0xffffffff, d); + EXPECT_EQ(0xb6b1ffef, e); + EXPECT_EQ(0x196aca46, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(4, false, &g)); +} + +TEST(LittleEndian, Unsigned8) { + uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, + 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint64_t a, b, c, d, e, f, g; + ASSERT_TRUE(cursor + .Read(8, false, &a) + .Read(8, false, &b) + .Read(8, false, &c) + .Read(8, false, &d) + .Read(8, false, &e) + .Read(8, false, &f)); + EXPECT_EQ(0U, a); + EXPECT_EQ(0x7fffffffffffffffULL, b); + EXPECT_EQ(0x8000000000000000ULL, c); + EXPECT_EQ(0xffffffffffffffffULL, d); + EXPECT_EQ(0x9320d5e9d2d5879cULL, e); + EXPECT_EQ(0x4e4249d27f8414a4ULL, f); + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor.Read(8, false, &g)); +} + +TEST(Extractor, Signed1) { + uint8_t data[] = { 0xfd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int8_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-3, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Signed2) { + uint8_t data[] = { 0x13, 0xcd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int16_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-13037, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Signed4) { + uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + int32_t a; + // For some reason, G++ 4.4.1 complains: + // warning: array subscript is above array bounds + // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // I'm not able to see how such a reference would occur. + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(-380377902, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned1) { + uint8_t data[] = { 0xfd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint8_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xfd, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned2) { + uint8_t data[] = { 0x13, 0xcd }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint16_t a; + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xcd13, a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Unsigned4) { + uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + uint32_t a; + // For some reason, G++ 4.4.1 complains: + // warning: array subscript is above array bounds + // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but + // I'm not able to see how such a reference would occur. + EXPECT_TRUE(cursor >> a); + EXPECT_EQ(0xe953e4d2, a); + EXPECT_FALSE(cursor >> a); + EXPECT_FALSE(cursor >> a); +} + +TEST(Extractor, Mixed) { + uint8_t data[] = { 0x42, + 0x25, 0x0b, + 0x3d, 0x25, 0xed, 0x2a, + 0xec, 0x16, 0x9e, 0x14, 0x61, 0x5b, 0x2c, 0xcf, + 0xd8, + 0x22, 0xa5, + 0x3a, 0x02, 0x6a, 0xd7, + 0x93, 0x2a, 0x2d, 0x8d, 0xb4, 0x95, 0xe0, 0xc6 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + cursor.set_big_endian(true); + + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; + int z; + EXPECT_FALSE(cursor.AtEnd()); + EXPECT_TRUE(cursor >> a >> b >> c >> d >> e >> f >> g >> h); + EXPECT_EQ(0x42U, a); + EXPECT_EQ(0x250bU, b); + EXPECT_EQ(0x3d25ed2aU, c); + EXPECT_EQ(0xec169e14615b2ccfULL, d); + EXPECT_EQ(-40, e); + EXPECT_EQ(0x22a5, f); + EXPECT_EQ(0x3a026ad7, g); + EXPECT_EQ(-7842405714468937530LL, h); + + EXPECT_TRUE(cursor.AtEnd()); + EXPECT_FALSE(cursor >> z); +} + +TEST(Strings, Zero) { + uint8_t data[] = { 0xa6 }; + ByteBuffer buffer(data, 0); + ByteCursor cursor(&buffer); + + uint8_t received[1]; + received[0] = 0xc2; + EXPECT_TRUE(cursor.Read(received, 0)); + EXPECT_EQ(0xc2U, received[0]); +} + +TEST(Strings, Some) { + uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t received[7] = { 0xa7, 0xf7, 0x43, 0x0c, 0x27, 0xea, 0xed }; + EXPECT_TRUE(cursor.Skip(2).Read(received, 5)); + uint8_t expected[7] = { 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xea, 0xed }; + EXPECT_TRUE(memcmp(received, expected, 7) == 0); +} + +TEST(Strings, TooMuch) { + uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + uint8_t received1[3]; + uint8_t received2[3]; + uint8_t received3[3]; + EXPECT_FALSE(cursor + .Read(received1, 3) + .Read(received2, 3) + .Read(received3, 3)); + uint8_t expected1[3] = { 0x5d, 0x31, 0x09 }; + uint8_t expected2[3] = { 0xa6, 0x2e, 0x2c }; + + EXPECT_TRUE(memcmp(received1, expected1, 3) == 0); + EXPECT_TRUE(memcmp(received2, expected2, 3) == 0); +} + +TEST(Strings, PointTo) { + uint8_t data[] = { 0x83, 0x80, 0xb4, 0x38, 0x00, 0x2c, 0x0a, 0x27 }; + ByteBuffer buffer(data, sizeof(data)); + ByteCursor cursor(&buffer); + + const uint8_t *received1; + const uint8_t *received2; + const uint8_t *received3; + const uint8_t *received4; + EXPECT_FALSE(cursor + .PointTo(&received1, 3) + .PointTo(&received2, 3) + .PointTo(&received3) + .PointTo(&received4, 3)); + EXPECT_EQ(data + 0, received1); + EXPECT_EQ(data + 3, received2); + EXPECT_EQ(data + 6, received3); + EXPECT_EQ(NULL, received4); +} + +TEST(Strings, CString) { + uint8_t data[] = "abc\0\0foo"; + ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' + ByteCursor cursor(&buffer); + + string a, b, c; + EXPECT_TRUE(cursor.CString(&a).CString(&b)); + EXPECT_EQ("abc", a); + EXPECT_EQ("", b); + EXPECT_FALSE(cursor.CString(&c)); + EXPECT_EQ("", c); + EXPECT_TRUE(cursor.AtEnd()); +} + +TEST(Strings, CStringLimit) { + uint8_t data[] = "abcdef\0\0foobar"; + ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' + ByteCursor cursor(&buffer); + + string a, b, c, d, e; + + EXPECT_TRUE(cursor.CString(&a, 3)); + EXPECT_EQ("abc", a); + + EXPECT_TRUE(cursor.CString(&b, 0)); + EXPECT_EQ("", b); + + EXPECT_TRUE(cursor.CString(&c, 6)); + EXPECT_EQ("def", c); + + EXPECT_TRUE(cursor.CString(&d, 4)); + EXPECT_EQ("ooba", d); + + EXPECT_FALSE(cursor.CString(&e, 4)); + EXPECT_EQ("", e); + + EXPECT_TRUE(cursor.AtEnd()); +} + +// uint8_t data[] = { 0xa6, 0x54, 0xdf, 0x67, 0x51, 0x43, 0xac, 0xf1 }; +// ByteBuffer buffer(data, sizeof(data)); diff --git a/toolkit/crashreporter/google-breakpad/src/common/common.gyp b/toolkit/crashreporter/google-breakpad/src/common/common.gyp new file mode 100644 index 0000000000..c1dbb0febf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/common.gyp @@ -0,0 +1,260 @@ +# Copyright 2014 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. + +{ + 'target_defaults': { + 'target_conditions': [ + ['OS=="mac"', { + 'defines': ['HAVE_MACH_O_NLIST_H'], + }], + ['OS=="linux"', { + # Assume glibc. + 'defines': ['HAVE_A_OUT_H', 'HAVE_GETCONTEXT'], + 'sources!': [ + 'linux/breakpad_getcontext.S', + 'linux/breakpad_getcontext.h', + 'linux/breakpad_getcontext_unittest.cc', + ], + }], + ['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}], + ['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}], + ['OS!="mac"', {'sources/': [['exclude', '(^|/)mac/']]}], + ['OS!="solaris"', {'sources/': [['exclude', '(^|/)solaris/']]}], + ['OS!="win"', {'sources/': [['exclude', '(^|/)windows/']]}], + ], + }, + 'targets': [ + { + 'target_name': 'common', + 'type': 'static_library', + 'sources': [ + 'android/include/elf.h', + 'android/include/link.h', + 'android/include/stab.h', + 'android/include/sys/procfs.h', + 'android/include/sys/user.h', + 'android/testing/include/wchar.h', + 'android/testing/mkdtemp.h', + 'android/testing/pthread_fixes.h', + 'android/ucontext_constants.h', + 'basictypes.h', + 'byte_cursor.h', + 'convert_UTF.cc', + 'convert_UTF.h', + 'dwarf/bytereader-inl.h', + 'dwarf/bytereader.cc', + 'dwarf/bytereader.h', + 'dwarf/cfi_assembler.cc', + 'dwarf/cfi_assembler.h', + 'dwarf/dwarf2diehandler.cc', + 'dwarf/dwarf2diehandler.h', + 'dwarf/dwarf2enums.h', + 'dwarf/dwarf2reader.cc', + 'dwarf/dwarf2reader.h', + 'dwarf/dwarf2reader_test_common.h', + 'dwarf/elf_reader.cc', + 'dwarf/elf_reader.h', + 'dwarf/functioninfo.cc', + 'dwarf/functioninfo.h', + 'dwarf/line_state_machine.h', + 'dwarf/types.h', + 'dwarf_cfi_to_module.cc', + 'dwarf_cfi_to_module.h', + 'dwarf_cu_to_module.cc', + 'dwarf_cu_to_module.h', + 'dwarf_line_to_module.cc', + 'dwarf_line_to_module.h', + 'language.cc', + 'language.h', + 'linux/breakpad_getcontext.S', + 'linux/breakpad_getcontext.h', + 'linux/crc32.cc', + 'linux/crc32.h', + 'linux/dump_symbols.cc', + 'linux/dump_symbols.h', + 'linux/eintr_wrapper.h', + 'linux/elf_core_dump.cc', + 'linux/elf_core_dump.h', + 'linux/elf_gnu_compat.h', + 'linux/elf_symbols_to_module.cc', + 'linux/elf_symbols_to_module.h', + 'linux/elfutils-inl.h', + 'linux/elfutils.cc', + 'linux/elfutils.h', + 'linux/file_id.cc', + 'linux/file_id.h', + 'linux/google_crashdump_uploader.cc', + 'linux/google_crashdump_uploader.h', + 'linux/guid_creator.cc', + 'linux/guid_creator.h', + 'linux/http_upload.cc', + 'linux/http_upload.h', + 'linux/ignore_ret.h', + 'linux/libcurl_wrapper.cc', + 'linux/libcurl_wrapper.h', + 'linux/linux_libc_support.cc', + 'linux/linux_libc_support.h', + 'linux/memory_mapped_file.cc', + 'linux/memory_mapped_file.h', + 'linux/safe_readlink.cc', + 'linux/safe_readlink.h', + 'linux/symbol_collector_client.cc', + 'linux/symbol_collector_client.h', + 'linux/synth_elf.cc', + 'linux/synth_elf.h', + 'long_string_dictionary.cc', + 'long_string_dictionary.h', + 'mac/arch_utilities.cc', + 'mac/arch_utilities.h', + 'mac/bootstrap_compat.cc', + 'mac/bootstrap_compat.h', + 'mac/byteswap.h', + 'mac/dump_syms.h', + 'mac/dump_syms.cc', + 'mac/file_id.cc', + 'mac/file_id.h', + 'mac/GTMDefines.h', + 'mac/GTMLogger.h', + 'mac/GTMLogger.m', + 'mac/HTTPMultipartUpload.h', + 'mac/HTTPMultipartUpload.m', + 'mac/MachIPC.h', + 'mac/MachIPC.mm', + 'mac/macho_id.cc', + 'mac/macho_id.h', + 'mac/macho_reader.cc', + 'mac/macho_reader.h', + 'mac/macho_utilities.cc', + 'mac/macho_utilities.h', + 'mac/macho_walker.cc', + 'mac/macho_walker.h', + 'mac/scoped_task_suspend-inl.h', + 'mac/string_utilities.cc', + 'mac/string_utilities.h', + 'mac/super_fat_arch.h', + 'md5.cc', + 'md5.h', + 'memory_allocator.h', + 'memory_range.h', + 'module.cc', + 'module.h', + 'scoped_ptr.h', + 'simple_string_dictionary.cc', + 'simple_string_dictionary.h', + 'solaris/dump_symbols.cc', + 'solaris/dump_symbols.h', + 'solaris/file_id.cc', + 'solaris/file_id.h', + 'solaris/guid_creator.cc', + 'solaris/guid_creator.h', + 'solaris/message_output.h', + 'stabs_reader.cc', + 'stabs_reader.h', + 'stabs_to_module.cc', + 'stabs_to_module.h', + 'string_conversion.cc', + 'string_conversion.h', + 'symbol_data.h', + 'test_assembler.cc', + 'test_assembler.h', + 'unordered.h', + 'using_std_string.h', + 'windows/common_windows.gyp', + 'windows/dia_util.cc', + 'windows/dia_util.h', + 'windows/guid_string.cc', + 'windows/guid_string.h', + 'windows/http_upload.cc', + 'windows/http_upload.h', + 'windows/omap.cc', + 'windows/omap.h', + 'windows/omap_internal.h', + 'windows/pdb_source_line_writer.cc', + 'windows/pdb_source_line_writer.h', + 'windows/string_utils-inl.h', + 'windows/string_utils.cc', + ], + 'include_dirs': [ + '..', + ], + }, + { + 'target_name': 'common_unittests', + 'type': 'executable', + 'sources': [ + 'byte_cursor_unittest.cc', + 'dwarf/bytereader_unittest.cc', + 'dwarf/dwarf2diehandler_unittest.cc', + 'dwarf/dwarf2reader_cfi_unittest.cc', + 'dwarf/dwarf2reader_die_unittest.cc', + 'dwarf_cfi_to_module_unittest.cc', + 'dwarf_cu_to_module_unittest.cc', + 'dwarf_line_to_module_unittest.cc', + 'linux/breakpad_getcontext_unittest.cc', + 'linux/dump_symbols_unittest.cc', + 'linux/elf_core_dump_unittest.cc', + 'linux/elf_symbols_to_module_unittest.cc', + 'linux/file_id_unittest.cc', + 'linux/google_crashdump_uploader_test.cc', + 'linux/linux_libc_support_unittest.cc', + 'linux/memory_mapped_file_unittest.cc', + 'linux/safe_readlink_unittest.cc', + 'linux/synth_elf_unittest.cc', + 'linux/tests/auto_testfile.h', + 'linux/tests/crash_generator.cc', + 'linux/tests/crash_generator.h', + 'long_string_dictionary_unittest.cc', + 'mac/macho_reader_unittest.cc', + 'memory_allocator_unittest.cc', + 'memory_range_unittest.cc', + 'module_unittest.cc', + 'simple_string_dictionary_unittest.cc', + 'stabs_reader_unittest.cc', + 'stabs_to_module_unittest.cc', + 'string_conversion_unittest.cc', + 'test_assembler_unittest.cc', + 'tests/auto_tempdir.h', + 'tests/file_utils.cc', + 'tests/file_utils.h', + 'windows/omap_unittest.cc', + ], + 'include_dirs': [ + '..', + ], + 'dependencies': [ + 'common', + '../build/testing.gyp:gmock_main', + '../build/testing.gyp:gmock', + '../build/testing.gyp:gtest', + ], + 'libraries': [ + '-ldl', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.cc b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.cc new file mode 100644 index 0000000000..4a5df1eb27 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.cc @@ -0,0 +1,591 @@ +/* + * Copyright © 1991-2015 Unicode, Inc. All rights reserved. + * Distributed under the Terms of Use in + * http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Unicode data files and any associated documentation + * (the "Data Files") or Unicode software and any associated documentation + * (the "Software") to deal in the Data Files or Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, and/or sell copies of + * the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that + * (a) this copyright and permission notice appear with all copies + * of the Data Files or Software, + * (b) this copyright and permission notice appear in associated + * documentation, and + * (c) there is clear notice in each modified Data File or in the Software + * as well as in the documentation associated with the Data File(s) or + * Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS + * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL + * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in these Data Files or Software without prior + * written authorization of the copyright holder. + */ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Source code file. +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Sept 2001: fixed const & error conditions per +mods suggested by S. Parent & A. Lillich. +June 2002: Tim Dodd added detection and handling of incomplete +source sequences, enhanced error detection, added casts +to eliminate compiler warnings. +July 2003: slight mods to back out aggressive FFFE detection. +Jan 2004: updated switches in from-UTF8 conversions. +Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + +See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "convert_UTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +#include "common/macros.h" + +namespace google_breakpad { + +namespace { + +const int halfShift = 10; /* used for shifting by 10 bits */ + +const UTF32 halfBase = 0x0010000UL; +const UTF32 halfMask = 0x3FFUL; + +} // namespace + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG + if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); + } +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +namespace { + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. +* Constants have been gathered. Loops & conditionals have been removed as +* much as possible for efficiency, in favor of drop-through switches. +* (See "Note A" at the bottom of the file for equivalent code.) +* If your compiler supports it, the "isLegalUTF8" call can be turned +* into an inline function. +*/ + +} // namespace + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 3: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 2: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 1: + *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +namespace { + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ +Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + BP_FALLTHROUGH; + case 3: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + BP_FALLTHROUGH; + case 2: + if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + BP_FALLTHROUGH; + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +} // namespace + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + /* remember, illegal UTF-8 */ + case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 3: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 2: + *--target = (UTF8)((ch | byteMark) & byteMask); + ch >>= 6; + BP_FALLTHROUGH; + case 1: + *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + +Note A. +The fall-through switches in UTF-8 reading code save a +temp variable, some decrements & conditionals. The switches +are equivalent to the following loop: +{ + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); +} +In UTF-8 writing code, the switches on "bytesToWrite" are +similarly unrolled loops. + +--------------------------------------------------------------------- */ + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h new file mode 100644 index 0000000000..2f69495d24 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h @@ -0,0 +1,159 @@ +/* + * Copyright © 1991-2015 Unicode, Inc. All rights reserved. + * Distributed under the Terms of Use in + * http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Unicode data files and any associated documentation + * (the "Data Files") or Unicode software and any associated documentation + * (the "Software") to deal in the Data Files or Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, and/or sell copies of + * the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that + * (a) this copyright and permission notice appear with all copies + * of the Data Files or Software, + * (b) this copyright and permission notice appear in associated + * documentation, and + * (c) there is clear notice in each modified Data File or in the Software + * as well as in the documentation associated with the Data File(s) or + * Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS + * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL + * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in these Data Files or Software without prior + * written authorization of the copyright holder. + */ + +#ifndef COMMON_CONVERT_UTF_H_ +#define COMMON_CONVERT_UTF_H_ + +/* --------------------------------------------------------------------- + +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: , , +or 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. +------------------------------------------------------------------------ */ + +namespace google_breakpad { + +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; + +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); + +} // namespace google_breakpad + +/* --------------------------------------------------------------------- */ + +#endif // COMMON_CONVERT_UTF_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h new file mode 100644 index 0000000000..42c92f943f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h @@ -0,0 +1,170 @@ +// Copyright 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 UTIL_DEBUGINFO_BYTEREADER_INL_H__ +#define UTIL_DEBUGINFO_BYTEREADER_INL_H__ + +#include "common/dwarf/bytereader.h" + +#include +#include + +namespace dwarf2reader { + +inline uint8 ByteReader::ReadOneByte(const uint8_t *buffer) const { + return buffer[0]; +} + +inline uint16 ByteReader::ReadTwoBytes(const uint8_t *buffer) const { + const uint16 buffer0 = buffer[0]; + const uint16 buffer1 = buffer[1]; + if (endian_ == ENDIANNESS_LITTLE) { + return buffer0 | buffer1 << 8; + } else { + return buffer1 | buffer0 << 8; + } +} + +inline uint64 ByteReader::ReadFourBytes(const uint8_t *buffer) const { + const uint32 buffer0 = buffer[0]; + const uint32 buffer1 = buffer[1]; + const uint32 buffer2 = buffer[2]; + const uint32 buffer3 = buffer[3]; + if (endian_ == ENDIANNESS_LITTLE) { + return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24; + } else { + return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24; + } +} + +inline uint64 ByteReader::ReadEightBytes(const uint8_t *buffer) const { + const uint64 buffer0 = buffer[0]; + const uint64 buffer1 = buffer[1]; + const uint64 buffer2 = buffer[2]; + const uint64 buffer3 = buffer[3]; + const uint64 buffer4 = buffer[4]; + const uint64 buffer5 = buffer[5]; + const uint64 buffer6 = buffer[6]; + const uint64 buffer7 = buffer[7]; + if (endian_ == ENDIANNESS_LITTLE) { + return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 | + buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56; + } else { + return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 | + buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56; + } +} + +// Read an unsigned LEB128 number. Each byte contains 7 bits of +// information, plus one bit saying whether the number continues or +// not. + +inline uint64 ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, + size_t* len) const { + uint64 result = 0; + size_t num_read = 0; + unsigned int shift = 0; + uint8_t byte; + + do { + byte = *buffer++; + num_read++; + + result |= (static_cast(byte & 0x7f)) << shift; + + shift += 7; + + } while (byte & 0x80); + + *len = num_read; + + return result; +} + +// Read a signed LEB128 number. These are like regular LEB128 +// numbers, except the last byte may have a sign bit set. + +inline int64 ByteReader::ReadSignedLEB128(const uint8_t *buffer, + size_t* len) const { + int64 result = 0; + unsigned int shift = 0; + size_t num_read = 0; + uint8_t byte; + + do { + byte = *buffer++; + num_read++; + result |= (static_cast(byte & 0x7f) << shift); + shift += 7; + } while (byte & 0x80); + + if ((shift < 8 * sizeof (result)) && (byte & 0x40)) + result |= -((static_cast(1)) << shift); + *len = num_read; + return result; +} + +inline uint64 ByteReader::ReadOffset(const uint8_t *buffer) const { + assert(this->offset_reader_); + return (this->*offset_reader_)(buffer); +} + +inline uint64 ByteReader::ReadAddress(const uint8_t *buffer) const { + assert(this->address_reader_); + return (this->*address_reader_)(buffer); +} + +inline void ByteReader::SetCFIDataBase(uint64 section_base, + const uint8_t *buffer_base) { + section_base_ = section_base; + buffer_base_ = buffer_base; + have_section_base_ = true; +} + +inline void ByteReader::SetTextBase(uint64 text_base) { + text_base_ = text_base; + have_text_base_ = true; +} + +inline void ByteReader::SetDataBase(uint64 data_base) { + data_base_ = data_base; + have_data_base_ = true; +} + +inline void ByteReader::SetFunctionBase(uint64 function_base) { + function_base_ = function_base; + have_function_base_ = true; +} + +inline void ByteReader::ClearFunctionBase() { + have_function_base_ = false; +} + +} // namespace dwarf2reader + +#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc new file mode 100644 index 0000000000..14b43adb8f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc @@ -0,0 +1,250 @@ +// Copyright (c) 2010 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 +#include +#include + +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/bytereader.h" + +namespace dwarf2reader { + +ByteReader::ByteReader(enum Endianness endian) + :offset_reader_(NULL), address_reader_(NULL), endian_(endian), + address_size_(0), offset_size_(0), + have_section_base_(), have_text_base_(), have_data_base_(), + have_function_base_() { } + +ByteReader::~ByteReader() { } + +void ByteReader::SetOffsetSize(uint8 size) { + offset_size_ = size; + assert(size == 4 || size == 8); + if (size == 4) { + this->offset_reader_ = &ByteReader::ReadFourBytes; + } else { + this->offset_reader_ = &ByteReader::ReadEightBytes; + } +} + +void ByteReader::SetAddressSize(uint8 size) { + address_size_ = size; + assert(size == 4 || size == 8); + if (size == 4) { + this->address_reader_ = &ByteReader::ReadFourBytes; + } else { + this->address_reader_ = &ByteReader::ReadEightBytes; + } +} + +uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) { + const uint64 initial_length = ReadFourBytes(start); + start += 4; + + // In DWARF2/3, if the initial length is all 1 bits, then the offset + // size is 8 and we need to read the next 8 bytes for the real length. + if (initial_length == 0xffffffff) { + SetOffsetSize(8); + *len = 12; + return ReadOffset(start); + } else { + SetOffsetSize(4); + *len = 4; + } + return initial_length; +} + +bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const { + if (encoding == DW_EH_PE_omit) return true; + if (encoding == DW_EH_PE_aligned) return true; + if ((encoding & 0x7) > DW_EH_PE_udata8) + return false; + if ((encoding & 0x70) > DW_EH_PE_funcrel) + return false; + return true; +} + +bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const { + switch (encoding & 0x70) { + case DW_EH_PE_absptr: return true; + case DW_EH_PE_pcrel: return have_section_base_; + case DW_EH_PE_textrel: return have_text_base_; + case DW_EH_PE_datarel: return have_data_base_; + case DW_EH_PE_funcrel: return have_function_base_; + default: return false; + } +} + +uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer, + DwarfPointerEncoding encoding, + size_t *len) const { + // UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't + // see it here. + assert(encoding != DW_EH_PE_omit); + + // The Linux Standards Base 4.0 does not make this clear, but the + // GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c) + // agree that aligned pointers are always absolute, machine-sized, + // machine-signed pointers. + if (encoding == DW_EH_PE_aligned) { + assert(have_section_base_); + + // We don't need to align BUFFER in *our* address space. Rather, we + // need to find the next position in our buffer that would be aligned + // when the .eh_frame section the buffer contains is loaded into the + // program's memory. So align assuming that buffer_base_ gets loaded at + // address section_base_, where section_base_ itself may or may not be + // aligned. + + // First, find the offset to START from the closest prior aligned + // address. + uint64 skew = section_base_ & (AddressSize() - 1); + // Now find the offset from that aligned address to buffer. + uint64 offset = skew + (buffer - buffer_base_); + // Round up to the next boundary. + uint64 aligned = (offset + AddressSize() - 1) & -AddressSize(); + // Convert back to a pointer. + const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew); + // Finally, store the length and actually fetch the pointer. + *len = aligned_buffer - buffer + AddressSize(); + return ReadAddress(aligned_buffer); + } + + // Extract the value first, ignoring whether it's a pointer or an + // offset relative to some base. + uint64 offset; + switch (encoding & 0x0f) { + case DW_EH_PE_absptr: + // DW_EH_PE_absptr is weird, as it is used as a meaningful value for + // both the high and low nybble of encoding bytes. When it appears in + // the high nybble, it means that the pointer is absolute, not an + // offset from some base address. When it appears in the low nybble, + // as here, it means that the pointer is stored as a normal + // machine-sized and machine-signed address. A low nybble of + // DW_EH_PE_absptr does not imply that the pointer is absolute; it is + // correct for us to treat the value as an offset from a base address + // if the upper nybble is not DW_EH_PE_absptr. + offset = ReadAddress(buffer); + *len = AddressSize(); + break; + + case DW_EH_PE_uleb128: + offset = ReadUnsignedLEB128(buffer, len); + break; + + case DW_EH_PE_udata2: + offset = ReadTwoBytes(buffer); + *len = 2; + break; + + case DW_EH_PE_udata4: + offset = ReadFourBytes(buffer); + *len = 4; + break; + + case DW_EH_PE_udata8: + offset = ReadEightBytes(buffer); + *len = 8; + break; + + case DW_EH_PE_sleb128: + offset = ReadSignedLEB128(buffer, len); + break; + + case DW_EH_PE_sdata2: + offset = ReadTwoBytes(buffer); + // Sign-extend from 16 bits. + offset = (offset ^ 0x8000) - 0x8000; + *len = 2; + break; + + case DW_EH_PE_sdata4: + offset = ReadFourBytes(buffer); + // Sign-extend from 32 bits. + offset = (offset ^ 0x80000000ULL) - 0x80000000ULL; + *len = 4; + break; + + case DW_EH_PE_sdata8: + // No need to sign-extend; this is the full width of our type. + offset = ReadEightBytes(buffer); + *len = 8; + break; + + default: + abort(); + } + + // Find the appropriate base address. + uint64 base; + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + base = 0; + break; + + case DW_EH_PE_pcrel: + assert(have_section_base_); + base = section_base_ + (buffer - buffer_base_); + break; + + case DW_EH_PE_textrel: + assert(have_text_base_); + base = text_base_; + break; + + case DW_EH_PE_datarel: + assert(have_data_base_); + base = data_base_; + break; + + case DW_EH_PE_funcrel: + assert(have_function_base_); + base = function_base_; + break; + + default: + abort(); + } + + uint64 pointer = base + offset; + + // Remove inappropriate upper bits. + if (AddressSize() == 4) + pointer = pointer & 0xffffffff; + else + assert(AddressSize() == sizeof(uint64)); + + return pointer; +} + +Endianness ByteReader::GetEndianness() const { + return endian_; +} + +} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h new file mode 100644 index 0000000000..59d4303480 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h @@ -0,0 +1,315 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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 COMMON_DWARF_BYTEREADER_H__ +#define COMMON_DWARF_BYTEREADER_H__ + +#include + +#include + +#include "common/dwarf/types.h" +#include "common/dwarf/dwarf2enums.h" + +namespace dwarf2reader { + +// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN +// because it conflicts with a macro +enum Endianness { + ENDIANNESS_BIG, + ENDIANNESS_LITTLE +}; + +// A ByteReader knows how to read single- and multi-byte values of +// various endiannesses, sizes, and encodings, as used in DWARF +// debugging information and Linux C++ exception handling data. +class ByteReader { + public: + // Construct a ByteReader capable of reading one-, two-, four-, and + // eight-byte values according to ENDIANNESS, absolute machine-sized + // addresses, DWARF-style "initial length" values, signed and + // unsigned LEB128 numbers, and Linux C++ exception handling data's + // encoded pointers. + explicit ByteReader(enum Endianness endianness); + virtual ~ByteReader(); + + // Read a single byte from BUFFER and return it as an unsigned 8 bit + // number. + uint8 ReadOneByte(const uint8_t *buffer) const; + + // Read two bytes from BUFFER and return them as an unsigned 16 bit + // number, using this ByteReader's endianness. + uint16 ReadTwoBytes(const uint8_t *buffer) const; + + // Read four bytes from BUFFER and return them as an unsigned 32 bit + // number, using this ByteReader's endianness. This function returns + // a uint64 so that it is compatible with ReadAddress and + // ReadOffset. The number it returns will never be outside the range + // of an unsigned 32 bit integer. + uint64 ReadFourBytes(const uint8_t *buffer) const; + + // Read eight bytes from BUFFER and return them as an unsigned 64 + // bit number, using this ByteReader's endianness. + uint64 ReadEightBytes(const uint8_t *buffer) const; + + // Read an unsigned LEB128 (Little Endian Base 128) number from + // BUFFER and return it as an unsigned 64 bit integer. Set LEN to + // the number of bytes read. + // + // The unsigned LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between 0 and 0x7f, then its unsigned LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | + // 0x80, followed by the unsigned LEB128 representation of N / + // 128, rounded towards negative infinity. + // + // In other words, we break VALUE into groups of seven bits, put + // them in little-endian order, and then write them as eight-bit + // bytes with the high bit on all but the last. + uint64 ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const; + + // Read a signed LEB128 number from BUFFER and return it as an + // signed 64 bit integer. Set LEN to the number of bytes read. + // + // The signed LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between -0x40 and 0x3f, then its signed LEB128 + // representation is a single byte whose value is N in two's + // complement. + // + // - Otherwise, its signed LEB128 representation is (N & 0x7f) | + // 0x80, followed by the signed LEB128 representation of N / 128, + // rounded towards negative infinity. + // + // In other words, we break VALUE into groups of seven bits, put + // them in little-endian order, and then write them as eight-bit + // bytes with the high bit on all but the last. + int64 ReadSignedLEB128(const uint8_t *buffer, size_t *len) const; + + // Indicate that addresses on this architecture are SIZE bytes long. SIZE + // must be either 4 or 8. (DWARF allows addresses to be any number of + // bytes in length from 1 to 255, but we only support 32- and 64-bit + // addresses at the moment.) You must call this before using the + // ReadAddress member function. + // + // For data in a .debug_info section, or something that .debug_info + // refers to like line number or macro data, the compilation unit + // header's address_size field indicates the address size to use. Call + // frame information doesn't indicate its address size (a shortcoming of + // the spec); you must supply the appropriate size based on the + // architecture of the target machine. + void SetAddressSize(uint8 size); + + // Return the current address size, in bytes. This is either 4, + // indicating 32-bit addresses, or 8, indicating 64-bit addresses. + uint8 AddressSize() const { return address_size_; } + + // Read an address from BUFFER and return it as an unsigned 64 bit + // integer, respecting this ByteReader's endianness and address size. You + // must call SetAddressSize before calling this function. + uint64 ReadAddress(const uint8_t *buffer) const; + + // DWARF actually defines two slightly different formats: 32-bit DWARF + // and 64-bit DWARF. This is *not* related to the size of registers or + // addresses on the target machine; it refers only to the size of section + // offsets and data lengths appearing in the DWARF data. One only needs + // 64-bit DWARF when the debugging data itself is larger than 4GiB. + // 32-bit DWARF can handle x86_64 or PPC64 code just fine, unless the + // debugging data itself is very large. + // + // DWARF information identifies itself as 32-bit or 64-bit DWARF: each + // compilation unit and call frame information entry begins with an + // "initial length" field, which, in addition to giving the length of the + // data, also indicates the size of section offsets and lengths appearing + // in that data. The ReadInitialLength member function, below, reads an + // initial length and sets the ByteReader's offset size as a side effect. + // Thus, in the normal process of reading DWARF data, the appropriate + // offset size is set automatically. So, you should only need to call + // SetOffsetSize if you are using the same ByteReader to jump from the + // midst of one block of DWARF data into another. + + // Read a DWARF "initial length" field from START, and return it as + // an unsigned 64 bit integer, respecting this ByteReader's + // endianness. Set *LEN to the length of the initial length in + // bytes, either four or twelve. As a side effect, set this + // ByteReader's offset size to either 4 (if we see a 32-bit DWARF + // initial length) or 8 (if we see a 64-bit DWARF initial length). + // + // A DWARF initial length is either: + // + // - a byte count stored as an unsigned 32-bit value less than + // 0xffffff00, indicating that the data whose length is being + // measured uses the 32-bit DWARF format, or + // + // - The 32-bit value 0xffffffff, followed by a 64-bit byte count, + // indicating that the data whose length is being measured uses + // the 64-bit DWARF format. + uint64 ReadInitialLength(const uint8_t *start, size_t *len); + + // Read an offset from BUFFER and return it as an unsigned 64 bit + // integer, respecting the ByteReader's endianness. In 32-bit DWARF, the + // offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes + // long. You must call ReadInitialLength or SetOffsetSize before calling + // this function; see the comments above for details. + uint64 ReadOffset(const uint8_t *buffer) const; + + // Return the current offset size, in bytes. + // A return value of 4 indicates that we are reading 32-bit DWARF. + // A return value of 8 indicates that we are reading 64-bit DWARF. + uint8 OffsetSize() const { return offset_size_; } + + // Indicate that section offsets and lengths are SIZE bytes long. SIZE + // must be either 4 (meaning 32-bit DWARF) or 8 (meaning 64-bit DWARF). + // Usually, you should not call this function yourself; instead, let a + // call to ReadInitialLength establish the data's offset size + // automatically. + void SetOffsetSize(uint8 size); + + // The Linux C++ ABI uses a variant of DWARF call frame information + // for exception handling. This data is included in the program's + // address space as the ".eh_frame" section, and intepreted at + // runtime to walk the stack, find exception handlers, and run + // cleanup code. The format is mostly the same as DWARF CFI, with + // some adjustments made to provide the additional + // exception-handling data, and to make the data easier to work with + // in memory --- for example, to allow it to be placed in read-only + // memory even when describing position-independent code. + // + // In particular, exception handling data can select a number of + // different encodings for pointers that appear in the data, as + // described by the DwarfPointerEncoding enum. There are actually + // four axes(!) to the encoding: + // + // - The pointer size: pointers can be 2, 4, or 8 bytes long, or use + // the DWARF LEB128 encoding. + // + // - The pointer's signedness: pointers can be signed or unsigned. + // + // - The pointer's base address: the data stored in the exception + // handling data can be the actual address (that is, an absolute + // pointer), or relative to one of a number of different base + // addreses --- including that of the encoded pointer itself, for + // a form of "pc-relative" addressing. + // + // - The pointer may be indirect: it may be the address where the + // true pointer is stored. (This is used to refer to things via + // global offset table entries, program linkage table entries, or + // other tricks used in position-independent code.) + // + // There are also two options that fall outside that matrix + // altogether: the pointer may be omitted, or it may have padding to + // align it on an appropriate address boundary. (That last option + // may seem like it should be just another axis, but it is not.) + + // Indicate that the exception handling data is loaded starting at + // SECTION_BASE, and that the start of its buffer in our own memory + // is BUFFER_BASE. This allows us to find the address that a given + // byte in our buffer would have when loaded into the program the + // data describes. We need this to resolve DW_EH_PE_pcrel pointers. + void SetCFIDataBase(uint64 section_base, const uint8_t *buffer_base); + + // Indicate that the base address of the program's ".text" section + // is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers. + void SetTextBase(uint64 text_base); + + // Indicate that the base address for DW_EH_PE_datarel pointers is + // DATA_BASE. The proper value depends on the ABI; it is usually the + // address of the global offset table, held in a designated register in + // position-independent code. You will need to look at the startup code + // for the target system to be sure. I tried; my eyes bled. + void SetDataBase(uint64 data_base); + + // Indicate that the base address for the FDE we are processing is + // FUNCTION_BASE. This is the start address of DW_EH_PE_funcrel + // pointers. (This encoding does not seem to be used by the GNU + // toolchain.) + void SetFunctionBase(uint64 function_base); + + // Indicate that we are no longer processing any FDE, so any use of + // a DW_EH_PE_funcrel encoding is an error. + void ClearFunctionBase(); + + // Return true if ENCODING is a valid pointer encoding. + bool ValidEncoding(DwarfPointerEncoding encoding) const; + + // Return true if we have all the information we need to read a + // pointer that uses ENCODING. This checks that the appropriate + // SetFooBase function for ENCODING has been called. + bool UsableEncoding(DwarfPointerEncoding encoding) const; + + // Read an encoded pointer from BUFFER using ENCODING; return the + // absolute address it represents, and set *LEN to the pointer's + // length in bytes, including any padding for aligned pointers. + // + // This function calls 'abort' if ENCODING is invalid or refers to a + // base address this reader hasn't been given, so you should check + // with ValidEncoding and UsableEncoding first if you would rather + // die in a more helpful way. + uint64 ReadEncodedPointer(const uint8_t *buffer, + DwarfPointerEncoding encoding, + size_t *len) const; + + Endianness GetEndianness() const; + private: + + // Function pointer type for our address and offset readers. + typedef uint64 (ByteReader::*AddressReader)(const uint8_t *) const; + + // Read an offset from BUFFER and return it as an unsigned 64 bit + // integer. DWARF2/3 define offsets as either 4 or 8 bytes, + // generally depending on the amount of DWARF2/3 info present. + // This function pointer gets set by SetOffsetSize. + AddressReader offset_reader_; + + // Read an address from BUFFER and return it as an unsigned 64 bit + // integer. DWARF2/3 allow addresses to be any size from 0-255 + // bytes currently. Internally we support 4 and 8 byte addresses, + // and will CHECK on anything else. + // This function pointer gets set by SetAddressSize. + AddressReader address_reader_; + + Endianness endian_; + uint8 address_size_; + uint8 offset_size_; + + // Base addresses for Linux C++ exception handling data's encoded pointers. + bool have_section_base_, have_text_base_, have_data_base_; + bool have_function_base_; + uint64 section_base_, text_base_, data_base_, function_base_; + const uint8_t *buffer_base_; +}; + +} // namespace dwarf2reader + +#endif // COMMON_DWARF_BYTEREADER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc new file mode 100644 index 0000000000..e66062d1fe --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc @@ -0,0 +1,707 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader + +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/cfi_assembler.h" +#include "common/using_std_string.h" + +using dwarf2reader::ByteReader; +using dwarf2reader::DwarfPointerEncoding; +using dwarf2reader::ENDIANNESS_BIG; +using dwarf2reader::ENDIANNESS_LITTLE; +using google_breakpad::CFISection; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Section; +using testing::Test; + +struct ReaderFixture { + string contents; + size_t pointer_size; +}; + +class Reader: public ReaderFixture, public Test { }; +class ReaderDeathTest: public ReaderFixture, public Test { }; + +TEST_F(Reader, SimpleConstructor) { + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CFISection section(kBigEndian, 4); + section + .D8(0xc0) + .D16(0xcf0d) + .D32(0x96fdd219) + .D64(0xbbf55fef0825f117ULL) + .ULEB128(0xa0927048ba8121afULL) + .LEB128(-0x4f337badf4483f83LL) + .D32(0xfec319c9); + ASSERT_TRUE(section.GetContents(&contents)); + const uint8_t *data = reinterpret_cast(contents.data()); + EXPECT_EQ(0xc0U, reader.ReadOneByte(data)); + EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1)); + EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3)); + EXPECT_EQ(0xbbf55fef0825f117ULL, reader.ReadEightBytes(data + 7)); + size_t leb128_size; + EXPECT_EQ(0xa0927048ba8121afULL, + reader.ReadUnsignedLEB128(data + 15, &leb128_size)); + EXPECT_EQ(10U, leb128_size); + EXPECT_EQ(-0x4f337badf4483f83LL, + reader.ReadSignedLEB128(data + 25, &leb128_size)); + EXPECT_EQ(10U, leb128_size); + EXPECT_EQ(0xfec319c9, reader.ReadAddress(data + 35)); +} + +TEST_F(Reader, ValidEncodings) { + ByteReader reader(ENDIANNESS_LITTLE); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_pcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_textrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_datarel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_absptr | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_uleb128 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata2 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata4 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_udata8 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sleb128 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata2 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata4 | + dwarf2reader::DW_EH_PE_funcrel))); + EXPECT_TRUE(reader.ValidEncoding( + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | + dwarf2reader::DW_EH_PE_sdata8 | + dwarf2reader::DW_EH_PE_funcrel))); + + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0d))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0f))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x51))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x60))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x70))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xf0))); + EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xd0))); +} + +TEST_F(ReaderDeathTest, DW_EH_PE_omit) { + static const uint8_t data[] = { 42 }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit, + &pointer_size), + "encoding != DW_EH_PE_omit"); +} + +TEST_F(Reader, DW_EH_PE_absptr4) { + static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + EXPECT_EQ(0x40ea5727U, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr, + &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_absptr8) { + static const uint8_t data[] = { + 0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50 + }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + EXPECT_EQ(0x010598c240ea5727ULL, + reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr, + &pointer_size)); + EXPECT_EQ(8U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_uleb128) { + static const uint8_t data[] = { 0x81, 0x84, 0x4c }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + EXPECT_EQ(0x130201U, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128, + &pointer_size)); + EXPECT_EQ(3U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_udata2) { + static const uint8_t data[] = { 0xf4, 0x8d }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + EXPECT_EQ(0xf48dU, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2, + &pointer_size)); + EXPECT_EQ(2U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_udata4) { + static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(8); + EXPECT_EQ(0xa5628f8b, + reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4, + &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_udata8Addr8) { + static const uint8_t data[] = { + 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe + }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + EXPECT_EQ(0x8fed199f69047304ULL, + reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + &pointer_size)); + EXPECT_EQ(8U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_udata8Addr4) { + static const uint8_t data[] = { + 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe + }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + EXPECT_EQ(0x69047304ULL, + reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, + &pointer_size)); + EXPECT_EQ(8U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_sleb128) { + static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + EXPECT_EQ(-0x030201U & 0xffffffff, + reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128, + &pointer_size)); + EXPECT_EQ(3U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_sdata2) { + static const uint8_t data[] = { 0xb9, 0xbf }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + EXPECT_EQ(0xffffffffffffbfb9ULL, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2, + &pointer_size)); + EXPECT_EQ(2U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_sdata4) { + static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + EXPECT_EQ(0xffffffffadc2b8f2ULL, + reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4, + &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_sdata8) { + static const uint8_t data[] = { + 0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87 + }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + EXPECT_EQ(0x87269b0ce0795766ULL, + reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8, + &pointer_size)); + EXPECT_EQ(8U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_pcrel) { + static const uint8_t data[] = { + 0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce + }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + DwarfPointerEncoding encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel + | dwarf2reader::DW_EH_PE_absptr); + reader.SetCFIDataBase(0x89951377, data); + EXPECT_EQ(0x89951377 + 3 + 0x14c8c402, + reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_textrel) { + static const uint8_t data[] = { + 0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e + }; + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + reader.SetTextBase(0xb91beaf0); + DwarfPointerEncoding encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel + | dwarf2reader::DW_EH_PE_sdata2); + EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff, + reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); + EXPECT_EQ(2U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_datarel) { + static const uint8_t data[] = { + 0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39 + }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(8); + reader.SetDataBase(0xbef308bd25ce74f0ULL); + DwarfPointerEncoding encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel + | dwarf2reader::DW_EH_PE_sleb128); + EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL, + reader.ReadEncodedPointer(data + 2, encoding, &pointer_size)); + EXPECT_EQ(3U, pointer_size); +} + +TEST_F(Reader, DW_EH_PE_funcrel) { + static const uint8_t data[] = { + 0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9 + }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + reader.SetFunctionBase(0x823c3520); + DwarfPointerEncoding encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel + | dwarf2reader::DW_EH_PE_udata2); + EXPECT_EQ(0x823c3520 + 0xd148, + reader.ReadEncodedPointer(data + 5, encoding, &pointer_size)); + EXPECT_EQ(2U, pointer_size); +} + +TEST(UsableBase, CFI) { + static const uint8_t data[] = { 0x42 }; + ByteReader reader(ENDIANNESS_BIG); + reader.SetCFIDataBase(0xb31cbd20, data); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); +} + +TEST(UsableBase, Text) { + ByteReader reader(ENDIANNESS_BIG); + reader.SetTextBase(0xa899ccb9); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); +} + +TEST(UsableBase, Data) { + ByteReader reader(ENDIANNESS_BIG); + reader.SetDataBase(0xf7b10bcd); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); +} + +TEST(UsableBase, Function) { + ByteReader reader(ENDIANNESS_BIG); + reader.SetFunctionBase(0xc2c0ed81); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); +} + +TEST(UsableBase, ClearFunction) { + ByteReader reader(ENDIANNESS_BIG); + reader.SetFunctionBase(0xc2c0ed81); + reader.ClearFunctionBase(); + EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); + EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); + EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); +} + +struct AlignedFixture { + AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); } + static const uint8_t data[10]; + ByteReader reader; + size_t pointer_size; +}; + +const uint8_t AlignedFixture::data[10] = { + 0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b +}; + +class Aligned: public AlignedFixture, public Test { }; + +TEST_F(Aligned, DW_EH_PE_aligned0) { + reader.SetCFIDataBase(0xb440305c, data); + EXPECT_EQ(0xfe6e93d8U, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned1) { + reader.SetCFIDataBase(0xb440305d, data); + EXPECT_EQ(0xd834d51cU, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(7U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned2) { + reader.SetCFIDataBase(0xb440305e, data); + EXPECT_EQ(0x93d834d5U, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(6U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned3) { + reader.SetCFIDataBase(0xb440305f, data); + EXPECT_EQ(0x6e93d834U, + reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(5U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned11) { + reader.SetCFIDataBase(0xb4403061, data); + EXPECT_EQ(0xd834d51cU, + reader.ReadEncodedPointer(data + 1, + dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(6U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned30) { + reader.SetCFIDataBase(0xb4403063, data); + EXPECT_EQ(0x6e93d834U, + reader.ReadEncodedPointer(data + 1, + dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(4U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned23) { + reader.SetCFIDataBase(0xb4403062, data); + EXPECT_EQ(0x1cd3ac2bU, + reader.ReadEncodedPointer(data + 3, + dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(7U, pointer_size); +} + +TEST_F(Aligned, DW_EH_PE_aligned03) { + reader.SetCFIDataBase(0xb4403064, data); + EXPECT_EQ(0x34d51cd3U, + reader.ReadEncodedPointer(data + 3, + dwarf2reader::DW_EH_PE_aligned, + &pointer_size)); + EXPECT_EQ(5U, pointer_size); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc new file mode 100644 index 0000000000..2dc2208577 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc @@ -0,0 +1,204 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. +// See cfi_assembler.h for details. + +#include "common/dwarf/cfi_assembler.h" + +#include +#include + +namespace google_breakpad { + +using dwarf2reader::DwarfPointerEncoding; + +CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, + int data_alignment_factor, + unsigned return_address_register, + uint8_t version, + const string &augmentation, + bool dwarf64, + uint8_t address_size, + uint8_t segment_size) { + assert(!entry_length_); + entry_length_ = new PendingLength(); + in_fde_ = false; + + if (dwarf64) { + D32(kDwarf64InitialLengthMarker); + D64(entry_length_->length); + entry_length_->start = Here(); + D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); + } else { + D32(entry_length_->length); + entry_length_->start = Here(); + D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); + } + D8(version); + AppendCString(augmentation); + if (version >= 4) { + D8(address_size); + D8(segment_size); + } + ULEB128(code_alignment_factor); + LEB128(data_alignment_factor); + if (version == 1) + D8(return_address_register); + else + ULEB128(return_address_register); + return *this; +} + +CFISection &CFISection::FDEHeader(Label cie_pointer, + uint64_t initial_location, + uint64_t address_range, + bool dwarf64) { + assert(!entry_length_); + entry_length_ = new PendingLength(); + in_fde_ = true; + fde_start_address_ = initial_location; + + if (dwarf64) { + D32(0xffffffff); + D64(entry_length_->length); + entry_length_->start = Here(); + if (eh_frame_) + D64(Here() - cie_pointer); + else + D64(cie_pointer); + } else { + D32(entry_length_->length); + entry_length_->start = Here(); + if (eh_frame_) + D32(Here() - cie_pointer); + else + D32(cie_pointer); + } + EncodedPointer(initial_location); + // The FDE length in an .eh_frame section uses the same encoding as the + // initial location, but ignores the base address (selected by the upper + // nybble of the encoding), as it's a length, not an address that can be + // made relative. + EncodedPointer(address_range, + DwarfPointerEncoding(pointer_encoding_ & 0x0f)); + return *this; +} + +CFISection &CFISection::FinishEntry() { + assert(entry_length_); + Align(address_size_, dwarf2reader::DW_CFA_nop); + entry_length_->length = Here() - entry_length_->start; + delete entry_length_; + entry_length_ = NULL; + in_fde_ = false; + return *this; +} + +CFISection &CFISection::EncodedPointer(uint64_t address, + DwarfPointerEncoding encoding, + const EncodedPointerBases &bases) { + // Omitted data is extremely easy to emit. + if (encoding == dwarf2reader::DW_EH_PE_omit) + return *this; + + // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume + // that ADDRESS is the address at which the pointer is stored --- in + // other words, that bit has no effect on how we write the pointer. + encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect); + + // Find the base address to which this pointer is relative. The upper + // nybble of the encoding specifies this. + uint64_t base; + switch (encoding & 0xf0) { + case dwarf2reader::DW_EH_PE_absptr: base = 0; break; + case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; + case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break; + case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break; + case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break; + case dwarf2reader::DW_EH_PE_aligned: base = 0; break; + default: abort(); + }; + + // Make ADDRESS relative. Yes, this is appropriate even for "absptr" + // values; see gcc/unwind-pe.h. + address -= base; + + // Align the pointer, if required. + if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned) + Align(AddressSize()); + + // Append ADDRESS to this section in the appropriate form. For the + // fixed-width forms, we don't need to differentiate between signed and + // unsigned encodings, because ADDRESS has already been extended to 64 + // bits before it was passed to us. + switch (encoding & 0x0f) { + case dwarf2reader::DW_EH_PE_absptr: + Address(address); + break; + + case dwarf2reader::DW_EH_PE_uleb128: + ULEB128(address); + break; + + case dwarf2reader::DW_EH_PE_sleb128: + LEB128(address); + break; + + case dwarf2reader::DW_EH_PE_udata2: + case dwarf2reader::DW_EH_PE_sdata2: + D16(address); + break; + + case dwarf2reader::DW_EH_PE_udata4: + case dwarf2reader::DW_EH_PE_sdata4: + D32(address); + break; + + case dwarf2reader::DW_EH_PE_udata8: + case dwarf2reader::DW_EH_PE_sdata8: + D64(address); + break; + + default: + abort(); + } + + return *this; +}; + +const uint32_t CFISection::kDwarf64InitialLengthMarker; +const uint32_t CFISection::kDwarf32CIEIdentifier; +const uint64_t CFISection::kDwarf64CIEIdentifier; +const uint32_t CFISection::kEHFrame32CIEIdentifier; +const uint64_t CFISection::kEHFrame64CIEIdentifier; + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h new file mode 100644 index 0000000000..bd7354d127 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h @@ -0,0 +1,271 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_assembler.h: Define CFISection, a class for creating properly +// (and improperly) formatted DWARF CFI data for unit tests. + +#ifndef PROCESSOR_CFI_ASSEMBLER_H_ +#define PROCESSOR_CFI_ASSEMBLER_H_ + +#include + +#include "common/dwarf/dwarf2enums.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using dwarf2reader::DwarfPointerEncoding; +using google_breakpad::test_assembler::Endianness; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; + +class CFISection: public Section { + public: + + // CFI augmentation strings beginning with 'z', defined by the + // Linux/IA-64 C++ ABI, can specify interesting encodings for + // addresses appearing in FDE headers and call frame instructions (and + // for additional fields whose presence the augmentation string + // specifies). In particular, pointers can be specified to be relative + // to various base address: the start of the .text section, the + // location holding the address itself, and so on. These allow the + // frame data to be position-independent even when they live in + // write-protected pages. These variants are specified at the + // following two URLs: + // + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html + // + // CFISection leaves the production of well-formed 'z'-augmented CIEs and + // FDEs to the user, but does provide EncodedPointer, to emit + // properly-encoded addresses for a given pointer encoding. + // EncodedPointer uses an instance of this structure to find the base + // addresses it should use; you can establish a default for all encoded + // pointers appended to this section with SetEncodedPointerBases. + struct EncodedPointerBases { + EncodedPointerBases() : cfi(), text(), data() { } + + // The starting address of this CFI section in memory, for + // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data + // that has is loaded into the program's address space. + uint64_t cfi; + + // The starting address of this file's .text section, for DW_EH_PE_textrel. + uint64_t text; + + // The starting address of this file's .got or .eh_frame_hdr section, + // for DW_EH_PE_datarel. + uint64_t data; + }; + + // Create a CFISection whose endianness is ENDIANNESS, and where + // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is + // true, use the .eh_frame format, as described by the Linux + // Standards Base Core Specification, instead of the DWARF CFI + // format. + CFISection(Endianness endianness, size_t address_size, + bool eh_frame = false) + : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), + pointer_encoding_(dwarf2reader::DW_EH_PE_absptr), + encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { + // The 'start', 'Here', and 'Mark' members of a CFISection all refer + // to section offsets. + start() = 0; + } + + // Return this CFISection's address size. + size_t AddressSize() const { return address_size_; } + + // Return true if this CFISection uses the .eh_frame format, or + // false if it contains ordinary DWARF CFI data. + bool ContainsEHFrame() const { return eh_frame_; } + + // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer. + void SetPointerEncoding(DwarfPointerEncoding encoding) { + pointer_encoding_ = encoding; + } + + // Use the addresses in BASES as the base addresses for encoded + // pointers in subsequent calls to FDEHeader or EncodedPointer. + // This function makes a copy of BASES. + void SetEncodedPointerBases(const EncodedPointerBases &bases) { + encoded_pointer_bases_ = bases; + } + + // Append a Common Information Entry header to this section with the + // given values. If dwarf64 is true, use the 64-bit DWARF initial + // length format for the CIE's initial length. Return a reference to + // this section. You should call FinishEntry after writing the last + // instruction for the CIE. + // + // Before calling this function, you will typically want to use Mark + // or Here to make a label to pass to FDEHeader that refers to this + // CIE's position in the section. + CFISection &CIEHeader(uint64_t code_alignment_factor, + int data_alignment_factor, + unsigned return_address_register, + uint8_t version = 3, + const string &augmentation = "", + bool dwarf64 = false, + uint8_t address_size = 8, + uint8_t segment_size = 0); + + // Append a Frame Description Entry header to this section with the + // given values. If dwarf64 is true, use the 64-bit DWARF initial + // length format for the CIE's initial length. Return a reference to + // this section. You should call FinishEntry after writing the last + // instruction for the CIE. + // + // This function doesn't support entries that are longer than + // 0xffffff00 bytes. (The "initial length" is always a 32-bit + // value.) Nor does it support .debug_frame sections longer than + // 0xffffff00 bytes. + CFISection &FDEHeader(Label cie_pointer, + uint64_t initial_location, + uint64_t address_range, + bool dwarf64 = false); + + // Note the current position as the end of the last CIE or FDE we + // started, after padding with DW_CFA_nops for alignment. This + // defines the label representing the entry's length, cited in the + // entry's header. Return a reference to this section. + CFISection &FinishEntry(); + + // Append the contents of BLOCK as a DW_FORM_block value: an + // unsigned LEB128 length, followed by that many bytes of data. + CFISection &Block(const string &block) { + ULEB128(block.size()); + Append(block); + return *this; + } + + // Append ADDRESS to this section, in the appropriate size and + // endianness. Return a reference to this section. + CFISection &Address(uint64_t address) { + Section::Append(endianness(), address_size_, address); + return *this; + } + CFISection &Address(Label address) { + Section::Append(endianness(), address_size_, address); + return *this; + } + + // Append ADDRESS to this section, using ENCODING and BASES. ENCODING + // defaults to this section's default encoding, established by + // SetPointerEncoding. BASES defaults to this section's bases, set by + // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the + // encoding, assume that ADDRESS is where the true address is stored. + // Return a reference to this section. + // + // (C++ doesn't let me use default arguments here, because I want to + // refer to members of *this in the default argument expression.) + CFISection &EncodedPointer(uint64_t address) { + return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); + } + CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { + return EncodedPointer(address, encoding, encoded_pointer_bases_); + } + CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, + const EncodedPointerBases &bases); + + // Restate some member functions, to keep chaining working nicely. + CFISection &Mark(Label *label) { Section::Mark(label); return *this; } + CFISection &D8(uint8_t v) { Section::D8(v); return *this; } + CFISection &D16(uint16_t v) { Section::D16(v); return *this; } + CFISection &D16(Label v) { Section::D16(v); return *this; } + CFISection &D32(uint32_t v) { Section::D32(v); return *this; } + CFISection &D32(const Label &v) { Section::D32(v); return *this; } + CFISection &D64(uint64_t v) { Section::D64(v); return *this; } + CFISection &D64(const Label &v) { Section::D64(v); return *this; } + CFISection &LEB128(long long v) { Section::LEB128(v); return *this; } + CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } + + private: + // A length value that we've appended to the section, but is not yet + // known. LENGTH is the appended value; START is a label referring + // to the start of the data whose length was cited. + struct PendingLength { + Label length; + Label start; + }; + + // Constants used in CFI/.eh_frame data: + + // If the first four bytes of an "initial length" are this constant, then + // the data uses the 64-bit DWARF format, and the length itself is the + // subsequent eight bytes. + static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU; + + // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data. + static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0; + static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0; + static const uint32_t kEHFrame32CIEIdentifier = 0; + static const uint64_t kEHFrame64CIEIdentifier = 0; + + // The size of a machine address for the data in this section. + size_t address_size_; + + // If true, we are generating a Linux .eh_frame section, instead of + // a standard DWARF .debug_frame section. + bool eh_frame_; + + // The encoding to use for FDE pointers. + DwarfPointerEncoding pointer_encoding_; + + // The base addresses to use when emitting encoded pointers. + EncodedPointerBases encoded_pointer_bases_; + + // The length value for the current entry. + // + // Oddly, this must be dynamically allocated. Labels never get new + // values; they only acquire constraints on the value they already + // have, or assert if you assign them something incompatible. So + // each header needs truly fresh Label objects to cite in their + // headers and track their positions. The alternative is explicit + // destructor invocation and a placement new. Ick. + PendingLength *entry_length_; + + // True if we are currently emitting an FDE --- that is, we have + // called FDEHeader but have not yet called FinishEntry. + bool in_fde_; + + // If in_fde_ is true, this is its starting address. We use this for + // emitting DW_EH_PE_funcrel pointers. + uint64_t fde_start_address_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_CFI_ASSEMBLER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc new file mode 100644 index 0000000000..94542b5ea9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. +// See dwarf2diehandler.h for details. + +#include +#include + +#include + +#include "common/dwarf/dwarf2diehandler.h" +#include "common/using_std_string.h" + +namespace dwarf2reader { + +DIEDispatcher::~DIEDispatcher() { + while (!die_handlers_.empty()) { + HandlerStack &entry = die_handlers_.top(); + if (entry.handler_ != root_handler_) + delete entry.handler_; + die_handlers_.pop(); + } +} + +bool DIEDispatcher::StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version) { + return root_handler_->StartCompilationUnit(offset, address_size, + offset_size, cu_length, + dwarf_version); +} + +bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag) { + // The stack entry for the parent of this DIE, if there is one. + HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); + + // Does this call indicate that we're done receiving the parent's + // attributes' values? If so, call its EndAttributes member function. + if (parent && parent->handler_ && !parent->reported_attributes_end_) { + parent->reported_attributes_end_ = true; + if (!parent->handler_->EndAttributes()) { + // Finish off this handler now. and edit *PARENT to indicate that + // we don't want to visit any of the children. + parent->handler_->Finish(); + if (parent->handler_ != root_handler_) + delete parent->handler_; + parent->handler_ = NULL; + return false; + } + } + + // Find a handler for this DIE. + DIEHandler *handler; + if (parent) { + if (parent->handler_) + // Ask the parent to find a handler. + handler = parent->handler_->FindChildHandler(offset, tag); + else + // No parent handler means we're not interested in any of our + // children. + handler = NULL; + } else { + // This is the root DIE. For a non-root DIE, the parent's handler + // decides whether to visit it, but the root DIE has no parent + // handler, so we have a special method on the root DIE handler + // itself to decide. + if (root_handler_->StartRootDIE(offset, tag)) + handler = root_handler_; + else + handler = NULL; + } + + // Push a handler stack entry for this new handler. As an + // optimization, we don't push NULL-handler entries on top of other + // NULL-handler entries; we just let the oldest such entry stand for + // the whole subtree. + if (handler || !parent || parent->handler_) { + HandlerStack entry; + entry.offset_ = offset; + entry.handler_ = handler; + entry.reported_attributes_end_ = false; + die_handlers_.push(entry); + } + + return handler != NULL; +} + +void DIEDispatcher::EndDIE(uint64 offset) { + assert(!die_handlers_.empty()); + HandlerStack *entry = &die_handlers_.top(); + if (entry->handler_) { + // This entry had better be the handler for this DIE. + assert(entry->offset_ == offset); + // If a DIE has no children, this EndDIE call indicates that we're + // done receiving its attributes' values. + if (!entry->reported_attributes_end_) + entry->handler_->EndAttributes(); // Ignore return value: no children. + entry->handler_->Finish(); + if (entry->handler_ != root_handler_) + delete entry->handler_; + } else { + // If this DIE is within a tree we're ignoring, then don't pop the + // handler stack: that entry stands for the whole tree. + if (entry->offset_ != offset) + return; + } + die_handlers_.pop(); +} + +void DIEDispatcher::ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeUnsigned(attr, form, data); +} + +void DIEDispatcher::ProcessAttributeSigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeSigned(attr, form, data); +} + +void DIEDispatcher::ProcessAttributeReference(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeReference(attr, form, data); +} + +void DIEDispatcher::ProcessAttributeBuffer(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64 len) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeBuffer(attr, form, data, len); +} + +void DIEDispatcher::ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string& data) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeString(attr, form, data); +} + +void DIEDispatcher::ProcessAttributeSignature(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 signature) { + HandlerStack ¤t = die_handlers_.top(); + // This had better be an attribute of the DIE we were meant to handle. + assert(offset == current.offset_); + current.handler_->ProcessAttributeSignature(attr, form, signature); +} + +} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h new file mode 100644 index 0000000000..a1e589a863 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h @@ -0,0 +1,365 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf2reader::CompilationUnit is a simple and direct parser for +// DWARF data, but its handler interface is not convenient to use. In +// particular: +// +// - CompilationUnit calls Dwarf2Handler's member functions to report +// every attribute's value, regardless of what sort of DIE it is. +// As a result, the ProcessAttributeX functions end up looking like +// this: +// +// switch (parent_die_tag) { +// case DW_TAG_x: +// switch (attribute_name) { +// case DW_AT_y: +// handle attribute y of DIE type x +// ... +// } break; +// ... +// } +// +// In C++ it's much nicer to use virtual function dispatch to find +// the right code for a given case than to switch on the DIE tag +// like this. +// +// - Processing different kinds of DIEs requires different sets of +// data: lexical block DIEs have start and end addresses, but struct +// type DIEs don't. It would be nice to be able to have separate +// handler classes for separate kinds of DIEs, each with the members +// appropriate to its role, instead of having one handler class that +// needs to hold data for every DIE type. +// +// - There should be a separate instance of the appropriate handler +// class for each DIE, instead of a single object with tables +// tracking all the dies in the compilation unit. +// +// - It's not convenient to take some action after all a DIE's +// attributes have been seen, but before visiting any of its +// children. The only indication you have that a DIE's attribute +// list is complete is that you get either a StartDIE or an EndDIE +// call. +// +// - It's not convenient to make use of the tree structure of the +// DIEs. Skipping all the children of a given die requires +// maintaining state and returning false from StartDIE until we get +// an EndDIE call with the appropriate offset. +// +// This interface tries to take care of all that. (You're shocked, I'm sure.) +// +// Using the classes here, you provide an initial handler for the root +// DIE of the compilation unit. Each handler receives its DIE's +// attributes, and provides fresh handler objects for children of +// interest, if any. The three classes are: +// +// - DIEHandler: the base class for your DIE-type-specific handler +// classes. +// +// - RootDIEHandler: derived from DIEHandler, the base class for your +// root DIE handler class. +// +// - DIEDispatcher: derived from Dwarf2Handler, an instance of this +// invokes your DIE-type-specific handler objects. +// +// In detail: +// +// - Define handler classes specialized for the DIE types you're +// interested in. These handler classes must inherit from +// DIEHandler. Thus: +// +// class My_DW_TAG_X_Handler: public DIEHandler { ... }; +// class My_DW_TAG_Y_Handler: public DIEHandler { ... }; +// +// DIEHandler subclasses needn't correspond exactly to single DIE +// types, as shown here; the point is that you can have several +// different classes appropriate to different kinds of DIEs. +// +// - In particular, define a handler class for the compilation +// unit's root DIE, that inherits from RootDIEHandler: +// +// class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... }; +// +// RootDIEHandler inherits from DIEHandler, adding a few additional +// member functions for examining the compilation unit as a whole, +// and other quirks of rootness. +// +// - Then, create a DIEDispatcher instance, passing it an instance of +// your root DIE handler class, and use that DIEDispatcher as the +// dwarf2reader::CompilationUnit's handler: +// +// My_DW_TAG_compile_unit_Handler root_die_handler(...); +// DIEDispatcher die_dispatcher(&root_die_handler); +// CompilationUnit reader(sections, offset, bytereader, &die_dispatcher); +// +// Here, 'die_dispatcher' acts as a shim between 'reader' and the +// various DIE-specific handlers you have defined. +// +// - When you call reader.Start(), die_dispatcher behaves as follows, +// starting with your root die handler and the compilation unit's +// root DIE: +// +// - It calls the handler's ProcessAttributeX member functions for +// each of the DIE's attributes. +// +// - It calls the handler's EndAttributes member function. This +// should return true if any of the DIE's children should be +// visited, in which case: +// +// - For each of the DIE's children, die_dispatcher calls the +// DIE's handler's FindChildHandler member function. If that +// returns a pointer to a DIEHandler instance, then +// die_dispatcher uses that handler to process the child, using +// this procedure recursively. Alternatively, if +// FindChildHandler returns NULL, die_dispatcher ignores that +// child and its descendants. +// +// - When die_dispatcher has finished processing all the DIE's +// children, it invokes the handler's Finish() member function, +// and destroys the handler. (As a special case, it doesn't +// destroy the root DIE handler.) +// +// This allows the code for handling a particular kind of DIE to be +// gathered together in a single class, makes it easy to skip all the +// children or individual children of a particular DIE, and provides +// appropriate parental context for each die. + +#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__ +#define COMMON_DWARF_DWARF2DIEHANDLER_H__ + +#include + +#include +#include + +#include "common/dwarf/types.h" +#include "common/dwarf/dwarf2enums.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + +namespace dwarf2reader { + +// A base class for handlers for specific DIE types. The series of +// calls made on a DIE handler is as follows: +// +// - for each attribute of the DIE: +// - ProcessAttributeX() +// - EndAttributes() +// - if that returned true, then for each child: +// - FindChildHandler() +// - if that returns a non-NULL pointer to a new handler: +// - recurse, with the new handler and the child die +// - Finish() +// - destruction +class DIEHandler { + public: + DIEHandler() { } + virtual ~DIEHandler() { } + + // When we visit a DIE, we first use these member functions to + // report the DIE's attributes and their values. These have the + // same restrictions as the corresponding member functions of + // dwarf2reader::Dwarf2Handler. + // + // Since DWARF does not specify in what order attributes must + // appear, avoid making decisions in these functions that would be + // affected by the presence of other attributes. The EndAttributes + // function is a more appropriate place for such work, as all the + // DIE's attributes have been seen at that point. + // + // The default definitions ignore the values they are passed. + virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { } + virtual void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { } + virtual void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { } + virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64 len) { } + virtual void ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string& data) { } + virtual void ProcessAttributeSignature(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 signture) { } + + // Once we have reported all the DIE's attributes' values, we call + // this member function. If it returns false, we skip all the DIE's + // children. If it returns true, we call FindChildHandler on each + // child. If that returns a handler object, we use that to visit + // the child; otherwise, we skip the child. + // + // This is a good place to make decisions that depend on more than + // one attribute. DWARF does not specify in what order attributes + // must appear, so only when the EndAttributes function is called + // does the handler have a complete picture of the DIE's attributes. + // + // The default definition elects to ignore the DIE's children. + // You'll need to override this if you override FindChildHandler, + // but at least the default behavior isn't to pass the children to + // FindChildHandler, which then ignores them all. + virtual bool EndAttributes() { return false; } + + // If EndAttributes returns true to indicate that some of the DIE's + // children might be of interest, then we apply this function to + // each of the DIE's children. If it returns a handler object, then + // we use that to visit the child DIE. If it returns NULL, we skip + // that child DIE (and all its descendants). + // + // OFFSET is the offset of the child; TAG indicates what kind of DIE + // it is. + // + // The default definition skips all children. + virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag) { + return NULL; + } + + // When we are done processing a DIE, we call this member function. + // This happens after the EndAttributes call, all FindChildHandler + // calls (if any), and all operations on the children themselves (if + // any). We call Finish on every handler --- even if EndAttributes + // returns false. + virtual void Finish() { }; +}; + +// A subclass of DIEHandler, with additional kludges for handling the +// compilation unit's root die. +class RootDIEHandler: public DIEHandler { + public: + RootDIEHandler() { } + virtual ~RootDIEHandler() { } + + // We pass the values reported via Dwarf2Handler::StartCompilationUnit + // to this member function, and skip the entire compilation unit if it + // returns false. So the root DIE handler is actually also + // responsible for handling the compilation unit metadata. + // The default definition always visits the compilation unit. + virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version) { return true; } + + // For the root DIE handler only, we pass the offset, tag and + // attributes of the compilation unit's root DIE. This is the only + // way the root DIE handler can find the root DIE's tag. If this + // function returns true, we will visit the root DIE using the usual + // DIEHandler methods; otherwise, we skip the entire compilation + // unit. + // + // The default definition elects to visit the root DIE. + virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag) { return true; } +}; + +class DIEDispatcher: public Dwarf2Handler { + public: + // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for + // the compilation unit's root die, as described for the DIEHandler + // class. + DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { } + // Destroying a DIEDispatcher destroys all active handler objects + // except the root handler. + ~DIEDispatcher(); + bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version); + bool StartDIE(uint64 offset, enum DwarfTag tag); + void ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeSigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeReference(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeBuffer(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64 len); + void ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string &data); + void ProcessAttributeSignature(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 signature); + void EndDIE(uint64 offset); + + private: + + // The type of a handler stack entry. This includes some fields + // which don't really need to be on the stack --- they could just be + // single data members of DIEDispatcher --- but putting them here + // makes it easier to see that the code is correct. + struct HandlerStack { + // The offset of the DIE for this handler stack entry. + uint64 offset_; + + // The handler object interested in this DIE's attributes and + // children. If NULL, we're not interested in either. + DIEHandler *handler_; + + // Have we reported the end of this DIE's attributes to the handler? + bool reported_attributes_end_; + }; + + // Stack of DIE attribute handlers. At StartDIE(D), the top of the + // stack is the handler of D's parent, whom we may ask for a handler + // for D itself. At EndDIE(D), the top of the stack is D's handler. + // Special cases: + // + // - Before we've seen the compilation unit's root DIE, the stack is + // empty; we'll call root_handler_'s special member functions, and + // perhaps push root_handler_ on the stack to look at the root's + // immediate children. + // + // - When we decide to ignore a subtree, we only push an entry on + // the stack for the root of the tree being ignored, rather than + // pushing lots of stack entries with handler_ set to NULL. + std::stack die_handlers_; + + // The root handler. We don't push it on die_handlers_ until we + // actually get the StartDIE call for the root. + RootDIEHandler *root_handler_; +}; + +} // namespace dwarf2reader +#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc new file mode 100644 index 0000000000..db70eb31b9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc @@ -0,0 +1,527 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. + +#include + +#include +#include + +#include "breakpad_googletest_includes.h" + +#include "common/dwarf/dwarf2diehandler.h" +#include "common/using_std_string.h" + +using std::make_pair; + +using ::testing::_; +using ::testing::ContainerEq; +using ::testing::ElementsAreArray; +using ::testing::Eq; +using ::testing::InSequence; +using ::testing::Return; +using ::testing::Sequence; +using ::testing::StrEq; + +using dwarf2reader::DIEDispatcher; +using dwarf2reader::DIEHandler; +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfTag; +using dwarf2reader::RootDIEHandler; + +class MockDIEHandler: public DIEHandler { + public: + MOCK_METHOD3(ProcessAttributeUnsigned, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD3(ProcessAttributeSigned, + void(DwarfAttribute, DwarfForm, int64)); + MOCK_METHOD3(ProcessAttributeReference, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD4(ProcessAttributeBuffer, + void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); + MOCK_METHOD3(ProcessAttributeString, + void(DwarfAttribute, DwarfForm, const string &)); + MOCK_METHOD3(ProcessAttributeSignature, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD0(EndAttributes, bool()); + MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); + MOCK_METHOD0(Finish, void()); +}; + +class MockRootDIEHandler: public RootDIEHandler { + public: + MOCK_METHOD3(ProcessAttributeUnsigned, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD3(ProcessAttributeSigned, + void(DwarfAttribute, DwarfForm, int64)); + MOCK_METHOD3(ProcessAttributeReference, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD4(ProcessAttributeBuffer, + void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); + MOCK_METHOD3(ProcessAttributeString, + void(DwarfAttribute, DwarfForm, const string &)); + MOCK_METHOD3(ProcessAttributeSignature, + void(DwarfAttribute, DwarfForm, uint64)); + MOCK_METHOD0(EndAttributes, bool()); + MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); + MOCK_METHOD0(Finish, void()); + MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8)); + MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag)); +}; + +// If the handler elects to skip the compilation unit, the dispatcher +// should tell the reader so. +TEST(Dwarf2DIEHandler, SkipCompilationUnit) { + Sequence s; + MockRootDIEHandler mock_root_handler; + DIEDispatcher die_dispatcher(&mock_root_handler); + + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0x8d42aed77cfccf3eLL, + 0x89, 0xdc, + 0x2ecb4dc778a80f21LL, + 0x66)) + .InSequence(s) + .WillOnce(Return(false)); + + EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, + 0x89, 0xdc, + 0x2ecb4dc778a80f21LL, + 0x66)); +} + +// If the handler elects to skip the root DIE, the dispatcher should +// tell the reader so. +TEST(Dwarf2DIEHandler, SkipRootDIE) { + Sequence s; + MockRootDIEHandler mock_root_handler; + DIEDispatcher die_dispatcher(&mock_root_handler); + + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02, + 0xb00febffa76e2b2bLL, 0x5c)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(mock_root_handler, + StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) + .InSequence(s) + .WillOnce(Return(false)); + + EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL, + 0xf4, 0x02, + 0xb00febffa76e2b2bLL, 0x5c)); + EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, + (DwarfTag) 0xb4f98da6)); + die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); +} + +// If the handler elects to skip the root DIE's children, the +// dispatcher should tell the reader so --- and avoid deleting the +// root handler. +TEST(Dwarf2DIEHandler, SkipRootDIEChildren) { + MockRootDIEHandler mock_root_handler; + DIEDispatcher die_dispatcher(&mock_root_handler); + + { + InSequence s; + + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0, + 0x09f8bf0767f91675LL, 0xdb)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_root_handler, + StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) + .WillOnce(Return(true)); + // Please don't tell me about my children. + EXPECT_CALL(mock_root_handler, EndAttributes()) + .WillOnce(Return(false)); + EXPECT_CALL(mock_root_handler, Finish()) + .WillOnce(Return()); + } + + EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL, + 0x26, 0xa0, + 0x09f8bf0767f91675LL, 0xdb)); + EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, + (DwarfTag) 0xb4f98da6)); + EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL, + (DwarfTag) 0xc3a17bba)); + die_dispatcher.EndDIE(0x435150ceedccda18LL); + die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); +} + +// The dispatcher should pass attribute values through to the die +// handler accurately. +TEST(Dwarf2DIEHandler, PassAttributeValues) { + MockRootDIEHandler mock_root_handler; + DIEDispatcher die_dispatcher(&mock_root_handler); + + const uint8_t buffer[10] = { + 0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18 + }; + string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d"; + + // Set expectations. + { + InSequence s; + + // We'll like the compilation unit header. + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc, + 0x2ecb4dc778a80f21LL, 0x66)) + .WillOnce(Return(true)); + + // We'll like the root DIE. + EXPECT_CALL(mock_root_handler, + StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c)) + .WillOnce(Return(true)); + + // Expect some attribute values. + EXPECT_CALL(mock_root_handler, + ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed, + (DwarfForm) 0x424f1468, + 0xa592571997facda1ULL)) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, + ProcessAttributeSigned((DwarfAttribute) 0x43694dc9, + (DwarfForm) 0xf6f78901L, + 0x92602a4e3bf1f446LL)) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, + ProcessAttributeReference((DwarfAttribute) 0x4033e8cL, + (DwarfForm) 0xf66fbe0bL, + 0x50fddef44734fdecULL)) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, + ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af, + (DwarfForm) 0xe99a539a, + buffer, sizeof(buffer))) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, + ProcessAttributeString((DwarfAttribute) 0x310ed065, + (DwarfForm) 0x15762fec, + StrEq(str))) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, + ProcessAttributeSignature((DwarfAttribute) 0x58790d72, + (DwarfForm) 0x4159f138, + 0x94682463613e6a5fULL)) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, EndAttributes()) + .WillOnce(Return(true)); + EXPECT_CALL(mock_root_handler, FindChildHandler(_, _)) + .Times(0); + EXPECT_CALL(mock_root_handler, Finish()) + .WillOnce(Return()); + } + + // Drive the dispatcher. + + // Report the CU header. + EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, + 0x89, 0xdc, + 0x2ecb4dc778a80f21LL, + 0x66)); + // Report the root DIE. + EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL, + (DwarfTag) 0x9829445c)); + + // Report some attribute values. + die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x1cc0bfed, + (DwarfForm) 0x424f1468, + 0xa592571997facda1ULL); + die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x43694dc9, + (DwarfForm) 0xf6f78901, + 0x92602a4e3bf1f446LL); + die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x4033e8c, + (DwarfForm) 0xf66fbe0b, + 0x50fddef44734fdecULL); + die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x25d7e0af, + (DwarfForm) 0xe99a539a, + buffer, sizeof(buffer)); + die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x310ed065, + (DwarfForm) 0x15762fec, + str); + die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL, + (DwarfAttribute) 0x58790d72, + (DwarfForm) 0x4159f138, + 0x94682463613e6a5fULL); + + // Finish the root DIE (and thus the CU). + die_dispatcher.EndDIE(0xe2222da01e29f2a9LL); +} + +TEST(Dwarf2DIEHandler, FindAndSkipChildren) { + MockRootDIEHandler mock_root_handler; + MockDIEHandler *mock_child1_handler = new(MockDIEHandler); + MockDIEHandler *mock_child3_handler = new(MockDIEHandler); + DIEDispatcher die_dispatcher(&mock_root_handler); + + { + InSequence s; + + // We'll like the compilation unit header. + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, + 0x47dd3c764275a216LL, 0xa5)) + .WillOnce(Return(true)); + + // Root DIE. + { + EXPECT_CALL(mock_root_handler, + StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_root_handler, + ProcessAttributeSigned((DwarfAttribute) 0xf779a642, + (DwarfForm) 0x2cb63027, + 0x18e744661769d08fLL)) + .WillOnce(Return()); + EXPECT_CALL(mock_root_handler, EndAttributes()) + .WillOnce(Return(true)); + + // First child DIE. + EXPECT_CALL(mock_root_handler, + FindChildHandler(0x149f644f8116fe8cLL, + (DwarfTag) 0xac2cbd8c)) + .WillOnce(Return(mock_child1_handler)); + { + EXPECT_CALL(*mock_child1_handler, + ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65, + (DwarfForm) 0xe4f64c41, + 0x1b04e5444a55fe67LL)) + .WillOnce(Return()); + EXPECT_CALL(*mock_child1_handler, EndAttributes()) + .WillOnce(Return(false)); + // Skip first grandchild DIE and first great-grandchild DIE. + EXPECT_CALL(*mock_child1_handler, Finish()) + .WillOnce(Return()); + } + + // Second child DIE. Root handler will decline to return a handler + // for this child. + EXPECT_CALL(mock_root_handler, + FindChildHandler(0x97412be24875de9dLL, + (DwarfTag) 0x505a068b)) + .WillOnce(Return((DIEHandler *) NULL)); + + // Third child DIE. + EXPECT_CALL(mock_root_handler, + FindChildHandler(0x753c964c8ab538aeLL, + (DwarfTag) 0x8c22970e)) + .WillOnce(Return(mock_child3_handler)); + { + EXPECT_CALL(*mock_child3_handler, + ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, + (DwarfForm) 0x610b7ae1, + 0x3ea5c609d7d7560fLL)) + .WillOnce(Return()); + EXPECT_CALL(*mock_child3_handler, EndAttributes()) + .WillOnce(Return(true)); + EXPECT_CALL(*mock_child3_handler, Finish()) + .WillOnce(Return()); + } + + EXPECT_CALL(mock_root_handler, Finish()) + .WillOnce(Return()); + } + } + + + // Drive the dispatcher. + + // Report the CU header. + EXPECT_TRUE(die_dispatcher + .StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, + 0x47dd3c764275a216LL, 0xa5)); + // Report the root DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL, + (DwarfTag) 0xf5d60c59)); + die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL, + (DwarfAttribute) 0xf779a642, + (DwarfForm) 0x2cb63027, + 0x18e744661769d08fLL); + + // First child DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL, + (DwarfTag) 0xac2cbd8c)); + die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL, + (DwarfAttribute) 0xa6fd6f65, + (DwarfForm) 0xe4f64c41, + 0x1b04e5444a55fe67LL); + + // First grandchild DIE. Will be skipped. + { + EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL, + (DwarfTag) 0x22f05a15)); + // First great-grandchild DIE. Will be skipped without being + // mentioned to any handler. + { + EXPECT_FALSE(die_dispatcher + .StartDIE(0xb3076285d25cac25LL, + (DwarfTag) 0xcff4061b)); + die_dispatcher.EndDIE(0xb3076285d25cac25LL); + } + die_dispatcher.EndDIE(0xd68de1ee0bd29419LL); + } + die_dispatcher.EndDIE(0x149f644f8116fe8cLL); + } + + // Second child DIE. Root handler will decline to find a handler for it. + { + EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL, + (DwarfTag) 0x505a068b)); + die_dispatcher.EndDIE(0x97412be24875de9dLL); + } + + // Third child DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL, + (DwarfTag) 0x8c22970e)); + die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL, + (DwarfAttribute) 0x4e2b7cfb, + (DwarfForm) 0x610b7ae1, + 0x3ea5c609d7d7560fLL); + die_dispatcher.EndDIE(0x753c964c8ab538aeLL); + } + + // Finish the root DIE (and thus the CU). + die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL); + } +} + +// The DIEDispatcher destructor is supposed to delete all handlers on +// the stack, except for the root. +TEST(Dwarf2DIEHandler, FreeHandlersOnStack) { + MockRootDIEHandler mock_root_handler; + MockDIEHandler *mock_child_handler = new(MockDIEHandler); + MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler); + + { + InSequence s; + + // We'll like the compilation unit header. + EXPECT_CALL(mock_root_handler, + StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, + 0x76d392ff393ddda2LL, 0xbf)) + .WillOnce(Return(true)); + + // Root DIE. + { + EXPECT_CALL(mock_root_handler, + StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_root_handler, EndAttributes()) + .WillOnce(Return(true)); + + // Child DIE. + EXPECT_CALL(mock_root_handler, + FindChildHandler(0x058f09240c5fc8c9LL, + (DwarfTag) 0x898bf0d0)) + .WillOnce(Return(mock_child_handler)); + { + EXPECT_CALL(*mock_child_handler, EndAttributes()) + .WillOnce(Return(true)); + + // Grandchild DIE. + EXPECT_CALL(*mock_child_handler, + FindChildHandler(0x32dc00c9945dc0c8LL, + (DwarfTag) 0x2802d007)) + .WillOnce(Return(mock_grandchild_handler)); + { + EXPECT_CALL(*mock_grandchild_handler, + ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, + (DwarfForm) 0x610b7ae1, + 0x3ea5c609d7d7560fLL)) + .WillOnce(Return()); + + // At this point, we abandon the traversal, so none of the + // usual stuff should get called. + EXPECT_CALL(*mock_grandchild_handler, EndAttributes()) + .Times(0); + EXPECT_CALL(*mock_grandchild_handler, Finish()) + .Times(0); + } + + EXPECT_CALL(*mock_child_handler, Finish()) + .Times(0); + } + + EXPECT_CALL(mock_root_handler, Finish()) + .Times(0); + } + } + + // The dispatcher. + DIEDispatcher die_dispatcher(&mock_root_handler); + + // Report the CU header. + EXPECT_TRUE(die_dispatcher + .StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, + 0x76d392ff393ddda2LL, 0xbf)); + // Report the root DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL, + (DwarfTag) 0x98980361)); + + // Child DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL, + (DwarfTag) 0x898bf0d0)); + + // Grandchild DIE. + { + EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL, + (DwarfTag) 0x2802d007)); + die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL, + (DwarfAttribute) 0x4e2b7cfb, + (DwarfForm) 0x610b7ae1, + 0x3ea5c609d7d7560fLL); + + // Stop the traversal abruptly, so that there will still be + // handlers on the stack when the dispatcher is destructed. + + // No EndDIE call... + } + // No EndDIE call... + } + // No EndDIE call... + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h new file mode 100644 index 0000000000..4316a89ccd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h @@ -0,0 +1,679 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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 COMMON_DWARF_DWARF2ENUMS_H__ +#define COMMON_DWARF_DWARF2ENUMS_H__ + +namespace dwarf2reader { + +// These enums do not follow the google3 style only because they are +// known universally (specs, other implementations) by the names in +// exactly this capitalization. +// Tag names and codes. +enum DwarfTag { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + // DWARF 3. + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + // SGI/MIPS Extensions. + DW_TAG_MIPS_loop = 0x4081, + // HP extensions. See: + // ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz + DW_TAG_HP_array_descriptor = 0x4090, + // GNU extensions. + DW_TAG_format_label = 0x4101, // For FORTRAN 77 and Fortran 90. + DW_TAG_function_template = 0x4102, // For C++. + DW_TAG_class_template = 0x4103, // For C++. + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + // Extensions for UPC. See: http://upc.gwu.edu/~upc. + DW_TAG_upc_shared_type = 0x8765, + DW_TAG_upc_strict_type = 0x8766, + DW_TAG_upc_relaxed_type = 0x8767, + // PGI (STMicroelectronics) extensions. No documentation available. + DW_TAG_PGI_kanji_type = 0xA000, + DW_TAG_PGI_interface_block = 0xA020 +}; + + +enum DwarfHasChild { + DW_children_no = 0, + DW_children_yes = 1 +}; + +// Form names and codes. +enum DwarfForm { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + + // Added in DWARF 4: + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_ref_sig8 = 0x20, + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. + DW_FORM_GNU_addr_index = 0x1f01, + DW_FORM_GNU_str_index = 0x1f02 +}; + +// Attribute names and codes +enum DwarfAttribute { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + // DWARF 3 values. + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + // DWARF 4 + DW_AT_linkage_name = 0x6e, + // SGI/MIPS extensions. + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + // HP extensions. + DW_AT_HP_block_index = 0x2000, + DW_AT_HP_unmodifiable = 0x2001, // Same as DW_AT_MIPS_fde. + DW_AT_HP_actuals_stmt_list = 0x2010, + DW_AT_HP_proc_per_section = 0x2011, + DW_AT_HP_raw_data_ptr = 0x2012, + DW_AT_HP_pass_by_reference = 0x2013, + DW_AT_HP_opt_level = 0x2014, + DW_AT_HP_prof_version_id = 0x2015, + DW_AT_HP_opt_flags = 0x2016, + DW_AT_HP_cold_region_low_pc = 0x2017, + DW_AT_HP_cold_region_high_pc = 0x2018, + DW_AT_HP_all_variables_modifiable = 0x2019, + DW_AT_HP_linkage_name = 0x201a, + DW_AT_HP_prof_flags = 0x201b, // In comp unit of procs_info for -g. + // GNU extensions. + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. + DW_AT_GNU_dwo_name = 0x2130, + DW_AT_GNU_dwo_id = 0x2131, + DW_AT_GNU_ranges_base = 0x2132, + DW_AT_GNU_addr_base = 0x2133, + DW_AT_GNU_pubnames = 0x2134, + DW_AT_GNU_pubtypes = 0x2135, + // VMS extensions. + DW_AT_VMS_rtnbeg_pd_address = 0x2201, + // UPC extension. + DW_AT_upc_threads_scaled = 0x3210, + // PGI (STMicroelectronics) extensions. + DW_AT_PGI_lbase = 0x3a00, + DW_AT_PGI_soffset = 0x3a01, + DW_AT_PGI_lstride = 0x3a02 +}; + + +// Line number opcodes. +enum DwarfLineNumberOps { + DW_LNS_extended_op = 0, + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + // DWARF 3. + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 +}; + +// Line number extended opcodes. +enum DwarfLineNumberExtendedOps { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + // HP extensions. + DW_LNE_HP_negate_is_UV_update = 0x11, + DW_LNE_HP_push_context = 0x12, + DW_LNE_HP_pop_context = 0x13, + DW_LNE_HP_set_file_line_column = 0x14, + DW_LNE_HP_set_routine_name = 0x15, + DW_LNE_HP_set_sequence = 0x16, + DW_LNE_HP_negate_post_semantics = 0x17, + DW_LNE_HP_negate_function_exit = 0x18, + DW_LNE_HP_negate_front_end_logical = 0x19, + DW_LNE_HP_define_proc = 0x20 +}; + +// Type encoding names and codes +enum DwarfEncoding { + DW_ATE_address =0x1, + DW_ATE_boolean =0x2, + DW_ATE_complex_float =0x3, + DW_ATE_float =0x4, + DW_ATE_signed =0x5, + DW_ATE_signed_char =0x6, + DW_ATE_unsigned =0x7, + DW_ATE_unsigned_char =0x8, + // DWARF3/DWARF3f + DW_ATE_imaginary_float =0x9, + DW_ATE_packed_decimal =0xa, + DW_ATE_numeric_string =0xb, + DW_ATE_edited =0xc, + DW_ATE_signed_fixed =0xd, + DW_ATE_unsigned_fixed =0xe, + DW_ATE_decimal_float =0xf, + DW_ATE_lo_user =0x80, + DW_ATE_hi_user =0xff +}; + +// Location virtual machine opcodes +enum DwarfOpcode { + DW_OP_addr =0x03, + DW_OP_deref =0x06, + DW_OP_const1u =0x08, + DW_OP_const1s =0x09, + DW_OP_const2u =0x0a, + DW_OP_const2s =0x0b, + DW_OP_const4u =0x0c, + DW_OP_const4s =0x0d, + DW_OP_const8u =0x0e, + DW_OP_const8s =0x0f, + DW_OP_constu =0x10, + DW_OP_consts =0x11, + DW_OP_dup =0x12, + DW_OP_drop =0x13, + DW_OP_over =0x14, + DW_OP_pick =0x15, + DW_OP_swap =0x16, + DW_OP_rot =0x17, + DW_OP_xderef =0x18, + DW_OP_abs =0x19, + DW_OP_and =0x1a, + DW_OP_div =0x1b, + DW_OP_minus =0x1c, + DW_OP_mod =0x1d, + DW_OP_mul =0x1e, + DW_OP_neg =0x1f, + DW_OP_not =0x20, + DW_OP_or =0x21, + DW_OP_plus =0x22, + DW_OP_plus_uconst =0x23, + DW_OP_shl =0x24, + DW_OP_shr =0x25, + DW_OP_shra =0x26, + DW_OP_xor =0x27, + DW_OP_bra =0x28, + DW_OP_eq =0x29, + DW_OP_ge =0x2a, + DW_OP_gt =0x2b, + DW_OP_le =0x2c, + DW_OP_lt =0x2d, + DW_OP_ne =0x2e, + DW_OP_skip =0x2f, + DW_OP_lit0 =0x30, + DW_OP_lit1 =0x31, + DW_OP_lit2 =0x32, + DW_OP_lit3 =0x33, + DW_OP_lit4 =0x34, + DW_OP_lit5 =0x35, + DW_OP_lit6 =0x36, + DW_OP_lit7 =0x37, + DW_OP_lit8 =0x38, + DW_OP_lit9 =0x39, + DW_OP_lit10 =0x3a, + DW_OP_lit11 =0x3b, + DW_OP_lit12 =0x3c, + DW_OP_lit13 =0x3d, + DW_OP_lit14 =0x3e, + DW_OP_lit15 =0x3f, + DW_OP_lit16 =0x40, + DW_OP_lit17 =0x41, + DW_OP_lit18 =0x42, + DW_OP_lit19 =0x43, + DW_OP_lit20 =0x44, + DW_OP_lit21 =0x45, + DW_OP_lit22 =0x46, + DW_OP_lit23 =0x47, + DW_OP_lit24 =0x48, + DW_OP_lit25 =0x49, + DW_OP_lit26 =0x4a, + DW_OP_lit27 =0x4b, + DW_OP_lit28 =0x4c, + DW_OP_lit29 =0x4d, + DW_OP_lit30 =0x4e, + DW_OP_lit31 =0x4f, + DW_OP_reg0 =0x50, + DW_OP_reg1 =0x51, + DW_OP_reg2 =0x52, + DW_OP_reg3 =0x53, + DW_OP_reg4 =0x54, + DW_OP_reg5 =0x55, + DW_OP_reg6 =0x56, + DW_OP_reg7 =0x57, + DW_OP_reg8 =0x58, + DW_OP_reg9 =0x59, + DW_OP_reg10 =0x5a, + DW_OP_reg11 =0x5b, + DW_OP_reg12 =0x5c, + DW_OP_reg13 =0x5d, + DW_OP_reg14 =0x5e, + DW_OP_reg15 =0x5f, + DW_OP_reg16 =0x60, + DW_OP_reg17 =0x61, + DW_OP_reg18 =0x62, + DW_OP_reg19 =0x63, + DW_OP_reg20 =0x64, + DW_OP_reg21 =0x65, + DW_OP_reg22 =0x66, + DW_OP_reg23 =0x67, + DW_OP_reg24 =0x68, + DW_OP_reg25 =0x69, + DW_OP_reg26 =0x6a, + DW_OP_reg27 =0x6b, + DW_OP_reg28 =0x6c, + DW_OP_reg29 =0x6d, + DW_OP_reg30 =0x6e, + DW_OP_reg31 =0x6f, + DW_OP_breg0 =0x70, + DW_OP_breg1 =0x71, + DW_OP_breg2 =0x72, + DW_OP_breg3 =0x73, + DW_OP_breg4 =0x74, + DW_OP_breg5 =0x75, + DW_OP_breg6 =0x76, + DW_OP_breg7 =0x77, + DW_OP_breg8 =0x78, + DW_OP_breg9 =0x79, + DW_OP_breg10 =0x7a, + DW_OP_breg11 =0x7b, + DW_OP_breg12 =0x7c, + DW_OP_breg13 =0x7d, + DW_OP_breg14 =0x7e, + DW_OP_breg15 =0x7f, + DW_OP_breg16 =0x80, + DW_OP_breg17 =0x81, + DW_OP_breg18 =0x82, + DW_OP_breg19 =0x83, + DW_OP_breg20 =0x84, + DW_OP_breg21 =0x85, + DW_OP_breg22 =0x86, + DW_OP_breg23 =0x87, + DW_OP_breg24 =0x88, + DW_OP_breg25 =0x89, + DW_OP_breg26 =0x8a, + DW_OP_breg27 =0x8b, + DW_OP_breg28 =0x8c, + DW_OP_breg29 =0x8d, + DW_OP_breg30 =0x8e, + DW_OP_breg31 =0x8f, + DW_OP_regX =0x90, + DW_OP_fbreg =0x91, + DW_OP_bregX =0x92, + DW_OP_piece =0x93, + DW_OP_deref_size =0x94, + DW_OP_xderef_size =0x95, + DW_OP_nop =0x96, + // DWARF3/DWARF3f + DW_OP_push_object_address =0x97, + DW_OP_call2 =0x98, + DW_OP_call4 =0x99, + DW_OP_call_ref =0x9a, + DW_OP_form_tls_address =0x9b, + DW_OP_call_frame_cfa =0x9c, + DW_OP_bit_piece =0x9d, + DW_OP_lo_user =0xe0, + DW_OP_hi_user =0xff, + // GNU extensions + DW_OP_GNU_push_tls_address =0xe0, + // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. + DW_OP_GNU_addr_index =0xfb, + DW_OP_GNU_const_index =0xfc +}; + +// Section identifiers for DWP files +enum DwarfSectionId { + DW_SECT_INFO = 1, + DW_SECT_TYPES = 2, + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOC = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACINFO = 7, + DW_SECT_MACRO = 8 +}; + +// Source languages. These are values for DW_AT_language. +enum DwarfLanguage + { + DW_LANG_none =0x0000, + DW_LANG_C89 =0x0001, + DW_LANG_C =0x0002, + DW_LANG_Ada83 =0x0003, + DW_LANG_C_plus_plus =0x0004, + DW_LANG_Cobol74 =0x0005, + DW_LANG_Cobol85 =0x0006, + DW_LANG_Fortran77 =0x0007, + DW_LANG_Fortran90 =0x0008, + DW_LANG_Pascal83 =0x0009, + DW_LANG_Modula2 =0x000a, + DW_LANG_Java =0x000b, + DW_LANG_C99 =0x000c, + DW_LANG_Ada95 =0x000d, + DW_LANG_Fortran95 =0x000e, + DW_LANG_PLI =0x000f, + DW_LANG_ObjC =0x0010, + DW_LANG_ObjC_plus_plus =0x0011, + DW_LANG_UPC =0x0012, + DW_LANG_D =0x0013, + DW_LANG_Rust =0x001c, + DW_LANG_Swift =0x001e, + // Implementation-defined language code range. + DW_LANG_lo_user = 0x8000, + DW_LANG_hi_user = 0xffff, + + // Extensions. + + // MIPS assembly language. The GNU toolchain uses this for all + // assembly languages, since there's no generic DW_LANG_ value for that. + // See include/dwarf2.h in the binutils, gdb, or gcc source trees. + DW_LANG_Mips_Assembler =0x8001, + DW_LANG_Upc =0x8765 // Unified Parallel C + }; + +// Inline codes. These are values for DW_AT_inline. +enum DwarfInline { + DW_INL_not_inlined =0x0, + DW_INL_inlined =0x1, + DW_INL_declared_not_inlined =0x2, + DW_INL_declared_inlined =0x3 +}; + +// Call Frame Info instructions. +enum DwarfCFI + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + // Opcodes in this range are reserved for user extensions. + DW_CFA_lo_user = 0x1c, + DW_CFA_hi_user = 0x3f, + + // SGI/MIPS specific. + DW_CFA_MIPS_advance_loc8 = 0x1d, + + // GNU extensions. + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f + }; + +// Exception handling 'z' augmentation letters. +enum DwarfZAugmentationCodes { + // If the CFI augmentation string begins with 'z', then the CIE and FDE + // have an augmentation data area just before the instructions, whose + // contents are determined by the subsequent augmentation letters. + DW_Z_augmentation_start = 'z', + + // If this letter is present in a 'z' augmentation string, the CIE + // augmentation data includes a pointer encoding, and the FDE + // augmentation data includes a language-specific data area pointer, + // represented using that encoding. + DW_Z_has_LSDA = 'L', + + // If this letter is present in a 'z' augmentation string, the CIE + // augmentation data includes a pointer encoding, followed by a pointer + // to a personality routine, represented using that encoding. + DW_Z_has_personality_routine = 'P', + + // If this letter is present in a 'z' augmentation string, the CIE + // augmentation data includes a pointer encoding describing how the FDE's + // initial location, address range, and DW_CFA_set_loc operands are + // encoded. + DW_Z_has_FDE_address_encoding = 'R', + + // If this letter is present in a 'z' augmentation string, then code + // addresses covered by FDEs that cite this CIE are signal delivery + // trampolines. Return addresses of frames in trampolines should not be + // adjusted as described in section 6.4.4 of the DWARF 3 spec. + DW_Z_is_signal_trampoline = 'S' +}; + +// Exception handling frame description pointer formats, as described +// by the Linux Standard Base Core Specification 4.0, section 11.5, +// DWARF Extensions. +enum DwarfPointerEncoding + { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_omit = 0xff, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + // The GNU toolchain sources define this enum value as well, + // simply to help classify the lower nybble values into signed and + // unsigned groups. + DW_EH_PE_signed = 0x08, + + // This is not documented in LSB 4.0, but it is used in both the + // Linux and OS X toolchains. It can be added to any other + // encoding (except DW_EH_PE_aligned), and indicates that the + // encoded value represents the address at which the true address + // is stored, not the true address itself. + DW_EH_PE_indirect = 0x80 + }; + +} // namespace dwarf2reader +#endif // COMMON_DWARF_DWARF2ENUMS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc new file mode 100644 index 0000000000..3e6a3e89f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc @@ -0,0 +1,2815 @@ +// Copyright (c) 2010 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. + +// CFI reader author: Jim Blandy + +// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit, +// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details. + +#include "common/dwarf/dwarf2reader.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/line_state_machine.h" +#include "common/using_std_string.h" + +namespace dwarf2reader { + +CompilationUnit::CompilationUnit(const string& path, + const SectionMap& sections, uint64 offset, + ByteReader* reader, Dwarf2Handler* handler) + : path_(path), offset_from_section_start_(offset), reader_(reader), + sections_(sections), handler_(handler), abbrevs_(), + string_buffer_(NULL), string_buffer_length_(0), + str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), + addr_buffer_(NULL), addr_buffer_length_(0), + is_split_dwarf_(false), dwo_id_(0), dwo_name_(), + skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), + have_checked_for_dwp_(false), dwp_path_(), + dwp_byte_reader_(), dwp_reader_() {} + +// Initialize a compilation unit from a .dwo or .dwp file. +// In this case, we need the .debug_addr section from the +// executable file that contains the corresponding skeleton +// compilation unit. We also inherit the Dwarf2Handler from +// the executable file, and call it as if we were still +// processing the original compilation unit. + +void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, + uint64 addr_buffer_length, + uint64 addr_base, + uint64 ranges_base, + uint64 dwo_id) { + is_split_dwarf_ = true; + addr_buffer_ = addr_buffer; + addr_buffer_length_ = addr_buffer_length; + addr_base_ = addr_base; + ranges_base_ = ranges_base; + skeleton_dwo_id_ = dwo_id; +} + +// Read a DWARF2/3 abbreviation section. +// Each abbrev consists of a abbreviation number, a tag, a byte +// specifying whether the tag has children, and a list of +// attribute/form pairs. +// The list of forms is terminated by a 0 for the attribute, and a +// zero for the form. The entire abbreviation section is terminated +// by a zero for the code. + +void CompilationUnit::ReadAbbrevs() { + if (abbrevs_) + return; + + // First get the debug_abbrev section. ".debug_abbrev" is the name + // recommended in the DWARF spec, and used on Linux; + // "__debug_abbrev" is the name used in Mac OS X Mach-O files. + SectionMap::const_iterator iter = sections_.find(".debug_abbrev"); + if (iter == sections_.end()) + iter = sections_.find("__debug_abbrev"); + assert(iter != sections_.end()); + + abbrevs_ = new std::vector; + abbrevs_->resize(1); + + // The only way to check whether we are reading over the end of the + // buffer would be to first compute the size of the leb128 data by + // reading it, then go back and read it again. + const uint8_t *abbrev_start = iter->second.first + + header_.abbrev_offset; + const uint8_t *abbrevptr = abbrev_start; +#ifndef NDEBUG + const uint64 abbrev_length = iter->second.second - header_.abbrev_offset; +#endif + + while (1) { + CompilationUnit::Abbrev abbrev; + size_t len; + const uint64 number = reader_->ReadUnsignedLEB128(abbrevptr, &len); + + if (number == 0) + break; + abbrev.number = number; + abbrevptr += len; + + assert(abbrevptr < abbrev_start + abbrev_length); + const uint64 tag = reader_->ReadUnsignedLEB128(abbrevptr, &len); + abbrevptr += len; + abbrev.tag = static_cast(tag); + + assert(abbrevptr < abbrev_start + abbrev_length); + abbrev.has_children = reader_->ReadOneByte(abbrevptr); + abbrevptr += 1; + + assert(abbrevptr < abbrev_start + abbrev_length); + + while (1) { + const uint64 nametemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); + abbrevptr += len; + + assert(abbrevptr < abbrev_start + abbrev_length); + const uint64 formtemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); + abbrevptr += len; + if (nametemp == 0 && formtemp == 0) + break; + + const enum DwarfAttribute name = + static_cast(nametemp); + const enum DwarfForm form = static_cast(formtemp); + abbrev.attributes.push_back(std::make_pair(name, form)); + } + assert(abbrev.number == abbrevs_->size()); + abbrevs_->push_back(abbrev); + } +} + +// Skips a single DIE's attributes. +const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start, + const Abbrev& abbrev) { + for (AttributeList::const_iterator i = abbrev.attributes.begin(); + i != abbrev.attributes.end(); + i++) { + start = SkipAttribute(start, i->second); + } + return start; +} + +// Skips a single attribute form's data. +const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, + enum DwarfForm form) { + size_t len; + + switch (form) { + case DW_FORM_indirect: + form = static_cast(reader_->ReadUnsignedLEB128(start, + &len)); + start += len; + return SkipAttribute(start, form); + + case DW_FORM_flag_present: + return start; + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + return start + 1; + case DW_FORM_ref2: + case DW_FORM_data2: + return start + 2; + case DW_FORM_ref4: + case DW_FORM_data4: + return start + 4; + case DW_FORM_ref8: + case DW_FORM_data8: + case DW_FORM_ref_sig8: + return start + 8; + case DW_FORM_string: + return start + strlen(reinterpret_cast(start)) + 1; + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_addr_index: + reader_->ReadUnsignedLEB128(start, &len); + return start + len; + + case DW_FORM_sdata: + reader_->ReadSignedLEB128(start, &len); + return start + len; + case DW_FORM_addr: + return start + reader_->AddressSize(); + case DW_FORM_ref_addr: + // DWARF2 and 3/4 differ on whether ref_addr is address size or + // offset size. + assert(header_.version >= 2); + if (header_.version == 2) { + return start + reader_->AddressSize(); + } else if (header_.version >= 3) { + return start + reader_->OffsetSize(); + } + break; + + case DW_FORM_block1: + return start + 1 + reader_->ReadOneByte(start); + case DW_FORM_block2: + return start + 2 + reader_->ReadTwoBytes(start); + case DW_FORM_block4: + return start + 4 + reader_->ReadFourBytes(start); + case DW_FORM_block: + case DW_FORM_exprloc: { + uint64 size = reader_->ReadUnsignedLEB128(start, &len); + return start + size + len; + } + case DW_FORM_strp: + case DW_FORM_sec_offset: + return start + reader_->OffsetSize(); + } + fprintf(stderr,"Unhandled form type"); + return NULL; +} + +// Read a DWARF2/3 header. +// The header is variable length in DWARF3 (and DWARF2 as extended by +// most compilers), and consists of an length field, a version number, +// the offset in the .debug_abbrev section for our abbrevs, and an +// address size. +void CompilationUnit::ReadHeader() { + const uint8_t *headerptr = buffer_; + size_t initial_length_size; + + assert(headerptr + 4 < buffer_ + buffer_length_); + const uint64 initial_length + = reader_->ReadInitialLength(headerptr, &initial_length_size); + headerptr += initial_length_size; + header_.length = initial_length; + + assert(headerptr + 2 < buffer_ + buffer_length_); + header_.version = reader_->ReadTwoBytes(headerptr); + headerptr += 2; + + assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); + header_.abbrev_offset = reader_->ReadOffset(headerptr); + headerptr += reader_->OffsetSize(); + + // Compare against less than or equal because this may be the last + // section in the file. + assert(headerptr + 1 <= buffer_ + buffer_length_); + header_.address_size = reader_->ReadOneByte(headerptr); + reader_->SetAddressSize(header_.address_size); + headerptr += 1; + + after_header_ = headerptr; + + // This check ensures that we don't have to do checking during the + // reading of DIEs. header_.length does not include the size of the + // initial length. + assert(buffer_ + initial_length_size + header_.length <= + buffer_ + buffer_length_); +} + +uint64 CompilationUnit::Start() { + // First get the debug_info section. ".debug_info" is the name + // recommended in the DWARF spec, and used on Linux; "__debug_info" + // is the name used in Mac OS X Mach-O files. + SectionMap::const_iterator iter = sections_.find(".debug_info"); + if (iter == sections_.end()) + iter = sections_.find("__debug_info"); + assert(iter != sections_.end()); + + // Set up our buffer + buffer_ = iter->second.first + offset_from_section_start_; + buffer_length_ = iter->second.second - offset_from_section_start_; + + // Read the header + ReadHeader(); + + // Figure out the real length from the end of the initial length to + // the end of the compilation unit, since that is the value we + // return. + uint64 ourlength = header_.length; + if (reader_->OffsetSize() == 8) + ourlength += 12; + else + ourlength += 4; + + // See if the user wants this compilation unit, and if not, just return. + if (!handler_->StartCompilationUnit(offset_from_section_start_, + reader_->AddressSize(), + reader_->OffsetSize(), + header_.length, + header_.version)) + return ourlength; + + // Otherwise, continue by reading our abbreviation entries. + ReadAbbrevs(); + + // Set the string section if we have one. ".debug_str" is the name + // recommended in the DWARF spec, and used on Linux; "__debug_str" + // is the name used in Mac OS X Mach-O files. + iter = sections_.find(".debug_str"); + if (iter == sections_.end()) + iter = sections_.find("__debug_str"); + if (iter != sections_.end()) { + string_buffer_ = iter->second.first; + string_buffer_length_ = iter->second.second; + } + + // Set the string offsets section if we have one. + iter = sections_.find(".debug_str_offsets"); + if (iter != sections_.end()) { + str_offsets_buffer_ = iter->second.first; + str_offsets_buffer_length_ = iter->second.second; + } + + // Set the address section if we have one. + iter = sections_.find(".debug_addr"); + if (iter != sections_.end()) { + addr_buffer_ = iter->second.first; + addr_buffer_length_ = iter->second.second; + } + + // Now that we have our abbreviations, start processing DIE's. + ProcessDIEs(); + + // If this is a skeleton compilation unit generated with split DWARF, + // and the client needs the full debug info, we need to find the full + // compilation unit in a .dwo or .dwp file. + if (!is_split_dwarf_ + && dwo_name_ != NULL + && handler_->NeedSplitDebugInfo()) + ProcessSplitDwarf(); + + return ourlength; +} + +// If one really wanted, you could merge SkipAttribute and +// ProcessAttribute +// This is all boring data manipulation and calling of the handler. +const uint8_t *CompilationUnit::ProcessAttribute( + uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr, + enum DwarfForm form) { + size_t len; + + switch (form) { + // DW_FORM_indirect is never used because it is such a space + // waster. + case DW_FORM_indirect: + form = static_cast(reader_->ReadUnsignedLEB128(start, + &len)); + start += len; + return ProcessAttribute(dieoffset, start, attr, form); + + case DW_FORM_flag_present: + ProcessAttributeUnsigned(dieoffset, attr, form, 1); + return start; + case DW_FORM_data1: + case DW_FORM_flag: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadOneByte(start)); + return start + 1; + case DW_FORM_data2: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadTwoBytes(start)); + return start + 2; + case DW_FORM_data4: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadFourBytes(start)); + return start + 4; + case DW_FORM_data8: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadEightBytes(start)); + return start + 8; + case DW_FORM_string: { + const char *str = reinterpret_cast(start); + ProcessAttributeString(dieoffset, attr, form, str); + return start + strlen(str) + 1; + } + case DW_FORM_udata: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadUnsignedLEB128(start, &len)); + return start + len; + + case DW_FORM_sdata: + ProcessAttributeSigned(dieoffset, attr, form, + reader_->ReadSignedLEB128(start, &len)); + return start + len; + case DW_FORM_addr: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadAddress(start)); + return start + reader_->AddressSize(); + case DW_FORM_sec_offset: + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadOffset(start)); + return start + reader_->OffsetSize(); + + case DW_FORM_ref1: + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadOneByte(start) + + offset_from_section_start_); + return start + 1; + case DW_FORM_ref2: + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadTwoBytes(start) + + offset_from_section_start_); + return start + 2; + case DW_FORM_ref4: + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadFourBytes(start) + + offset_from_section_start_); + return start + 4; + case DW_FORM_ref8: + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadEightBytes(start) + + offset_from_section_start_); + return start + 8; + case DW_FORM_ref_udata: + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadUnsignedLEB128(start, + &len) + + offset_from_section_start_); + return start + len; + case DW_FORM_ref_addr: + // DWARF2 and 3/4 differ on whether ref_addr is address size or + // offset size. + assert(header_.version >= 2); + if (header_.version == 2) { + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadAddress(start)); + return start + reader_->AddressSize(); + } else if (header_.version >= 3) { + handler_->ProcessAttributeReference(dieoffset, attr, form, + reader_->ReadOffset(start)); + return start + reader_->OffsetSize(); + } + break; + case DW_FORM_ref_sig8: + handler_->ProcessAttributeSignature(dieoffset, attr, form, + reader_->ReadEightBytes(start)); + return start + 8; + + case DW_FORM_block1: { + uint64 datalen = reader_->ReadOneByte(start); + handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1, + datalen); + return start + 1 + datalen; + } + case DW_FORM_block2: { + uint64 datalen = reader_->ReadTwoBytes(start); + handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 2, + datalen); + return start + 2 + datalen; + } + case DW_FORM_block4: { + uint64 datalen = reader_->ReadFourBytes(start); + handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 4, + datalen); + return start + 4 + datalen; + } + case DW_FORM_block: + case DW_FORM_exprloc: { + uint64 datalen = reader_->ReadUnsignedLEB128(start, &len); + handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len, + datalen); + return start + datalen + len; + } + case DW_FORM_strp: { + assert(string_buffer_ != NULL); + + const uint64 offset = reader_->ReadOffset(start); + assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); + + const char *str = reinterpret_cast(string_buffer_ + offset); + ProcessAttributeString(dieoffset, attr, form, str); + return start + reader_->OffsetSize(); + } + + case DW_FORM_GNU_str_index: { + uint64 str_index = reader_->ReadUnsignedLEB128(start, &len); + const uint8_t* offset_ptr = + str_offsets_buffer_ + str_index * reader_->OffsetSize(); + const uint64 offset = reader_->ReadOffset(offset_ptr); + if (offset >= string_buffer_length_) { + return NULL; + } + + const char* str = reinterpret_cast(string_buffer_) + offset; + ProcessAttributeString(dieoffset, attr, form, str); + return start + len; + break; + } + case DW_FORM_GNU_addr_index: { + uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len); + const uint8_t* addr_ptr = + addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); + ProcessAttributeUnsigned(dieoffset, attr, form, + reader_->ReadAddress(addr_ptr)); + return start + len; + } + } + fprintf(stderr, "Unhandled form type\n"); + return NULL; +} + +const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset, + const uint8_t *start, + const Abbrev& abbrev) { + for (AttributeList::const_iterator i = abbrev.attributes.begin(); + i != abbrev.attributes.end(); + i++) { + start = ProcessAttribute(dieoffset, start, i->first, i->second); + } + + // If this is a compilation unit in a split DWARF object, verify that + // the dwo_id matches. If it does not match, we will ignore this + // compilation unit. + if (abbrev.tag == DW_TAG_compile_unit + && is_split_dwarf_ + && dwo_id_ != skeleton_dwo_id_) { + return NULL; + } + + return start; +} + +void CompilationUnit::ProcessDIEs() { + const uint8_t *dieptr = after_header_; + size_t len; + + // lengthstart is the place the length field is based on. + // It is the point in the header after the initial length field + const uint8_t *lengthstart = buffer_; + + // In 64 bit dwarf, the initial length is 12 bytes, because of the + // 0xffffffff at the start. + if (reader_->OffsetSize() == 8) + lengthstart += 12; + else + lengthstart += 4; + + std::stack die_stack; + + while (dieptr < (lengthstart + header_.length)) { + // We give the user the absolute offset from the beginning of + // debug_info, since they need it to deal with ref_addr forms. + uint64 absolute_offset = (dieptr - buffer_) + offset_from_section_start_; + + uint64 abbrev_num = reader_->ReadUnsignedLEB128(dieptr, &len); + + dieptr += len; + + // Abbrev == 0 represents the end of a list of children, or padding + // at the end of the compilation unit. + if (abbrev_num == 0) { + if (die_stack.size() == 0) + // If it is padding, then we are done with the compilation unit's DIEs. + return; + const uint64 offset = die_stack.top(); + die_stack.pop(); + handler_->EndDIE(offset); + continue; + } + + const Abbrev& abbrev = abbrevs_->at(static_cast(abbrev_num)); + const enum DwarfTag tag = abbrev.tag; + if (!handler_->StartDIE(absolute_offset, tag)) { + dieptr = SkipDIE(dieptr, abbrev); + } else { + dieptr = ProcessDIE(absolute_offset, dieptr, abbrev); + } + + if (abbrev.has_children) { + die_stack.push(absolute_offset); + } else { + handler_->EndDIE(absolute_offset); + } + } +} + +// Check for a valid ELF file and return the Address size. +// Returns 0 if not a valid ELF file. +inline int GetElfWidth(const ElfReader& elf) { + if (elf.IsElf32File()) + return 4; + if (elf.IsElf64File()) + return 8; + return 0; +} + +void CompilationUnit::ProcessSplitDwarf() { + struct stat statbuf; + if (!have_checked_for_dwp_) { + // Look for a .dwp file in the same directory as the executable. + have_checked_for_dwp_ = true; + string dwp_suffix(".dwp"); + dwp_path_ = path_ + dwp_suffix; + if (stat(dwp_path_.c_str(), &statbuf) != 0) { + // Fall back to a split .debug file in the same directory. + string debug_suffix(".debug"); + dwp_path_ = path_; + size_t found = path_.rfind(debug_suffix); + if (found + debug_suffix.length() == path_.length()) + dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); + } + if (stat(dwp_path_.c_str(), &statbuf) == 0) { + ElfReader* elf = new ElfReader(dwp_path_); + int width = GetElfWidth(*elf); + if (width != 0) { + dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); + dwp_byte_reader_->SetAddressSize(width); + dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); + dwp_reader_->Initialize(); + } else { + delete elf; + } + } + } + bool found_in_dwp = false; + if (dwp_reader_) { + // If we have a .dwp file, read the debug sections for the requested CU. + SectionMap sections; + dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); + if (!sections.empty()) { + found_in_dwp = true; + CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, + dwp_byte_reader_.get(), handler_); + dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, + ranges_base_, dwo_id_); + dwp_comp_unit.Start(); + } + } + if (!found_in_dwp) { + // If no .dwp file, try to open the .dwo file. + if (stat(dwo_name_, &statbuf) == 0) { + ElfReader elf(dwo_name_); + int width = GetElfWidth(elf); + if (width != 0) { + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(width); + SectionMap sections; + ReadDebugSectionsFromDwo(&elf, §ions); + CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, + handler_); + dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, + addr_base_, ranges_base_, dwo_id_); + dwo_comp_unit.Start(); + } + } + } +} + +void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, + SectionMap* sections) { + static const char* const section_names[] = { + ".debug_abbrev", + ".debug_info", + ".debug_str_offsets", + ".debug_str" + }; + for (unsigned int i = 0u; + i < sizeof(section_names)/sizeof(*(section_names)); ++i) { + string base_name = section_names[i]; + string dwo_name = base_name + ".dwo"; + size_t section_size; + const char* section_data = elf_reader->GetSectionByName(dwo_name, + §ion_size); + if (section_data != NULL) + sections->insert(std::make_pair( + base_name, std::make_pair( + reinterpret_cast(section_data), + section_size))); + } +} + +DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) + : elf_reader_(elf_reader), byte_reader_(byte_reader), + cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL), + string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0), + nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL), + offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL), + abbrev_size_(0), info_data_(NULL), info_size_(0), + str_offsets_data_(NULL), str_offsets_size_(0) {} + +DwpReader::~DwpReader() { + if (elf_reader_) delete elf_reader_; +} + +void DwpReader::Initialize() { + cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", + &cu_index_size_); + if (cu_index_ == NULL) { + return; + } + // The .debug_str.dwo section is shared by all CUs in the file. + string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo", + &string_buffer_size_); + + version_ = byte_reader_.ReadFourBytes( + reinterpret_cast(cu_index_)); + + if (version_ == 1) { + nslots_ = byte_reader_.ReadFourBytes( + reinterpret_cast(cu_index_) + + 3 * sizeof(uint32)); + phash_ = cu_index_ + 4 * sizeof(uint32); + pindex_ = phash_ + nslots_ * sizeof(uint64); + shndx_pool_ = pindex_ + nslots_ * sizeof(uint32); + if (shndx_pool_ >= cu_index_ + cu_index_size_) { + version_ = 0; + } + } else if (version_ == 2) { + ncolumns_ = byte_reader_.ReadFourBytes( + reinterpret_cast(cu_index_) + sizeof(uint32)); + nunits_ = byte_reader_.ReadFourBytes( + reinterpret_cast(cu_index_) + 2 * sizeof(uint32)); + nslots_ = byte_reader_.ReadFourBytes( + reinterpret_cast(cu_index_) + 3 * sizeof(uint32)); + phash_ = cu_index_ + 4 * sizeof(uint32); + pindex_ = phash_ + nslots_ * sizeof(uint64); + offset_table_ = pindex_ + nslots_ * sizeof(uint32); + size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32); + abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo", + &abbrev_size_); + info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); + str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", + &str_offsets_size_); + if (size_table_ >= cu_index_ + cu_index_size_) { + version_ = 0; + } + } +} + +void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id, + SectionMap* sections) { + if (version_ == 1) { + int slot = LookupCU(dwo_id); + if (slot == -1) { + return; + } + + // The index table points to the section index pool, where we + // can read a list of section indexes for the debug sections + // for the CU whose dwo_id we are looking for. + int index = byte_reader_.ReadFourBytes( + reinterpret_cast(pindex_) + + slot * sizeof(uint32)); + const char* shndx_list = shndx_pool_ + index * sizeof(uint32); + for (;;) { + if (shndx_list >= cu_index_ + cu_index_size_) { + version_ = 0; + return; + } + unsigned int shndx = byte_reader_.ReadFourBytes( + reinterpret_cast(shndx_list)); + shndx_list += sizeof(uint32); + if (shndx == 0) + break; + const char* section_name = elf_reader_->GetSectionName(shndx); + size_t section_size; + const char* section_data; + // We're only interested in these four debug sections. + // The section names in the .dwo file end with ".dwo", but we + // add them to the sections table with their normal names. + if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) { + section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); + sections->insert(std::make_pair( + ".debug_abbrev", + std::make_pair(reinterpret_cast (section_data), + section_size))); + } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) { + section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); + sections->insert(std::make_pair( + ".debug_info", + std::make_pair(reinterpret_cast (section_data), + section_size))); + } else if (!strncmp(section_name, ".debug_str_offsets", + strlen(".debug_str_offsets"))) { + section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); + sections->insert(std::make_pair( + ".debug_str_offsets", + std::make_pair(reinterpret_cast (section_data), + section_size))); + } + } + sections->insert(std::make_pair( + ".debug_str", + std::make_pair(reinterpret_cast (string_buffer_), + string_buffer_size_))); + } else if (version_ == 2) { + uint32 index = LookupCUv2(dwo_id); + if (index == 0) { + return; + } + + // The index points to a row in each of the section offsets table + // and the section size table, where we can read the offsets and sizes + // of the contributions to each debug section from the CU whose dwo_id + // we are looking for. Row 0 of the section offsets table has the + // section ids for each column of the table. The size table begins + // with row 1. + const char* id_row = offset_table_; + const char* offset_row = offset_table_ + + index * ncolumns_ * sizeof(uint32); + const char* size_row = + size_table_ + (index - 1) * ncolumns_ * sizeof(uint32); + if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) { + version_ = 0; + return; + } + for (unsigned int col = 0u; col < ncolumns_; ++col) { + uint32 section_id = + byte_reader_.ReadFourBytes(reinterpret_cast(id_row) + + col * sizeof(uint32)); + uint32 offset = byte_reader_.ReadFourBytes( + reinterpret_cast(offset_row) + + col * sizeof(uint32)); + uint32 size = byte_reader_.ReadFourBytes( + reinterpret_cast(size_row) + col * sizeof(uint32)); + if (section_id == DW_SECT_ABBREV) { + sections->insert(std::make_pair( + ".debug_abbrev", + std::make_pair(reinterpret_cast (abbrev_data_) + + offset, size))); + } else if (section_id == DW_SECT_INFO) { + sections->insert(std::make_pair( + ".debug_info", + std::make_pair(reinterpret_cast (info_data_) + + offset, size))); + } else if (section_id == DW_SECT_STR_OFFSETS) { + sections->insert(std::make_pair( + ".debug_str_offsets", + std::make_pair(reinterpret_cast (str_offsets_data_) + + offset, size))); + } + } + sections->insert(std::make_pair( + ".debug_str", + std::make_pair(reinterpret_cast (string_buffer_), + string_buffer_size_))); + } +} + +int DwpReader::LookupCU(uint64 dwo_id) { + uint32 slot = static_cast(dwo_id) & (nslots_ - 1); + uint64 probe = byte_reader_.ReadEightBytes( + reinterpret_cast(phash_) + slot * sizeof(uint64)); + if (probe != 0 && probe != dwo_id) { + uint32 secondary_hash = + (static_cast(dwo_id >> 32) & (nslots_ - 1)) | 1; + do { + slot = (slot + secondary_hash) & (nslots_ - 1); + probe = byte_reader_.ReadEightBytes( + reinterpret_cast(phash_) + slot * sizeof(uint64)); + } while (probe != 0 && probe != dwo_id); + } + if (probe == 0) + return -1; + return slot; +} + +uint32 DwpReader::LookupCUv2(uint64 dwo_id) { + uint32 slot = static_cast(dwo_id) & (nslots_ - 1); + uint64 probe = byte_reader_.ReadEightBytes( + reinterpret_cast(phash_) + slot * sizeof(uint64)); + uint32 index = byte_reader_.ReadFourBytes( + reinterpret_cast(pindex_) + slot * sizeof(uint32)); + if (index != 0 && probe != dwo_id) { + uint32 secondary_hash = + (static_cast(dwo_id >> 32) & (nslots_ - 1)) | 1; + do { + slot = (slot + secondary_hash) & (nslots_ - 1); + probe = byte_reader_.ReadEightBytes( + reinterpret_cast(phash_) + slot * sizeof(uint64)); + index = byte_reader_.ReadFourBytes( + reinterpret_cast(pindex_) + slot * sizeof(uint32)); + } while (index != 0 && probe != dwo_id); + } + return index; +} + +LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length, + ByteReader* reader, LineInfoHandler* handler): + handler_(handler), reader_(reader), buffer_(buffer) { +#ifndef NDEBUG + buffer_length_ = buffer_length; +#endif + header_.std_opcode_lengths = NULL; +} + +uint64 LineInfo::Start() { + ReadHeader(); + ReadLines(); + return after_header_ - buffer_; +} + +// The header for a debug_line section is mildly complicated, because +// the line info is very tightly encoded. +void LineInfo::ReadHeader() { + const uint8_t *lineptr = buffer_; + size_t initial_length_size; + + const uint64 initial_length + = reader_->ReadInitialLength(lineptr, &initial_length_size); + + lineptr += initial_length_size; + header_.total_length = initial_length; + assert(buffer_ + initial_length_size + header_.total_length <= + buffer_ + buffer_length_); + + // Address size *must* be set by CU ahead of time. + assert(reader_->AddressSize() != 0); + + header_.version = reader_->ReadTwoBytes(lineptr); + lineptr += 2; + + header_.prologue_length = reader_->ReadOffset(lineptr); + lineptr += reader_->OffsetSize(); + + header_.min_insn_length = reader_->ReadOneByte(lineptr); + lineptr += 1; + + if (header_.version >= 4) { + __attribute__((unused)) uint8 max_ops_per_insn = + reader_->ReadOneByte(lineptr); + ++lineptr; + assert(max_ops_per_insn == 1); + } + + header_.default_is_stmt = reader_->ReadOneByte(lineptr); + lineptr += 1; + + header_.line_base = *reinterpret_cast(lineptr); + lineptr += 1; + + header_.line_range = reader_->ReadOneByte(lineptr); + lineptr += 1; + + header_.opcode_base = reader_->ReadOneByte(lineptr); + lineptr += 1; + + header_.std_opcode_lengths = new std::vector; + header_.std_opcode_lengths->resize(header_.opcode_base + 1); + (*header_.std_opcode_lengths)[0] = 0; + for (int i = 1; i < header_.opcode_base; i++) { + (*header_.std_opcode_lengths)[i] = reader_->ReadOneByte(lineptr); + lineptr += 1; + } + + // It is legal for the directory entry table to be empty. + if (*lineptr) { + uint32 dirindex = 1; + while (*lineptr) { + const char *dirname = reinterpret_cast(lineptr); + handler_->DefineDir(dirname, dirindex); + lineptr += strlen(dirname) + 1; + dirindex++; + } + } + lineptr++; + + // It is also legal for the file entry table to be empty. + if (*lineptr) { + uint32 fileindex = 1; + size_t len; + while (*lineptr) { + const char *filename = reinterpret_cast(lineptr); + lineptr += strlen(filename) + 1; + + uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64 mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + + uint64 filelength = reader_->ReadUnsignedLEB128(lineptr, &len); + lineptr += len; + handler_->DefineFile(filename, fileindex, static_cast(dirindex), + mod_time, filelength); + fileindex++; + } + } + lineptr++; + + after_header_ = lineptr; +} + +/* static */ +bool LineInfo::ProcessOneOpcode(ByteReader* reader, + LineInfoHandler* handler, + const struct LineInfoHeader &header, + const uint8_t *start, + struct LineStateMachine* lsm, + size_t* len, + uintptr pc, + bool *lsm_passes_pc) { + size_t oplen = 0; + size_t templen; + uint8 opcode = reader->ReadOneByte(start); + oplen++; + start++; + + // If the opcode is great than the opcode_base, it is a special + // opcode. Most line programs consist mainly of special opcodes. + if (opcode >= header.opcode_base) { + opcode -= header.opcode_base; + const int64 advance_address = (opcode / header.line_range) + * header.min_insn_length; + const int32 advance_line = (opcode % header.line_range) + + header.line_base; + + // Check if the lsm passes "pc". If so, mark it as passed. + if (lsm_passes_pc && + lsm->address <= pc && pc < lsm->address + advance_address) { + *lsm_passes_pc = true; + } + + lsm->address += advance_address; + lsm->line_num += advance_line; + lsm->basic_block = true; + *len = oplen; + return true; + } + + // Otherwise, we have the regular opcodes + switch (opcode) { + case DW_LNS_copy: { + lsm->basic_block = false; + *len = oplen; + return true; + } + + case DW_LNS_advance_pc: { + uint64 advance_address = reader->ReadUnsignedLEB128(start, &templen); + oplen += templen; + + // Check if the lsm passes "pc". If so, mark it as passed. + if (lsm_passes_pc && lsm->address <= pc && + pc < lsm->address + header.min_insn_length * advance_address) { + *lsm_passes_pc = true; + } + + lsm->address += header.min_insn_length * advance_address; + } + break; + case DW_LNS_advance_line: { + const int64 advance_line = reader->ReadSignedLEB128(start, &templen); + oplen += templen; + lsm->line_num += static_cast(advance_line); + + // With gcc 4.2.1, we can get the line_no here for the first time + // since DW_LNS_advance_line is called after DW_LNE_set_address is + // called. So we check if the lsm passes "pc" here, not in + // DW_LNE_set_address. + if (lsm_passes_pc && lsm->address == pc) { + *lsm_passes_pc = true; + } + } + break; + case DW_LNS_set_file: { + const uint64 fileno = reader->ReadUnsignedLEB128(start, &templen); + oplen += templen; + lsm->file_num = static_cast(fileno); + } + break; + case DW_LNS_set_column: { + const uint64 colno = reader->ReadUnsignedLEB128(start, &templen); + oplen += templen; + lsm->column_num = static_cast(colno); + } + break; + case DW_LNS_negate_stmt: { + lsm->is_stmt = !lsm->is_stmt; + } + break; + case DW_LNS_set_basic_block: { + lsm->basic_block = true; + } + break; + case DW_LNS_fixed_advance_pc: { + const uint16 advance_address = reader->ReadTwoBytes(start); + oplen += 2; + + // Check if the lsm passes "pc". If so, mark it as passed. + if (lsm_passes_pc && + lsm->address <= pc && pc < lsm->address + advance_address) { + *lsm_passes_pc = true; + } + + lsm->address += advance_address; + } + break; + case DW_LNS_const_add_pc: { + const int64 advance_address = header.min_insn_length + * ((255 - header.opcode_base) + / header.line_range); + + // Check if the lsm passes "pc". If so, mark it as passed. + if (lsm_passes_pc && + lsm->address <= pc && pc < lsm->address + advance_address) { + *lsm_passes_pc = true; + } + + lsm->address += advance_address; + } + break; + case DW_LNS_extended_op: { + const uint64 extended_op_len = reader->ReadUnsignedLEB128(start, + &templen); + start += templen; + oplen += templen + extended_op_len; + + const uint64 extended_op = reader->ReadOneByte(start); + start++; + + switch (extended_op) { + case DW_LNE_end_sequence: { + lsm->end_sequence = true; + *len = oplen; + return true; + } + break; + case DW_LNE_set_address: { + // With gcc 4.2.1, we cannot tell the line_no here since + // DW_LNE_set_address is called before DW_LNS_advance_line is + // called. So we do not check if the lsm passes "pc" here. See + // also the comment in DW_LNS_advance_line. + uint64 address = reader->ReadAddress(start); + lsm->address = address; + } + break; + case DW_LNE_define_file: { + const char *filename = reinterpret_cast(start); + + templen = strlen(filename) + 1; + start += templen; + + uint64 dirindex = reader->ReadUnsignedLEB128(start, &templen); + oplen += templen; + + const uint64 mod_time = reader->ReadUnsignedLEB128(start, + &templen); + oplen += templen; + + const uint64 filelength = reader->ReadUnsignedLEB128(start, + &templen); + oplen += templen; + + if (handler) { + handler->DefineFile(filename, -1, static_cast(dirindex), + mod_time, filelength); + } + } + break; + } + } + break; + + default: { + // Ignore unknown opcode silently + if (header.std_opcode_lengths) { + for (int i = 0; i < (*header.std_opcode_lengths)[opcode]; i++) { + reader->ReadUnsignedLEB128(start, &templen); + start += templen; + oplen += templen; + } + } + } + break; + } + *len = oplen; + return false; +} + +void LineInfo::ReadLines() { + struct LineStateMachine lsm; + + // lengthstart is the place the length field is based on. + // It is the point in the header after the initial length field + const uint8_t *lengthstart = buffer_; + + // In 64 bit dwarf, the initial length is 12 bytes, because of the + // 0xffffffff at the start. + if (reader_->OffsetSize() == 8) + lengthstart += 12; + else + lengthstart += 4; + + const uint8_t *lineptr = after_header_; + lsm.Reset(header_.default_is_stmt); + + // The LineInfoHandler interface expects each line's length along + // with its address, but DWARF only provides addresses (sans + // length), and an end-of-sequence address; one infers the length + // from the next address. So we report a line only when we get the + // next line's address, or the end-of-sequence address. + bool have_pending_line = false; + uint64 pending_address = 0; + uint32 pending_file_num = 0, pending_line_num = 0, pending_column_num = 0; + + while (lineptr < lengthstart + header_.total_length) { + size_t oplength; + bool add_row = ProcessOneOpcode(reader_, handler_, header_, + lineptr, &lsm, &oplength, (uintptr)-1, + NULL); + if (add_row) { + if (have_pending_line) + handler_->AddLine(pending_address, lsm.address - pending_address, + pending_file_num, pending_line_num, + pending_column_num); + if (lsm.end_sequence) { + lsm.Reset(header_.default_is_stmt); + have_pending_line = false; + } else { + pending_address = lsm.address; + pending_file_num = lsm.file_num; + pending_line_num = lsm.line_num; + pending_column_num = lsm.column_num; + have_pending_line = true; + } + } + lineptr += oplength; + } + + after_header_ = lengthstart + header_.total_length; +} + +RangeListReader::RangeListReader(const uint8_t *buffer, uint64 size, + ByteReader *reader, RangeListHandler *handler) + : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } + +bool RangeListReader::ReadRangeList(uint64 offset) { + const uint64 max_address = + (reader_->AddressSize() == 4) ? 0xffffffffUL + : 0xffffffffffffffffULL; + const uint64 entry_size = reader_->AddressSize() * 2; + bool list_end = false; + + do { + if (offset > size_ - entry_size) { + return false; // Invalid range detected + } + + uint64 start_address = reader_->ReadAddress(buffer_ + offset); + uint64 end_address = + reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); + + if (start_address == max_address) { // Base address selection + handler_->SetBaseAddress(end_address); + } else if (start_address == 0 && end_address == 0) { // End-of-list + handler_->Finish(); + list_end = true; + } else { // Add a range entry + handler_->AddRange(start_address, end_address); + } + + offset += entry_size; + } while (!list_end); + + return true; +} + +// A DWARF rule for recovering the address or value of a register, or +// computing the canonical frame address. There is one subclass of this for +// each '*Rule' member function in CallFrameInfo::Handler. +// +// It's annoying that we have to handle Rules using pointers (because +// the concrete instances can have an arbitrary size). They're small, +// so it would be much nicer if we could just handle them by value +// instead of fretting about ownership and destruction. +// +// It seems like all these could simply be instances of std::tr1::bind, +// except that we need instances to be EqualityComparable, too. +// +// This could logically be nested within State, but then the qualified names +// get horrendous. +class CallFrameInfo::Rule { + public: + virtual ~Rule() { } + + // Tell HANDLER that, at ADDRESS in the program, REG can be recovered using + // this rule. If REG is kCFARegister, then this rule describes how to compute + // the canonical frame address. Return what the HANDLER member function + // returned. + virtual bool Handle(Handler *handler, + uint64 address, int reg) const = 0; + + // Equality on rules. We use these to decide which rules we need + // to report after a DW_CFA_restore_state instruction. + virtual bool operator==(const Rule &rhs) const = 0; + + bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } + + // Return a pointer to a copy of this rule. + virtual Rule *Copy() const = 0; + + // If this is a base+offset rule, change its base register to REG. + // Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.) + virtual void SetBaseRegister(unsigned reg) { } + + // If this is a base+offset rule, change its offset to OFFSET. Otherwise, + // do nothing. (Ugly, but required for DW_CFA_def_cfa_offset.) + virtual void SetOffset(long long offset) { } +}; + +// Rule: the value the register had in the caller cannot be recovered. +class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { + public: + UndefinedRule() { } + ~UndefinedRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->UndefinedRule(address, reg); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const UndefinedRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs != NULL); + } + Rule *Copy() const { return new UndefinedRule(*this); } +}; + +// Rule: the register's value is the same as that it had in the caller. +class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { + public: + SameValueRule() { } + ~SameValueRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->SameValueRule(address, reg); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const SameValueRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs != NULL); + } + Rule *Copy() const { return new SameValueRule(*this); } +}; + +// Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER +// may be CallFrameInfo::Handler::kCFARegister. +class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { + public: + OffsetRule(int base_register, long offset) + : base_register_(base_register), offset_(offset) { } + ~OffsetRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->OffsetRule(address, reg, base_register_, offset_); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const OffsetRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs && + base_register_ == our_rhs->base_register_ && + offset_ == our_rhs->offset_); + } + Rule *Copy() const { return new OffsetRule(*this); } + // We don't actually need SetBaseRegister or SetOffset here, since they + // are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it + // doesn't make sense to use OffsetRule for computing the CFA: it + // computes the address at which a register is saved, not a value. + private: + int base_register_; + long offset_; +}; + +// Rule: the value the register had in the caller is the value of +// BASE_REGISTER plus offset. BASE_REGISTER may be +// CallFrameInfo::Handler::kCFARegister. +class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { + public: + ValOffsetRule(int base_register, long offset) + : base_register_(base_register), offset_(offset) { } + ~ValOffsetRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->ValOffsetRule(address, reg, base_register_, offset_); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const ValOffsetRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs && + base_register_ == our_rhs->base_register_ && + offset_ == our_rhs->offset_); + } + Rule *Copy() const { return new ValOffsetRule(*this); } + void SetBaseRegister(unsigned reg) { base_register_ = reg; } + void SetOffset(long long offset) { offset_ = offset; } + private: + int base_register_; + long offset_; +}; + +// Rule: the register has been saved in another register REGISTER_NUMBER_. +class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { + public: + explicit RegisterRule(int register_number) + : register_number_(register_number) { } + ~RegisterRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->RegisterRule(address, reg, register_number_); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const RegisterRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs && register_number_ == our_rhs->register_number_); + } + Rule *Copy() const { return new RegisterRule(*this); } + private: + int register_number_; +}; + +// Rule: EXPRESSION evaluates to the address at which the register is saved. +class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { + public: + explicit ExpressionRule(const string &expression) + : expression_(expression) { } + ~ExpressionRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->ExpressionRule(address, reg, expression_); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const ExpressionRule *our_rhs = dynamic_cast(&rhs); + return (our_rhs && expression_ == our_rhs->expression_); + } + Rule *Copy() const { return new ExpressionRule(*this); } + private: + string expression_; +}; + +// Rule: EXPRESSION evaluates to the address at which the register is saved. +class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { + public: + explicit ValExpressionRule(const string &expression) + : expression_(expression) { } + ~ValExpressionRule() { } + bool Handle(Handler *handler, uint64 address, int reg) const { + return handler->ValExpressionRule(address, reg, expression_); + } + bool operator==(const Rule &rhs) const { + // dynamic_cast is allowed by the Google C++ Style Guide, if the use has + // been carefully considered; cheap RTTI-like workarounds are forbidden. + const ValExpressionRule *our_rhs = + dynamic_cast(&rhs); + return (our_rhs && expression_ == our_rhs->expression_); + } + Rule *Copy() const { return new ValExpressionRule(*this); } + private: + string expression_; +}; + +// A map from register numbers to rules. +class CallFrameInfo::RuleMap { + public: + RuleMap() : cfa_rule_(NULL) { } + RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } + ~RuleMap() { Clear(); } + + RuleMap &operator=(const RuleMap &rhs); + + // Set the rule for computing the CFA to RULE. Take ownership of RULE. + void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; } + + // Return the current CFA rule. Unlike RegisterRule, this RuleMap retains + // ownership of the rule. We use this for DW_CFA_def_cfa_offset and + // DW_CFA_def_cfa_register, and for detecting references to the CFA before + // a rule for it has been established. + Rule *CFARule() const { return cfa_rule_; } + + // Return the rule for REG, or NULL if there is none. The caller takes + // ownership of the result. + Rule *RegisterRule(int reg) const; + + // Set the rule for computing REG to RULE. Take ownership of RULE. + void SetRegisterRule(int reg, Rule *rule); + + // Make all the appropriate calls to HANDLER as if we were changing from + // this RuleMap to NEW_RULES at ADDRESS. We use this to implement + // DW_CFA_restore_state, where lots of rules can change simultaneously. + // Return true if all handlers returned true; otherwise, return false. + bool HandleTransitionTo(Handler *handler, uint64 address, + const RuleMap &new_rules) const; + + private: + // A map from register numbers to Rules. + typedef std::map RuleByNumber; + + // Remove all register rules and clear cfa_rule_. + void Clear(); + + // The rule for computing the canonical frame address. This RuleMap owns + // this rule. + Rule *cfa_rule_; + + // A map from register numbers to postfix expressions to recover + // their values. This RuleMap owns the Rules the map refers to. + RuleByNumber registers_; +}; + +CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { + Clear(); + // Since each map owns the rules it refers to, assignment must copy them. + if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy(); + for (RuleByNumber::const_iterator it = rhs.registers_.begin(); + it != rhs.registers_.end(); it++) + registers_[it->first] = it->second->Copy(); + return *this; +} + +CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { + assert(reg != Handler::kCFARegister); + RuleByNumber::const_iterator it = registers_.find(reg); + if (it != registers_.end()) + return it->second->Copy(); + else + return NULL; +} + +void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { + assert(reg != Handler::kCFARegister); + assert(rule); + Rule **slot = ®isters_[reg]; + delete *slot; + *slot = rule; +} + +bool CallFrameInfo::RuleMap::HandleTransitionTo( + Handler *handler, + uint64 address, + const RuleMap &new_rules) const { + // Transition from cfa_rule_ to new_rules.cfa_rule_. + if (cfa_rule_ && new_rules.cfa_rule_) { + if (*cfa_rule_ != *new_rules.cfa_rule_ && + !new_rules.cfa_rule_->Handle(handler, address, + Handler::kCFARegister)) + return false; + } else if (cfa_rule_) { + // this RuleMap has a CFA rule but new_rules doesn't. + // CallFrameInfo::Handler has no way to handle this --- and shouldn't; + // it's garbage input. The instruction interpreter should have + // detected this and warned, so take no action here. + } else if (new_rules.cfa_rule_) { + // This shouldn't be possible: NEW_RULES is some prior state, and + // there's no way to remove entries. + assert(0); + } else { + // Both CFA rules are empty. No action needed. + } + + // Traverse the two maps in order by register number, and report + // whatever differences we find. + RuleByNumber::const_iterator old_it = registers_.begin(); + RuleByNumber::const_iterator new_it = new_rules.registers_.begin(); + while (old_it != registers_.end() && new_it != new_rules.registers_.end()) { + if (old_it->first < new_it->first) { + // This RuleMap has an entry for old_it->first, but NEW_RULES + // doesn't. + // + // This isn't really the right thing to do, but since CFI generally + // only mentions callee-saves registers, and GCC's convention for + // callee-saves registers is that they are unchanged, it's a good + // approximation. + if (!handler->SameValueRule(address, old_it->first)) + return false; + old_it++; + } else if (old_it->first > new_it->first) { + // NEW_RULES has entry for new_it->first, but this RuleMap + // doesn't. This shouldn't be possible: NEW_RULES is some prior + // state, and there's no way to remove entries. + assert(0); + } else { + // Both maps have an entry for this register. Report the new + // rule if it is different. + if (*old_it->second != *new_it->second && + !new_it->second->Handle(handler, address, new_it->first)) + return false; + new_it++, old_it++; + } + } + // Finish off entries from this RuleMap with no counterparts in new_rules. + while (old_it != registers_.end()) { + if (!handler->SameValueRule(address, old_it->first)) + return false; + old_it++; + } + // Since we only make transitions from a rule set to some previously + // saved rule set, and we can only add rules to the map, NEW_RULES + // must have fewer rules than *this. + assert(new_it == new_rules.registers_.end()); + + return true; +} + +// Remove all register rules and clear cfa_rule_. +void CallFrameInfo::RuleMap::Clear() { + delete cfa_rule_; + cfa_rule_ = NULL; + for (RuleByNumber::iterator it = registers_.begin(); + it != registers_.end(); it++) + delete it->second; + registers_.clear(); +} + +// The state of the call frame information interpreter as it processes +// instructions from a CIE and FDE. +class CallFrameInfo::State { + public: + // Create a call frame information interpreter state with the given + // reporter, reader, handler, and initial call frame info address. + State(ByteReader *reader, Handler *handler, Reporter *reporter, + uint64 address) + : reader_(reader), handler_(handler), reporter_(reporter), + address_(address), entry_(NULL), cursor_(NULL) { } + + // Interpret instructions from CIE, save the resulting rule set for + // DW_CFA_restore instructions, and return true. On error, report + // the problem to reporter_ and return false. + bool InterpretCIE(const CIE &cie); + + // Interpret instructions from FDE, and return true. On error, + // report the problem to reporter_ and return false. + bool InterpretFDE(const FDE &fde); + + private: + // The operands of a CFI instruction, for ParseOperands. + struct Operands { + unsigned register_number; // A register number. + uint64 offset; // An offset or address. + long signed_offset; // A signed offset. + string expression; // A DWARF expression. + }; + + // Parse CFI instruction operands from STATE's instruction stream as + // described by FORMAT. On success, populate OPERANDS with the + // results, and return true. On failure, report the problem and + // return false. + // + // Each character of FORMAT should be one of the following: + // + // 'r' unsigned LEB128 register number (OPERANDS->register_number) + // 'o' unsigned LEB128 offset (OPERANDS->offset) + // 's' signed LEB128 offset (OPERANDS->signed_offset) + // 'a' machine-size address (OPERANDS->offset) + // (If the CIE has a 'z' augmentation string, 'a' uses the + // encoding specified by the 'R' argument.) + // '1' a one-byte offset (OPERANDS->offset) + // '2' a two-byte offset (OPERANDS->offset) + // '4' a four-byte offset (OPERANDS->offset) + // '8' an eight-byte offset (OPERANDS->offset) + // 'e' a DW_FORM_block holding a (OPERANDS->expression) + // DWARF expression + bool ParseOperands(const char *format, Operands *operands); + + // Interpret one CFI instruction from STATE's instruction stream, update + // STATE, report any rule changes to handler_, and return true. On + // failure, report the problem and return false. + bool DoInstruction(); + + // The following Do* member functions are subroutines of DoInstruction, + // factoring out the actual work of operations that have several + // different encodings. + + // Set the CFA rule to be the value of BASE_REGISTER plus OFFSET, and + // return true. On failure, report and return false. (Used for + // DW_CFA_def_cfa and DW_CFA_def_cfa_sf.) + bool DoDefCFA(unsigned base_register, long offset); + + // Change the offset of the CFA rule to OFFSET, and return true. On + // failure, report and return false. (Subroutine for + // DW_CFA_def_cfa_offset and DW_CFA_def_cfa_offset_sf.) + bool DoDefCFAOffset(long offset); + + // Specify that REG can be recovered using RULE, and return true. On + // failure, report and return false. + bool DoRule(unsigned reg, Rule *rule); + + // Specify that REG can be found at OFFSET from the CFA, and return true. + // On failure, report and return false. (Subroutine for DW_CFA_offset, + // DW_CFA_offset_extended, and DW_CFA_offset_extended_sf.) + bool DoOffset(unsigned reg, long offset); + + // Specify that the caller's value for REG is the CFA plus OFFSET, + // and return true. On failure, report and return false. (Subroutine + // for DW_CFA_val_offset and DW_CFA_val_offset_sf.) + bool DoValOffset(unsigned reg, long offset); + + // Restore REG to the rule established in the CIE, and return true. On + // failure, report and return false. (Subroutine for DW_CFA_restore and + // DW_CFA_restore_extended.) + bool DoRestore(unsigned reg); + + // Return the section offset of the instruction at cursor. For use + // in error messages. + uint64 CursorOffset() { return entry_->offset + (cursor_ - entry_->start); } + + // Report that entry_ is incomplete, and return false. For brevity. + bool ReportIncomplete() { + reporter_->Incomplete(entry_->offset, entry_->kind); + return false; + } + + // For reading multi-byte values with the appropriate endianness. + ByteReader *reader_; + + // The handler to which we should report the data we find. + Handler *handler_; + + // For reporting problems in the info we're parsing. + Reporter *reporter_; + + // The code address to which the next instruction in the stream applies. + uint64 address_; + + // The entry whose instructions we are currently processing. This is + // first a CIE, and then an FDE. + const Entry *entry_; + + // The next instruction to process. + const uint8_t *cursor_; + + // The current set of rules. + RuleMap rules_; + + // The set of rules established by the CIE, used by DW_CFA_restore + // and DW_CFA_restore_extended. We set this after interpreting the + // CIE's instructions. + RuleMap cie_rules_; + + // A stack of saved states, for DW_CFA_remember_state and + // DW_CFA_restore_state. + std::stack saved_rules_; +}; + +bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { + entry_ = &cie; + cursor_ = entry_->instructions; + while (cursor_ < entry_->end) + if (!DoInstruction()) + return false; + // Note the rules established by the CIE, for use by DW_CFA_restore + // and DW_CFA_restore_extended. + cie_rules_ = rules_; + return true; +} + +bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { + entry_ = &fde; + cursor_ = entry_->instructions; + while (cursor_ < entry_->end) + if (!DoInstruction()) + return false; + return true; +} + +bool CallFrameInfo::State::ParseOperands(const char *format, + Operands *operands) { + size_t len; + const char *operand; + + for (operand = format; *operand; operand++) { + size_t bytes_left = entry_->end - cursor_; + switch (*operand) { + case 'r': + operands->register_number = reader_->ReadUnsignedLEB128(cursor_, &len); + if (len > bytes_left) return ReportIncomplete(); + cursor_ += len; + break; + + case 'o': + operands->offset = reader_->ReadUnsignedLEB128(cursor_, &len); + if (len > bytes_left) return ReportIncomplete(); + cursor_ += len; + break; + + case 's': + operands->signed_offset = reader_->ReadSignedLEB128(cursor_, &len); + if (len > bytes_left) return ReportIncomplete(); + cursor_ += len; + break; + + case 'a': + operands->offset = + reader_->ReadEncodedPointer(cursor_, entry_->cie->pointer_encoding, + &len); + if (len > bytes_left) return ReportIncomplete(); + cursor_ += len; + break; + + case '1': + if (1 > bytes_left) return ReportIncomplete(); + operands->offset = static_cast(*cursor_++); + break; + + case '2': + if (2 > bytes_left) return ReportIncomplete(); + operands->offset = reader_->ReadTwoBytes(cursor_); + cursor_ += 2; + break; + + case '4': + if (4 > bytes_left) return ReportIncomplete(); + operands->offset = reader_->ReadFourBytes(cursor_); + cursor_ += 4; + break; + + case '8': + if (8 > bytes_left) return ReportIncomplete(); + operands->offset = reader_->ReadEightBytes(cursor_); + cursor_ += 8; + break; + + case 'e': { + size_t expression_length = reader_->ReadUnsignedLEB128(cursor_, &len); + if (len > bytes_left || expression_length > bytes_left - len) + return ReportIncomplete(); + cursor_ += len; + operands->expression = string(reinterpret_cast(cursor_), + expression_length); + cursor_ += expression_length; + break; + } + + default: + assert(0); + } + } + + return true; +} + +bool CallFrameInfo::State::DoInstruction() { + CIE *cie = entry_->cie; + Operands ops; + + // Our entry's kind should have been set by now. + assert(entry_->kind != kUnknown); + + // We shouldn't have been invoked unless there were more + // instructions to parse. + assert(cursor_ < entry_->end); + + unsigned opcode = *cursor_++; + if ((opcode & 0xc0) != 0) { + switch (opcode & 0xc0) { + // Advance the address. + case DW_CFA_advance_loc: { + size_t code_offset = opcode & 0x3f; + address_ += code_offset * cie->code_alignment_factor; + break; + } + + // Find a register at an offset from the CFA. + case DW_CFA_offset: + if (!ParseOperands("o", &ops) || + !DoOffset(opcode & 0x3f, ops.offset * cie->data_alignment_factor)) + return false; + break; + + // Restore the rule established for a register by the CIE. + case DW_CFA_restore: + if (!DoRestore(opcode & 0x3f)) return false; + break; + + // The 'if' above should have excluded this possibility. + default: + assert(0); + } + + // Return here, so the big switch below won't be indented. + return true; + } + + switch (opcode) { + // Set the address. + case DW_CFA_set_loc: + if (!ParseOperands("a", &ops)) return false; + address_ = ops.offset; + break; + + // Advance the address. + case DW_CFA_advance_loc1: + if (!ParseOperands("1", &ops)) return false; + address_ += ops.offset * cie->code_alignment_factor; + break; + + // Advance the address. + case DW_CFA_advance_loc2: + if (!ParseOperands("2", &ops)) return false; + address_ += ops.offset * cie->code_alignment_factor; + break; + + // Advance the address. + case DW_CFA_advance_loc4: + if (!ParseOperands("4", &ops)) return false; + address_ += ops.offset * cie->code_alignment_factor; + break; + + // Advance the address. + case DW_CFA_MIPS_advance_loc8: + if (!ParseOperands("8", &ops)) return false; + address_ += ops.offset * cie->code_alignment_factor; + break; + + // Compute the CFA by adding an offset to a register. + case DW_CFA_def_cfa: + if (!ParseOperands("ro", &ops) || + !DoDefCFA(ops.register_number, ops.offset)) + return false; + break; + + // Compute the CFA by adding an offset to a register. + case DW_CFA_def_cfa_sf: + if (!ParseOperands("rs", &ops) || + !DoDefCFA(ops.register_number, + ops.signed_offset * cie->data_alignment_factor)) + return false; + break; + + // Change the base register used to compute the CFA. + case DW_CFA_def_cfa_register: { + if (!ParseOperands("r", &ops)) return false; + Rule *cfa_rule = rules_.CFARule(); + if (!cfa_rule) { + if (!DoDefCFA(ops.register_number, ops.offset)) { + reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); + return false; + } + } else { + cfa_rule->SetBaseRegister(ops.register_number); + if (!cfa_rule->Handle(handler_, address_, + Handler::kCFARegister)) + return false; + } + break; + } + + // Change the offset used to compute the CFA. + case DW_CFA_def_cfa_offset: + if (!ParseOperands("o", &ops) || + !DoDefCFAOffset(ops.offset)) + return false; + break; + + // Change the offset used to compute the CFA. + case DW_CFA_def_cfa_offset_sf: + if (!ParseOperands("s", &ops) || + !DoDefCFAOffset(ops.signed_offset * cie->data_alignment_factor)) + return false; + break; + + // Specify an expression whose value is the CFA. + case DW_CFA_def_cfa_expression: { + if (!ParseOperands("e", &ops)) + return false; + Rule *rule = new ValExpressionRule(ops.expression); + rules_.SetCFARule(rule); + if (!rule->Handle(handler_, address_, + Handler::kCFARegister)) + return false; + break; + } + + // The register's value cannot be recovered. + case DW_CFA_undefined: { + if (!ParseOperands("r", &ops) || + !DoRule(ops.register_number, new UndefinedRule())) + return false; + break; + } + + // The register's value is unchanged from its value in the caller. + case DW_CFA_same_value: { + if (!ParseOperands("r", &ops) || + !DoRule(ops.register_number, new SameValueRule())) + return false; + break; + } + + // Find a register at an offset from the CFA. + case DW_CFA_offset_extended: + if (!ParseOperands("ro", &ops) || + !DoOffset(ops.register_number, + ops.offset * cie->data_alignment_factor)) + return false; + break; + + // The register is saved at an offset from the CFA. + case DW_CFA_offset_extended_sf: + if (!ParseOperands("rs", &ops) || + !DoOffset(ops.register_number, + ops.signed_offset * cie->data_alignment_factor)) + return false; + break; + + // The register is saved at an offset from the CFA. + case DW_CFA_GNU_negative_offset_extended: + if (!ParseOperands("ro", &ops) || + !DoOffset(ops.register_number, + -ops.offset * cie->data_alignment_factor)) + return false; + break; + + // The register's value is the sum of the CFA plus an offset. + case DW_CFA_val_offset: + if (!ParseOperands("ro", &ops) || + !DoValOffset(ops.register_number, + ops.offset * cie->data_alignment_factor)) + return false; + break; + + // The register's value is the sum of the CFA plus an offset. + case DW_CFA_val_offset_sf: + if (!ParseOperands("rs", &ops) || + !DoValOffset(ops.register_number, + ops.signed_offset * cie->data_alignment_factor)) + return false; + break; + + // The register has been saved in another register. + case DW_CFA_register: { + if (!ParseOperands("ro", &ops) || + !DoRule(ops.register_number, new RegisterRule(ops.offset))) + return false; + break; + } + + // An expression yields the address at which the register is saved. + case DW_CFA_expression: { + if (!ParseOperands("re", &ops) || + !DoRule(ops.register_number, new ExpressionRule(ops.expression))) + return false; + break; + } + + // An expression yields the caller's value for the register. + case DW_CFA_val_expression: { + if (!ParseOperands("re", &ops) || + !DoRule(ops.register_number, new ValExpressionRule(ops.expression))) + return false; + break; + } + + // Restore the rule established for a register by the CIE. + case DW_CFA_restore_extended: + if (!ParseOperands("r", &ops) || + !DoRestore( ops.register_number)) + return false; + break; + + // Save the current set of rules on a stack. + case DW_CFA_remember_state: + saved_rules_.push(rules_); + break; + + // Pop the current set of rules off the stack. + case DW_CFA_restore_state: { + if (saved_rules_.empty()) { + reporter_->EmptyStateStack(entry_->offset, entry_->kind, + CursorOffset()); + return false; + } + const RuleMap &new_rules = saved_rules_.top(); + if (rules_.CFARule() && !new_rules.CFARule()) { + reporter_->ClearingCFARule(entry_->offset, entry_->kind, + CursorOffset()); + return false; + } + rules_.HandleTransitionTo(handler_, address_, new_rules); + rules_ = new_rules; + saved_rules_.pop(); + break; + } + + // No operation. (Padding instruction.) + case DW_CFA_nop: + break; + + // A SPARC register window save: Registers 8 through 15 (%o0-%o7) + // are saved in registers 24 through 31 (%i0-%i7), and registers + // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets + // (0-15 * the register size). The register numbers must be + // hard-coded. A GNU extension, and not a pretty one. + case DW_CFA_GNU_window_save: { + // Save %o0-%o7 in %i0-%i7. + for (int i = 8; i < 16; i++) + if (!DoRule(i, new RegisterRule(i + 16))) + return false; + // Save %l0-%l7 and %i0-%i7 at the CFA. + for (int i = 16; i < 32; i++) + // Assume that the byte reader's address size is the same as + // the architecture's register size. !@#%*^ hilarious. + if (!DoRule(i, new OffsetRule(Handler::kCFARegister, + (i - 16) * reader_->AddressSize()))) + return false; + break; + } + + // I'm not sure what this is. GDB doesn't use it for unwinding. + case DW_CFA_GNU_args_size: + if (!ParseOperands("o", &ops)) return false; + break; + + // An opcode we don't recognize. + default: { + reporter_->BadInstruction(entry_->offset, entry_->kind, CursorOffset()); + return false; + } + } + + return true; +} + +bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { + Rule *rule = new ValOffsetRule(base_register, offset); + rules_.SetCFARule(rule); + return rule->Handle(handler_, address_, + Handler::kCFARegister); +} + +bool CallFrameInfo::State::DoDefCFAOffset(long offset) { + Rule *cfa_rule = rules_.CFARule(); + if (!cfa_rule) { + reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); + return false; + } + cfa_rule->SetOffset(offset); + return cfa_rule->Handle(handler_, address_, + Handler::kCFARegister); +} + +bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { + rules_.SetRegisterRule(reg, rule); + return rule->Handle(handler_, address_, reg); +} + +bool CallFrameInfo::State::DoOffset(unsigned reg, long offset) { + if (!rules_.CFARule()) { + reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); + return false; + } + return DoRule(reg, + new OffsetRule(Handler::kCFARegister, offset)); +} + +bool CallFrameInfo::State::DoValOffset(unsigned reg, long offset) { + if (!rules_.CFARule()) { + reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); + return false; + } + return DoRule(reg, + new ValOffsetRule(Handler::kCFARegister, offset)); +} + +bool CallFrameInfo::State::DoRestore(unsigned reg) { + // DW_CFA_restore and DW_CFA_restore_extended don't make sense in a CIE. + if (entry_->kind == kCIE) { + reporter_->RestoreInCIE(entry_->offset, CursorOffset()); + return false; + } + Rule *rule = cie_rules_.RegisterRule(reg); + if (!rule) { + // This isn't really the right thing to do, but since CFI generally + // only mentions callee-saves registers, and GCC's convention for + // callee-saves registers is that they are unchanged, it's a good + // approximation. + rule = new SameValueRule(); + } + return DoRule(reg, rule); +} + +bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { + const uint8_t *buffer_end = buffer_ + buffer_length_; + + // Initialize enough of ENTRY for use in error reporting. + entry->offset = cursor - buffer_; + entry->start = cursor; + entry->kind = kUnknown; + entry->end = NULL; + + // Read the initial length. This sets reader_'s offset size. + size_t length_size; + uint64 length = reader_->ReadInitialLength(cursor, &length_size); + if (length_size > size_t(buffer_end - cursor)) + return ReportIncomplete(entry); + cursor += length_size; + + // In a .eh_frame section, a length of zero marks the end of the series + // of entries. + if (length == 0 && eh_frame_) { + entry->kind = kTerminator; + entry->end = cursor; + return true; + } + + // Validate the length. + if (length > size_t(buffer_end - cursor)) + return ReportIncomplete(entry); + + // The length is the number of bytes after the initial length field; + // we have that position handy at this point, so compute the end + // now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine, + // and the length didn't fit in a size_t, we would have rejected it + // above.) + entry->end = cursor + length; + + // Parse the next field: either the offset of a CIE or a CIE id. + size_t offset_size = reader_->OffsetSize(); + if (offset_size > size_t(entry->end - cursor)) return ReportIncomplete(entry); + entry->id = reader_->ReadOffset(cursor); + + // Don't advance cursor past id field yet; in .eh_frame data we need + // the id's position to compute the section offset of an FDE's CIE. + + // Now we can decide what kind of entry this is. + if (eh_frame_) { + // In .eh_frame data, an ID of zero marks the entry as a CIE, and + // anything else is an offset from the id field of the FDE to the start + // of the CIE. + if (entry->id == 0) { + entry->kind = kCIE; + } else { + entry->kind = kFDE; + // Turn the offset from the id into an offset from the buffer's start. + entry->id = (cursor - buffer_) - entry->id; + } + } else { + // In DWARF CFI data, an ID of ~0 (of the appropriate width, given the + // offset size for the entry) marks the entry as a CIE, and anything + // else is the offset of the CIE from the beginning of the section. + if (offset_size == 4) + entry->kind = (entry->id == 0xffffffff) ? kCIE : kFDE; + else { + assert(offset_size == 8); + entry->kind = (entry->id == 0xffffffffffffffffULL) ? kCIE : kFDE; + } + } + + // Now advance cursor past the id. + cursor += offset_size; + + // The fields specific to this kind of entry start here. + entry->fields = cursor; + + entry->cie = NULL; + + return true; +} + +bool CallFrameInfo::ReadCIEFields(CIE *cie) { + const uint8_t *cursor = cie->fields; + size_t len; + + assert(cie->kind == kCIE); + + // Prepare for early exit. + cie->version = 0; + cie->augmentation.clear(); + cie->code_alignment_factor = 0; + cie->data_alignment_factor = 0; + cie->return_address_register = 0; + cie->has_z_augmentation = false; + cie->pointer_encoding = DW_EH_PE_absptr; + cie->instructions = 0; + + // Parse the version number. + if (cie->end - cursor < 1) + return ReportIncomplete(cie); + cie->version = reader_->ReadOneByte(cursor); + cursor++; + + // If we don't recognize the version, we can't parse any more fields of the + // CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a + // version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well; + // the difference between those versions seems to be the same as for + // .debug_frame. + if (cie->version < 1 || cie->version > 4) { + reporter_->UnrecognizedVersion(cie->offset, cie->version); + return false; + } + + const uint8_t *augmentation_start = cursor; + const uint8_t *augmentation_end = + reinterpret_cast(memchr(augmentation_start, '\0', + cie->end - augmentation_start)); + if (! augmentation_end) return ReportIncomplete(cie); + cursor = augmentation_end; + cie->augmentation = string(reinterpret_cast(augmentation_start), + cursor - augmentation_start); + // Skip the terminating '\0'. + cursor++; + + // Is this CFI augmented? + if (!cie->augmentation.empty()) { + // Is it an augmentation we recognize? + if (cie->augmentation[0] == DW_Z_augmentation_start) { + // Linux C++ ABI 'z' augmentation, used for exception handling data. + cie->has_z_augmentation = true; + } else { + // Not an augmentation we recognize. Augmentations can have arbitrary + // effects on the form of rest of the content, so we have to give up. + reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); + return false; + } + } + + if (cie->version >= 4) { + cie->address_size = *cursor++; + if (cie->address_size != 8 && cie->address_size != 4) { + reporter_->UnexpectedAddressSize(cie->offset, cie->address_size); + return false; + } + + cie->segment_size = *cursor++; + if (cie->segment_size != 0) { + reporter_->UnexpectedSegmentSize(cie->offset, cie->segment_size); + return false; + } + } + + // Parse the code alignment factor. + cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len); + if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); + cursor += len; + + // Parse the data alignment factor. + cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len); + if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); + cursor += len; + + // Parse the return address register. This is a ubyte in version 1, and + // a ULEB128 in version 3. + if (cie->version == 1) { + if (cursor >= cie->end) return ReportIncomplete(cie); + cie->return_address_register = uint8(*cursor++); + } else { + cie->return_address_register = reader_->ReadUnsignedLEB128(cursor, &len); + if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); + cursor += len; + } + + // If we have a 'z' augmentation string, find the augmentation data and + // use the augmentation string to parse it. + if (cie->has_z_augmentation) { + uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &len); + if (size_t(cie->end - cursor) < len + data_size) + return ReportIncomplete(cie); + cursor += len; + const uint8_t *data = cursor; + cursor += data_size; + const uint8_t *data_end = cursor; + + cie->has_z_lsda = false; + cie->has_z_personality = false; + cie->has_z_signal_frame = false; + + // Walk the augmentation string, and extract values from the + // augmentation data as the string directs. + for (size_t i = 1; i < cie->augmentation.size(); i++) { + switch (cie->augmentation[i]) { + case DW_Z_has_LSDA: + // The CIE's augmentation data holds the language-specific data + // area pointer's encoding, and the FDE's augmentation data holds + // the pointer itself. + cie->has_z_lsda = true; + // Fetch the LSDA encoding from the augmentation data. + if (data >= data_end) return ReportIncomplete(cie); + cie->lsda_encoding = DwarfPointerEncoding(*data++); + if (!reader_->ValidEncoding(cie->lsda_encoding)) { + reporter_->InvalidPointerEncoding(cie->offset, cie->lsda_encoding); + return false; + } + // Don't check if the encoding is usable here --- we haven't + // read the FDE's fields yet, so we're not prepared for + // DW_EH_PE_funcrel, although that's a fine encoding for the + // LSDA to use, since it appears in the FDE. + break; + + case DW_Z_has_personality_routine: + // The CIE's augmentation data holds the personality routine + // pointer's encoding, followed by the pointer itself. + cie->has_z_personality = true; + // Fetch the personality routine pointer's encoding from the + // augmentation data. + if (data >= data_end) return ReportIncomplete(cie); + cie->personality_encoding = DwarfPointerEncoding(*data++); + if (!reader_->ValidEncoding(cie->personality_encoding)) { + reporter_->InvalidPointerEncoding(cie->offset, + cie->personality_encoding); + return false; + } + if (!reader_->UsableEncoding(cie->personality_encoding)) { + reporter_->UnusablePointerEncoding(cie->offset, + cie->personality_encoding); + return false; + } + // Fetch the personality routine's pointer itself from the data. + cie->personality_address = + reader_->ReadEncodedPointer(data, cie->personality_encoding, + &len); + if (len > size_t(data_end - data)) + return ReportIncomplete(cie); + data += len; + break; + + case DW_Z_has_FDE_address_encoding: + // The CIE's augmentation data holds the pointer encoding to use + // for addresses in the FDE. + if (data >= data_end) return ReportIncomplete(cie); + cie->pointer_encoding = DwarfPointerEncoding(*data++); + if (!reader_->ValidEncoding(cie->pointer_encoding)) { + reporter_->InvalidPointerEncoding(cie->offset, + cie->pointer_encoding); + return false; + } + if (!reader_->UsableEncoding(cie->pointer_encoding)) { + reporter_->UnusablePointerEncoding(cie->offset, + cie->pointer_encoding); + return false; + } + break; + + case DW_Z_is_signal_trampoline: + // Frames using this CIE are signal delivery frames. + cie->has_z_signal_frame = true; + break; + + default: + // An augmentation we don't recognize. + reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); + return false; + } + } + } + + // The CIE's instructions start here. + cie->instructions = cursor; + + return true; +} + +bool CallFrameInfo::ReadFDEFields(FDE *fde) { + const uint8_t *cursor = fde->fields; + size_t size; + + fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, + &size); + if (size > size_t(fde->end - cursor)) + return ReportIncomplete(fde); + cursor += size; + reader_->SetFunctionBase(fde->address); + + // For the length, we strip off the upper nybble of the encoding used for + // the starting address. + DwarfPointerEncoding length_encoding = + DwarfPointerEncoding(fde->cie->pointer_encoding & 0x0f); + fde->size = reader_->ReadEncodedPointer(cursor, length_encoding, &size); + if (size > size_t(fde->end - cursor)) + return ReportIncomplete(fde); + cursor += size; + + // If the CIE has a 'z' augmentation string, then augmentation data + // appears here. + if (fde->cie->has_z_augmentation) { + uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &size); + if (size_t(fde->end - cursor) < size + data_size) + return ReportIncomplete(fde); + cursor += size; + + // In the abstract, we should walk the augmentation string, and extract + // items from the FDE's augmentation data as we encounter augmentation + // string characters that specify their presence: the ordering of items + // in the augmentation string determines the arrangement of values in + // the augmentation data. + // + // In practice, there's only ever one value in FDE augmentation data + // that we support --- the LSDA pointer --- and we have to bail if we + // see any unrecognized augmentation string characters. So if there is + // anything here at all, we know what it is, and where it starts. + if (fde->cie->has_z_lsda) { + // Check whether the LSDA's pointer encoding is usable now: only once + // we've parsed the FDE's starting address do we call reader_-> + // SetFunctionBase, so that the DW_EH_PE_funcrel encoding becomes + // usable. + if (!reader_->UsableEncoding(fde->cie->lsda_encoding)) { + reporter_->UnusablePointerEncoding(fde->cie->offset, + fde->cie->lsda_encoding); + return false; + } + + fde->lsda_address = + reader_->ReadEncodedPointer(cursor, fde->cie->lsda_encoding, &size); + if (size > data_size) + return ReportIncomplete(fde); + // Ideally, we would also complain here if there were unconsumed + // augmentation data. + } + + cursor += data_size; + } + + // The FDE's instructions start after those. + fde->instructions = cursor; + + return true; +} + +bool CallFrameInfo::Start() { + const uint8_t *buffer_end = buffer_ + buffer_length_; + const uint8_t *cursor; + bool all_ok = true; + const uint8_t *entry_end; + bool ok; + + // Traverse all the entries in buffer_, skipping CIEs and offering + // FDEs to the handler. + for (cursor = buffer_; cursor < buffer_end; + cursor = entry_end, all_ok = all_ok && ok) { + FDE fde; + + // Make it easy to skip this entry with 'continue': assume that + // things are not okay until we've checked all the data, and + // prepare the address of the next entry. + ok = false; + + // Read the entry's prologue. + if (!ReadEntryPrologue(cursor, &fde)) { + if (!fde.end) { + // If we couldn't even figure out this entry's extent, then we + // must stop processing entries altogether. + all_ok = false; + break; + } + entry_end = fde.end; + continue; + } + + // The next iteration picks up after this entry. + entry_end = fde.end; + + // Did we see an .eh_frame terminating mark? + if (fde.kind == kTerminator) { + // If there appears to be more data left in the section after the + // terminating mark, warn the user. But this is just a warning; + // we leave all_ok true. + if (fde.end < buffer_end) reporter_->EarlyEHTerminator(fde.offset); + break; + } + + // In this loop, we skip CIEs. We only parse them fully when we + // parse an FDE that refers to them. This limits our memory + // consumption (beyond the buffer itself) to that needed to + // process the largest single entry. + if (fde.kind != kFDE) { + ok = true; + continue; + } + + // Validate the CIE pointer. + if (fde.id > buffer_length_) { + reporter_->CIEPointerOutOfRange(fde.offset, fde.id); + continue; + } + + CIE cie; + + // Parse this FDE's CIE header. + if (!ReadEntryPrologue(buffer_ + fde.id, &cie)) + continue; + // This had better be an actual CIE. + if (cie.kind != kCIE) { + reporter_->BadCIEId(fde.offset, fde.id); + continue; + } + if (!ReadCIEFields(&cie)) + continue; + + // TODO(nbilling): This could lead to strange behavior if a single buffer + // contained a mixture of DWARF versions as well as address sizes. Not + // sure if it's worth handling such a case. + + // DWARF4 CIE specifies address_size, so use it for this call frame. + if (cie.version >= 4) { + reader_->SetAddressSize(cie.address_size); + } + + // We now have the values that govern both the CIE and the FDE. + cie.cie = &cie; + fde.cie = &cie; + + // Parse the FDE's header. + if (!ReadFDEFields(&fde)) + continue; + + // Call Entry to ask the consumer if they're interested. + if (!handler_->Entry(fde.offset, fde.address, fde.size, + cie.version, cie.augmentation, + cie.return_address_register)) { + // The handler isn't interested in this entry. That's not an error. + ok = true; + continue; + } + + if (cie.has_z_augmentation) { + // Report the personality routine address, if we have one. + if (cie.has_z_personality) { + if (!handler_ + ->PersonalityRoutine(cie.personality_address, + IsIndirectEncoding(cie.personality_encoding))) + continue; + } + + // Report the language-specific data area address, if we have one. + if (cie.has_z_lsda) { + if (!handler_ + ->LanguageSpecificDataArea(fde.lsda_address, + IsIndirectEncoding(cie.lsda_encoding))) + continue; + } + + // If this is a signal-handling frame, report that. + if (cie.has_z_signal_frame) { + if (!handler_->SignalHandler()) + continue; + } + } + + // Interpret the CIE's instructions, and then the FDE's instructions. + State state(reader_, handler_, reporter_, fde.address); + ok = state.InterpretCIE(cie) && state.InterpretFDE(fde); + + // Tell the ByteReader that the function start address from the + // FDE header is no longer valid. + reader_->ClearFunctionBase(); + + // Report the end of the entry. + handler_->End(); + } + + return all_ok; +} + +const char *CallFrameInfo::KindName(EntryKind kind) { + if (kind == CallFrameInfo::kUnknown) + return "entry"; + else if (kind == CallFrameInfo::kCIE) + return "common information entry"; + else if (kind == CallFrameInfo::kFDE) + return "frame description entry"; + else { + assert (kind == CallFrameInfo::kTerminator); + return ".eh_frame sequence terminator"; + } +} + +bool CallFrameInfo::ReportIncomplete(Entry *entry) { + reporter_->Incomplete(entry->offset, entry->kind); + return false; +} + +void CallFrameInfo::Reporter::Incomplete(uint64 offset, + CallFrameInfo::EntryKind kind) { + fprintf(stderr, + "%s: CFI %s at offset 0x%llx in '%s': entry ends early\n", + filename_.c_str(), CallFrameInfo::KindName(kind), offset, + section_.c_str()); +} + +void CallFrameInfo::Reporter::EarlyEHTerminator(uint64 offset) { + fprintf(stderr, + "%s: CFI at offset 0x%llx in '%s': saw end-of-data marker" + " before end of section contents\n", + filename_.c_str(), offset, section_.c_str()); +} + +void CallFrameInfo::Reporter::CIEPointerOutOfRange(uint64 offset, + uint64 cie_offset) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE pointer is out of range: 0x%llx\n", + filename_.c_str(), offset, section_.c_str(), cie_offset); +} + +void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE pointer does not point to a CIE: 0x%llx\n", + filename_.c_str(), offset, section_.c_str(), cie_offset); +} + +void CallFrameInfo::Reporter::UnexpectedAddressSize(uint64 offset, + uint8_t address_size) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unexpected address size: %d\n", + filename_.c_str(), offset, section_.c_str(), address_size); +} + +void CallFrameInfo::Reporter::UnexpectedSegmentSize(uint64 offset, + uint8_t segment_size) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unexpected segment size: %d\n", + filename_.c_str(), offset, section_.c_str(), segment_size); +} + +void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unrecognized version: %d\n", + filename_.c_str(), offset, section_.c_str(), version); +} + +void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset, + const string &aug) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unrecognized augmentation: '%s'\n", + filename_.c_str(), offset, section_.c_str(), aug.c_str()); +} + +void CallFrameInfo::Reporter::InvalidPointerEncoding(uint64 offset, + uint8 encoding) { + fprintf(stderr, + "%s: CFI common information entry at offset 0x%llx in '%s':" + " 'z' augmentation specifies invalid pointer encoding: 0x%02x\n", + filename_.c_str(), offset, section_.c_str(), encoding); +} + +void CallFrameInfo::Reporter::UnusablePointerEncoding(uint64 offset, + uint8 encoding) { + fprintf(stderr, + "%s: CFI common information entry at offset 0x%llx in '%s':" + " 'z' augmentation specifies a pointer encoding for which" + " we have no base address: 0x%02x\n", + filename_.c_str(), offset, section_.c_str(), encoding); +} + +void CallFrameInfo::Reporter::RestoreInCIE(uint64 offset, uint64 insn_offset) { + fprintf(stderr, + "%s: CFI common information entry at offset 0x%llx in '%s':" + " the DW_CFA_restore instruction at offset 0x%llx" + " cannot be used in a common information entry\n", + filename_.c_str(), offset, section_.c_str(), insn_offset); +} + +void CallFrameInfo::Reporter::BadInstruction(uint64 offset, + CallFrameInfo::EntryKind kind, + uint64 insn_offset) { + fprintf(stderr, + "%s: CFI %s at offset 0x%llx in section '%s':" + " the instruction at offset 0x%llx is unrecognized\n", + filename_.c_str(), CallFrameInfo::KindName(kind), + offset, section_.c_str(), insn_offset); +} + +void CallFrameInfo::Reporter::NoCFARule(uint64 offset, + CallFrameInfo::EntryKind kind, + uint64 insn_offset) { + fprintf(stderr, + "%s: CFI %s at offset 0x%llx in section '%s':" + " the instruction at offset 0x%llx assumes that a CFA rule has" + " been set, but none has been set\n", + filename_.c_str(), CallFrameInfo::KindName(kind), offset, + section_.c_str(), insn_offset); +} + +void CallFrameInfo::Reporter::EmptyStateStack(uint64 offset, + CallFrameInfo::EntryKind kind, + uint64 insn_offset) { + fprintf(stderr, + "%s: CFI %s at offset 0x%llx in section '%s':" + " the DW_CFA_restore_state instruction at offset 0x%llx" + " should pop a saved state from the stack, but the stack is empty\n", + filename_.c_str(), CallFrameInfo::KindName(kind), offset, + section_.c_str(), insn_offset); +} + +void CallFrameInfo::Reporter::ClearingCFARule(uint64 offset, + CallFrameInfo::EntryKind kind, + uint64 insn_offset) { + fprintf(stderr, + "%s: CFI %s at offset 0x%llx in section '%s':" + " the DW_CFA_restore_state instruction at offset 0x%llx" + " would clear the CFA rule in effect\n", + filename_.c_str(), CallFrameInfo::KindName(kind), offset, + section_.c_str(), insn_offset); +} + +} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h new file mode 100644 index 0000000000..902d9ef1f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h @@ -0,0 +1,1331 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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. + +// CFI reader author: Jim Blandy + +// This file contains definitions related to the DWARF2/3 reader and +// it's handler interfaces. +// The DWARF2/3 specification can be found at +// http://dwarf.freestandards.org and should be considered required +// reading if you wish to modify the implementation. +// Only a cursory attempt is made to explain terminology that is +// used here, as it is much better explained in the standard documents +#ifndef COMMON_DWARF_DWARF2READER_H__ +#define COMMON_DWARF_DWARF2READER_H__ + +#include + +#include +#include +#include +#include +#include +#include + +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2enums.h" +#include "common/dwarf/types.h" +#include "common/using_std_string.h" +#include "common/dwarf/elf_reader.h" + +namespace dwarf2reader { +struct LineStateMachine; +class Dwarf2Handler; +class LineInfoHandler; +class DwpReader; + +// This maps from a string naming a section to a pair containing a +// the data for the section, and the size of the section. +typedef std::map > SectionMap; +typedef std::list > + AttributeList; +typedef AttributeList::iterator AttributeIterator; +typedef AttributeList::const_iterator ConstAttributeIterator; + +struct LineInfoHeader { + uint64 total_length; + uint16 version; + uint64 prologue_length; + uint8 min_insn_length; // insn stands for instructin + bool default_is_stmt; // stmt stands for statement + int8 line_base; + uint8 line_range; + uint8 opcode_base; + // Use a pointer so that signalsafe_addr2line is able to use this structure + // without heap allocation problem. + std::vector *std_opcode_lengths; +}; + +class LineInfo { + public: + + // Initializes a .debug_line reader. Buffer and buffer length point + // to the beginning and length of the line information to read. + // Reader is a ByteReader class that has the endianness set + // properly. + LineInfo(const uint8_t *buffer_, uint64 buffer_length, + ByteReader* reader, LineInfoHandler* handler); + + virtual ~LineInfo() { + if (header_.std_opcode_lengths) { + delete header_.std_opcode_lengths; + } + } + + // Start processing line info, and calling callbacks in the handler. + // Consumes the line number information for a single compilation unit. + // Returns the number of bytes processed. + uint64 Start(); + + // Process a single line info opcode at START using the state + // machine at LSM. Return true if we should define a line using the + // current state of the line state machine. Place the length of the + // opcode in LEN. + // If LSM_PASSES_PC is non-NULL, this function also checks if the lsm + // passes the address of PC. In other words, LSM_PASSES_PC will be + // set to true, if the following condition is met. + // + // lsm's old address < PC <= lsm's new address + static bool ProcessOneOpcode(ByteReader* reader, + LineInfoHandler* handler, + const struct LineInfoHeader &header, + const uint8_t *start, + struct LineStateMachine* lsm, + size_t* len, + uintptr pc, + bool *lsm_passes_pc); + + private: + // Reads the DWARF2/3 header for this line info. + void ReadHeader(); + + // Reads the DWARF2/3 line information + void ReadLines(); + + // The associated handler to call processing functions in + LineInfoHandler* handler_; + + // The associated ByteReader that handles endianness issues for us + ByteReader* reader_; + + // A DWARF2/3 line info header. This is not the same size as + // in the actual file, as the one in the file may have a 32 bit or + // 64 bit lengths + + struct LineInfoHeader header_; + + // buffer is the buffer for our line info, starting at exactly where + // the line info to read is. after_header is the place right after + // the end of the line information header. + const uint8_t *buffer_; +#ifndef NDEBUG + uint64 buffer_length_; +#endif + const uint8_t *after_header_; +}; + +// This class is the main interface between the line info reader and +// the client. The virtual functions inside this get called for +// interesting events that happen during line info reading. The +// default implementation does nothing + +class LineInfoHandler { + public: + LineInfoHandler() { } + + virtual ~LineInfoHandler() { } + + // Called when we define a directory. NAME is the directory name, + // DIR_NUM is the directory number + virtual void DefineDir(const string& name, uint32 dir_num) { } + + // Called when we define a filename. NAME is the filename, FILE_NUM + // is the file number which is -1 if the file index is the next + // index after the last numbered index (this happens when files are + // dynamically defined by the line program), DIR_NUM is the + // directory index for the directory name of this file, MOD_TIME is + // the modification time of the file, and LENGTH is the length of + // the file + virtual void DefineFile(const string& name, int32 file_num, + uint32 dir_num, uint64 mod_time, + uint64 length) { } + + // Called when the line info reader has a new line, address pair + // ready for us. ADDRESS is the address of the code, LENGTH is the + // length of its machine code in bytes, FILE_NUM is the file number + // containing the code, LINE_NUM is the line number in that file for + // the code, and COLUMN_NUM is the column number the code starts at, + // if we know it (0 otherwise). + virtual void AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, uint32 column_num) { } +}; + +class RangeListHandler { + public: + RangeListHandler() { } + + virtual ~RangeListHandler() { } + + // Add a range. + virtual void AddRange(uint64 begin, uint64 end) { }; + + // A new base address must be set for computing the ranges' addresses. + virtual void SetBaseAddress(uint64 base_address) { }; + + // Finish processing the range list. + virtual void Finish() { }; +}; + +class RangeListReader { + public: + RangeListReader(const uint8_t *buffer, uint64 size, ByteReader *reader, + RangeListHandler *handler); + + bool ReadRangeList(uint64 offset); + + private: + const uint8_t *buffer_; + uint64 size_; + ByteReader* reader_; + RangeListHandler *handler_; +}; + +// This class is the main interface between the reader and the +// client. The virtual functions inside this get called for +// interesting events that happen during DWARF2 reading. +// The default implementation skips everything. +class Dwarf2Handler { + public: + Dwarf2Handler() { } + + virtual ~Dwarf2Handler() { } + + // Start to process a compilation unit at OFFSET from the beginning of the + // .debug_info section. Return false if you would like to skip this + // compilation unit. + virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version) { return false; } + + // When processing a skeleton compilation unit, resulting from a split + // DWARF compilation, once the skeleton debug info has been read, + // the reader will call this function to ask the client if it needs + // the full debug info from the .dwo or .dwp file. Return true if + // you need it, or false to skip processing the split debug info. + virtual bool NeedSplitDebugInfo() { return true; } + + // Start to process a split compilation unit at OFFSET from the beginning of + // the debug_info section in the .dwp/.dwo file. Return false if you would + // like to skip this compilation unit. + virtual bool StartSplitCompilationUnit(uint64 offset, + uint64 cu_length) { return false; } + + // Start to process a DIE at OFFSET from the beginning of the .debug_info + // section. Return false if you would like to skip this DIE. + virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; } + + // Called when we have an attribute with unsigned data to give to our + // handler. The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { } + + // Called when we have an attribute with signed data to give to our handler. + // The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeSigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { } + + // Called when we have an attribute whose value is a reference to + // another DIE. The attribute belongs to the DIE at OFFSET from the + // beginning of the .debug_info section. Its name is ATTR, its form + // is FORM, and the offset of the DIE being referred to from the + // beginning of the .debug_info section is DATA. + virtual void ProcessAttributeReference(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { } + + // Called when we have an attribute with a buffer of data to give to our + // handler. The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, DATA points to + // the buffer's contents, and its length in bytes is LENGTH. The buffer is + // owned by the caller, not the callee, and may not persist for very long. + // If you want the data to be available later, it needs to be copied. + virtual void ProcessAttributeBuffer(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64 len) { } + + // Called when we have an attribute with string data to give to our handler. + // The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string& data) { } + + // Called when we have an attribute whose value is the 64-bit signature + // of a type unit in the .debug_types section. OFFSET is the offset of + // the DIE whose attribute we're reporting. ATTR and FORM are the + // attribute's name and form. SIGNATURE is the type unit's signature. + virtual void ProcessAttributeSignature(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 signature) { } + + // Called when finished processing the DIE at OFFSET. + // Because DWARF2/3 specifies a tree of DIEs, you may get starts + // before ends of the previous DIE, as we process children before + // ending the parent. + virtual void EndDIE(uint64 offset) { } + +}; + +// The base of DWARF2/3 debug info is a DIE (Debugging Information +// Entry. +// DWARF groups DIE's into a tree and calls the root of this tree a +// "compilation unit". Most of the time, there is one compilation +// unit in the .debug_info section for each file that had debug info +// generated. +// Each DIE consists of + +// 1. a tag specifying a thing that is being described (ie +// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc +// 2. attributes (such as DW_AT_location for location in memory, +// DW_AT_name for name), and data for each attribute. +// 3. A flag saying whether the DIE has children or not + +// In order to gain some amount of compression, the format of +// each DIE (tag name, attributes and data forms for the attributes) +// are stored in a separate table called the "abbreviation table". +// This is done because a large number of DIEs have the exact same tag +// and list of attributes, but different data for those attributes. +// As a result, the .debug_info section is just a stream of data, and +// requires reading of the .debug_abbrev section to say what the data +// means. + +// As a warning to the user, it should be noted that the reason for +// using absolute offsets from the beginning of .debug_info is that +// DWARF2/3 supports referencing DIE's from other DIE's by their offset +// from either the current compilation unit start, *or* the beginning +// of the .debug_info section. This means it is possible to reference +// a DIE in one compilation unit from a DIE in another compilation +// unit. This style of reference is usually used to eliminate +// duplicated information that occurs across compilation +// units, such as base types, etc. GCC 3.4+ support this with +// -feliminate-dwarf2-dups. Other toolchains will sometimes do +// duplicate elimination in the linker. + +class CompilationUnit { + public: + + // Initialize a compilation unit. This requires a map of sections, + // the offset of this compilation unit in the .debug_info section, a + // ByteReader, and a Dwarf2Handler class to call callbacks in. + CompilationUnit(const string& path, const SectionMap& sections, uint64 offset, + ByteReader* reader, Dwarf2Handler* handler); + virtual ~CompilationUnit() { + if (abbrevs_) delete abbrevs_; + } + + // Initialize a compilation unit from a .dwo or .dwp file. + // In this case, we need the .debug_addr section from the + // executable file that contains the corresponding skeleton + // compilation unit. We also inherit the Dwarf2Handler from + // the executable file, and call it as if we were still + // processing the original compilation unit. + void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length, + uint64 addr_base, uint64 ranges_base, uint64 dwo_id); + + // Begin reading a Dwarf2 compilation unit, and calling the + // callbacks in the Dwarf2Handler + + // Return the full length of the compilation unit, including + // headers. This plus the starting offset passed to the constructor + // is the offset of the end of the compilation unit --- and the + // start of the next compilation unit, if there is one. + uint64 Start(); + + private: + + // This struct represents a single DWARF2/3 abbreviation + // The abbreviation tells how to read a DWARF2/3 DIE, and consist of a + // tag and a list of attributes, as well as the data form of each attribute. + struct Abbrev { + uint64 number; + enum DwarfTag tag; + bool has_children; + AttributeList attributes; + }; + + // A DWARF2/3 compilation unit header. This is not the same size as + // in the actual file, as the one in the file may have a 32 bit or + // 64 bit length. + struct CompilationUnitHeader { + uint64 length; + uint16 version; + uint64 abbrev_offset; + uint8 address_size; + } header_; + + // Reads the DWARF2/3 header for this compilation unit. + void ReadHeader(); + + // Reads the DWARF2/3 abbreviations for this compilation unit + void ReadAbbrevs(); + + // Processes a single DIE for this compilation unit and return a new + // pointer just past the end of it + const uint8_t *ProcessDIE(uint64 dieoffset, + const uint8_t *start, + const Abbrev& abbrev); + + // Processes a single attribute and return a new pointer just past the + // end of it + const uint8_t *ProcessAttribute(uint64 dieoffset, + const uint8_t *start, + enum DwarfAttribute attr, + enum DwarfForm form); + + // Called when we have an attribute with unsigned data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + // If we see a DW_AT_GNU_dwo_id attribute, save the value so that + // we can find the debug info in a .dwo or .dwp file. + void ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + if (attr == DW_AT_GNU_dwo_id) { + dwo_id_ = data; + } + else if (attr == DW_AT_GNU_addr_base) { + addr_base_ = data; + } + else if (attr == DW_AT_GNU_ranges_base) { + ranges_base_ = data; + } + // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, + // that base will apply to DW_AT_ranges attributes in the + // skeleton CU as well as in the .dwo/.dwp files. + else if (attr == DW_AT_ranges && is_split_dwarf_) { + data += ranges_base_; + } + handler_->ProcessAttributeUnsigned(offset, attr, form, data); + } + + // Called when we have an attribute with signed data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + void ProcessAttributeSigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + handler_->ProcessAttributeSigned(offset, attr, form, data); + } + + // Called when we have an attribute with a buffer of data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA, and the + // length of the buffer is LENGTH. + void ProcessAttributeBuffer(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t* data, + uint64 len) { + handler_->ProcessAttributeBuffer(offset, attr, form, data, len); + } + + // Called when we have an attribute with string data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + // If we see a DW_AT_GNU_dwo_name attribute, save the value so + // that we can find the debug info in a .dwo or .dwp file. + void ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const char* data) { + if (attr == DW_AT_GNU_dwo_name) + dwo_name_ = data; + handler_->ProcessAttributeString(offset, attr, form, data); + } + + // Processes all DIEs for this compilation unit + void ProcessDIEs(); + + // Skips the die with attributes specified in ABBREV starting at + // START, and return the new place to position the stream to. + const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev); + + // Skips the attribute starting at START, with FORM, and return the + // new place to position the stream to. + const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form); + + // Process the actual debug information in a split DWARF file. + void ProcessSplitDwarf(); + + // Read the debug sections from a .dwo file. + void ReadDebugSectionsFromDwo(ElfReader* elf_reader, + SectionMap* sections); + + // Path of the file containing the debug information. + const string path_; + + // Offset from section start is the offset of this compilation unit + // from the beginning of the .debug_info section. + uint64 offset_from_section_start_; + + // buffer is the buffer for our CU, starting at .debug_info + offset + // passed in from constructor. + // after_header points to right after the compilation unit header. + const uint8_t *buffer_; + uint64 buffer_length_; + const uint8_t *after_header_; + + // The associated ByteReader that handles endianness issues for us + ByteReader* reader_; + + // The map of sections in our file to buffers containing their data + const SectionMap& sections_; + + // The associated handler to call processing functions in + Dwarf2Handler* handler_; + + // Set of DWARF2/3 abbreviations for this compilation unit. Indexed + // by abbreviation number, which means that abbrevs_[0] is not + // valid. + std::vector* abbrevs_; + + // String section buffer and length, if we have a string section. + // This is here to avoid doing a section lookup for strings in + // ProcessAttribute, which is in the hot path for DWARF2 reading. + const uint8_t *string_buffer_; + uint64 string_buffer_length_; + + // String offsets section buffer and length, if we have a string offsets + // section (.debug_str_offsets or .debug_str_offsets.dwo). + const uint8_t* str_offsets_buffer_; + uint64 str_offsets_buffer_length_; + + // Address section buffer and length, if we have an address section + // (.debug_addr). + const uint8_t* addr_buffer_; + uint64 addr_buffer_length_; + + // Flag indicating whether this compilation unit is part of a .dwo + // or .dwp file. If true, we are reading this unit because a + // skeleton compilation unit in an executable file had a + // DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute. + // In a .dwo file, we expect the string offsets section to + // have a ".dwo" suffix, and we will use the ".debug_addr" section + // associated with the skeleton compilation unit. + bool is_split_dwarf_; + + // The value of the DW_AT_GNU_dwo_id attribute, if any. + uint64 dwo_id_; + + // The value of the DW_AT_GNU_dwo_name attribute, if any. + const char* dwo_name_; + + // If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute + // from the skeleton CU. + uint64 skeleton_dwo_id_; + + // The value of the DW_AT_GNU_ranges_base attribute, if any. + uint64 ranges_base_; + + // The value of the DW_AT_GNU_addr_base attribute, if any. + uint64 addr_base_; + + // True if we have already looked for a .dwp file. + bool have_checked_for_dwp_; + + // Path to the .dwp file. + string dwp_path_; + + // ByteReader for the DWP file. + std::unique_ptr dwp_byte_reader_; + + // DWP reader. + std::unique_ptr dwp_reader_; +}; + +// A Reader for a .dwp file. Supports the fetching of DWARF debug +// info for a given dwo_id. +// +// There are two versions of .dwp files. In both versions, the +// .dwp file is an ELF file containing only debug sections. +// In Version 1, the file contains many copies of each debug +// section, one for each .dwo file that is packaged in the .dwp +// file, and the .debug_cu_index section maps from the dwo_id +// to a set of section indexes. In Version 2, the file contains +// one of each debug section, and the .debug_cu_index section +// maps from the dwo_id to a set of offsets and lengths that +// identify each .dwo file's contribution to the larger sections. + +class DwpReader { + public: + DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); + + ~DwpReader(); + + // Read the CU index and initialize data members. + void Initialize(); + + // Read the debug sections for the given dwo_id. + void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections); + + private: + // Search a v1 hash table for "dwo_id". Returns the slot index + // where the dwo_id was found, or -1 if it was not found. + int LookupCU(uint64 dwo_id); + + // Search a v2 hash table for "dwo_id". Returns the row index + // in the offsets and sizes tables, or 0 if it was not found. + uint32 LookupCUv2(uint64 dwo_id); + + // The ELF reader for the .dwp file. + ElfReader* elf_reader_; + + // The ByteReader for the .dwp file. + const ByteReader& byte_reader_; + + // Pointer to the .debug_cu_index section. + const char* cu_index_; + + // Size of the .debug_cu_index section. + size_t cu_index_size_; + + // Pointer to the .debug_str.dwo section. + const char* string_buffer_; + + // Size of the .debug_str.dwo section. + size_t string_buffer_size_; + + // Version of the .dwp file. We support versions 1 and 2 currently. + int version_; + + // Number of columns in the section tables (version 2). + unsigned int ncolumns_; + + // Number of units in the section tables (version 2). + unsigned int nunits_; + + // Number of slots in the hash table. + unsigned int nslots_; + + // Pointer to the beginning of the hash table. + const char* phash_; + + // Pointer to the beginning of the index table. + const char* pindex_; + + // Pointer to the beginning of the section index pool (version 1). + const char* shndx_pool_; + + // Pointer to the beginning of the section offset table (version 2). + const char* offset_table_; + + // Pointer to the beginning of the section size table (version 2). + const char* size_table_; + + // Contents of the sections of interest (version 2). + const char* abbrev_data_; + size_t abbrev_size_; + const char* info_data_; + size_t info_size_; + const char* str_offsets_data_; + size_t str_offsets_size_; +}; + +// This class is a reader for DWARF's Call Frame Information. CFI +// describes how to unwind stack frames --- even for functions that do +// not follow fixed conventions for saving registers, whose frame size +// varies as they execute, etc. +// +// CFI describes, at each machine instruction, how to compute the +// stack frame's base address, how to find the return address, and +// where to find the saved values of the caller's registers (if the +// callee has stashed them somewhere to free up the registers for its +// own use). +// +// For example, suppose we have a function whose machine code looks +// like this (imagine an assembly language that looks like C, for a +// machine with 32-bit registers, and a stack that grows towards lower +// addresses): +// +// func: ; entry point; return address at sp +// func+0: sp = sp - 16 ; allocate space for stack frame +// func+1: sp[12] = r0 ; save r0 at sp+12 +// ... ; other code, not frame-related +// func+10: sp -= 4; *sp = x ; push some x on the stack +// ... ; other code, not frame-related +// func+20: r0 = sp[16] ; restore saved r0 +// func+21: sp += 20 ; pop whole stack frame +// func+22: pc = *sp; sp += 4 ; pop return address and jump to it +// +// DWARF CFI is (a very compressed representation of) a table with a +// row for each machine instruction address and a column for each +// register showing how to restore it, if possible. +// +// A special column named "CFA", for "Canonical Frame Address", tells how +// to compute the base address of the frame; registers' entries may +// refer to the CFA in describing where the registers are saved. +// +// Another special column, named "RA", represents the return address. +// +// For example, here is a complete (uncompressed) table describing the +// function above: +// +// insn cfa r0 r1 ... ra +// ======================================= +// func+0: sp cfa[0] +// func+1: sp+16 cfa[0] +// func+2: sp+16 cfa[-4] cfa[0] +// func+11: sp+20 cfa[-4] cfa[0] +// func+21: sp+20 cfa[0] +// func+22: sp cfa[0] +// +// Some things to note here: +// +// - Each row describes the state of affairs *before* executing the +// instruction at the given address. Thus, the row for func+0 +// describes the state before we allocate the stack frame. In the +// next row, the formula for computing the CFA has changed, +// reflecting that allocation. +// +// - The other entries are written in terms of the CFA; this allows +// them to remain unchanged as the stack pointer gets bumped around. +// For example, the rule for recovering the return address (the "ra" +// column) remains unchanged throughout the function, even as the +// stack pointer takes on three different offsets from the return +// address. +// +// - Although we haven't shown it, most calling conventions designate +// "callee-saves" and "caller-saves" registers. The callee must +// preserve the values of callee-saves registers; if it uses them, +// it must save their original values somewhere, and restore them +// before it returns. In contrast, the callee is free to trash +// caller-saves registers; if the callee uses these, it will +// probably not bother to save them anywhere, and the CFI will +// probably mark their values as "unrecoverable". +// +// (However, since the caller cannot assume the callee was going to +// save them, caller-saves registers are probably dead in the caller +// anyway, so compilers usually don't generate CFA for caller-saves +// registers.) +// +// - Exactly where the CFA points is a matter of convention that +// depends on the architecture and ABI in use. In the example, the +// CFA is the value the stack pointer had upon entry to the +// function, pointing at the saved return address. But on the x86, +// the call frame information generated by GCC follows the +// convention that the CFA is the address *after* the saved return +// address. +// +// But by definition, the CFA remains constant throughout the +// lifetime of the frame. This makes it a useful value for other +// columns to refer to. It is also gives debuggers a useful handle +// for identifying a frame. +// +// If you look at the table above, you'll notice that a given entry is +// often the same as the one immediately above it: most instructions +// change only one or two aspects of the stack frame, if they affect +// it at all. The DWARF format takes advantage of this fact, and +// reduces the size of the data by mentioning only the addresses and +// columns at which changes take place. So for the above, DWARF CFI +// data would only actually mention the following: +// +// insn cfa r0 r1 ... ra +// ======================================= +// func+0: sp cfa[0] +// func+1: sp+16 +// func+2: cfa[-4] +// func+11: sp+20 +// func+21: r0 +// func+22: sp +// +// In fact, this is the way the parser reports CFI to the consumer: as +// a series of statements of the form, "At address X, column Y changed +// to Z," and related conventions for describing the initial state. +// +// Naturally, it would be impractical to have to scan the entire +// program's CFI, noting changes as we go, just to recover the +// unwinding rules in effect at one particular instruction. To avoid +// this, CFI data is grouped into "entries", each of which covers a +// specified range of addresses and begins with a complete statement +// of the rules for all recoverable registers at that starting +// address. Each entry typically covers a single function. +// +// Thus, to compute the contents of a given row of the table --- that +// is, rules for recovering the CFA, RA, and registers at a given +// instruction --- the consumer should find the entry that covers that +// instruction's address, start with the initial state supplied at the +// beginning of the entry, and work forward until it has processed all +// the changes up to and including those for the present instruction. +// +// There are seven kinds of rules that can appear in an entry of the +// table: +// +// - "undefined": The given register is not preserved by the callee; +// its value cannot be recovered. +// +// - "same value": This register has the same value it did in the callee. +// +// - offset(N): The register is saved at offset N from the CFA. +// +// - val_offset(N): The value the register had in the caller is the +// CFA plus offset N. (This is usually only useful for describing +// the stack pointer.) +// +// - register(R): The register's value was saved in another register R. +// +// - expression(E): Evaluating the DWARF expression E using the +// current frame's registers' values yields the address at which the +// register was saved. +// +// - val_expression(E): Evaluating the DWARF expression E using the +// current frame's registers' values yields the value the register +// had in the caller. + +class CallFrameInfo { + public: + // The different kinds of entries one finds in CFI. Used internally, + // and for error reporting. + enum EntryKind { kUnknown, kCIE, kFDE, kTerminator }; + + // The handler class to which the parser hands the parsed call frame + // information. Defined below. + class Handler; + + // A reporter class, which CallFrameInfo uses to report errors + // encountered while parsing call frame information. Defined below. + class Reporter; + + // Create a DWARF CFI parser. BUFFER points to the contents of the + // .debug_frame section to parse; BUFFER_LENGTH is its length in bytes. + // REPORTER is an error reporter the parser should use to report + // problems. READER is a ByteReader instance that has the endianness and + // address size set properly. Report the data we find to HANDLER. + // + // This class can also parse Linux C++ exception handling data, as found + // in '.eh_frame' sections. This data is a variant of DWARF CFI that is + // placed in loadable segments so that it is present in the program's + // address space, and is interpreted by the C++ runtime to search the + // call stack for a handler interested in the exception being thrown, + // actually pop the frames, and find cleanup code to run. + // + // There are two differences between the call frame information described + // in the DWARF standard and the exception handling data Linux places in + // the .eh_frame section: + // + // - Exception handling data uses uses a different format for call frame + // information entry headers. The distinguished CIE id, the way FDEs + // refer to their CIEs, and the way the end of the series of entries is + // determined are all slightly different. + // + // If the constructor's EH_FRAME argument is true, then the + // CallFrameInfo parses the entry headers as Linux C++ exception + // handling data. If EH_FRAME is false or omitted, the CallFrameInfo + // parses standard DWARF call frame information. + // + // - Linux C++ exception handling data uses CIE augmentation strings + // beginning with 'z' to specify the presence of additional data after + // the CIE and FDE headers and special encodings used for addresses in + // frame description entries. + // + // CallFrameInfo can handle 'z' augmentations in either DWARF CFI or + // exception handling data if you have supplied READER with the base + // addresses needed to interpret the pointer encodings that 'z' + // augmentations can specify. See the ByteReader interface for details + // about the base addresses. See the CallFrameInfo::Handler interface + // for details about the additional information one might find in + // 'z'-augmented data. + // + // Thus: + // + // - If you are parsing standard DWARF CFI, as found in a .debug_frame + // section, you should pass false for the EH_FRAME argument, or omit + // it, and you need not worry about providing READER with the + // additional base addresses. + // + // - If you want to parse Linux C++ exception handling data from a + // .eh_frame section, you should pass EH_FRAME as true, and call + // READER's Set*Base member functions before calling our Start method. + // + // - If you want to parse DWARF CFI that uses the 'z' augmentations + // (although I don't think any toolchain ever emits such data), you + // could pass false for EH_FRAME, but call READER's Set*Base members. + // + // The extensions the Linux C++ ABI makes to DWARF for exception + // handling are described here, rather poorly: + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html + // + // The mechanics of C++ exception handling, personality routines, + // and language-specific data areas are described here, rather nicely: + // http://www.codesourcery.com/public/cxx-abi/abi-eh.html + CallFrameInfo(const uint8_t *buffer, size_t buffer_length, + ByteReader *reader, Handler *handler, Reporter *reporter, + bool eh_frame = false) + : buffer_(buffer), buffer_length_(buffer_length), + reader_(reader), handler_(handler), reporter_(reporter), + eh_frame_(eh_frame) { } + + ~CallFrameInfo() { } + + // Parse the entries in BUFFER, reporting what we find to HANDLER. + // Return true if we reach the end of the section successfully, or + // false if we encounter an error. + bool Start(); + + // Return the textual name of KIND. For error reporting. + static const char *KindName(EntryKind kind); + + private: + + struct CIE; + + // A CFI entry, either an FDE or a CIE. + struct Entry { + // The starting offset of the entry in the section, for error + // reporting. + size_t offset; + + // The start of this entry in the buffer. + const uint8_t *start; + + // Which kind of entry this is. + // + // We want to be able to use this for error reporting even while we're + // in the midst of parsing. Error reporting code may assume that kind, + // offset, and start fields are valid, although kind may be kUnknown. + EntryKind kind; + + // The end of this entry's common prologue (initial length and id), and + // the start of this entry's kind-specific fields. + const uint8_t *fields; + + // The start of this entry's instructions. + const uint8_t *instructions; + + // The address past the entry's last byte in the buffer. (Note that + // since offset points to the entry's initial length field, and the + // length field is the number of bytes after that field, this is not + // simply buffer_ + offset + length.) + const uint8_t *end; + + // For both DWARF CFI and .eh_frame sections, this is the CIE id in a + // CIE, and the offset of the associated CIE in an FDE. + uint64 id; + + // The CIE that applies to this entry, if we've parsed it. If this is a + // CIE, then this field points to this structure. + CIE *cie; + }; + + // A common information entry (CIE). + struct CIE: public Entry { + uint8 version; // CFI data version number + string augmentation; // vendor format extension markers + uint64 code_alignment_factor; // scale for code address adjustments + int data_alignment_factor; // scale for stack pointer adjustments + unsigned return_address_register; // which register holds the return addr + + // True if this CIE includes Linux C++ ABI 'z' augmentation data. + bool has_z_augmentation; + + // Parsed 'z' augmentation data. These are meaningful only if + // has_z_augmentation is true. + bool has_z_lsda; // The 'z' augmentation included 'L'. + bool has_z_personality; // The 'z' augmentation included 'P'. + bool has_z_signal_frame; // The 'z' augmentation included 'S'. + + // If has_z_lsda is true, this is the encoding to be used for language- + // specific data area pointers in FDEs. + DwarfPointerEncoding lsda_encoding; + + // If has_z_personality is true, this is the encoding used for the + // personality routine pointer in the augmentation data. + DwarfPointerEncoding personality_encoding; + + // If has_z_personality is true, this is the address of the personality + // routine --- or, if personality_encoding & DW_EH_PE_indirect, the + // address where the personality routine's address is stored. + uint64 personality_address; + + // This is the encoding used for addresses in the FDE header and + // in DW_CFA_set_loc instructions. This is always valid, whether + // or not we saw a 'z' augmentation string; its default value is + // DW_EH_PE_absptr, which is what normal DWARF CFI uses. + DwarfPointerEncoding pointer_encoding; + + // These were only introduced in DWARF4, so will not be set in older + // versions. + uint8 address_size; + uint8 segment_size; + }; + + // A frame description entry (FDE). + struct FDE: public Entry { + uint64 address; // start address of described code + uint64 size; // size of described code, in bytes + + // If cie->has_z_lsda is true, then this is the language-specific data + // area's address --- or its address's address, if cie->lsda_encoding + // has the DW_EH_PE_indirect bit set. + uint64 lsda_address; + }; + + // Internal use. + class Rule; + class UndefinedRule; + class SameValueRule; + class OffsetRule; + class ValOffsetRule; + class RegisterRule; + class ExpressionRule; + class ValExpressionRule; + class RuleMap; + class State; + + // Parse the initial length and id of a CFI entry, either a CIE, an FDE, + // or a .eh_frame end-of-data mark. CURSOR points to the beginning of the + // data to parse. On success, populate ENTRY as appropriate, and return + // true. On failure, report the problem, and return false. Even if we + // return false, set ENTRY->end to the first byte after the entry if we + // were able to figure that out, or NULL if we weren't. + bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry); + + // Parse the fields of a CIE after the entry prologue, including any 'z' + // augmentation data. Assume that the 'Entry' fields of CIE are + // populated; use CIE->fields and CIE->end as the start and limit for + // parsing. On success, populate the rest of *CIE, and return true; on + // failure, report the problem and return false. + bool ReadCIEFields(CIE *cie); + + // Parse the fields of an FDE after the entry prologue, including any 'z' + // augmentation data. Assume that the 'Entry' fields of *FDE are + // initialized; use FDE->fields and FDE->end as the start and limit for + // parsing. Assume that FDE->cie is fully initialized. On success, + // populate the rest of *FDE, and return true; on failure, report the + // problem and return false. + bool ReadFDEFields(FDE *fde); + + // Report that ENTRY is incomplete, and return false. This is just a + // trivial wrapper for invoking reporter_->Incomplete; it provides a + // little brevity. + bool ReportIncomplete(Entry *entry); + + // Return true if ENCODING has the DW_EH_PE_indirect bit set. + static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { + return encoding & DW_EH_PE_indirect; + } + + // The contents of the DWARF .debug_info section we're parsing. + const uint8_t *buffer_; + size_t buffer_length_; + + // For reading multi-byte values with the appropriate endianness. + ByteReader *reader_; + + // The handler to which we should report the data we find. + Handler *handler_; + + // For reporting problems in the info we're parsing. + Reporter *reporter_; + + // True if we are processing .eh_frame-format data. + bool eh_frame_; +}; + +// The handler class for CallFrameInfo. The a CFI parser calls the +// member functions of a handler object to report the data it finds. +class CallFrameInfo::Handler { + public: + // The pseudo-register number for the canonical frame address. + enum { kCFARegister = -1 }; + + Handler() { } + virtual ~Handler() { } + + // The parser has found CFI for the machine code at ADDRESS, + // extending for LENGTH bytes. OFFSET is the offset of the frame + // description entry in the section, for use in error messages. + // VERSION is the version number of the CFI format. AUGMENTATION is + // a string describing any producer-specific extensions present in + // the data. RETURN_ADDRESS is the number of the register that holds + // the address to which the function should return. + // + // Entry should return true to process this CFI, or false to skip to + // the next entry. + // + // The parser invokes Entry for each Frame Description Entry (FDE) + // it finds. The parser doesn't report Common Information Entries + // to the handler explicitly; instead, if the handler elects to + // process a given FDE, the parser reiterates the appropriate CIE's + // contents at the beginning of the FDE's rules. + virtual bool Entry(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address) = 0; + + // When the Entry function returns true, the parser calls these + // handler functions repeatedly to describe the rules for recovering + // registers at each instruction in the given range of machine code. + // Immediately after a call to Entry, the handler should assume that + // the rule for each callee-saves register is "unchanged" --- that + // is, that the register still has the value it had in the caller. + // + // If a *Rule function returns true, we continue processing this entry's + // instructions. If a *Rule function returns false, we stop evaluating + // instructions, and skip to the next entry. Either way, we call End + // before going on to the next entry. + // + // In all of these functions, if the REG parameter is kCFARegister, then + // the rule describes how to find the canonical frame address. + // kCFARegister may be passed as a BASE_REGISTER argument, meaning that + // the canonical frame address should be used as the base address for the + // computation. All other REG values will be positive. + + // At ADDRESS, register REG's value is not recoverable. + virtual bool UndefinedRule(uint64 address, int reg) = 0; + + // At ADDRESS, register REG's value is the same as that it had in + // the caller. + virtual bool SameValueRule(uint64 address, int reg) = 0; + + // At ADDRESS, register REG has been saved at offset OFFSET from + // BASE_REGISTER. + virtual bool OffsetRule(uint64 address, int reg, + int base_register, long offset) = 0; + + // At ADDRESS, the caller's value of register REG is the current + // value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an + // address at which the register's value is saved.) + virtual bool ValOffsetRule(uint64 address, int reg, + int base_register, long offset) = 0; + + // At ADDRESS, register REG has been saved in BASE_REGISTER. This differs + // from ValOffsetRule(ADDRESS, REG, BASE_REGISTER, 0), in that + // BASE_REGISTER is the "home" for REG's saved value: if you want to + // assign to a variable whose home is REG in the calling frame, you + // should put the value in BASE_REGISTER. + virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0; + + // At ADDRESS, the DWARF expression EXPRESSION yields the address at + // which REG was saved. + virtual bool ExpressionRule(uint64 address, int reg, + const string &expression) = 0; + + // At ADDRESS, the DWARF expression EXPRESSION yields the caller's + // value for REG. (This rule doesn't provide an address at which the + // register's value is saved.) + virtual bool ValExpressionRule(uint64 address, int reg, + const string &expression) = 0; + + // Indicate that the rules for the address range reported by the + // last call to Entry are complete. End should return true if + // everything is okay, or false if an error has occurred and parsing + // should stop. + virtual bool End() = 0; + + // Handler functions for Linux C++ exception handling data. These are + // only called if the data includes 'z' augmentation strings. + + // The Linux C++ ABI uses an extension of the DWARF CFI format to + // walk the stack to propagate exceptions from the throw to the + // appropriate catch, and do the appropriate cleanups along the way. + // CFI entries used for exception handling have two additional data + // associated with them: + // + // - The "language-specific data area" describes which exception + // types the function has 'catch' clauses for, and indicates how + // to go about re-entering the function at the appropriate catch + // clause. If the exception is not caught, it describes the + // destructors that must run before the frame is popped. + // + // - The "personality routine" is responsible for interpreting the + // language-specific data area's contents, and deciding whether + // the exception should continue to propagate down the stack, + // perhaps after doing some cleanup for this frame, or whether the + // exception will be caught here. + // + // In principle, the language-specific data area is opaque to + // everybody but the personality routine. In practice, these values + // may be useful or interesting to readers with extra context, and + // we have to at least skip them anyway, so we might as well report + // them to the handler. + + // This entry's exception handling personality routine's address is + // ADDRESS. If INDIRECT is true, then ADDRESS is the address at + // which the routine's address is stored. The default definition for + // this handler function simply returns true, allowing parsing of + // the entry to continue. + virtual bool PersonalityRoutine(uint64 address, bool indirect) { + return true; + } + + // This entry's language-specific data area (LSDA) is located at + // ADDRESS. If INDIRECT is true, then ADDRESS is the address at + // which the area's address is stored. The default definition for + // this handler function simply returns true, allowing parsing of + // the entry to continue. + virtual bool LanguageSpecificDataArea(uint64 address, bool indirect) { + return true; + } + + // This entry describes a signal trampoline --- this frame is the + // caller of a signal handler. The default definition for this + // handler function simply returns true, allowing parsing of the + // entry to continue. + // + // The best description of the rationale for and meaning of signal + // trampoline CFI entries seems to be in the GCC bug database: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26208 + virtual bool SignalHandler() { return true; } +}; + +// The CallFrameInfo class makes calls on an instance of this class to +// report errors or warn about problems in the data it is parsing. The +// default definitions of these methods print a message to stderr, but +// you can make a derived class that overrides them. +class CallFrameInfo::Reporter { + public: + // Create an error reporter which attributes troubles to the section + // named SECTION in FILENAME. + // + // Normally SECTION would be .debug_frame, but the Mac puts CFI data + // in a Mach-O section named __debug_frame. If we support + // Linux-style exception handling data, we could be reading an + // .eh_frame section. + Reporter(const string &filename, + const string §ion = ".debug_frame") + : filename_(filename), section_(section) { } + virtual ~Reporter() { } + + // The CFI entry at OFFSET ends too early to be well-formed. KIND + // indicates what kind of entry it is; KIND can be kUnknown if we + // haven't parsed enough of the entry to tell yet. + virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind); + + // The .eh_frame data has a four-byte zero at OFFSET where the next + // entry's length would be; this is a terminator. However, the buffer + // length as given to the CallFrameInfo constructor says there should be + // more data. + virtual void EarlyEHTerminator(uint64 offset); + + // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the + // section is not that large. + virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset); + + // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry + // there is not a CIE. + virtual void BadCIEId(uint64 offset, uint64 cie_offset); + + // The FDE at OFFSET refers to a CIE with an address size we don't know how + // to handle. + virtual void UnexpectedAddressSize(uint64 offset, uint8_t address_size); + + // The FDE at OFFSET refers to a CIE with an segment descriptor size we + // don't know how to handle. + virtual void UnexpectedSegmentSize(uint64 offset, uint8_t segment_size); + + // The FDE at OFFSET refers to a CIE with version number VERSION, + // which we don't recognize. We cannot parse DWARF CFI if it uses + // a version number we don't recognize. + virtual void UnrecognizedVersion(uint64 offset, int version); + + // The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION, + // which we don't recognize. We cannot parse DWARF CFI if it uses + // augmentations we don't recognize. + virtual void UnrecognizedAugmentation(uint64 offset, + const string &augmentation); + + // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not + // a valid encoding. + virtual void InvalidPointerEncoding(uint64 offset, uint8 encoding); + + // The pointer encoding ENCODING, specified by the CIE at OFFSET, depends + // on a base address which has not been supplied. + virtual void UnusablePointerEncoding(uint64 offset, uint8 encoding); + + // The CIE at OFFSET contains a DW_CFA_restore instruction at + // INSN_OFFSET, which may not appear in a CIE. + virtual void RestoreInCIE(uint64 offset, uint64 insn_offset); + + // The entry at OFFSET, of kind KIND, has an unrecognized + // instruction at INSN_OFFSET. + virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind, + uint64 insn_offset); + + // The instruction at INSN_OFFSET in the entry at OFFSET, of kind + // KIND, establishes a rule that cites the CFA, but we have not + // established a CFA rule yet. + virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind, + uint64 insn_offset); + + // The instruction at INSN_OFFSET in the entry at OFFSET, of kind + // KIND, is a DW_CFA_restore_state instruction, but the stack of + // saved states is empty. + virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind, + uint64 insn_offset); + + // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry + // at OFFSET, of kind KIND, would restore a state that has no CFA + // rule, whereas the current state does have a CFA rule. This is + // bogus input, which the CallFrameInfo::Handler interface doesn't + // (and shouldn't) have any way to report. + virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind, + uint64 insn_offset); + + protected: + // The name of the file whose CFI we're reading. + string filename_; + + // The name of the CFI section in that file. + string section_; +}; + +} // namespace dwarf2reader + +#endif // UTIL_DEBUGINFO_DWARF2READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc new file mode 100644 index 0000000000..35d4f340d7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc @@ -0,0 +1,2582 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo + +#include +#include + +#include +#include + +// The '.eh_frame' format, used by the Linux C++ ABI for exception +// handling, is poorly specified. To help test our support for .eh_frame, +// if you #define WRITE_ELF while compiling this file, and add the +// 'include' directory from the binutils, gcc, or gdb source tree to the +// #include path, then each test that calls the +// PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write +// an ELF file containing a .debug_frame or .eh_frame section; you can then +// use tools like readelf to examine the test data, and check the tools' +// interpretation against the test's intentions. Each ELF file is named +// "cfitest-TEST", where TEST identifies the particular test. +#ifdef WRITE_ELF +#include +#include +#include +extern "C" { +// To compile with WRITE_ELF, you should add the 'include' directory +// of the binutils, gcc, or gdb source tree to your #include path; +// that directory contains this header. +#include "elf/common.h" +} +#endif + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/cfi_assembler.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +using google_breakpad::CFISection; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Section; + +using dwarf2reader::DwarfPointerEncoding; +using dwarf2reader::ENDIANNESS_BIG; +using dwarf2reader::ENDIANNESS_LITTLE; +using dwarf2reader::ByteReader; +using dwarf2reader::CallFrameInfo; + +using std::vector; +using testing::InSequence; +using testing::Return; +using testing::Sequence; +using testing::Test; +using testing::_; + +#ifdef WRITE_ELF +void WriteELFFrameSection(const char *filename, const char *section_name, + const CFISection §ion); +#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \ + WriteELFFrameSection("cfitest-" name, ".debug_frame", section); +#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \ + WriteELFFrameSection("cfitest-" name, ".eh_frame", section); +#else +#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) +#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) +#endif + +class MockCallFrameInfoHandler: public CallFrameInfo::Handler { + public: + MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address)); + MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg)); + MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg)); + MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register, + long offset)); + MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register, + long offset)); + MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register)); + MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg, + const string &expression)); + MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg, + const string &expression)); + MOCK_METHOD0(End, bool()); + MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect)); + MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect)); + MOCK_METHOD0(SignalHandler, bool()); +}; + +class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { + public: + MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { } + MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind)); + MOCK_METHOD1(EarlyEHTerminator, void(uint64)); + MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); + MOCK_METHOD2(BadCIEId, void(uint64, uint64)); + MOCK_METHOD2(UnexpectedAddressSize, void(uint64, uint8_t)); + MOCK_METHOD2(UnexpectedSegmentSize, void(uint64, uint8_t)); + MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); + MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); + MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); + MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8)); + MOCK_METHOD2(RestoreInCIE, void(uint64, uint64)); + MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64)); + MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); + MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64)); +}; + +struct CFIFixture { + + enum { kCFARegister = CallFrameInfo::Handler::kCFARegister }; + + CFIFixture() { + // Default expectations for the data handler. + // + // - Leave Entry and End without expectations, as it's probably a + // good idea to set those explicitly in each test. + // + // - Expect the *Rule functions to not be called, + // so that each test can simply list the calls they expect. + // + // I gather I could use StrictMock for this, but the manual seems + // to suggest using that only as a last resort, and this isn't so + // bad. + EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0); + EXPECT_CALL(handler, SameValueRule(_, _)).Times(0); + EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0); + EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0); + EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0); + EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0); + EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0); + EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0); + EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0); + EXPECT_CALL(handler, SignalHandler()).Times(0); + + // Default expectations for the error/warning reporer. + EXPECT_CALL(reporter, Incomplete(_, _)).Times(0); + EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0); + EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0); + EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0); + EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0); + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0); + EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0); + EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0); + EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0); + EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0); + EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0); + EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0); + } + + MockCallFrameInfoHandler handler; + MockCallFrameErrorReporter reporter; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, EmptyRegion) { + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + static const uint8_t data[] = { 42 }; + + ByteReader byte_reader(ENDIANNESS_BIG); + CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(CFI, IncompleteLength32) { + CFISection section(kBigEndian, 8); + section + // Not even long enough for an initial length. + .D16(0xa0f) + // Padding to keep valgrind happy. We subtract these off when we + // construct the parser. + .D16(0); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size() - 2, + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(CFI, IncompleteLength64) { + CFISection section(kLittleEndian, 4); + section + // An incomplete 64-bit DWARF initial length. + .D32(0xffffffff).D32(0x71fbaec2) + // Padding to keep valgrind happy. We subtract these off when we + // construct the parser. + .D32(0); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader byte_reader(ENDIANNESS_LITTLE); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size() - 4, + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(CFI, IncompleteId32) { + CFISection section(kBigEndian, 8); + section + .D32(3) // Initial length, not long enough for id + .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id + .CIEHeader(8727, 3983, 8889, 3, "") + .FinishEntry(); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(CFI, BadId32) { + CFISection section(kBigEndian, 8); + section + .D32(0x100) // Initial length + .D32(0xe802fade) // bogus ID + .Append(0x100 - 4, 0x42); // make the length true + section + .CIEHeader(1672, 9872, 8529, 3, "") + .FinishEntry(); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// A lone CIE shouldn't cause any handler calls. +TEST_F(CFI, SingleCIE) { + CFISection section(kLittleEndian, 4); + section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); + section.Append(10, dwarf2reader::DW_CFA_nop); + section.FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_LITTLE); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// One FDE, one CIE. +TEST_F(CFI, OneFDE) { + CFISection section(kBigEndian, 4); + Label cie; + section + .Mark(&cie) + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "") + .FinishEntry() + .FDEHeader(cie, 0x7714740d, 0x3d5a10cd) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// Two FDEs share a CIE. +TEST_F(CFI, TwoFDEsOneCIE) { + CFISection section(kBigEndian, 4); + Label cie; + section + // First FDE. readelf complains about this one because it makes + // a forward reference to its CIE. + .FDEHeader(cie, 0xa42744df, 0xa3b42121) + .FinishEntry() + // CIE. + .Mark(&cie) + .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "") + .FinishEntry() + // Second FDE. + .FDEHeader(cie, 0x6057d391, 0x700f608d) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// Two FDEs, two CIEs. +TEST_F(CFI, TwoFDEsTwoCIEs) { + CFISection section(kLittleEndian, 8); + Label cie1, cie2; + section + // First CIE. + .Mark(&cie1) + .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "") + .FinishEntry() + // First FDE which cites second CIE. readelf complains about + // this one because it makes a forward reference to its CIE. + .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL) + .FinishEntry() + // Second FDE, which cites first CIE. + .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL) + .FinishEntry() + // Second CIE. + .Mark(&cie2) + .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "") + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2, + "", 0x61d2c581)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3, + "", 0xbf45e65a)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_LITTLE); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// An FDE whose CIE specifies a version we don't recognize. +TEST_F(CFI, BadVersion) { + CFISection section(kBigEndian, 4); + Label cie1, cie2; + section + .Mark(&cie1) + .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "") + .FinishEntry() + // We should skip this entry, as its CIE specifies a version we + // don't recognize. + .FDEHeader(cie1, 0x08852292, 0x2204004a) + .FinishEntry() + // Despite the above, we should visit this entry. + .Mark(&cie2) + .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "") + .FinishEntry() + .FDEHeader(cie2, 0x2094735a, 0x6e875501) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section); + + EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52)) + .WillOnce(Return()); + + { + InSequence s; + // We should see no mention of the first FDE, but we should get + // a call to Entry for the second. + EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "", + 0x96cb3264)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// An FDE whose CIE specifies an augmentation we don't recognize. +TEST_F(CFI, BadAugmentation) { + CFISection section(kBigEndian, 4); + Label cie1, cie2; + section + .Mark(&cie1) + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!") + .FinishEntry() + // We should skip this entry, as its CIE specifies an + // augmentation we don't recognize. + .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd) + .FinishEntry() + // Despite the above, we should visit this entry. + .Mark(&cie2) + .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "") + .FinishEntry() + .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section); + + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!")) + .WillOnce(Return()); + + { + InSequence s; + // We should see no mention of the first FDE, but we should get + // a call to Entry for the second. + EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "", + 0xf2f519b2)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// The return address column field is a byte in CFI version 1 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3). +TEST_F(CFI, CIEVersion1ReturnColumn) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, using the version 1 format: return column is a ubyte. + .Mark(&cie) + // Use a value for the return column that is parsed differently + // as a ubyte and as a ULEB128. + .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "") + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0xb8d347b5, 0x825e55dc) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// The return address column field is a byte in CFI version 1 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3). +TEST_F(CFI, CIEVersion3ReturnColumn) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, using the version 3 format: return column is a ULEB128. + .Mark(&cie) + // Use a value for the return column that is parsed differently + // as a ubyte and as a ULEB128. + .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "") + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFields) { + CFISection section(kBigEndian, 8); + Label cie; + section + .Mark(&cie) + // CIE version 4 with expected address (64bit) and segment size. + .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 8, 0) + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFields32BitAddress) { + CFISection section(kBigEndian, 4); + Label cie; + section + .Mark(&cie) + // CIE version 4 with expected address (32bit) and segment size. + .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 4, 0) + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) { + CFISection section(kBigEndian, 4); + Label cie; + + section + .Mark(&cie) + // Unexpected address size. + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 4, "", true, 3, 0) + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedAddress", section); + + EXPECT_CALL(reporter, UnexpectedAddressSize(_, 3)) + .WillOnce(Return()); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) { + CFISection section(kBigEndian, 8); + Label cie; + + section + .Mark(&cie) + .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 4, "", true, 8, 7) + .FinishEntry() + .FDEHeader(cie, 0x7bf0fda0, 0xcbcd28d8) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedSegment", section); + + EXPECT_CALL(reporter, UnexpectedSegmentSize(_, 7)) + .WillOnce(Return()); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +struct CFIInsnFixture: public CFIFixture { + CFIInsnFixture() : CFIFixture() { + data_factor = 0xb6f; + return_register = 0x9be1ed9f; + version = 3; + cfa_base_register = 0x383a3aa; + cfa_offset = 0xf748; + } + + // Prepare SECTION to receive FDE instructions. + // + // - Append a stock CIE header that establishes the fixture's + // code_factor, data_factor, return_register, version, and + // augmentation values. + // - Have the CIE set up a CFA rule using cfa_base_register and + // cfa_offset. + // - Append a stock FDE header, referring to the above CIE, for the + // fde_size bytes at fde_start. Choose fde_start and fde_size + // appropriately for the section's address size. + // - Set appropriate expectations on handler in sequence s for the + // frame description entry and the CIE's CFA rule. + // + // On return, SECTION is ready to have FDE instructions appended to + // it, and its FinishEntry member called. + void StockCIEAndFDE(CFISection *section) { + // Choose appropriate constants for our address size. + if (section->AddressSize() == 4) { + fde_start = 0xc628ecfbU; + fde_size = 0x5dee04a2; + code_factor = 0x60b; + } else { + assert(section->AddressSize() == 8); + fde_start = 0x0005c57ce7806bd3ULL; + fde_size = 0x2699521b5e333100ULL; + code_factor = 0x01008e32855274a8ULL; + } + + // Create the CIE. + (*section) + .Mark(&cie_label) + .CIEHeader(code_factor, data_factor, return_register, version, + "") + .D8(dwarf2reader::DW_CFA_def_cfa) + .ULEB128(cfa_base_register) + .ULEB128(cfa_offset) + .FinishEntry(); + + // Create the FDE. + section->FDEHeader(cie_label, fde_start, fde_size); + + // Expect an Entry call for the FDE and a ValOffsetRule call for the + // CIE's CFA rule. + EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "", + return_register)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister, + cfa_base_register, cfa_offset)) + .InSequence(s) + .WillOnce(Return(true)); + } + + // Run the contents of SECTION through a CallFrameInfo parser, + // expecting parser.Start to return SUCCEEDS + void ParseSection(CFISection *section, bool succeeds = true) { + string contents; + EXPECT_TRUE(section->GetContents(&contents)); + dwarf2reader::Endianness endianness; + if (section->endianness() == kBigEndian) + endianness = ENDIANNESS_BIG; + else { + assert(section->endianness() == kLittleEndian); + endianness = ENDIANNESS_LITTLE; + } + ByteReader byte_reader(endianness); + byte_reader.SetAddressSize(section->AddressSize()); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + if (succeeds) + EXPECT_TRUE(parser.Start()); + else + EXPECT_FALSE(parser.Start()); + } + + Label cie_label; + Sequence s; + uint64 code_factor; + int data_factor; + unsigned return_register; + unsigned version; + unsigned cfa_base_register; + int cfa_offset; + uint64 fde_start, fde_size; +}; + +class CFIInsn: public CFIInsnFixture, public Test { }; + +TEST_F(CFIInsn, DW_CFA_set_loc) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a) + // Use DW_CFA_def_cfa to force a handler call that we can use to + // check the effect of the DW_CFA_set_loc. + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); + + EXPECT_CALL(handler, + ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_advance_loc) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a) + // Use DW_CFA_def_cfa to force a handler call that we can use to + // check the effect of the DW_CFA_advance_loc. + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start + 0x2a * code_factor, + kCFARegister, 0x5bbb3715, 0x0186c7bf)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_advance_loc1) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8) + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0xd8 * code_factor), + kCFARegister, 0x69d5696a, 0x1eb7fc93)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_advance_loc2) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb) + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x3adb * code_factor), + kCFARegister, 0x3a368bed, 0x3194ee37)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_advance_loc4) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88) + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x15813c88ULL * code_factor), + kCFARegister, 0x135270c5, 0x24bad7cb)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) { + code_factor = 0x2d; + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor), + kCFARegister, 0xe17ed602, 0x3d162e7f)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa_sf) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) + .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7, + 0x9ea * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da, + -0x40a2 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa_register) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// DW_CFA_def_cfa_register should have no effect when applied to a +// non-base/offset rule. +TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack") + .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, kCFARegister, + "needle in a haystack")) + .WillRepeatedly(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + 0x1e8e3b9b)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970) + .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + 0x970 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + -0x2cd * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// DW_CFA_def_cfa_offset should have no effect when applied to a +// non-base/offset rule. +TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday") + .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday")) + .WillRepeatedly(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_def_cfa_expression) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow") + .FinishEntry(); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, + "eating crow")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_undefined) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_same_value) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_offset_extended) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_offset_extended_sf) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .ULEB128(0x997c23ee).LEB128(0x2d00) + .D8(dwarf2reader::DW_CFA_offset_extended_sf) + .ULEB128(0x9519eb82).LEB128(-0xa77) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x997c23ee, + kCFARegister, 0x2d00 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x9519eb82, + kCFARegister, -0xa77 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_val_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x623562fe, + kCFARegister, 0x673 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_val_offset_sf) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) + .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x6f4f, + kCFARegister, 0xaab * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x2483, + kCFARegister, -0x8a2 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_register) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_expression) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2) + .Block("plus ça change, plus c'est la même chose") + .FinishEntry(); + + EXPECT_CALL(handler, + ExpressionRule(fde_start, 0xa1619fb2, + "plus ça change, plus c'est la même chose")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_val_expression) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) + .Block("he who has the gold makes the rules") + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, 0xc5e4a9e3, + "he who has the gold makes the rules")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_restore) { + CFISection section(kLittleEndian, 8); + code_factor = 0x01bd188a9b1fa083ULL; + data_factor = -0x1ac8; + return_register = 0x8c35b049; + version = 2; + fde_start = 0x2d70fe998298bbb1ULL; + fde_size = 0x46ccc2e63cf0b108ULL; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, + "") + // Provide a CFA rule, because register rules require them. + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) + // Provide an offset(N) rule for register 0x3c. + .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide a new offset(N) rule for register 0x3c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0x13) + .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50) + // At a third address, restore the original rule for register 0x3c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0x01) + .D8(dwarf2reader::DW_CFA_restore | 0x3c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8)) + .WillOnce(Return(true)); + // CIE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor)) + .WillOnce(Return(true)); + // FDE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x13 * code_factor, 0x3c, + kCFARegister, 0x9a50 * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c, + kCFARegister, 0xb348 * data_factor)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_restoreNoRule) { + CFISection section(kBigEndian, 4); + code_factor = 0x005f78143c1c3b82ULL; + data_factor = 0x25d0; + return_register = 0xe8; + version = 1; + fde_start = 0x4062e30f; + fde_size = 0x5302a389; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, "") + // Provide a CFA rule, because register rules require them. + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide an offset(N) rule for register 0x2c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0x7) + .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47) + // At a third address, restore the (missing) CIE rule for register 0x2c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0xb) + .D8(dwarf2reader::DW_CFA_restore | 0x2c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127)) + .WillOnce(Return(true)); + // FDE's rule for register 0x2c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x7 * code_factor, 0x2c, + kCFARegister, 0x1f47 * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's (missing) rule for register 0x2c. + EXPECT_CALL(handler, + SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_restore_extended) { + CFISection section(kBigEndian, 4); + code_factor = 0x126e; + data_factor = -0xd8b; + return_register = 0x77711787; + version = 3; + fde_start = 0x01f55a45; + fde_size = 0x452adb80; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, + "", true /* dwarf64 */ ) + // Provide a CFA rule, because register rules require them. + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) + // Provide an offset(N) rule for register 0x0f9b8a1c. + .D8(dwarf2reader::DW_CFA_offset_extended) + .ULEB128(0x0f9b8a1c).ULEB128(0xc979) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0x3) + .D8(dwarf2reader::DW_CFA_offset_extended) + .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) + // At a third address, restore the original rule for register 0x0f9b8a1c. + .D8(dwarf2reader::DW_CFA_advance_loc | 0x04) + .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5)) + .WillOnce(Return(true)); + // CIE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister, + 0xc979 * data_factor)) + .WillOnce(Return(true)); + // FDE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c, + kCFARegister, 0x3b7b * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c, + kCFARegister, 0xc979 * data_factor)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + + // We create a state, save it, modify it, and then restore. We + // refer to the state that is overridden the restore as the + // "outgoing" state, and the restored state the "incoming" state. + // + // Register outgoing incoming expect + // 1 offset(N) no rule new "same value" rule + // 2 register(R) offset(N) report changed rule + // 3 offset(N) offset(M) report changed offset + // 4 offset(N) offset(N) no report + // 5 offset(N) no rule new "same value" rule + section + // Create the "incoming" state, which we will save and later restore. + .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806) + .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d) + .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055) + .D8(dwarf2reader::DW_CFA_remember_state) + // Advance to a new instruction; an implementation could legitimately + // ignore all but the final rule for a given register at a given address. + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + // Create the "outgoing" state, which we will discard. + .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a) + .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) + .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29) + .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce) + // At a third address, restore the incoming state. + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + uint64 addr = fde_start; + + // Expect the incoming rules to be reported. + EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + + addr += code_factor; + + // After the save, we establish the outgoing rule set. + EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor)) + .InSequence(s).WillOnce(Return(true)); + + addr += code_factor; + + // Finally, after the restore, expect to see the differences from + // the outgoing to the incoming rules reported. + EXPECT_CALL(handler, SameValueRule(addr, 1)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(addr, 5)) + .InSequence(s).WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// Check that restoring a rule set reports changes to the CFA rule. +TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + + section + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, + cfa_base_register, 0x90481102)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister, + cfa_base_register, cfa_offset)) + .InSequence(s).WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_nop) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_nop) + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) + .D8(dwarf2reader::DW_CFA_nop) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_GNU_window_save) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_GNU_window_save) + .FinishEntry(); + + // Don't include all the rules in any particular sequence. + + // The caller's %o0-%o7 have become the callee's %i0-%i7. This is + // the GCC register numbering. + for (int i = 8; i < 16; i++) + EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16)) + .WillOnce(Return(true)); + // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of + // its frame. + for (int i = 16; i < 32; i++) + EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4)) + .WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_GNU_args_size) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) + // Verify that we see this, meaning we parsed the above properly. + .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended) + .ULEB128(0x430cc87a).ULEB128(0x613) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x430cc87a, + kCFARegister, -0x613 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// Three FDEs: skip the second +TEST_F(CFIInsn, SkipFDE) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, used by all FDEs. + .Mark(&cie) + .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) + .FinishEntry() + // First FDE. + .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) + .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) + .FinishEntry() + // Second FDE. + .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) + .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) + .FinishEntry() + // Third FDE. + .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) + .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) + .FinishEntry(); + + { + InSequence s; + + // Process the first FDE. + EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister, + 0x42ed390b, 0x98f43aad)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + + // Skip the second FDE. + EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849)) + .WillOnce(Return(false)); + + // Process the third FDE. + EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister, + 0x42ed390b, 0x98f43aad)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +// Quit processing in the middle of an entry's instructions. +TEST_F(CFIInsn, QuitMidentry) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) + .InSequence(s).WillOnce(Return(false)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, false); +} + +class CFIRestore: public CFIInsnFixture, public Test { }; + +TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreUndefinedRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreSameValueRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, + kCFARegister, 0xb6f * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreOffsetRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, + kCFARegister, 0x134 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21, + kCFARegister, 0xf4f * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, + kCFARegister, 0x134 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, + kCFARegister, 0xe4c * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValOffsetRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, + kCFARegister, 0x562 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b, + kCFARegister, 0xe88 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b, + kCFARegister, 0x562 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreRegisterRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5, + 0x095f1559)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1, + 0xbabb4742)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1, + 0x16607d6a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreExpressionRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, + "elf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739, + "orc")) + .InSequence(s).WillOnce(Return(true)); + // Expectations are not wishes. + EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739, + "smurf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152) + .Block("hideous") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValExpressionRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46) + .Block("revolting") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, + "revolting")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) + .Block("repulsive") + .D8(dwarf2reader::DW_CFA_remember_state) + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) + .Block("nauseous") + .D8(dwarf2reader::DW_CFA_advance_loc | 1) + .D8(dwarf2reader::DW_CFA_restore_state) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", + section); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739, + "nauseous")) + .InSequence(s).WillOnce(Return(true)); + // Expectations are not wishes. + EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739, + "repulsive")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +struct EHFrameFixture: public CFIInsnFixture { + EHFrameFixture() + : CFIInsnFixture(), section(kBigEndian, 4, true) { + encoded_pointer_bases.cfi = 0x7f496cb2; + encoded_pointer_bases.text = 0x540f67b6; + encoded_pointer_bases.data = 0xe3eab768; + section.SetEncodedPointerBases(encoded_pointer_bases); + } + CFISection section; + CFISection::EncodedPointerBases encoded_pointer_bases; + + // Parse CFIInsnFixture::ParseSection, but parse the section as + // .eh_frame data, supplying stock base addresses. + void ParseEHFrameSection(CFISection *section, bool succeeds = true) { + EXPECT_TRUE(section->ContainsEHFrame()); + string contents; + EXPECT_TRUE(section->GetContents(&contents)); + dwarf2reader::Endianness endianness; + if (section->endianness() == kBigEndian) + endianness = ENDIANNESS_BIG; + else { + assert(section->endianness() == kLittleEndian); + endianness = ENDIANNESS_LITTLE; + } + ByteReader byte_reader(endianness); + byte_reader.SetAddressSize(section->AddressSize()); + byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, + reinterpret_cast(contents.data())); + byte_reader.SetTextBase(encoded_pointer_bases.text); + byte_reader.SetDataBase(encoded_pointer_bases.data); + CallFrameInfo parser(reinterpret_cast(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter, true); + if (succeeds) + EXPECT_TRUE(parser.Start()); + else + EXPECT_FALSE(parser.Start()); + } + +}; + +class EHFrame: public EHFrameFixture, public Test { }; + +// A simple CIE, an FDE, and a terminator. +TEST_F(EHFrame, Terminator) { + Label cie; + section + .Mark(&cie) + .CIEHeader(9968, 2466, 67, 1, "") + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) + .FinishEntry() + .FDEHeader(cie, 0x848037a1, 0x7b30475e) + .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721) + .FinishEntry() + .D32(0) // Terminate the sequence. + // This FDE should be ignored. + .FDEHeader(cie, 0xf19629fe, 0x439fb09b) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section); + + EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(reporter, EarlyEHTerminator(_)) + .InSequence(s).WillOnce(Return()); + + ParseEHFrameSection(§ion); +} + +// The parser should recognize the Linux Standards Base 'z' augmentations. +TEST_F(EHFrame, SimpleFDE) { + DwarfPointerEncoding lsda_encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect + | dwarf2reader::DW_EH_PE_datarel + | dwarf2reader::DW_EH_PE_sdata2); + DwarfPointerEncoding fde_encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel + | dwarf2reader::DW_EH_PE_udata2); + + section.SetPointerEncoding(fde_encoding); + section.SetEncodedPointerBases(encoded_pointer_bases); + Label cie; + section + .Mark(&cie) + .CIEHeader(4873, 7012, 100, 1, "zSLPR") + .ULEB128(7) // Augmentation data length + .D8(lsda_encoding) // LSDA pointer format + .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format + .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value + .D8(fde_encoding) // FDE pointer format + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) + .FinishEntry() + .FDEHeader(cie, 0x540f6b56, 0xf686) + .ULEB128(2) // Augmentation data length + .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed + .D8(dwarf2reader::DW_CFA_set_loc) + .EncodedPointer(0x540fa4ce, fde_encoding) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e) + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section); + + EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SignalHandler()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// Check that we can handle an empty 'z' augmentation. +TEST_F(EHFrame, EmptyZ) { + Label cie; + section + .Mark(&cie) + .CIEHeader(5955, 5805, 228, 1, "z") + .ULEB128(0) // Augmentation data length + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) + .FinishEntry() + .FDEHeader(cie, 0xda007738, 0xfb55c641) + .ULEB128(0) // Augmentation data length + .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11) + .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); + + EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// Check that we recognize bad 'z' augmentation characters. +TEST_F(EHFrame, BadZ) { + Label cie; + section + .Mark(&cie) + .CIEHeader(6937, 1045, 142, 1, "zQ") + .ULEB128(0) // Augmentation data length + .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) + .FinishEntry() + .FDEHeader(cie, 0x1293efa8, 0x236f53f2) + .ULEB128(0) // Augmentation data length + .D8(dwarf2reader::DW_CFA_advance_loc | 12) + .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); + + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ")) + .WillOnce(Return()); + + ParseEHFrameSection(§ion, false); +} + +TEST_F(EHFrame, zL) { + Label cie; + DwarfPointerEncoding lsda_encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel + | dwarf2reader::DW_EH_PE_udata2); + section + .Mark(&cie) + .CIEHeader(9285, 9959, 54, 1, "zL") + .ULEB128(1) // Augmentation data length + .D8(lsda_encoding) // encoding for LSDA pointer in FDE + + .FinishEntry() + .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) + .ULEB128(2) // Augmentation data length + .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section); + + EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(EHFrame, zP) { + Label cie; + DwarfPointerEncoding personality_encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel + | dwarf2reader::DW_EH_PE_udata2); + section + .Mark(&cie) + .CIEHeader(1097, 6313, 17, 1, "zP") + .ULEB128(3) // Augmentation data length + .D8(personality_encoding) // encoding for personality routine + .EncodedPointer(0xe3eaccac, personality_encoding) // value + .FinishEntry() + .FDEHeader(cie, 0x0c8350c9, 0xbef11087) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section); + + EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(EHFrame, zR) { + Label cie; + DwarfPointerEncoding pointer_encoding = + DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel + | dwarf2reader::DW_EH_PE_sdata2); + section.SetPointerEncoding(pointer_encoding); + section + .Mark(&cie) + .CIEHeader(8011, 5496, 75, 1, "zR") + .ULEB128(1) // Augmentation data length + .D8(pointer_encoding) // encoding for FDE addresses + .FinishEntry() + .FDEHeader(cie, 0x540f9431, 0xbd0) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section); + + EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(EHFrame, zS) { + Label cie; + section + .Mark(&cie) + .CIEHeader(9217, 7694, 57, 1, "zS") + .ULEB128(0) // Augmentation data length + .FinishEntry() + .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section); + + EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SignalHandler()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// These tests require manual inspection of the test output. +struct CFIReporterFixture { + CFIReporterFixture() : reporter("test file name", "test section name") { } + CallFrameInfo::Reporter reporter; +}; + +class CFIReporter: public CFIReporterFixture, public Test { }; + +TEST_F(CFIReporter, Incomplete) { + reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown); +} + +TEST_F(CFIReporter, EarlyEHTerminator) { + reporter.EarlyEHTerminator(0x0102030405060708ULL); +} + +TEST_F(CFIReporter, CIEPointerOutOfRange) { + reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, BadCIEId) { + reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, UnrecognizedVersion) { + reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43); +} + +TEST_F(CFIReporter, UnrecognizedAugmentation) { + reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles"); +} + +TEST_F(CFIReporter, InvalidPointerEncoding) { + reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42); +} + +TEST_F(CFIReporter, UnusablePointerEncoding) { + reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42); +} + +TEST_F(CFIReporter, RestoreInCIE) { + reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, BadInstruction) { + reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE, + 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, NoCFARule) { + reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE, + 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, EmptyStateStack) { + reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator, + 0xfedcba9876543210ULL); +} + +TEST_F(CFIReporter, ClearingCFARule) { + reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE, + 0xfedcba9876543210ULL); +} + +#ifdef WRITE_ELF +// See comments at the top of the file mentioning WRITE_ELF for details. + +using google_breakpad::test_assembler::Section; + +struct ELFSectionHeader { + ELFSectionHeader(unsigned int set_type) + : type(set_type), flags(0), address(0), link(0), info(0), + alignment(1), entry_size(0) { } + Label name; + unsigned int type; + uint64_t flags; + uint64_t address; + Label file_offset; + Label file_size; + unsigned int link; + unsigned int info; + uint64_t alignment; + uint64_t entry_size; +}; + +void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { + (*table) + .D32(header.name) // name, index in string tbl + .D32(header.type) // type + .Address(header.flags) // flags + .Address(header.address) // address in memory + .Address(header.file_offset) // offset in ELF file + .Address(header.file_size) // length in bytes + .D32(header.link) // link to related section + .D32(header.info) // miscellaneous + .Address(header.alignment) // alignment + .Address(header.entry_size); // entry size +} + +void WriteELFFrameSection(const char *filename, const char *cfi_name, + const CFISection &cfi) { + int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64; + int elf_data = (cfi.endianness() == kBigEndian + ? ELFDATA2MSB : ELFDATA2LSB); + CFISection elf(cfi.endianness(), cfi.AddressSize()); + Label elf_header_size, section_table_offset; + elf + .Append("\x7f" "ELF") + .D8(elf_class) // 32-bit or 64-bit ELF + .D8(elf_data) // endianness + .D8(1) // ELF version + .D8(ELFOSABI_LINUX) // Operating System/ABI indication + .D8(0) // ABI version + .Append(7, 0xda) // padding + .D16(ET_EXEC) // file type: executable file + .D16(EM_386) // architecture: Intel IA-32 + .D32(EV_CURRENT); // ELF version + elf + .Address(0x0123456789abcdefULL) // program entry point + .Address(0) // program header offset + .Address(section_table_offset) // section header offset + .D32(0) // processor-specific flags + .D16(elf_header_size) // ELF header size in bytes */ + .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size + .D16(0) // program header table entry count + .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size + .D16(3) // section count + .D16(1) // section name string table + .Mark(&elf_header_size); + + // The null section. Every ELF file has one, as the first entry in + // the section header table. + ELFSectionHeader null_header(SHT_NULL); + null_header.file_offset = 0; + null_header.file_size = 0; + + // The CFI section. The whole reason for writing out this ELF file + // is to put this in it so that we can run other dumping programs on + // it to check its contents. + ELFSectionHeader cfi_header(SHT_PROGBITS); + cfi_header.file_size = cfi.Size(); + + // The section holding the names of the sections. This is the + // section whose index appears in the e_shstrndx member of the ELF + // header. + ELFSectionHeader section_names_header(SHT_STRTAB); + CFISection section_names(cfi.endianness(), cfi.AddressSize()); + section_names + .Mark(&null_header.name) + .AppendCString("") + .Mark(§ion_names_header.name) + .AppendCString(".shstrtab") + .Mark(&cfi_header.name) + .AppendCString(cfi_name) + .Mark(§ion_names_header.file_size); + + // Create the section table. The ELF header's e_shoff member refers + // to this, and the e_shnum member gives the number of entries it + // contains. + CFISection section_table(cfi.endianness(), cfi.AddressSize()); + AppendSectionHeader(§ion_table, null_header); + AppendSectionHeader(§ion_table, section_names_header); + AppendSectionHeader(§ion_table, cfi_header); + + // Append the section table and the section contents to the ELF file. + elf + .Mark(§ion_table_offset) + .Append(section_table) + .Mark(§ion_names_header.file_offset) + .Append(section_names) + .Mark(&cfi_header.file_offset) + .Append(cfi); + + string contents; + if (!elf.GetContents(&contents)) { + fprintf(stderr, "failed to get ELF file contents\n"); + exit(1); + } + + FILE *out = fopen(filename, "w"); + if (!out) { + fprintf(stderr, "error opening ELF file '%s': %s\n", + filename, strerror(errno)); + exit(1); + } + + if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) { + fprintf(stderr, "error writing ELF data to '%s': %s\n", + filename, strerror(errno)); + exit(1); + } + + if (fclose(out) == EOF) { + fprintf(stderr, "error closing ELF file '%s': %s\n", + filename, strerror(errno)); + exit(1); + } +} +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc new file mode 100644 index 0000000000..71418eb8d7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -0,0 +1,487 @@ +// Copyright (c) 2012, 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. + +// Original author: Jim Blandy + +// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit + +#include +#include + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/dwarf2reader_test_common.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +using google_breakpad::test_assembler::Endianness; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; + +using dwarf2reader::ByteReader; +using dwarf2reader::CompilationUnit; +using dwarf2reader::Dwarf2Handler; +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfHasChild; +using dwarf2reader::DwarfTag; +using dwarf2reader::ENDIANNESS_BIG; +using dwarf2reader::ENDIANNESS_LITTLE; +using dwarf2reader::SectionMap; + +using std::vector; +using testing::InSequence; +using testing::Pointee; +using testing::Return; +using testing::Sequence; +using testing::Test; +using testing::TestWithParam; +using testing::_; + +class MockDwarf2Handler: public Dwarf2Handler { + public: + MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version)); + MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag)); + MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset, + DwarfAttribute attr, + enum DwarfForm form, + uint64 data)); + MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data)); + MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data)); + MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64 len)); + MOCK_METHOD4(ProcessAttributeString, void(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string& data)); + MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset, + DwarfAttribute attr, + enum DwarfForm form, + uint64 signature)); + MOCK_METHOD1(EndDIE, void(uint64 offset)); +}; + +struct DIEFixture { + + DIEFixture() { + // Fix the initial offset of the .debug_info and .debug_abbrev sections. + info.start() = 0; + abbrevs.start() = 0; + + // Default expectations for the data handler. + EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0); + EXPECT_CALL(handler, StartDIE(_, _)).Times(0); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0); + EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0); + EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0); + EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0); + EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0); + EXPECT_CALL(handler, EndDIE(_)).Times(0); + } + + // Return a reference to a section map whose .debug_info section refers + // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This + // function returns a reference to the same SectionMap each time; new + // calls wipe out maps established by earlier calls. + const SectionMap &MakeSectionMap() { + // Copy the sections' contents into strings that will live as long as + // the map itself. + assert(info.GetContents(&info_contents)); + assert(abbrevs.GetContents(&abbrevs_contents)); + section_map.clear(); + section_map[".debug_info"].first + = reinterpret_cast(info_contents.data()); + section_map[".debug_info"].second = info_contents.size(); + section_map[".debug_abbrev"].first + = reinterpret_cast(abbrevs_contents.data()); + section_map[".debug_abbrev"].second = abbrevs_contents.size(); + return section_map; + } + + TestCompilationUnit info; + TestAbbrevTable abbrevs; + MockDwarf2Handler handler; + string abbrevs_contents, info_contents; + SectionMap section_map; +}; + +struct DwarfHeaderParams { + DwarfHeaderParams(Endianness endianness, size_t format_size, + int version, size_t address_size) + : endianness(endianness), format_size(format_size), + version(version), address_size(address_size) { } + Endianness endianness; + size_t format_size; // 4-byte or 8-byte DWARF offsets + int version; + size_t address_size; +}; + +class DwarfHeader: public DIEFixture, + public TestWithParam { }; + +TEST_P(DwarfHeader, Header) { + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, + dwarf2reader::DW_children_yes) + .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + + info.Header(GetParam().version, abbrev_table, GetParam().address_size) + .ULEB128(1) // DW_TAG_compile_unit, with children + .AppendCString("sam") // DW_AT_name, DW_FORM_string + .D8(0); // end of children + info.Finish(); + + { + InSequence s; + EXPECT_CALL(handler, + StartCompilationUnit(0, GetParam().address_size, + GetParam().format_size, _, + GetParam().version)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_string, + "sam")) + .WillOnce(Return()); + EXPECT_CALL(handler, EndDIE(_)) + .WillOnce(Return()); + } + + ByteReader byte_reader(GetParam().endianness == kLittleEndian ? + ENDIANNESS_LITTLE : ENDIANNESS_BIG); + CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler); + EXPECT_EQ(parser.Start(), info_contents.size()); +} + +INSTANTIATE_TEST_CASE_P( + HeaderVariants, DwarfHeader, + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), + DwarfHeaderParams(kLittleEndian, 4, 2, 8), + DwarfHeaderParams(kLittleEndian, 4, 3, 4), + DwarfHeaderParams(kLittleEndian, 4, 3, 8), + DwarfHeaderParams(kLittleEndian, 4, 4, 4), + DwarfHeaderParams(kLittleEndian, 4, 4, 8), + DwarfHeaderParams(kLittleEndian, 8, 2, 4), + DwarfHeaderParams(kLittleEndian, 8, 2, 8), + DwarfHeaderParams(kLittleEndian, 8, 3, 4), + DwarfHeaderParams(kLittleEndian, 8, 3, 8), + DwarfHeaderParams(kLittleEndian, 8, 4, 4), + DwarfHeaderParams(kLittleEndian, 8, 4, 8), + DwarfHeaderParams(kBigEndian, 4, 2, 4), + DwarfHeaderParams(kBigEndian, 4, 2, 8), + DwarfHeaderParams(kBigEndian, 4, 3, 4), + DwarfHeaderParams(kBigEndian, 4, 3, 8), + DwarfHeaderParams(kBigEndian, 4, 4, 4), + DwarfHeaderParams(kBigEndian, 4, 4, 8), + DwarfHeaderParams(kBigEndian, 8, 2, 4), + DwarfHeaderParams(kBigEndian, 8, 2, 8), + DwarfHeaderParams(kBigEndian, 8, 3, 4), + DwarfHeaderParams(kBigEndian, 8, 3, 8), + DwarfHeaderParams(kBigEndian, 8, 4, 4), + DwarfHeaderParams(kBigEndian, 8, 4, 8))); + +struct DwarfFormsFixture: public DIEFixture { + // Start a compilation unit, as directed by |params|, containing one + // childless DIE of the given tag, with one attribute of the given name + // and form. The 'info' fixture member is left just after the abbrev + // code, waiting for the attribute value to be appended. + void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, + DwarfTag tag, DwarfAttribute name, + DwarfForm form) { + // Create the abbreviation table. + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no) + .Attribute(name, form) + .EndAbbrev() + .EndTable(); + + // Create the compilation unit, up to the attribute value. + info.set_format_size(params.format_size); + info.set_endianness(params.endianness); + info.Header(params.version, abbrev_table, params.address_size) + .ULEB128(1); // abbrev code + } + + // Set up handler to expect a compilation unit matching |params|, + // containing one childless DIE of the given tag, in the sequence s. Stop + // just before the expectations. + void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, + DwarfTag tag, uint64 offset=0) { + EXPECT_CALL(handler, + StartCompilationUnit(offset, params.address_size, + params.format_size, _, + params.version)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, StartDIE(_, tag)) + .InSequence(s) + .WillOnce(Return(true)); + } + + void ExpectEndCompilationUnit() { + EXPECT_CALL(handler, EndDIE(_)) + .InSequence(s) + .WillOnce(Return()); + } + + void ParseCompilationUnit(const DwarfHeaderParams ¶ms, uint64 offset=0) { + ByteReader byte_reader(params.endianness == kLittleEndian ? + ENDIANNESS_LITTLE : ENDIANNESS_BIG); + CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); + EXPECT_EQ(offset + parser.Start(), info_contents.size()); + } + + // The sequence to which the fixture's methods append expectations. + Sequence s; +}; + +struct DwarfForms: public DwarfFormsFixture, + public TestWithParam { }; + +TEST_P(DwarfForms, addr) { + StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit, + dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr); + uint64_t value; + if (GetParam().address_size == 4) { + value = 0xc8e9ffcc; + info.D32(value); + } else { + value = 0xe942517fc2768564ULL; + info.D64(value); + } + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, block2_empty) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, + (DwarfAttribute) 0xe52c4463, + dwarf2reader::DW_FORM_block2); + info.D16(0); + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); + EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, + dwarf2reader::DW_FORM_block2, + _, 0)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, block2) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, + (DwarfAttribute) 0xe52c4463, + dwarf2reader::DW_FORM_block2); + unsigned char data[258]; + memset(data, '*', sizeof(data)); + info.D16(sizeof(data)) + .Append(data, sizeof(data)); + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); + EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, + dwarf2reader::DW_FORM_block2, + Pointee('*'), 258)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, flag_present) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, + (DwarfAttribute) 0x359d1972, + dwarf2reader::DW_FORM_flag_present); + // DW_FORM_flag_present occupies no space in the DIE. + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); + EXPECT_CALL(handler, + ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, + dwarf2reader::DW_FORM_flag_present, + 1)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, sec_offset) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, + (DwarfAttribute) 0xa060bfd1, + dwarf2reader::DW_FORM_sec_offset); + uint64_t value; + if (GetParam().format_size == 4) { + value = 0xacc9c388; + info.D32(value); + } else { + value = 0xcffe5696ffe3ed0aULL; + info.D64(value); + } + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, + dwarf2reader::DW_FORM_sec_offset, + value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, exprloc) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, + (DwarfAttribute) 0xba3ae5cb, + dwarf2reader::DW_FORM_exprloc); + info.ULEB128(29) + .Append(29, 173); + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); + EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, + dwarf2reader::DW_FORM_exprloc, + Pointee(173), 29)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, ref_sig8) { + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, + (DwarfAttribute) 0xd708d908, + dwarf2reader::DW_FORM_ref_sig8); + info.D64(0xf72fa0cb6ddcf9d6ULL); + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); + EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, + dwarf2reader::DW_FORM_ref_sig8, + 0xf72fa0cb6ddcf9d6ULL)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +// A value passed to ProcessAttributeSignature is just an absolute number, +// not an offset within the compilation unit as most of the other +// DW_FORM_ref forms are. Check that the reader doesn't try to apply any +// offset to the signature, by reading it from a compilation unit that does +// not start at the beginning of the section. +TEST_P(DwarfForms, ref_sig8_not_first) { + info.Append(98, '*'); + StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, + (DwarfAttribute) 0xd708d908, + dwarf2reader::DW_FORM_ref_sig8); + info.D64(0xf72fa0cb6ddcf9d6ULL); + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); + EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, + dwarf2reader::DW_FORM_ref_sig8, + 0xf72fa0cb6ddcf9d6ULL)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam(), 98); +} + +// Tests for the other attribute forms could go here. + +INSTANTIATE_TEST_CASE_P( + HeaderVariants, DwarfForms, + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), + DwarfHeaderParams(kLittleEndian, 4, 2, 8), + DwarfHeaderParams(kLittleEndian, 4, 3, 4), + DwarfHeaderParams(kLittleEndian, 4, 3, 8), + DwarfHeaderParams(kLittleEndian, 4, 4, 4), + DwarfHeaderParams(kLittleEndian, 4, 4, 8), + DwarfHeaderParams(kLittleEndian, 8, 2, 4), + DwarfHeaderParams(kLittleEndian, 8, 2, 8), + DwarfHeaderParams(kLittleEndian, 8, 3, 4), + DwarfHeaderParams(kLittleEndian, 8, 3, 8), + DwarfHeaderParams(kLittleEndian, 8, 4, 4), + DwarfHeaderParams(kLittleEndian, 8, 4, 8), + DwarfHeaderParams(kBigEndian, 4, 2, 4), + DwarfHeaderParams(kBigEndian, 4, 2, 8), + DwarfHeaderParams(kBigEndian, 4, 3, 4), + DwarfHeaderParams(kBigEndian, 4, 3, 8), + DwarfHeaderParams(kBigEndian, 4, 4, 4), + DwarfHeaderParams(kBigEndian, 4, 4, 8), + DwarfHeaderParams(kBigEndian, 8, 2, 4), + DwarfHeaderParams(kBigEndian, 8, 2, 8), + DwarfHeaderParams(kBigEndian, 8, 3, 4), + DwarfHeaderParams(kBigEndian, 8, 3, 8), + DwarfHeaderParams(kBigEndian, 8, 4, 4), + DwarfHeaderParams(kBigEndian, 8, 4, 8))); diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h new file mode 100644 index 0000000000..e91de90610 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h @@ -0,0 +1,149 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2012, 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. + +// Original author: Jim Blandy + +// dwarf2reader_test_common.h: Define TestCompilationUnit and +// TestAbbrevTable, classes for creating properly (and improperly) +// formatted DWARF compilation unit data for unit tests. + +#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ +#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ + +#include "common/test_assembler.h" +#include "common/dwarf/dwarf2enums.h" + +// A subclass of test_assembler::Section, specialized for constructing +// DWARF compilation units. +class TestCompilationUnit: public google_breakpad::test_assembler::Section { + public: + typedef dwarf2reader::DwarfTag DwarfTag; + typedef dwarf2reader::DwarfAttribute DwarfAttribute; + typedef dwarf2reader::DwarfForm DwarfForm; + typedef google_breakpad::test_assembler::Label Label; + + // Set the section's DWARF format size (the 32-bit DWARF format or the + // 64-bit DWARF format, for lengths and section offsets --- not the + // address size) to format_size. + void set_format_size(size_t format_size) { + assert(format_size == 4 || format_size == 8); + format_size_ = format_size; + } + + // Append a DWARF section offset value, of the appropriate size for this + // compilation unit. + template + void SectionOffset(T offset) { + if (format_size_ == 4) + D32(offset); + else + D64(offset); + } + + // Append a DWARF compilation unit header to the section, with the given + // DWARF version, abbrev table offset, and address size. + TestCompilationUnit &Header(int version, const Label &abbrev_offset, + size_t address_size) { + if (format_size_ == 4) { + D32(length_); + } else { + D32(0xffffffff); + D64(length_); + } + post_length_offset_ = Size(); + D16(version); + SectionOffset(abbrev_offset); + D8(address_size); + return *this; + } + + // Mark the end of this header's DIEs. + TestCompilationUnit &Finish() { + length_ = Size() - post_length_offset_; + return *this; + } + + private: + // The DWARF format size for this compilation unit. + size_t format_size_; + + // The offset of the point in the compilation unit header immediately + // after the initial length field. + uint64_t post_length_offset_; + + // The length of the compilation unit, not including the initial length field. + Label length_; +}; + +// A subclass of test_assembler::Section specialized for constructing DWARF +// abbreviation tables. +class TestAbbrevTable: public google_breakpad::test_assembler::Section { + public: + typedef dwarf2reader::DwarfTag DwarfTag; + typedef dwarf2reader::DwarfAttribute DwarfAttribute; + typedef dwarf2reader::DwarfForm DwarfForm; + typedef dwarf2reader::DwarfHasChild DwarfHasChild; + typedef google_breakpad::test_assembler::Label Label; + + // Start a new abbreviation table entry for abbreviation code |code|, + // encoding a DIE whose tag is |tag|, and which has children if and only + // if |has_children| is true. + TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { + assert(code != 0); + ULEB128(code); + ULEB128(static_cast(tag)); + D8(static_cast(has_children)); + return *this; + }; + + // Add an attribute to the current abbreviation code whose name is |name| + // and whose form is |form|. + TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) { + ULEB128(static_cast(name)); + ULEB128(static_cast(form)); + return *this; + } + + // Finish the current abbreviation code. + TestAbbrevTable &EndAbbrev() { + ULEB128(0); + ULEB128(0); + return *this; + } + + // Finish the current abbreviation table. + TestAbbrevTable &EndTable() { + ULEB128(0); + return *this; + } +}; + +#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc new file mode 100644 index 0000000000..7e4be639a7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc @@ -0,0 +1,1274 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// Author: chatham@google.com (Andrew Chatham) +// Author: satorux@google.com (Satoru Takabayashi) +// +// Code for reading in ELF files. +// +// For information on the ELF format, see +// http://www.x86.org/ftp/manuals/tools/elf.pdf +// +// I also liked: +// http://www.caldera.com/developers/gabi/1998-04-29/contents.html +// +// A note about types: When dealing with the file format, we use types +// like Elf32_Word, but in the public interfaces we treat all +// addresses as uint64. As a result, we should be able to symbolize +// 64-bit binaries from a 32-bit process (which we don't do, +// anyway). size_t should therefore be avoided, except where required +// by things like mmap(). +// +// Although most of this code can deal with arbitrary ELF files of +// either word size, the public ElfReader interface only examines +// files loaded into the current address space, which must all match +// the machine's native word size. This code cannot handle ELF files +// with a non-native byte ordering. +// +// TODO(chatham): It would be nice if we could accomplish this task +// without using malloc(), so we could use it as the process is dying. + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE // needed for pread() +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +// TODO(saugustine): Add support for compressed debug. +// Also need to add configure tests for zlib. +//#include "zlib.h" + +#include "third_party/musl/include/elf.h" +#include "elf_reader.h" +#include "common/using_std_string.h" + +// EM_AARCH64 is not defined by elf.h of GRTE v3 on x86. +// TODO(dougkwan): Remove this when v17 is retired. +#if !defined(EM_AARCH64) +#define EM_AARCH64 183 /* ARM AARCH64 */ +#endif + +// Map Linux macros to their Apple equivalents. +#if __APPLE__ || __FreeBSD__ +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#endif // __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif // __BIG_ENDIAN +#ifndef __BYTE_ORDER +#define __BYTE_ORDER __BYTE_ORDER__ +#endif // __BYTE_ORDER +#endif // __APPLE__ + +// TODO(dthomson): Can be removed once all Java code is using the Google3 +// launcher. We need to avoid processing PLT functions as it causes memory +// fragmentation in malloc, which is fixed in tcmalloc - and if the Google3 +// launcher is used the JVM will then use tcmalloc. b/13735638 +//DEFINE_bool(elfreader_process_dynsyms, true, +// "Activate PLT function processing"); + +using std::vector; + +namespace { + +// The lowest bit of an ARM symbol value is used to indicate a Thumb address. +const int kARMThumbBitOffset = 0; + +// Converts an ARM Thumb symbol value to a true aligned address value. +template +T AdjustARMThumbSymbolValue(const T& symbol_table_value) { + return symbol_table_value & ~(1 << kARMThumbBitOffset); +} + +// Names of PLT-related sections. +const char kElfPLTRelSectionName[] = ".rel.plt"; // Use Rel struct. +const char kElfPLTRelaSectionName[] = ".rela.plt"; // Use Rela struct. +const char kElfPLTSectionName[] = ".plt"; +const char kElfDynSymSectionName[] = ".dynsym"; + +const int kX86PLTCodeSize = 0x10; // Size of one x86 PLT function in bytes. +const int kARMPLTCodeSize = 0xc; +const int kAARCH64PLTCodeSize = 0x10; + +const int kX86PLT0Size = 0x10; // Size of the special PLT0 entry. +const int kARMPLT0Size = 0x14; +const int kAARCH64PLT0Size = 0x20; + +// Suffix for PLT functions when it needs to be explicitly identified as such. +const char kPLTFunctionSuffix[] = "@plt"; + +} // namespace + +namespace dwarf2reader { + +template class ElfReaderImpl; + +// 32-bit and 64-bit ELF files are processed exactly the same, except +// for various field sizes. Elf32 and Elf64 encompass all of the +// differences between the two formats, and all format-specific code +// in this file is templated on one of them. +class Elf32 { + public: + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Phdr Phdr; + typedef Elf32_Word Word; + typedef Elf32_Sym Sym; + typedef Elf32_Rel Rel; + typedef Elf32_Rela Rela; + + // What should be in the EI_CLASS header. + static const int kElfClass = ELFCLASS32; + + // Given a symbol pointer, return the binding type (eg STB_WEAK). + static char Bind(const Elf32_Sym *sym) { + return ELF32_ST_BIND(sym->st_info); + } + // Given a symbol pointer, return the symbol type (eg STT_FUNC). + static char Type(const Elf32_Sym *sym) { + return ELF32_ST_TYPE(sym->st_info); + } + + // Extract the symbol index from the r_info field of a relocation. + static int r_sym(const Elf32_Word r_info) { + return ELF32_R_SYM(r_info); + } +}; + + +class Elf64 { + public: + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Phdr Phdr; + typedef Elf64_Word Word; + typedef Elf64_Sym Sym; + typedef Elf64_Rel Rel; + typedef Elf64_Rela Rela; + + // What should be in the EI_CLASS header. + static const int kElfClass = ELFCLASS64; + + static char Bind(const Elf64_Sym *sym) { + return ELF64_ST_BIND(sym->st_info); + } + static char Type(const Elf64_Sym *sym) { + return ELF64_ST_TYPE(sym->st_info); + } + static int r_sym(const Elf64_Xword r_info) { + return ELF64_R_SYM(r_info); + } +}; + + +// ElfSectionReader mmaps a section of an ELF file ("section" is ELF +// terminology). The ElfReaderImpl object providing the section header +// must exist for the lifetime of this object. +// +// The motivation for mmaping individual sections of the file is that +// many Google executables are large enough when unstripped that we +// have to worry about running out of virtual address space. +// +// For compressed sections we have no choice but to allocate memory. +template +class ElfSectionReader { + public: + ElfSectionReader(const char *name, const string &path, int fd, + const typename ElfArch::Shdr §ion_header) + : contents_aligned_(NULL), + contents_(NULL), + header_(section_header) { + // Back up to the beginning of the page we're interested in. + const size_t additional = header_.sh_offset % getpagesize(); + const size_t offset_aligned = header_.sh_offset - additional; + section_size_ = header_.sh_size; + size_aligned_ = section_size_ + additional; + // If the section has been stripped or is empty, do not attempt + // to process its contents. + if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) + return; + contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED, + fd, offset_aligned); + // Set where the offset really should begin. + contents_ = reinterpret_cast(contents_aligned_) + + (header_.sh_offset - offset_aligned); + + // Check for and handle any compressed contents. + //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0) + // DecompressZlibContents(); + // TODO(saugustine): Add support for proposed elf-section flag + // "SHF_COMPRESS". + } + + ~ElfSectionReader() { + if (contents_aligned_ != NULL) + munmap(contents_aligned_, size_aligned_); + else + delete[] contents_; + } + + // Return the section header for this section. + typename ElfArch::Shdr const &header() const { return header_; } + + // Return memory at the given offset within this section. + const char *GetOffset(typename ElfArch::Word bytes) const { + return contents_ + bytes; + } + + const char *contents() const { return contents_; } + size_t section_size() const { return section_size_; } + + private: + // page-aligned file contents + void *contents_aligned_; + // contents as usable by the client. For non-compressed sections, + // pointer within contents_aligned_ to where the section data + // begins; for compressed sections, pointer to the decompressed + // data. + char *contents_; + // size of contents_aligned_ + size_t size_aligned_; + // size of contents. + size_t section_size_; + const typename ElfArch::Shdr header_; +}; + +// An iterator over symbols in a given section. It handles walking +// through the entries in the specified section and mapping symbol +// entries to their names in the appropriate string table (in +// another section). +template +class SymbolIterator { + public: + SymbolIterator(ElfReaderImpl *reader, + typename ElfArch::Word section_type) + : symbol_section_(reader->GetSectionByType(section_type)), + string_section_(NULL), + num_symbols_in_section_(0), + symbol_within_section_(0) { + + // If this section type doesn't exist, leave + // num_symbols_in_section_ as zero, so this iterator is already + // done(). + if (symbol_section_ != NULL) { + num_symbols_in_section_ = symbol_section_->header().sh_size / + symbol_section_->header().sh_entsize; + + // Symbol sections have sh_link set to the section number of + // the string section containing the symbol names. + string_section_ = reader->GetSection(symbol_section_->header().sh_link); + } + } + + // Return true iff we have passed all symbols in this section. + bool done() const { + return symbol_within_section_ >= num_symbols_in_section_; + } + + // Advance to the next symbol in this section. + // REQUIRES: !done() + void Next() { ++symbol_within_section_; } + + // Return a pointer to the current symbol. + // REQUIRES: !done() + const typename ElfArch::Sym *GetSymbol() const { + return reinterpret_cast( + symbol_section_->GetOffset(symbol_within_section_ * + symbol_section_->header().sh_entsize)); + } + + // Return the name of the current symbol, NULL if it has none. + // REQUIRES: !done() + const char *GetSymbolName() const { + int name_offset = GetSymbol()->st_name; + if (name_offset == 0) + return NULL; + return string_section_->GetOffset(name_offset); + } + + int GetCurrentSymbolIndex() const { + return symbol_within_section_; + } + + private: + const ElfSectionReader *const symbol_section_; + const ElfSectionReader *string_section_; + int num_symbols_in_section_; + int symbol_within_section_; +}; + + +// Copied from strings/strutil.h. Per chatham, +// this library should not depend on strings. + +static inline bool MyHasSuffixString(const string& str, const string& suffix) { + int len = str.length(); + int suflen = suffix.length(); + return (suflen <= len) && (str.compare(len-suflen, suflen, suffix) == 0); +} + + +// ElfReader loads an ELF binary and can provide information about its +// contents. It is most useful for matching addresses to function +// names. It does not understand debugging formats (eg dwarf2), so it +// can't print line numbers. It takes a path to an elf file and a +// readable file descriptor for that file, which it does not assume +// ownership of. +template +class ElfReaderImpl { + public: + explicit ElfReaderImpl(const string &path, int fd) + : path_(path), + fd_(fd), + section_headers_(NULL), + program_headers_(NULL), + opd_section_(NULL), + base_for_text_(0), + plts_supported_(false), + plt_code_size_(0), + plt0_size_(0), + visited_relocation_entries_(false) { + string error; + is_dwp_ = MyHasSuffixString(path, ".dwp"); + ParseHeaders(fd, path); + // Currently we need some extra information for PowerPC64 binaries + // including a way to read the .opd section for function descriptors and a + // way to find the linked base for function symbols. + if (header_.e_machine == EM_PPC64) { + // "opd_section_" must always be checked for NULL before use. + opd_section_ = GetSectionInfoByName(".opd", &opd_info_); + for (unsigned int k = 0u; k < GetNumSections(); ++k) { + const char *name = GetSectionName(section_headers_[k].sh_name); + if (strncmp(name, ".text", strlen(".text")) == 0) { + base_for_text_ = + section_headers_[k].sh_addr - section_headers_[k].sh_offset; + break; + } + } + } + // Turn on PLTs. + if (header_.e_machine == EM_386 || header_.e_machine == EM_X86_64) { + plt_code_size_ = kX86PLTCodeSize; + plt0_size_ = kX86PLT0Size; + plts_supported_ = true; + } else if (header_.e_machine == EM_ARM) { + plt_code_size_ = kARMPLTCodeSize; + plt0_size_ = kARMPLT0Size; + plts_supported_ = true; + } else if (header_.e_machine == EM_AARCH64) { + plt_code_size_ = kAARCH64PLTCodeSize; + plt0_size_ = kAARCH64PLT0Size; + plts_supported_ = true; + } + } + + ~ElfReaderImpl() { + for (unsigned int i = 0u; i < sections_.size(); ++i) + delete sections_[i]; + delete [] section_headers_; + delete [] program_headers_; + } + + // Examine the headers of the file and return whether the file looks + // like an ELF file for this architecture. Takes an already-open + // file descriptor for the candidate file, reading in the prologue + // to see if the ELF file appears to match the current + // architecture. If error is non-NULL, it will be set with a reason + // in case of failure. + static bool IsArchElfFile(int fd, string *error) { + unsigned char header[EI_NIDENT]; + if (pread(fd, header, sizeof(header), 0) != sizeof(header)) { + if (error != NULL) *error = "Could not read header"; + return false; + } + + if (memcmp(header, ELFMAG, SELFMAG) != 0) { + if (error != NULL) *error = "Missing ELF magic"; + return false; + } + + if (header[EI_CLASS] != ElfArch::kElfClass) { + if (error != NULL) *error = "Different word size"; + return false; + } + + int endian = 0; + if (header[EI_DATA] == ELFDATA2LSB) + endian = __LITTLE_ENDIAN; + else if (header[EI_DATA] == ELFDATA2MSB) + endian = __BIG_ENDIAN; + if (endian != __BYTE_ORDER) { + if (error != NULL) *error = "Different byte order"; + return false; + } + + return true; + } + + // Return true if we can use this symbol in Address-to-Symbol map. + bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) { + // For now we only save FUNC and NOTYPE symbols. For now we just + // care about functions, but some functions written in assembler + // don't have a proper ELF type attached to them, so we store + // NOTYPE symbols as well. The remaining significant type is + // OBJECT (eg global variables), which represent about 25% of + // the symbols in a typical google3 binary. + if (ElfArch::Type(sym) != STT_FUNC && + ElfArch::Type(sym) != STT_NOTYPE) { + return false; + } + + // Target specific filtering. + switch (header_.e_machine) { + case EM_AARCH64: + case EM_ARM: + // Filter out '$x' special local symbols used by tools + return name[0] != '$' || ElfArch::Bind(sym) != STB_LOCAL; + case EM_X86_64: + // Filter out read-only constants like .LC123. + return name[0] != '.' || ElfArch::Bind(sym) != STB_LOCAL; + default: + return true; + } + } + + // Iterate over the symbols in a section, either SHT_DYNSYM or + // SHT_SYMTAB. Add all symbols to the given SymbolMap. + /* + void GetSymbolPositions(SymbolMap *symbols, + typename ElfArch::Word section_type, + uint64 mem_offset, + uint64 file_offset) { + // This map is used to filter out "nested" functions. + // See comment below. + AddrToSymMap addr_to_sym_map; + for (SymbolIterator it(this, section_type); + !it.done(); it.Next()) { + const char *name = it.GetSymbolName(); + if (name == NULL) + continue; + const typename ElfArch::Sym *sym = it.GetSymbol(); + if (CanUseSymbol(name, sym)) { + const int sec = sym->st_shndx; + + // We don't support special section indices. The most common + // is SHN_ABS, for absolute symbols used deep in the bowels of + // glibc. Also ignore any undefined symbols. + if (sec == SHN_UNDEF || + (sec >= SHN_LORESERVE && sec <= SHN_HIRESERVE)) { + continue; + } + + const typename ElfArch::Shdr& hdr = section_headers_[sec]; + + // Adjust for difference between where we expected to mmap + // this section, and where it was actually mmapped. + const int64 expected_base = hdr.sh_addr - hdr.sh_offset; + const int64 real_base = mem_offset - file_offset; + const int64 adjust = real_base - expected_base; + + uint64 start = sym->st_value + adjust; + + // Adjust function symbols for PowerPC64 by dereferencing and adjusting + // the function descriptor to get the function address. + if (header_.e_machine == EM_PPC64 && ElfArch::Type(sym) == STT_FUNC) { + const uint64 opd_addr = + AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); + // Only adjust the returned value if the function address was found. + if (opd_addr != sym->st_value) { + const int64 adjust_function_symbols = + real_base - base_for_text_; + start = opd_addr + adjust_function_symbols; + } + } + + addr_to_sym_map.push_back(std::make_pair(start, sym)); + } + } + std::sort(addr_to_sym_map.begin(), addr_to_sym_map.end(), &AddrToSymSorter); + addr_to_sym_map.erase(std::unique(addr_to_sym_map.begin(), + addr_to_sym_map.end(), &AddrToSymEquals), + addr_to_sym_map.end()); + + // Squeeze out any "nested functions". + // Nested functions are not allowed in C, but libc plays tricks. + // + // For example, here is disassembly of /lib64/tls/libc-2.3.5.so: + // 0x00000000000aa380 : cmpl $0x0,0x2781b9(%rip) + // 0x00000000000aa387 : jne 0xaa39b + // 0x00000000000aa389 <__read_nocancel+0>: mov $0x0,%rax + // 0x00000000000aa390 <__read_nocancel+7>: syscall + // 0x00000000000aa392 <__read_nocancel+9>: cmp $0xfffffffffffff001,%rax + // 0x00000000000aa398 <__read_nocancel+15>: jae 0xaa3ef + // 0x00000000000aa39a <__read_nocancel+17>: retq + // 0x00000000000aa39b : sub $0x28,%rsp + // 0x00000000000aa39f : mov %rdi,0x8(%rsp) + // ... + // Without removing __read_nocancel, symbolizer will return NULL + // given e.g. 0xaa39f (because the lower bound is __read_nocancel, + // but 0xaa39f is beyond its end. + if (addr_to_sym_map.empty()) { + return; + } + const ElfSectionReader *const symbol_section = + this->GetSectionByType(section_type); + const ElfSectionReader *const string_section = + this->GetSection(symbol_section->header().sh_link); + + typename AddrToSymMap::iterator curr = addr_to_sym_map.begin(); + // Always insert the first symbol. + symbols->AddSymbol(string_section->GetOffset(curr->second->st_name), + curr->first, curr->second->st_size); + typename AddrToSymMap::iterator prev = curr++; + for (; curr != addr_to_sym_map.end(); ++curr) { + const uint64 prev_addr = prev->first; + const uint64 curr_addr = curr->first; + const typename ElfArch::Sym *const prev_sym = prev->second; + const typename ElfArch::Sym *const curr_sym = curr->second; + if (prev_addr + prev_sym->st_size <= curr_addr || + // The next condition is true if two symbols overlap like this: + // + // Previous symbol |----------------------------| + // Current symbol |-------------------------------| + // + // These symbols are not found in google3 codebase, but in + // jdk1.6.0_01_gg1/jre/lib/i386/server/libjvm.so. + // + // 0619e040 00000046 t CardTableModRefBS::write_region_work() + // 0619e070 00000046 t CardTableModRefBS::write_ref_array_work() + // + // We allow overlapped symbols rather than ignore these. + // Due to the way SymbolMap::GetSymbolAtPosition() works, + // lookup for any address in [curr_addr, curr_addr + its size) + // (e.g. 0619e071) will produce the current symbol, + // which is the desired outcome. + prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) { + const char *name = string_section->GetOffset(curr_sym->st_name); + symbols->AddSymbol(name, curr_addr, curr_sym->st_size); + prev = curr; + } else { + // Current symbol is "nested" inside previous one like this: + // + // Previous symbol |----------------------------| + // Current symbol |---------------------| + // + // This happens within glibc, e.g. __read_nocancel is nested + // "inside" __read. Ignore "inner" symbol. + //DCHECK_LE(curr_addr + curr_sym->st_size, + // prev_addr + prev_sym->st_size); + ; + } + } + } +*/ + + void VisitSymbols(typename ElfArch::Word section_type, + ElfReader::SymbolSink *sink) { + VisitSymbols(section_type, sink, -1, -1, false); + } + + void VisitSymbols(typename ElfArch::Word section_type, + ElfReader::SymbolSink *sink, + int symbol_binding, + int symbol_type, + bool get_raw_symbol_values) { + for (SymbolIterator it(this, section_type); + !it.done(); it.Next()) { + const char *name = it.GetSymbolName(); + if (!name) continue; + const typename ElfArch::Sym *sym = it.GetSymbol(); + if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) && + (symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) { + typename ElfArch::Sym symbol = *sym; + // Add a PLT symbol in addition to the main undefined symbol. + // Only do this for SHT_DYNSYM, because PLT symbols are dynamic. + int symbol_index = it.GetCurrentSymbolIndex(); + // TODO(dthomson): Can be removed once all Java code is using the + // Google3 launcher. + if (section_type == SHT_DYNSYM && + static_cast(symbol_index) < symbols_plt_offsets_.size() && + symbols_plt_offsets_[symbol_index] != 0) { + string plt_name = string(name) + kPLTFunctionSuffix; + if (plt_function_names_[symbol_index].empty()) { + plt_function_names_[symbol_index] = plt_name; + } else if (plt_function_names_[symbol_index] != plt_name) { + ; + } + sink->AddSymbol(plt_function_names_[symbol_index].c_str(), + symbols_plt_offsets_[it.GetCurrentSymbolIndex()], + plt_code_size_); + } + if (!get_raw_symbol_values) + AdjustSymbolValue(&symbol); + sink->AddSymbol(name, symbol.st_value, symbol.st_size); + } + } + } + + void VisitRelocationEntries() { + if (visited_relocation_entries_) { + return; + } + visited_relocation_entries_ = true; + + if (!plts_supported_) { + return; + } + // First determine if PLTs exist. If not, then there is nothing to do. + ElfReader::SectionInfo plt_section_info; + const char* plt_section = + GetSectionInfoByName(kElfPLTSectionName, &plt_section_info); + if (!plt_section) { + return; + } + if (plt_section_info.size == 0) { + return; + } + + // The PLTs could be referenced by either a Rel or Rela (Rel with Addend) + // section. + ElfReader::SectionInfo rel_section_info; + ElfReader::SectionInfo rela_section_info; + const char* rel_section = + GetSectionInfoByName(kElfPLTRelSectionName, &rel_section_info); + const char* rela_section = + GetSectionInfoByName(kElfPLTRelaSectionName, &rela_section_info); + + const typename ElfArch::Rel* rel = + reinterpret_cast(rel_section); + const typename ElfArch::Rela* rela = + reinterpret_cast(rela_section); + + if (!rel_section && !rela_section) { + return; + } + + // Use either Rel or Rela section, depending on which one exists. + size_t section_size = rel_section ? rel_section_info.size + : rela_section_info.size; + size_t entry_size = rel_section ? sizeof(typename ElfArch::Rel) + : sizeof(typename ElfArch::Rela); + + // Determine the number of entries in the dynamic symbol table. + ElfReader::SectionInfo dynsym_section_info; + const char* dynsym_section = + GetSectionInfoByName(kElfDynSymSectionName, &dynsym_section_info); + // The dynsym section might not exist, or it might be empty. In either case + // there is nothing to be done so return. + if (!dynsym_section || dynsym_section_info.size == 0) { + return; + } + size_t num_dynamic_symbols = + dynsym_section_info.size / dynsym_section_info.entsize; + symbols_plt_offsets_.resize(num_dynamic_symbols, 0); + + // TODO(dthomson): Can be removed once all Java code is using the + // Google3 launcher. + // Make storage room for PLT function name strings. + plt_function_names_.resize(num_dynamic_symbols); + + for (size_t i = 0; i < section_size / entry_size; ++i) { + // Determine symbol index from the |r_info| field. + int sym_index = ElfArch::r_sym(rel_section ? rel[i].r_info + : rela[i].r_info); + if (static_cast(sym_index) >= symbols_plt_offsets_.size()) { + continue; + } + symbols_plt_offsets_[sym_index] = + plt_section_info.addr + plt0_size_ + i * plt_code_size_; + } + } + + // Return an ElfSectionReader for the first section of the given + // type by iterating through all section headers. Returns NULL if + // the section type is not found. + const ElfSectionReader *GetSectionByType( + typename ElfArch::Word section_type) { + for (unsigned int k = 0u; k < GetNumSections(); ++k) { + if (section_headers_[k].sh_type == section_type) { + return GetSection(k); + } + } + return NULL; + } + + // Return the name of section "shndx". Returns NULL if the section + // is not found. + const char *GetSectionNameByIndex(int shndx) { + return GetSectionName(section_headers_[shndx].sh_name); + } + + // Return a pointer to section "shndx", and store the size in + // "size". Returns NULL if the section is not found. + const char *GetSectionContentsByIndex(int shndx, size_t *size) { + const ElfSectionReader *section = GetSection(shndx); + if (section != NULL) { + *size = section->section_size(); + return section->contents(); + } + return NULL; + } + + // Return a pointer to the first section of the given name by + // iterating through all section headers, and store the size in + // "size". Returns NULL if the section name is not found. + const char *GetSectionContentsByName(const string §ion_name, + size_t *size) { + for (unsigned int k = 0u; k < GetNumSections(); ++k) { + // When searching for sections in a .dwp file, the sections + // we're looking for will always be at the end of the section + // table, so reverse the direction of iteration. + int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; + const char *name = GetSectionName(section_headers_[shndx].sh_name); + if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { + const ElfSectionReader *section = GetSection(shndx); + if (section == NULL) { + return NULL; + } else { + *size = section->section_size(); + return section->contents(); + } + } + } + return NULL; + } + + // This is like GetSectionContentsByName() but it returns a lot of extra + // information about the section. + const char *GetSectionInfoByName(const string §ion_name, + ElfReader::SectionInfo *info) { + for (unsigned int k = 0u; k < GetNumSections(); ++k) { + // When searching for sections in a .dwp file, the sections + // we're looking for will always be at the end of the section + // table, so reverse the direction of iteration. + int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; + const char *name = GetSectionName(section_headers_[shndx].sh_name); + if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { + const ElfSectionReader *section = GetSection(shndx); + if (section == NULL) { + return NULL; + } else { + info->type = section->header().sh_type; + info->flags = section->header().sh_flags; + info->addr = section->header().sh_addr; + info->offset = section->header().sh_offset; + info->size = section->header().sh_size; + info->link = section->header().sh_link; + info->info = section->header().sh_info; + info->addralign = section->header().sh_addralign; + info->entsize = section->header().sh_entsize; + return section->contents(); + } + } + } + return NULL; + } + + // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD + // segments are present. This is the address an ELF image was linked + // (by static linker) to be loaded at. Usually (but not always) 0 for + // shared libraries and position-independent executables. + uint64 VaddrOfFirstLoadSegment() const { + // Relocatable objects (of type ET_REL) do not have LOAD segments. + if (header_.e_type == ET_REL) { + return 0; + } + for (int i = 0; i < GetNumProgramHeaders(); ++i) { + if (program_headers_[i].p_type == PT_LOAD) { + return program_headers_[i].p_vaddr; + } + } + return 0; + } + + // According to the LSB ("ELF special sections"), sections with debug + // info are prefixed by ".debug". The names are not specified, but they + // look like ".debug_line", ".debug_info", etc. + bool HasDebugSections() { + // Debug sections are likely to be near the end, so reverse the + // direction of iteration. + for (int k = GetNumSections() - 1; k >= 0; --k) { + const char *name = GetSectionName(section_headers_[k].sh_name); + if (strncmp(name, ".debug", strlen(".debug")) == 0) return true; + if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true; + } + return false; + } + + bool IsDynamicSharedObject() const { + return header_.e_type == ET_DYN; + } + + // Return the number of sections. + uint64_t GetNumSections() const { + if (HasManySections()) + return first_section_header_.sh_size; + return header_.e_shnum; + } + + private: + typedef vector > AddrToSymMap; + + static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs, + const typename AddrToSymMap::value_type& rhs) { + return lhs.first < rhs.first; + } + + static bool AddrToSymEquals(const typename AddrToSymMap::value_type& lhs, + const typename AddrToSymMap::value_type& rhs) { + return lhs.first == rhs.first; + } + + // Does this ELF file have too many sections to fit in the program header? + bool HasManySections() const { + return header_.e_shnum == SHN_UNDEF; + } + + // Return the number of program headers. + int GetNumProgramHeaders() const { + if (HasManySections() && header_.e_phnum == 0xffff && + first_section_header_.sh_info != 0) + return first_section_header_.sh_info; + return header_.e_phnum; + } + + // Return the index of the string table. + int GetStringTableIndex() const { + if (HasManySections()) { + if (header_.e_shstrndx == 0xffff) + return first_section_header_.sh_link; + else if (header_.e_shstrndx >= GetNumSections()) + return 0; + } + return header_.e_shstrndx; + } + + // Given an offset into the section header string table, return the + // section name. + const char *GetSectionName(typename ElfArch::Word sh_name) { + const ElfSectionReader *shstrtab = + GetSection(GetStringTableIndex()); + if (shstrtab != NULL) { + return shstrtab->GetOffset(sh_name); + } + return NULL; + } + + // Return an ElfSectionReader for the given section. The reader will + // be freed when this object is destroyed. + const ElfSectionReader *GetSection(int num) { + const char *name; + // Hard-coding the name for the section-name string table prevents + // infinite recursion. + if (num == GetStringTableIndex()) + name = ".shstrtab"; + else + name = GetSectionNameByIndex(num); + ElfSectionReader *& reader = sections_[num]; + if (reader == NULL) + reader = new ElfSectionReader(name, path_, fd_, + section_headers_[num]); + return reader; + } + + // Parse out the overall header information from the file and assert + // that it looks sane. This contains information like the magic + // number and target architecture. + bool ParseHeaders(int fd, const string &path) { + // Read in the global ELF header. + if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) { + return false; + } + + // Must be an executable, dynamic shared object or relocatable object + if (header_.e_type != ET_EXEC && + header_.e_type != ET_DYN && + header_.e_type != ET_REL) { + return false; + } + // Need a section header. + if (header_.e_shoff == 0) { + return false; + } + + if (header_.e_shnum == SHN_UNDEF) { + // The number of sections in the program header is only a 16-bit value. In + // the event of overflow (greater than SHN_LORESERVE sections), e_shnum + // will read SHN_UNDEF and the true number of section header table entries + // is found in the sh_size field of the first section header. + // See: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html + if (pread(fd, &first_section_header_, sizeof(first_section_header_), + header_.e_shoff) != sizeof(first_section_header_)) { + return false; + } + } + + // Dynamically allocate enough space to store the section headers + // and read them out of the file. + const int section_headers_size = + GetNumSections() * sizeof(*section_headers_); + section_headers_ = new typename ElfArch::Shdr[section_headers_size]; + if (pread(fd, section_headers_, section_headers_size, header_.e_shoff) != + section_headers_size) { + return false; + } + + // Dynamically allocate enough space to store the program headers + // and read them out of the file. + //const int program_headers_size = + // GetNumProgramHeaders() * sizeof(*program_headers_); + program_headers_ = new typename ElfArch::Phdr[GetNumProgramHeaders()]; + + // Presize the sections array for efficiency. + sections_.resize(GetNumSections(), NULL); + return true; + } + + // Given the "value" of a function descriptor return the address of the + // function (i.e. the dereferenced value). Otherwise return "value". + uint64 AdjustPPC64FunctionDescriptorSymbolValue(uint64 value) { + if (opd_section_ != NULL && + opd_info_.addr <= value && + value < opd_info_.addr + opd_info_.size) { + uint64 offset = value - opd_info_.addr; + return (*reinterpret_cast(opd_section_ + offset)); + } + return value; + } + + void AdjustSymbolValue(typename ElfArch::Sym* sym) { + switch (header_.e_machine) { + case EM_ARM: + // For ARM architecture, if the LSB of the function symbol offset is set, + // it indicates a Thumb function. This bit should not be taken literally. + // Clear it. + if (ElfArch::Type(sym) == STT_FUNC) + sym->st_value = AdjustARMThumbSymbolValue(sym->st_value); + break; + case EM_386: + // No adjustment needed for Intel x86 architecture. However, explicitly + // define this case as we use it quite often. + break; + case EM_PPC64: + // PowerPC64 currently has function descriptors as part of the ABI. + // Function symbols need to be adjusted accordingly. + if (ElfArch::Type(sym) == STT_FUNC) + sym->st_value = AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); + break; + default: + break; + } + } + + friend class SymbolIterator; + + // The file we're reading. + const string path_; + // Open file descriptor for path_. Not owned by this object. + const int fd_; + + // The global header of the ELF file. + typename ElfArch::Ehdr header_; + + // The header of the first section. This may be used to supplement the ELF + // file header. + typename ElfArch::Shdr first_section_header_; + + // Array of GetNumSections() section headers, allocated when we read + // in the global header. + typename ElfArch::Shdr *section_headers_; + + // Array of GetNumProgramHeaders() program headers, allocated when we read + // in the global header. + typename ElfArch::Phdr *program_headers_; + + // An array of pointers to ElfSectionReaders. Sections are + // mmaped as they're needed and not released until this object is + // destroyed. + vector*> sections_; + + // For PowerPC64 we need to keep track of function descriptors when looking up + // values for funtion symbols values. Function descriptors are kept in the + // .opd section and are dereferenced to find the function address. + ElfReader::SectionInfo opd_info_; + const char *opd_section_; // Must be checked for NULL before use. + int64 base_for_text_; + + // Read PLT-related sections for the current architecture. + bool plts_supported_; + // Code size of each PLT function for the current architecture. + size_t plt_code_size_; + // Size of the special first entry in the .plt section that calls the runtime + // loader resolution routine, and that all other entries jump to when doing + // lazy symbol binding. + size_t plt0_size_; + + // Maps a dynamic symbol index to a PLT offset. + // The vector entry index is the dynamic symbol index. + std::vector symbols_plt_offsets_; + + // Container for PLT function name strings. These strings are passed by + // reference to SymbolSink::AddSymbol() so they need to be stored somewhere. + std::vector plt_function_names_; + + bool visited_relocation_entries_; + + // True if this is a .dwp file. + bool is_dwp_; +}; + +ElfReader::ElfReader(const string &path) + : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) { + // linux 2.6.XX kernel can show deleted files like this: + // /var/run/nscd/dbYLJYaE (deleted) + // and the kernel-supplied vdso and vsyscall mappings like this: + // [vdso] + // [vsyscall] + if (MyHasSuffixString(path, " (deleted)")) + return; + if (path == "[vdso]") + return; + if (path == "[vsyscall]") + return; + + fd_ = open(path.c_str(), O_RDONLY); +} + +ElfReader::~ElfReader() { + if (fd_ != -1) + close(fd_); + if (impl32_ != NULL) + delete impl32_; + if (impl64_ != NULL) + delete impl64_; +} + + +// The only word-size specific part of this file is IsNativeElfFile(). +#if ULONG_MAX == 0xffffffff +#define NATIVE_ELF_ARCH Elf32 +#elif ULONG_MAX == 0xffffffffffffffff +#define NATIVE_ELF_ARCH Elf64 +#else +#error "Invalid word size" +#endif + +template +static bool IsElfFile(const int fd, const string &path) { + if (fd < 0) + return false; + if (!ElfReaderImpl::IsArchElfFile(fd, NULL)) { + // No error message here. IsElfFile gets called many times. + return false; + } + return true; +} + +bool ElfReader::IsNativeElfFile() const { + return IsElfFile(fd_, path_); +} + +bool ElfReader::IsElf32File() const { + return IsElfFile(fd_, path_); +} + +bool ElfReader::IsElf64File() const { + return IsElfFile(fd_, path_); +} + +/* +void ElfReader::AddSymbols(SymbolMap *symbols, + uint64 mem_offset, uint64 file_offset, + uint64 length) { + if (fd_ < 0) + return; + // TODO(chatham): Actually use the information about file offset and + // the length of the mapped section. On some machines the data + // section gets mapped as executable, and we'll end up reading the + // file twice and getting some of the offsets wrong. + if (IsElf32File()) { + GetImpl32()->GetSymbolPositions(symbols, SHT_SYMTAB, + mem_offset, file_offset); + GetImpl32()->GetSymbolPositions(symbols, SHT_DYNSYM, + mem_offset, file_offset); + } else if (IsElf64File()) { + GetImpl64()->GetSymbolPositions(symbols, SHT_SYMTAB, + mem_offset, file_offset); + GetImpl64()->GetSymbolPositions(symbols, SHT_DYNSYM, + mem_offset, file_offset); + } +} +*/ + +void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) { + VisitSymbols(sink, -1, -1); +} + +void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, + int symbol_binding, + int symbol_type) { + VisitSymbols(sink, symbol_binding, symbol_type, false); +} + +void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, + int symbol_binding, + int symbol_type, + bool get_raw_symbol_values) { + if (IsElf32File()) { + GetImpl32()->VisitRelocationEntries(); + GetImpl32()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, + get_raw_symbol_values); + GetImpl32()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, + get_raw_symbol_values); + } else if (IsElf64File()) { + GetImpl64()->VisitRelocationEntries(); + GetImpl64()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, + get_raw_symbol_values); + GetImpl64()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, + get_raw_symbol_values); + } +} + +uint64 ElfReader::VaddrOfFirstLoadSegment() { + if (IsElf32File()) { + return GetImpl32()->VaddrOfFirstLoadSegment(); + } else if (IsElf64File()) { + return GetImpl64()->VaddrOfFirstLoadSegment(); + } else { + return 0; + } +} + +const char *ElfReader::GetSectionName(int shndx) { + if (shndx < 0 || static_cast(shndx) >= GetNumSections()) return NULL; + if (IsElf32File()) { + return GetImpl32()->GetSectionNameByIndex(shndx); + } else if (IsElf64File()) { + return GetImpl64()->GetSectionNameByIndex(shndx); + } else { + return NULL; + } +} + +uint64 ElfReader::GetNumSections() { + if (IsElf32File()) { + return GetImpl32()->GetNumSections(); + } else if (IsElf64File()) { + return GetImpl64()->GetNumSections(); + } else { + return 0; + } +} + +const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { + if (IsElf32File()) { + return GetImpl32()->GetSectionContentsByIndex(shndx, size); + } else if (IsElf64File()) { + return GetImpl64()->GetSectionContentsByIndex(shndx, size); + } else { + return NULL; + } +} + +const char *ElfReader::GetSectionByName(const string §ion_name, + size_t *size) { + if (IsElf32File()) { + return GetImpl32()->GetSectionContentsByName(section_name, size); + } else if (IsElf64File()) { + return GetImpl64()->GetSectionContentsByName(section_name, size); + } else { + return NULL; + } +} + +const char *ElfReader::GetSectionInfoByName(const string §ion_name, + SectionInfo *info) { + if (IsElf32File()) { + return GetImpl32()->GetSectionInfoByName(section_name, info); + } else if (IsElf64File()) { + return GetImpl64()->GetSectionInfoByName(section_name, info); + } else { + return NULL; + } +} + +bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) { + if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { + const string name_suffix(name, strlen(".debug_")); + const string sh_name_suffix(sh_name, strlen(".zdebug_")); + return name_suffix == sh_name_suffix; + } + return name == sh_name; +} + +bool ElfReader::IsDynamicSharedObject() { + if (IsElf32File()) { + return GetImpl32()->IsDynamicSharedObject(); + } else if (IsElf64File()) { + return GetImpl64()->IsDynamicSharedObject(); + } else { + return false; + } +} + +ElfReaderImpl *ElfReader::GetImpl32() { + if (impl32_ == NULL) { + impl32_ = new ElfReaderImpl(path_, fd_); + } + return impl32_; +} + +ElfReaderImpl *ElfReader::GetImpl64() { + if (impl64_ == NULL) { + impl64_ = new ElfReaderImpl(path_, fd_); + } + return impl64_; +} + +// Return true if file is an ELF binary of ElfArch, with unstripped +// debug info (debug_only=true) or symbol table (debug_only=false). +// Otherwise, return false. +template +static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, + bool debug_only) { + if (!ElfReaderImpl::IsArchElfFile(fd, NULL)) return false; + ElfReaderImpl elf_reader(path, fd); + return debug_only ? + elf_reader.HasDebugSections() + : (elf_reader.GetSectionByType(SHT_SYMTAB) != NULL); +} + +// Helper for the IsNon[Debug]StrippedELFBinary functions. +static bool IsNonStrippedELFBinaryHelper(const string &path, + bool debug_only) { + const int fd = open(path.c_str(), O_RDONLY); + if (fd == -1) { + return false; + } + + if (IsNonStrippedELFBinaryImpl(path, fd, debug_only) || + IsNonStrippedELFBinaryImpl(path, fd, debug_only)) { + close(fd); + return true; + } + close(fd); + return false; +} + +bool ElfReader::IsNonStrippedELFBinary(const string &path) { + return IsNonStrippedELFBinaryHelper(path, false); +} + +bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) { + return IsNonStrippedELFBinaryHelper(path, true); +} +} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h new file mode 100644 index 0000000000..b1bb67a882 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h @@ -0,0 +1,166 @@ +// Copyright 2005 Google Inc. All Rights Reserved. +// Author: chatham@google.com (Andrew Chatham) +// Author: satorux@google.com (Satoru Takabayashi) +// +// ElfReader handles reading in ELF. It can extract symbols from the +// current process, which may be used to symbolize stack traces +// without having to make a potentially dangerous call to fork(). +// +// ElfReader dynamically allocates memory, so it is not appropriate to +// use once the address space might be corrupted, such as during +// process death. +// +// ElfReader supports both 32-bit and 64-bit ELF binaries. + +#ifndef COMMON_DWARF_ELF_READER_H__ +#define COMMON_DWARF_ELF_READER_H__ + +#include +#include + +#include "common/dwarf/types.h" +#include "common/using_std_string.h" + +using std::vector; +using std::pair; + +namespace dwarf2reader { + +class SymbolMap; +class Elf32; +class Elf64; +template +class ElfReaderImpl; + +class ElfReader { + public: + explicit ElfReader(const string &path); + ~ElfReader(); + + // Parse the ELF prologue of this file and return whether it was + // successfully parsed and matches the word size and byte order of + // the current process. + bool IsNativeElfFile() const; + + // Similar to IsNativeElfFile but checks if it's a 32-bit ELF file. + bool IsElf32File() const; + + // Similar to IsNativeElfFile but checks if it's a 64-bit ELF file. + bool IsElf64File() const; + + // Checks if it's an ELF file of type ET_DYN (shared object file). + bool IsDynamicSharedObject(); + + // Add symbols in the given ELF file into the provided SymbolMap, + // assuming that the file has been loaded into the specified + // offset. + // + // The remaining arguments are typically taken from a + // ProcMapsIterator (base/sysinfo.h) and describe which portions of + // the ELF file are mapped into which parts of memory: + // + // mem_offset - position at which the segment is mapped into memory + // file_offset - offset in the file where the mapping begins + // length - length of the mapped segment + void AddSymbols(SymbolMap *symbols, + uint64 mem_offset, uint64 file_offset, + uint64 length); + + class SymbolSink { + public: + virtual ~SymbolSink() {} + virtual void AddSymbol(const char *name, uint64 address, uint64 size) = 0; + }; + + // Like AddSymbols above, but with no address correction. + // Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section. + void VisitSymbols(SymbolSink *sink); + + // Like VisitSymbols above, but for a specific symbol binding/type. + // A negative value for the binding and type parameters means any + // binding or type. + void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type); + + // Like VisitSymbols above but can optionally export raw symbol values instead + // of adjusted ones. + void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type, + bool get_raw_symbol_values); + + // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD + // segments are present. This is the address an ELF image was linked + // (by static linker) to be loaded at. Usually (but not always) 0 for + // shared libraries and position-independent executables. + uint64 VaddrOfFirstLoadSegment(); + + // Return the name of section "shndx". Returns NULL if the section + // is not found. + const char *GetSectionName(int shndx); + + // Return the number of sections in the given ELF file. + uint64 GetNumSections(); + + // Get section "shndx" from the given ELF file. On success, return + // the pointer to the section and store the size in "size". + // On error, return NULL. The returned section data is only valid + // until the ElfReader gets destroyed. + const char *GetSectionByIndex(int shndx, size_t *size); + + // Get section with "section_name" (ex. ".text", ".symtab") in the + // given ELF file. On success, return the pointer to the section + // and store the size in "size". On error, return NULL. The + // returned section data is only valid until the ElfReader gets + // destroyed. + const char *GetSectionByName(const string §ion_name, size_t *size); + + // This is like GetSectionByName() but it returns a lot of extra information + // about the section. The SectionInfo structure is almost identical to + // the typedef struct Elf64_Shdr defined in , but is redefined + // here so that the many short macro names in don't have to be + // added to our already cluttered namespace. + struct SectionInfo { + uint32 type; // Section type (SHT_xxx constant from elf.h). + uint64 flags; // Section flags (SHF_xxx constants from elf.h). + uint64 addr; // Section virtual address at execution. + uint64 offset; // Section file offset. + uint64 size; // Section size in bytes. + uint32 link; // Link to another section. + uint32 info; // Additional section information. + uint64 addralign; // Section alignment. + uint64 entsize; // Entry size if section holds a table. + }; + const char *GetSectionInfoByName(const string §ion_name, + SectionInfo *info); + + // Check if "path" is an ELF binary that has not been stripped of symbol + // tables. This function supports both 32-bit and 64-bit ELF binaries. + static bool IsNonStrippedELFBinary(const string &path); + + // Check if "path" is an ELF binary that has not been stripped of debug + // info. Unlike IsNonStrippedELFBinary, this function will return + // false for binaries passed through "strip -S". + static bool IsNonDebugStrippedELFBinary(const string &path); + + // Match a requested section name with the section name as it + // appears in the elf-file, adjusting for compressed debug section + // names. For example, returns true if name == ".debug_abbrev" and + // sh_name == ".zdebug_abbrev" + static bool SectionNamesMatch(const string &name, const string &sh_name); + + private: + // Lazily initialize impl32_ and return it. + ElfReaderImpl *GetImpl32(); + // Ditto for impl64_. + ElfReaderImpl *GetImpl64(); + + // Path of the file we're reading. + const string path_; + // Read-only file descriptor for the file. May be -1 if there was an + // error during open. + int fd_; + ElfReaderImpl *impl32_; + ElfReaderImpl *impl64_; +}; + +} // namespace dwarf2reader + +#endif // COMMON_DWARF_ELF_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc new file mode 100644 index 0000000000..ee198fc5d2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc @@ -0,0 +1,234 @@ +// Copyright (c) 2010 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. + +// This is a client for the dwarf2reader to extract function and line +// information from the debug info. + +#include +#include +#include + +#include +#include +#include + +#include "common/dwarf/functioninfo.h" +#include "common/dwarf/bytereader.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" + +using google_breakpad::scoped_ptr; + +namespace dwarf2reader { + +CULineInfoHandler::CULineInfoHandler(std::vector* files, + std::vector* dirs, + LineMap* linemap):linemap_(linemap), + files_(files), + dirs_(dirs) { + // The dirs and files are 1 indexed, so just make sure we put + // nothing in the 0 vector. + assert(dirs->size() == 0); + assert(files->size() == 0); + dirs->push_back(""); + SourceFileInfo s; + s.name = ""; + s.lowpc = ULLONG_MAX; + files->push_back(s); +} + +void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) { + // These should never come out of order, actually + assert(dir_num == dirs_->size()); + dirs_->push_back(name); +} + +void CULineInfoHandler::DefineFile(const string& name, + int32 file_num, uint32 dir_num, + uint64 mod_time, uint64 length) { + assert(dir_num >= 0); + assert(dir_num < dirs_->size()); + + // These should never come out of order, actually. + if (file_num == (int32)files_->size() || file_num == -1) { + string dir = dirs_->at(dir_num); + + SourceFileInfo s; + s.lowpc = ULLONG_MAX; + + if (dir == "") { + s.name = name; + } else { + s.name = dir + "/" + name; + } + + files_->push_back(s); + } else { + fprintf(stderr, "error in DefineFile"); + } +} + +void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num, + uint32 line_num, uint32 column_num) { + if (file_num < files_->size()) { + linemap_->insert( + std::make_pair(address, + std::make_pair(files_->at(file_num).name.c_str(), + line_num))); + + if (address < files_->at(file_num).lowpc) { + files_->at(file_num).lowpc = address; + } + } else { + fprintf(stderr, "error in AddLine"); + } +} + +bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, + uint8 address_size, + uint8 offset_size, + uint64 cu_length, + uint8 dwarf_version) { + current_compilation_unit_offset_ = offset; + return true; +} + + +// For function info, we only care about subprograms and inlined +// subroutines. For line info, the DW_AT_stmt_list lives in the +// compile unit tag. + +bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) { + switch (tag) { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: { + current_function_info_ = new FunctionInfo; + current_function_info_->lowpc = current_function_info_->highpc = 0; + current_function_info_->name = ""; + current_function_info_->line = 0; + current_function_info_->file = ""; + offset_to_funcinfo_->insert(std::make_pair(offset, + current_function_info_)); + }; + // FALLTHROUGH + case DW_TAG_compile_unit: + return true; + default: + return false; + } + return false; +} + +// Only care about the name attribute for functions + +void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string &data) { + if (current_function_info_) { + if (attr == DW_AT_name) + current_function_info_->name = data; + else if (attr == DW_AT_MIPS_linkage_name) + current_function_info_->mangled_name = data; + } +} + +void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + if (attr == DW_AT_stmt_list) { + SectionMap::const_iterator iter = sections_.find("__debug_line"); + assert(iter != sections_.end()); + + scoped_ptr lireader(new LineInfo(iter->second.first + data, + iter->second.second - data, + reader_, linehandler_)); + lireader->Start(); + } else if (current_function_info_) { + switch (attr) { + case DW_AT_low_pc: + current_function_info_->lowpc = data; + break; + case DW_AT_high_pc: + current_function_info_->highpc = data; + break; + case DW_AT_decl_line: + current_function_info_->line = data; + break; + case DW_AT_decl_file: + current_function_info_->file = files_->at(data).name; + break; + case DW_AT_ranges: + current_function_info_->ranges = data; + break; + default: + break; + } + } +} + +void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + if (current_function_info_) { + switch (attr) { + case DW_AT_specification: { + // Some functions have a "specification" attribute + // which means they were defined elsewhere. The name + // attribute is not repeated, and must be taken from + // the specification DIE. Here we'll assume that + // any DIE referenced in this manner will already have + // been seen, but that's not really required by the spec. + FunctionMap::iterator iter = offset_to_funcinfo_->find(data); + if (iter != offset_to_funcinfo_->end()) { + current_function_info_->name = iter->second->name; + current_function_info_->mangled_name = iter->second->mangled_name; + } else { + // If you hit this, this code probably needs to be rewritten. + fprintf(stderr, + "Error: DW_AT_specification was seen before the referenced " + "DIE! (Looking for DIE at offset %08llx, in DIE at " + "offset %08llx)\n", data, offset); + } + break; + } + default: + break; + } + } +} + +void CUFunctionInfoHandler::EndDIE(uint64 offset) { + if (current_function_info_ && current_function_info_->lowpc) + address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, + current_function_info_)); +} + +} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h new file mode 100644 index 0000000000..9efae6d4ee --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h @@ -0,0 +1,190 @@ +// Copyright (c) 2010 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. + + +// This file contains the definitions for a DWARF2/3 information +// collector that uses the DWARF2/3 reader interface to build a mapping +// of addresses to files, lines, and functions. + +#ifndef COMMON_DWARF_FUNCTIONINFO_H__ +#define COMMON_DWARF_FUNCTIONINFO_H__ + +#include +#include +#include +#include + +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + + +namespace dwarf2reader { + +struct FunctionInfo { + // Name of the function + string name; + // Mangled name of the function + string mangled_name; + // File containing this function + string file; + // Line number for start of function. + uint32 line; + // Beginning address for this function + uint64 lowpc; + // End address for this function. + uint64 highpc; + // Ranges offset + uint64 ranges; +}; + +struct SourceFileInfo { + // Name of the source file name + string name; + // Low address of source file name + uint64 lowpc; +}; + +typedef std::map FunctionMap; +typedef std::map > LineMap; + +// This class is a basic line info handler that fills in the dirs, +// file, and linemap passed into it with the data produced from the +// LineInfoHandler. +class CULineInfoHandler: public LineInfoHandler { + public: + + // + CULineInfoHandler(std::vector* files, + std::vector* dirs, + LineMap* linemap); + virtual ~CULineInfoHandler() { } + + // Called when we define a directory. We just place NAME into dirs_ + // at position DIR_NUM. + virtual void DefineDir(const string& name, uint32 dir_num); + + // Called when we define a filename. We just place + // concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM. + virtual void DefineFile(const string& name, int32 file_num, + uint32 dir_num, uint64 mod_time, uint64 length); + + + // Called when the line info reader has a new line, address pair + // ready for us. ADDRESS is the address of the code, LENGTH is the + // length of its machine code in bytes, FILE_NUM is the file number + // containing the code, LINE_NUM is the line number in that file for + // the code, and COLUMN_NUM is the column number the code starts at, + // if we know it (0 otherwise). + virtual void AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, uint32 column_num); + + private: + LineMap* linemap_; + std::vector* files_; + std::vector* dirs_; +}; + +class CUFunctionInfoHandler: public Dwarf2Handler { + public: + CUFunctionInfoHandler(std::vector* files, + std::vector* dirs, + LineMap* linemap, + FunctionMap* offset_to_funcinfo, + FunctionMap* address_to_funcinfo, + CULineInfoHandler* linehandler, + const SectionMap& sections, + ByteReader* reader) + : files_(files), dirs_(dirs), linemap_(linemap), + offset_to_funcinfo_(offset_to_funcinfo), + address_to_funcinfo_(address_to_funcinfo), + linehandler_(linehandler), sections_(sections), + reader_(reader), current_function_info_(NULL) { } + + virtual ~CUFunctionInfoHandler() { } + + // Start to process a compilation unit at OFFSET from the beginning of the + // .debug_info section. We want to see all compilation units, so we + // always return true. + + virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version); + + // Start to process a DIE at OFFSET from the beginning of the + // .debug_info section. We only care about function related DIE's. + virtual bool StartDIE(uint64 offset, enum DwarfTag tag); + + // Called when we have an attribute with unsigned data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of the .debug_info section, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + virtual void ProcessAttributeUnsigned(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Called when we have an attribute with a DIE reference to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of the .debug_info section, has a name of ATTR, a form of + // FORM, and the offset of the referenced DIE from the start of the + // .debug_info section is in DATA. + virtual void ProcessAttributeReference(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Called when we have an attribute with string data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of the .debug_info section, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + virtual void ProcessAttributeString(uint64 offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string& data); + + // Called when finished processing the DIE at OFFSET. + // Because DWARF2/3 specifies a tree of DIEs, you may get starts + // before ends of the previous DIE, as we process children before + // ending the parent. + virtual void EndDIE(uint64 offset); + + private: + std::vector* files_; + std::vector* dirs_; + LineMap* linemap_; + FunctionMap* offset_to_funcinfo_; + FunctionMap* address_to_funcinfo_; + CULineInfoHandler* linehandler_; + const SectionMap& sections_; + ByteReader* reader_; + FunctionInfo* current_function_info_; + uint64 current_compilation_unit_offset_; +}; + +} // namespace dwarf2reader +#endif // COMMON_DWARF_FUNCTIONINFO_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h new file mode 100644 index 0000000000..0ff72abcfc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h @@ -0,0 +1,61 @@ +// Copyright 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 COMMON_DWARF_LINE_STATE_MACHINE_H__ +#define COMMON_DWARF_LINE_STATE_MACHINE_H__ + +namespace dwarf2reader { + +// This is the format of a DWARF2/3 line state machine that we process +// opcodes using. There is no need for anything outside the lineinfo +// processor to know how this works. +struct LineStateMachine { + void Reset(bool default_is_stmt) { + file_num = 1; + address = 0; + line_num = 1; + column_num = 0; + is_stmt = default_is_stmt; + basic_block = false; + end_sequence = false; + } + + uint32 file_num; + uint64 address; + uint32 line_num; + uint32 column_num; + bool is_stmt; // stmt means statement. + bool basic_block; + bool end_sequence; +}; + +} // namespace dwarf2reader + + +#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h new file mode 100644 index 0000000000..59dda31600 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h @@ -0,0 +1,51 @@ +// Copyright 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. + + +// This file contains some typedefs for basic types + + +#ifndef _COMMON_DWARF_TYPES_H__ +#define _COMMON_DWARF_TYPES_H__ + +#include + +typedef signed char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef intptr_t intptr; +typedef uintptr_t uintptr; + +#endif // _COMMON_DWARF_TYPES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc new file mode 100644 index 0000000000..bd298a2f79 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc @@ -0,0 +1,295 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// Implementation of google_breakpad::DwarfCFIToModule. +// See dwarf_cfi_to_module.h for details. + +#include + +#include "common/dwarf_cfi_to_module.h" + +namespace google_breakpad { + +using std::ostringstream; + +vector DwarfCFIToModule::RegisterNames::MakeVector( + const char * const *strings, + size_t size) { + vector names(strings, strings + size); + return names; +} + +vector DwarfCFIToModule::RegisterNames::I386() { + static const char *const names[] = { + "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", + "$eip", "$eflags", "$unused1", + "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", + "$unused2", "$unused3", + "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", + "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", + "$fcw", "$fsw", "$mxcsr", + "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", + "$tr", "$ldtr" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +vector DwarfCFIToModule::RegisterNames::X86_64() { + static const char *const names[] = { + "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", + "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", + "$rip", + "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", + "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", + "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", + "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", + "$rflags", + "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", + "$fs.base", "$gs.base", "$unused3", "$unused4", + "$tr", "$ldtr", + "$mxcsr", "$fcw", "$fsw" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +// Per ARM IHI 0040A, section 3.1 +vector DwarfCFIToModule::RegisterNames::ARM() { + static const char *const names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "fps", "cpsr", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +// Per ARM IHI 0057A, section 3.1 +vector DwarfCFIToModule::RegisterNames::ARM64() { + static const char *const names[] = { + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", + "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + +vector DwarfCFIToModule::RegisterNames::MIPS() { + static const char* const kRegisterNames[] = { + "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", + "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5", + "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", + "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", + "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", + "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir" + }; + + return MakeVector(kRegisterNames, + sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); +} + +bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address) { + assert(!entry_); + + // If dwarf2reader::CallFrameInfo can handle this version and + // augmentation, then we should be okay with that, so there's no + // need to check them here. + + // Get ready to collect entries. + entry_ = new Module::StackFrameEntry; + entry_->address = address; + entry_->size = length; + entry_offset_ = offset; + return_address_ = return_address; + + // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI + // may not establish any rule for .ra if the return address column + // is an ordinary register, and that register holds the return + // address on entry to the function. So establish an initial .ra + // rule citing the return address register. + if (return_address_ < register_names_.size()) + entry_->initial_rules[ra_name_] = register_names_[return_address_]; + + return true; +} + +string DwarfCFIToModule::RegisterName(int i) { + assert(entry_); + if (i < 0) { + assert(i == kCFARegister); + return cfa_name_; + } + unsigned reg = i; + if (reg == return_address_) + return ra_name_; + + // Ensure that a non-empty name exists for this register value. + if (reg < register_names_.size() && !register_names_[reg].empty()) + return register_names_[reg]; + + reporter_->UnnamedRegister(entry_offset_, reg); + char buf[30]; + sprintf(buf, "unnamed_register%u", reg); + return buf; +} + +void DwarfCFIToModule::Record(Module::Address address, int reg, + const string &rule) { + assert(entry_); + + // Place the name in our global set of strings, and then use the string + // from the set. Even though the assignment looks like a copy, all the + // major string implementations use reference counting internally, + // so the effect is to have all our data structures share copies of rules + // whenever possible. Since register names are drawn from a + // vector, register names are already shared. + string shared_rule = *common_strings_.insert(rule).first; + + // Is this one of this entry's initial rules? + if (address == entry_->address) + entry_->initial_rules[RegisterName(reg)] = shared_rule; + // File it under the appropriate address. + else + entry_->rule_changes[address][RegisterName(reg)] = shared_rule; +} + +bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { + reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { + ostringstream s; + s << RegisterName(reg); + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, + int base_register, long offset) { + ostringstream s; + s << RegisterName(base_register) << " " << offset << " + ^"; + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, + int base_register, long offset) { + ostringstream s; + s << RegisterName(base_register) << " " << offset << " +"; + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, + int base_register) { + ostringstream s; + s << RegisterName(base_register); + Record(address, reg, s.str()); + return true; +} + +bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, + const string &expression) { + reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, + const string &expression) { + reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); + // Treat this as a non-fatal error. + return true; +} + +bool DwarfCFIToModule::End() { + module_->AddStackFrameEntry(entry_); + entry_ = NULL; + return true; +} + +void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx refers to register %d," + " whose name we don't know\n", + file_.c_str(), section_.c_str(), offset, reg); +} + +void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, + const string ®) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx sets the rule for " + "register '%s' to 'undefined', but the Breakpad symbol file format" + " cannot express this\n", + file_.c_str(), section_.c_str(), offset, reg.c_str()); +} + +void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, + const string ®) { + fprintf(stderr, "%s, section '%s': " + "the call frame entry at offset 0x%zx uses a DWARF expression to" + " describe how to recover register '%s', " + " but this translator cannot yet translate DWARF expressions to" + " Breakpad postfix expressions\n", + file_.c_str(), section_.c_str(), offset, reg.c_str()); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h new file mode 100644 index 0000000000..a5302e15eb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h @@ -0,0 +1,202 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which +// accepts parsed DWARF call frame info and adds it to a +// google_breakpad::Module object, which can write that information to +// a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H +#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H + +#include +#include + +#include +#include +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using dwarf2reader::CallFrameInfo; +using google_breakpad::Module; +using std::set; +using std::vector; + +// A class that accepts parsed call frame information from the DWARF +// CFI parser and populates a google_breakpad::Module object with the +// contents. +class DwarfCFIToModule: public CallFrameInfo::Handler { + public: + + // DwarfCFIToModule uses an instance of this class to report errors + // detected while converting DWARF CFI to Breakpad STACK CFI records. + class Reporter { + public: + // Create a reporter that writes messages to the standard error + // stream. FILE is the name of the file we're processing, and + // SECTION is the name of the section within that file that we're + // looking at (.debug_frame, .eh_frame, etc.). + Reporter(const string &file, const string §ion) + : file_(file), section_(section) { } + virtual ~Reporter() { } + + // The DWARF CFI entry at OFFSET cites register REG, but REG is not + // covered by the vector of register names passed to the + // DwarfCFIToModule constructor, nor does it match the return + // address column number for this entry. + virtual void UnnamedRegister(size_t offset, int reg); + + // The DWARF CFI entry at OFFSET says that REG is undefined, but the + // Breakpad symbol file format cannot express this. + virtual void UndefinedNotSupported(size_t offset, const string ®); + + // The DWARF CFI entry at OFFSET says that REG uses a DWARF + // expression to find its value, but DwarfCFIToModule is not + // capable of translating DWARF expressions to Breakpad postfix + // expressions. + virtual void ExpressionsNotSupported(size_t offset, const string ®); + + protected: + string file_, section_; + }; + + // Register name tables. If TABLE is a vector returned by one of these + // functions, then TABLE[R] is the name of the register numbered R in + // DWARF call frame information. + class RegisterNames { + public: + // Intel's "x86" or IA-32. + static vector I386(); + + // AMD x86_64, AMD64, Intel EM64T, or Intel 64 + static vector X86_64(); + + // ARM. + static vector ARM(); + + // ARM64, aka AARCH64. + static vector ARM64(); + + // MIPS. + static vector MIPS(); + + private: + // Given STRINGS, an array of C strings with SIZE elements, return an + // equivalent vector. + static vector MakeVector(const char * const *strings, size_t size); + }; + + // Create a handler for the dwarf2reader::CallFrameInfo parser that + // records the stack unwinding information it receives in MODULE. + // + // Use REGISTER_NAMES[I] as the name of register number I; *this + // keeps a reference to the vector, so the vector should remain + // alive for as long as the DwarfCFIToModule does. + // + // Use REPORTER for reporting problems encountered in the conversion + // process. + DwarfCFIToModule(Module *module, const vector ®ister_names, + Reporter *reporter) + : module_(module), register_names_(register_names), reporter_(reporter), + entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { + } + virtual ~DwarfCFIToModule() { delete entry_; } + + virtual bool Entry(size_t offset, uint64 address, uint64 length, + uint8 version, const string &augmentation, + unsigned return_address); + virtual bool UndefinedRule(uint64 address, int reg); + virtual bool SameValueRule(uint64 address, int reg); + virtual bool OffsetRule(uint64 address, int reg, + int base_register, long offset); + virtual bool ValOffsetRule(uint64 address, int reg, + int base_register, long offset); + virtual bool RegisterRule(uint64 address, int reg, int base_register); + virtual bool ExpressionRule(uint64 address, int reg, + const string &expression); + virtual bool ValExpressionRule(uint64 address, int reg, + const string &expression); + virtual bool End(); + + private: + // Return the name to use for register REG. + string RegisterName(int i); + + // Record RULE for register REG at ADDRESS. + void Record(Module::Address address, int reg, const string &rule); + + // The module to which we should add entries. + Module *module_; + + // Map from register numbers to register names. + const vector ®ister_names_; + + // The reporter to use to report problems. + Reporter *reporter_; + + // The current entry we're constructing. + Module::StackFrameEntry *entry_; + + // The section offset of the current frame description entry, for + // use in error messages. + size_t entry_offset_; + + // The return address column for that entry. + unsigned return_address_; + + // The names of the return address and canonical frame address. Putting + // these here instead of using string literals allows us to share their + // texts in reference-counted string implementations (all the + // popular ones). Many, many rules cite these strings. + string cfa_name_, ra_name_; + + // A set of strings used by this CFI. Before storing a string in one of + // our data structures, insert it into this set, and then use the string + // from the set. + // + // Because string uses reference counting internally, simply using + // strings from this set, even if passed by value, assigned, or held + // directly in structures and containers (map, for example), + // causes those strings to share a single instance of each distinct piece + // of text. + set common_strings_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc new file mode 100644 index 0000000000..807d1b20c3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc @@ -0,0 +1,306 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/using_std_string.h" + +using std::vector; + +using google_breakpad::Module; +using google_breakpad::DwarfCFIToModule; +using testing::ContainerEq; +using testing::Test; +using testing::_; + +struct MockCFIReporter: public DwarfCFIToModule::Reporter { + MockCFIReporter(const string &file, const string §ion) + : Reporter(file, section) { } + MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); + MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); + MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); +}; + +struct DwarfCFIToModuleFixture { + DwarfCFIToModuleFixture() + : module("module name", "module os", "module arch", "module id"), + reporter("reporter file", "reporter section"), + handler(&module, register_names, &reporter) { + register_names.push_back("reg0"); + register_names.push_back("reg1"); + register_names.push_back("reg2"); + register_names.push_back("reg3"); + register_names.push_back("reg4"); + register_names.push_back("reg5"); + register_names.push_back("reg6"); + register_names.push_back("reg7"); + register_names.push_back("sp"); + register_names.push_back("pc"); + register_names.push_back(""); + + EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); + EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); + EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); + } + + Module module; + vector register_names; + MockCFIReporter reporter; + DwarfCFIToModule handler; + vector entries; +}; + +class Entry: public DwarfCFIToModuleFixture, public Test { }; + +TEST_F(Entry, Accept) { + ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL, + 0xb440ce248169c8d6ULL, 3, "", 0xea93c106)); + ASSERT_TRUE(handler.End()); + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address); + EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Entry, AcceptOldVersion) { + ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL, + 0xc771f44958d40bbcULL, 1, "", 0x093c945e)); + ASSERT_TRUE(handler.End()); + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address); + EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +struct RuleFixture: public DwarfCFIToModuleFixture { + RuleFixture() : DwarfCFIToModuleFixture() { + entry_address = 0x89327ebf86b47492ULL; + entry_size = 0x2f8cd573072fe02aULL; + return_reg = 0x7886a346; + } + void StartEntry() { + ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size, + 3, "", return_reg)); + } + void CheckEntry() { + module.GetStackFrameEntries(&entries); + EXPECT_EQ(1U, entries.size()); + EXPECT_EQ(entry_address, entries[0]->address); + EXPECT_EQ(entry_size, entries[0]->size); + } + uint64 entry_address, entry_size; + unsigned return_reg; +}; + +class Rule: public RuleFixture, public Test { }; + +TEST_F(Rule, UndefinedRule) { + EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); + StartEntry(); + ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, RegisterWithEmptyName) { + EXPECT_CALL(reporter, UnnamedRegister(_, 10)); + EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10")); + StartEntry(); + ASSERT_TRUE(handler.UndefinedRule(entry_address, 10)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, SameValueRule) { + StartEntry(); + ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial["reg6"] = "reg6"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, OffsetRule) { + StartEntry(); + ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, + DwarfCFIToModule::kCFARegister, + 16927065)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, OffsetRuleNegative) { + StartEntry(); + ASSERT_TRUE(handler.OffsetRule(entry_address + 1, + DwarfCFIToModule::kCFARegister, 4, -34530721)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, ValOffsetRule) { + // Use an unnamed register number, to exercise that branch of RegisterName. + EXPECT_CALL(reporter, UnnamedRegister(_, 11)); + StartEntry(); + ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, + DwarfCFIToModule::kCFARegister, + 11, 61812979)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 0x5ab7][".cfa"] = + "unnamed_register11 61812979 +"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST_F(Rule, RegisterRule) { + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg3"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, ExpressionRule) { + EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); + StartEntry(); + ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, + "it takes two to tango")); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, ValExpressionRule) { + EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); + StartEntry(); + ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, + "bit off more than he could chew")); + ASSERT_TRUE(handler.End()); + CheckEntry(); + EXPECT_EQ(0U, entries[0]->initial_rules.size()); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRule) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg2"; + expected_initial["reg0"] = "reg1"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRuleOverride) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg1"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + EXPECT_EQ(0U, entries[0]->rule_changes.size()); +} + +TEST_F(Rule, DefaultReturnAddressRuleLater) { + return_reg = 2; + StartEntry(); + ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); + ASSERT_TRUE(handler.End()); + CheckEntry(); + Module::RuleMap expected_initial; + expected_initial[".ra"] = "reg2"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); + Module::RuleChangeMap expected_changes; + expected_changes[entry_address + 1][".ra"] = "reg1"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); +} + +TEST(RegisterNames, I386) { + vector names = DwarfCFIToModule::RegisterNames::I386(); + + EXPECT_EQ("$eax", names[0]); + EXPECT_EQ("$ecx", names[1]); + EXPECT_EQ("$esp", names[4]); + EXPECT_EQ("$eip", names[8]); +} + +TEST(RegisterNames, ARM) { + vector names = DwarfCFIToModule::RegisterNames::ARM(); + + EXPECT_EQ("r0", names[0]); + EXPECT_EQ("r10", names[10]); + EXPECT_EQ("sp", names[13]); + EXPECT_EQ("lr", names[14]); + EXPECT_EQ("pc", names[15]); +} + +TEST(RegisterNames, X86_64) { + vector names = DwarfCFIToModule::RegisterNames::X86_64(); + + EXPECT_EQ("$rax", names[0]); + EXPECT_EQ("$rdx", names[1]); + EXPECT_EQ("$rbp", names[6]); + EXPECT_EQ("$rsp", names[7]); + EXPECT_EQ("$rip", names[16]); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc new file mode 100644 index 0000000000..56399c3a0b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc @@ -0,0 +1,1243 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. + +// For PRI* macros, before anything else might #include it. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ + +#include "common/dwarf_cu_to_module.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "common/dwarf_line_to_module.h" +#include "common/unordered.h" + +namespace google_breakpad { + +using std::accumulate; +using std::map; +using std::pair; +using std::sort; +using std::vector; + +// Data provided by a DWARF specification DIE. +// +// In DWARF, the DIE for a definition may contain a DW_AT_specification +// attribute giving the offset of the corresponding declaration DIE, and +// the definition DIE may omit information given in the declaration. For +// example, it's common for a function's address range to appear only in +// its definition DIE, but its name to appear only in its declaration +// DIE. +// +// The dumper needs to be able to follow DW_AT_specification links to +// bring all this information together in a FUNC record. Conveniently, +// DIEs that are the target of such links have a DW_AT_declaration flag +// set, so we can identify them when we first see them, and record their +// contents for later reference. +// +// A Specification holds information gathered from a declaration DIE that +// we may need if we find a DW_AT_specification link pointing to it. +struct DwarfCUToModule::Specification { + // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name. + string qualified_name; + + // The name of the enclosing scope, or the empty string if there is none. + string enclosing_name; + + // The name for the specification DIE itself, without any enclosing + // name components. + string unqualified_name; +}; + +// An abstract origin -- base definition of an inline function. +struct AbstractOrigin { + AbstractOrigin() : name() {} + explicit AbstractOrigin(const string& name) : name(name) {} + + string name; +}; + +typedef map AbstractOriginByOffset; + +// Data global to the DWARF-bearing file that is private to the +// DWARF-to-Module process. +struct DwarfCUToModule::FilePrivate { + // A set of strings used in this CU. Before storing a string in one of + // our data structures, insert it into this set, and then use the string + // from the set. + // + // In some STL implementations, strings are reference-counted internally, + // meaning that simply using strings from this set, even if passed by + // value, assigned, or held directly in structures and containers + // (map, for example), causes those strings to share a + // single instance of each distinct piece of text. GNU's libstdc++ uses + // reference counts, and I believe MSVC did as well, at some point. + // However, C++ '11 implementations are moving away from reference + // counting. + // + // In other implementations, string assignments copy the string's text, + // so this set will actually hold yet another copy of the string (although + // everything will still work). To improve memory consumption portably, + // we will probably need to use pointers to strings held in this set. + unordered_set common_strings; + + // A map from offsets of DIEs within the .debug_info section to + // Specifications describing those DIEs. Specification references can + // cross compilation unit boundaries. + SpecificationByOffset specifications; + + AbstractOriginByOffset origins; +}; + +DwarfCUToModule::FileContext::FileContext(const string &filename, + Module *module, + bool handle_inter_cu_refs) + : filename_(filename), + module_(module), + handle_inter_cu_refs_(handle_inter_cu_refs), + file_private_(new FilePrivate()) { +} + +DwarfCUToModule::FileContext::~FileContext() { +} + +void DwarfCUToModule::FileContext::AddSectionToSectionMap( + const string& name, const uint8_t *contents, uint64 length) { + section_map_[name] = std::make_pair(contents, length); +} + +void DwarfCUToModule::FileContext::ClearSectionMapForTest() { + section_map_.clear(); +} + +const dwarf2reader::SectionMap& +DwarfCUToModule::FileContext::section_map() const { + return section_map_; +} + +void DwarfCUToModule::FileContext::ClearSpecifications() { + if (!handle_inter_cu_refs_) + file_private_->specifications.clear(); +} + +bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( + uint64 offset, uint64 compilation_unit_start) const { + if (handle_inter_cu_refs_) + return false; + return offset < compilation_unit_start; +} + +// Information global to the particular compilation unit we're +// parsing. This is for data shared across the CU's entire DIE tree, +// and parameters from the code invoking the CU parser. +struct DwarfCUToModule::CUContext { + CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg, + RangesHandler *ranges_handler_arg) + : file_context(file_context_arg), + reporter(reporter_arg), + ranges_handler(ranges_handler_arg), + language(Language::CPlusPlus), + low_pc(0), + high_pc(0), + ranges(0) {} + + ~CUContext() { + for (vector::iterator it = functions.begin(); + it != functions.end(); ++it) { + delete *it; + } + }; + + // The DWARF-bearing file into which this CU was incorporated. + FileContext *file_context; + + // For printing error messages. + WarningReporter *reporter; + + // For reading ranges from the .debug_ranges section + RangesHandler *ranges_handler; + + // The source language of this compilation unit. + const Language *language; + + // Addresses covered by this CU. If high_pc_ is non-zero then the CU covers + // low_pc to high_pc, otherwise ranges is non-zero and low_pc represents + // the base address of the ranges covered by the CU. + uint64 low_pc; + uint64 high_pc; + uint64 ranges; + + // The functions defined in this compilation unit. We accumulate + // them here during parsing. Then, in DwarfCUToModule::Finish, we + // assign them lines and add them to file_context->module. + // + // Destroying this destroys all the functions this vector points to. + vector functions; + + // Keep a list of forward references from DW_AT_abstract_origin and + // DW_AT_specification attributes so names can be fixed up. + std::map forward_ref_die_to_func; +}; + +// Information about the context of a particular DIE. This is for +// information that changes as we descend the tree towards the leaves: +// the containing classes/namespaces, etc. +struct DwarfCUToModule::DIEContext { + // The fully-qualified name of the context. For example, for a + // tree like: + // + // DW_TAG_namespace Foo + // DW_TAG_class Bar + // DW_TAG_subprogram Baz + // + // in a C++ compilation unit, the DIEContext's name for the + // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's + // name for the DW_TAG_namespace DIE would be "". + string name; +}; + +// An abstract base class for all the dumper's DIE handlers. +class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { + public: + // Create a handler for the DIE at OFFSET whose compilation unit is + // described by CU_CONTEXT, and whose immediate context is described + // by PARENT_CONTEXT. + GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : cu_context_(cu_context), + parent_context_(parent_context), + offset_(offset), + declaration_(false), + specification_(NULL), + forward_ref_die_offset_(0) { } + + // Derived classes' ProcessAttributeUnsigned can defer to this to + // handle DW_AT_declaration, or simply not override it. + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Derived classes' ProcessAttributeReference can defer to this to + // handle DW_AT_specification, or simply not override it. + void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + // Derived classes' ProcessAttributeReference can defer to this to + // handle DW_AT_specification, or simply not override it. + void ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data); + + protected: + // Compute and return the fully-qualified name of the DIE. If this + // DIE is a declaration DIE, to be cited by other DIEs' + // DW_AT_specification attributes, record its enclosing name and + // unqualified name in the specification table. + // + // Use this from EndAttributes member functions, not ProcessAttribute* + // functions; only the former can be sure that all the DIE's attributes + // have been seen. + string ComputeQualifiedName(); + + CUContext *cu_context_; + DIEContext *parent_context_; + uint64 offset_; + + // Place the name in the global set of strings. Even though this looks + // like a copy, all the major string implementations use reference + // counting internally, so the effect is to have all the data structures + // share copies of strings whenever possible. + // FIXME: Should this return something like a string_ref to avoid the + // assumption about how strings are implemented? + string AddStringToPool(const string &str); + + // If this DIE has a DW_AT_declaration attribute, this is its value. + // It is false on DIEs with no DW_AT_declaration attribute. + bool declaration_; + + // If this DIE has a DW_AT_specification attribute, this is the + // Specification structure for the DIE the attribute refers to. + // Otherwise, this is NULL. + Specification *specification_; + + // If this DIE has a DW_AT_specification or DW_AT_abstract_origin and it is a + // forward reference, no Specification will be available. Track the reference + // to be fixed up when the DIE is parsed. + uint64_t forward_ref_die_offset_; + + // The value of the DW_AT_name attribute, or the empty string if the + // DIE has no such attribute. + string name_attribute_; + + // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty + // string if the DIE has no such attribute or its content could not be + // demangled. + string demangled_name_; + + // The non-demangled value of the DW_AT_MIPS_linkage_name attribute, + // it its content count not be demangled. + string raw_name_; +}; + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; + default: break; + } +} + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_specification: { + FileContext *file_context = cu_context_->file_context; + if (file_context->IsUnhandledInterCUReference( + data, cu_context_->reporter->cu_offset())) { + cu_context_->reporter->UnhandledInterCUReference(offset_, data); + break; + } + // Find the Specification to which this attribute refers, and + // set specification_ appropriately. We could do more processing + // here, but it's better to leave the real work to our + // EndAttribute member function, at which point we know we have + // seen all the DIE's attributes. + SpecificationByOffset *specifications = + &file_context->file_private_->specifications; + SpecificationByOffset::iterator spec = specifications->find(data); + if (spec != specifications->end()) { + specification_ = &spec->second; + } else if (data > offset_) { + forward_ref_die_offset_ = data; + } else { + cu_context_->reporter->UnknownSpecification(offset_, data); + } + break; + } + default: break; + } +} + +string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { + pair::iterator, bool> result = + cu_context_->file_context->file_private_->common_strings.insert(str); + return *result.first; +} + +void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( + enum DwarfAttribute attr, + enum DwarfForm form, + const string &data) { + switch (attr) { + case dwarf2reader::DW_AT_name: + name_attribute_ = AddStringToPool(data); + break; + case dwarf2reader::DW_AT_MIPS_linkage_name: + case dwarf2reader::DW_AT_linkage_name: { + string demangled; + Language::DemangleResult result = + cu_context_->language->DemangleName(data, &demangled); + switch (result) { + case Language::kDemangleSuccess: + demangled_name_ = AddStringToPool(demangled); + break; + + case Language::kDemangleFailure: + cu_context_->reporter->DemangleError(data); + // fallthrough + case Language::kDontDemangle: + demangled_name_.clear(); + raw_name_ = AddStringToPool(data); + break; + } + break; + } + default: break; + } +} + +string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { + // Use the demangled name, if one is available. Demangled names are + // preferable to those inferred from the DWARF structure because they + // include argument types. + const string *qualified_name = NULL; + if (!demangled_name_.empty()) { + // Found it is this DIE. + qualified_name = &demangled_name_; + } else if (specification_ && !specification_->qualified_name.empty()) { + // Found it on the specification. + qualified_name = &specification_->qualified_name; + } + + const string *unqualified_name = NULL; + const string *enclosing_name; + if (!qualified_name) { + // Find the unqualified name. If the DIE has its own DW_AT_name + // attribute, then use that; otherwise, check the specification. + if (!name_attribute_.empty()) + unqualified_name = &name_attribute_; + else if (specification_) + unqualified_name = &specification_->unqualified_name; + else if (!raw_name_.empty()) + unqualified_name = &raw_name_; + + // Find the name of the enclosing context. If this DIE has a + // specification, it's the specification's enclosing context that + // counts; otherwise, use this DIE's context. + if (specification_) + enclosing_name = &specification_->enclosing_name; + else + enclosing_name = &parent_context_->name; + } + + // Prepare the return value before upcoming mutations possibly invalidate the + // existing pointers. + string return_value; + if (qualified_name) { + return_value = *qualified_name; + } else if (unqualified_name && enclosing_name) { + // Combine the enclosing name and unqualified name to produce our + // own fully-qualified name. + return_value = cu_context_->language->MakeQualifiedName(*enclosing_name, + *unqualified_name); + } + + // If this DIE was marked as a declaration, record its names in the + // specification table. + if ((declaration_ && qualified_name) || + (unqualified_name && enclosing_name)) { + Specification spec; + if (qualified_name) { + spec.qualified_name = *qualified_name; + } else { + spec.enclosing_name = *enclosing_name; + spec.unqualified_name = *unqualified_name; + } + cu_context_->file_context->file_private_->specifications[offset_] = spec; + } + + return return_value; +} + +// A handler class for DW_TAG_subprogram DIEs. +class DwarfCUToModule::FuncHandler: public GenericDIEHandler { + public: + FuncHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : GenericDIEHandler(cu_context, parent_context, offset), + low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), + ranges_(0), abstract_origin_(NULL), inline_(false) { } + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeReference(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + + bool EndAttributes(); + void Finish(); + + private: + // The fully-qualified name, as derived from name_attribute_, + // specification_, parent_context_. Computed in EndAttributes. + string name_; + uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc + DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. + uint64 ranges_; // DW_AT_ranges + const AbstractOrigin* abstract_origin_; + bool inline_; +}; + +void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + // If this attribute is present at all --- even if its value is + // DW_INL_not_inlined --- then GCC may cite it as someone else's + // DW_AT_abstract_origin attribute. + case dwarf2reader::DW_AT_inline: inline_ = true; break; + + case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; + case dwarf2reader::DW_AT_high_pc: + high_pc_form_ = form; + high_pc_ = data; + break; + case dwarf2reader::DW_AT_ranges: + ranges_ = data; + break; + + default: + GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); + break; + } +} + +void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( + enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + switch (attr) { + // If this attribute is present at all --- even if its value is + // DW_INL_not_inlined --- then GCC may cite it as someone else's + // DW_AT_abstract_origin attribute. + case dwarf2reader::DW_AT_inline: inline_ = true; break; + + default: + break; + } +} + +void DwarfCUToModule::FuncHandler::ProcessAttributeReference( + enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_abstract_origin: { + const AbstractOriginByOffset& origins = + cu_context_->file_context->file_private_->origins; + AbstractOriginByOffset::const_iterator origin = origins.find(data); + if (origin != origins.end()) { + abstract_origin_ = &(origin->second); + } else if (data > offset_) { + forward_ref_die_offset_ = data; + } else { + cu_context_->reporter->UnknownAbstractOrigin(offset_, data); + } + break; + } + default: + GenericDIEHandler::ProcessAttributeReference(attr, form, data); + break; + } +} + +bool DwarfCUToModule::FuncHandler::EndAttributes() { + // Compute our name, and record a specification, if appropriate. + name_ = ComputeQualifiedName(); + if (name_.empty() && abstract_origin_) { + name_ = abstract_origin_->name; + } + return true; +} + +static bool IsEmptyRange(const vector& ranges) { + uint64 size = accumulate(ranges.cbegin(), ranges.cend(), 0, + [](uint64 total, Module::Range entry) { + return total + entry.size; + } + ); + + return size == 0; +} + +void DwarfCUToModule::FuncHandler::Finish() { + vector ranges; + + // Check if this DIE was one of the forward references that was not able + // to be processed, and fix up the name of the appropriate Module::Function. + // "name_" will have already been fixed up in EndAttributes(). + if (!name_.empty()) { + auto iter = cu_context_->forward_ref_die_to_func.find(offset_); + if (iter != cu_context_->forward_ref_die_to_func.end()) + iter->second->name = name_; + } + + if (!ranges_) { + // Make high_pc_ an address, if it isn't already. + if (high_pc_form_ != dwarf2reader::DW_FORM_addr && + high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index) { + high_pc_ += low_pc_; + } + + Module::Range range(low_pc_, high_pc_ - low_pc_); + ranges.push_back(range); + } else { + RangesHandler *ranges_handler = cu_context_->ranges_handler; + + if (ranges_handler) { + if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) { + ranges.clear(); + cu_context_->reporter->MalformedRangeList(ranges_); + } + } else { + cu_context_->reporter->MissingRanges(); + } + } + + // Did we collect the information we need? Not all DWARF function + // entries are non-empty (for example, inlined functions that were never + // used), but all the ones we're interested in cover a non-empty range of + // bytes. + if (!IsEmptyRange(ranges)) { + low_pc_ = ranges.front().address; + + // Malformed DWARF may omit the name, but all Module::Functions must + // have names. + string name; + if (!name_.empty()) { + name = name_; + } else { + // If we have a forward reference to a DW_AT_specification or + // DW_AT_abstract_origin, then don't warn, the name will be fixed up + // later + if (forward_ref_die_offset_ == 0) + cu_context_->reporter->UnnamedFunction(offset_); + name = ""; + } + + // Create a Module::Function based on the data we've gathered, and + // add it to the functions_ list. + scoped_ptr func(new Module::Function(name, low_pc_)); + func->ranges = ranges; + func->parameter_size = 0; + if (func->address) { + // If the function address is zero this is a sign that this function + // description is just empty debug data and should just be discarded. + cu_context_->functions.push_back(func.release()); + if (forward_ref_die_offset_ != 0) { + auto iter = + cu_context_->forward_ref_die_to_func.find(forward_ref_die_offset_); + if (iter == cu_context_->forward_ref_die_to_func.end()) { + cu_context_->reporter->UnknownSpecification(offset_, + forward_ref_die_offset_); + } else { + iter->second = cu_context_->functions.back(); + } + } + } + } else if (inline_) { + AbstractOrigin origin(name_); + cu_context_->file_context->file_private_->origins[offset_] = origin; + } +} + +// A handler for DIEs that contain functions and contribute a +// component to their names: namespaces, classes, etc. +class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { + public: + NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, + uint64 offset) + : GenericDIEHandler(cu_context, parent_context, offset) { } + bool EndAttributes(); + DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); + + private: + DIEContext child_context_; // A context for our children. +}; + +bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { + child_context_.name = ComputeQualifiedName(); + return true; +} + +dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( + uint64 offset, + enum DwarfTag tag) { + switch (tag) { + case dwarf2reader::DW_TAG_subprogram: + return new FuncHandler(cu_context_, &child_context_, offset); + case dwarf2reader::DW_TAG_namespace: + case dwarf2reader::DW_TAG_class_type: + case dwarf2reader::DW_TAG_structure_type: + case dwarf2reader::DW_TAG_union_type: + return new NamedScopeHandler(cu_context_, &child_context_, offset); + default: + return NULL; + } +} + +void DwarfCUToModule::WarningReporter::CUHeading() { + if (printed_cu_header_) + return; + fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", + filename_.c_str(), cu_name_.c_str(), cu_offset_); + printed_cu_header_ = true; +} + +void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, + uint64 target) { + CUHeading(); + fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" + " attribute referring to the DIE at offset 0x%llx, which was not" + " marked as a declaration\n", + filename_.c_str(), offset, target); +} + +void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, + uint64 target) { + CUHeading(); + fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" + " attribute referring to the DIE at offset 0x%llx, which was not" + " marked as an inline\n", + filename_.c_str(), offset, target); +} + +void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { + CUHeading(); + fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", + filename_.c_str(), name.c_str()); +} + +void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: line number data offset beyond end" + " of '.debug_line' section\n", + filename_.c_str()); +} + +void DwarfCUToModule::WarningReporter::UncoveredHeading() { + if (printed_unpaired_header_) + return; + CUHeading(); + fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", + filename_.c_str()); + printed_unpaired_header_ = true; +} + +void DwarfCUToModule::WarningReporter::UncoveredFunction( + const Module::Function &function) { + if (!uncovered_warnings_enabled_) + return; + UncoveredHeading(); + fprintf(stderr, " function%s: %s\n", + IsEmptyRange(function.ranges) ? " (zero-length)" : "", + function.name.c_str()); +} + +void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { + if (!uncovered_warnings_enabled_) + return; + UncoveredHeading(); + fprintf(stderr, " line%s: %s:%d at 0x%" PRIx64 "\n", + (line.size == 0 ? " (zero-length)" : ""), + line.file->name.c_str(), line.number, line.address); +} + +void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: function at offset 0x%llx has no name\n", + filename_.c_str(), offset); +} + +void DwarfCUToModule::WarningReporter::DemangleError(const string &input) { + CUHeading(); + fprintf(stderr, "%s: warning: failed to demangle %s\n", + filename_.c_str(), input.c_str()); +} + +void DwarfCUToModule::WarningReporter::UnhandledInterCUReference( + uint64 offset, uint64 target) { + CUHeading(); + fprintf(stderr, "%s: warning: the DIE at offset 0x%llx has a " + "DW_FORM_ref_addr attribute with an inter-CU reference to " + "0x%llx, but inter-CU reference handling is turned off.\n", + filename_.c_str(), offset, target); +} + +void DwarfCUToModule::WarningReporter::MalformedRangeList(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: the range list at offset 0x%llx falls out of " + "the .debug_ranges section.\n", + filename_.c_str(), offset); +} + +void DwarfCUToModule::WarningReporter::MissingRanges() { + CUHeading(); + fprintf(stderr, "%s: warning: A DW_AT_ranges attribute was encountered but " + "the .debug_ranges section is missing.\n", filename_.c_str()); +} + +DwarfCUToModule::DwarfCUToModule(FileContext *file_context, + LineToModuleHandler *line_reader, + RangesHandler *ranges_handler, + WarningReporter *reporter) + : line_reader_(line_reader), + cu_context_(new CUContext(file_context, reporter, ranges_handler)), + child_context_(new DIEContext()), + has_source_line_info_(false) { +} + +DwarfCUToModule::~DwarfCUToModule() { +} + +void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data) { + switch (attr) { + case dwarf2reader::DW_AT_language: // source language of this CU + SetLanguage(static_cast(data)); + break; + default: + break; + } +} + +void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data) { + switch (attr) { + case dwarf2reader::DW_AT_stmt_list: // Line number information. + has_source_line_info_ = true; + source_line_offset_ = data; + break; + case dwarf2reader::DW_AT_language: // source language of this CU + SetLanguage(static_cast(data)); + break; + case dwarf2reader::DW_AT_low_pc: + cu_context_->low_pc = data; + break; + case dwarf2reader::DW_AT_high_pc: + cu_context_->high_pc = data; + break; + case dwarf2reader::DW_AT_ranges: + cu_context_->ranges = data; + break; + + default: + break; + } +} + +void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data) { + switch (attr) { + case dwarf2reader::DW_AT_name: + cu_context_->reporter->SetCUName(data); + break; + case dwarf2reader::DW_AT_comp_dir: + line_reader_->StartCompilationUnit(data); + break; + default: + break; + } +} + +bool DwarfCUToModule::EndAttributes() { + return true; +} + +dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( + uint64 offset, + enum DwarfTag tag) { + switch (tag) { + case dwarf2reader::DW_TAG_subprogram: + return new FuncHandler(cu_context_.get(), child_context_.get(), offset); + case dwarf2reader::DW_TAG_namespace: + case dwarf2reader::DW_TAG_class_type: + case dwarf2reader::DW_TAG_structure_type: + case dwarf2reader::DW_TAG_union_type: + case dwarf2reader::DW_TAG_module: + return new NamedScopeHandler(cu_context_.get(), child_context_.get(), + offset); + default: + return NULL; + } +} + +void DwarfCUToModule::SetLanguage(DwarfLanguage language) { + switch (language) { + case dwarf2reader::DW_LANG_Java: + cu_context_->language = Language::Java; + break; + + case dwarf2reader::DW_LANG_Swift: + cu_context_->language = Language::Swift; + break; + + case dwarf2reader::DW_LANG_Rust: + cu_context_->language = Language::Rust; + break; + + // DWARF has no generic language code for assembly language; this is + // what the GNU toolchain uses. + case dwarf2reader::DW_LANG_Mips_Assembler: + cu_context_->language = Language::Assembler; + break; + + // C++ covers so many cases that it probably has some way to cope + // with whatever the other languages throw at us. So make it the + // default. + // + // Objective C and Objective C++ seem to create entries for + // methods whose DW_AT_name values are already fully-qualified: + // "-[Classname method:]". These appear at the top level. + // + // DWARF data for C should never include namespaces or functions + // nested in struct types, but if it ever does, then C++'s + // notation is probably not a bad choice for that. + default: + case dwarf2reader::DW_LANG_ObjC: + case dwarf2reader::DW_LANG_ObjC_plus_plus: + case dwarf2reader::DW_LANG_C: + case dwarf2reader::DW_LANG_C89: + case dwarf2reader::DW_LANG_C99: + case dwarf2reader::DW_LANG_C_plus_plus: + cu_context_->language = Language::CPlusPlus; + break; + } +} + +void DwarfCUToModule::ReadSourceLines(uint64 offset) { + const dwarf2reader::SectionMap §ion_map + = cu_context_->file_context->section_map(); + dwarf2reader::SectionMap::const_iterator map_entry + = section_map.find(".debug_line"); + // Mac OS X puts DWARF data in sections whose names begin with "__" + // instead of ".". + if (map_entry == section_map.end()) + map_entry = section_map.find("__debug_line"); + if (map_entry == section_map.end()) { + cu_context_->reporter->MissingSection(".debug_line"); + return; + } + const uint8_t *section_start = map_entry->second.first; + uint64 section_length = map_entry->second.second; + if (offset >= section_length) { + cu_context_->reporter->BadLineInfoOffset(offset); + return; + } + line_reader_->ReadProgram(section_start + offset, section_length - offset, + cu_context_->file_context->module_, &lines_); +} + +namespace { +class FunctionRange { + public: + FunctionRange(const Module::Range &range, Module::Function *function) : + address(range.address), size(range.size), function(function) { } + + void AddLine(Module::Line &line) { + function->lines.push_back(line); + } + + Module::Address address; + Module::Address size; + Module::Function *function; +}; + +// Fills an array of ranges with pointers to the functions which owns +// them. The array is sorted in ascending order and the ranges are non +// empty and non-overlapping. + +static void FillSortedFunctionRanges(vector &dest_ranges, + vector *functions) { + for (vector::const_iterator func_it = functions->cbegin(); + func_it != functions->cend(); + func_it++) + { + Module::Function *func = *func_it; + vector &ranges = func->ranges; + for (vector::const_iterator ranges_it = ranges.cbegin(); + ranges_it != ranges.cend(); + ++ranges_it) { + FunctionRange range(*ranges_it, func); + if (range.size != 0) { + dest_ranges.push_back(range); + } + } + } + + sort(dest_ranges.begin(), dest_ranges.end(), + [](const FunctionRange &fr1, const FunctionRange &fr2) { + return fr1.address < fr2.address; + } + ); +} + +// Return true if ADDRESS falls within the range of ITEM. +template +inline bool within(const T &item, Module::Address address) { + // Because Module::Address is unsigned, and unsigned arithmetic + // wraps around, this will be false if ADDRESS falls before the + // start of ITEM, or if it falls after ITEM's end. + return address - item.address < item.size; +} +} + +void DwarfCUToModule::AssignLinesToFunctions() { + vector *functions = &cu_context_->functions; + WarningReporter *reporter = cu_context_->reporter; + + // This would be simpler if we assumed that source line entries + // don't cross function boundaries. However, there's no real reason + // to assume that (say) a series of function definitions on the same + // line wouldn't get coalesced into one line number entry. The + // DWARF spec certainly makes no such promises. + // + // So treat the functions and lines as peers, and take the trouble + // to compute their ranges' intersections precisely. In any case, + // the hair here is a constant factor for performance; the + // complexity from here on out is linear. + + // Put both our functions and lines in order by address. + std::sort(functions->begin(), functions->end(), + Module::Function::CompareByAddress); + std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress); + + // The last line that we used any piece of. We use this only for + // generating warnings. + const Module::Line *last_line_used = NULL; + + // The last function and line we warned about --- so we can avoid + // doing so more than once. + const Module::Function *last_function_cited = NULL; + const Module::Line *last_line_cited = NULL; + + // Prepare a sorted list of ranges with range-to-function mapping + vector sorted_ranges; + FillSortedFunctionRanges(sorted_ranges, functions); + + // Make a single pass through both the range and line vectors from lower to + // higher addresses, populating each range's function lines vector with lines + // from our lines_ vector that fall within the range. + vector::iterator range_it = sorted_ranges.begin(); + vector::const_iterator line_it = lines_.begin(); + + Module::Address current; + + // Pointers to the referents of func_it and line_it, or NULL if the + // iterator is at the end of the sequence. + FunctionRange *range; + const Module::Line *line; + + // Start current at the beginning of the first line or function, + // whichever is earlier. + if (range_it != sorted_ranges.end() && line_it != lines_.end()) { + range = &*range_it; + line = &*line_it; + current = std::min(range->address, line->address); + } else if (line_it != lines_.end()) { + range = NULL; + line = &*line_it; + current = line->address; + } else if (range_it != sorted_ranges.end()) { + range = &*range_it; + line = NULL; + current = range->address; + } else { + return; + } + + while (range || line) { + // This loop has two invariants that hold at the top. + // + // First, at least one of the iterators is not at the end of its + // sequence, and those that are not refer to the earliest + // range or line that contains or starts after CURRENT. + // + // Note that every byte is in one of four states: it is covered + // or not covered by a range, and, independently, it is + // covered or not covered by a line. + // + // The second invariant is that CURRENT refers to a byte whose + // state is different from its predecessor, or it refers to the + // first byte in the address space. In other words, CURRENT is + // always the address of a transition. + // + // Note that, although each iteration advances CURRENT from one + // transition address to the next in each iteration, it might + // not advance the iterators. Suppose we have a range that + // starts with a line, has a gap, and then a second line, and + // suppose that we enter an iteration with CURRENT at the end of + // the first line. The next transition address is the start of + // the second line, after the gap, so the iteration should + // advance CURRENT to that point. At the head of that iteration, + // the invariants require that the line iterator be pointing at + // the second line. But this is also true at the head of the + // next. And clearly, the iteration must not change the range + // iterator. So neither iterator moves. + + // Assert the first invariant (see above). + assert(!range || current < range->address || within(*range, current)); + assert(!line || current < line->address || within(*line, current)); + + // The next transition after CURRENT. + Module::Address next_transition; + + // Figure out which state we're in, add lines or warn, and compute + // the next transition address. + if (range && current >= range->address) { + if (line && current >= line->address) { + // Covered by both a line and a range. + Module::Address range_left = range->size - (current - range->address); + Module::Address line_left = line->size - (current - line->address); + // This may overflow, but things work out. + next_transition = current + std::min(range_left, line_left); + Module::Line l = *line; + l.address = current; + l.size = next_transition - current; + range->AddLine(l); + last_line_used = line; + } else { + // Covered by a range, but no line. + if (range->function != last_function_cited) { + reporter->UncoveredFunction(*(range->function)); + last_function_cited = range->function; + } + if (line && within(*range, line->address)) + next_transition = line->address; + else + // If this overflows, we'll catch it below. + next_transition = range->address + range->size; + } + } else { + if (line && current >= line->address) { + // Covered by a line, but no range. + // + // If GCC emits padding after one function to align the start + // of the next, then it will attribute the padding + // instructions to the last source line of function (to reduce + // the size of the line number info), but omit it from the + // DW_AT_{low,high}_pc range given in .debug_info (since it + // costs nothing to be precise there). If we did use at least + // some of the line we're about to skip, and it ends at the + // start of the next function, then assume this is what + // happened, and don't warn. + if (line != last_line_cited + && !(range + && line == last_line_used + && range->address - line->address == line->size)) { + reporter->UncoveredLine(*line); + last_line_cited = line; + } + if (range && within(*line, range->address)) + next_transition = range->address; + else + // If this overflows, we'll catch it below. + next_transition = line->address + line->size; + } else { + // Covered by neither a range nor a line. By the invariant, + // both range and line begin after CURRENT. The next transition + // is the start of the next range or next line, whichever + // is earliest. + assert(range || line); + if (range && line) + next_transition = std::min(range->address, line->address); + else if (range) + next_transition = range->address; + else + next_transition = line->address; + } + } + + // If a function or line abuts the end of the address space, then + // next_transition may end up being zero, in which case we've completed + // our pass. Handle that here, instead of trying to deal with it in + // each place we compute next_transition. + if (!next_transition) + break; + + // Advance iterators as needed. If lines overlap or functions overlap, + // then we could go around more than once. We don't worry too much + // about what result we produce in that case, just as long as we don't + // hang or crash. + while (range_it != sorted_ranges.end() + && next_transition >= range_it->address + && !within(*range_it, next_transition)) + range_it++; + range = (range_it != sorted_ranges.end()) ? &(*range_it) : NULL; + while (line_it != lines_.end() + && next_transition >= line_it->address + && !within(*line_it, next_transition)) + line_it++; + line = (line_it != lines_.end()) ? &*line_it : NULL; + + // We must make progress. + assert(next_transition > current); + current = next_transition; + } +} + +void DwarfCUToModule::Finish() { + // Assembly language files have no function data, and that gives us + // no place to store our line numbers (even though the GNU toolchain + // will happily produce source line info for assembly language + // files). To avoid spurious warnings about lines we can't assign + // to functions, skip CUs in languages that lack functions. + if (!cu_context_->language->HasFunctions()) + return; + + // Read source line info, if we have any. + if (has_source_line_info_) + ReadSourceLines(source_line_offset_); + + vector *functions = &cu_context_->functions; + + // Dole out lines to the appropriate functions. + AssignLinesToFunctions(); + + // Add our functions, which now have source lines assigned to them, + // to module_. + cu_context_->file_context->module_->AddFunctions(functions->begin(), + functions->end()); + + // Ownership of the function objects has shifted from cu_context to + // the Module. + functions->clear(); + + cu_context_->file_context->ClearSpecifications(); +} + +bool DwarfCUToModule::StartCompilationUnit(uint64 offset, + uint8 address_size, + uint8 offset_size, + uint64 cu_length, + uint8 dwarf_version) { + return dwarf_version >= 2; +} + +bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag) { + // We don't deal with partial compilation units (the only other tag + // likely to be used for root DIE). + return tag == dwarf2reader::DW_TAG_compile_unit; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h new file mode 100644 index 0000000000..f73a3c933b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h @@ -0,0 +1,345 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// Add DWARF debugging information to a Breakpad symbol file. This +// file defines the DwarfCUToModule class, which accepts parsed DWARF +// data and populates a google_breakpad::Module with the results; the +// Module can then write its contents as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__ +#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__ + +#include + +#include + +#include "common/language.h" +#include "common/module.h" +#include "common/dwarf/bytereader.h" +#include "common/dwarf/dwarf2diehandler.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfLanguage; +using dwarf2reader::DwarfTag; + +// Populate a google_breakpad::Module with DWARF debugging information. +// +// An instance of this class can be provided as a handler to a +// dwarf2reader::DIEDispatcher, which can in turn be a handler for a +// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results +// of parsing to populate a google_breakpad::Module with source file, +// function, and source line information. +class DwarfCUToModule: public dwarf2reader::RootDIEHandler { + struct FilePrivate; + public: + // Information global to the DWARF-bearing file we are processing, + // for use by DwarfCUToModule. Each DwarfCUToModule instance deals + // with a single compilation unit within the file, but information + // global to the whole file is held here. The client is responsible + // for filling it in appropriately (except for the 'file_private' + // field, which the constructor and destructor take care of), and + // then providing it to the DwarfCUToModule instance for each + // compilation unit we process in that file. Set HANDLE_INTER_CU_REFS + // to true to handle debugging symbols with DW_FORM_ref_addr entries. + class FileContext { + public: + FileContext(const string &filename, + Module *module, + bool handle_inter_cu_refs); + ~FileContext(); + + // Add CONTENTS of size LENGTH to the section map as NAME. + void AddSectionToSectionMap(const string& name, + const uint8_t *contents, + uint64 length); + + // Clear the section map for testing. + void ClearSectionMapForTest(); + + const dwarf2reader::SectionMap& section_map() const; + + private: + friend class DwarfCUToModule; + + // Clears all the Specifications if HANDLE_INTER_CU_REFS_ is false. + void ClearSpecifications(); + + // Given an OFFSET and a CU that starts at COMPILATION_UNIT_START, returns + // true if this is an inter-compilation unit reference that is not being + // handled. + bool IsUnhandledInterCUReference(uint64 offset, + uint64 compilation_unit_start) const; + + // The name of this file, for use in error messages. + const string filename_; + + // A map of this file's sections, used for finding other DWARF + // sections that the .debug_info section may refer to. + dwarf2reader::SectionMap section_map_; + + // The Module to which we're contributing definitions. + Module *module_; + + // True if we are handling references between compilation units. + const bool handle_inter_cu_refs_; + + // Inter-compilation unit data used internally by the handlers. + scoped_ptr file_private_; + }; + + // An abstract base class for handlers that handle DWARF range lists for + // DwarfCUToModule. + class RangesHandler { + public: + RangesHandler() { } + virtual ~RangesHandler() { } + + // Called when finishing a function to populate the function's ranges. + // The ranges' entries are read starting from offset in the .debug_ranges + // section, base_address holds the base PC the range list values are + // offsets off. Return false if the rangelist falls out of the + // .debug_ranges section. + virtual bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) = 0; + }; + + // An abstract base class for handlers that handle DWARF line data + // for DwarfCUToModule. DwarfCUToModule could certainly just use + // dwarf2reader::LineInfo itself directly, but decoupling things + // this way makes unit testing a little easier. + class LineToModuleHandler { + public: + LineToModuleHandler() { } + virtual ~LineToModuleHandler() { } + + // Called at the beginning of a new compilation unit, prior to calling + // ReadProgram(). compilation_dir will indicate the path that the + // current compilation unit was compiled in, consistent with the + // DW_AT_comp_dir DIE. + virtual void StartCompilationUnit(const string& compilation_dir) = 0; + + // Populate MODULE and LINES with source file names and code/line + // mappings, given a pointer to some DWARF line number data + // PROGRAM, and an overestimate of its size. Add no zero-length + // lines to LINES. + virtual void ReadProgram(const uint8_t *program, uint64 length, + Module *module, vector *lines) = 0; + }; + + // The interface DwarfCUToModule uses to report warnings. The member + // function definitions for this class write messages to stderr, but + // you can override them if you'd like to detect or report these + // conditions yourself. + class WarningReporter { + public: + // Warn about problems in the DWARF file FILENAME, in the + // compilation unit at OFFSET. + WarningReporter(const string &filename, uint64 cu_offset) + : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false), + printed_unpaired_header_(false), + uncovered_warnings_enabled_(false) { } + virtual ~WarningReporter() { } + + // Set the name of the compilation unit we're processing to NAME. + virtual void SetCUName(const string &name) { cu_name_ = name; } + + // Accessor and setter for uncovered_warnings_enabled_. + // UncoveredFunction and UncoveredLine only report a problem if that is + // true. By default, these warnings are disabled, because those + // conditions occur occasionally in healthy code. + virtual bool uncovered_warnings_enabled() const { + return uncovered_warnings_enabled_; + } + virtual void set_uncovered_warnings_enabled(bool value) { + uncovered_warnings_enabled_ = value; + } + + // A DW_AT_specification in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as a declaration, + // at TARGET. + virtual void UnknownSpecification(uint64 offset, uint64 target); + + // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we + // haven't processed yet, or that wasn't marked as inline, at TARGET. + virtual void UnknownAbstractOrigin(uint64 offset, uint64 target); + + // We were unable to find the DWARF section named SECTION_NAME. + virtual void MissingSection(const string §ion_name); + + // The CU's DW_AT_stmt_list offset OFFSET is bogus. + virtual void BadLineInfoOffset(uint64 offset); + + // FUNCTION includes code covered by no line number data. + virtual void UncoveredFunction(const Module::Function &function); + + // Line number NUMBER in LINE_FILE, of length LENGTH, includes code + // covered by no function. + virtual void UncoveredLine(const Module::Line &line); + + // The DW_TAG_subprogram DIE at OFFSET has no name specified directly + // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin + // link. + virtual void UnnamedFunction(uint64 offset); + + // __cxa_demangle() failed to demangle INPUT. + virtual void DemangleError(const string &input); + + // The DW_FORM_ref_addr at OFFSET to TARGET was not handled because + // FilePrivate did not retain the inter-CU specification data. + virtual void UnhandledInterCUReference(uint64 offset, uint64 target); + + // The DW_AT_ranges at offset is malformed (truncated or outside of the + // .debug_ranges section's bound). + virtual void MalformedRangeList(uint64 offset); + + // A DW_AT_ranges attribute was encountered but the no .debug_ranges + // section was found. + virtual void MissingRanges(); + + uint64 cu_offset() const { + return cu_offset_; + } + + protected: + const string filename_; + const uint64 cu_offset_; + string cu_name_; + bool printed_cu_header_; + bool printed_unpaired_header_; + bool uncovered_warnings_enabled_; + + private: + // Print a per-CU heading, once. + void CUHeading(); + // Print an unpaired function/line heading, once. + void UncoveredHeading(); + }; + + // Create a DWARF debugging info handler for a compilation unit + // within FILE_CONTEXT. This uses information received from the + // dwarf2reader::CompilationUnit DWARF parser to populate + // FILE_CONTEXT->module. Use LINE_READER to handle the compilation + // unit's line number data. Use REPORTER to report problems with the + // data we find. + DwarfCUToModule(FileContext *file_context, + LineToModuleHandler *line_reader, + RangesHandler *ranges_handler, + WarningReporter *reporter); + ~DwarfCUToModule(); + + void ProcessAttributeSigned(enum DwarfAttribute attr, + enum DwarfForm form, + int64 data); + void ProcessAttributeUnsigned(enum DwarfAttribute attr, + enum DwarfForm form, + uint64 data); + void ProcessAttributeString(enum DwarfAttribute attr, + enum DwarfForm form, + const string &data); + bool EndAttributes(); + DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); + + // Assign all our source Lines to the Functions that cover their + // addresses, and then add them to module_. + void Finish(); + + bool StartCompilationUnit(uint64 offset, uint8 address_size, + uint8 offset_size, uint64 cu_length, + uint8 dwarf_version); + bool StartRootDIE(uint64 offset, enum DwarfTag tag); + + private: + // Used internally by the handler. Full definitions are in + // dwarf_cu_to_module.cc. + struct CUContext; + struct DIEContext; + struct Specification; + class GenericDIEHandler; + class FuncHandler; + class NamedScopeHandler; + + // A map from section offsets to specifications. + typedef map SpecificationByOffset; + + // Set this compilation unit's source language to LANGUAGE. + void SetLanguage(DwarfLanguage language); + + // Read source line information at OFFSET in the .debug_line + // section. Record source files in module_, but record source lines + // in lines_; we apportion them to functions in + // AssignLinesToFunctions. + void ReadSourceLines(uint64 offset); + + // Assign the lines in lines_ to the individual line lists of the + // functions in functions_. (DWARF line information maps an entire + // compilation unit at a time, and gives no indication of which + // lines belong to which functions, beyond their addresses.) + void AssignLinesToFunctions(); + + // The only reason cu_context_ and child_context_ are pointers is + // that we want to keep their definitions private to + // dwarf_cu_to_module.cc, instead of listing them all here. They are + // owned by this DwarfCUToModule: the constructor sets them, and the + // destructor deletes them. + + // The handler to use to handle line number data. + LineToModuleHandler *line_reader_; + + // This compilation unit's context. + scoped_ptr cu_context_; + + // A context for our children. + scoped_ptr child_context_; + + // True if this compilation unit has source line information. + bool has_source_line_info_; + + // The offset of this compilation unit's line number information in + // the .debug_line section. + uint64 source_line_offset_; + + // The line numbers we have seen thus far. We accumulate these here + // during parsing. Then, in Finish, we call AssignLinesToFunctions + // to dole them out to the appropriate functions. + vector lines_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc new file mode 100644 index 0000000000..aef69221ce --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc @@ -0,0 +1,1854 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. + +#include + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_cu_to_module.h" +#include "common/using_std_string.h" + +using std::make_pair; +using std::vector; + +using dwarf2reader::DIEHandler; +using dwarf2reader::DwarfTag; +using dwarf2reader::DwarfAttribute; +using dwarf2reader::DwarfForm; +using dwarf2reader::DwarfInline; +using dwarf2reader::RootDIEHandler; +using google_breakpad::DwarfCUToModule; +using google_breakpad::Module; + +using ::testing::_; +using ::testing::AtMost; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::Test; +using ::testing::TestWithParam; +using ::testing::Values; +using ::testing::ValuesIn; + +// Mock classes. + +class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler { + public: + MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir)); + MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64 length, + Module *module, vector *lines)); +}; + +class MockWarningReporter: public DwarfCUToModule::WarningReporter { + public: + MockWarningReporter(const string &filename, uint64 cu_offset) + : DwarfCUToModule::WarningReporter(filename, cu_offset) { } + MOCK_METHOD1(SetCUName, void(const string &name)); + MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target)); + MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target)); + MOCK_METHOD1(MissingSection, void(const string §ion_name)); + MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset)); + MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); + MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); + MOCK_METHOD1(UnnamedFunction, void(uint64 offset)); + MOCK_METHOD1(DemangleError, void(const string &input)); + MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target)); +}; + +// A fixture class including all the objects needed to handle a +// compilation unit, and their entourage. It includes member functions +// for doing common kinds of setup and tests. +class CUFixtureBase { + public: + // If we have: + // + // vector lines; + // AppendLinesFunctor appender(lines); + // + // then doing: + // + // appender(line_program, length, module, line_vector); + // + // will append lines to the end of line_vector. We can use this with + // MockLineToModuleHandler like this: + // + // MockLineToModuleHandler l2m; + // EXPECT_CALL(l2m, ReadProgram(_,_,_,_)) + // .WillOnce(DoAll(Invoke(appender), Return())); + // + // in which case calling l2m with some line vector will append lines. + class AppendLinesFunctor { + public: + explicit AppendLinesFunctor( + const vector *lines) : lines_(lines) { } + void operator()(const uint8_t *program, uint64 length, + Module *module, vector *lines) { + lines->insert(lines->end(), lines_->begin(), lines_->end()); + } + private: + const vector *lines_; + }; + + CUFixtureBase() + : module_("module-name", "module-os", "module-arch", "module-id"), + file_context_("dwarf-filename", &module_, true), + language_(dwarf2reader::DW_LANG_none), + language_signed_(false), + appender_(&lines_), + reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), + root_handler_(&file_context_, &line_reader_, + /* ranges_reader */ nullptr, &reporter_), + functions_filled_(false) { + // By default, expect no warnings to be reported, and expect the + // compilation unit's name to be provided. The test can override + // these expectations. + EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1); + EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0); + EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0); + EXPECT_CALL(reporter_, MissingSection(_)).Times(0); + EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0); + EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); + EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); + EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0); + + // By default, expect the line program reader not to be invoked. We + // may override this in StartCU. + EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0); + EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0); + + // The handler will consult this section map to decide what to + // pass to our line reader. + file_context_.AddSectionToSectionMap(".debug_line", + dummy_line_program_, + dummy_line_size_); + } + + // Add a line with the given address, size, filename, and line + // number to the end of the statement list the handler will receive + // when it invokes its LineToModuleHandler. Call this before calling + // StartCU. + void PushLine(Module::Address address, Module::Address size, + const string &filename, int line_number); + + // Use LANGUAGE for the compilation unit. More precisely, arrange + // for StartCU to pass the compilation unit's root DIE a + // DW_AT_language attribute whose value is LANGUAGE. + void SetLanguage(dwarf2reader::DwarfLanguage language) { + language_ = language; + } + + // If SIGNED true, have StartCU report DW_AT_language as a signed + // attribute; if false, have it report it as unsigned. + void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; } + + // Call the handler this.root_handler_'s StartCompilationUnit and + // StartRootDIE member functions, passing it appropriate attributes as + // determined by prior calls to PushLine and SetLanguage. Leave + // this.root_handler_ ready to hear about children: call + // this.root_handler_.EndAttributes, but not this.root_handler_.Finish. + void StartCU(); + + // Have HANDLER process some strange attribute/form/value triples. + void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); + + // Start a child DIE of PARENT with the given tag and name. Leave + // the handler ready to hear about children: call EndAttributes, but + // not Finish. + DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, + const string &name); + + // Start a child DIE of PARENT with the given tag and a + // DW_AT_specification attribute whose value is SPECIFICATION. Leave + // the handler ready to hear about children: call EndAttributes, but + // not Finish. If NAME is non-zero, use it as the DW_AT_name + // attribute. + DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, + uint64 specification, const char *name = NULL); + + // Define a function as a child of PARENT with the given name, address, and + // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute + // will be written as an address; otherwise it will be written as the + // function's size. Call EndAttributes and Finish; one cannot define + // children of the defined function's DIE. + void DefineFunction(DIEHandler *parent, const string &name, + Module::Address address, Module::Address size, + const char* mangled_name, + DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr); + + // Create a declaration DIE as a child of PARENT with the given + // offset, tag and name. If NAME is the empty string, don't provide + // a DW_AT_name attribute. Call EndAttributes and Finish. + void DeclarationDIE(DIEHandler *parent, uint64 offset, + DwarfTag tag, const string &name, + const string &mangled_name); + + // Create a definition DIE as a child of PARENT with the given tag + // that refers to the declaration DIE at offset SPECIFICATION as its + // specification. If NAME is non-empty, pass it as the DW_AT_name + // attribute. If SIZE is non-zero, record ADDRESS and SIZE as + // low_pc/high_pc attributes. + void DefinitionDIE(DIEHandler *parent, DwarfTag tag, + uint64 specification, const string &name, + Module::Address address = 0, Module::Address size = 0); + + // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If + // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at + // offset SPECIFICATION as its specification. If Name is non-empty, pass it + // as the DW_AT_name attribute. + void AbstractInstanceDIE(DIEHandler *parent, uint64 offset, + DwarfInline type, uint64 specification, + const string &name, + DwarfForm form = dwarf2reader::DW_FORM_data1); + + // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to + // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty + // string, don't provide a DW_AT_name attribute. + void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, + uint64 origin, Module::Address address, + Module::Address size); + + // The following Test* functions should be called after calling + // this.root_handler_.Finish. After that point, no further calls + // should be made on the handler. + + // Test that the number of functions defined in the module this.module_ is + // equal to EXPECTED. + void TestFunctionCount(size_t expected); + + // Test that the I'th function (ordered by address) in the module + // this.module_ has the given name, address, and size, and that its + // parameter size is zero. + void TestFunction(int i, const string &name, + Module::Address address, Module::Address size); + + // Test that the number of source lines owned by the I'th function + // in the module this.module_ is equal to EXPECTED. + void TestLineCount(int i, size_t expected); + + // Test that the J'th line (ordered by address) of the I'th function + // (again, by address) has the given address, size, filename, and + // line number. + void TestLine(int i, int j, Module::Address address, Module::Address size, + const string &filename, int number); + + // Actual objects under test. + Module module_; + DwarfCUToModule::FileContext file_context_; + + // If this is not DW_LANG_none, we'll pass it as a DW_AT_language + // attribute to the compilation unit. This defaults to DW_LANG_none. + dwarf2reader::DwarfLanguage language_; + + // If this is true, report DW_AT_language as a signed value; if false, + // report it as an unsigned value. + bool language_signed_; + + // If this is not empty, we'll give the CU a DW_AT_comp_dir attribute that + // indicates the path that this compilation unit was compiled in. + string compilation_dir_; + + // If this is not empty, we'll give the CU a DW_AT_stmt_list + // attribute that, when passed to line_reader_, adds these lines to the + // provided lines array. + vector lines_; + + // Mock line program reader. + MockLineToModuleHandler line_reader_; + AppendLinesFunctor appender_; + static const uint8_t dummy_line_program_[]; + static const size_t dummy_line_size_; + + MockWarningReporter reporter_; + DwarfCUToModule root_handler_; + + private: + // Fill functions_, if we haven't already. + void FillFunctions(); + + // If functions_filled_ is true, this is a table of functions we've + // extracted from module_, sorted by address. + vector functions_; + // True if we have filled the above vector with this.module_'s function list. + bool functions_filled_; +}; + +const uint8_t CUFixtureBase::dummy_line_program_[] = "lots of fun data"; +const size_t CUFixtureBase::dummy_line_size_ = + sizeof(CUFixtureBase::dummy_line_program_); + +void CUFixtureBase::PushLine(Module::Address address, Module::Address size, + const string &filename, int line_number) { + Module::Line l; + l.address = address; + l.size = size; + l.file = module_.FindFile(filename); + l.number = line_number; + lines_.push_back(l); +} + +void CUFixtureBase::StartCU() { + if (!compilation_dir_.empty()) + EXPECT_CALL(line_reader_, + StartCompilationUnit(compilation_dir_)).Times(1); + + // If we have lines, make the line reader expect to be invoked at + // most once. (Hey, if the handler can pass its tests without + // bothering to read the line number data, that's great.) + // Have it add the lines passed to PushLine. Otherwise, leave the + // initial expectation (no calls) in force. + if (!lines_.empty()) + EXPECT_CALL(line_reader_, + ReadProgram(&dummy_line_program_[0], dummy_line_size_, + &module_, _)) + .Times(AtMost(1)) + .WillOnce(DoAll(Invoke(appender_), Return())); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, + 0x4241b4f33720dd5cULL, 3)); + { + ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, + dwarf2reader::DW_TAG_compile_unit)); + } + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + "compilation-unit-name"); + if (!compilation_dir_.empty()) + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir, + dwarf2reader::DW_FORM_strp, + compilation_dir_); + if (!lines_.empty()) + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, + dwarf2reader::DW_FORM_ref4, + 0); + if (language_ != dwarf2reader::DW_LANG_none) { + if (language_signed_) + root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, + dwarf2reader::DW_FORM_sdata, + language_); + else + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, + dwarf2reader::DW_FORM_udata, + language_); + } + ASSERT_TRUE(root_handler_.EndAttributes()); +} + +void CUFixtureBase::ProcessStrangeAttributes( + dwarf2reader::DIEHandler *handler) { + handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, + (DwarfForm) 0x4106e4db, + 0xa592571997facda1ULL); + handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095, + (DwarfForm) 0x0f16fe87, + 0x12602a4e3bf1f446LL); + handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f, + (DwarfForm) 0x829e038a, + 0x50fddef44734fdecULL); + static const uint8_t buffer[10] = "frobynode"; + handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51, + (DwarfForm) 0x2f43b041, + buffer, sizeof(buffer)); + handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041, + (DwarfForm) 0x895ffa23, + "strange string"); +} + +DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, + DwarfTag tag, + const string &name) { + dwarf2reader::DIEHandler *handler + = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); + if (!handler) + return NULL; + handler->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + ProcessStrangeAttributes(handler); + if (!handler->EndAttributes()) { + handler->Finish(); + delete handler; + return NULL; + } + + return handler; +} + +DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, + DwarfTag tag, + uint64 specification, + const char *name) { + dwarf2reader::DIEHandler *handler + = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); + if (!handler) + return NULL; + if (name) + handler->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (!handler->EndAttributes()) { + handler->Finish(); + delete handler; + return NULL; + } + + return handler; +} + +void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, + const string &name, Module::Address address, + Module::Address size, + const char* mangled_name, + DwarfForm high_pc_form) { + dwarf2reader::DIEHandler *func + = parent->FindChildHandler(0xe34797c7e68590a8LL, + dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(func != NULL); + func->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + + Module::Address high_pc = size; + if (high_pc_form == dwarf2reader::DW_FORM_addr) { + high_pc += address; + } + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + high_pc_form, + high_pc); + + if (mangled_name) + func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, + dwarf2reader::DW_FORM_strp, + mangled_name); + + ProcessStrangeAttributes(func); + EXPECT_TRUE(func->EndAttributes()); + func->Finish(); + delete func; +} + +void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset, + DwarfTag tag, + const string &name, + const string &mangled_name) { + dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag); + ASSERT_TRUE(die != NULL); + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + if (!mangled_name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, + dwarf2reader::DW_FORM_strp, + mangled_name); + + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, + dwarf2reader::DW_FORM_flag, + 1); + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::DefinitionDIE(DIEHandler *parent, + DwarfTag tag, + uint64 specification, + const string &name, + Module::Address address, + Module::Address size) { + dwarf2reader::DIEHandler *die + = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag); + ASSERT_TRUE(die != NULL); + die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + if (size) { + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + dwarf2reader::DW_FORM_addr, + address + size); + } + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, + uint64 offset, + DwarfInline type, + uint64 specification, + const string &name, + DwarfForm form) { + dwarf2reader::DIEHandler *die + = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(die != NULL); + if (specification != 0ULL) + die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, + dwarf2reader::DW_FORM_ref4, + specification); + if (form == dwarf2reader::DW_FORM_sdata) { + die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); + } else { + die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); + } + if (!name.empty()) + die->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + + EXPECT_TRUE(die->EndAttributes()); + die->Finish(); + delete die; +} + +void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, + const string &name, + uint64 origin, + Module::Address address, + Module::Address size) { + dwarf2reader::DIEHandler *func + = parent->FindChildHandler(0x11c70f94c6e87ccdLL, + dwarf2reader::DW_TAG_subprogram); + ASSERT_TRUE(func != NULL); + if (!name.empty()) { + func->ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + name); + } + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, + dwarf2reader::DW_FORM_addr, + address); + func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, + dwarf2reader::DW_FORM_addr, + address + size); + func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, + dwarf2reader::DW_FORM_ref4, + origin); + ProcessStrangeAttributes(func); + EXPECT_TRUE(func->EndAttributes()); + func->Finish(); + delete func; +} + +void CUFixtureBase::FillFunctions() { + if (functions_filled_) + return; + module_.GetFunctions(&functions_, functions_.end()); + sort(functions_.begin(), functions_.end(), + Module::Function::CompareByAddress); + functions_filled_ = true; +} + +void CUFixtureBase::TestFunctionCount(size_t expected) { + FillFunctions(); + ASSERT_EQ(expected, functions_.size()); +} + +void CUFixtureBase::TestFunction(int i, const string &name, + Module::Address address, + Module::Address size) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + + Module::Function *function = functions_[i]; + EXPECT_EQ(name, function->name); + EXPECT_EQ(address, function->address); + EXPECT_EQ(size, function->ranges[0].size); + EXPECT_EQ(0U, function->parameter_size); +} + +void CUFixtureBase::TestLineCount(int i, size_t expected) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + + ASSERT_EQ(expected, functions_[i]->lines.size()); +} + +void CUFixtureBase::TestLine(int i, int j, + Module::Address address, Module::Address size, + const string &filename, int number) { + FillFunctions(); + ASSERT_LT((size_t) i, functions_.size()); + ASSERT_LT((size_t) j, functions_[i]->lines.size()); + + Module::Line *line = &functions_[i]->lines[j]; + EXPECT_EQ(address, line->address); + EXPECT_EQ(size, line->size); + EXPECT_EQ(filename, line->file->name.c_str()); + EXPECT_EQ(number, line->number); +} + +// Include caller locations for our test subroutines. +#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) +#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) +#define SetLanguage(a) TRACE(SetLanguage(a)) +#define StartCU() TRACE(StartCU()) +#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e))) +// (DefineFunction) instead of DefineFunction to avoid macro expansion. +#define DefineFunction6(a,b,c,d,e,f) \ + TRACE((DefineFunction)((a),(b),(c),(d),(e),(f))) +#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e))) +#define DefinitionDIE(a,b,c,d,e,f) \ + TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) +#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) +#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) +#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) +#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) + +class SimpleCU: public CUFixtureBase, public Test { +}; + +TEST_F(SimpleCU, CompilationDir) { + compilation_dir_ = "/src/build/"; + + StartCU(); + root_handler_.Finish(); +} + +TEST_F(SimpleCU, OneFunc) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); + TestLineCount(0, 1); + TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", + 246571772); +} + +// As above, only DW_AT_high_pc is a length rather than an address. +TEST_F(SimpleCU, OneFuncHighPcIsLength) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction6(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, + dwarf2reader::DW_FORM_udata); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); + TestLineCount(0, 1); + TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", + 246571772); +} + +TEST_F(SimpleCU, MangledName) { + PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); + + StartCU(); + DefineFunction(&root_handler_, "function1", + 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi"); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); +} + +TEST_F(SimpleCU, IrrelevantRootChildren) { + StartCU(); + EXPECT_FALSE(root_handler_ + .FindChildHandler(0x7db32bff4e2dcfb1ULL, + dwarf2reader::DW_TAG_lexical_block)); +} + +TEST_F(SimpleCU, IrrelevantNamedScopeChildren) { + StartCU(); + DIEHandler *class_A_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + EXPECT_TRUE(class_A_handler != NULL); + EXPECT_FALSE(class_A_handler + ->FindChildHandler(0x02e55999b865e4e9ULL, + dwarf2reader::DW_TAG_lexical_block)); + delete class_A_handler; +} + +// Verify that FileContexts can safely be deleted unused. +TEST_F(SimpleCU, UnusedFileContext) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); +} + +TEST_F(SimpleCU, InlineFunction) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name"); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +TEST_F(SimpleCU, InlineFunctionSignedAttribute) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name", + dwarf2reader::DW_FORM_sdata); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +// Any DIE with an DW_AT_inline attribute can be cited by +// DW_AT_abstract_origin attributes --- even if the value of the +// DW_AT_inline attribute is DW_INL_not_inlined. +TEST_F(SimpleCU, AbstractOriginNotInlined) { + PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, + dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); + DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, + 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "abstract-instance", + 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); +} + +TEST_F(SimpleCU, UnknownAbstractOrigin) { + EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); + EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL)) + .WillOnce(Return()); + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0, "inline-name"); + DefineInlineInstanceDIE(&root_handler_, "", 1ULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +TEST_F(SimpleCU, UnnamedFunction) { + EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL)) + .WillOnce(Return()); + PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850); + + StartCU(); + DefineFunction(&root_handler_, "", + 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "", + 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL); +} + +// An address range. +struct Range { + Module::Address start, end; +}; + +// Test data for pairing functions and lines. +struct Situation { + // Two function intervals, and two line intervals. + Range functions[2], lines[2]; + + // The number of lines we expect to be assigned to each of the + // functions, and the address ranges. + int paired_count[2]; + Range paired[2][2]; + + // The number of functions that are not entirely covered by lines, + // and vice versa. + int uncovered_functions, uncovered_lines; +}; + +#define PAIRING(func1_start, func1_end, func2_start, func2_end, \ + line1_start, line1_end, line2_start, line2_end, \ + func1_num_lines, func2_num_lines, \ + func1_line1_start, func1_line1_end, \ + func1_line2_start, func1_line2_end, \ + func2_line1_start, func2_line1_end, \ + func2_line2_start, func2_line2_end, \ + uncovered_functions, uncovered_lines) \ + { { { func1_start, func1_end }, { func2_start, func2_end } }, \ + { { line1_start, line1_end }, { line2_start, line2_end } }, \ + { func1_num_lines, func2_num_lines }, \ + { { { func1_line1_start, func1_line1_end }, \ + { func1_line2_start, func1_line2_end } }, \ + { { func2_line1_start, func2_line1_end }, \ + { func2_line2_start, func2_line2_end } } }, \ + uncovered_functions, uncovered_lines }, + +Situation situations[] = { +#include "common/testdata/func-line-pairing.h" +}; + +#undef PAIRING + +class FuncLinePairing: public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, + ValuesIn(situations)); + +TEST_P(FuncLinePairing, Pairing) { + const Situation &s = GetParam(); + PushLine(s.lines[0].start, + s.lines[0].end - s.lines[0].start, + "line-file", 67636963); + PushLine(s.lines[1].start, + s.lines[1].end - s.lines[1].start, + "line-file", 67636963); + if (s.uncovered_functions) + EXPECT_CALL(reporter_, UncoveredFunction(_)) + .Times(s.uncovered_functions) + .WillRepeatedly(Return()); + if (s.uncovered_lines) + EXPECT_CALL(reporter_, UncoveredLine(_)) + .Times(s.uncovered_lines) + .WillRepeatedly(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", + s.functions[0].start, + s.functions[0].end - s.functions[0].start, NULL); + DefineFunction(&root_handler_, "function2", + s.functions[1].start, + s.functions[1].end - s.functions[1].start, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", + s.functions[0].start, + s.functions[0].end - s.functions[0].start); + TestLineCount(0, s.paired_count[0]); + for (int i = 0; i < s.paired_count[0]; i++) + TestLine(0, i, s.paired[0][i].start, + s.paired[0][i].end - s.paired[0][i].start, + "line-file", 67636963); + TestFunction(1, "function2", + s.functions[1].start, + s.functions[1].end - s.functions[1].start); + TestLineCount(1, s.paired_count[1]); + for (int i = 0; i < s.paired_count[1]; i++) + TestLine(1, i, s.paired[1][i].start, + s.paired[1][i].end - s.paired[1][i].start, + "line-file", 67636963); +} + +TEST_F(FuncLinePairing, EmptyCU) { + StartCU(); + root_handler_.Finish(); + + TestFunctionCount(0); +} + +TEST_F(FuncLinePairing, LinesNoFuncs) { + PushLine(40, 2, "line-file", 82485646); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + root_handler_.Finish(); + + TestFunctionCount(0); +} + +TEST_F(FuncLinePairing, FuncsNoLines) { + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U, + NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U); +} + +TEST_F(FuncLinePairing, GapThenFunction) { + PushLine(20, 2, "line-file-2", 174314698); + PushLine(10, 2, "line-file-1", 263008005); + + StartCU(); + DefineFunction(&root_handler_, "function1", 10, 2, NULL); + DefineFunction(&root_handler_, "function2", 20, 2, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 10, 2); + TestLineCount(0, 1); + TestLine(0, 0, 10, 2, "line-file-1", 263008005); + TestFunction(1, "function2", 20, 2); + TestLineCount(1, 1); + TestLine(1, 0, 20, 2, "line-file-2", 174314698); +} + +// If GCC emits padding after one function to align the start of +// the next, then it will attribute the padding instructions to +// the last source line of function (to reduce the size of the +// line number info), but omit it from the DW_AT_{low,high}_pc +// range given in .debug_info (since it costs nothing to be +// precise there). If we did use at least some of the line +// we're about to skip, then assume this is what happened, and +// don't warn. +TEST_F(FuncLinePairing, GCCAlignmentStretch) { + PushLine(10, 10, "line-file", 63351048); + PushLine(20, 10, "line-file", 61661044); + + StartCU(); + DefineFunction(&root_handler_, "function1", 10, 5, NULL); + // five-byte gap between functions, covered by line 63351048. + // This should not elicit a warning. + DefineFunction(&root_handler_, "function2", 20, 10, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 10, 5); + TestLineCount(0, 1); + TestLine(0, 0, 10, 5, "line-file", 63351048); + TestFunction(1, "function2", 20, 10); + TestLineCount(1, 1); + TestLine(1, 0, 20, 10, "line-file", 61661044); +} + +// Unfortunately, neither the DWARF parser's handler interface nor the +// DIEHandler interface is capable of expressing a function that abuts +// the end of the address space: the high_pc value looks like zero. + +TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { + PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL); + DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6); + TestLineCount(0, 1); + TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048); + TestFunction(1, "function2", 0xfffffffffffffffaULL, 5); + TestLineCount(1, 1); + TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048); +} + +// A function with more than one uncovered area should only be warned +// about once. +TEST_F(FuncLinePairing, WarnOnceFunc) { + PushLine(20, 1, "line-file-2", 262951329); + PushLine(11, 1, "line-file-1", 219964021); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function", 10, 11, NULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "function", 10, 11); + TestLineCount(0, 2); + TestLine(0, 0, 11, 1, "line-file-1", 219964021); + TestLine(0, 1, 20, 1, "line-file-2", 262951329); +} + +// A line with more than one uncovered area should only be warned +// about once. +TEST_F(FuncLinePairing, WarnOnceLine) { + PushLine(10, 20, "filename1", 118581871); + EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); + + StartCU(); + DefineFunction(&root_handler_, "function1", 11, 1, NULL); + DefineFunction(&root_handler_, "function2", 13, 1, NULL); + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "function1", 11, 1); + TestLineCount(0, 1); + TestLine(0, 0, 11, 1, "filename1", 118581871); + TestFunction(1, "function2", 13, 1); + TestLineCount(1, 1); + TestLine(1, 0, 13, 1, "filename1", 118581871); +} + +class CXXQualifiedNames: public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, + Values(dwarf2reader::DW_TAG_class_type, + dwarf2reader::DW_TAG_structure_type, + dwarf2reader::DW_TAG_union_type, + dwarf2reader::DW_TAG_namespace)); + +TEST_P(CXXQualifiedNames, TwoFunctions) { + DwarfTag tag = GetParam(); + + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "filename1", 69819327); + PushLine(20, 1, "filename2", 95115701); + + StartCU(); + DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, + "Enclosure"); + EXPECT_TRUE(enclosure_handler != NULL); + DefineFunction(enclosure_handler, "func_B", 10, 1, NULL); + DefineFunction(enclosure_handler, "func_C", 20, 1, NULL); + enclosure_handler->Finish(); + delete enclosure_handler; + root_handler_.Finish(); + + TestFunctionCount(2); + TestFunction(0, "Enclosure::func_B", 10, 1); + TestFunction(1, "Enclosure::func_C", 20, 1); +} + +TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { + DwarfTag tag = GetParam(); + + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "line-file", 69819327); + + StartCU(); + DIEHandler *namespace_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "Namespace"); + EXPECT_TRUE(namespace_handler != NULL); + DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, + "Enclosure"); + EXPECT_TRUE(enclosure_handler != NULL); + DefineFunction(enclosure_handler, "function", 10, 1, NULL); + enclosure_handler->Finish(); + delete enclosure_handler; + namespace_handler->Finish(); + delete namespace_handler; + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "Namespace::Enclosure::function", 10, 1); +} + +TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + PushLine(10, 1, "filename1", 69819327); + + StartCU(); + DIEHandler *namespace_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "namespace_A"); + EXPECT_TRUE(namespace_handler != NULL); + DIEHandler *struct_handler + = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, + "struct_B"); + EXPECT_TRUE(struct_handler != NULL); + DIEHandler *class_handler + = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, + "class_C"); + DefineFunction(class_handler, "function_D", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + struct_handler->Finish(); + delete struct_handler; + namespace_handler->Finish(); + delete namespace_handler; + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1); +} + +struct LanguageAndQualifiedName { + dwarf2reader::DwarfLanguage language; + const char *name; +}; + +const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { + { dwarf2reader::DW_LANG_none, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, + { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, + { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, + { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, + { dwarf2reader::DW_LANG_Mips_Assembler, NULL } +}; + +class QualifiedForLanguage + : public CUFixtureBase, + public TestWithParam { }; + +INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, + ValuesIn(LanguageAndQualifiedNameCases)); + +TEST_P(QualifiedForLanguage, MemberFunction) { + const LanguageAndQualifiedName ¶m = GetParam(); + + PushLine(10, 1, "line-file", 212966758); + SetLanguage(param.language); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + DefineFunction(class_handler, "function_B", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + root_handler_.Finish(); + + if (param.name) { + TestFunctionCount(1); + TestFunction(0, param.name, 10, 1); + } else { + TestFunctionCount(0); + } +} + +TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { + const LanguageAndQualifiedName ¶m = GetParam(); + + PushLine(10, 1, "line-file", 212966758); + SetLanguage(param.language); + SetLanguageSigned(true); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + DefineFunction(class_handler, "function_B", 10, 1, NULL); + class_handler->Finish(); + delete class_handler; + root_handler_.Finish(); + + if (param.name) { + TestFunctionCount(1); + TestFunction(0, param.name, 10, 1); + } else { + TestFunctionCount(0); + } +} + +class Specifications: public CUFixtureBase, public Test { }; + +TEST_F(Specifications, Function) { + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "declaration-name", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MangledName) { + // Language defaults to C++, so no need to set it here. + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", + "_ZN1C1fEi"); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "C::f(int)", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MangledNameSwift) { + // Swift mangled names should pass through untouched. + SetLanguage(dwarf2reader::DW_LANG_Swift); + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + StartCU(); + const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si"; + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", + kName); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, kName, + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MangledNameRust) { + SetLanguage(dwarf2reader::DW_LANG_Rust); + PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); + + StartCU(); + const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE"; + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", + kName); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xcd3c51b946fb1eeeLL, "", + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, +#ifndef HAVE_RUST_DEMANGLE + // Rust mangled names should pass through untouched if not + // using rust-demangle. + kName, +#else + // If rust-demangle is available this should be properly + // demangled. + "rustc_demangle::demangle", +#endif + 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); +} + +TEST_F(Specifications, MemberFunction) { + PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); + + StartCU(); + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); + DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + class_handler->Finish(); + delete class_handler; + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x7d83028c431406e8ULL, "", + 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class_A::declaration-name", + 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); +} + +// This case should gather the name from both the definition and the +// declaration's parent. +TEST_F(Specifications, FunctionDeclarationParent) { + PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922); + + StartCU(); + { + DIEHandler *class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "class_A"); + ASSERT_TRUE(class_handler != NULL); + DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + class_handler->Finish(); + delete class_handler; + } + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x0e0e877c8404544aULL, "definition-name", + 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class_A::definition-name", + 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); +} + +// Named scopes should also gather enclosing name components from +// their declarations. +TEST_F(Specifications, NamedScopeDeclarationParent) { + PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604); + + StartCU(); + { + DIEHandler *space_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "space_A"); + ASSERT_TRUE(space_handler != NULL); + DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, + dwarf2reader::DW_TAG_class_type, "class-declaration-name", + ""); + space_handler->Finish(); + delete space_handler; + } + + { + DIEHandler *class_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0x419bb1d12f9a73a2ULL, "class-definition-name"); + ASSERT_TRUE(class_handler != NULL); + DefineFunction(class_handler, "function", + 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL); + class_handler->Finish(); + delete class_handler; + } + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "space_A::class-definition-name::function", + 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); +} + +// This test recreates bug 364. +TEST_F(Specifications, InlineFunction) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, + dwarf2reader::DW_TAG_subprogram, "inline-name", ""); + AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); + DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "inline-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +// An inline function in a namespace should correctly derive its +// name from its abstract origin, and not just the namespace name. +TEST_F(Specifications, InlineFunctionInNamespace) { + PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); + + StartCU(); + DIEHandler* space_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "Namespace"); + ASSERT_TRUE(space_handler != NULL); + AbstractInstanceDIE(space_handler, 0x1e8dac5d507ed7abULL, + dwarf2reader::DW_INL_inlined, 0LL, "func-name"); + DefineInlineInstanceDIE(space_handler, "", 0x1e8dac5d507ed7abULL, + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); + space_handler->Finish(); + delete space_handler; + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "Namespace::func-name", + 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); +} + +// Check name construction for a long chain containing each combination of: +// - struct, union, class, namespace +// - direct and definition +TEST_F(Specifications, LongChain) { + PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); + SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); + + StartCU(); + // The structure we're building here is: + // space_A full definition + // space_B declaration + // space_B definition + // struct_C full definition + // struct_D declaration + // struct_D definition + // union_E full definition + // union_F declaration + // union_F definition + // class_G full definition + // class_H declaration + // class_H definition + // func_I declaration + // func_I definition + // + // So: + // - space_A, struct_C, union_E, and class_G don't use specifications; + // - space_B, struct_D, union_F, and class_H do. + // - func_I uses a specification. + // + // The full name for func_I is thus: + // + // space_A::space_B::struct_C::struct_D::union_E::union_F:: + // class_G::class_H::func_I + { + DIEHandler *space_A_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + "space_A"); + DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, + dwarf2reader::DW_TAG_namespace, "space_B", ""); + space_A_handler->Finish(); + delete space_A_handler; + } + + { + DIEHandler *space_B_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, + 0x2e111126496596e2ULL); + DIEHandler *struct_C_handler + = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, + "struct_C"); + DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, + dwarf2reader::DW_TAG_structure_type, "struct_D", ""); + struct_C_handler->Finish(); + delete struct_C_handler; + space_B_handler->Finish(); + delete space_B_handler; + } + + { + DIEHandler *struct_D_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, + 0x20cd423bf2a25a4cULL); + DIEHandler *union_E_handler + = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, + "union_E"); + DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, + dwarf2reader::DW_TAG_union_type, "union_F", ""); + union_E_handler->Finish(); + delete union_E_handler; + struct_D_handler->Finish(); + delete struct_D_handler; + } + + { + DIEHandler *union_F_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, + 0xe25c84805aa58c32ULL); + DIEHandler *class_G_handler + = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, + "class_G"); + DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, + dwarf2reader::DW_TAG_class_type, "class_H", ""); + class_G_handler->Finish(); + delete class_G_handler; + union_F_handler->Finish(); + delete union_F_handler; + } + + { + DIEHandler *class_H_handler + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0xb70d960dcc173b6eULL); + DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, + dwarf2reader::DW_TAG_subprogram, "func_I", ""); + class_H_handler->Finish(); + delete class_H_handler; + } + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x27ff829e3bf69f37ULL, "", + 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F" + "::class_G::class_H::func_I", + 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); +} + +TEST_F(Specifications, InterCU) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + MockLineToModuleHandler lr; + EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + // First CU. Declares class_A. + { + DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root1_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ProcessStrangeAttributes(&root1_handler); + ASSERT_TRUE(root1_handler.EndAttributes()); + DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, + dwarf2reader::DW_TAG_class_type, "class_A", ""); + root1_handler.Finish(); + } + + // Second CU. Defines class_A, declares member_func_B. + { + DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root2_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root2_handler.EndAttributes()); + DIEHandler *class_A_handler + = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + 0xb8fbfdd5f0b26fceULL); + DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, + dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + class_A_handler->Finish(); + delete class_A_handler; + root2_handler.Finish(); + } + + // Third CU. Defines member_func_B. + { + DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root3_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root3_handler.EndAttributes()); + DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + 0xb01fef8b380bd1a2ULL, "", + 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); + root3_handler.Finish(); + } + + vector functions; + m.GetFunctions(&functions, functions.end()); + EXPECT_EQ(1U, functions.size()); + EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); +} + +TEST_F(Specifications, UnhandledInterCU) { + Module m("module-name", "module-os", "module-arch", "module-id"); + DwarfCUToModule::FileContext fc("dwarf-filename", &m, false); + EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); + MockLineToModuleHandler lr; + EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); + + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + // First CU. Declares class_A. + { + DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root1_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ProcessStrangeAttributes(&root1_handler); + ASSERT_TRUE(root1_handler.EndAttributes()); + DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, + dwarf2reader::DW_TAG_class_type, "class_A", ""); + root1_handler.Finish(); + } + + // Second CU. Defines class_A, declares member_func_B. + { + DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root2_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root2_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + DIEHandler *class_A_handler + = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, + 0xb8fbfdd5f0b26fceULL); + DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, + dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); + class_A_handler->Finish(); + delete class_A_handler; + root2_handler.Finish(); + } + + // Third CU. Defines member_func_B. + { + DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); + ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); + ASSERT_TRUE(root3_handler.StartRootDIE(1, + dwarf2reader::DW_TAG_compile_unit)); + ASSERT_TRUE(root3_handler.EndAttributes()); + EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); + EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1); + DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, + 0xb01fef8b380bd1a2ULL, "", + 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); + root3_handler.Finish(); + } +} + +TEST_F(Specifications, BadOffset) { + PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); + EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) + .WillOnce(Return()); + + StartCU(); + DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, + dwarf2reader::DW_TAG_subprogram, "", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x2be953efa6f9a996ULL, "function", + 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); + root_handler_.Finish(); +} + +TEST_F(Specifications, FunctionDefinitionHasOwnName) { + PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403); + + StartCU(); + DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, + dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0xc34ff4786cae78bdULL, "definition-name", + 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "definition-name", + 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); +} + +TEST_F(Specifications, ClassDefinitionHasOwnName) { + PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241); + + StartCU(); + DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, + dwarf2reader::DW_TAG_class_type, "class-declaration-name", ""); + + dwarf2reader::DIEHandler *class_definition + = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + 0xd0fe467ec2f1a58cULL, "class-definition-name"); + ASSERT_TRUE(class_definition); + DeclarationDIE(class_definition, 0x6d028229c15623dbULL, + dwarf2reader::DW_TAG_subprogram, + "function-declaration-name", ""); + class_definition->Finish(); + delete class_definition; + + DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, + 0x6d028229c15623dbULL, "function-definition-name", + 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); + + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "class-definition-name::function-definition-name", + 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); +} + +// DIEs that cite a specification should prefer the specification's +// parents over their own when choosing qualified names. In this test, +// we take the name from our definition but the enclosing scope name +// from our declaration. I don't see why they'd ever be different, but +// we want to verify what DwarfCUToModule is looking at. +TEST_F(Specifications, PreferSpecificationParents) { + PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694); + + StartCU(); + { + dwarf2reader::DIEHandler *declaration_class_handler = + StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "declaration-class"); + DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, + dwarf2reader::DW_TAG_subprogram, "function-declaration", + ""); + declaration_class_handler->Finish(); + delete declaration_class_handler; + } + { + dwarf2reader::DIEHandler *definition_class_handler + = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, + "definition-class"); + DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, + 0x9ddb35517455ef7aULL, "function-definition", + 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); + definition_class_handler->Finish(); + delete definition_class_handler; + } + root_handler_.Finish(); + + TestFunctionCount(1); + TestFunction(0, "declaration-class::function-definition", + 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); +} + +class CUErrors: public CUFixtureBase, public Test { }; + +TEST_F(CUErrors, BadStmtList) { + EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, + 0x2d7d19546cf6590cULL, 3)); + ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, + dwarf2reader::DW_TAG_compile_unit)); + root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, + dwarf2reader::DW_FORM_strp, + "compilation-unit-name"); + root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, + dwarf2reader::DW_FORM_ref4, + dummy_line_size_ + 10); + root_handler_.EndAttributes(); + root_handler_.Finish(); +} + +TEST_F(CUErrors, NoLineSection) { + EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); + PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); + // Delete the entry for .debug_line added by the fixture class's constructor. + file_context_.ClearSectionMapForTest(); + + StartCU(); + root_handler_.Finish(); +} + +TEST_F(CUErrors, BadDwarfVersion1) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_FALSE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 1)); +} + +TEST_F(CUErrors, GoodDwarfVersion2) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 2)); +} + +TEST_F(CUErrors, GoodDwarfVersion3) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 3)); +} + +TEST_F(CUErrors, BadCURootDIETag) { + // Kludge: satisfy reporter_'s expectation. + reporter_.SetCUName("compilation-unit-name"); + + ASSERT_TRUE(root_handler_ + .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, + 0xc9de224ccb99ac3eULL, 3)); + + ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, + dwarf2reader::DW_TAG_subprogram)); +} + +// Tests for DwarfCUToModule::Reporter. These just produce (or fail to +// produce) output, so their results need to be checked by hand. +struct Reporter: public Test { + Reporter() + : reporter("filename", 0x123456789abcdef0ULL), + function("function name", 0x19c45c30770c1eb0ULL), + file("source file name") { + reporter.SetCUName("compilation-unit-name"); + + Module::Range range(0x19c45c30770c1eb0ULL, 0x89808a5bdfa0a6a3ULL); + function.ranges.push_back(range); + function.parameter_size = 0x6a329f18683dcd51ULL; + + line.address = 0x3606ac6267aebeccULL; + line.size = 0x5de482229f32556aULL; + line.file = &file; + line.number = 93400201; + } + + DwarfCUToModule::WarningReporter reporter; + Module::Function function; + Module::File file; + Module::Line line; +}; + +TEST_F(Reporter, UnknownSpecification) { + reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); +} + +TEST_F(Reporter, UnknownAbstractOrigin) { + reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); +} + +TEST_F(Reporter, MissingSection) { + reporter.MissingSection("section name"); +} + +TEST_F(Reporter, BadLineInfoOffset) { + reporter.BadLineInfoOffset(0x123456789abcdef1ULL); +} + +TEST_F(Reporter, UncoveredFunctionDisabled) { + reporter.UncoveredFunction(function); + EXPECT_FALSE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredFunctionEnabled) { + reporter.set_uncovered_warnings_enabled(true); + reporter.UncoveredFunction(function); + EXPECT_TRUE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredLineDisabled) { + reporter.UncoveredLine(line); + EXPECT_FALSE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UncoveredLineEnabled) { + reporter.set_uncovered_warnings_enabled(true); + reporter.UncoveredLine(line); + EXPECT_TRUE(reporter.uncovered_warnings_enabled()); +} + +TEST_F(Reporter, UnnamedFunction) { + reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL); +} + +// Would be nice to also test: +// - overlapping lines, functions diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc new file mode 100644 index 0000000000..258b0b603f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. +// See dwarf_line_to_module.h for details. + +#include + +#include + +#include "common/dwarf_line_to_module.h" +#include "common/using_std_string.h" + +// Trying to support Windows paths in a reasonable way adds a lot of +// variations to test; it would be better to just put off dealing with +// it until we actually have to deal with DWARF on Windows. + +// Return true if PATH is an absolute path, false if it is relative. +static bool PathIsAbsolute(const string &path) { + return (path.size() >= 1 && path[0] == '/'); +} + +static bool HasTrailingSlash(const string &path) { + return (path.size() >= 1 && path[path.size() - 1] == '/'); +} + +// If PATH is an absolute path, return PATH. If PATH is a relative path, +// treat it as relative to BASE and return the combined path. +static string ExpandPath(const string &path, + const string &base) { + if (PathIsAbsolute(path) || base.empty()) + return path; + return base + (HasTrailingSlash(base) ? "" : "/") + path; +} + +namespace google_breakpad { + +void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) { + // Directory number zero is reserved to mean the compilation + // directory. Silently ignore attempts to redefine it. + if (dir_num != 0) + directories_[dir_num] = ExpandPath(name, compilation_dir_); +} + +void DwarfLineToModule::DefineFile(const string &name, int32 file_num, + uint32 dir_num, uint64 mod_time, + uint64 length) { + if (file_num == -1) + file_num = ++highest_file_number_; + else if (file_num > highest_file_number_) + highest_file_number_ = file_num; + + string dir_name; + if (dir_num == 0) { + // Directory number zero is the compilation directory, and is stored as + // an attribute on the compilation unit, rather than in the program table. + dir_name = compilation_dir_; + } else { + DirectoryTable::const_iterator directory_it = directories_.find(dir_num); + if (directory_it != directories_.end()) { + dir_name = directory_it->second; + } else { + if (!warned_bad_directory_number_) { + fprintf(stderr, "warning: DWARF line number data refers to undefined" + " directory numbers\n"); + warned_bad_directory_number_ = true; + } + } + } + + string full_name = ExpandPath(name, dir_name); + + // Find a Module::File object of the given name, and add it to the + // file table. + files_[file_num] = module_->FindFile(full_name); +} + +void DwarfLineToModule::AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, + uint32 column_num) { + if (length == 0) + return; + + // Clip lines not to extend beyond the end of the address space. + if (address + length < address) + length = -address; + + // Should we omit this line? (See the comments for omitted_line_end_.) + if (address == 0 || address == omitted_line_end_) { + omitted_line_end_ = address + length; + return; + } else { + omitted_line_end_ = 0; + } + + // Find the source file being referred to. + Module::File *file = files_[file_num]; + if (!file) { + if (!warned_bad_file_number_) { + fprintf(stderr, "warning: DWARF line number data refers to " + "undefined file numbers\n"); + warned_bad_file_number_ = true; + } + return; + } + Module::Line line; + line.address = address; + // We set the size when we get the next line or the EndSequence call. + line.size = length; + line.file = file; + line.number = line_num; + lines_->push_back(line); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h new file mode 100644 index 0000000000..1fdd4cb716 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h @@ -0,0 +1,188 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// The DwarfLineToModule class accepts line number information from a +// DWARF parser and adds it to a google_breakpad::Module. The Module +// can write that data out as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H +#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H + +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A class for producing a vector of google_breakpad::Module::Line +// instances from parsed DWARF line number data. +// +// An instance of this class can be provided as a handler to a +// dwarf2reader::LineInfo DWARF line number information parser. The +// handler accepts source location information from the parser and +// uses it to produce a vector of google_breakpad::Module::Line +// objects, referring to google_breakpad::Module::File objects added +// to a particular google_breakpad::Module. +// +// GNU toolchain omitted sections support: +// ====================================== +// +// Given the right options, the GNU toolchain will omit unreferenced +// functions from the final executable. Unfortunately, when it does so, it +// does not remove the associated portions of the DWARF line number +// program; instead, it gives the DW_LNE_set_address instructions referring +// to the now-deleted code addresses of zero. Given this input, the DWARF +// line parser will call AddLine with a series of lines starting at address +// zero. For example, here is the output from 'readelf -wl' for a program +// with four functions, the first three of which have been omitted: +// +// Line Number Statements: +// Extended opcode 2: set Address to 0x0 +// Advance Line by 14 to 15 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 +// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 +// Advance PC by 2 to 0xd +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x0 +// Advance Line by 14 to 15 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 +// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 +// Advance PC by 2 to 0xd +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x0 +// Advance Line by 19 to 20 +// Copy +// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 21 +// Special opcode 76: advance Address by 5 to 0x8 and Line by 1 to 22 +// Advance PC by 2 to 0xa +// Extended opcode 1: End of Sequence +// +// Extended opcode 2: set Address to 0x80483a4 +// Advance Line by 23 to 24 +// Copy +// Special opcode 202: advance Address by 14 to 0x80483b2 and Line by 1 to 25 +// Special opcode 76: advance Address by 5 to 0x80483b7 and Line by 1 to 26 +// Advance PC by 6 to 0x80483bd +// Extended opcode 1: End of Sequence +// +// Instead of collecting runs of lines describing code that is not there, +// we try to recognize and drop them. Since the linker doesn't explicitly +// distinguish references to dropped sections from genuine references to +// code at address zero, we must use a heuristic. We have chosen: +// +// - If a line starts at address zero, omit it. (On the platforms +// breakpad targets, it is extremely unlikely that there will be code +// at address zero.) +// +// - If a line starts immediately after an omitted line, omit it too. +class DwarfLineToModule: public dwarf2reader::LineInfoHandler { + public: + // As the DWARF line info parser passes us line records, add source + // files to MODULE, and add all lines to the end of LINES. LINES + // need not be empty. If the parser hands us a zero-length line, we + // omit it. If the parser hands us a line that extends beyond the + // end of the address space, we clip it. It's up to our client to + // sort out which lines belong to which functions; we don't add them + // to any particular function in MODULE ourselves. + DwarfLineToModule(Module *module, const string& compilation_dir, + vector *lines) + : module_(module), + compilation_dir_(compilation_dir), + lines_(lines), + highest_file_number_(-1), + omitted_line_end_(0), + warned_bad_file_number_(false), + warned_bad_directory_number_(false) { } + + ~DwarfLineToModule() { } + + void DefineDir(const string &name, uint32 dir_num); + void DefineFile(const string &name, int32 file_num, + uint32 dir_num, uint64 mod_time, + uint64 length); + void AddLine(uint64 address, uint64 length, + uint32 file_num, uint32 line_num, uint32 column_num); + + private: + + typedef std::map DirectoryTable; + typedef std::map FileTable; + + // The module we're contributing debugging info to. Owned by our + // client. + Module *module_; + + // The compilation directory for the current compilation unit whose + // lines are being accumulated. + string compilation_dir_; + + // The vector of lines we're accumulating. Owned by our client. + // + // In a Module, as in a breakpad symbol file, lines belong to + // specific functions, but DWARF simply assigns lines to addresses; + // one must infer the line/function relationship using the + // functions' beginning and ending addresses. So we can't add these + // to the appropriate function from module_ until we've read the + // function info as well. Instead, we accumulate lines here, and let + // whoever constructed this sort it all out. + vector *lines_; + + // A table mapping directory numbers to paths. + DirectoryTable directories_; + + // A table mapping file numbers to Module::File pointers. + FileTable files_; + + // The highest file number we've seen so far, or -1 if we've seen + // none. Used for dynamically defined file numbers. + int32 highest_file_number_; + + // This is the ending address of the last line we omitted, or zero if we + // didn't omit the previous line. It is zero before we have received any + // AddLine calls. + uint64 omitted_line_end_; + + // True if we've warned about: + bool warned_bad_file_number_; // bad file numbers + bool warned_bad_directory_number_; // bad directory numbers +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_LINE_TO_MODULE_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc new file mode 100644 index 0000000000..7c0fcfd35a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc @@ -0,0 +1,391 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. + +#include + +#include "breakpad_googletest_includes.h" +#include "common/dwarf_line_to_module.h" + +using std::vector; + +using google_breakpad::DwarfLineToModule; +using google_breakpad::Module; +using google_breakpad::Module; + +TEST(SimpleModule, One) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); + h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, + 0x4c090cbf, 0x1cf9fe0d); + + vector files; + m.GetFiles(&files); + EXPECT_EQ(1U, files.size()); + EXPECT_STREQ("/file1", files[0]->name.c_str()); + + EXPECT_EQ(1U, lines.size()); + EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address); + EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size); + EXPECT_TRUE(lines[0].file == files[0]); + EXPECT_EQ(0x4c090cbf, lines[0].number); +} + +TEST(SimpleModule, Many) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 0x838299ab); + h.DefineDir("directory2", 0xf85de023); + h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0); + h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0); + h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0); + h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0); + h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a, + 0x15b0f0a9U, 0x3ff5abd6U); + h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4, + 0x4d259ce9U, 0x41c5ee32U); + h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56, + 0x1ee9fa4fU, 0xbf70e46aU); + h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c, + 0x77fc280eU, 0x2c4a728cU); + h.DefineFile("file3", -1, 0, 0, 0); + h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5, + 0x75047044U, 0xb6a0016cU); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(5U, files.size()); + EXPECT_STREQ("/directory1/file1", files[0]->name.c_str()); + EXPECT_STREQ("/directory1/file2", files[1]->name.c_str()); + EXPECT_STREQ("/directory2/file1", files[2]->name.c_str()); + EXPECT_STREQ("/directory2/file2", files[3]->name.c_str()); + EXPECT_STREQ("/file3", files[4]->name.c_str()); + + ASSERT_EQ(5U, lines.size()); + + EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address); + EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size); + EXPECT_TRUE(lines[0].file == files[0]); + EXPECT_EQ(0x15b0f0a9, lines[0].number); + + EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address); + EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size); + EXPECT_TRUE(lines[1].file == files[2]); + EXPECT_EQ(0x4d259ce9, lines[1].number); + + EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address); + EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size); + EXPECT_TRUE(lines[2].file == files[1]); + EXPECT_EQ(0x1ee9fa4f, lines[2].number); + + EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address); + EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size); + EXPECT_TRUE(lines[3].file == files[3]); + EXPECT_EQ(0x77fc280e, lines[3].number); + + EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address); + EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size); + EXPECT_TRUE(lines[4].file == files[4]); + EXPECT_EQ(0x75047044, lines[4].number); +} + +TEST(Filenames, Absolute) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("/absolute", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(1U, files.size()); + EXPECT_STREQ("/absolute", files[0]->name.c_str()); + ASSERT_EQ(1U, lines.size()); + EXPECT_TRUE(lines[0].file == files[0]); +} + +TEST(Filenames, Relative) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("relative", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + vector files; + m.GetFiles(&files); + ASSERT_EQ(1U, files.size()); + EXPECT_STREQ("/directory1/relative", files[0]->name.c_str()); + ASSERT_EQ(1U, lines.size()); + EXPECT_TRUE(lines[0].file == files[0]); +} + +TEST(Filenames, StrangeFile) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/directory1/", lines[0].file->name.c_str()); +} + +TEST(Filenames, StrangeDirectory) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("", 1); + h.DefineFile("file1", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/file1", lines[0].file->name.c_str()); +} + +TEST(Filenames, StrangeDirectoryAndFile) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("", 1); + h.DefineFile("", 1, 1, 0, 0); + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/", lines[0].file->name.c_str()); +} + +// We should use the compilation directory when encountering a file for +// directory number zero. +TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("Dir", 1); + h.DefineFile("File", 1, 0, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("src/build/File", lines[0].file->name.c_str()); +} + +// We should treat non-absolute directories as relative to the compilation +// directory. +TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("Dir", 1); + h.DefineFile("File", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("src/build/Dir/File", lines[0].file->name.c_str()); +} + +// We should treat absolute directories as absolute, and not relative to +// the compilation dir. +TEST(Filenames, IncludeDirectoryAbsolute) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "src/build", &lines); + + h.DefineDir("/Dir", 1); + h.DefineFile("File", 1, 1, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/Dir/File", lines[0].file->name.c_str()); +} + +// We should silently ignore attempts to define directory number zero, +// since that is always the compilation directory. +TEST(ModuleErrors, DirectoryZero) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory0", 0); // should be ignored + h.DefineFile("relative", 1, 0, 0, 0); + + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("/relative", lines[0].file->name.c_str()); +} + +// We should refuse to add lines with bogus file numbers. We should +// produce only one warning, however. +TEST(ModuleErrors, BadFileNumber) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("relative", 1, 0, 0, 0); + h.AddLine(1, 1, 2, 0, 0); // bad file number + h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning) + + EXPECT_EQ(0U, lines.size()); +} + +// We should treat files with bogus directory numbers as relative to +// the compilation unit. +TEST(ModuleErrors, BadDirectoryNumber) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineDir("directory1", 1); + h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number + h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning) + h.AddLine(1, 1, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str()); +} + +// We promise not to report empty lines. +TEST(ModuleErrors, EmptyLine) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(1, 0, 1, 0, 0); + + ASSERT_EQ(0U, lines.size()); +} + +// We are supposed to clip lines that extend beyond the end of the +// address space. +TEST(ModuleErrors, BigLine) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(1U, lines[0].size); +} + +// The 'Omitted' tests verify that we correctly omit line information +// for code in sections that the linker has dropped. See "GNU +// toolchain omitted sections support" at the top of the +// DwarfLineToModule class. + +TEST(Omitted, DroppedThenGood) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0, 10, 1, 83816211, 0); // should be omitted + h.AddLine(20, 10, 1, 13059195, 0); // should be recorded + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(13059195, lines[0].number); +} + +TEST(Omitted, GoodThenDropped) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded + h.AddLine(0, 10, 1, 44793413, 0); // should be omitted + + ASSERT_EQ(1U, lines.size()); + EXPECT_EQ(41454594, lines[0].number); +} + +TEST(Omitted, Mix1) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded + h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded + h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted + h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted + h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted + h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded + h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded + + ASSERT_EQ(4U, lines.size()); + EXPECT_EQ(58932642, lines[0].number); + EXPECT_EQ(39847385, lines[1].number); + EXPECT_EQ(91806582, lines[2].number); + EXPECT_EQ(56169221, lines[3].number); +} + +TEST(Omitted, Mix2) { + Module m("name", "os", "architecture", "id"); + vector lines; + DwarfLineToModule h(&m, "/", &lines); + + h.DefineFile("filename1", 1, 0, 0, 0); + h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted + h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted + h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted + h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded + h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded + h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted + h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted + h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted + + ASSERT_EQ(2U, lines.size()); + EXPECT_EQ(67355743, lines[0].number); + EXPECT_EQ(23365776, lines[1].number); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.cc new file mode 100644 index 0000000000..8733df3611 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2018 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. + +// Original author: Gabriele Svelto +// + +// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class. +// See dwarf_range_list_handler.h for details. + +#include + +#include "common/dwarf_range_list_handler.h" + +namespace google_breakpad { + +void DwarfRangeListHandler::AddRange(uint64 begin, uint64 end) { + Module::Range r(begin + base_address_, end - begin); + + ranges_->push_back(r); +} + +void DwarfRangeListHandler::SetBaseAddress(uint64 base_address) { + base_address_ = base_address; +} + +void DwarfRangeListHandler::Finish() { + std::sort(ranges_->begin(), ranges_->end(), + [](const Module::Range &a, const Module::Range &b) { + return a.address < b.address; + } + ); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.h new file mode 100644 index 0000000000..bd0996863d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/dwarf_range_list_handler.h @@ -0,0 +1,79 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2018 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. + +// Original author: Gabriele Svelto +// + +// The DwarfRangeListHandler class accepts rangelist data from a DWARF parser +// and adds it to a google_breakpad::Function or other objects supporting +// ranges. + +#ifndef COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H +#define COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H + +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" + +namespace google_breakpad { + +// A class for producing a vector of google_breakpad::Module::Range +// instances from a parsed DWARF range list. + +class DwarfRangeListHandler: public dwarf2reader::RangeListHandler { + public: + DwarfRangeListHandler(uint64 base_address, vector *ranges) + : base_address_(base_address), ranges_(ranges) { } + + ~DwarfRangeListHandler() { } + + // Add a range to the list + void AddRange(uint64 begin, uint64 end); + + // Record the new base address and use it for the following entries + void SetBaseAddress(uint64 base_address); + + // Sort the ranges so that they are in ascending order of starting address + void Finish(); + + private: + // The current PC to add to every entry, this can be overridden by a special + // list entry + uint64 base_address_; + + // The list of ranges to be populated + vector *ranges_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/language.cc b/toolkit/crashreporter/google-breakpad/src/common/language.cc new file mode 100644 index 0000000000..978fb85567 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/language.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// language.cc: Subclasses and singletons for google_breakpad::Language. +// See language.h for details. + +#include "common/language.h" + +#include + +#if !defined(__ANDROID__) +#include +#endif + +#if defined(HAVE_RUST_DEMANGLE) +#include +#endif + +#include + +namespace { + +string MakeQualifiedNameWithSeparator(const string& parent_name, + const char* separator, + const string& name) { + if (parent_name.empty()) { + return name; + } + + return parent_name + separator + name; +} + +} // namespace + +namespace google_breakpad { + +// C++ language-specific operations. +class CPPLanguage: public Language { + public: + CPPLanguage() {} + + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return MakeQualifiedNameWithSeparator(parent_name, "::", name); + } + + virtual DemangleResult DemangleName(const string& mangled, + string* demangled) const { +#if defined(__ANDROID__) + // Android NDK doesn't provide abi::__cxa_demangle. + demangled->clear(); + return kDontDemangle; +#else + int status; + char* demangled_c = + abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); + + DemangleResult result; + if (status == 0) { + result = kDemangleSuccess; + demangled->assign(demangled_c); + } else { + result = kDemangleFailure; + demangled->clear(); + } + + if (demangled_c) { + free(reinterpret_cast(demangled_c)); + } + + return result; +#endif + } +}; + +CPPLanguage CPPLanguageSingleton; + +// Java language-specific operations. +class JavaLanguage: public Language { + public: + JavaLanguage() {} + + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return MakeQualifiedNameWithSeparator(parent_name, ".", name); + } +}; + +JavaLanguage JavaLanguageSingleton; + +// Swift language-specific operations. +class SwiftLanguage: public Language { + public: + SwiftLanguage() {} + + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return MakeQualifiedNameWithSeparator(parent_name, ".", name); + } + + virtual DemangleResult DemangleName(const string& mangled, + string* demangled) const { + // There is no programmatic interface to a Swift demangler. Pass through the + // mangled form because it encodes more information than the qualified name + // that would have been built by MakeQualifiedName(). The output can be + // post-processed by xcrun swift-demangle to transform mangled Swift names + // into something more readable. + demangled->assign(mangled); + return kDemangleSuccess; + } +}; + +SwiftLanguage SwiftLanguageSingleton; + +// Rust language-specific operations. +class RustLanguage: public Language { + public: + RustLanguage() {} + + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return MakeQualifiedNameWithSeparator(parent_name, ".", name); + } + + virtual DemangleResult DemangleName(const string& mangled, + string* demangled) const { + // Rust names use GCC C++ name mangling, but demangling them with + // abi_demangle doesn't produce stellar results due to them having + // another layer of encoding. + // If callers provide rustc-demangle, use that. +#if defined(HAVE_RUST_DEMANGLE) + char* rust_demangled = rust_demangle(mangled.c_str()); + if (rust_demangled == nullptr) { + return kDemangleFailure; + } + demangled->assign(rust_demangled); + free_rust_demangled_name(rust_demangled); +#else + // Otherwise, pass through the mangled name so callers can demangle + // after the fact. + demangled->assign(mangled); +#endif + return kDemangleSuccess; + } +}; + +RustLanguage RustLanguageSingleton; + +// Assembler language-specific operations. +class AssemblerLanguage: public Language { + public: + AssemblerLanguage() {} + + bool HasFunctions() const { return false; } + string MakeQualifiedName(const string &parent_name, + const string &name) const { + return name; + } +}; + +AssemblerLanguage AssemblerLanguageSingleton; + +const Language * const Language::CPlusPlus = &CPPLanguageSingleton; +const Language * const Language::Java = &JavaLanguageSingleton; +const Language * const Language::Swift = &SwiftLanguageSingleton; +const Language * const Language::Rust = &RustLanguageSingleton; +const Language * const Language::Assembler = &AssemblerLanguageSingleton; + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/language.h b/toolkit/crashreporter/google-breakpad/src/common/language.h new file mode 100644 index 0000000000..2d2dbcd9e9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/language.h @@ -0,0 +1,105 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// language.h: Define google_breakpad::Language. Instances of +// subclasses of this class provide language-appropriate operations +// for the Breakpad symbol dumper. + +#ifndef COMMON_LINUX_LANGUAGE_H__ +#define COMMON_LINUX_LANGUAGE_H__ + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// An abstract base class for language-specific operations. We choose +// an instance of a subclass of this when we find the CU's language. +// This class's definitions are appropriate for CUs with no specified +// language. +class Language { + public: + // A base class destructor should be either public and virtual, + // or protected and nonvirtual. + virtual ~Language() {} + + // Return true if this language has functions to which we can assign + // line numbers. (Debugging info for assembly language, for example, + // can have source location information, but does not have functions + // recorded using DW_TAG_subprogram DIEs.) + virtual bool HasFunctions() const { return true; } + + // Construct a fully-qualified, language-appropriate form of NAME, + // given that PARENT_NAME is the name of the construct enclosing + // NAME. If PARENT_NAME is the empty string, then NAME is a + // top-level name. + // + // This API sort of assumes that a fully-qualified name is always + // some simple textual composition of the unqualified name and its + // parent's name, and that we don't need to know anything else about + // the parent or the child (say, their DIEs' tags) to do the job. + // This is true for the languages we support at the moment, and + // keeps things concrete. Perhaps a more refined operation would + // take into account the parent and child DIE types, allow languages + // to use their own data type for complex parent names, etc. But if + // C++ doesn't need all that, who would? + virtual string MakeQualifiedName (const string &parent_name, + const string &name) const = 0; + + enum DemangleResult { + // Demangling was not performed because it’s not appropriate to attempt. + kDontDemangle = -1, + + kDemangleSuccess, + kDemangleFailure, + }; + + // Wraps abi::__cxa_demangle() or similar for languages where appropriate. + virtual DemangleResult DemangleName(const string& mangled, + string* demangled) const { + demangled->clear(); + return kDontDemangle; + } + + // Instances for specific languages. + static const Language * const CPlusPlus, + * const Java, + * const Swift, + * const Rust, + * const Assembler; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_LANGUAGE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.S b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.S new file mode 100644 index 0000000000..fea0109d15 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.S @@ -0,0 +1,486 @@ +// Copyright (c) 2012, 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 minimalistic implementation of getcontext() to be used by +// Google Breakpad when getcontext() is not available in libc. + +#include "common/linux/ucontext_constants.h" + +/* int getcontext (ucontext_t *ucp) */ + +#if defined(__arm__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 0 + .fnstart +breakpad_getcontext: + + /* First, save r4-r11 */ + add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4) + stm r1, {r4-r11} + + /* r12 is a scratch register, don't save it */ + + /* Save sp and lr explicitly. */ + /* - sp can't be stored with stmia in Thumb-2 */ + /* - STM instructions that store sp and pc are deprecated in ARM */ + str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)] + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + + /* Save the caller's address in 'pc' */ + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] + + /* Save ucontext_t* pointer across next call */ + mov r4, r0 + + /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ + mov r0, #0 /* SIG_BLOCK */ + mov r1, #0 /* NULL */ + add r2, r4, #UCONTEXT_SIGMASK_OFFSET + bl sigprocmask(PLT) + + /* Intentionally do not save the FPU state here. This is because on + * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or + * ptrace(PTRACE_GETVFPREGS) to get it. + * + * Note that a real implementation of getcontext() would need to save + * this here to allow setcontext()/swapcontext() to work correctly. + */ + + /* Restore the values of r4 and lr */ + mov r0, r4 + ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)] + + /* Return 0 */ + mov r0, #0 + bx lr + + .fnend + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__aarch64__) + +#define _NSIG 64 +#define __NR_rt_sigprocmask 135 + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 4 + .cfi_startproc +breakpad_getcontext: + + /* The saved context will return to the getcontext() call point + with a return value of 0 */ + str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE] + + stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE] + stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE] + stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE] + stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE] + stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE] + stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE] + str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE] + + /* Place LR into the saved PC, this will ensure that when + switching to this saved context with setcontext() control + will pass back to the caller of getcontext(), we have + already arranged to return the appropriate return value in x0 + above. */ + str x30, [x0, MCONTEXT_PC_OFFSET] + + /* Save the current SP */ + mov x2, sp + str x2, [x0, MCONTEXT_SP_OFFSET] + + /* Initialize the pstate. */ + str xzr, [x0, MCONTEXT_PSTATE_OFFSET] + + /* Figure out where to place the first context extension + block. */ + add x2, x0, #MCONTEXT_EXTENSION_OFFSET + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Fill in the FP SIMD context. */ + add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE) + stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE) + + add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET + + mrs x4, fpsr + str w4, [x3] + + mrs x4, fpcr + str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET] + + /* Write the termination context extension header. */ + add x2, x2, #FPSIMD_CONTEXT_SIZE + + str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add x2, x0, #UCONTEXT_SIGMASK_OFFSET + mov x0, #0 /* SIG_BLOCK */ + mov x1, #0 /* NULL */ + mov x3, #(_NSIG / 8) + mov x8, #__NR_rt_sigprocmask + svc 0 + + /* Return x0 for success */ + mov x0, 0 + ret + + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__i386__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + + movl 4(%esp), %eax /* eax = uc */ + + /* Save register values */ + movl %ecx, MCONTEXT_ECX_OFFSET(%eax) + movl %edx, MCONTEXT_EDX_OFFSET(%eax) + movl %ebx, MCONTEXT_EBX_OFFSET(%eax) + movl %edi, MCONTEXT_EDI_OFFSET(%eax) + movl %esi, MCONTEXT_ESI_OFFSET(%eax) + movl %ebp, MCONTEXT_EBP_OFFSET(%eax) + + movl (%esp), %edx /* return address */ + lea 4(%esp), %ecx /* exclude return address from stack */ + mov %edx, MCONTEXT_EIP_OFFSET(%eax) + mov %ecx, MCONTEXT_ESP_OFFSET(%eax) + + xorl %ecx, %ecx + movw %fs, %cx + mov %ecx, MCONTEXT_FS_OFFSET(%eax) + + movl $0, MCONTEXT_EAX_OFFSET(%eax) + + /* Save floating point state to fpregstate, then update + * the fpregs pointer to point to it */ + leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx + fnstenv (%ecx) + fldenv (%ecx) + mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx + xorl %ecx, %ecx + push %edx /* &uc->uc_sigmask */ + push %ecx /* NULL */ + push %ecx /* SIGBLOCK == 0 on i386 */ + call sigprocmask@PLT + addl $12, %esp + + movl $0, %eax + ret + + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__mips__) + +// This implementation is inspired by implementation of getcontext in glibc. +#include +#include +#if _MIPS_SIM == _ABIO32 +#include +#endif + +// from asm-mips/asm.h +#if _MIPS_SIM == _ABIO32 +#define ALSZ 7 +#define ALMASK ~7 +#define SZREG 4 +#else // _MIPS_SIM != _ABIO32 +#define ALSZ 15 +#define ALMASK ~15 +#define SZREG 8 +#endif + +#include // for __NR_rt_sigprocmask + +#define _NSIG8 128 / 8 +#define SIG_BLOCK 1 + + + .text +LOCALS_NUM = 1 // save gp on stack +FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK + +GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG) +MCONTEXT_REG_SIZE = 8 + +#if _MIPS_SIM == _ABIO32 + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + .set noreorder + .cpload t9 + .set reorder + + move a2, sp +#define _SP a2 + + addiu sp, -FRAME_SIZE + .cprestore GP_FRAME_OFFSET + + sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, fcr31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif // __mips_hard_float + + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + addu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + li v0, __NR_rt_sigprocmask + syscall + + addiu sp, FRAME_SIZE + jr ra + +END (breakpad_getcontext) +#else + +#ifndef NESTED +/* + * NESTED - declare nested routine entry point + */ +#define NESTED(symbol, framesize, rpc) \ + .globl symbol; \ + .align 2; \ + .type symbol,@function; \ + .ent symbol,0; \ +symbol: .frame sp, framesize, rpc; +#endif + +/* + * END - mark end of function + */ +#ifndef END +# define END(function) \ + .end function; \ + .size function,.-function +#endif + +/* int getcontext (ucontext_t *ucp) */ + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x10000000, 0 + .fmask 0x00000000, 0 + + move a2, sp +#define _SP a2 + move a3, gp +#define _GP a3 + + daddiu sp, -FRAME_SIZE + .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext + + /* Store a magic flag. */ + li v1, 1 + sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */ + + sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, $31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif /* __mips_hard_float */ + +/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + daddu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + + li v0, __NR_rt_sigprocmask + syscall + + .cpreturn + daddiu sp, FRAME_SIZE + move v0, zero + jr ra + +END (breakpad_getcontext) +#endif // _MIPS_SIM == _ABIO32 + +#elif defined(__x86_64__) +/* The x64 implementation of breakpad_getcontext was derived in part + from the implementation of libunwind which requires the following + notice. */ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + .cfi_startproc + + /* Callee saved: RBX, RBP, R12-R15 */ + movq %r12, MCONTEXT_GREGS_R12(%rdi) + movq %r13, MCONTEXT_GREGS_R13(%rdi) + movq %r14, MCONTEXT_GREGS_R14(%rdi) + movq %r15, MCONTEXT_GREGS_R15(%rdi) + movq %rbp, MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, MCONTEXT_GREGS_RBX(%rdi) + + /* Save argument registers (not strictly needed, but setcontext + restores them, so don't restore garbage). */ + movq %r8, MCONTEXT_GREGS_R8(%rdi) + movq %r9, MCONTEXT_GREGS_R9(%rdi) + movq %rdi, MCONTEXT_GREGS_RDI(%rdi) + movq %rsi, MCONTEXT_GREGS_RSI(%rdi) + movq %rdx, MCONTEXT_GREGS_RDX(%rdi) + movq %rax, MCONTEXT_GREGS_RAX(%rdi) + movq %rcx, MCONTEXT_GREGS_RCX(%rdi) + + /* Save fp state (not needed, except for setcontext not + restoring garbage). */ + leaq MCONTEXT_FPREGS_MEM(%rdi),%r8 + movq %r8, MCONTEXT_FPREGS_PTR(%rdi) + fnstenv (%r8) + stmxcsr FPREGS_OFFSET_MXCSR(%r8) + + leaq 8(%rsp), %rax /* exclude this call. */ + movq %rax, MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, MCONTEXT_GREGS_RIP(%rdi) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3 + xorq %rsi, %rsi // arg2 NULL + xorq %rdi, %rdi // arg1 SIGBLOCK == 0 + call sigprocmask@PLT + + /* Always return 0 for success, even if sigprocmask failed. */ + xorl %eax, %eax + ret + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#else +#error "This file has not been ported for your CPU!" +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.h b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.h new file mode 100644 index 0000000000..1418cde621 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012, 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_COMMON_LINUX_INCLUDE_UCONTEXT_H +#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_GETCONTEXT + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Provided by src/common/linux/breakpad_getcontext.S +int breakpad_getcontext(ucontext_t* ucp); + +#define getcontext(x) breakpad_getcontext(x) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // HAVE_GETCONTEXT + +#endif // GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext_unittest.cc new file mode 100644 index 0000000000..a57bfedf9b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/breakpad_getcontext_unittest.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2012, 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. + +// asm/sigcontext.h can't be included with signal.h on glibc or +// musl, so only compare _libc_fpstate and _fpstate on Android. +#if defined(__ANDROID__) && defined(__x86_64__) +#include +#endif + +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/ucontext_constants.h" + +template +struct CompileAssertEquals { + // a compilation error here indicates left and right are not equal. + char left_too_large[right - left]; + // a compilation error here indicates left and right are not equal. + char right_too_large[left - right]; +}; + +#define COMPILE_ASSERT_EQ(left, right, tag) \ + CompileAssertEquals tag; + +TEST(AndroidUContext, GRegsOffset) { +#if defined(__arm__) + // There is no gregs[] array on ARM, so compare to the offset of + // first register fields, since they're stored in order. + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.arm_r0)); +#elif defined(__aarch64__) + // There is no gregs[] array on ARM, so compare to the offset of + // first register fields, since they're stored in order. + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.regs[0])); + ASSERT_EQ(static_cast(MCONTEXT_SP_OFFSET), + offsetof(ucontext_t,uc_mcontext.sp)); + ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), + offsetof(ucontext_t,uc_mcontext.pc)); + ASSERT_EQ(static_cast(MCONTEXT_PSTATE_OFFSET), + offsetof(ucontext_t,uc_mcontext.pstate)); + ASSERT_EQ(static_cast(MCONTEXT_EXTENSION_OFFSET), + offsetof(ucontext_t,uc_mcontext.__reserved)); +#elif defined(__i386__) + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); +#define CHECK_REG(x) \ + ASSERT_EQ(static_cast(MCONTEXT_##x##_OFFSET), \ + offsetof(ucontext_t,uc_mcontext.gregs[REG_##x])) + CHECK_REG(GS); + CHECK_REG(FS); + CHECK_REG(ES); + CHECK_REG(DS); + CHECK_REG(EDI); + CHECK_REG(ESI); + CHECK_REG(EBP); + CHECK_REG(ESP); + CHECK_REG(EBX); + CHECK_REG(EDX); + CHECK_REG(ECX); + CHECK_REG(EAX); + CHECK_REG(TRAPNO); + CHECK_REG(ERR); + CHECK_REG(EIP); + CHECK_REG(CS); + CHECK_REG(EFL); + CHECK_REG(UESP); + CHECK_REG(SS); + + ASSERT_EQ(static_cast(UCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.fpregs)); + + ASSERT_EQ(static_cast(UCONTEXT_FPREGS_MEM_OFFSET), + offsetof(ucontext_t,__fpregs_mem)); +#elif defined(__mips__) + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); + + // PC for mips is not part of gregs. + ASSERT_EQ(static_cast(MCONTEXT_PC_OFFSET), + offsetof(ucontext_t,uc_mcontext.pc)); + + ASSERT_EQ(static_cast(MCONTEXT_FPREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.fpregs)); + + ASSERT_EQ(static_cast(MCONTEXT_FPC_CSR), + offsetof(ucontext_t,uc_mcontext.fpc_csr)); +#elif defined(__x86_64__) + + COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs), + mcontext_gregs_offset); +#define CHECK_REG(x) \ + COMPILE_ASSERT_EQ(static_cast(MCONTEXT_GREGS_##x), \ + offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]), reg_##x) + CHECK_REG(R8); + CHECK_REG(R9); + CHECK_REG(R10); + CHECK_REG(R11); + CHECK_REG(R12); + CHECK_REG(R13); + CHECK_REG(R14); + CHECK_REG(R15); + CHECK_REG(RDI); + CHECK_REG(RSI); + CHECK_REG(RBP); + CHECK_REG(RBX); + CHECK_REG(RDX); + CHECK_REG(RAX); + CHECK_REG(RCX); + CHECK_REG(RSP); + CHECK_REG(RIP); + + // sigcontext is an analog to mcontext_t. The layout should be the same. + COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs), + offsetof(sigcontext,fpstate), sigcontext_fpstate); + +#if defined(__ANDROID__) + // Check that _fpstate from asm/sigcontext.h is essentially the same + // as _libc_fpstate. + COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate), + sigcontext_fpstate_size); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,cwd),offsetof(_fpstate,cwd), + sigcontext_fpstate_cwd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,swd),offsetof(_fpstate,swd), + sigcontext_fpstate_swd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,ftw),offsetof(_fpstate,twd), + sigcontext_fpstate_twd); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,fop),offsetof(_fpstate,fop), + sigcontext_fpstate_fop); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rip),offsetof(_fpstate,rip), + sigcontext_fpstate_rip); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rdp),offsetof(_fpstate,rdp), + sigcontext_fpstate_rdp); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcsr),offsetof(_fpstate,mxcsr), + sigcontext_fpstate_mxcsr); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcr_mask), + offsetof(_fpstate,mxcsr_mask), + sigcontext_fpstate_mxcsr_mask); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_st), offsetof(_fpstate,st_space), + sigcontext_fpstate_stspace); + COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space), + sigcontext_fpstate_xmm_space); +#endif + + COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR, + offsetof(ucontext_t,uc_mcontext.fpregs), + mcontext_fpregs_ptr); + COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem), + mcontext_fpregs_mem); + COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR, + offsetof(std::remove_pointer::type,mxcsr), + fpregs_offset_mxcsr); + COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask), + ucontext_sigmask); +#else + ASSERT_EQ(static_cast(MCONTEXT_GREGS_OFFSET), + offsetof(ucontext_t,uc_mcontext.gregs)); +#endif +} + +TEST(AndroidUContext, SigmakOffset) { + ASSERT_EQ(static_cast(UCONTEXT_SIGMASK_OFFSET), + offsetof(ucontext_t,uc_sigmask)); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc new file mode 100644 index 0000000000..8df636ce4d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc @@ -0,0 +1,70 @@ +// Copyright 2014 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 "common/linux/crc32.h" + +namespace google_breakpad { + +// This implementation is based on the sample implementation in RFC 1952. + +// CRC32 polynomial, in reversed form. +// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check +static const uint32_t kCrc32Polynomial = 0xEDB88320; +static uint32_t kCrc32Table[256] = { 0 }; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +static void EnsureCrc32TableInited() { + if (kCrc32Table[arraysize(kCrc32Table) - 1]) + return; // already inited + for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { + uint32_t c = i; + for (size_t j = 0; j < 8; ++j) { + if (c & 1) { + c = kCrc32Polynomial ^ (c >> 1); + } else { + c >>= 1; + } + } + kCrc32Table[i] = c; + } +} + +uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) { + EnsureCrc32TableInited(); + + uint32_t c = start ^ 0xFFFFFFFF; + const uint8_t* u = static_cast(buf); + for (size_t i = 0; i < len; ++i) { + c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8); + } + return c ^ 0xFFFFFFFF; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h new file mode 100644 index 0000000000..e3d9db92be --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h @@ -0,0 +1,53 @@ +// Copyright 2014 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 COMMON_LINUX_CRC32_H_ +#define COMMON_LINUX_CRC32_H_ + +#include + +#include + +namespace google_breakpad { + +// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the +// checksum result from the previous update; for the first call, it should be 0. +uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len); + +// Computes a CRC32 checksum using |len| bytes from |buf|. +inline uint32_t ComputeCrc32(const void* buf, size_t len) { + return UpdateCrc32(0, buf, len); +} +inline uint32_t ComputeCrc32(const std::string& str) { + return ComputeCrc32(str.c_str(), str.size()); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_CRC32_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc new file mode 100644 index 0000000000..e398f7b392 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc @@ -0,0 +1,1218 @@ +// Copyright (c) 2011 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. + +// Restructured in 2009 by: Jim Blandy + +// dump_symbols.cc: implement google_breakpad::WriteSymbolFile: +// Find all the debugging info in a file and dump it as a Breakpad symbol file. + +#include "common/linux/dump_symbols.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common/arm_ex_reader.h" +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/dwarf2diehandler.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/dwarf_cu_to_module.h" +#include "common/dwarf_line_to_module.h" +#include "common/dwarf_range_list_handler.h" +#include "common/linux/crc32.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/elfutils.h" +#include "common/linux/elfutils-inl.h" +#include "common/linux/elf_symbols_to_module.h" +#include "common/linux/file_id.h" +#include "common/memory_allocator.h" +#include "common/module.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#ifndef NO_STABS_SUPPORT +#include "common/stabs_reader.h" +#include "common/stabs_to_module.h" +#endif +#include "common/using_std_string.h" + +#ifndef SHT_ARM_EXIDX +// bionic and older glibc don't define this +# define SHT_ARM_EXIDX (SHT_LOPROC + 1) +#endif + +// This namespace contains helper functions. +namespace { + +using google_breakpad::DumpOptions; +using google_breakpad::DwarfCFIToModule; +using google_breakpad::DwarfCUToModule; +using google_breakpad::DwarfLineToModule; +using google_breakpad::DwarfRangeListHandler; +using google_breakpad::ElfClass; +using google_breakpad::ElfClass32; +using google_breakpad::ElfClass64; +using google_breakpad::FileID; +using google_breakpad::FindElfSectionByName; +using google_breakpad::GetOffset; +using google_breakpad::IsValidElf; +using google_breakpad::kDefaultBuildIdSize; +using google_breakpad::Module; +using google_breakpad::PageAllocator; +#ifndef NO_STABS_SUPPORT +using google_breakpad::StabsToModule; +#endif +using google_breakpad::scoped_ptr; +using google_breakpad::wasteful_vector; + +// Define AARCH64 ELF architecture if host machine does not include this define. +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif + +// +// FDWrapper +// +// Wrapper class to make sure opened file is closed. +// +class FDWrapper { + public: + explicit FDWrapper(int fd) : + fd_(fd) {} + ~FDWrapper() { + if (fd_ != -1) + close(fd_); + } + int get() { + return fd_; + } + int release() { + int fd = fd_; + fd_ = -1; + return fd; + } + private: + int fd_; +}; + +// +// MmapWrapper +// +// Wrapper class to make sure mapped regions are unmapped. +// +class MmapWrapper { + public: + MmapWrapper() : is_set_(false) {} + ~MmapWrapper() { + if (is_set_ && base_ != NULL) { + assert(size_ > 0); + munmap(base_, size_); + } + } + void set(void *mapped_address, size_t mapped_size) { + is_set_ = true; + base_ = mapped_address; + size_ = mapped_size; + } + void release() { + assert(is_set_); + is_set_ = false; + base_ = NULL; + size_ = 0; + } + + private: + bool is_set_; + void* base_; + size_t size_; +}; + +// Find the preferred loading address of the binary. +template +typename ElfClass::Addr GetLoadingAddress( + const typename ElfClass::Phdr* program_headers, + int nheader) { + typedef typename ElfClass::Phdr Phdr; + + // For non-PIC executables (e_type == ET_EXEC), the load address is + // the start address of the first PT_LOAD segment. (ELF requires + // the segments to be sorted by load address.) For PIC executables + // and dynamic libraries (e_type == ET_DYN), this address will + // normally be zero. + for (int i = 0; i < nheader; ++i) { + const Phdr& header = program_headers[i]; + if (header.p_type == PT_LOAD) + return header.p_vaddr; + } + return 0; +} + +// Find the set of address ranges for all PT_LOAD segments. +template +vector GetPtLoadSegmentRanges( + const typename ElfClass::Phdr* program_headers, + int nheader) { + typedef typename ElfClass::Phdr Phdr; + vector ranges; + + for (int i = 0; i < nheader; ++i) { + const Phdr& header = program_headers[i]; + if (header.p_type == PT_LOAD) { + ranges.push_back(Module::Range(header.p_vaddr, header.p_memsz)); + } + } + return ranges; +} + +#ifndef NO_STABS_SUPPORT +template +bool LoadStabs(const typename ElfClass::Ehdr* elf_header, + const typename ElfClass::Shdr* stab_section, + const typename ElfClass::Shdr* stabstr_section, + const bool big_endian, + Module* module) { + // A callback object to handle data from the STABS reader. + StabsToModule handler(module); + // Find the addresses of the STABS data, and create a STABS reader object. + // On Linux, STABS entries always have 32-bit values, regardless of the + // address size of the architecture whose code they're describing, and + // the strings are always "unitized". + const uint8_t* stabs = + GetOffset(elf_header, stab_section->sh_offset); + const uint8_t* stabstr = + GetOffset(elf_header, stabstr_section->sh_offset); + google_breakpad::StabsReader reader(stabs, stab_section->sh_size, + stabstr, stabstr_section->sh_size, + big_endian, 4, true, &handler); + // Read the STABS data, and do post-processing. + if (!reader.Process()) + return false; + handler.Finalize(); + return true; +} +#endif // NO_STABS_SUPPORT + +// A range handler that accepts rangelist data parsed by +// dwarf2reader::RangeListReader and populates a range vector (typically +// owned by a function) with the results. +class DumperRangesHandler : public DwarfCUToModule::RangesHandler { + public: + DumperRangesHandler(const uint8_t *buffer, uint64 size, + dwarf2reader::ByteReader* reader) + : buffer_(buffer), size_(size), reader_(reader) { } + + bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) { + DwarfRangeListHandler handler(base_address, ranges); + dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, + &handler); + + return rangelist_reader.ReadRangeList(offset); + } + + private: + const uint8_t *buffer_; + uint64 size_; + dwarf2reader::ByteReader* reader_; +}; + +// A line-to-module loader that accepts line number info parsed by +// dwarf2reader::LineInfo and populates a Module and a line vector +// with the results. +class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { + public: + // Create a line-to-module converter using BYTE_READER. + explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader) + : byte_reader_(byte_reader) { } + void StartCompilationUnit(const string& compilation_dir) { + compilation_dir_ = compilation_dir; + } + void ReadProgram(const uint8_t *program, uint64 length, + Module* module, std::vector* lines) { + DwarfLineToModule handler(module, compilation_dir_, lines); + dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); + parser.Start(); + } + private: + string compilation_dir_; + dwarf2reader::ByteReader *byte_reader_; +}; + +template +bool LoadDwarf(const string& dwarf_filename, + const typename ElfClass::Ehdr* elf_header, + const bool big_endian, + bool handle_inter_cu_refs, + Module* module) { + typedef typename ElfClass::Shdr Shdr; + + const dwarf2reader::Endianness endianness = big_endian ? + dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; + dwarf2reader::ByteReader byte_reader(endianness); + + // Construct a context for this file. + DwarfCUToModule::FileContext file_context(dwarf_filename, + module, + handle_inter_cu_refs); + + // Build a map of the ELF file's sections. + const Shdr* sections = + GetOffset(elf_header, elf_header->e_shoff); + int num_sections = elf_header->e_shnum; + const Shdr* section_names = sections + elf_header->e_shstrndx; + for (int i = 0; i < num_sections; i++) { + const Shdr* section = §ions[i]; + string name = GetOffset(elf_header, + section_names->sh_offset) + + section->sh_name; + const uint8_t *contents = GetOffset(elf_header, + section->sh_offset); + file_context.AddSectionToSectionMap(name, contents, section->sh_size); + } + + // Optional .debug_ranges reader + scoped_ptr ranges_handler; + dwarf2reader::SectionMap::const_iterator ranges_entry = + file_context.section_map().find(".debug_ranges"); + if (ranges_entry != file_context.section_map().end()) { + const std::pair& ranges_section = + ranges_entry->second; + ranges_handler.reset( + new DumperRangesHandler(ranges_section.first, ranges_section.second, + &byte_reader)); + } + + // Parse all the compilation units in the .debug_info section. + DumperLineToModule line_to_module(&byte_reader); + dwarf2reader::SectionMap::const_iterator debug_info_entry = + file_context.section_map().find(".debug_info"); + assert(debug_info_entry != file_context.section_map().end()); + const std::pair& debug_info_section = + debug_info_entry->second; + // This should never have been called if the file doesn't have a + // .debug_info section. + assert(debug_info_section.first); + uint64 debug_info_length = debug_info_section.second; + for (uint64 offset = 0; offset < debug_info_length;) { + // Make a handler for the root DIE that populates MODULE with the + // data that was found. + DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); + DwarfCUToModule root_handler(&file_context, &line_to_module, + ranges_handler.get(), &reporter); + // Make a Dwarf2Handler that drives the DIEHandler. + dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); + // Make a DWARF parser for the compilation unit at OFFSET. + dwarf2reader::CompilationUnit reader(dwarf_filename, + file_context.section_map(), + offset, + &byte_reader, + &die_dispatcher); + // Process the entire compilation unit; get the offset of the next. + offset += reader.Start(); + } + return true; +} + +// Fill REGISTER_NAMES with the register names appropriate to the +// machine architecture given in HEADER, indexed by the register +// numbers used in DWARF call frame information. Return true on +// success, or false if HEADER's machine architecture is not +// supported. +template +bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, + std::vector* register_names) { + switch (elf_header->e_machine) { + case EM_386: + *register_names = DwarfCFIToModule::RegisterNames::I386(); + return true; + case EM_ARM: + *register_names = DwarfCFIToModule::RegisterNames::ARM(); + return true; + case EM_AARCH64: + *register_names = DwarfCFIToModule::RegisterNames::ARM64(); + return true; + case EM_MIPS: + *register_names = DwarfCFIToModule::RegisterNames::MIPS(); + return true; + case EM_X86_64: + *register_names = DwarfCFIToModule::RegisterNames::X86_64(); + return true; + default: + return false; + } +} + +template +bool LoadDwarfCFI(const string& dwarf_filename, + const typename ElfClass::Ehdr* elf_header, + const char* section_name, + const typename ElfClass::Shdr* section, + const bool eh_frame, + const typename ElfClass::Shdr* got_section, + const typename ElfClass::Shdr* text_section, + const bool big_endian, + Module* module) { + // Find the appropriate set of register names for this file's + // architecture. + std::vector register_names; + if (!DwarfCFIRegisterNames(elf_header, ®ister_names)) { + fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';" + " cannot convert DWARF call frame information\n", + dwarf_filename.c_str(), elf_header->e_machine); + return false; + } + + const dwarf2reader::Endianness endianness = big_endian ? + dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; + + // Find the call frame information and its size. + const uint8_t *cfi = + GetOffset(elf_header, section->sh_offset); + size_t cfi_size = section->sh_size; + + // Plug together the parser, handler, and their entourages. + DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name); + DwarfCFIToModule handler(module, register_names, &module_reporter); + dwarf2reader::ByteReader byte_reader(endianness); + + byte_reader.SetAddressSize(ElfClass::kAddrSize); + + // Provide the base addresses for .eh_frame encoded pointers, if + // possible. + byte_reader.SetCFIDataBase(section->sh_addr, cfi); + if (got_section) + byte_reader.SetDataBase(got_section->sh_addr); + if (text_section) + byte_reader.SetTextBase(text_section->sh_addr); + + dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, + section_name); + dwarf2reader::CallFrameInfo parser(cfi, cfi_size, + &byte_reader, &handler, &dwarf_reporter, + eh_frame); + parser.Start(); + return true; +} + +template +bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header, + const typename ElfClass::Shdr* exidx_section, + const typename ElfClass::Shdr* extab_section, + uint32_t loading_addr, + Module* module) { + // To do this properly we need to know: + // * the bounds of the .ARM.exidx section in the mapped image + // * the bounds of the .ARM.extab section in the mapped image + // * the vma of the last byte in the text section associated with the .exidx + // The first two are easy. The third is a bit tricky. If we can't + // figure out what it is, just pass in zero. + const char *exidx_img + = GetOffset(elf_header, exidx_section->sh_offset); + size_t exidx_size = exidx_section->sh_size; + const char *extab_img + = GetOffset(elf_header, extab_section->sh_offset); + size_t extab_size = extab_section->sh_size; + + // The sh_link field of the exidx section gives the section number + // for the associated text section. + uint32_t exidx_text_last_svma = 0; + int exidx_text_sno = exidx_section->sh_link; + typedef typename ElfClass::Shdr Shdr; + // |sections| points to the section header table + const Shdr* sections + = GetOffset(elf_header, elf_header->e_shoff); + const int num_sections = elf_header->e_shnum; + if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) { + const Shdr* exidx_text_shdr = §ions[exidx_text_sno]; + if (exidx_text_shdr->sh_size > 0) { + exidx_text_last_svma + = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1; + } + } + + arm_ex_to_module::ARMExToModule handler(module); + arm_ex_reader::ExceptionTableInfo + parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma, + &handler, + reinterpret_cast(elf_header), + loading_addr); + parser.Start(); + return true; +} + +bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, + void** elf_header) { + int obj_fd = open(obj_file.c_str(), O_RDONLY); + if (obj_fd < 0) { + fprintf(stderr, "Failed to open ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + FDWrapper obj_fd_wrapper(obj_fd); + struct stat st; + if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) { + fprintf(stderr, "Unable to fstat ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + void* obj_base = mmap(NULL, st.st_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0); + if (obj_base == MAP_FAILED) { + fprintf(stderr, "Failed to mmap ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + map_wrapper->set(obj_base, st.st_size); + *elf_header = obj_base; + if (!IsValidElf(*elf_header)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str()); + return false; + } + return true; +} + +// Get the endianness of ELF_HEADER. If it's invalid, return false. +template +bool ElfEndianness(const typename ElfClass::Ehdr* elf_header, + bool* big_endian) { + if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB) { + *big_endian = false; + return true; + } + if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB) { + *big_endian = true; + return true; + } + + fprintf(stderr, "bad data encoding in ELF header: %d\n", + elf_header->e_ident[EI_DATA]); + return false; +} + +// Given |left_abspath|, find the absolute path for |right_path| and see if the +// two absolute paths are the same. +bool IsSameFile(const char* left_abspath, const string& right_path) { + char right_abspath[PATH_MAX]; + if (!realpath(right_path.c_str(), right_abspath)) + return false; + return strcmp(left_abspath, right_abspath) == 0; +} + +// Read the .gnu_debuglink and get the debug file name. If anything goes +// wrong, return an empty string. +string ReadDebugLink(const uint8_t *debuglink, + const size_t debuglink_size, + const bool big_endian, + const string& obj_file, + const std::vector& debug_dirs) { + // Include '\0' + CRC32 (4 bytes). + size_t debuglink_len = strlen(reinterpret_cast(debuglink)) + 5; + debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. + + // Sanity check. + if (debuglink_len != debuglink_size) { + fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " + "%zx %zx\n", debuglink_len, debuglink_size); + return string(); + } + + char obj_file_abspath[PATH_MAX]; + if (!realpath(obj_file.c_str(), obj_file_abspath)) { + fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str()); + return string(); + } + + std::vector searched_paths; + string debuglink_path; + std::vector::const_iterator it; + for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { + const string& debug_dir = *it; + debuglink_path = debug_dir + "/" + + reinterpret_cast(debuglink); + + // There is the annoying case of /path/to/foo.so having foo.so as the + // debug link file name. Thus this may end up opening /path/to/foo.so again, + // and there is a small chance of the two files having the same CRC. + if (IsSameFile(obj_file_abspath, debuglink_path)) + continue; + + searched_paths.push_back(debug_dir); + int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); + if (debuglink_fd < 0) + continue; + + FDWrapper debuglink_fd_wrapper(debuglink_fd); + + // The CRC is the last 4 bytes in |debuglink|. + const dwarf2reader::Endianness endianness = big_endian ? + dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; + dwarf2reader::ByteReader byte_reader(endianness); + uint32_t expected_crc = + byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]); + + uint32_t actual_crc = 0; + while (true) { + const size_t kReadSize = 4096; + char buf[kReadSize]; + ssize_t bytes_read = HANDLE_EINTR(read(debuglink_fd, &buf, kReadSize)); + if (bytes_read < 0) { + fprintf(stderr, "Error reading debug ELF file %s.\n", + debuglink_path.c_str()); + return string(); + } + if (bytes_read == 0) + break; + actual_crc = google_breakpad::UpdateCrc32(actual_crc, buf, bytes_read); + } + if (actual_crc != expected_crc) { + fprintf(stderr, "Error reading debug ELF file - CRC32 mismatch: %s\n", + debuglink_path.c_str()); + continue; + } + + // Found debug file. + return debuglink_path; + } + + // Not found case. + fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n", + obj_file.c_str()); + for (it = searched_paths.begin(); it < searched_paths.end(); ++it) { + const string& debug_dir = *it; + fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink); + } + return string(); +} + +// +// LoadSymbolsInfo +// +// Holds the state between the two calls to LoadSymbols() in case it's necessary +// to follow the .gnu_debuglink section and load debug information from a +// different file. +// +template +class LoadSymbolsInfo { + public: + typedef typename ElfClass::Addr Addr; + + explicit LoadSymbolsInfo(const std::vector& dbg_dirs) : + debug_dirs_(dbg_dirs), + has_loading_addr_(false) {} + + // Keeps track of which sections have been loaded so sections don't + // accidentally get loaded twice from two different files. + void LoadedSection(const string §ion) { + if (loaded_sections_.count(section) == 0) { + loaded_sections_.insert(section); + } else { + fprintf(stderr, "Section %s has already been loaded.\n", + section.c_str()); + } + } + + // The ELF file and linked debug file are expected to have the same preferred + // loading address. + void set_loading_addr(Addr addr, const string &filename) { + if (!has_loading_addr_) { + loading_addr_ = addr; + loaded_file_ = filename; + return; + } + + if (addr != loading_addr_) { + fprintf(stderr, + "ELF file '%s' and debug ELF file '%s' " + "have different load addresses.\n", + loaded_file_.c_str(), filename.c_str()); + assert(false); + } + } + + // Setters and getters + const std::vector& debug_dirs() const { + return debug_dirs_; + } + + string debuglink_file() const { + return debuglink_file_; + } + void set_debuglink_file(string file) { + debuglink_file_ = file; + } + + private: + const std::vector& debug_dirs_; // Directories in which to + // search for the debug ELF file. + + string debuglink_file_; // Full path to the debug ELF file. + + bool has_loading_addr_; // Indicate if LOADING_ADDR_ is valid. + + Addr loading_addr_; // Saves the preferred loading address from the + // first call to LoadSymbols(). + + string loaded_file_; // Name of the file loaded from the first call to + // LoadSymbols(). + + std::set loaded_sections_; // Tracks the Loaded ELF sections + // between calls to LoadSymbols(). +}; + +template +bool LoadSymbols(const string& obj_file, + const bool big_endian, + const typename ElfClass::Ehdr* elf_header, + const bool read_gnu_debug_link, + LoadSymbolsInfo* info, + const DumpOptions& options, + Module* module) { + typedef typename ElfClass::Addr Addr; + typedef typename ElfClass::Phdr Phdr; + typedef typename ElfClass::Shdr Shdr; + + Addr loading_addr = GetLoadingAddress( + GetOffset(elf_header, elf_header->e_phoff), + elf_header->e_phnum); + module->SetLoadAddress(loading_addr); + info->set_loading_addr(loading_addr, obj_file); + + // Allow filtering of extraneous debug information in partitioned libraries. + // Such libraries contain debug information for all libraries extracted from + // the same combined library, implying extensive duplication. + vector address_ranges = GetPtLoadSegmentRanges( + GetOffset(elf_header, elf_header->e_phoff), + elf_header->e_phnum); + module->SetAddressRanges(address_ranges); + + const Shdr* sections = + GetOffset(elf_header, elf_header->e_shoff); + const Shdr* section_names = sections + elf_header->e_shstrndx; + const char* names = + GetOffset(elf_header, section_names->sh_offset); + const char *names_end = names + section_names->sh_size; + bool found_debug_info_section = false; + bool found_usable_info = false; + + if (options.symbol_data != ONLY_CFI) { +#ifndef NO_STABS_SUPPORT + // Look for STABS debugging information, and load it if present. + const Shdr* stab_section = + FindElfSectionByName(".stab", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + if (stab_section) { + const Shdr* stabstr_section = stab_section->sh_link + sections; + if (stabstr_section) { + found_debug_info_section = true; + found_usable_info = true; + info->LoadedSection(".stab"); + if (!LoadStabs(elf_header, stab_section, stabstr_section, + big_endian, module)) { + fprintf(stderr, "%s: \".stab\" section found, but failed to load" + " STABS debugging information\n", obj_file.c_str()); + } + } + } +#endif // NO_STABS_SUPPORT + + // Look for DWARF debugging information, and load it if present. + const Shdr* dwarf_section = + FindElfSectionByName(".debug_info", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + + // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains, + // but MIPS_DWARF for regular gnu toolchains, so both need to be checked + if (elf_header->e_machine == EM_MIPS && !dwarf_section) { + dwarf_section = + FindElfSectionByName(".debug_info", SHT_MIPS_DWARF, + sections, names, names_end, + elf_header->e_shnum); + } + + if (dwarf_section) { + found_debug_info_section = true; + found_usable_info = true; + info->LoadedSection(".debug_info"); + if (!LoadDwarf(obj_file, elf_header, big_endian, + options.handle_inter_cu_refs, module)) { + fprintf(stderr, "%s: \".debug_info\" section found, but failed to load " + "DWARF debugging information\n", obj_file.c_str()); + } + } + + // See if there are export symbols available. + const Shdr* symtab_section = + FindElfSectionByName(".symtab", SHT_SYMTAB, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* strtab_section = + FindElfSectionByName(".strtab", SHT_STRTAB, + sections, names, names_end, + elf_header->e_shnum); + if (symtab_section && strtab_section) { + info->LoadedSection(".symtab"); + + const uint8_t* symtab = + GetOffset(elf_header, + symtab_section->sh_offset); + const uint8_t* strtab = + GetOffset(elf_header, + strtab_section->sh_offset); + bool result = + ELFSymbolsToModule(symtab, + symtab_section->sh_size, + strtab, + strtab_section->sh_size, + big_endian, + ElfClass::kAddrSize, + module); + found_usable_info = found_usable_info || result; + } else { + // Look in dynsym only if full symbol table was not available. + const Shdr* dynsym_section = + FindElfSectionByName(".dynsym", SHT_DYNSYM, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* dynstr_section = + FindElfSectionByName(".dynstr", SHT_STRTAB, + sections, names, names_end, + elf_header->e_shnum); + if (dynsym_section && dynstr_section) { + info->LoadedSection(".dynsym"); + + const uint8_t* dynsyms = + GetOffset(elf_header, + dynsym_section->sh_offset); + const uint8_t* dynstrs = + GetOffset(elf_header, + dynstr_section->sh_offset); + bool result = + ELFSymbolsToModule(dynsyms, + dynsym_section->sh_size, + dynstrs, + dynstr_section->sh_size, + big_endian, + ElfClass::kAddrSize, + module); + found_usable_info = found_usable_info || result; + } + } + } + + if (options.symbol_data != NO_CFI) { + // Dwarf Call Frame Information (CFI) is actually independent from + // the other DWARF debugging information, and can be used alone. + const Shdr* dwarf_cfi_section = + FindElfSectionByName(".debug_frame", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + + // .debug_frame section type is SHT_PROGBITS for mips on pnacl toolchains, + // but MIPS_DWARF for regular gnu toolchains, so both need to be checked + if (elf_header->e_machine == EM_MIPS && !dwarf_cfi_section) { + dwarf_cfi_section = + FindElfSectionByName(".debug_frame", SHT_MIPS_DWARF, + sections, names, names_end, + elf_header->e_shnum); + } + + if (dwarf_cfi_section) { + // Ignore the return value of this function; even without call frame + // information, the other debugging information could be perfectly + // useful. + info->LoadedSection(".debug_frame"); + bool result = + LoadDwarfCFI(obj_file, elf_header, ".debug_frame", + dwarf_cfi_section, false, 0, 0, big_endian, + module); + found_usable_info = found_usable_info || result; + } + + // Linux C++ exception handling information can also provide + // unwinding data. + const Shdr* eh_frame_section = + FindElfSectionByName(".eh_frame", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + if (eh_frame_section) { + // Pointers in .eh_frame data may be relative to the base addresses of + // certain sections. Provide those sections if present. + const Shdr* got_section = + FindElfSectionByName(".got", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* text_section = + FindElfSectionByName(".text", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + info->LoadedSection(".eh_frame"); + // As above, ignore the return value of this function. + bool result = + LoadDwarfCFI(obj_file, elf_header, ".eh_frame", + eh_frame_section, true, + got_section, text_section, big_endian, module); + found_usable_info = found_usable_info || result; + } + } + + // ARM has special unwind tables that can be used. + const Shdr* arm_exidx_section = + FindElfSectionByName(".ARM.exidx", SHT_ARM_EXIDX, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* arm_extab_section = + FindElfSectionByName(".ARM.extab", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + // Load information from these sections even if there is + // .debug_info, because some functions (e.g., hand-written or + // script-generated assembly) could have exidx entries but no DWARF. + // (For functions with both, the DWARF info that has already been + // parsed will take precedence.) + if (arm_exidx_section && arm_extab_section && options.symbol_data != NO_CFI) { + info->LoadedSection(".ARM.exidx"); + info->LoadedSection(".ARM.extab"); + bool result = LoadARMexidx(elf_header, + arm_exidx_section, arm_extab_section, + loading_addr, module); + found_usable_info = found_usable_info || result; + } + + if (!found_debug_info_section) { + fprintf(stderr, "%s: file contains no debugging information" + " (no \".stab\" or \".debug_info\" sections)\n", + obj_file.c_str()); + + // Failed, but maybe there's a .gnu_debuglink section? + if (read_gnu_debug_link) { + const Shdr* gnu_debuglink_section + = FindElfSectionByName(".gnu_debuglink", SHT_PROGBITS, + sections, names, + names_end, elf_header->e_shnum); + if (gnu_debuglink_section) { + if (!info->debug_dirs().empty()) { + const uint8_t *debuglink_contents = + GetOffset(elf_header, + gnu_debuglink_section->sh_offset); + string debuglink_file = + ReadDebugLink(debuglink_contents, + gnu_debuglink_section->sh_size, + big_endian, + obj_file, + info->debug_dirs()); + info->set_debuglink_file(debuglink_file); + } else { + fprintf(stderr, ".gnu_debuglink section found in '%s', " + "but no debug path specified.\n", obj_file.c_str()); + } + } else { + fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n", + obj_file.c_str()); + } + } else { + // Return true if some usable information was found, since the caller + // doesn't want to use .gnu_debuglink. + return found_usable_info; + } + + // No debug info was found, let the user try again with .gnu_debuglink + // if present. + return false; + } + + return true; +} + +// Return the breakpad symbol file identifier for the architecture of +// ELF_HEADER. +template +const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { + typedef typename ElfClass::Half Half; + Half arch = elf_header->e_machine; + switch (arch) { + case EM_386: return "x86"; + case EM_ARM: return "arm"; + case EM_AARCH64: return "arm64"; + case EM_MIPS: return "mips"; + case EM_PPC64: return "ppc64"; + case EM_PPC: return "ppc"; + case EM_S390: return "s390"; + case EM_SPARC: return "sparc"; + case EM_SPARCV9: return "sparcv9"; + case EM_X86_64: return "x86_64"; + default: return NULL; + } +} + +template +bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header, + const string& debuglink_file, + const string& obj_filename, + const char* obj_file_architecture, + const bool obj_file_is_big_endian) { + const char* debug_architecture = + ElfArchitecture(debug_elf_header); + if (!debug_architecture) { + fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n", + debuglink_file.c_str(), debug_elf_header->e_machine); + return false; + } + if (strcmp(obj_file_architecture, debug_architecture)) { + fprintf(stderr, "%s with ELF machine architecture %s does not match " + "%s with ELF architecture %s\n", + debuglink_file.c_str(), debug_architecture, + obj_filename.c_str(), obj_file_architecture); + return false; + } + bool debug_big_endian; + if (!ElfEndianness(debug_elf_header, &debug_big_endian)) + return false; + if (debug_big_endian != obj_file_is_big_endian) { + fprintf(stderr, "%s and %s does not match in endianness\n", + obj_filename.c_str(), debuglink_file.c_str()); + return false; + } + return true; +} + +template +bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, + const string& obj_filename, + const string& obj_os, + scoped_ptr& module) { + PageAllocator allocator; + wasteful_vector identifier(&allocator, kDefaultBuildIdSize); + if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) { + fprintf(stderr, "%s: unable to generate file identifier\n", + obj_filename.c_str()); + return false; + } + + const char *architecture = ElfArchitecture(elf_header); + if (!architecture) { + fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n", + obj_filename.c_str(), elf_header->e_machine); + return false; + } + + char name_buf[NAME_MAX] = {}; + std::string name = google_breakpad::ElfFileSoNameFromMappedFile( + elf_header, name_buf, sizeof(name_buf)) + ? name_buf + : google_breakpad::BaseName(obj_filename); + + // Add an extra "0" at the end. PDB files on Windows have an 'age' + // number appended to the end of the file identifier; this isn't + // really used or necessary on other platforms, but be consistent. + string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0"; + // This is just the raw Build ID in hex. + string code_id = FileID::ConvertIdentifierToString(identifier); + + module.reset(new Module(name, obj_os, architecture, id, code_id)); + + return true; +} + +template +bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, + const string& obj_filename, + const string& obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + Module** out_module) { + typedef typename ElfClass::Ehdr Ehdr; + + *out_module = NULL; + + scoped_ptr module; + if (!InitModuleForElfClass(elf_header, obj_filename, obj_os, + module)) { + return false; + } + + // Figure out what endianness this file is. + bool big_endian; + if (!ElfEndianness(elf_header, &big_endian)) + return false; + + LoadSymbolsInfo info(debug_dirs); + if (!LoadSymbols(obj_filename, big_endian, elf_header, + !debug_dirs.empty(), &info, + options, module.get())) { + const string debuglink_file = info.debuglink_file(); + if (debuglink_file.empty()) + return false; + + // Load debuglink ELF file. + fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str()); + MmapWrapper debug_map_wrapper; + Ehdr* debug_elf_header = NULL; + if (!LoadELF(debuglink_file, &debug_map_wrapper, + reinterpret_cast(&debug_elf_header)) || + !SanitizeDebugFile(debug_elf_header, debuglink_file, + obj_filename, + module->architecture().c_str(), + big_endian)) { + return false; + } + + if (!LoadSymbols(debuglink_file, big_endian, + debug_elf_header, false, &info, + options, module.get())) { + return false; + } + } + + *out_module = module.release(); + return true; +} + +} // namespace + +namespace google_breakpad { + +// Not explicitly exported, but not static so it can be used in unit tests. +bool ReadSymbolDataInternal(const uint8_t* obj_file, + const string& obj_filename, + const string& obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + Module** module) { + if (!IsValidElf(obj_file)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str()); + return false; + } + + int elfclass = ElfClass(obj_file); + if (elfclass == ELFCLASS32) { + return ReadSymbolDataElfClass( + reinterpret_cast(obj_file), obj_filename, obj_os, + debug_dirs, options, module); + } + if (elfclass == ELFCLASS64) { + return ReadSymbolDataElfClass( + reinterpret_cast(obj_file), obj_filename, obj_os, + debug_dirs, options, module); + } + + return false; +} + +bool WriteSymbolFile(const string &load_path, + const string &obj_file, + const string &obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + std::ostream &sym_stream) { + Module* module; + if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options, + &module)) + return false; + + bool result = module->Write(sym_stream, options.symbol_data); + delete module; + return result; +} + +// Read the selected object file's debugging information, and write out the +// header only to |stream|. Return true on success; if an error occurs, report +// it and return false. +bool WriteSymbolFileHeader(const string& load_path, + const string& obj_file, + const string& obj_os, + std::ostream &sym_stream) { + MmapWrapper map_wrapper; + void* elf_header = NULL; + if (!LoadELF(load_path, &map_wrapper, &elf_header)) { + fprintf(stderr, "Could not load ELF file: %s\n", obj_file.c_str()); + return false; + } + + if (!IsValidElf(elf_header)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str()); + return false; + } + + int elfclass = ElfClass(elf_header); + scoped_ptr module; + if (elfclass == ELFCLASS32) { + if (!InitModuleForElfClass( + reinterpret_cast(elf_header), obj_file, obj_os, + module)) { + fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); + return false; + } + } else if (elfclass == ELFCLASS64) { + if (!InitModuleForElfClass( + reinterpret_cast(elf_header), obj_file, obj_os, + module)) { + fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); + return false; + } + } else { + fprintf(stderr, "Unsupported module file: %s\n", obj_file.c_str()); + return false; + } + + return module->Write(sym_stream, ALL_SYMBOL_DATA); +} + +bool ReadSymbolData(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + Module** module) { + MmapWrapper map_wrapper; + void* elf_header = NULL; + if (!LoadELF(load_path, &map_wrapper, &elf_header)) + return false; + + return ReadSymbolDataInternal(reinterpret_cast(elf_header), + obj_file, obj_os, debug_dirs, options, module); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h new file mode 100644 index 0000000000..eaddd8b2ec --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h @@ -0,0 +1,93 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011, 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. + +// dump_symbols.h: Read debugging information from an ELF file, and write +// it out as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__ +#define COMMON_LINUX_DUMP_SYMBOLS_H__ + +#include +#include +#include + +#include "common/symbol_data.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +class Module; + +struct DumpOptions { + DumpOptions(SymbolData symbol_data, bool handle_inter_cu_refs) + : symbol_data(symbol_data), + handle_inter_cu_refs(handle_inter_cu_refs) { + } + + SymbolData symbol_data; + bool handle_inter_cu_refs; +}; + +// Find all the debugging information in OBJ_FILE, an ELF executable +// or shared library, and write it to SYM_STREAM in the Breakpad symbol +// file format. +// If OBJ_FILE has been stripped but contains a .gnu_debuglink section, +// then look for the debug file in DEBUG_DIRS. +// SYMBOL_DATA allows limiting the type of symbol data written. +bool WriteSymbolFile(const string &load_path, + const string &obj_file, + const string &obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + std::ostream &sym_stream); + +// Read the selected object file's debugging information, and write out the +// header only to |stream|. Return true on success; if an error occurs, report +// it and return false. |obj_file| becomes the MODULE file name and |obj_os| +// becomes the MODULE operating system. +bool WriteSymbolFileHeader(const string& load_path, + const string& obj_file, + const string& obj_os, + std::ostream &sym_stream); + +// As above, but simply return the debugging information in MODULE +// instead of writing it to a stream. The caller owns the resulting +// Module object and must delete it when finished. +bool ReadSymbolData(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector& debug_dirs, + const DumpOptions& options, + Module** module); + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc new file mode 100644 index 0000000000..54c2109625 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek + +// dump_symbols_unittest.cc: +// Unittests for google_breakpad::DumpSymbols + +#include +#include +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" +#include "common/linux/dump_symbols.h" +#include "common/linux/synth_elf.h" +#include "common/module.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +bool ReadSymbolDataInternal(const uint8_t* obj_file, + const string& obj_filename, + const string& obj_os, + const std::vector& debug_dir, + const DumpOptions& options, + Module** module); + +using google_breakpad::synth_elf::ELF; +using google_breakpad::synth_elf::Notes; +using google_breakpad::synth_elf::StringTable; +using google_breakpad::synth_elf::SymbolTable; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Section; +using std::stringstream; +using std::vector; +using ::testing::Test; +using ::testing::Types; + +template +class DumpSymbols : public Test { + public: + void GetElfContents(ELF& elf) { + string contents; + ASSERT_TRUE(elf.GetContents(&contents)); + ASSERT_LT(0U, contents.size()); + + elfdata_v.clear(); + elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); + elfdata = &elfdata_v[0]; + } + + vector elfdata_v; + uint8_t* elfdata; +}; + +typedef Types ElfClasses; + +TYPED_TEST_SUITE(DumpSymbols, ElfClasses); + +TYPED_TEST(DumpSymbols, Invalid) { + Elf32_Ehdr header; + memset(&header, 0, sizeof(header)); + Module* module; + DumpOptions options(ALL_SYMBOL_DATA, true); + EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast(&header), + "foo", + "Linux", + vector(), + options, + &module)); +} + +TYPED_TEST(DumpSymbols, SimplePublic) { + ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); + // Zero out text section for simplicity. + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + + // Add a public symbol. + StringTable table(kLittleEndian); + SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); + syms.AddSymbol("superfunc", + (typename TypeParam::Addr)0x1000, + (typename TypeParam::Addr)0x10, + // ELF32_ST_INFO works for 32-or 64-bit. + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF + 1); + int index = elf.AddSection(".dynstr", table, SHT_STRTAB); + elf.AddSection(".dynsym", syms, + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(typename TypeParam::Sym)); // entsize + + elf.Finish(); + this->GetElfContents(elf); + + Module* module; + DumpOptions options(ALL_SYMBOL_DATA, true); + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, + "foo", + "Linux", + vector(), + options, + &module)); + + stringstream s; + module->Write(s, ALL_SYMBOL_DATA); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " 000000000000000000000000000000000 foo\n" + "INFO CODE_ID 00000000000000000000000000000000\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); + delete module; +} + +TYPED_TEST(DumpSymbols, SimpleBuildID) { + ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); + // Zero out text section for simplicity. + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + + // Add a Build ID + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + Notes notes(kLittleEndian); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); + + // Add a public symbol. + StringTable table(kLittleEndian); + SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); + syms.AddSymbol("superfunc", + (typename TypeParam::Addr)0x1000, + (typename TypeParam::Addr)0x10, + // ELF32_ST_INFO works for 32-or 64-bit. + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF + 1); + int index = elf.AddSection(".dynstr", table, SHT_STRTAB); + elf.AddSection(".dynsym", syms, + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(typename TypeParam::Sym)); // entsize + + elf.Finish(); + this->GetElfContents(elf); + + Module* module; + DumpOptions options(ALL_SYMBOL_DATA, true); + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, + "foo", + "Linux", + vector(), + options, + &module)); + + stringstream s; + module->Write(s, ALL_SYMBOL_DATA); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " 030201000504070608090A0B0C0D0E0F0 foo\n" + "INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); + delete module; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h new file mode 100644 index 0000000000..3f1d184817 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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 COMMON_LINUX_EINTR_WRAPPER_H_ +#define COMMON_LINUX_EINTR_WRAPPER_H_ + +#include + +// This provides a wrapper around system calls which may be interrupted by a +// signal and return EINTR. See man 7 signal. +// + +#define HANDLE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + eintr_wrapper_result; \ +}) + +#define IGNORE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + if (eintr_wrapper_result == -1 && errno == EINTR) { \ + eintr_wrapper_result = 0; \ + } \ + } while (0); \ + eintr_wrapper_result; \ +}) + +#endif // COMMON_LINUX_EINTR_WRAPPER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc new file mode 100644 index 0000000000..0e7db7b1fa --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2011, 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. + +// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. +// See elf_core_dump.h for details. + +#include "common/linux/elf_core_dump.h" + +#include +#include + +namespace google_breakpad { + +// Implementation of ElfCoreDump::Note. + +ElfCoreDump::Note::Note() {} + +ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {} + +bool ElfCoreDump::Note::IsValid() const { + return GetHeader() != NULL; +} + +const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const { + return content_.GetData(0); +} + +ElfCoreDump::Word ElfCoreDump::Note::GetType() const { + const Nhdr* header = GetHeader(); + // 0 is not being used as a NOTE type. + return header ? header->n_type : 0; +} + +MemoryRange ElfCoreDump::Note::GetName() const { + const Nhdr* header = GetHeader(); + if (header) { + return content_.Subrange(sizeof(Nhdr), header->n_namesz); + } + return MemoryRange(); +} + +MemoryRange ElfCoreDump::Note::GetDescription() const { + const Nhdr* header = GetHeader(); + if (header) { + return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz), + header->n_descsz); + } + return MemoryRange(); +} + +ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const { + MemoryRange next_content; + const Nhdr* header = GetHeader(); + if (header) { + size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz); + next_offset = AlignedSize(next_offset + header->n_descsz); + next_content = + content_.Subrange(next_offset, content_.length() - next_offset); + } + return Note(next_content); +} + +// static +size_t ElfCoreDump::Note::AlignedSize(size_t size) { + size_t mask = sizeof(Word) - 1; + return (size + mask) & ~mask; +} + + +// Implementation of ElfCoreDump. + +ElfCoreDump::ElfCoreDump() {} + +ElfCoreDump::ElfCoreDump(const MemoryRange& content) + : content_(content) { +} + +void ElfCoreDump::SetContent(const MemoryRange& content) { + content_ = content; +} + +bool ElfCoreDump::IsValid() const { + const Ehdr* header = GetHeader(); + return (header && + header->e_ident[0] == ELFMAG0 && + header->e_ident[1] == ELFMAG1 && + header->e_ident[2] == ELFMAG2 && + header->e_ident[3] == ELFMAG3 && + header->e_ident[4] == kClass && + header->e_version == EV_CURRENT && + header->e_type == ET_CORE); +} + +const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const { + return content_.GetData(0); +} + +const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const { + const Ehdr* header = GetHeader(); + if (header) { + return reinterpret_cast(content_.GetArrayElement( + header->e_phoff, header->e_phentsize, index)); + } + return NULL; +} + +const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType( + Word type) const { + for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { + const Phdr* program = GetProgramHeader(i); + if (program->p_type == type) { + return program; + } + } + return NULL; +} + +unsigned ElfCoreDump::GetProgramHeaderCount() const { + const Ehdr* header = GetHeader(); + return header ? header->e_phnum : 0; +} + +bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) { + for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { + const Phdr* program = GetProgramHeader(i); + if (program->p_type != PT_LOAD) + continue; + + size_t offset_in_segment = virtual_address - program->p_vaddr; + if (virtual_address >= program->p_vaddr && + offset_in_segment < program->p_filesz) { + const void* data = + content_.GetData(program->p_offset + offset_in_segment, length); + if (data) { + memcpy(buffer, data, length); + return true; + } + } + } + return false; +} + +ElfCoreDump::Note ElfCoreDump::GetFirstNote() const { + MemoryRange note_content; + const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE); + if (program_header) { + note_content = content_.Subrange(program_header->p_offset, + program_header->p_filesz); + } + return Note(note_content); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h new file mode 100644 index 0000000000..6e153745db --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h @@ -0,0 +1,149 @@ +// Copyright (c) 2011, 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. + +// elf_core_dump.h: Define the google_breakpad::ElfCoreDump class, which +// encapsulates an ELF core dump file mapped into memory. + +#ifndef COMMON_LINUX_ELF_CORE_DUMP_H_ +#define COMMON_LINUX_ELF_CORE_DUMP_H_ + +#include +#include +#include +#include + +#include "common/memory_range.h" + +namespace google_breakpad { + +// A class encapsulating an ELF core dump file mapped into memory, which +// provides methods for accessing program headers and the note section. +class ElfCoreDump { + public: + // ELF types based on the native word size. + typedef ElfW(Ehdr) Ehdr; + typedef ElfW(Nhdr) Nhdr; + typedef ElfW(Phdr) Phdr; + typedef ElfW(Word) Word; + typedef ElfW(Addr) Addr; +#if ULONG_MAX == 0xffffffff + static const int kClass = ELFCLASS32; +#elif ULONG_MAX == 0xffffffffffffffff + static const int kClass = ELFCLASS64; +#else +#error "Unsupported word size for ElfCoreDump." +#endif + + // A class encapsulating the note content in a core dump, which provides + // methods for accessing the name and description of a note. + class Note { + public: + Note(); + + // Constructor that takes the note content from |content|. + explicit Note(const MemoryRange& content); + + // Returns true if this note is valid, i,e. a note header is found in + // |content_|, or false otherwise. + bool IsValid() const; + + // Returns the note header, or NULL if no note header is found in + // |content_|. + const Nhdr* GetHeader() const; + + // Returns the note type, or 0 if no note header is found in |content_|. + Word GetType() const; + + // Returns a memory range covering the note name, or an empty range + // if no valid note name is found in |content_|. + MemoryRange GetName() const; + + // Returns a memory range covering the note description, or an empty + // range if no valid note description is found in |content_|. + MemoryRange GetDescription() const; + + // Returns the note following this note, or an empty note if no valid + // note is found after this note. + Note GetNextNote() const; + + private: + // Returns the size in bytes round up to the word alignment, specified + // for the note section, of a given size in bytes. + static size_t AlignedSize(size_t size); + + // Note content. + MemoryRange content_; + }; + + ElfCoreDump(); + + // Constructor that takes the core dump content from |content|. + explicit ElfCoreDump(const MemoryRange& content); + + // Sets the core dump content to |content|. + void SetContent(const MemoryRange& content); + + // Returns true if a valid ELF header in the core dump, or false otherwise. + bool IsValid() const; + + // Returns the ELF header in the core dump, or NULL if no ELF header + // is found in |content_|. + const Ehdr* GetHeader() const; + + // Returns the |index|-th program header in the core dump, or NULL if no + // ELF header is found in |content_| or |index| is out of bounds. + const Phdr* GetProgramHeader(unsigned index) const; + + // Returns the first program header of |type| in the core dump, or NULL if + // no ELF header is found in |content_| or no program header of |type| is + // found. + const Phdr* GetFirstProgramHeaderOfType(Word type) const; + + // Returns the number of program headers in the core dump, or 0 if no + // ELF header is found in |content_|. + unsigned GetProgramHeaderCount() const; + + // Copies |length| bytes of data starting at |virtual_address| in the core + // dump to |buffer|. |buffer| should be a valid pointer to a buffer of at + // least |length| bytes. Returns true if the data to be copied is found in + // the core dump, or false otherwise. + bool CopyData(void* buffer, Addr virtual_address, size_t length); + + // Returns the first note found in the note section of the core dump, or + // an empty note if no note is found. + Note GetFirstNote() const; + + private: + // Core dump content. + MemoryRange content_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELF_CORE_DUMP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc new file mode 100644 index 0000000000..2399c12fda --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc @@ -0,0 +1,265 @@ +// Copyright (c) 2011, 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. + +// elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. + +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/elf_core_dump.h" +#include "common/linux/memory_mapped_file.h" +#include "common/tests/file_utils.h" +#include "common/linux/tests/crash_generator.h" +#include "common/using_std_string.h" + +using google_breakpad::AutoTempDir; +using google_breakpad::CrashGenerator; +using google_breakpad::ElfCoreDump; +using google_breakpad::MemoryMappedFile; +using google_breakpad::MemoryRange; +using google_breakpad::WriteFile; +using std::set; + +TEST(ElfCoreDumpTest, DefaultConstructor) { + ElfCoreDump core; + EXPECT_FALSE(core.IsValid()); + EXPECT_EQ(NULL, core.GetHeader()); + EXPECT_EQ(0U, core.GetProgramHeaderCount()); + EXPECT_EQ(NULL, core.GetProgramHeader(0)); + EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); + EXPECT_FALSE(core.GetFirstNote().IsValid()); +} + +TEST(ElfCoreDumpTest, TestElfHeader) { + ElfCoreDump::Ehdr header; + memset(&header, 0, sizeof(header)); + + AutoTempDir temp_dir; + string core_path = temp_dir.path() + "/core"; + const char* core_file = core_path.c_str(); + MemoryMappedFile mapped_core_file; + ElfCoreDump core; + + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1)); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + EXPECT_EQ(NULL, core.GetHeader()); + EXPECT_EQ(0U, core.GetProgramHeaderCount()); + EXPECT_EQ(NULL, core.GetProgramHeader(0)); + EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); + EXPECT_FALSE(core.GetFirstNote().IsValid()); + + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_ident[0] = ELFMAG0; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_ident[1] = ELFMAG1; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_ident[2] = ELFMAG2; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_ident[3] = ELFMAG3; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_ident[4] = ElfCoreDump::kClass; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_version = EV_CURRENT; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_FALSE(core.IsValid()); + + header.e_type = ET_CORE; + ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); + ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); + core.SetContent(mapped_core_file.content()); + EXPECT_TRUE(core.IsValid()); +} + +TEST(ElfCoreDumpTest, ValidCoreFile) { + CrashGenerator crash_generator; + if (!crash_generator.HasDefaultCorePattern()) { + fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " + "due to non-default core pattern"); + return; + } + + const unsigned kNumOfThreads = 3; + const unsigned kCrashThread = 1; + const int kCrashSignal = SIGABRT; + ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, + kCrashSignal, NULL)); + pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); + set expected_thread_ids; + for (unsigned i = 0; i < kNumOfThreads; ++i) { + expected_thread_ids.insert(crash_generator.GetThreadId(i)); + } + +#if defined(__ANDROID__) + struct stat st; + if (stat(crash_generator.GetCoreFilePath().c_str(), &st) != 0) { + fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " + "due to no core file being generated"); + return; + } +#endif + + MemoryMappedFile mapped_core_file; + ASSERT_TRUE( + mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0)); + + ElfCoreDump core; + core.SetContent(mapped_core_file.content()); + EXPECT_TRUE(core.IsValid()); + + // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are + // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific): + // Thread Name Type + // ------------------------------------------------------------------- + // 1st thread CORE NT_PRSTATUS + // process-wide CORE NT_PRPSINFO + // process-wide CORE NT_AUXV + // 1st thread CORE NT_FPREGSET + // 1st thread LINUX NT_PRXFPREG + // 1st thread LINUX NT_386_TLS + // + // 2nd thread CORE NT_PRSTATUS + // 2nd thread CORE NT_FPREGSET + // 2nd thread LINUX NT_PRXFPREG + // 2nd thread LINUX NT_386_TLS + // + // 3rd thread CORE NT_PRSTATUS + // 3rd thread CORE NT_FPREGSET + // 3rd thread LINUX NT_PRXFPREG + // 3rd thread LINUX NT_386_TLS + + size_t num_nt_prpsinfo = 0; + size_t num_nt_prstatus = 0; + size_t num_pr_fpvalid = 0; +#if defined(__i386__) || defined(__x86_64__) + size_t num_nt_fpregset = 0; +#endif +#if defined(__i386__) + size_t num_nt_prxfpreg = 0; +#endif + set actual_thread_ids; + ElfCoreDump::Note note = core.GetFirstNote(); + while (note.IsValid()) { + MemoryRange name = note.GetName(); + MemoryRange description = note.GetDescription(); + EXPECT_FALSE(name.IsEmpty()); + EXPECT_FALSE(description.IsEmpty()); + + switch (note.GetType()) { + case NT_PRPSINFO: { + EXPECT_TRUE(description.data() != NULL); + EXPECT_EQ(sizeof(elf_prpsinfo), description.length()); + ++num_nt_prpsinfo; + break; + } + case NT_PRSTATUS: { + EXPECT_TRUE(description.data() != NULL); + EXPECT_EQ(sizeof(elf_prstatus), description.length()); + const elf_prstatus* status = description.GetData(0); + actual_thread_ids.insert(status->pr_pid); + if (num_nt_prstatus == 0) { + EXPECT_EQ(expected_crash_thread_id, status->pr_pid); + EXPECT_EQ(kCrashSignal, status->pr_info.si_signo); + } + ++num_nt_prstatus; + if (status->pr_fpvalid) + ++num_pr_fpvalid; + break; + } +#if defined(__i386__) || defined(__x86_64__) + case NT_FPREGSET: { + EXPECT_TRUE(description.data() != NULL); + EXPECT_EQ(sizeof(user_fpregs_struct), description.length()); + ++num_nt_fpregset; + break; + } +#endif +#if defined(__i386__) + case NT_PRXFPREG: { + EXPECT_TRUE(description.data() != NULL); + EXPECT_EQ(sizeof(user_fpxregs_struct), description.length()); + ++num_nt_prxfpreg; + break; + } +#endif + default: + break; + } + note = note.GetNextNote(); + } + +#if defined(THREAD_SANITIZER) + for (std::set::const_iterator expected = expected_thread_ids.begin(); + expected != expected_thread_ids.end(); + ++expected) { + EXPECT_NE(actual_thread_ids.find(*expected), actual_thread_ids.end()); + } + EXPECT_GE(num_nt_prstatus, kNumOfThreads); +#else + EXPECT_EQ(actual_thread_ids, expected_thread_ids); + EXPECT_EQ(num_nt_prstatus, kNumOfThreads); +#endif + EXPECT_EQ(1U, num_nt_prpsinfo); +#if defined(__i386__) || defined(__x86_64__) + EXPECT_EQ(num_pr_fpvalid, num_nt_fpregset); +#endif +#if defined(__i386__) + EXPECT_EQ(num_pr_fpvalid, num_nt_prxfpreg); +#endif +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h new file mode 100644 index 0000000000..0a3dfedb57 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h @@ -0,0 +1,51 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2013, 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. + +// Original author: Lei Zhang + +// elf_gnu_compat.h: #defines unique to glibc's elf.h. + +#ifndef COMMON_LINUX_ELF_GNU_COMPAT_H_ +#define COMMON_LINUX_ELF_GNU_COMPAT_H_ + +#include + +// A note type on GNU systems corresponding to the .note.gnu.build-id section. +#ifndef NT_GNU_BUILD_ID +#define NT_GNU_BUILD_ID 3 +#endif + +// Newer Linux systems offer this. +#ifndef NT_SIGINFO +#define NT_SIGINFO 0x53494749 +#endif + +#endif // COMMON_LINUX_ELF_GNU_COMPAT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc new file mode 100644 index 0000000000..562875e11b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc @@ -0,0 +1,178 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek + +#include "common/linux/elf_symbols_to_module.h" + +#include +#include +#include + +#include "common/byte_cursor.h" +#include "common/module.h" + +namespace google_breakpad { + +class ELFSymbolIterator { +public: + // The contents of an ELF symbol, adjusted for the host's endianness, + // word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym. + struct Symbol { + // True if this iterator has reached the end of the symbol array. When + // this is set, the other members of this structure are not valid. + bool at_end; + + // The number of this symbol within the list. + size_t index; + + // The current symbol's name offset. This is the offset within the + // string table. + size_t name_offset; + + // The current symbol's value, size, info and shndx fields. + uint64_t value; + uint64_t size; + unsigned char info; + uint16_t shndx; + }; + + // Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the + // symbols as big-endian if BIG_ENDIAN is true, as little-endian + // otherwise. Assume each symbol has a 'value' field whose size is + // VALUE_SIZE. + // + ELFSymbolIterator(const ByteBuffer *buffer, bool big_endian, + size_t value_size) + : value_size_(value_size), cursor_(buffer, big_endian) { + // Actually, weird sizes could be handled just fine, but they're + // probably mistakes --- expressed in bits, say. + assert(value_size == 4 || value_size == 8); + symbol_.index = 0; + Fetch(); + } + + // Move to the next symbol. This function's behavior is undefined if + // at_end() is true when it is called. + ELFSymbolIterator &operator++() { Fetch(); symbol_.index++; return *this; } + + // Dereferencing this iterator produces a reference to an Symbol structure + // that holds the current symbol's values. The symbol is owned by this + // SymbolIterator, and will be invalidated at the next call to operator++. + const Symbol &operator*() const { return symbol_; } + const Symbol *operator->() const { return &symbol_; } + +private: + // Read the symbol at cursor_, and set symbol_ appropriately. + void Fetch() { + // Elf32_Sym and Elf64_Sym have different layouts. + unsigned char other; + if (value_size_ == 4) { + // Elf32_Sym + cursor_ + .Read(4, false, &symbol_.name_offset) + .Read(4, false, &symbol_.value) + .Read(4, false, &symbol_.size) + .Read(1, false, &symbol_.info) + .Read(1, false, &other) + .Read(2, false, &symbol_.shndx); + } else { + // Elf64_Sym + cursor_ + .Read(4, false, &symbol_.name_offset) + .Read(1, false, &symbol_.info) + .Read(1, false, &other) + .Read(2, false, &symbol_.shndx) + .Read(8, false, &symbol_.value) + .Read(8, false, &symbol_.size); + } + symbol_.at_end = !cursor_; + } + + // The size of symbols' value field, in bytes. + size_t value_size_; + + // A byte cursor traversing buffer_. + ByteCursor cursor_; + + // Values for the symbol this iterator refers to. + Symbol symbol_; +}; + +const char *SymbolString(ptrdiff_t offset, ByteBuffer& strings) { + if (offset < 0 || (size_t) offset >= strings.Size()) { + // Return the null string. + offset = 0; + } + return reinterpret_cast(strings.start + offset); +} + +bool ELFSymbolsToModule(const uint8_t *symtab_section, + size_t symtab_size, + const uint8_t *string_section, + size_t string_size, + const bool big_endian, + size_t value_size, + Module *module) { + ByteBuffer symbols(symtab_section, symtab_size); + // Ensure that the string section is null-terminated. + if (string_section[string_size - 1] != '\0') { + const void* null_terminator = memrchr(string_section, '\0', string_size); + string_size = reinterpret_cast(null_terminator) + - string_section; + } + ByteBuffer strings(string_section, string_size); + + // The iterator walking the symbol table. + ELFSymbolIterator iterator(&symbols, big_endian, value_size); + + while(!iterator->at_end) { + if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && + iterator->shndx != SHN_UNDEF) { + Module::Extern *ext = new Module::Extern(iterator->value); + ext->name = SymbolString(iterator->name_offset, strings); +#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. + int status = 0; + char* demangled = + abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status); + if (demangled) { + if (status == 0) + ext->name = demangled; + free(demangled); + } +#endif + module->AddExtern(ext); + } + ++iterator; + } + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h new file mode 100644 index 0000000000..2e7c097151 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h @@ -0,0 +1,58 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek + +// elf_symbols_to_module.h: Exposes ELFSymbolsToModule, a function +// for reading ELF symbol tables and inserting exported symbol names +// into a google_breakpad::Module as Extern definitions. + +#ifndef BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ +#define BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ + +#include +#include + +namespace google_breakpad { + +class Module; + +bool ELFSymbolsToModule(const uint8_t *symtab_section, + size_t symtab_size, + const uint8_t *string_section, + size_t string_size, + const bool big_endian, + size_t value_size, + Module *module); + +} // namespace google_breakpad + + +#endif // BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc new file mode 100644 index 0000000000..8984449ab6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc @@ -0,0 +1,370 @@ +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek + +// elf_symbols_to_module_unittest.cc: +// Unittests for google_breakpad::ELFSymbolsToModule + +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/elf_symbols_to_module.h" +#include "common/linux/synth_elf.h" +#include "common/module.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" + +using google_breakpad::Module; +using google_breakpad::synth_elf::StringTable; +using google_breakpad::test_assembler::Endianness; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using ::testing::Test; +using ::testing::TestWithParam; +using std::vector; + +class ELFSymbolsToModuleTestFixture { +public: + ELFSymbolsToModuleTestFixture(Endianness endianness, + size_t value_size) : module("a", "b", "c", "d"), + section(endianness), + table(endianness), + value_size(value_size) {} + + bool ProcessSection() { + string section_contents, table_contents; + section.GetContents(§ion_contents); + table.GetContents(&table_contents); + + bool ret = ELFSymbolsToModule(reinterpret_cast(section_contents.data()), + section_contents.size(), + reinterpret_cast(table_contents.data()), + table_contents.size(), + section.endianness() == kBigEndian, + value_size, + &module); + module.GetExterns(&externs, externs.end()); + return ret; + } + + Module module; + Section section; + StringTable table; + string section_contents; + // 4 or 8 (bytes) + size_t value_size; + + vector externs; +}; + +class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture, + public TestWithParam { +public: + ELFSymbolsToModuleTest32() : ELFSymbolsToModuleTestFixture(GetParam(), 4) {} + + void AddElf32Sym(const string& name, uint32_t value, + uint32_t size, unsigned info, uint16_t shndx) { + section + .D32(table.Add(name)) + .D32(value) + .D32(size) + .D8(info) + .D8(0) // other + .D16(shndx); + } +}; + +TEST_P(ELFSymbolsToModuleTest32, NoFuncs) { + ProcessSection(); + + ASSERT_EQ((size_t)0, externs.size()); +} + +TEST_P(ELFSymbolsToModuleTest32, OneFunc) { + const string kFuncName = "superfunc"; + const uint32_t kFuncAddr = 0x1000; + const uint32_t kFuncSize = 0x10; + + AddElf32Sym(kFuncName, kFuncAddr, kFuncSize, + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +TEST_P(ELFSymbolsToModuleTest32, NameOutOfBounds) { + const string kFuncName = ""; + const uint32_t kFuncAddr = 0x1000; + const uint32_t kFuncSize = 0x10; + + table.Add("Foo"); + table.Add("Bar"); + // Can't use AddElf32Sym because it puts in a valid string offset. + section + .D32((uint32_t)table.Here().Value() + 1) + .D32(kFuncAddr) + .D32(kFuncSize) + .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) + .D8(0) // other + .D16(SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +TEST_P(ELFSymbolsToModuleTest32, NonTerminatedStringTable) { + const string kFuncName = ""; + const uint32_t kFuncAddr = 0x1000; + const uint32_t kFuncSize = 0x10; + + table.Add("Foo"); + table.Add("Bar"); + // Add a non-null-terminated string to the end of the string table + Label l; + table + .Mark(&l) + .Append("Unterminated"); + // Can't use AddElf32Sym because it puts in a valid string offset. + section + .D32((uint32_t)l.Value()) + .D32(kFuncAddr) + .D32(kFuncSize) + .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) + .D8(0) // other + .D16(SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +TEST_P(ELFSymbolsToModuleTest32, MultipleFuncs) { + const string kFuncName1 = "superfunc"; + const uint32_t kFuncAddr1 = 0x10001000; + const uint32_t kFuncSize1 = 0x10; + const string kFuncName2 = "awesomefunc"; + const uint32_t kFuncAddr2 = 0x20002000; + const uint32_t kFuncSize2 = 0x2f; + const string kFuncName3 = "megafunc"; + const uint32_t kFuncAddr3 = 0x30003000; + const uint32_t kFuncSize3 = 0x3c; + + AddElf32Sym(kFuncName1, kFuncAddr1, kFuncSize1, + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + AddElf32Sym(kFuncName2, kFuncAddr2, kFuncSize2, + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 2); + AddElf32Sym(kFuncName3, kFuncAddr3, kFuncSize3, + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 3); + + ProcessSection(); + + ASSERT_EQ((size_t)3, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName1, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address); + Module::Extern *extern2 = externs[1]; + EXPECT_EQ(kFuncName2, extern2->name); + EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address); + Module::Extern *extern3 = externs[2]; + EXPECT_EQ(kFuncName3, extern3->name); + EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address); +} + +TEST_P(ELFSymbolsToModuleTest32, SkipStuff) { + const string kFuncName = "superfunc"; + const uint32_t kFuncAddr = 0x1000; + const uint32_t kFuncSize = 0x10; + + // Should skip functions in SHN_UNDEF + AddElf32Sym("skipme", 0xFFFF, 0x10, + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF); + AddElf32Sym(kFuncName, kFuncAddr, kFuncSize, + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + // Should skip non-STT_FUNC entries. + AddElf32Sym("skipmetoo", 0xAAAA, 0x10, + ELF32_ST_INFO(STB_GLOBAL, STT_FILE), + SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +// Run all the 32-bit tests with both endianness +INSTANTIATE_TEST_CASE_P(Endian, + ELFSymbolsToModuleTest32, + ::testing::Values(kLittleEndian, kBigEndian)); + +// Similar tests, but with 64-bit values. Ostensibly this could be +// shoehorned into the parameterization by using ::testing::Combine, +// but that would make it difficult to get the types right since these +// actual test cases aren't parameterized. This could also be written +// as a type-parameterized test, but combining that with a value-parameterized +// test seemed really ugly, and also makes it harder to test 64-bit +// values. +class ELFSymbolsToModuleTest64 : public ELFSymbolsToModuleTestFixture, + public TestWithParam { +public: + ELFSymbolsToModuleTest64() : ELFSymbolsToModuleTestFixture(GetParam(), 8) {} + + void AddElf64Sym(const string& name, uint64_t value, + uint64_t size, unsigned info, uint16_t shndx) { + section + .D32(table.Add(name)) + .D8(info) + .D8(0) // other + .D16(shndx) + .D64(value) + .D64(size); + } +}; + +TEST_P(ELFSymbolsToModuleTest64, NoFuncs) { + ProcessSection(); + + ASSERT_EQ((size_t)0, externs.size()); +} + +TEST_P(ELFSymbolsToModuleTest64, OneFunc) { + const string kFuncName = "superfunc"; + const uint64_t kFuncAddr = 0x1000200030004000ULL; + const uint64_t kFuncSize = 0x1000; + + AddElf64Sym(kFuncName, kFuncAddr, kFuncSize, + ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +TEST_P(ELFSymbolsToModuleTest64, MultipleFuncs) { + const string kFuncName1 = "superfunc"; + const uint64_t kFuncAddr1 = 0x1000100010001000ULL; + const uint64_t kFuncSize1 = 0x1000; + const string kFuncName2 = "awesomefunc"; + const uint64_t kFuncAddr2 = 0x2000200020002000ULL; + const uint64_t kFuncSize2 = 0x2f00; + const string kFuncName3 = "megafunc"; + const uint64_t kFuncAddr3 = 0x3000300030003000ULL; + const uint64_t kFuncSize3 = 0x3c00; + + AddElf64Sym(kFuncName1, kFuncAddr1, kFuncSize1, + ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + AddElf64Sym(kFuncName2, kFuncAddr2, kFuncSize2, + ELF64_ST_INFO(STB_LOCAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 2); + AddElf64Sym(kFuncName3, kFuncAddr3, kFuncSize3, + ELF64_ST_INFO(STB_LOCAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 3); + + ProcessSection(); + + ASSERT_EQ((size_t)3, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName1, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address); + Module::Extern *extern2 = externs[1]; + EXPECT_EQ(kFuncName2, extern2->name); + EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address); + Module::Extern *extern3 = externs[2]; + EXPECT_EQ(kFuncName3, extern3->name); + EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address); +} + +TEST_P(ELFSymbolsToModuleTest64, SkipStuff) { + const string kFuncName = "superfunc"; + const uint64_t kFuncAddr = 0x1000100010001000ULL; + const uint64_t kFuncSize = 0x1000; + + // Should skip functions in SHN_UNDEF + AddElf64Sym("skipme", 0xFFFF, 0x10, + ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF); + AddElf64Sym(kFuncName, kFuncAddr, kFuncSize, + ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), + // Doesn't really matter, just can't be SHN_UNDEF. + SHN_UNDEF + 1); + // Should skip non-STT_FUNC entries. + AddElf64Sym("skipmetoo", 0xAAAA, 0x10, + ELF64_ST_INFO(STB_GLOBAL, STT_FILE), + SHN_UNDEF + 1); + + ProcessSection(); + + ASSERT_EQ((size_t)1, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_EQ(kFuncName, extern1->name); + EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); +} + +// Run all the 64-bit tests with both endianness +INSTANTIATE_TEST_CASE_P(Endian, + ELFSymbolsToModuleTest64, + ::testing::Values(kLittleEndian, kBigEndian)); diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h new file mode 100644 index 0000000000..e56b37a9f5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h @@ -0,0 +1,74 @@ +// Copyright (c) 2012, 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 COMMON_LINUX_ELFUTILS_INL_H__ +#define COMMON_LINUX_ELFUTILS_INL_H__ + +#include "common/linux/linux_libc_support.h" +#include "elfutils.h" + +namespace google_breakpad { + +template +const T* GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset) { + return reinterpret_cast(reinterpret_cast(elf_header) + + offset); +} + +template +const typename ElfClass::Shdr* FindElfSectionByName( + const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection) { + assert(name != NULL); + assert(sections != NULL); + assert(nsection > 0); + + int name_len = my_strlen(name); + if (name_len == 0) + return NULL; + + for (int i = 0; i < nsection; ++i) { + const char* section_name = section_names + sections[i].sh_name; + if (sections[i].sh_type == section_type && + names_end - section_name >= name_len + 1 && + my_strcmp(name, section_name) == 0) { + return sections + i; + } + } + return NULL; +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc new file mode 100644 index 0000000000..e2e16e6dfd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2012, 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 "common/linux/elfutils.h" + +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "common/linux/elfutils-inl.h" + +#if defined(__FreeBSD__) +# define ElfW(type) Elf_##type +#endif + +namespace google_breakpad { + +namespace { + +template +void FindElfClassSection(const char *elf_base, + const char *section_name, + typename ElfClass::Word section_type, + const void **section_start, + size_t *section_size) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Shdr Shdr; + + assert(elf_base); + assert(section_start); + assert(section_size); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Shdr* sections = + GetOffset(elf_header, elf_header->e_shoff); + const Shdr* section_names = sections + elf_header->e_shstrndx; + const char* names = + GetOffset(elf_header, section_names->sh_offset); + const char *names_end = names + section_names->sh_size; + + const Shdr* section = + FindElfSectionByName(section_name, section_type, + sections, names, names_end, + elf_header->e_shnum); + + if (section != NULL && section->sh_size > 0) { + *section_start = elf_base + section->sh_offset; + *section_size = section->sh_size; + } +} + +template +void FindElfClassSegment(const char *elf_base, + typename ElfClass::Word segment_type, + wasteful_vector *segments) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Phdr Phdr; + + assert(elf_base); + assert(segments); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Phdr* phdrs = + GetOffset(elf_header, elf_header->e_phoff); + + for (int i = 0; i < elf_header->e_phnum; ++i) { + if (phdrs[i].p_type == segment_type) { + ElfSegment seg = {}; + seg.start = elf_base + phdrs[i].p_offset; + seg.size = phdrs[i].p_filesz; + segments->push_back(seg); + } + } +} + +} // namespace + +bool IsValidElf(const void* elf_base) { + return my_strncmp(reinterpret_cast(elf_base), + ELFMAG, SELFMAG) == 0; +} + +int ElfClass(const void* elf_base) { + const ElfW(Ehdr)* elf_header = + reinterpret_cast(elf_base); + + return elf_header->e_ident[EI_CLASS]; +} + +bool FindElfSection(const void *elf_mapped_base, + const char *section_name, + uint32_t section_type, + const void **section_start, + size_t *section_size) { + assert(elf_mapped_base); + assert(section_start); + assert(section_size); + + *section_start = NULL; + *section_size = 0; + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + const char* elf_base = + static_cast(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSection(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } else if (cls == ELFCLASS64) { + FindElfClassSection(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } + + return false; +} + +bool FindElfSegments(const void* elf_mapped_base, + uint32_t segment_type, + wasteful_vector* segments) { + assert(elf_mapped_base); + assert(segments); + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + const char* elf_base = + static_cast(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSegment(elf_base, segment_type, segments); + return true; + } else if (cls == ELFCLASS64) { + FindElfClassSegment(elf_base, segment_type, segments); + return true; + } + + return false; +} + +template +bool FindElfSoNameFromDynamicSection(const void* section_start, + size_t section_size, + const void* dynstr_start, + size_t dynstr_size, + char* soname, + size_t soname_size) { + typedef typename ElfClass::Dyn Dyn; + + auto* dynamic = static_cast(section_start); + size_t dcount = section_size / sizeof(Dyn); + for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) { + if (dyn->d_tag == DT_SONAME) { + const char* dynstr = static_cast(dynstr_start); + if (dyn->d_un.d_val >= dynstr_size) { + // Beyond the end of the dynstr section + return false; + } + const char* str = dynstr + dyn->d_un.d_val; + const size_t maxsize = dynstr_size - dyn->d_un.d_val; + my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size); + return true; + } + } + + return false; +} + +bool ElfFileSoNameFromMappedFile(const void* elf_base, + char* soname, + size_t soname_size) { + if (!IsValidElf(elf_base)) { + // Not ELF + return false; + } + + const void* segment_start; + size_t segment_size; + if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start, + &segment_size)) { + // No dynamic section + return false; + } + + const void* dynstr_start; + size_t dynstr_size; + if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start, + &dynstr_size)) { + // No dynstr section + return false; + } + + int cls = ElfClass(elf_base); + return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection( + segment_start, segment_size, dynstr_start, + dynstr_size, soname, soname_size) + : FindElfSoNameFromDynamicSection( + segment_start, segment_size, dynstr_start, + dynstr_size, soname, soname_size); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h new file mode 100644 index 0000000000..aefb6cf5f8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h @@ -0,0 +1,135 @@ +// Copyright (c) 2012, 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. +// +// elfutils.h: Utilities for dealing with ELF files. +// + +#ifndef COMMON_LINUX_ELFUTILS_H_ +#define COMMON_LINUX_ELFUTILS_H_ + +#include +#include +#include + +#include "common/memory_allocator.h" + +namespace google_breakpad { + +// Traits classes so consumers can write templatized code to deal +// with specific ELF bits. +struct ElfClass32 { + typedef Elf32_Addr Addr; + typedef Elf32_Dyn Dyn; + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Nhdr Nhdr; + typedef Elf32_Phdr Phdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Half Half; + typedef Elf32_Off Off; + typedef Elf32_Sym Sym; + typedef Elf32_Word Word; + + static const int kClass = ELFCLASS32; + static const uint16_t kMachine = EM_386; + static const size_t kAddrSize = sizeof(Elf32_Addr); + static constexpr const char* kMachineName = "x86"; +}; + +struct ElfClass64 { + typedef Elf64_Addr Addr; + typedef Elf64_Dyn Dyn; + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Nhdr Nhdr; + typedef Elf64_Phdr Phdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Half Half; + typedef Elf64_Off Off; + typedef Elf64_Sym Sym; + typedef Elf64_Word Word; + + static const int kClass = ELFCLASS64; + static const uint16_t kMachine = EM_X86_64; + static const size_t kAddrSize = sizeof(Elf64_Addr); + static constexpr const char* kMachineName = "x86_64"; +}; + +bool IsValidElf(const void* elf_header); +int ElfClass(const void* elf_base); + +// Attempt to find a section named |section_name| of type |section_type| +// in the ELF binary data at |elf_mapped_base|. On success, returns true +// and sets |*section_start| to point to the start of the section data, +// and |*section_size| to the size of the section's data. +bool FindElfSection(const void *elf_mapped_base, + const char *section_name, + uint32_t section_type, + const void **section_start, + size_t *section_size); + +// Internal helper method, exposed for convenience for callers +// that already have more info. +template +const typename ElfClass::Shdr* +FindElfSectionByName(const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection); + +struct ElfSegment { + const void* start; + size_t size; +}; + +// Attempt to find all segments of type |segment_type| in the ELF +// binary data at |elf_mapped_base|. On success, returns true and fills +// |*segments| with a list of segments of the given type. +bool FindElfSegments(const void* elf_mapped_base, + uint32_t segment_type, + wasteful_vector* segments); + +// Convert an offset from an Elf header into a pointer to the mapped +// address in the current process. Takes an extra template parameter +// to specify the return type to avoid having to dynamic_cast the +// result. +template +const T* +GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset); + +// Read the value of DT_SONAME from the elf file mapped at |elf_base|. Returns +// true and fills |soname| with the result if found. +bool ElfFileSoNameFromMappedFile(const void* elf_base, + char* soname, + size_t soname_size); + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc new file mode 100644 index 0000000000..701a4f070f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc @@ -0,0 +1,200 @@ +// 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. +// +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// + +#include "common/linux/file_id.h" + +#include +#include +#include + +#include +#include + +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" +#include "common/linux/linux_libc_support.h" +#include "common/linux/memory_mapped_file.h" +#include "common/using_std_string.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// Used in a few places for backwards-compatibility. +const size_t kMDGUIDSize = sizeof(MDGUID); + +FileID::FileID(const char* path) : path_(path) {} + +// ELF note name and desc are 32-bits word padded. +#define NOTE_PADDING(a) ((a + 3) & ~3) + +// These functions are also used inside the crashed process, so be safe +// and use the syscall/libc wrappers instead of direct syscalls or libc. + +static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, + wasteful_vector& identifier) { + static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr), + "Elf32_Nhdr and Elf64_Nhdr should be the same"); + typedef typename ElfClass32::Nhdr Nhdr; + + const void* section_end = reinterpret_cast(section) + length; + const Nhdr* note_header = reinterpret_cast(section); + while (reinterpret_cast(note_header) < section_end) { + if (note_header->n_type == NT_GNU_BUILD_ID) + break; + note_header = reinterpret_cast( + reinterpret_cast(note_header) + sizeof(Nhdr) + + NOTE_PADDING(note_header->n_namesz) + + NOTE_PADDING(note_header->n_descsz)); + } + if (reinterpret_cast(note_header) >= section_end || + note_header->n_descsz == 0) { + return false; + } + + const uint8_t* build_id = reinterpret_cast(note_header) + + sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); + identifier.insert(identifier.end(), + build_id, + build_id + note_header->n_descsz); + + return true; +} + +// Attempt to locate a .note.gnu.build-id section in an ELF binary +// and copy it into |identifier|. +static bool FindElfBuildIDNote(const void* elf_mapped_base, + wasteful_vector& identifier) { + PageAllocator allocator; + // lld normally creates 2 PT_NOTEs, gold normally creates 1. + auto_wasteful_vector segs(&allocator); + if (FindElfSegments(elf_mapped_base, PT_NOTE, &segs)) { + for (ElfSegment& seg : segs) { + if (ElfClassBuildIDNoteIdentifier(seg.start, seg.size, identifier)) { + return true; + } + } + } + + void* note_section; + size_t note_size; + if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, + (const void**)¬e_section, ¬e_size)) { + return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier); + } + + return false; +} + +// Attempt to locate the .text section of an ELF binary and generate +// a simple hash by XORing the first page worth of bytes into |identifier|. +static bool HashElfTextSection(const void* elf_mapped_base, + wasteful_vector& identifier) { + void* text_section; + size_t text_size; + if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, + (const void**)&text_section, &text_size) || + text_size == 0) { + return false; + } + + // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this + // function backwards-compatible. + identifier.resize(kMDGUIDSize); + my_memset(&identifier[0], 0, kMDGUIDSize); + const uint8_t* ptr = reinterpret_cast(text_section); + const uint8_t* ptr_end = ptr + std::min(text_size, static_cast(4096)); + while (ptr < ptr_end) { + for (unsigned i = 0; i < kMDGUIDSize; i++) + identifier[i] ^= ptr[i]; + ptr += kMDGUIDSize; + } + return true; +} + +// static +bool FileID::ElfFileIdentifierFromMappedFile(const void* base, + wasteful_vector& identifier) { + // Look for a build id note first. + if (FindElfBuildIDNote(base, identifier)) + return true; + + // Fall back on hashing the first page of the text section. + return HashElfTextSection(base, identifier); +} + +bool FileID::ElfFileIdentifier(wasteful_vector& identifier) { + MemoryMappedFile mapped_file(path_.c_str(), 0); + if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? + return false; + + return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); +} + +// These three functions are not ever called in an unsafe context, so it's OK +// to allocate memory and use libc. +static string bytes_to_hex_string(const uint8_t* bytes, size_t count) { + string result; + for (unsigned int idx = 0; idx < count; ++idx) { + char buf[3]; + snprintf(buf, sizeof(buf), "%02X", bytes[idx]); + result.append(buf); + } + return result; +} + +// static +string FileID::ConvertIdentifierToUUIDString( + const wasteful_vector& identifier) { + uint8_t identifier_swapped[kMDGUIDSize] = { 0 }; + + // Endian-ness swap to match dump processor expectation. + memcpy(identifier_swapped, &identifier[0], + std::min(kMDGUIDSize, identifier.size())); + uint32_t* data1 = reinterpret_cast(identifier_swapped); + *data1 = htonl(*data1); + uint16_t* data2 = reinterpret_cast(identifier_swapped + 4); + *data2 = htons(*data2); + uint16_t* data3 = reinterpret_cast(identifier_swapped + 6); + *data3 = htons(*data3); + + return bytes_to_hex_string(identifier_swapped, kMDGUIDSize); +} + +// static +string FileID::ConvertIdentifierToString( + const wasteful_vector& identifier) { + return bytes_to_hex_string(&identifier[0], identifier.size()); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h new file mode 100644 index 0000000000..4aff021ded --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h @@ -0,0 +1,88 @@ +// 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. +// +// file_id.h: Return a unique identifier for a file +// + +#ifndef COMMON_LINUX_FILE_ID_H__ +#define COMMON_LINUX_FILE_ID_H__ + +#include +#include + +#include "common/linux/guid_creator.h" +#include "common/memory_allocator.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes, +// so this is enough to fit that, which most binaries will use. +// This is just a sensible default for auto_wasteful_vector so most +// callers can get away with stack allocation. +static const size_t kDefaultBuildIdSize = 20; + +class FileID { + public: + explicit FileID(const char* path); + ~FileID() {} + + // Load the identifier for the elf file path specified in the constructor into + // |identifier|. + // + // The current implementation will look for a .note.gnu.build-id + // section and use that as the file id, otherwise it falls back to + // XORing the first 4096 bytes of the .text section to generate an identifier. + bool ElfFileIdentifier(wasteful_vector& identifier); + + // Load the identifier for the elf file mapped into memory at |base| into + // |identifier|. Return false if the identifier could not be created for this + // file. + static bool ElfFileIdentifierFromMappedFile( + const void* base, + wasteful_vector& identifier); + + // Convert the |identifier| data to a string. The string will + // be formatted as a UUID in all uppercase without dashes. + // (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE). + static string ConvertIdentifierToUUIDString( + const wasteful_vector& identifier); + + // Convert the entire |identifier| data to a hex string. + static string ConvertIdentifierToString( + const wasteful_vector& identifier); + + private: + // Storage for the path specified + string path_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc new file mode 100644 index 0000000000..f4f9ac45ce --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc @@ -0,0 +1,372 @@ +// Copyright (c) 2010, 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. + +// Unit tests for FileID + +#include +#include + +#include +#include + +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" +#include "common/linux/file_id.h" +#include "common/linux/safe_readlink.h" +#include "common/linux/synth_elf.h" +#include "common/test_assembler.h" +#include "common/tests/auto_tempdir.h" +#include "common/using_std_string.h" +#include "breakpad_googletest_includes.h" + +using namespace google_breakpad; +using google_breakpad::synth_elf::ELF; +using google_breakpad::synth_elf::Notes; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Section; +using std::vector; +using ::testing::Types; + +namespace { + +// Simply calling Section::Append(size, byte) produces a uninteresting pattern +// that tends to get hashed to 0000...0000. This populates the section with +// data to produce better hashes. +void PopulateSection(Section* section, int size, int prime_number) { + for (int i = 0; i < size; i++) + section->Append(1, (i % prime_number) % 256); +} + +typedef wasteful_vector id_vector; + +} // namespace + +#ifndef __ANDROID__ +// This test is disabled on Android: It will always fail, since there is no +// 'strip' binary installed on test devices. +TEST(FileIDStripTest, StripSelf) { + // Calculate the File ID of this binary using + // FileID::ElfFileIdentifier, then make a copy of this binary, + // strip it, and ensure that the result is the same. + char exe_name[PATH_MAX]; + ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); + + // copy our binary to a temp file, and strip it + AutoTempDir temp_dir; + string templ = temp_dir.path() + "/file-id-unittest"; + char cmdline[4096]; + sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str()); + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; + sprintf(cmdline, "chmod u+w \"%s\"", templ.c_str()); + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; + sprintf(cmdline, "strip \"%s\"", templ.c_str()); + ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; + + PageAllocator allocator; + id_vector identifier1(&allocator, kDefaultBuildIdSize); + id_vector identifier2(&allocator, kDefaultBuildIdSize); + + FileID fileid1(exe_name); + EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1)); + FileID fileid2(templ.c_str()); + EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2)); + + string identifier_string1 = + FileID::ConvertIdentifierToUUIDString(identifier1); + string identifier_string2 = + FileID::ConvertIdentifierToUUIDString(identifier2); + EXPECT_EQ(identifier_string1, identifier_string2); +} +#endif // !__ANDROID__ + +template +class FileIDTest : public testing::Test { +public: + void GetElfContents(ELF& elf) { + string contents; + ASSERT_TRUE(elf.GetContents(&contents)); + ASSERT_LT(0U, contents.size()); + + elfdata_v.clear(); + elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); + elfdata = &elfdata_v[0]; + } + + id_vector make_vector() { + return id_vector(&allocator, kDefaultBuildIdSize); + } + + template + string get_file_id(const uint8_t (&data)[N]) { + id_vector expected_identifier(make_vector()); + expected_identifier.insert(expected_identifier.end(), + &data[0], + data + N); + return FileID::ConvertIdentifierToUUIDString(expected_identifier); + } + + vector elfdata_v; + uint8_t* elfdata; + PageAllocator allocator; +}; + +typedef Types ElfClasses; + +TYPED_TEST_SUITE(FileIDTest, ElfClasses); + +TYPED_TEST(FileIDTest, ElfClass) { + const char expected_identifier_string[] = + "80808080808000000000008080808080"; + const size_t kTextSectionSize = 128; + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + for (size_t i = 0; i < kTextSectionSize; ++i) { + text.D8(i * 3); + } + elf.AddSection(".text", text, SHT_PROGBITS); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +TYPED_TEST(FileIDTest, BuildID) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes(kLittleEndian); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +// Test that a build id note with fewer bytes than usual is handled. +TYPED_TEST(FileIDTest, BuildIDShort) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes(kLittleEndian); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +// Test that a build id note with more bytes than usual is handled. +TYPED_TEST(FileIDTest, BuildIDLong) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes(kLittleEndian); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +TYPED_TEST(FileIDTest, BuildIDPH) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes(kLittleEndian); + notes.AddNote(0, "Linux", + reinterpret_cast("\0x42\0x02\0\0"), 4); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + int note_idx = elf.AddSection(".note", notes, SHT_NOTE); + elf.AddSegment(note_idx, note_idx, PT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +TYPED_TEST(FileIDTest, BuildIDMultiplePH) { + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + const string expected_identifier_string = + this->get_file_id(kExpectedIdentifierBytes); + + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + Notes notes1(kLittleEndian); + notes1.AddNote(0, "Linux", + reinterpret_cast("\0x42\0x02\0\0"), 4); + Notes notes2(kLittleEndian); + notes2.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + int note1_idx = elf.AddSection(".note1", notes1, SHT_NOTE); + int note2_idx = elf.AddSection(".note2", notes2, SHT_NOTE); + elf.AddSegment(note1_idx, note1_idx, PT_NOTE); + elf.AddSegment(note2_idx, note2_idx, PT_NOTE); + elf.Finish(); + this->GetElfContents(elf); + + id_vector identifier(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier)); + EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); + + string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); + EXPECT_EQ(expected_identifier_string, identifier_string); +} + +// Test to make sure two files with different text sections produce +// different hashes when not using a build id. +TYPED_TEST(FileIDTest, UniqueHashes) { + { + ELF elf1(EM_386, TypeParam::kClass, kLittleEndian); + Section foo_1(kLittleEndian); + PopulateSection(&foo_1, 32, 5); + elf1.AddSection(".foo", foo_1, SHT_PROGBITS); + Section text_1(kLittleEndian); + PopulateSection(&text_1, 4096, 17); + elf1.AddSection(".text", text_1, SHT_PROGBITS); + elf1.Finish(); + this->GetElfContents(elf1); + } + + id_vector identifier_1(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier_1)); + string identifier_string_1 = + FileID::ConvertIdentifierToUUIDString(identifier_1); + + { + ELF elf2(EM_386, TypeParam::kClass, kLittleEndian); + Section text_2(kLittleEndian); + Section foo_2(kLittleEndian); + PopulateSection(&foo_2, 32, 5); + elf2.AddSection(".foo", foo_2, SHT_PROGBITS); + PopulateSection(&text_2, 4096, 31); + elf2.AddSection(".text", text_2, SHT_PROGBITS); + elf2.Finish(); + this->GetElfContents(elf2); + } + + id_vector identifier_2(this->make_vector()); + EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, + identifier_2)); + string identifier_string_2 = + FileID::ConvertIdentifierToUUIDString(identifier_2); + + EXPECT_NE(identifier_string_1, identifier_string_2); +} + +TYPED_TEST(FileIDTest, ConvertIdentifierToString) { + const uint8_t kIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; + const char* kExpected = + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; + + id_vector identifier(this->make_vector()); + identifier.insert(identifier.end(), + kIdentifierBytes, + kIdentifierBytes + sizeof(kIdentifierBytes)); + ASSERT_EQ(kExpected, + FileID::ConvertIdentifierToString(identifier)); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc new file mode 100644 index 0000000000..a0d940b614 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc @@ -0,0 +1,207 @@ +// Copyright (c) 2009, 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 "common/linux/google_crashdump_uploader.h" + +#include +#include +#include + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword) { + LibcurlWrapper* http_layer = new LibcurlWrapper(); + Init(product, + version, + guid, + ptime, + ctime, + email, + comments, + minidump_pathname, + crash_server, + proxy_host, + proxy_userpassword, + http_layer); +} + +GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword, + LibcurlWrapper* http_layer) { + Init(product, + version, + guid, + ptime, + ctime, + email, + comments, + minidump_pathname, + crash_server, + proxy_host, + proxy_userpassword, + http_layer); +} + +void GoogleCrashdumpUploader::Init(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword, + LibcurlWrapper* http_layer) { + product_ = product; + version_ = version; + guid_ = guid; + ptime_ = ptime; + ctime_ = ctime; + email_ = email; + comments_ = comments; + http_layer_.reset(http_layer); + + crash_server_ = crash_server; + proxy_host_ = proxy_host; + proxy_userpassword_ = proxy_userpassword; + minidump_pathname_ = minidump_pathname; + std::cout << "Uploader initializing"; + std::cout << "\tProduct: " << product_; + std::cout << "\tVersion: " << version_; + std::cout << "\tGUID: " << guid_; + if (!ptime_.empty()) { + std::cout << "\tProcess uptime: " << ptime_; + } + if (!ctime_.empty()) { + std::cout << "\tCumulative Process uptime: " << ctime_; + } + if (!email_.empty()) { + std::cout << "\tEmail: " << email_; + } + if (!comments_.empty()) { + std::cout << "\tComments: " << comments_; + } +} + +bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() { + string error_text; + if (product_.empty()) { + error_text.append("\nProduct name must be specified."); + } + + if (version_.empty()) { + error_text.append("\nProduct version must be specified."); + } + + if (guid_.empty()) { + error_text.append("\nClient ID must be specified."); + } + + if (minidump_pathname_.empty()) { + error_text.append("\nMinidump pathname must be specified."); + } + + if (!error_text.empty()) { + std::cout << error_text; + return false; + } + return true; + +} + +bool GoogleCrashdumpUploader::Upload(int* http_status_code, + string* http_response_header, + string* http_response_body) { + bool ok = http_layer_->Init(); + if (!ok) { + std::cout << "http layer init failed"; + return ok; + } + + if (!CheckRequiredParametersArePresent()) { + return false; + } + + struct stat st; + int err = stat(minidump_pathname_.c_str(), &st); + if (err) { + std::cout << minidump_pathname_ << " could not be found"; + return false; + } + + parameters_["prod"] = product_; + parameters_["ver"] = version_; + parameters_["guid"] = guid_; + parameters_["ptime"] = ptime_; + parameters_["ctime"] = ctime_; + parameters_["email"] = email_; + parameters_["comments_"] = comments_; + if (!http_layer_->AddFile(minidump_pathname_, + "upload_file_minidump")) { + return false; + } + std::cout << "Sending request to " << crash_server_; + long status_code; + bool success = http_layer_->SendRequest(crash_server_, + parameters_, + &status_code, + http_response_header, + http_response_body); + if (http_status_code) { + *http_status_code = status_code; + } + return success; +} +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h new file mode 100644 index 0000000000..a2d0575b5e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h @@ -0,0 +1,107 @@ +// Copyright (c) 2009, 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 COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ +#define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ + +#include +#include + +#include "common/linux/libcurl_wrapper.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +class GoogleCrashdumpUploader { + public: + GoogleCrashdumpUploader(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword); + + GoogleCrashdumpUploader(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword, + LibcurlWrapper* http_layer); + + void Init(const string& product, + const string& version, + const string& guid, + const string& ptime, + const string& ctime, + const string& email, + const string& comments, + const string& minidump_pathname, + const string& crash_server, + const string& proxy_host, + const string& proxy_userpassword, + LibcurlWrapper* http_layer); + bool Upload(int* http_status_code, + string* http_response_header, + string* http_response_body); + + private: + bool CheckRequiredParametersArePresent(); + + scoped_ptr http_layer_; + string product_; + string version_; + string guid_; + string ptime_; + string ctime_; + string email_; + string comments_; + string minidump_pathname_; + + string crash_server_; + string proxy_host_; + string proxy_userpassword_; + + std::map parameters_; +}; +} + +#endif // COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc new file mode 100644 index 0000000000..3d6612e821 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc @@ -0,0 +1,170 @@ +// Copyright (c) 2009, 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. + +// Unit test for crash dump uploader. + +#include + +#include "common/linux/google_crashdump_uploader.h" +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using ::testing::Return; +using ::testing::_; + +class MockLibcurlWrapper : public LibcurlWrapper { + public: + MOCK_METHOD0(Init, bool()); + MOCK_METHOD2(SetProxy, bool(const string& proxy_host, + const string& proxy_userpwd)); + MOCK_METHOD2(AddFile, bool(const string& upload_file_path, + const string& basename)); + MOCK_METHOD5(SendRequest, + bool(const string& url, + const std::map& parameters, + long* http_status_code, + string* http_header_data, + string* http_response_data)); +}; + +class GoogleCrashdumpUploaderTest : public ::testing::Test { +}; + +TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) { + MockLibcurlWrapper m; + EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false)); + GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", + "1.0", + "AAA-BBB", + "", + "", + "test@test.com", + "none", + "/tmp/foo.dmp", + "http://foo.com", + "", + "", + &m); + ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); +} + +TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { + // Create a temp file + char tempfn[80] = "/tmp/googletest-upload-XXXXXX"; + int fd = mkstemp(tempfn); + ASSERT_NE(fd, -1); + close(fd); + + MockLibcurlWrapper m; + EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true)); + EXPECT_CALL(m, + SendRequest("http://foo.com",_,_,_,_)).Times(1).WillOnce(Return(true)); + GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", + "1.0", + "AAA-BBB", + "", + "", + "test@test.com", + "none", + tempfn, + "http://foo.com", + "", + "", + &m); + ASSERT_TRUE(uploader->Upload(NULL, NULL, NULL)); +} + + +TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { + MockLibcurlWrapper m; + EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(m, SendRequest(_,_,_,_,_)).Times(0); + GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", + "1.0", + "AAA-BBB", + "", + "", + "test@test.com", + "none", + "/tmp/foo.dmp", + "http://foo.com", + "", + "", + &m); + ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); +} + +TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { + // Test with empty product name. + GoogleCrashdumpUploader uploader("", + "1.0", + "AAA-BBB", + "", + "", + "test@test.com", + "none", + "/tmp/foo.dmp", + "http://foo.com", + "", + ""); + ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); + + // Test with empty product version. + GoogleCrashdumpUploader uploader1("product", + "", + "AAA-BBB", + "", + "", + "", + "", + "/tmp/foo.dmp", + "", + "", + ""); + + ASSERT_FALSE(uploader1.Upload(NULL, NULL, NULL)); + + // Test with empty client GUID. + GoogleCrashdumpUploader uploader2("product", + "1.0", + "", + "", + "", + "", + "", + "/tmp/foo.dmp", + "", + "", + ""); + ASSERT_FALSE(uploader2.Upload(NULL, NULL, NULL)); +} +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc new file mode 100644 index 0000000000..03e3d781fb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc @@ -0,0 +1,189 @@ +// 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. + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "common/linux/eintr_wrapper.h" +#include "common/linux/guid_creator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_SYS_RANDOM_H) +#include +#endif + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID since Linux has +// no native GUID generator. This should be OK since we don't expect +// crash to happen very offen. +// +class GUIDGenerator { + public: + static uint32_t BytesToUInt32(const uint8_t bytes[]) { + return ((uint32_t) bytes[0] + | ((uint32_t) bytes[1] << 8) + | ((uint32_t) bytes[2] << 16) + | ((uint32_t) bytes[3] << 24)); + } + + static void UInt32ToBytes(uint8_t bytes[], uint32_t n) { + bytes[0] = n & 0xff; + bytes[1] = (n >> 8) & 0xff; + bytes[2] = (n >> 16) & 0xff; + bytes[3] = (n >> 24) & 0xff; + } + + static bool CreateGUID(GUID *guid) { +#if defined(HAVE_ARC4RANDOM) // Android, BSD, ... + CreateGuidFromArc4Random(guid); +#else // Linux + bool success = false; + +#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) + success = CreateGUIDFromGetrandom(guid); +#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM + if (!success) { + success = CreateGUIDFromDevUrandom(guid); + } + + if (!success) { + CreateGUIDFromRand(guid); + success = true; + } +#endif + + // Put in the version according to RFC 4122. + guid->data3 &= 0x0fff; + guid->data3 |= 0x4000; + + // Put in the variant according to RFC 4122. + guid->data4[0] &= 0x3f; + guid->data4[0] |= 0x80; + + return true; + } + + private: +#ifdef HAVE_ARC4RANDOM + static void CreateGuidFromArc4Random(GUID *guid) { + char *buf = reinterpret_cast(guid); + + for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) { + uint32_t random_data = arc4random(); + + memcpy(buf + i, &random_data, sizeof(uint32_t)); + } + } +#else + static void InitOnce() { + pthread_once(&once_control, &InitOnceImpl); + } + + static void InitOnceImpl() { + // time(NULL) is a very poor seed, so lacking anything better mix an + // address into it. We drop the four rightmost bits as they're likely to + // be 0 on almost all architectures. + srand(time(NULL) | ((uintptr_t)&once_control >> 4)); + } + + static pthread_once_t once_control; + +#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) + static bool CreateGUIDFromGetrandom(GUID *guid) { + char *buf = reinterpret_cast(guid); + int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK); + + return (read_bytes == static_cast(sizeof(GUID))); + } +#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM + + // Populate the GUID using random bytes read from /dev/urandom, returns false + // if the GUID wasn't fully populated with random data. + static bool CreateGUIDFromDevUrandom(GUID *guid) { + char *buf = reinterpret_cast(guid); + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + + if (fd == -1) { + return false; + } + + ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID))); + close(fd); + + return (read_bytes == static_cast(sizeof(GUID))); + } + + // Populate the GUID using a stream of random bytes obtained from rand(). + static void CreateGUIDFromRand(GUID *guid) { + char *buf = reinterpret_cast(guid); + + InitOnce(); + + for (size_t i = 0; i < sizeof(GUID); i++) { + buf[i] = rand(); + } + } +#endif +}; + +#ifndef HAVE_ARC4RANDOM +pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; +#endif + +bool CreateGUID(GUID *guid) { + return GUIDGenerator::CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, int buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + GUIDGenerator::BytesToUInt32(&(guid->data4[0])), + GUIDGenerator::BytesToUInt32(&(guid->data4[4]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h new file mode 100644 index 0000000000..c86d856c4d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h @@ -0,0 +1,48 @@ +// 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 COMMON_LINUX_GUID_CREATOR_H__ +#define COMMON_LINUX_GUID_CREATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x" +// Length of GUID string. Don't count the ending '\0'. +#define kGUIDStringLength 36 + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, int buf_len); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc new file mode 100644 index 0000000000..0a1019dd0d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc @@ -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. + +#include "common/linux/http_upload.h" + +#include +#include +#include "third_party/curl/curl.h" + +namespace { + +// Callback to get the response data from server. +static size_t WriteCallback(void *ptr, size_t size, + size_t nmemb, void *userp) { + if (!userp) + return 0; + + string *response = reinterpret_cast(userp); + size_t real_size = size * nmemb; + response->append(reinterpret_cast(ptr), real_size); + return real_size; +} + +} // namespace + +namespace google_breakpad { + +static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; + +// static +bool HTTPUpload::SendRequest(const string &url, + const string ¶meters, + const map &files, + const string &proxy, + const string &proxy_user_pwd, + const string &ca_certificate_file, + string *response_body, + long *response_code, + string *error_description) { + if (response_code != NULL) + *response_code = 0; + + // We may have been linked statically; if curl_easy_init is in the + // current binary, no need to search for a dynamic version. + void* curl_lib = dlopen(NULL, RTLD_NOW); + if (!CheckCurlLib(curl_lib)) { + fprintf(stderr, + "Failed to open curl lib from binary, use libcurl.so instead\n"); + dlerror(); // Clear dlerror before attempting to open libraries. + dlclose(curl_lib); + curl_lib = NULL; + } + if (!curl_lib) { + curl_lib = dlopen("libcurl.so", RTLD_NOW); + } + if (!curl_lib) { + if (error_description != NULL) + *error_description = dlerror(); + curl_lib = dlopen("libcurl.so.4", RTLD_NOW); + } + if (!curl_lib) { + // Debian gives libcurl a different name when it is built against GnuTLS + // instead of OpenSSL. + curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_NOW); + } + if (!curl_lib) { + curl_lib = dlopen("libcurl.so.3", RTLD_NOW); + } + if (!curl_lib) { + return false; + } + + CURL* (*curl_easy_init)(void); + *(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init"); + CURL *curl = (*curl_easy_init)(); + if (error_description != NULL) + *error_description = "No Error"; + + if (!curl) { + dlclose(curl_lib); + return false; + } + + CURLcode err_code = CURLE_OK; + CURLcode (*curl_easy_setopt)(CURL *, CURLoption, ...); + *(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt"); + (*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str()); + (*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent); + // Support multithread by disabling timeout handling, would get SIGSEGV with + // Curl_resolv_timeout in stack trace otherwise. + // See https://curl.haxx.se/libcurl/c/threadsafe.html + (*curl_easy_setopt)(curl, CURLOPT_NOSIGNAL, 1); + // Set proxy information if necessary. + if (!proxy.empty()) + (*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str()); + if (!proxy_user_pwd.empty()) + (*curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str()); + + if (!ca_certificate_file.empty()) + (*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); + + struct curl_httppost *formpost = NULL; + struct curl_httppost *lastptr = NULL; + // Add form data. + CURLFORMcode (*curl_formadd)(struct curl_httppost **, struct curl_httppost **, ...); + *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); + (*curl_formadd)(&formpost, &lastptr, CURLFORM_COPYNAME, "extra", + CURLFORM_BUFFER, "extra.json", CURLFORM_BUFFERPTR, + parameters.c_str(), CURLFORM_BUFFERLENGTH, + parameters.length(), CURLFORM_CONTENTTYPE, "application/json", + CURLFORM_END); + + // Add form files. + map::const_iterator iter = files.begin(); + for (iter = files.begin(); iter != files.end(); ++iter) { + (*curl_formadd)(&formpost, &lastptr, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_FILE, iter->second.c_str(), + CURLFORM_END); + } + + (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost); + + // Disable 100-continue header. + struct curl_slist *headerlist = NULL; + char buf[] = "Expect:"; + struct curl_slist* (*curl_slist_append)(struct curl_slist *, const char *); + *(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append"); + headerlist = (*curl_slist_append)(headerlist, buf); + (*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist); + + if (response_body != NULL) { + (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA, + reinterpret_cast(response_body)); + } + + // Fail if 400+ is returned from the web server. + (*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1); + + CURLcode (*curl_easy_perform)(CURL *); + *(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform"); + err_code = (*curl_easy_perform)(curl); + if (response_code != NULL) { + CURLcode (*curl_easy_getinfo)(CURL *, CURLINFO, ...); + *(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo"); + (*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code); + } + const char* (*curl_easy_strerror)(CURLcode); + *(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror"); +#ifndef NDEBUG + if (err_code != CURLE_OK) + fprintf(stderr, "Failed to send http request to %s, error: %s\n", + url.c_str(), + (*curl_easy_strerror)(err_code)); +#endif + if (error_description != NULL) + *error_description = (*curl_easy_strerror)(err_code); + + void (*curl_easy_cleanup)(CURL *); + *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup"); + (*curl_easy_cleanup)(curl); + if (formpost != NULL) { + void (*curl_formfree)(struct curl_httppost *); + *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree"); + (*curl_formfree)(formpost); + } + if (headerlist != NULL) { + void (*curl_slist_free_all)(struct curl_slist *); + *(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all"); + (*curl_slist_free_all)(headerlist); + } + dlclose(curl_lib); + return err_code == CURLE_OK; +} + +// static +bool HTTPUpload::CheckCurlLib(void* curl_lib) { + return curl_lib && + dlsym(curl_lib, "curl_easy_init") && + dlsym(curl_lib, "curl_easy_setopt"); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h new file mode 100644 index 0000000000..95dedebc3b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.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. + +// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST +// request using libcurl. It currently supports requests that contain +// parameters encoded in a JSON string, and a file to upload. + +#ifndef COMMON_LINUX_HTTP_UPLOAD_H__ +#define COMMON_LINUX_HTTP_UPLOAD_H__ + +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::map; + +class HTTPUpload { + public: + // Sends the given sets of parameters and files as a multipart POST + // request to the given URL. + // Each key in |files| is the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an . + // Parameters are specified as a JSON-encoded string in |parameters|. + // 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). + // If the send fails, a description of the error will be + // returned in error_description. + static bool SendRequest(const string &url, + const string ¶meters, + const map &files, + const string &proxy, + const string &proxy_user_pwd, + const string &ca_certificate_file, + string *response_body, + long *response_code, + string *error_description); + + private: + // Checks the curl_lib parameter points to a valid curl lib. + static bool CheckCurlLib(void* curl_lib); + + // 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 + +#endif // COMMON_LINUX_HTTP_UPLOAD_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h b/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h new file mode 100644 index 0000000000..efd274c20c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 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 COMMON_LINUX_IGNORE_RET_H_ +#define COMMON_LINUX_IGNORE_RET_H_ + +// Some compilers are prone to warn about unused return values. In cases where +// either a) the call cannot fail, or b) there is nothing that can be done when +// the call fails, IGNORE_RET() can be used to mark the return code as ignored. +// This avoids spurious compiler warnings. + +#define IGNORE_RET(x) do { if (x) {} } while (0) + +#endif // COMMON_LINUX_IGNORE_RET_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc new file mode 100644 index 0000000000..e96c203852 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2009, 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 + +#include +#include + +#include "common/linux/libcurl_wrapper.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +LibcurlWrapper::LibcurlWrapper() + : init_ok_(false), + curl_lib_(nullptr), + last_curl_error_(""), + curl_(nullptr), + formpost_(nullptr), + lastptr_(nullptr), + headerlist_(nullptr) {} + +LibcurlWrapper::~LibcurlWrapper() { + if (init_ok_) { + (*easy_cleanup_)(curl_); + dlclose(curl_lib_); + } +} + +bool LibcurlWrapper::SetProxy(const string& proxy_host, + const string& proxy_userpwd) { + if (!CheckInit()) return false; + + // Set proxy information if necessary. + if (!proxy_host.empty()) { + (*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str()); + } else { + std::cout << "SetProxy called with empty proxy host."; + return false; + } + if (!proxy_userpwd.empty()) { + (*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str()); + } else { + std::cout << "SetProxy called with empty proxy username/password."; + return false; + } + std::cout << "Set proxy host to " << proxy_host; + return true; +} + +bool LibcurlWrapper::AddFile(const string& upload_file_path, + const string& basename) { + if (!CheckInit()) return false; + + std::cout << "Adding " << upload_file_path << " to form upload."; + // Add form file. + (*formadd_)(&formpost_, &lastptr_, + CURLFORM_COPYNAME, basename.c_str(), + CURLFORM_FILE, upload_file_path.c_str(), + CURLFORM_END); + + return true; +} + +// Callback to get the response data from server. +static size_t WriteCallback(void *ptr, size_t size, + size_t nmemb, void *userp) { + if (!userp) + return 0; + + string *response = reinterpret_cast(userp); + size_t real_size = size * nmemb; + response->append(reinterpret_cast(ptr), real_size); + return real_size; +} + +bool LibcurlWrapper::SendRequest(const string& url, + const std::map& parameters, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + std::map::const_iterator iter = parameters.begin(); + for (; iter != parameters.end(); ++iter) + (*formadd_)(&formpost_, &lastptr_, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_COPYCONTENTS, iter->second.c_str(), + CURLFORM_END); + + (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::SendGetRequest(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + (*easy_setopt_)(curl_, CURLOPT_HTTPGET, 1L); + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::SendPutRequest(const string& url, + const string& path, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + FILE* file = fopen(path.c_str(), "rb"); + (*easy_setopt_)(curl_, CURLOPT_UPLOAD, 1L); + (*easy_setopt_)(curl_, CURLOPT_PUT, 1L); + (*easy_setopt_)(curl_, CURLOPT_READDATA, file); + + bool success = SendRequestInner(url, http_status_code, http_header_data, + http_response_data); + + fclose(file); + return success; +} + +bool LibcurlWrapper::SendSimplePostRequest(const string& url, + const string& body, + const string& content_type, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + (*easy_setopt_)(curl_, CURLOPT_POSTFIELDSIZE, body.size()); + (*easy_setopt_)(curl_, CURLOPT_COPYPOSTFIELDS, body.c_str()); + + if (!content_type.empty()) { + string content_type_header = "Content-Type: " + content_type; + headerlist_ = (*slist_append_)( + headerlist_, + content_type_header.c_str()); + } + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::Init() { + // First check to see if libcurl was statically linked: + curl_lib_ = dlopen(nullptr, RTLD_NOW); + if (curl_lib_ && + (!dlsym(curl_lib_, "curl_easy_init") || + !dlsym(curl_lib_, "curl_easy_setopt"))) { + // Not statically linked, try again below. + dlerror(); // Clear dlerror before attempting to open libraries. + dlclose(curl_lib_); + curl_lib_ = nullptr; + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so", RTLD_NOW); + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW); + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW); + } + if (!curl_lib_) { + std::cout << "Could not find libcurl via dlopen"; + return false; + } + + if (!SetFunctionPointers()) { + std::cout << "Could not find function pointers"; + return false; + } + + curl_ = (*easy_init_)(); + + last_curl_error_ = "No Error"; + + if (!curl_) { + dlclose(curl_lib_); + std::cout << "Curl initialization failed"; + return false; + } + + init_ok_ = true; + return true; +} + +#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ + var = reinterpret_cast(dlsym(curl_lib_, function_name)); \ + if (!var) { \ + std::cout << "Could not find libcurl function " << function_name; \ + init_ok_ = false; \ + return false; \ + } + +bool LibcurlWrapper::SetFunctionPointers() { + + SET_AND_CHECK_FUNCTION_POINTER(easy_init_, + "curl_easy_init", + CURL*(*)()); + + SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, + "curl_easy_setopt", + CURLcode(*)(CURL*, CURLoption, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd", + CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", + curl_slist*(*)(curl_slist*, const char*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, + "curl_easy_perform", + CURLcode(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, + "curl_easy_cleanup", + void(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, + "curl_easy_getinfo", + CURLcode(*)(CURL *, CURLINFO info, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_reset_, + "curl_easy_reset", + void(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, + "curl_slist_free_all", + void(*)(curl_slist*)); + + SET_AND_CHECK_FUNCTION_POINTER(formfree_, + "curl_formfree", + void(*)(curl_httppost*)); + return true; +} + +bool LibcurlWrapper::SendRequestInner(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + string url_copy(url); + (*easy_setopt_)(curl_, CURLOPT_URL, url_copy.c_str()); + + // Disable 100-continue header. + char buf[] = "Expect:"; + headerlist_ = (*slist_append_)(headerlist_, buf); + (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); + + if (http_response_data != nullptr) { + http_response_data->clear(); + (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); + (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, + reinterpret_cast(http_response_data)); + } + if (http_header_data != nullptr) { + http_header_data->clear(); + (*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback); + (*easy_setopt_)(curl_, CURLOPT_HEADERDATA, + reinterpret_cast(http_header_data)); + } + CURLcode err_code = CURLE_OK; + err_code = (*easy_perform_)(curl_); + easy_strerror_ = reinterpret_cast + (dlsym(curl_lib_, "curl_easy_strerror")); + + if (http_status_code != nullptr) { + (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); + } + +#ifndef NDEBUG + if (err_code != CURLE_OK) + fprintf(stderr, "Failed to send http request to %s, error: %s\n", + url.c_str(), + (*easy_strerror_)(err_code)); +#endif + + Reset(); + + return err_code == CURLE_OK; +} + +void LibcurlWrapper::Reset() { + if (headerlist_ != nullptr) { + (*slist_free_all_)(headerlist_); + headerlist_ = nullptr; + } + + if (formpost_ != nullptr) { + (*formfree_)(formpost_); + formpost_ = nullptr; + } + + (*easy_reset_)(curl_); +} + +bool LibcurlWrapper::CheckInit() { + if (!init_ok_) { + std::cout << "LibcurlWrapper: You must call Init(), and have it return " + "'true' before invoking any other methods.\n"; + return false; + } + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h new file mode 100644 index 0000000000..77aa6cbb72 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h @@ -0,0 +1,119 @@ +// Copyright (c) 2009, 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 wrapper for libcurl to do HTTP Uploads, to support easy mocking +// and unit testing of the HTTPUpload class. + +#ifndef COMMON_LINUX_LIBCURL_WRAPPER_H_ +#define COMMON_LINUX_LIBCURL_WRAPPER_H_ + +#include +#include + +#include "common/using_std_string.h" +#include "third_party/curl/curl.h" + +namespace google_breakpad { +class LibcurlWrapper { + public: + LibcurlWrapper(); + virtual ~LibcurlWrapper(); + virtual bool Init(); + virtual bool SetProxy(const string& proxy_host, + const string& proxy_userpwd); + virtual bool AddFile(const string& upload_file_path, + const string& basename); + virtual bool SendRequest(const string& url, + const std::map& parameters, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendGetRequest(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendPutRequest(const string& url, + const string& path, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendSimplePostRequest(const string& url, + const string& body, + const string& content_type, + long* http_status_code, + string* http_header_data, + string* http_response_data); + + private: + // This function initializes class state corresponding to function + // pointers into the CURL library. + bool SetFunctionPointers(); + + bool SendRequestInner(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data); + + void Reset(); + + bool CheckInit(); + + bool init_ok_; // Whether init succeeded + void* curl_lib_; // Pointer to result of dlopen() on + // curl library + string last_curl_error_; // The text of the last error when + // dealing + // with CURL. + + CURL *curl_; // Pointer for handle for CURL calls. + + CURL* (*easy_init_)(void); + + // Stateful pointers for calling into curl_formadd() + struct curl_httppost *formpost_; + struct curl_httppost *lastptr_; + struct curl_slist *headerlist_; + + // Function pointers into CURL library + CURLcode (*easy_setopt_)(CURL *, CURLoption, ...); + CURLFORMcode (*formadd_)(struct curl_httppost **, + struct curl_httppost **, ...); + struct curl_slist* (*slist_append_)(struct curl_slist *, const char *); + void (*slist_free_all_)(struct curl_slist *); + CURLcode (*easy_perform_)(CURL *); + const char* (*easy_strerror_)(CURLcode); + void (*easy_cleanup_)(CURL *); + CURLcode (*easy_getinfo_)(CURL *, CURLINFO info, ...); + void (*easy_reset_)(CURL*); + void (*formfree_)(struct curl_httppost *); + +}; +} + +#endif // COMMON_LINUX_LIBCURL_WRAPPER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc new file mode 100644 index 0000000000..79281a9043 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc @@ -0,0 +1,248 @@ +// Copyright (c) 2012, 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. + +// This source file provides replacements for libc functions that we need. If +// we call the libc functions directly we risk crashing in the dynamic linker +// as it tries to resolve uncached PLT entries. + +#include "common/linux/linux_libc_support.h" + +#include + +extern "C" { + +size_t my_strlen(const char* s) { + size_t len = 0; + while (*s++) len++; + return len; +} + +int my_strcmp(const char* a, const char* b) { + for (;;) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } +} + +int my_strncmp(const char* a, const char* b, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } + + return 0; +} + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +bool my_strtoui(int* result, const char* s) { + if (*s == 0) + return false; + int r = 0; + for (;; s++) { + if (*s == 0) + break; + const int old_r = r; + r *= 10; + if (*s < '0' || *s > '9') + return false; + r += *s - '0'; + if (r < old_r) + return false; + } + + *result = r; + return true; +} + +// Return the length of the given unsigned integer when expressed in base 10. +unsigned my_uint_len(uintmax_t i) { + if (!i) + return 1; + + int len = 0; + while (i) { + len++; + i /= 10; + } + + return len; +} + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +void my_uitos(char* output, uintmax_t i, unsigned i_len) { + for (unsigned index = i_len; index; --index, i /= 10) + output[index - 1] = '0' + (i % 10); +} + +const char* my_strchr(const char* haystack, char needle) { + while (*haystack && *haystack != needle) + haystack++; + if (*haystack == needle) + return haystack; + return (const char*) 0; +} + +const char* my_strrchr(const char* haystack, char needle) { + const char* ret = NULL; + while (*haystack) { + if (*haystack == needle) + ret = haystack; + haystack++; + } + return ret; +} + +const char* my_strstr(const char* haystack, const char* needle) { + while (*haystack != 0) { + if((*haystack == *needle) && + (my_strncmp(haystack, needle, my_strlen(needle)) == 0)) { + return haystack; + } + haystack++; + } + return nullptr; +} + +void* my_memchr(const void* src, int needle, size_t src_len) { + const unsigned char* p = (const unsigned char*)src; + const unsigned char* p_end = p + src_len; + for (; p < p_end; ++p) { + if (*p == needle) + return (void*)p; + } + return NULL; +} + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +const char* my_read_hex_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r <<= 4; + r += *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + r <<= 4; + r += (*s - 'a') + 10; + } else if (*s >= 'A' && *s <= 'F') { + r <<= 4; + r += (*s - 'A') + 10; + } else { + break; + } + } + + *result = r; + return s; +} + +const char* my_read_decimal_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r *= 10; + r += *s - '0'; + } else { + break; + } + } + *result = r; + return s; +} + +void my_memset(void* ip, char c, size_t len) { + char* p = (char *) ip; + while (len--) + *p++ = c; +} + +size_t my_strlcpy(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + size_t pos2 = 0; + + while (s2[pos2] != '\0') { + if (pos1 + 1 < len) { + s1[pos1] = s2[pos2]; + pos1++; + } + pos2++; + } + if (len > 0) + s1[pos1] = '\0'; + + return pos2; +} + +size_t my_strlcat(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + + while (pos1 < len && s1[pos1] != '\0') + pos1++; + + if (pos1 == len) + return pos1; + + return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1); +} + +int my_isspace(int ch) { + // Matches the C locale. + const char spaces[] = " \t\f\n\r\t\v"; + for (size_t i = 0; i < sizeof(spaces); i++) { + if (ch == spaces[i]) + return 1; + } + return 0; +} + +} // extern "C" diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h new file mode 100644 index 0000000000..03e3aa0657 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h @@ -0,0 +1,98 @@ +// Copyright (c) 2009, 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. + +// This header provides replacements for libc functions that we need. We if +// call the libc functions directly we risk crashing in the dynamic linker as +// it tries to resolve uncached PLT entries. + +#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ +#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ + +#include +#include +#include + +extern "C" { + +extern size_t my_strlen(const char* s); + +extern int my_strcmp(const char* a, const char* b); + +extern int my_strncmp(const char* a, const char* b, size_t len); + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +extern bool my_strtoui(int* result, const char* s); + +// Return the length of the given unsigned integer when expressed in base 10. +extern unsigned my_uint_len(uintmax_t i); + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +extern void my_uitos(char* output, uintmax_t i, unsigned i_len); + +extern const char* my_strchr(const char* haystack, char needle); + +extern const char* my_strrchr(const char* haystack, char needle); + +extern const char *my_strstr(const char *haystack, const char *needle); + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +extern const char* my_read_hex_ptr(uintptr_t* result, const char* s); + +extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s); + +extern void my_memset(void* ip, char c, size_t len); + +extern void* my_memchr(const void* src, int c, size_t len); + +// The following are considered safe to use in a compromised environment. +// Besides, this gives the compiler an opportunity to optimize their calls. +#define my_memcpy memcpy +#define my_memmove memmove +#define my_memcmp memcmp + +extern size_t my_strlcpy(char* s1, const char* s2, size_t len); + +extern size_t my_strlcat(char* s1, const char* s2, size_t len); + +extern int my_isspace(int ch); + +} // extern "C" + +#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc new file mode 100644 index 0000000000..adadfed44d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc @@ -0,0 +1,213 @@ +// Copyright (c) 2009, 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 "breakpad_googletest_includes.h" +#include "common/linux/linux_libc_support.h" + +namespace { +typedef testing::Test LinuxLibcSupportTest; +} + +TEST(LinuxLibcSupportTest, strlen) { + static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", NULL }; + for (unsigned i = 0; ; ++i) { + if (!test_data[i]) + break; + ASSERT_EQ(strlen(test_data[i]), my_strlen(test_data[i])); + } +} + +TEST(LinuxLibcSupportTest, strcmp) { + static const char* test_data[] = { + "", "", + "a", "", + "", "a", + "a", "b", + "a", "a", + "ab", "aa", + "abc", "ab", + "abc", "abc", + NULL, + }; + + for (unsigned i = 0; ; ++i) { + if (!test_data[i*2]) + break; + int libc_result = strcmp(test_data[i*2], test_data[i*2 + 1]); + if (libc_result > 1) + libc_result = 1; + else if (libc_result < -1) + libc_result = -1; + ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]), libc_result); + } +} + +TEST(LinuxLibcSupportTest, strtoui) { + int result; + + ASSERT_FALSE(my_strtoui(&result, "")); + ASSERT_FALSE(my_strtoui(&result, "-1")); + ASSERT_FALSE(my_strtoui(&result, "-")); + ASSERT_FALSE(my_strtoui(&result, "a")); + ASSERT_FALSE(my_strtoui(&result, "23472893472938472987987398472398")); + + ASSERT_TRUE(my_strtoui(&result, "0")); + ASSERT_EQ(result, 0); + ASSERT_TRUE(my_strtoui(&result, "1")); + ASSERT_EQ(result, 1); + ASSERT_TRUE(my_strtoui(&result, "12")); + ASSERT_EQ(result, 12); + ASSERT_TRUE(my_strtoui(&result, "123")); + ASSERT_EQ(result, 123); + ASSERT_TRUE(my_strtoui(&result, "0123")); + ASSERT_EQ(result, 123); +} + +TEST(LinuxLibcSupportTest, uint_len) { + ASSERT_EQ(my_uint_len(0), 1U); + ASSERT_EQ(my_uint_len(2), 1U); + ASSERT_EQ(my_uint_len(5), 1U); + ASSERT_EQ(my_uint_len(9), 1U); + ASSERT_EQ(my_uint_len(10), 2U); + ASSERT_EQ(my_uint_len(99), 2U); + ASSERT_EQ(my_uint_len(100), 3U); + ASSERT_EQ(my_uint_len(101), 3U); + ASSERT_EQ(my_uint_len(1000), 4U); + // 0xFFFFFFFFFFFFFFFF + ASSERT_EQ(my_uint_len(18446744073709551615LLU), 20U); +} + +TEST(LinuxLibcSupportTest, uitos) { + char buf[32]; + + my_uitos(buf, 0, 1); + ASSERT_EQ(0, memcmp(buf, "0", 1)); + + my_uitos(buf, 1, 1); + ASSERT_EQ(0, memcmp(buf, "1", 1)); + + my_uitos(buf, 10, 2); + ASSERT_EQ(0, memcmp(buf, "10", 2)); + + my_uitos(buf, 63, 2); + ASSERT_EQ(0, memcmp(buf, "63", 2)); + + my_uitos(buf, 101, 3); + ASSERT_EQ(0, memcmp(buf, "101", 2)); + + // 0xFFFFFFFFFFFFFFFF + my_uitos(buf, 18446744073709551615LLU, 20); + ASSERT_EQ(0, memcmp(buf, "18446744073709551615", 20)); +} + +TEST(LinuxLibcSupportTest, strchr) { + ASSERT_EQ(NULL, my_strchr("abc", 'd')); + ASSERT_EQ(NULL, my_strchr("", 'd')); + ASSERT_EQ(NULL, my_strchr("efghi", 'd')); + + ASSERT_TRUE(my_strchr("a", 'a')); + ASSERT_TRUE(my_strchr("abc", 'a')); + ASSERT_TRUE(my_strchr("bcda", 'a')); + ASSERT_TRUE(my_strchr("sdfasdf", 'a')); + + static const char abc3[] = "abcabcabc"; + ASSERT_EQ(abc3, my_strchr(abc3, 'a')); +} + +TEST(LinuxLibcSupportTest, strrchr) { + ASSERT_EQ(NULL, my_strrchr("abc", 'd')); + ASSERT_EQ(NULL, my_strrchr("", 'd')); + ASSERT_EQ(NULL, my_strrchr("efghi", 'd')); + + ASSERT_TRUE(my_strrchr("a", 'a')); + ASSERT_TRUE(my_strrchr("abc", 'a')); + ASSERT_TRUE(my_strrchr("bcda", 'a')); + ASSERT_TRUE(my_strrchr("sdfasdf", 'a')); + + static const char abc3[] = "abcabcabc"; + ASSERT_EQ(abc3 + 6, my_strrchr(abc3, 'a')); +} + +TEST(LinuxLibcSupportTest, memchr) { + ASSERT_EQ(NULL, my_memchr("abc", 'd', 3)); + ASSERT_EQ(NULL, my_memchr("abcd", 'd', 3)); + ASSERT_EQ(NULL, my_memchr("a", 'a', 0)); + + static const char abc3[] = "abcabcabc"; + ASSERT_EQ(abc3, my_memchr(abc3, 'a', 3)); + ASSERT_EQ(abc3, my_memchr(abc3, 'a', 9)); + ASSERT_EQ(abc3+1, my_memchr(abc3, 'b', 9)); + ASSERT_EQ(abc3+2, my_memchr(abc3, 'c', 9)); +} + +TEST(LinuxLibcSupportTest, read_hex_ptr) { + uintptr_t result; + const char* last; + + last = my_read_hex_ptr(&result, ""); + ASSERT_EQ(result, 0U); + ASSERT_EQ(*last, 0); + + last = my_read_hex_ptr(&result, "0"); + ASSERT_EQ(result, 0U); + ASSERT_EQ(*last, 0); + + last = my_read_hex_ptr(&result, "0123"); + ASSERT_EQ(result, 0x123U); + ASSERT_EQ(*last, 0); + + last = my_read_hex_ptr(&result, "0123a"); + ASSERT_EQ(result, 0x123aU); + ASSERT_EQ(*last, 0); + + last = my_read_hex_ptr(&result, "0123a-"); + ASSERT_EQ(result, 0x123aU); + ASSERT_EQ(*last, '-'); +} + +TEST(LinuxLibcSupportTest, read_decimal_ptr) { + uintptr_t result; + const char* last; + + last = my_read_decimal_ptr(&result, "0"); + ASSERT_EQ(result, 0U); + ASSERT_EQ(*last, 0); + + last = my_read_decimal_ptr(&result, "0123"); + ASSERT_EQ(result, 123U); + ASSERT_EQ(*last, 0); + + last = my_read_decimal_ptr(&result, "1234"); + ASSERT_EQ(result, 1234U); + ASSERT_EQ(*last, 0); + + last = my_read_decimal_ptr(&result, "01234-"); + ASSERT_EQ(result, 1234U); + ASSERT_EQ(*last, '-'); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc new file mode 100644 index 0000000000..4e938269f2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc @@ -0,0 +1,107 @@ +// Copyright (c) 2011, 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_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. +// See memory_mapped_file.h for details. + +#include "common/linux/memory_mapped_file.h" + +#include +#include +#if defined(__ANDROID__) +#include +#endif +#include + +#include "common/memory_range.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +MemoryMappedFile::MemoryMappedFile() {} + +MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) { + Map(path, offset); +} + +MemoryMappedFile::~MemoryMappedFile() { + Unmap(); +} + +#include + +bool MemoryMappedFile::Map(const char* path, size_t offset) { + Unmap(); + + int fd = sys_open(path, O_RDONLY, 0); + if (fd == -1) { + return false; + } + +#if defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM == _ABI64) + + struct kernel_stat st; + if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { +#else + struct kernel_stat64 st; + if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) { +#endif + sys_close(fd); + return false; + } + + // Strangely file size can be negative, but we check above that it is not. + size_t file_len = static_cast(st.st_size); + // If the file does not extend beyond the offset, simply use an empty + // MemoryRange and return true. Don't bother to call mmap() + // even though mmap() can handle an empty file on some platforms. + if (offset >= file_len) { + sys_close(fd); + return true; + } + + void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset); + sys_close(fd); + if (data == MAP_FAILED) { + return false; + } + + content_.Set(data, file_len - offset); + return true; +} + +void MemoryMappedFile::Unmap() { + if (content_.data()) { + sys_munmap(const_cast(content_.data()), content_.length()); + content_.Set(NULL, 0); + } +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h new file mode 100644 index 0000000000..fa660cc91a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h @@ -0,0 +1,87 @@ +// Copyright (c) 2011, 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_mapped_file.h: Define the google_breakpad::MemoryMappedFile +// class, which maps a file into memory for read-only access. + +#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_ +#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ + +#include +#include "common/basictypes.h" +#include "common/memory_range.h" + +namespace google_breakpad { + +// A utility class for mapping a file into memory for read-only access of +// the file content. Its implementation avoids calling into libc functions +// by directly making system calls for open, close, mmap, and munmap. +class MemoryMappedFile { + public: + MemoryMappedFile(); + + // Constructor that calls Map() to map a file at |path| into memory. + // If Map() fails, the object behaves as if it is default constructed. + MemoryMappedFile(const char* path, size_t offset); + + ~MemoryMappedFile(); + + // Maps a file at |path| into memory, which can then be accessed via + // content() as a MemoryRange object or via data(), and returns true on + // success. Mapping an empty file will succeed but with data() and size() + // returning NULL and 0, respectively. An existing mapping is unmapped + // before a new mapping is created. + bool Map(const char* path, size_t offset); + + // Unmaps the memory for the mapped file. It's a no-op if no file is + // mapped. + void Unmap(); + + // Returns a MemoryRange object that covers the memory for the mapped + // file. The MemoryRange object is empty if no file is mapped. + const MemoryRange& content() const { return content_; } + + // Returns a pointer to the beginning of the memory for the mapped file. + // or NULL if no file is mapped or the mapped file is empty. + const void* data() const { return content_.data(); } + + // Returns the size in bytes of the mapped file, or zero if no file + // is mapped. + size_t size() const { return content_.length(); } + + private: + // Mapped file content as a MemoryRange object. + MemoryRange content_; + + DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_MEMORY_MAPPED_FILE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc new file mode 100644 index 0000000000..fad59f40cd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2011, 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_mapped_file_unittest.cc: +// Unit tests for google_breakpad::MemoryMappedFile. + +#include +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/memory_mapped_file.h" +#include "common/tests/auto_tempdir.h" +#include "common/tests/file_utils.h" +#include "common/using_std_string.h" + +using google_breakpad::AutoTempDir; +using google_breakpad::MemoryMappedFile; +using google_breakpad::WriteFile; + +namespace { + +class MemoryMappedFileTest : public testing::Test { + protected: + void ExpectNoMappedData(const MemoryMappedFile& mapped_file) { + EXPECT_TRUE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() == NULL); + EXPECT_EQ(0U, mapped_file.size()); + } +}; + +} // namespace + +TEST_F(MemoryMappedFileTest, DefaultConstructor) { + MemoryMappedFile mapped_file; + ExpectNoMappedData(mapped_file); +} + +TEST_F(MemoryMappedFileTest, UnmapWithoutMap) { + MemoryMappedFile mapped_file; + mapped_file.Unmap(); +} + +TEST_F(MemoryMappedFileTest, MapNonexistentFile) { + { + MemoryMappedFile mapped_file("nonexistent-file", 0); + ExpectNoMappedData(mapped_file); + } + { + MemoryMappedFile mapped_file; + EXPECT_FALSE(mapped_file.Map("nonexistent-file", 0)); + ExpectNoMappedData(mapped_file); + } +} + +TEST_F(MemoryMappedFileTest, MapEmptyFile) { + AutoTempDir temp_dir; + string test_file = temp_dir.path() + "/empty_file"; + ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0)); + + { + MemoryMappedFile mapped_file(test_file.c_str(), 0); + ExpectNoMappedData(mapped_file); + } + { + MemoryMappedFile mapped_file; + EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0)); + ExpectNoMappedData(mapped_file); + } +} + +TEST_F(MemoryMappedFileTest, MapNonEmptyFile) { + char data[256]; + size_t data_size = sizeof(data); + for (size_t i = 0; i < data_size; ++i) { + data[i] = i; + } + + AutoTempDir temp_dir; + string test_file = temp_dir.path() + "/test_file"; + ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size)); + + { + MemoryMappedFile mapped_file(test_file.c_str(), 0); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); + } + { + MemoryMappedFile mapped_file; + EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0)); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); + } +} + +TEST_F(MemoryMappedFileTest, RemapAfterMap) { + char data1[256]; + size_t data1_size = sizeof(data1); + for (size_t i = 0; i < data1_size; ++i) { + data1[i] = i; + } + + char data2[50]; + size_t data2_size = sizeof(data2); + for (size_t i = 0; i < data2_size; ++i) { + data2[i] = 255 - i; + } + + AutoTempDir temp_dir; + string test_file1 = temp_dir.path() + "/test_file1"; + string test_file2 = temp_dir.path() + "/test_file2"; + ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size)); + ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size)); + + { + MemoryMappedFile mapped_file(test_file1.c_str(), 0); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data1_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); + + mapped_file.Map(test_file2.c_str(), 0); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data2_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); + } + { + MemoryMappedFile mapped_file; + EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0)); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data1_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); + + mapped_file.Map(test_file2.c_str(), 0); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data2_size, mapped_file.size()); + EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); + } +} + +TEST_F(MemoryMappedFileTest, MapWithOffset) { + // Put more data in the test file this time. Offsets can only be + // done on page boundaries, so we need a two page file to test this. + const int page_size = 4096; + char data1[2 * page_size]; + size_t data1_size = sizeof(data1); + for (size_t i = 0; i < data1_size; ++i) { + data1[i] = i & 0x7f; + } + + AutoTempDir temp_dir; + string test_file1 = temp_dir.path() + "/test_file1"; + ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size)); + { + MemoryMappedFile mapped_file(test_file1.c_str(), page_size); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data1_size - page_size, mapped_file.size()); + EXPECT_EQ( + 0, + memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size)); + } + { + MemoryMappedFile mapped_file; + mapped_file.Map(test_file1.c_str(), page_size); + EXPECT_FALSE(mapped_file.content().IsEmpty()); + EXPECT_TRUE(mapped_file.data() != NULL); + EXPECT_EQ(data1_size - page_size, mapped_file.size()); + EXPECT_EQ( + 0, + memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size)); + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build b/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build new file mode 100644 index 0000000000..ecd1e5ffe7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build @@ -0,0 +1,42 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'elfutils.cc', + 'linux_libc_support.cc', + 'memory_mapped_file.cc', + 'safe_readlink.cc', +] + +# file_id.cc cannot be built in unified mode because it uses a custom DISABLE_STL_WRAPPING +SOURCES += [ + 'file_id.cc', +] + +if CONFIG['OS_TARGET'] != 'Android': + UNIFIED_SOURCES += [ + 'http_upload.cc', + ] + +if CONFIG['OS_TARGET'] == 'Android': + DEFINES['ANDROID_NDK_MAJOR_VERSION'] = CONFIG['ANDROID_NDK_MAJOR_VERSION'] + DEFINES['ANDROID_NDK_MINOR_VERSION'] = CONFIG['ANDROID_NDK_MINOR_VERSION'] + COMPILE_FLAGS['OS_INCLUDES'] += [ + '-I%s/toolkit/crashreporter/google-breakpad/src/common/android/include' % TOPSRCDIR, + ] + +if not CONFIG['HAVE_GETCONTEXT']: + # We don't support unifying assembly files. + SOURCES += [ + 'breakpad_getcontext.S', + ] + +Library('breakpad_linux_common_s') + +include('/toolkit/crashreporter/crashreporter.mozbuild') + +if CONFIG['CC_TYPE'] in ('clang', 'gcc'): + CXXFLAGS += ['-Wno-error=stack-protector'] diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc new file mode 100644 index 0000000000..870c28af3b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2011, 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. + +// safe_readlink.cc: Implement google_breakpad::SafeReadLink. +// See safe_readlink.h for details. + +#include + +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size) { + // sys_readlink() does not add a NULL byte to |buffer|. In order to return + // a NULL-terminated string in |buffer|, |buffer_size| should be at least + // one byte longer than the expected path length. Also, sys_readlink() + // returns the actual path length on success, which does not count the + // NULL byte, so |result_size| should be less than |buffer_size|. + ssize_t result_size = sys_readlink(path, buffer, buffer_size); + if (result_size >= 0 && static_cast(result_size) < buffer_size) { + buffer[result_size] = '\0'; + return true; + } + return false; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h new file mode 100644 index 0000000000..4ae131b580 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011, 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. + +// safe_readlink.h: Define the google_breakpad::SafeReadLink function, +// which wraps sys_readlink and gurantees the result is NULL-terminated. + +#ifndef COMMON_LINUX_SAFE_READLINK_H_ +#define COMMON_LINUX_SAFE_READLINK_H_ + +#include + +namespace google_breakpad { + +// This function wraps sys_readlink() and performs the same functionalty, +// but guarantees |buffer| is NULL-terminated if sys_readlink() returns +// no error. It takes the same arguments as sys_readlink(), but unlike +// sys_readlink(), it returns true on success. +// +// |buffer_size| specifies the size of |buffer| in bytes. As this function +// always NULL-terminates |buffer| on success, |buffer_size| should be +// at least one byte longer than the expected path length (e.g. PATH_MAX, +// which is typically defined as the maximum length of a path name +// including the NULL byte). +// +// The implementation of this function calls sys_readlink() instead of +// readlink(), it can thus be used in the context where calling to libc +// functions is discouraged. +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size); + +// Same as the three-argument version of SafeReadLink() but deduces the +// size of |buffer| if it is a char array of known size. +template +bool SafeReadLink(const char* path, char (&buffer)[N]) { + return SafeReadLink(path, buffer, sizeof(buffer)); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SAFE_READLINK_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc new file mode 100644 index 0000000000..d346b2a807 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2011, 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. + +// safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink. + +#include "breakpad_googletest_includes.h" +#include "common/linux/safe_readlink.h" + +using google_breakpad::SafeReadLink; + +TEST(SafeReadLinkTest, ZeroBufferSize) { + char buffer[1]; + EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 0)); +} + +TEST(SafeReadLinkTest, BufferSizeTooSmall) { + char buffer[1]; + EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 1)); +} + +TEST(SafeReadLinkTest, BoundaryBufferSize) { + char buffer[PATH_MAX]; + EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer, sizeof(buffer))); + size_t path_length = strlen(buffer); + EXPECT_LT(0U, path_length); + EXPECT_GT(sizeof(buffer), path_length); + + // Buffer size equals to the expected path length plus 1 for the NULL byte. + char buffer2[PATH_MAX]; + EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2, path_length + 1)); + EXPECT_EQ(path_length, strlen(buffer2)); + EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX)); + + // Buffer size equals to the expected path length. + EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, path_length)); +} + +TEST(SafeReadLinkTest, NonexistentPath) { + char buffer[PATH_MAX]; + EXPECT_FALSE(SafeReadLink("nonexistent_path", buffer, sizeof(buffer))); +} + +TEST(SafeReadLinkTest, NonSymbolicLinkPath) { + char actual_path[PATH_MAX]; + EXPECT_TRUE(SafeReadLink("/proc/self/exe", actual_path, sizeof(actual_path))); + + char buffer[PATH_MAX]; + EXPECT_FALSE(SafeReadLink(actual_path, buffer, sizeof(buffer))); +} + +TEST(SafeReadLinkTest, DeduceBufferSizeFromCharArray) { + char buffer[PATH_MAX]; + char* buffer_pointer = buffer; + EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer_pointer, sizeof(buffer))); + size_t path_length = strlen(buffer); + + // Use the template version of SafeReadLink to deduce the buffer size + // from the char array. + char buffer2[PATH_MAX]; + EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2)); + EXPECT_EQ(path_length, strlen(buffer2)); + EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX)); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.cc new file mode 100644 index 0000000000..92b25ddba9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2019 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 "common/linux/symbol_collector_client.h" + +#include + +#include +#include + +#include "common/linux/libcurl_wrapper.h" + +namespace google_breakpad { +namespace sym_upload { + +// static +bool SymbolCollectorClient::CreateUploadUrl( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + UploadUrlResponse* uploadUrlResponse) { + string header, response; + long response_code; + + string url = api_url + "/v1/uploads:create"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + + if (!libcurl_wrapper->SendSimplePostRequest(url, + /*body=*/"", + /*content_type=*/"", + &response_code, + &header, + &response)) { + printf("Failed to create upload url.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + + // Note camel-case rather than underscores. + std::regex upload_url_regex("\"uploadUrl\": \"([^\"]+)\""); + std::regex upload_key_regex("\"uploadKey\": \"([^\"]+)\""); + + std::smatch upload_url_match; + if (!std::regex_search(response, upload_url_match, upload_url_regex) || + upload_url_match.size() != 2) { + printf("Failed to parse create url response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + string upload_url = upload_url_match[1].str(); + + std::smatch upload_key_match; + if (!std::regex_search(response, upload_key_match, upload_key_regex) || + upload_key_match.size() != 2) { + printf("Failed to parse create url response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + string upload_key = upload_key_match[1].str(); + + uploadUrlResponse->upload_url = upload_url; + uploadUrlResponse->upload_key = upload_key; + return true; +} + +// static +CompleteUploadResult SymbolCollectorClient::CompleteUpload( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& upload_key, + const string& debug_file, + const string& debug_id, + const string& type) { + string header, response; + long response_code; + + string url = api_url + "/v1/uploads/" + upload_key + ":complete"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + string body = + "{ symbol_id: {" + "debug_file: \"" + debug_file + "\", " + "debug_id: \"" + debug_id + "\" }, " + "symbol_upload_type: \"" + type + "\" }"; + + if (!libcurl_wrapper->SendSimplePostRequest(url, + body, + "application/son", + &response_code, + &header, + &response)) { + printf("Failed to complete upload.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + + std::regex result_regex("\"result\": \"([^\"]+)\""); + std::smatch result_match; + if (!std::regex_search(response, result_match, result_regex) || + result_match.size() != 2) { + printf("Failed to parse complete upload response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + string result = result_match[1].str(); + + if (result.compare("DUPLICATE_DATA") == 0) { + return CompleteUploadResult::DuplicateData; + } + + return CompleteUploadResult::Ok; +} + +// static +SymbolStatus SymbolCollectorClient::CheckSymbolStatus( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& debug_file, + const string& debug_id) { + string header, response; + long response_code; + string url = api_url + + "/v1/symbols/" + debug_file + "/" + debug_id + ":checkStatus"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + + if (!libcurl_wrapper->SendGetRequest( + url, + &response_code, + &header, + &response)) { + printf("Failed to check symbol status, error message.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + + std::regex status_regex("\"status\": \"([^\"]+)\""); + std::smatch status_match; + if (!std::regex_search(response, status_match, status_regex) || + status_match.size() != 2) { + printf("Failed to parse check symbol status response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + string status = status_match[1].str(); + + return (status.compare("FOUND") == 0) ? + SymbolStatus::Found : + SymbolStatus::Missing; +} + +} // namespace sym_upload +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.h b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.h new file mode 100644 index 0000000000..0e23242a2b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_collector_client.h @@ -0,0 +1,88 @@ +// Copyright (c) 2019, 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 COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ +#define COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ + +#include + +#include "common/linux/libcurl_wrapper.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace sym_upload { + +struct UploadUrlResponse { + string upload_url; + string upload_key; +}; + +enum SymbolStatus { + Found, + Missing, + Unknown +}; + +enum CompleteUploadResult { + Ok, + DuplicateData, + Error +}; + +// Helper class to communicate with a sym-upload-v2 service over HTTP/REST, +// via libcurl. +class SymbolCollectorClient { + public: + static bool CreateUploadUrl( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + UploadUrlResponse* uploadUrlResponse); + + static CompleteUploadResult CompleteUpload( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& upload_key, + const string& debug_file, + const string& debug_id, + const string& type); + + static SymbolStatus CheckSymbolStatus( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& debug_file, + const string& debug_id); +}; + +} // namespace sym_upload +} // namespace google_breakpad + +#endif // COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc new file mode 100644 index 0000000000..87741a0a21 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc @@ -0,0 +1,284 @@ +// Copyright (c) 2011 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. + +// symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper +// function for linux symbol upload tool. + +#include "common/linux/symbol_upload.h" + +#include +#include + +#include +#include +#include + +#include "common/linux/http_upload.h" +#include "common/linux/libcurl_wrapper.h" +#include "common/linux/symbol_collector_client.h" + +namespace google_breakpad { +namespace sym_upload { + +void TokenizeByChar(const string &source_string, int c, + std::vector *results) { + assert(results); + string::size_type cur_pos = 0, next_pos = 0; + while ((next_pos = source_string.find(c, cur_pos)) != string::npos) { + if (next_pos != cur_pos) + results->push_back(source_string.substr(cur_pos, next_pos - cur_pos)); + cur_pos = next_pos + 1; + } + if (cur_pos < source_string.size() && next_pos != cur_pos) + results->push_back(source_string.substr(cur_pos)); +} + +//============================================================================= +// Parse out the module line which have 5 parts. +// MODULE +bool ModuleDataForSymbolFile(const string &file, + std::vector *module_parts) { + assert(module_parts); + const size_t kModulePartNumber = 5; + FILE* fp = fopen(file.c_str(), "r"); + if (fp) { + char buffer[1024]; + if (fgets(buffer, sizeof(buffer), fp)) { + string line(buffer); + string::size_type line_break_pos = line.find_first_of('\n'); + if (line_break_pos == string::npos) { + assert(0 && "The file is invalid!"); + fclose(fp); + return false; + } + line.resize(line_break_pos); + const char kDelimiter = ' '; + TokenizeByChar(line, kDelimiter, module_parts); + if (module_parts->size() != kModulePartNumber) + module_parts->clear(); + } + fclose(fp); + } + + return module_parts->size() == kModulePartNumber; +} + +//============================================================================= +string CompactIdentifier(const string &uuid) { + std::vector components; + TokenizeByChar(uuid, '-', &components); + string result; + for (size_t i = 0; i < components.size(); ++i) + result += components[i]; + return result; +} + +// |options| describes the current sym_upload options. +// |module_parts| contains the strings parsed from the MODULE entry of the +// Breakpad symbol file being uploaded. +// |compacted_id| is the debug_id from the MODULE entry of the Breakpad symbol +// file being uploaded, with all hyphens removed. +bool SymUploadV1Start( + const Options& options, + std::vector module_parts, + const string& compacted_id) { + std::map parameters; + // Add parameters + if (!options.version.empty()) + parameters["version"] = options.version; + + // MODULE + // 0 1 2 3 4 + parameters["os"] = module_parts[1]; + parameters["cpu"] = module_parts[2]; + parameters["debug_file"] = module_parts[4]; + parameters["code_file"] = module_parts[4]; + parameters["debug_identifier"] = compacted_id; + + std::map files; + files["symbol_file"] = options.symbolsPath; + + string response, error; + long response_code; + bool success = HTTPUpload::SendRequest(options.uploadURLStr, + parameters, + files, + options.proxy, + options.proxy_user_pwd, + /*ca_certificate_file=*/"", + &response, + &response_code, + &error); + + if (!success) { + printf("Failed to send symbol file: %s\n", error.c_str()); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + } else if (response_code == 0) { + printf("Failed to send symbol file: No response code\n"); + } else if (response_code != 200) { + printf("Failed to send symbol file: Response code %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + } else { + printf("Successfully sent the symbol file.\n"); + } + + return success; +} + +// |options| describes the current sym_upload options. +// |code_id| is the basename of the module for which symbols are being +// uploaded. +// |debug_id| is the debug_id of the module for which symbols are being +// uploaded. +bool SymUploadV2Start( + const Options& options, + const string& code_file, + const string& debug_id, + const string& type) { + google_breakpad::LibcurlWrapper libcurl_wrapper; + if (!libcurl_wrapper.Init()) { + printf("Failed to init google_breakpad::LibcurlWrapper.\n"); + return false; + } + + if (!options.force) { + SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( + &libcurl_wrapper, + options.uploadURLStr, + options.api_key, + code_file, + debug_id); + if (symbolStatus == SymbolStatus::Found) { + printf("Symbol file already exists, upload aborted." + " Use \"-f\" to overwrite.\n"); + return true; + } else if (symbolStatus == SymbolStatus::Unknown) { + printf("Failed to check for existing symbol.\n"); + return false; + } + } + + UploadUrlResponse uploadUrlResponse; + if (!SymbolCollectorClient::CreateUploadUrl( + &libcurl_wrapper, + options.uploadURLStr, + options.api_key, + &uploadUrlResponse)) { + printf("Failed to create upload URL.\n"); + return false; + } + + string signed_url = uploadUrlResponse.upload_url; + string upload_key = uploadUrlResponse.upload_key; + string header; + string response; + long response_code; + + if (!libcurl_wrapper.SendPutRequest(signed_url, + options.symbolsPath, + &response_code, + &header, + &response)) { + printf("Failed to send symbol file.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } else if (response_code == 0) { + printf("Failed to send symbol file: No response code\n"); + return false; + } else if (response_code != 200) { + printf("Failed to send symbol file: Response code %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + + CompleteUploadResult completeUploadResult = + SymbolCollectorClient::CompleteUpload(&libcurl_wrapper, + options.uploadURLStr, + options.api_key, + upload_key, + code_file, + debug_id, + type); + if (completeUploadResult == CompleteUploadResult::Error) { + printf("Failed to complete upload.\n"); + return false; + } else if (completeUploadResult == CompleteUploadResult::DuplicateData) { + printf("Uploaded file checksum matched existing file checksum," + " no change necessary.\n"); + } else { + printf("Successfully sent the symbol file.\n"); + } + + return true; +} + +//============================================================================= +void Start(Options* options) { + if (options->upload_protocol == UploadProtocol::SYM_UPLOAD_V2) { + string code_file; + string debug_id; + string type; + + if (options->type.empty() || options->type == kBreakpadSymbolType) { + // Breakpad upload so read these from input file. + std::vector module_parts; + if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) { + fprintf(stderr, "Failed to parse symbol file!\n"); + return; + } + code_file = module_parts[4]; + debug_id = CompactIdentifier(module_parts[3]); + type = kBreakpadSymbolType; + } else { + // Native upload so these must be explicitly set. + code_file = options->code_file; + debug_id = options->debug_id; + type = options->type; + } + + options->success = SymUploadV2Start(*options, code_file, debug_id, type); + } else { + std::vector module_parts; + if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) { + fprintf(stderr, "Failed to parse symbol file!\n"); + return; + } + const string compacted_id = CompactIdentifier(module_parts[3]); + options->success = SymUploadV1Start(*options, module_parts, compacted_id); + } +} + +} // namespace sym_upload +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h new file mode 100644 index 0000000000..9033152bf2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h @@ -0,0 +1,76 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// symbol_upload.h: helper functions for linux symbol upload tool. + +#ifndef COMMON_LINUX_SYMBOL_UPLOAD_H_ +#define COMMON_LINUX_SYMBOL_UPLOAD_H_ + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace sym_upload { + +enum class UploadProtocol { + SYM_UPLOAD_V1, + SYM_UPLOAD_V2, +}; + +constexpr char kBreakpadSymbolType[] = "BREAKPAD"; + +struct Options { + Options() : upload_protocol(UploadProtocol::SYM_UPLOAD_V1), force(false) {} + + string symbolsPath; + string uploadURLStr; + string proxy; + string proxy_user_pwd; + string version; + bool success; + UploadProtocol upload_protocol; + bool force; + string api_key; + + // These only need to be set for native symbol uploads. + string code_file; + string debug_id; + string type; +}; + +// Starts upload to symbol server with options. +void Start(Options* options); + +} // namespace sym_upload +} // namespace google_breakpad + +#endif // COMMON_LINUX_SYMBOL_UPLOAD_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc new file mode 100644 index 0000000000..98e81dab75 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc @@ -0,0 +1,263 @@ +#include "common/linux/synth_elf.h" + +#include +#include +#include +#include + +#include "common/linux/elf_gnu_compat.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace synth_elf { + +ELF::ELF(uint16_t machine, + uint8_t file_class, + Endianness endianness) + : Section(endianness), + addr_size_(file_class == ELFCLASS64 ? 8 : 4), + program_count_(0), + program_header_table_(endianness), + section_count_(0), + section_header_table_(endianness), + section_header_strings_(endianness) { + // Could add support for more machine types here if needed. + assert(machine == EM_386 || + machine == EM_X86_64 || + machine == EM_ARM); + assert(file_class == ELFCLASS32 || file_class == ELFCLASS64); + + start() = 0; + // Add ELF header + // e_ident + // EI_MAG0...EI_MAG3 + D8(ELFMAG0); + D8(ELFMAG1); + D8(ELFMAG2); + D8(ELFMAG3); + // EI_CLASS + D8(file_class); + // EI_DATA + D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB); + // EI_VERSION + D8(EV_CURRENT); + // EI_OSABI + D8(ELFOSABI_SYSV); + // EI_ABIVERSION + D8(0); + // EI_PAD + Append(7, 0); + assert(Size() == EI_NIDENT); + + // e_type + D16(ET_EXEC); //TODO: allow passing ET_DYN? + // e_machine + D16(machine); + // e_version + D32(EV_CURRENT); + // e_entry + Append(endianness, addr_size_, 0); + // e_phoff + Append(endianness, addr_size_, program_header_label_); + // e_shoff + Append(endianness, addr_size_, section_header_label_); + // e_flags + D32(0); + // e_ehsize + D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); + // e_phentsize + D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr)); + // e_phnum + D16(program_count_label_); + // e_shentsize + D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr)); + // e_shnum + D16(section_count_label_); + // e_shstrndx + D16(section_header_string_index_); + + // Add an empty section for SHN_UNDEF. + Section shn_undef; + AddSection("", shn_undef, SHT_NULL); +} + +int ELF::AddSection(const string& name, const Section& section, + uint32_t type, uint32_t flags, uint64_t addr, + uint32_t link, uint64_t entsize, uint64_t offset) { + Label offset_label; + Label string_label(section_header_strings_.Add(name)); + size_t size = section.Size(); + + int index = section_count_; + ++section_count_; + + section_header_table_ + // sh_name + .D32(string_label) + // sh_type + .D32(type) + // sh_flags + .Append(endianness(), addr_size_, flags) + // sh_addr + .Append(endianness(), addr_size_, addr) + // sh_offset + .Append(endianness(), addr_size_, offset_label) + // sh_size + .Append(endianness(), addr_size_, size) + // sh_link + .D32(link) + // sh_info + .D32(0) + // sh_addralign + .Append(endianness(), addr_size_, 0) + // sh_entsize + .Append(endianness(), addr_size_, entsize); + + sections_.push_back(ElfSection(section, type, addr, offset, offset_label, + size)); + return index; +} + +void ELF::AppendSection(ElfSection §ion) { + // NULL and NOBITS sections have no content, so they + // don't need to be written to the file. + if (section.type_ == SHT_NULL) { + section.offset_label_ = 0; + } else if (section.type_ == SHT_NOBITS) { + section.offset_label_ = section.offset_; + } else { + Mark(§ion.offset_label_); + Append(section); + Align(4); + } +} + +void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) { + assert(start > 0); + assert(size_t(start) < sections_.size()); + assert(end > 0); + assert(size_t(end) < sections_.size()); + ++program_count_; + + // p_type + program_header_table_.D32(type); + + if (addr_size_ == 8) { + // p_flags + program_header_table_.D32(flags); + } + + size_t filesz = 0; + size_t memsz = 0; + bool prev_was_nobits = false; + for (int i = start; i <= end; ++i) { + size_t size = sections_[i].size_; + if (sections_[i].type_ != SHT_NOBITS) { + assert(!prev_was_nobits); + // non SHT_NOBITS sections are 4-byte aligned (see AddSection) + size = (size + 3) & ~3; + filesz += size; + } else { + prev_was_nobits = true; + } + memsz += size; + } + + program_header_table_ + // p_offset + .Append(endianness(), addr_size_, sections_[start].offset_label_) + // p_vaddr + .Append(endianness(), addr_size_, sections_[start].addr_) + // p_paddr + .Append(endianness(), addr_size_, sections_[start].addr_) + // p_filesz + .Append(endianness(), addr_size_, filesz) + // p_memsz + .Append(endianness(), addr_size_, memsz); + + if (addr_size_ == 4) { + // p_flags + program_header_table_.D32(flags); + } + + // p_align + program_header_table_.Append(endianness(), addr_size_, 0); +} + +void ELF::Finish() { + // Add the section header string table at the end. + section_header_string_index_ = section_count_; + //printf(".shstrtab size: %ld\n", section_header_strings_.Size()); + AddSection(".shstrtab", section_header_strings_, SHT_STRTAB); + //printf("section_count_: %ld, sections_.size(): %ld\n", + // section_count_, sections_.size()); + if (program_count_) { + Mark(&program_header_label_); + Append(program_header_table_); + } else { + program_header_label_ = 0; + } + + for (vector::iterator it = sections_.begin(); + it < sections_.end(); ++it) { + AppendSection(*it); + } + section_count_label_ = section_count_; + program_count_label_ = program_count_; + + // Section header table starts here. + Mark(§ion_header_label_); + Append(section_header_table_); +} + +SymbolTable::SymbolTable(Endianness endianness, + size_t addr_size, + StringTable& table) : Section(endianness), + table_(table) { +#ifndef NDEBUG + addr_size_ = addr_size; +#endif + assert(addr_size_ == 4 || addr_size_ == 8); +} + +void SymbolTable::AddSymbol(const string& name, uint32_t value, + uint32_t size, unsigned info, uint16_t shndx) { + assert(addr_size_ == 4); + D32(table_.Add(name)); + D32(value); + D32(size); + D8(info); + D8(0); // other + D16(shndx); +} + +void SymbolTable::AddSymbol(const string& name, uint64_t value, + uint64_t size, unsigned info, uint16_t shndx) { + assert(addr_size_ == 8); + D32(table_.Add(name)); + D8(info); + D8(0); // other + D16(shndx); + D64(value); + D64(size); +} + +void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes, + size_t desc_size) { + // Elf32_Nhdr and Elf64_Nhdr are exactly the same. + Elf32_Nhdr note_header; + memset(¬e_header, 0, sizeof(note_header)); + note_header.n_namesz = name.length() + 1; + note_header.n_descsz = desc_size; + note_header.n_type = type; + + Append(reinterpret_cast(¬e_header), + sizeof(note_header)); + AppendCString(name); + Align(4); + Append(desc_bytes, desc_size); + Align(4); +} + +} // namespace synth_elf +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h new file mode 100644 index 0000000000..1d2a20ca22 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h @@ -0,0 +1,197 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2011, 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. + +// Original author: Ted Mielczarek + +// synth_elf.h: Interface to synth_elf::ELF: fake ELF generator. + +#ifndef COMMON_LINUX_SYNTH_ELF_H_ +#define COMMON_LINUX_SYNTH_ELF_H_ + +#include "common/test_assembler.h" + +#include +#include +#include +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace synth_elf { + +using std::list; +using std::vector; +using std::map; +using std::pair; +using test_assembler::Endianness; +using test_assembler::kLittleEndian; +using test_assembler::kUnsetEndian; +using test_assembler::Label; +using test_assembler::Section; + +// String tables are common in ELF headers, so subclass Section +// to make them easy to generate. +class StringTable : public Section { +public: + StringTable(Endianness endianness = kUnsetEndian) + : Section(endianness) { + start() = 0; + empty_string = Add(""); + } + + // Add the string s to the string table, and return + // a label containing the offset into the string table + // at which it was added. + Label Add(const string& s) { + if (strings_.find(s) != strings_.end()) + return strings_[s]; + + Label string_label(Here()); + AppendCString(s); + strings_[s] = string_label; + return string_label; + } + + // All StringTables contain an empty string as their first + // entry. + Label empty_string; + + // Avoid inserting duplicate strings. + map strings_; +}; + +// A Section representing an entire ELF file. +class ELF : public Section { + public: + ELF(uint16_t machine, // EM_386, etc + uint8_t file_class, // ELFCLASS{32,64} + Endianness endianness = kLittleEndian); + + // Add the Section section to the section header table and append it + // to the file. Returns the index of the section in the section + // header table. + int AddSection(const string& name, const Section& section, + uint32_t type, uint32_t flags = 0, uint64_t addr = 0, + uint32_t link = 0, uint64_t entsize = 0, uint64_t offset = 0); + + // Add a segment containing from section index start to section index end. + // The indexes must have been gotten from AddSection. + void AddSegment(int start, int end, uint32_t type, uint32_t flags = 0); + + // Write out all data. GetContents may be used after this. + void Finish(); + + private: + // Size of an address, in bytes. + const size_t addr_size_; + + // Offset to the program header table. + Label program_header_label_; + // Number of entries in the program header table. + int program_count_; + Label program_count_label_; + // The program header table itself. + Section program_header_table_; + + // Offset to the section header table. + Label section_header_label_; + // Number of entries in the section header table. + int section_count_; + Label section_count_label_; + // The section header table itself. + Section section_header_table_; + + // Index of the section header string table in the section + // header table. + Label section_header_string_index_; + // Section containing the names of section header table entries. + StringTable section_header_strings_; + + // Record of an added section + struct ElfSection : public Section { + ElfSection(const Section& section, uint32_t type, uint32_t addr, + uint32_t offset, Label offset_label, uint32_t size) + : Section(section), type_(type), addr_(addr), offset_(offset) + , offset_label_(offset_label), size_(size) { + } + + uint32_t type_; + uint32_t addr_; + uint32_t offset_; + Label offset_label_; + uint32_t size_; + }; + + vector sections_; + + void AppendSection(ElfSection §ion); +}; + +// A class to build .symtab or .dynsym sections. +class SymbolTable : public Section { + public: + // table is the StringTable that contains symbol names. The caller + // must ensure that it remains alive for the life of the + // SymbolTable. + SymbolTable(Endianness endianness, size_t addr_size, StringTable& table); + + // Add an Elf32_Sym. + void AddSymbol(const string& name, uint32_t value, + uint32_t size, unsigned info, uint16_t shndx); + // Add an Elf64_Sym. + void AddSymbol(const string& name, uint64_t value, + uint64_t size, unsigned info, uint16_t shndx); + + private: +#ifndef NDEBUG + size_t addr_size_; +#endif + StringTable& table_; +}; + +// A class for note sections +class Notes : public Section { +public: + Notes(Endianness endianness) + : Section(endianness) { + } + + // Add a note. + void AddNote(int type, const string &name, const uint8_t* desc_bytes, + size_t desc_size); +}; + +} // namespace synth_elf +} // namespace google_breakpad + +#endif // COMMON_LINUX_SYNTH_ELF_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc new file mode 100644 index 0000000000..cd74c28624 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc @@ -0,0 +1,413 @@ +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek + +// synth_elf_unittest.cc: +// Unittests for google_breakpad::synth_elf::ELF + +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/elfutils.h" +#include "common/linux/synth_elf.h" +#include "common/using_std_string.h" + +using google_breakpad::ElfClass32; +using google_breakpad::ElfClass64; +using google_breakpad::synth_elf::ELF; +using google_breakpad::synth_elf::Notes; +using google_breakpad::synth_elf::Section; +using google_breakpad::synth_elf::StringTable; +using google_breakpad::synth_elf::SymbolTable; +using google_breakpad::test_assembler::Endianness; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using ::testing::Test; +using ::testing::Types; + +class StringTableTest : public Test { +public: + StringTableTest() : table(kLittleEndian) {} + + StringTable table; +}; + +TEST_F(StringTableTest, Empty) { + EXPECT_EQ(1U, table.Size()); + string contents; + ASSERT_TRUE(table.GetContents(&contents)); + const char* kExpectedContents = "\0"; + EXPECT_EQ(0, memcmp(kExpectedContents, + contents.c_str(), + contents.size())); + ASSERT_TRUE(table.empty_string.IsKnownConstant()); + EXPECT_EQ(0U, table.empty_string.Value()); +} + +TEST_F(StringTableTest, Basic) { + const string s1("table fills with strings"); + const string s2("offsets preserved as labels"); + const string s3("verified with tests"); + const char* kExpectedContents = + "\0table fills with strings\0" + "offsets preserved as labels\0" + "verified with tests\0"; + Label l1(table.Add(s1)); + Label l2(table.Add(s2)); + Label l3(table.Add(s3)); + string contents; + ASSERT_TRUE(table.GetContents(&contents)); + EXPECT_EQ(0, memcmp(kExpectedContents, + contents.c_str(), + contents.size())); + // empty_string is at zero, other strings start at 1. + ASSERT_TRUE(l1.IsKnownConstant()); + EXPECT_EQ(1U, l1.Value()); + // Each string has an extra byte for a trailing null. + EXPECT_EQ(1 + s1.length() + 1, l2.Value()); + EXPECT_EQ(1 + s1.length() + 1 + s2.length() + 1, l3.Value()); +} + +TEST_F(StringTableTest, Duplicates) { + const string s1("string 1"); + const string s2("string 2"); + const string s3(""); + const char* kExpectedContents = "\0string 1\0string 2\0"; + Label l1(table.Add(s1)); + Label l2(table.Add(s2)); + // Adding strings twice should return the same Label. + Label l3(table.Add(s3)); + Label l4(table.Add(s2)); + string contents; + ASSERT_TRUE(table.GetContents(&contents)); + EXPECT_EQ(0, memcmp(kExpectedContents, + contents.c_str(), + contents.size())); + EXPECT_EQ(0U, table.empty_string.Value()); + EXPECT_EQ(table.empty_string.Value(), l3.Value()); + EXPECT_EQ(l2.Value(), l4.Value()); +} + +class SymbolTableTest : public Test {}; + +TEST_F(SymbolTableTest, Simple32) { + StringTable table(kLittleEndian); + SymbolTable syms(kLittleEndian, 4, table); + + const string kFuncName1 = "superfunc"; + const uint32_t kFuncAddr1 = 0x10001000; + const uint32_t kFuncSize1 = 0x10; + const string kFuncName2 = "awesomefunc"; + const uint32_t kFuncAddr2 = 0x20002000; + const uint32_t kFuncSize2 = 0x2f; + const string kFuncName3 = "megafunc"; + const uint32_t kFuncAddr3 = 0x30003000; + const uint32_t kFuncSize3 = 0x3c; + + syms.AddSymbol(kFuncName1, kFuncAddr1, kFuncSize1, + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF + 1); + syms.AddSymbol(kFuncName2, kFuncAddr2, kFuncSize2, + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), + SHN_UNDEF + 2); + syms.AddSymbol(kFuncName3, kFuncAddr3, kFuncSize3, + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), + SHN_UNDEF + 3); + + const char kExpectedStringTable[] = "\0superfunc\0awesomefunc\0megafunc"; + const size_t kExpectedStringTableSize = sizeof(kExpectedStringTable); + EXPECT_EQ(kExpectedStringTableSize, table.Size()); + string table_contents; + table.GetContents(&table_contents); + EXPECT_EQ(0, memcmp(kExpectedStringTable, + table_contents.c_str(), + table_contents.size())); + + const uint8_t kExpectedSymbolContents[] = { + // Symbol 1 + 0x01, 0x00, 0x00, 0x00, // name + 0x00, 0x10, 0x00, 0x10, // value + 0x10, 0x00, 0x00, 0x00, // size + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), // info + 0x00, // other + 0x01, 0x00, // shndx + // Symbol 2 + 0x0B, 0x00, 0x00, 0x00, // name + 0x00, 0x20, 0x00, 0x20, // value + 0x2f, 0x00, 0x00, 0x00, // size + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info + 0x00, // other + 0x02, 0x00, // shndx + // Symbol 3 + 0x17, 0x00, 0x00, 0x00, // name + 0x00, 0x30, 0x00, 0x30, // value + 0x3c, 0x00, 0x00, 0x00, // size + ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info + 0x00, // other + 0x03, 0x00, // shndx + }; + const size_t kExpectedSymbolSize = sizeof(kExpectedSymbolContents); + EXPECT_EQ(kExpectedSymbolSize, syms.Size()); + + string symbol_contents; + syms.GetContents(&symbol_contents); + EXPECT_EQ(0, memcmp(kExpectedSymbolContents, + symbol_contents.c_str(), + symbol_contents.size())); +} + +template +class BasicElf : public Test {}; + +// Doesn't seem worthwhile writing the tests to be endian-independent +// when they're unlikely to ever be run on big-endian systems. +#if defined(__i386__) || defined(__x86_64__) + +typedef Types ElfClasses; + +TYPED_TEST_SUITE(BasicElf, ElfClasses); + +TYPED_TEST(BasicElf, EmptyLE) { + typedef typename TypeParam::Ehdr Ehdr; + typedef typename TypeParam::Phdr Phdr; + typedef typename TypeParam::Shdr Shdr; + const size_t kStringTableSize = sizeof("\0.shstrtab"); + const size_t kStringTableAlign = 4 - kStringTableSize % 4; + const size_t kExpectedSize = sizeof(Ehdr) + + // Two sections, SHT_NULL + the section header string table. + 2 * sizeof(Shdr) + + kStringTableSize + kStringTableAlign; + + // It doesn't really matter that the machine type is right for the class. + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + elf.Finish(); + EXPECT_EQ(kExpectedSize, elf.Size()); + + string contents; + ASSERT_TRUE(elf.GetContents(&contents)); + ASSERT_EQ(kExpectedSize, contents.size()); + const Ehdr* header = + reinterpret_cast(contents.data()); + const uint8_t kIdent[] = { + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, + TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); + EXPECT_EQ(ET_EXEC, header->e_type); + EXPECT_EQ(EM_386, header->e_machine); + EXPECT_EQ(static_cast(EV_CURRENT), header->e_version); + EXPECT_EQ(0U, header->e_entry); + EXPECT_EQ(0U, header->e_phoff); + EXPECT_EQ(sizeof(Ehdr) + kStringTableSize + kStringTableAlign, + header->e_shoff); + EXPECT_EQ(0U, header->e_flags); + EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); + EXPECT_EQ(sizeof(Phdr), header->e_phentsize); + EXPECT_EQ(0, header->e_phnum); + EXPECT_EQ(sizeof(Shdr), header->e_shentsize); + EXPECT_EQ(2, header->e_shnum); + EXPECT_EQ(1, header->e_shstrndx); + + const Shdr* shdr = + reinterpret_cast(contents.data() + header->e_shoff); + EXPECT_EQ(0U, shdr[0].sh_name); + EXPECT_EQ(static_cast(SHT_NULL), shdr[0].sh_type); + EXPECT_EQ(0U, shdr[0].sh_flags); + EXPECT_EQ(0U, shdr[0].sh_addr); + EXPECT_EQ(0U, shdr[0].sh_offset); + EXPECT_EQ(0U, shdr[0].sh_size); + EXPECT_EQ(0U, shdr[0].sh_link); + EXPECT_EQ(0U, shdr[0].sh_info); + EXPECT_EQ(0U, shdr[0].sh_addralign); + EXPECT_EQ(0U, shdr[0].sh_entsize); + + EXPECT_EQ(1U, shdr[1].sh_name); + EXPECT_EQ(static_cast(SHT_STRTAB), shdr[1].sh_type); + EXPECT_EQ(0U, shdr[1].sh_flags); + EXPECT_EQ(0U, shdr[1].sh_addr); + EXPECT_EQ(sizeof(Ehdr), shdr[1].sh_offset); + EXPECT_EQ(kStringTableSize, shdr[1].sh_size); + EXPECT_EQ(0U, shdr[1].sh_link); + EXPECT_EQ(0U, shdr[1].sh_info); + EXPECT_EQ(0U, shdr[1].sh_addralign); + EXPECT_EQ(0U, shdr[1].sh_entsize); +} + +TYPED_TEST(BasicElf, BasicLE) { + typedef typename TypeParam::Ehdr Ehdr; + typedef typename TypeParam::Phdr Phdr; + typedef typename TypeParam::Shdr Shdr; + const size_t kStringTableSize = sizeof("\0.text\0.bss\0.shstrtab"); + const size_t kStringTableAlign = 4 - kStringTableSize % 4; + const size_t kExpectedSize = sizeof(Ehdr) + + // Four sections, SHT_NULL + the section header string table + + // 4096 bytes of the size-aligned .text section + one program header. + sizeof(Phdr) + 4 * sizeof(Shdr) + 4096 + + kStringTableSize + kStringTableAlign; + + // It doesn't really matter that the machine type is right for the class. + ELF elf(EM_386, TypeParam::kClass, kLittleEndian); + Section text(kLittleEndian); + text.Append(4094, 0); + int text_idx = elf.AddSection(".text", text, SHT_PROGBITS); + Section bss(kLittleEndian); + bss.Append(16, 0); + int bss_idx = elf.AddSection(".bss", bss, SHT_NOBITS); + elf.AddSegment(text_idx, bss_idx, PT_LOAD); + elf.Finish(); + EXPECT_EQ(kExpectedSize, elf.Size()); + + string contents; + ASSERT_TRUE(elf.GetContents(&contents)); + ASSERT_EQ(kExpectedSize, contents.size()); + const Ehdr* header = + reinterpret_cast(contents.data()); + const uint8_t kIdent[] = { + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, + TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); + EXPECT_EQ(ET_EXEC, header->e_type); + EXPECT_EQ(EM_386, header->e_machine); + EXPECT_EQ(static_cast(EV_CURRENT), header->e_version); + EXPECT_EQ(0U, header->e_entry); + EXPECT_EQ(sizeof(Ehdr), header->e_phoff); + EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096 + kStringTableSize + + kStringTableAlign, header->e_shoff); + EXPECT_EQ(0U, header->e_flags); + EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); + EXPECT_EQ(sizeof(Phdr), header->e_phentsize); + EXPECT_EQ(1, header->e_phnum); + EXPECT_EQ(sizeof(Shdr), header->e_shentsize); + EXPECT_EQ(4, header->e_shnum); + EXPECT_EQ(3, header->e_shstrndx); + + const Shdr* shdr = + reinterpret_cast(contents.data() + header->e_shoff); + EXPECT_EQ(0U, shdr[0].sh_name); + EXPECT_EQ(static_cast(SHT_NULL), shdr[0].sh_type); + EXPECT_EQ(0U, shdr[0].sh_flags); + EXPECT_EQ(0U, shdr[0].sh_addr); + EXPECT_EQ(0U, shdr[0].sh_offset); + EXPECT_EQ(0U, shdr[0].sh_size); + EXPECT_EQ(0U, shdr[0].sh_link); + EXPECT_EQ(0U, shdr[0].sh_info); + EXPECT_EQ(0U, shdr[0].sh_addralign); + EXPECT_EQ(0U, shdr[0].sh_entsize); + + EXPECT_EQ(1U, shdr[1].sh_name); + EXPECT_EQ(static_cast(SHT_PROGBITS), shdr[1].sh_type); + EXPECT_EQ(0U, shdr[1].sh_flags); + EXPECT_EQ(0U, shdr[1].sh_addr); + EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), shdr[1].sh_offset); + EXPECT_EQ(4094U, shdr[1].sh_size); + EXPECT_EQ(0U, shdr[1].sh_link); + EXPECT_EQ(0U, shdr[1].sh_info); + EXPECT_EQ(0U, shdr[1].sh_addralign); + EXPECT_EQ(0U, shdr[1].sh_entsize); + + EXPECT_EQ(sizeof("\0.text"), shdr[2].sh_name); + EXPECT_EQ(static_cast(SHT_NOBITS), shdr[2].sh_type); + EXPECT_EQ(0U, shdr[2].sh_flags); + EXPECT_EQ(0U, shdr[2].sh_addr); + EXPECT_EQ(0U, shdr[2].sh_offset); + EXPECT_EQ(16U, shdr[2].sh_size); + EXPECT_EQ(0U, shdr[2].sh_link); + EXPECT_EQ(0U, shdr[2].sh_info); + EXPECT_EQ(0U, shdr[2].sh_addralign); + EXPECT_EQ(0U, shdr[2].sh_entsize); + + EXPECT_EQ(sizeof("\0.text\0.bss"), shdr[3].sh_name); + EXPECT_EQ(static_cast(SHT_STRTAB), shdr[3].sh_type); + EXPECT_EQ(0U, shdr[3].sh_flags); + EXPECT_EQ(0U, shdr[3].sh_addr); + EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096, shdr[3].sh_offset); + EXPECT_EQ(kStringTableSize, shdr[3].sh_size); + EXPECT_EQ(0U, shdr[3].sh_link); + EXPECT_EQ(0U, shdr[3].sh_info); + EXPECT_EQ(0U, shdr[3].sh_addralign); + EXPECT_EQ(0U, shdr[3].sh_entsize); + + const Phdr* phdr = + reinterpret_cast(contents.data() + header->e_phoff); + EXPECT_EQ(static_cast(PT_LOAD), phdr->p_type); + EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), phdr->p_offset); + EXPECT_EQ(0U, phdr->p_vaddr); + EXPECT_EQ(0U, phdr->p_paddr); + EXPECT_EQ(4096U, phdr->p_filesz); + EXPECT_EQ(4096U + 16U, phdr->p_memsz); + EXPECT_EQ(0U, phdr->p_flags); + EXPECT_EQ(0U, phdr->p_align); +} + +class ElfNotesTest : public Test {}; + +TEST_F(ElfNotesTest, Empty) { + Notes notes(kLittleEndian); + string contents; + ASSERT_TRUE(notes.GetContents(&contents)); + EXPECT_EQ(0U, contents.size()); +} + +TEST_F(ElfNotesTest, Notes) { + Notes notes(kLittleEndian); + notes.AddNote(1, "Linux", reinterpret_cast("\x42\x02\0\0"), + 4); + notes.AddNote(2, "a", reinterpret_cast("foobar"), + sizeof("foobar") - 1); + + const uint8_t kExpectedNotesContents[] = { + // Note 1 + 0x06, 0x00, 0x00, 0x00, // name size, including terminating zero + 0x04, 0x00, 0x00, 0x00, // desc size + 0x01, 0x00, 0x00, 0x00, // type + 'L', 'i', 'n', 'u', 'x', 0x00, 0x00, 0x00, // padded "Linux" + 0x42, 0x02, 0x00, 0x00, // desc + // Note 2 + 0x02, 0x00, 0x00, 0x00, // name size + 0x06, 0x00, 0x00, 0x00, // desc size + 0x02, 0x00, 0x00, 0x00, // type + 'a', 0x00, 0x00, 0x00, // padded "a" + 'f', 'o', 'o', 'b', 'a', 'r', 0x00, 0x00, // padded "foobar" + }; + const size_t kExpectedNotesSize = sizeof(kExpectedNotesContents); + EXPECT_EQ(kExpectedNotesSize, notes.Size()); + + string notes_contents; + ASSERT_TRUE(notes.GetContents(¬es_contents)); + EXPECT_EQ(0, memcmp(kExpectedNotesContents, + notes_contents.data(), + notes_contents.size())); +} + +#endif // defined(__i386__) || defined(__x86_64__) diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h new file mode 100644 index 0000000000..92fe017b92 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h @@ -0,0 +1,124 @@ +// Copyright (c) 2013, 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. + +// Utility class for creating a temporary file for unit tests +// that is deleted in the destructor. + +#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE +#define GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE + +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/linux/eintr_wrapper.h" +#include "common/tests/auto_tempdir.h" + +namespace google_breakpad { + +class AutoTestFile { + public: + // Create a new empty test file. + // test_prefix: (input) test-specific prefix, can't be NULL. + explicit AutoTestFile(const char* test_prefix) { + Init(test_prefix); + } + + // Create a new test file, and fill it with initial data from a C string. + // The terminating zero is not written. + // test_prefix: (input) test-specific prefix, can't be NULL. + // text: (input) initial content. + AutoTestFile(const char* test_prefix, const char* text) { + Init(test_prefix); + if (fd_ >= 0) + WriteText(text, static_cast(strlen(text))); + } + + AutoTestFile(const char* test_prefix, const char* text, size_t text_len) { + Init(test_prefix); + if (fd_ >= 0) + WriteText(text, text_len); + } + + // Destroy test file on scope exit. + ~AutoTestFile() { + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } + } + + // Returns true iff the test file could be created properly. + // Useful in tests inside EXPECT_TRUE(file.IsOk()); + bool IsOk() { + return fd_ >= 0; + } + + // Returns the Posix file descriptor for the test file, or -1 + // If IsOk() returns false. Note: on Windows, this always returns -1. + int GetFd() { + return fd_; + } + + private: + void Init(const char* test_prefix) { + fd_ = -1; + char path_templ[PATH_MAX]; + int ret = snprintf(path_templ, sizeof(path_templ), + TEMPDIR "/%s-unittest.XXXXXX", + test_prefix); + if (ret >= static_cast(sizeof(path_templ))) + return; + + fd_ = mkstemp(path_templ); + if (fd_ < 0) + return; + + unlink(path_templ); + } + + void WriteText(const char* text, size_t text_len) { + ssize_t r = HANDLE_EINTR(write(fd_, text, text_len)); + if (r != static_cast(text_len)) { + close(fd_); + fd_ = -1; + return; + } + + lseek(fd_, 0, SEEK_SET); + } + + int fd_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc new file mode 100644 index 0000000000..6896a688d9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc @@ -0,0 +1,329 @@ +// Copyright (c) 2011, 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. + +// crash_generator.cc: Implement google_breakpad::CrashGenerator. +// See crash_generator.h for details. + +#include "common/linux/tests/crash_generator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(__ANDROID__) +#include "common/android/testing/pthread_fixes.h" +#endif +#include "common/linux/eintr_wrapper.h" +#include "common/tests/auto_tempdir.h" +#include "common/tests/file_utils.h" +#include "common/using_std_string.h" + +namespace { + +struct ThreadData { + pthread_t thread; + pthread_barrier_t* barrier; + pid_t* thread_id_ptr; +}; + +const char* const kProcFilesToCopy[] = { + "auxv", "cmdline", "environ", "maps", "status" +}; +const size_t kNumProcFilesToCopy = + sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]); + +int gettid() { + // Glibc does not provide a wrapper for this. + return syscall(__NR_gettid); +} + +int tkill(pid_t tid, int sig) { + // Glibc does not provide a wrapper for this. + return syscall(__NR_tkill, tid, sig); +} + +// Core file size limit set to 1 MB, which is big enough for test purposes. +const rlim_t kCoreSizeLimit = 1024 * 1024; + +void *thread_function(void *data) { + ThreadData* thread_data = reinterpret_cast(data); + volatile pid_t thread_id = gettid(); + *(thread_data->thread_id_ptr) = thread_id; + int result = pthread_barrier_wait(thread_data->barrier); + if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { + perror("Failed to wait for sync barrier"); + exit(1); + } + while (true) { + sched_yield(); + } +} + +} // namespace + +namespace google_breakpad { + +CrashGenerator::CrashGenerator() + : shared_memory_(NULL), + shared_memory_size_(0) { +} + +CrashGenerator::~CrashGenerator() { + UnmapSharedMemory(); +} + +bool CrashGenerator::HasDefaultCorePattern() const { + char buffer[8]; + ssize_t buffer_size = sizeof(buffer); + return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) && + buffer_size == 5 && memcmp(buffer, "core", 4) == 0; +} + +string CrashGenerator::GetCoreFilePath() const { + return temp_dir_.path() + "/core"; +} + +string CrashGenerator::GetDirectoryOfProcFilesCopy() const { + return temp_dir_.path() + "/proc"; +} + +pid_t CrashGenerator::GetThreadId(unsigned index) const { + return reinterpret_cast(shared_memory_)[index]; +} + +pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) { + return reinterpret_cast(shared_memory_) + index; +} + +bool CrashGenerator::MapSharedMemory(size_t memory_size) { + if (!UnmapSharedMemory()) + return false; + + void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (mapped_memory == MAP_FAILED) { + perror("CrashGenerator: Failed to map shared memory"); + return false; + } + + memset(mapped_memory, 0, memory_size); + shared_memory_ = mapped_memory; + shared_memory_size_ = memory_size; + return true; +} + +bool CrashGenerator::UnmapSharedMemory() { + if (!shared_memory_) + return true; + + if (munmap(shared_memory_, shared_memory_size_) == 0) { + shared_memory_ = NULL; + shared_memory_size_ = 0; + return true; + } + + perror("CrashGenerator: Failed to unmap shared memory"); + return false; +} + +bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const { + struct rlimit limits = { limit, limit }; + if (setrlimit(RLIMIT_CORE, &limits) == -1) { + perror("CrashGenerator: Failed to set core file size limit"); + return false; + } + return true; +} + +bool CrashGenerator::CreateChildCrash( + unsigned num_threads, unsigned crash_thread, int crash_signal, + pid_t* child_pid) { + if (num_threads == 0 || crash_thread >= num_threads) { + fprintf(stderr, "CrashGenerator: Invalid thread counts; num_threads=%u" + " crash_thread=%u\n", num_threads, crash_thread); + return false; + } + + if (!MapSharedMemory(num_threads * sizeof(pid_t))) { + perror("CrashGenerator: Unable to map shared memory"); + return false; + } + + pid_t pid = fork(); + if (pid == 0) { + // Custom signal handlers, which may have been installed by a test launcher, + // are undesirable in this child. + if (signal(crash_signal, SIG_DFL) == SIG_ERR) { + perror("CrashGenerator: signal"); + exit(1); + } + if (chdir(temp_dir_.path().c_str()) == -1) { + perror("CrashGenerator: Failed to change directory"); + exit(1); + } + if (SetCoreFileSizeLimit(kCoreSizeLimit)) { + CreateThreadsInChildProcess(num_threads); + string proc_dir = GetDirectoryOfProcFilesCopy(); + if (mkdir(proc_dir.c_str(), 0755) == -1) { + perror("CrashGenerator: Failed to create proc directory"); + exit(1); + } + if (!CopyProcFiles(getpid(), proc_dir.c_str())) { + fprintf(stderr, "CrashGenerator: Failed to copy proc files\n"); + exit(1); + } + // On Android the signal sometimes doesn't seem to get sent even though + // tkill returns '0'. Retry a couple of times if the signal doesn't get + // through on the first go: + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=579 +#if defined(__ANDROID__) + const int kRetries = 60; + const unsigned int kSleepTimeInSeconds = 1; +#else + const int kRetries = 1; + const unsigned int kSleepTimeInSeconds = 600; +#endif + for (int i = 0; i < kRetries; i++) { + if (tkill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) { + perror("CrashGenerator: Failed to kill thread by signal"); + } else { + // At this point, we've queued the signal for delivery, but there's no + // guarantee when it'll be delivered. We don't want the main thread to + // race and exit before the thread we signaled is processed. So sleep + // long enough that we won't flake even under fairly high load. + // TODO: See if we can't be a bit more deterministic. There doesn't + // seem to be an API to check on signal delivery status, so we can't + // really poll and wait for the kernel to declare the signal has been + // delivered. If it has, and things worked, we'd be killed, so the + // sleep length doesn't really matter. + sleep(kSleepTimeInSeconds); + } + } + } else { + perror("CrashGenerator: Failed to set core limit"); + } + exit(1); + } else if (pid == -1) { + perror("CrashGenerator: Failed to create child process"); + return false; + } + + int status; + if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) { + perror("CrashGenerator: Failed to wait for child process"); + return false; + } + if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) { + fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n" + " exit status=0x%x pid=%u signaled=%s sig=%d expected=%d\n", + status, pid, WIFSIGNALED(status) ? "true" : "false", + WTERMSIG(status), crash_signal); + return false; + } + + if (child_pid) + *child_pid = pid; + return true; +} + +bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const { + char from_path[PATH_MAX], to_path[PATH_MAX]; + for (size_t i = 0; i < kNumProcFilesToCopy; ++i) { + int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s", + pid, kProcFilesToCopy[i]); + if (num_chars < 0 || num_chars >= PATH_MAX) + return false; + + num_chars = snprintf(to_path, PATH_MAX, "%s/%s", + path, kProcFilesToCopy[i]); + if (num_chars < 0 || num_chars >= PATH_MAX) + return false; + + if (!CopyFile(from_path, to_path)) + return false; + } + return true; +} + +void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) { + *GetThreadIdPointer(0) = getpid(); + + if (num_threads <= 1) + return; + + // This method does not clean up any pthread resource, as the process + // is expected to be killed anyway. + ThreadData* thread_data = new ThreadData[num_threads]; + + // Create detached threads so that we do not worry about pthread_join() + // later being called or not. + pthread_attr_t thread_attributes; + if (pthread_attr_init(&thread_attributes) != 0 || + pthread_attr_setdetachstate(&thread_attributes, + PTHREAD_CREATE_DETACHED) != 0) { + fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n"); + exit(1); + } + + pthread_barrier_t thread_barrier; + if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) { + fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n"); + exit(1); + } + + for (unsigned i = 1; i < num_threads; ++i) { + thread_data[i].barrier = &thread_barrier; + thread_data[i].thread_id_ptr = GetThreadIdPointer(i); + if (pthread_create(&thread_data[i].thread, &thread_attributes, + thread_function, &thread_data[i]) != 0) { + fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i); + exit(1); + } + } + + int result = pthread_barrier_wait(&thread_barrier); + if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { + fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n"); + exit(1); + } + + pthread_barrier_destroy(&thread_barrier); + pthread_attr_destroy(&thread_attributes); + delete[] thread_data; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h new file mode 100644 index 0000000000..7e2fcbf98a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h @@ -0,0 +1,117 @@ +// Copyright (c) 2011, 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. + +// crash_generator.h: Define the google_breakpad::CrashGenerator class, +// which is used to generate a crash (and a core dump file) for testing. + +#ifndef COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ +#define COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ + +#include + +#include + +#include "common/tests/auto_tempdir.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A utility class for generating a crash (and a core dump file) for +// testing. It creates a child process with the specified number of +// threads, which is then termainated by the specified signal. A core +// dump file is expected to be created upon the termination of the child +// process, which can then be used for testing code that processes core +// dump files. +class CrashGenerator { + public: + CrashGenerator(); + + ~CrashGenerator(); + + // Returns true if a core dump file named 'core' will be generated in + // the current directory for a test that produces a crash by checking + // if /proc/sys/kernel/core_pattern has the default value 'core'. + bool HasDefaultCorePattern() const; + + // Returns the expected path of the core dump file. + string GetCoreFilePath() const; + + // Returns the directory of a copy of proc files of the child process. + string GetDirectoryOfProcFilesCopy() const; + + // Creates a crash (and a core dump file) by creating a child process with + // |num_threads| threads, and the terminating the child process by sending + // a signal with number |crash_signal| to the |crash_thread|-th thread. + // Returns true on success. + bool CreateChildCrash(unsigned num_threads, unsigned crash_thread, + int crash_signal, pid_t* child_pid); + + // Returns the thread ID of the |index|-th thread in the child process. + // This method does not validate |index|. + pid_t GetThreadId(unsigned index) const; + + private: + // Copies the following proc files of the process with |pid| to the directory + // at |path|: auxv, cmdline, environ, maps, status + // The directory must have been created. Returns true on success. + bool CopyProcFiles(pid_t pid, const char* path) const; + + // Creates |num_threads| threads in the child process. + void CreateThreadsInChildProcess(unsigned num_threads); + + // Sets the maximum size of core dump file (both the soft and hard limit) + // to |limit| bytes. Returns true on success. + bool SetCoreFileSizeLimit(rlim_t limit) const; + + // Creates a shared memory of |memory_size| bytes for communicating thread + // IDs between the parent and child process. Returns true on success. + bool MapSharedMemory(size_t memory_size); + + // Releases any shared memory created by MapSharedMemory(). Returns true on + // success. + bool UnmapSharedMemory(); + + // Returns the pointer to the thread ID of the |index|-th thread in the child + // process. This method does not validate |index|. + pid_t* GetThreadIdPointer(unsigned index); + + // Temporary directory in which a core file is generated. + AutoTempDir temp_dir_; + + // Shared memory for communicating thread IDs between the parent and + // child process. + void* shared_memory_; + + // Number of bytes mapped for |shared_memory_|. + size_t shared_memory_size_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/ucontext_constants.h b/toolkit/crashreporter/google-breakpad/src/common/linux/ucontext_constants.h new file mode 100644 index 0000000000..c390508a1a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/ucontext_constants.h @@ -0,0 +1,153 @@ +// Copyright (c) 2012, 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. + +// This header can be included either from a C, C++ or Assembly file. +// Its purpose is to contain constants that must match the offsets of +// various fields in ucontext_t. +// +// They should match the definitions from signal.h. +// +// Used by src/common/linux/breakpad_getcontext.S +// Tested by src/common/linux/breakpad_getcontext_unittest.cc +// +// This header should not be used by anything else. + +#ifndef GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H +#define GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H + +#if defined(__arm__) + +#define MCONTEXT_GREGS_OFFSET 32 +#define UCONTEXT_SIGMASK_OFFSET 104 + +#elif defined(__aarch64__) + +#define UCONTEXT_SIGMASK_OFFSET 40 + +#define MCONTEXT_GREGS_OFFSET 184 +#define MCONTEXT_SP_OFFSET 432 +#define MCONTEXT_PC_OFFSET 440 +#define MCONTEXT_PSTATE_OFFSET 448 +#define MCONTEXT_EXTENSION_OFFSET 464 + +#define FPSIMD_MAGIC 0x46508001 + +#define FPSIMD_CONTEXT_MAGIC_OFFSET 0 +#define FPSIMD_CONTEXT_SIZE_OFFSET 4 +#define FPSIMD_CONTEXT_FPSR_OFFSET 8 +#define FPSIMD_CONTEXT_FPCR_OFFSET 12 +#define FPSIMD_CONTEXT_VREGS_OFFSET 16 +#define FPSIMD_CONTEXT_SIZE 528 + +#define REGISTER_SIZE 8 +#define SIMD_REGISTER_SIZE 16 + +#elif defined(__i386__) + +#define MCONTEXT_GREGS_OFFSET 20 +#define MCONTEXT_GS_OFFSET (MCONTEXT_GREGS_OFFSET + 0*4) +#define MCONTEXT_FS_OFFSET (MCONTEXT_GREGS_OFFSET + 1*4) +#define MCONTEXT_ES_OFFSET (MCONTEXT_GREGS_OFFSET + 2*4) +#define MCONTEXT_DS_OFFSET (MCONTEXT_GREGS_OFFSET + 3*4) +#define MCONTEXT_EDI_OFFSET (MCONTEXT_GREGS_OFFSET + 4*4) +#define MCONTEXT_ESI_OFFSET (MCONTEXT_GREGS_OFFSET + 5*4) +#define MCONTEXT_EBP_OFFSET (MCONTEXT_GREGS_OFFSET + 6*4) +#define MCONTEXT_ESP_OFFSET (MCONTEXT_GREGS_OFFSET + 7*4) +#define MCONTEXT_EBX_OFFSET (MCONTEXT_GREGS_OFFSET + 8*4) +#define MCONTEXT_EDX_OFFSET (MCONTEXT_GREGS_OFFSET + 9*4) +#define MCONTEXT_ECX_OFFSET (MCONTEXT_GREGS_OFFSET + 10*4) +#define MCONTEXT_EAX_OFFSET (MCONTEXT_GREGS_OFFSET + 11*4) +#define MCONTEXT_TRAPNO_OFFSET (MCONTEXT_GREGS_OFFSET + 12*4) +#define MCONTEXT_ERR_OFFSET (MCONTEXT_GREGS_OFFSET + 13*4) +#define MCONTEXT_EIP_OFFSET (MCONTEXT_GREGS_OFFSET + 14*4) +#define MCONTEXT_CS_OFFSET (MCONTEXT_GREGS_OFFSET + 15*4) +#define MCONTEXT_EFL_OFFSET (MCONTEXT_GREGS_OFFSET + 16*4) +#define MCONTEXT_UESP_OFFSET (MCONTEXT_GREGS_OFFSET + 17*4) +#define MCONTEXT_SS_OFFSET (MCONTEXT_GREGS_OFFSET + 18*4) + +#define UCONTEXT_SIGMASK_OFFSET 108 + +#define UCONTEXT_FPREGS_OFFSET 96 +#if defined(__BIONIC__) +#define UCONTEXT_FPREGS_MEM_OFFSET 116 +#else +#define UCONTEXT_FPREGS_MEM_OFFSET 236 +#endif + +#elif defined(__mips__) + +#if _MIPS_SIM == _ABIO32 +#define MCONTEXT_PC_OFFSET 32 +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_FPC_CSR 556 +#define UCONTEXT_SIGMASK_OFFSET 616 +#else +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_PC_OFFSET 616 +#define MCONTEXT_FPC_CSR 624 +#define UCONTEXT_SIGMASK_OFFSET 640 +#endif + +#elif defined(__x86_64__) + +#define MCONTEXT_GREGS_OFFSET 40 +#define UCONTEXT_SIGMASK_OFFSET 296 + +#define MCONTEXT_GREGS_R8 40 +#define MCONTEXT_GREGS_R9 48 +#define MCONTEXT_GREGS_R10 56 +#define MCONTEXT_GREGS_R11 64 +#define MCONTEXT_GREGS_R12 72 +#define MCONTEXT_GREGS_R13 80 +#define MCONTEXT_GREGS_R14 88 +#define MCONTEXT_GREGS_R15 96 +#define MCONTEXT_GREGS_RDI 104 +#define MCONTEXT_GREGS_RSI 112 +#define MCONTEXT_GREGS_RBP 120 +#define MCONTEXT_GREGS_RBX 128 +#define MCONTEXT_GREGS_RDX 136 +#define MCONTEXT_GREGS_RAX 144 +#define MCONTEXT_GREGS_RCX 152 +#define MCONTEXT_GREGS_RSP 160 +#define MCONTEXT_GREGS_RIP 168 +#define MCONTEXT_FPREGS_PTR 224 +#if defined(__BIONIC__) +#define MCONTEXT_FPREGS_MEM 304 +#else +#define MCONTEXT_FPREGS_MEM 424 +#endif +#define FPREGS_OFFSET_MXCSR 24 + +#else +#error "This header has not been ported for your CPU" +#endif + +#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.cc b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.cc new file mode 100644 index 0000000000..46bbf61370 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.cc @@ -0,0 +1,178 @@ +// Copyright (c) 2017, 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 "common/long_string_dictionary.h" + +#include +#include + +#include +#include + +#include "common/simple_string_dictionary.h" + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +namespace { +// Suffixes for segment keys. +const char* const kSuffixes[] = {"__1", "__2", "__3", "__4", "__5", "__6", + "__7", "__8", "__9", "__10"}; +#if !defined(NDEBUG) +// The maximum suffix string length. +const size_t kMaxSuffixLength = 4; +#endif +} // namespace + +namespace google_breakpad { + +using std::string; + +void LongStringDictionary::SetKeyValue(const char* key, const char* value) { + assert(key); + if (!key) + return; + + RemoveKey(key); + + if (!value) { + return; + } + + // Key must not be an empty string. + assert(key[0] != '\0'); + if (key[0] == '\0') + return; + + // If the value is not valid for segmentation, forwards the key and the value + // to SetKeyValue of SimpleStringDictionary and returns. + size_t value_length = strlen(value); + if (value_length <= (value_size - 1)) { + SimpleStringDictionary::SetKeyValue(key, value); + return; + } + + size_t key_length = strlen(key); + assert(key_length + kMaxSuffixLength <= (key_size - 1)); + + char segment_key[key_size]; + char segment_value[value_size]; + + strcpy(segment_key, key); + + const char* remain_value = value; + size_t remain_value_length = strlen(value); + + for (unsigned long i = 0; i < arraysize(kSuffixes); i++) { + if (remain_value_length == 0) { + return; + } + + strcpy(segment_key + key_length, kSuffixes[i]); + + size_t segment_value_length = + std::min(remain_value_length, value_size - 1); + + strncpy(segment_value, remain_value, segment_value_length); + segment_value[segment_value_length] = '\0'; + + remain_value += segment_value_length; + remain_value_length -= segment_value_length; + + SimpleStringDictionary::SetKeyValue(segment_key, segment_value); + } +} + +bool LongStringDictionary::RemoveKey(const char* key) { + assert(key); + if (!key) + return false; + + if (SimpleStringDictionary::RemoveKey(key)) { + return true; + } + + size_t key_length = strlen(key); + assert(key_length + kMaxSuffixLength <= (key_size - 1)); + + char segment_key[key_size]; + strcpy(segment_key, key); + + unsigned long i = 0; + for (; i < arraysize(kSuffixes); i++) { + strcpy(segment_key + key_length, kSuffixes[i]); + if (!SimpleStringDictionary::RemoveKey(segment_key)) { + break; + } + } + return i != 0; +} + +const string LongStringDictionary::GetValueForKey(const char* key) const { + assert(key); + if (!key) + return ""; + + // Key must not be an empty string. + assert(key[0] != '\0'); + if (key[0] == '\0') + return ""; + + const char* value = SimpleStringDictionary::GetValueForKey(key); + if (value) + return string(value); + + size_t key_length = strlen(key); + assert(key_length + kMaxSuffixLength <= (key_size - 1)); + + bool found_segment = false; + char segment_key[key_size]; + string return_value; + + strcpy(segment_key, key); + for (unsigned long i = 0; i < arraysize(kSuffixes); i++) { + strcpy(segment_key + key_length, kSuffixes[i]); + + const char* segment_value = + SimpleStringDictionary::GetValueForKey(segment_key); + + if (segment_value != NULL) { + found_segment = true; + return_value.append(segment_value); + } else { + break; + } + } + + if (found_segment) { + return return_value; + } + return ""; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.h b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.h new file mode 100644 index 0000000000..68bf03de2f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary.h @@ -0,0 +1,87 @@ +// Copyright (c) 2017, 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 COMMON_LONG_STRING_DICTIONARY_H_ +#define COMMON_LONG_STRING_DICTIONARY_H_ + +#include + +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { +// key_size is the maxium size that |key| can take in +// SimpleStringDictionary which is defined in simple_string_dictionary.h. +// +// value_size is the maxium size that |value| can take in +// SimpleStringDictionary which is defined in simple_string_dictionary.h. +// +// LongStringDictionary is a subclass of SimpleStringDictionary which supports +// longer values to be stored in the dictionary. The maximum length supported is +// (value_size - 1) * 10. +// +// For example, LongStringDictionary will store long value with key 'abc' into +// segment values with segment keys 'abc__1', 'abc__2', 'abc__3', ... +// +// Clients must avoid using the same suffixes as their key's suffix when +// LongStringDictionary is used. +class LongStringDictionary : public SimpleStringDictionary { + public: + // Stores |value| into |key|, or segment values into segment keys. The maxium + // number of segments is 10. If |value| can not be stored in 10 segments, it + // will be truncated. Replacing the existing value if |key| is already present + // and replacing the existing segment values if segment keys are already + // present. + // + // |key| must not be NULL. If the |value| need to be divided into segments, + // the lengh of |key| must be smaller enough so that lengths of segment keys + // which are key with suffixes are all samller than (key_size - 1). Currently, + // the max length of suffixes are 4. + // + // If |value| is NULL, the key and its corresponding segment keys are removed + // from the map. If there is no more space in the map, then the operation + // silently fails. + void SetKeyValue(const char* key, const char* value); + + // Given |key|, removes any associated value or associated segment values. + // |key| must not be NULL. If the key is not found, searchs its segment keys + // and removes corresponding segment values if found. + bool RemoveKey(const char* key); + + // Given |key|, returns its corresponding |value|. |key| must not be NULL. If + // the key is found, its corresponding |value| is returned. + // + // If no corresponding |value| is found, segment keys of the given |key| will + // be used to search for corresponding segment values. If segment values + // exist, assembled value from them is returned. If no segment value exists, + // NULL is returned. + const std::string GetValueForKey(const char* key) const; +}; +} // namespace google_breakpad + +#endif // COMMON_LONG_STRING_DICTIONARY_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary_unittest.cc new file mode 100644 index 0000000000..f9b645ba7b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/long_string_dictionary_unittest.cc @@ -0,0 +1,301 @@ +// Copyright (c) 2017, 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 +#include + +#include "breakpad_googletest_includes.h" +#include "common/long_string_dictionary.h" + +namespace google_breakpad { + +using std::string; + +TEST(LongStringDictionary, LongStringDictionary) { + // Make a new dictionary + LongStringDictionary dict; + + // Set three distinct values on three keys + dict.SetKeyValue("key1", "value1"); + dict.SetKeyValue("key2", "value2"); + dict.SetKeyValue("key3", "value3"); + + EXPECT_EQ("value1", dict.GetValueForKey("key1")); + EXPECT_EQ("value2", dict.GetValueForKey("key2")); + EXPECT_EQ("value3", dict.GetValueForKey("key3")); + EXPECT_EQ(3u, dict.GetCount()); + // try an unknown key + EXPECT_EQ("", dict.GetValueForKey("key4")); + + // Remove a key + dict.RemoveKey("key3"); + + // Now make sure it's not there anymore + EXPECT_EQ("", dict.GetValueForKey("key3")); + + // Remove by setting value to NULL + dict.SetKeyValue("key2", NULL); + + // Now make sure it's not there anymore + EXPECT_EQ("", dict.GetValueForKey("key2")); +} + +// Add a bunch of values to the dictionary, remove some entries in the middle, +// and then add more. +TEST(LongStringDictionary, Iterator) { + LongStringDictionary* dict = new LongStringDictionary(); + ASSERT_TRUE(dict); + + char key[LongStringDictionary::key_size]; + char value[LongStringDictionary::value_size]; + + const int kDictionaryCapacity = LongStringDictionary::num_entries; + const int kPartitionIndex = kDictionaryCapacity - 5; + + // We assume at least this size in the tests below + ASSERT_GE(kDictionaryCapacity, 64); + + // We'll keep track of the number of key/value pairs we think should + // be in the dictionary + int expectedDictionarySize = 0; + + // Set a bunch of key/value pairs like key0/value0, key1/value1, ... + for (int i = 0; i < kPartitionIndex; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize = kPartitionIndex; + + // set a couple of the keys twice (with the same value) - should be nop + dict->SetKeyValue("key2", "value2"); + dict->SetKeyValue("key4", "value4"); + dict->SetKeyValue("key15", "value15"); + + // Remove some random elements in the middle + dict->RemoveKey("key7"); + dict->RemoveKey("key18"); + dict->RemoveKey("key23"); + dict->RemoveKey("key31"); + expectedDictionarySize -= 4; // we just removed four key/value pairs + + // Set some more key/value pairs like key59/value59, key60/value60, ... + for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; + + // Now create an iterator on the dictionary + SimpleStringDictionary::Iterator iter(*dict); + + // We then verify that it iterates through exactly the number of + // key/value pairs we expect, and that they match one-for-one with what we + // would expect. The ordering of the iteration does not matter... + + // used to keep track of number of occurrences found for key/value pairs + int count[kDictionaryCapacity]; + memset(count, 0, sizeof(count)); + + int totalCount = 0; + + const SimpleStringDictionary::Entry* entry; + while ((entry = iter.Next())) { + totalCount++; + + // Extract keyNumber from a string of the form key + int keyNumber; + sscanf(entry->key, "key%d", &keyNumber); + + // Extract valueNumber from a string of the form value + int valueNumber; + sscanf(entry->value, "value%d", &valueNumber); + + // The value number should equal the key number since that's how we set them + EXPECT_EQ(keyNumber, valueNumber); + + // Key and value numbers should be in proper range: + // 0 <= keyNumber < kDictionaryCapacity + bool isKeyInGoodRange = (keyNumber >= 0 && keyNumber < kDictionaryCapacity); + bool isValueInGoodRange = + (valueNumber >= 0 && valueNumber < kDictionaryCapacity); + EXPECT_TRUE(isKeyInGoodRange); + EXPECT_TRUE(isValueInGoodRange); + + if (isKeyInGoodRange && isValueInGoodRange) { + ++count[keyNumber]; + } + } + + // Make sure each of the key/value pairs showed up exactly one time, except + // for the ones which we removed. + for (size_t i = 0; i < kDictionaryCapacity; ++i) { + // Skip over key7, key18, key23, and key31, since we removed them + if (!(i == 7 || i == 18 || i == 23 || i == 31)) { + EXPECT_EQ(count[i], 1); + } + } + + // Make sure the number of iterations matches the expected dictionary size. + EXPECT_EQ(totalCount, expectedDictionarySize); +} + +TEST(LongStringDictionary, AddRemove) { + LongStringDictionary dict; + dict.SetKeyValue("rob", "ert"); + dict.SetKeyValue("mike", "pink"); + dict.SetKeyValue("mark", "allays"); + + EXPECT_EQ(3u, dict.GetCount()); + EXPECT_EQ("ert", dict.GetValueForKey("rob")); + EXPECT_EQ("pink", dict.GetValueForKey("mike")); + EXPECT_EQ("allays", dict.GetValueForKey("mark")); + + dict.RemoveKey("mike"); + + EXPECT_EQ(2u, dict.GetCount()); + EXPECT_EQ("", dict.GetValueForKey("mike")); + + dict.SetKeyValue("mark", "mal"); + EXPECT_EQ(2u, dict.GetCount()); + EXPECT_EQ("mal", dict.GetValueForKey("mark")); + + dict.RemoveKey("mark"); + EXPECT_EQ(1u, dict.GetCount()); + EXPECT_EQ("", dict.GetValueForKey("mark")); +} + +TEST(LongStringDictionary, AddRemoveLongValue) { + LongStringDictionary dict; + + string long_value = string(256, 'x'); + dict.SetKeyValue("rob", long_value.c_str()); + + EXPECT_EQ(2u, dict.GetCount()); + + string long_value_part_1 = string(255, 'x'); + + EXPECT_EQ(long_value_part_1, dict.GetValueForKey("rob__1")); + EXPECT_EQ("x", dict.GetValueForKey("rob__2")); + + EXPECT_EQ(long_value, dict.GetValueForKey("rob")); + + dict.RemoveKey("rob"); + EXPECT_EQ(0u, dict.GetCount()); +} + +TEST(LongStringDictionary, AddRemoveSuperLongValue) { + LongStringDictionary dict; + + string long_value = string(255 * 10, 'x'); + dict.SetKeyValue("rob", long_value.c_str()); + + EXPECT_EQ(10u, dict.GetCount()); + + string long_value_part = string(255, 'x'); + + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__1")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__2")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__3")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__4")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__5")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__6")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__7")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__8")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__9")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__10")); + EXPECT_EQ(10u, dict.GetCount()); + + EXPECT_EQ(long_value, dict.GetValueForKey("rob")); + + dict.RemoveKey("rob"); + EXPECT_EQ(0u, dict.GetCount()); +} + +TEST(LongStringDictionary, TruncateSuperLongValue) { + LongStringDictionary dict; + + string long_value = string(255 * 11, 'x'); + dict.SetKeyValue("rob", long_value.c_str()); + + EXPECT_EQ(10u, dict.GetCount()); + + string long_value_part = string(255, 'x'); + + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__1")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__2")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__3")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__4")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__5")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__6")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__7")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__8")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__9")); + EXPECT_EQ(long_value_part, dict.GetValueForKey("rob__10")); + EXPECT_EQ(10u, dict.GetCount()); + + string expected_long_value = string(255 * 10, 'x'); + EXPECT_EQ(expected_long_value, dict.GetValueForKey("rob")); + + dict.RemoveKey("rob"); + EXPECT_EQ(0u, dict.GetCount()); +} + +TEST(LongStringDictionary, OverrideLongValue) { + LongStringDictionary dict; + + string long_value = string(255 * 10, 'x'); + dict.SetKeyValue("rob", long_value.c_str()); + + EXPECT_EQ(10u, dict.GetCount()); + EXPECT_EQ(long_value, dict.GetValueForKey("rob")); + + dict.SetKeyValue("rob", "short_value"); + + EXPECT_EQ(1u, dict.GetCount()); + EXPECT_EQ("short_value", dict.GetValueForKey("rob")); +} + +TEST(LongStringDictionary, OverrideShortValue) { + LongStringDictionary dict; + + dict.SetKeyValue("rob", "short_value"); + + EXPECT_EQ(1u, dict.GetCount()); + EXPECT_EQ("short_value", dict.GetValueForKey("rob")); + + string long_value = string(255 * 10, 'x'); + dict.SetKeyValue("rob", long_value.c_str()); + + EXPECT_EQ(10u, dict.GetCount()); + EXPECT_EQ(long_value, dict.GetValueForKey("rob")); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig new file mode 100644 index 0000000000..f091369081 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig @@ -0,0 +1,52 @@ +// Copyright (c) 2010, 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. + +GCC_C_LANGUAGE_STANDARD = c99 + +GCC_WARN_CHECK_SWITCH_STATEMENTS = YES +// TODO(nealsid): Get the code so we can turn on the 64_TO_32 warning. +GCC_WARN_64_TO_32_BIT_CONVERSION = NO +GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES +GCC_WARN_ABOUT_RETURN_TYPE = YES +GCC_WARN_MISSING_PARENTHESES = YES + +// Once https://bugs.chromium.org/p/google-breakpad/issues/detail?id=697 +// is fixed this should be reenabled. +//GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES +GCC_WARN_ABOUT_MISSING_NEWLINE = YES +GCC_WARN_SIGN_COMPARE = YES +GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES +GCC_WARN_UNDECLARED_SELECTOR = YES +GCC_WARN_UNKNOWN_PRAGMAS = YES +GCC_WARN_UNUSED_VARIABLE = YES +GCC_TREAT_WARNINGS_AS_ERRORS = YES + +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym + +ALWAYS_SEARCH_USER_PATHS = NO diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig new file mode 100644 index 0000000000..94cdd8cfca --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig @@ -0,0 +1,32 @@ +// Copyright (c) 2010, 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 "Breakpad.xcconfig" + +GCC_OPTIMIZATION_LEVEL = 0 diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig new file mode 100644 index 0000000000..920f277db8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig @@ -0,0 +1,34 @@ +// Copyright (c) 2010, 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 "Breakpad.xcconfig" + +GCC_OPTIMIZATION_LEVEL = s +GCC_WARN_UNINITIALIZED_AUTOS = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h new file mode 100644 index 0000000000..fce2990a3e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h @@ -0,0 +1,396 @@ +// +// GTMDefines.h +// +// Copyright 2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// ============================================================================ + +#include +#include + +#ifdef __OBJC__ +#include +#endif // __OBJC__ + +#if TARGET_OS_IPHONE +#include +#endif // TARGET_OS_IPHONE + +// Not all __IPHONE_X macros defined in past SDKs +#ifndef __IPHONE_3_0 + #define __IPHONE_3_0 30000 +#endif +#ifndef __IPHONE_3_1 + #define __IPHONE_3_1 30100 +#endif +#ifndef __IPHONE_3_2 + #define __IPHONE_3_2 30200 +#endif +#ifndef __IPHONE_4_0 + #define __IPHONE_4_0 40000 +#endif +#ifndef __IPHONE_4_3 + #define __IPHONE_4_3 40300 +#endif +#ifndef __IPHONE_5_0 + #define __IPHONE_5_0 50000 +#endif + +// ---------------------------------------------------------------------------- +// CPP symbols that can be overridden in a prefix to control how the toolbox +// is compiled. +// ---------------------------------------------------------------------------- + + +// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and +// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens +// when a validation fails. If you implement your own validators, you may want +// to control their internals using the same macros for consistency. +#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT + #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 +#endif + +// Give ourselves a consistent way to do inlines. Apple's macros even use +// a few different actual definitions, so we're based off of the foundation +// one. +#if !defined(GTM_INLINE) + #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__) + #define GTM_INLINE static __inline__ __attribute__((always_inline)) + #else + #define GTM_INLINE static __inline__ + #endif +#endif + +// Give ourselves a consistent way of doing externs that links up nicely +// when mixing objc and objc++ +#if !defined (GTM_EXTERN) + #if defined __cplusplus + #define GTM_EXTERN extern "C" + #define GTM_EXTERN_C_BEGIN extern "C" { + #define GTM_EXTERN_C_END } + #else + #define GTM_EXTERN extern + #define GTM_EXTERN_C_BEGIN + #define GTM_EXTERN_C_END + #endif +#endif + +// Give ourselves a consistent way of exporting things if we have visibility +// set to hidden. +#if !defined (GTM_EXPORT) + #define GTM_EXPORT __attribute__((visibility("default"))) +#endif + +// Give ourselves a consistent way of declaring something as unused. This +// doesn't use __unused because that is only supported in gcc 4.2 and greater. +#if !defined (GTM_UNUSED) +#define GTM_UNUSED(x) ((void)(x)) +#endif + +// _GTMDevLog & _GTMDevAssert +// +// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for +// developer level errors. This implementation simply macros to NSLog/NSAssert. +// It is not intended to be a general logging/reporting system. +// +// Please see https://github.com/google/google-toolbox-for-mac/wiki/DevLogNAssert +// for a little more background on the usage of these macros. +// +// _GTMDevLog log some error/problem in debug builds +// _GTMDevAssert assert if conditon isn't met w/in a method/function +// in all builds. +// +// To replace this system, just provide different macro definitions in your +// prefix header. Remember, any implementation you provide *must* be thread +// safe since this could be called by anything in what ever situtation it has +// been placed in. +// + +// We only define the simple macros if nothing else has defined this. +#ifndef _GTMDevLog + +#ifdef DEBUG + #define _GTMDevLog(...) NSLog(__VA_ARGS__) +#else + #define _GTMDevLog(...) do { } while (0) +#endif + +#endif // _GTMDevLog + +#ifndef _GTMDevAssert +// we directly invoke the NSAssert handler so we can pass on the varargs +// (NSAssert doesn't have a macro we can use that takes varargs) +#if !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) \ + do { \ + if (!(condition)) { \ + [[NSAssertionHandler currentHandler] \ + handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ + file:[NSString stringWithUTF8String:__FILE__] \ + lineNumber:__LINE__ \ + description:__VA_ARGS__]; \ + } \ + } while(0) +#else // !defined(NS_BLOCK_ASSERTIONS) + #define _GTMDevAssert(condition, ...) do { } while (0) +#endif // !defined(NS_BLOCK_ASSERTIONS) + +#endif // _GTMDevAssert + +// _GTMCompileAssert +// _GTMCompileAssert is an assert that is meant to fire at compile time if you +// want to check things at compile instead of runtime. For example if you +// want to check that a wchar is 4 bytes instead of 2 you would use +// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) +// Note that the second "arg" is not in quotes, and must be a valid processor +// symbol in it's own right (no spaces, punctuation etc). + +// Wrapping this in an #ifndef allows external groups to define their own +// compile time assert scheme. +#ifndef _GTMCompileAssert + // We got this technique from here: + // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html + + #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg + #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) + #define _GTMCompileAssert(test, msg) \ + typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] +#endif // _GTMCompileAssert + +// ---------------------------------------------------------------------------- +// CPP symbols defined based on the project settings so the GTM code has +// simple things to test against w/o scattering the knowledge of project +// setting through all the code. +// ---------------------------------------------------------------------------- + +// Provide a single constant CPP symbol that all of GTM uses for ifdefing +// iPhone code. +#if TARGET_OS_IPHONE // iPhone SDK + // For iPhone specific stuff + #define GTM_IPHONE_SDK 1 + #if TARGET_IPHONE_SIMULATOR + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_SIMULATOR 1 + #else + #define GTM_IPHONE_DEVICE 1 + #define GTM_IPHONE_SIMULATOR 0 + #endif // TARGET_IPHONE_SIMULATOR + // By default, GTM has provided it's own unittesting support, define this + // to use the support provided by Xcode, especially for the Xcode4 support + // for unittesting. + #ifndef GTM_IPHONE_USE_SENTEST + #define GTM_IPHONE_USE_SENTEST 0 + #endif + #define GTM_MACOS_SDK 0 +#else + // For MacOS specific stuff + #define GTM_MACOS_SDK 1 + #define GTM_IPHONE_SDK 0 + #define GTM_IPHONE_SIMULATOR 0 + #define GTM_IPHONE_DEVICE 0 + #define GTM_IPHONE_USE_SENTEST 0 +#endif + +// Some of our own availability macros +#if GTM_MACOS_SDK +#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE +#define GTM_AVAILABLE_ONLY_ON_MACOS +#else +#define GTM_AVAILABLE_ONLY_ON_IPHONE +#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE +#endif + +// GC was dropped by Apple, define the old constant incase anyone still keys +// off of it. +#ifndef GTM_SUPPORT_GC + #define GTM_SUPPORT_GC 0 +#endif + +// Some support for advanced clang static analysis functionality +// See http://clang-analyzer.llvm.org/annotations.html +#ifndef __has_feature // Optional. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +#ifndef NS_RETURNS_RETAINED + #if __has_feature(attribute_ns_returns_retained) + #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) + #else + #define NS_RETURNS_RETAINED + #endif +#endif + +#ifndef NS_RETURNS_NOT_RETAINED + #if __has_feature(attribute_ns_returns_not_retained) + #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) + #else + #define NS_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_RETAINED + #if __has_feature(attribute_cf_returns_retained) + #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) + #else + #define CF_RETURNS_RETAINED + #endif +#endif + +#ifndef CF_RETURNS_NOT_RETAINED + #if __has_feature(attribute_cf_returns_not_retained) + #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) + #else + #define CF_RETURNS_NOT_RETAINED + #endif +#endif + +#ifndef NS_CONSUMED + #if __has_feature(attribute_ns_consumed) + #define NS_CONSUMED __attribute__((ns_consumed)) + #else + #define NS_CONSUMED + #endif +#endif + +#ifndef CF_CONSUMED + #if __has_feature(attribute_cf_consumed) + #define CF_CONSUMED __attribute__((cf_consumed)) + #else + #define CF_CONSUMED + #endif +#endif + +#ifndef NS_CONSUMES_SELF + #if __has_feature(attribute_ns_consumes_self) + #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) + #else + #define NS_CONSUMES_SELF + #endif +#endif + +// Defined on 10.6 and above. +#ifndef NS_FORMAT_ARGUMENT + #define NS_FORMAT_ARGUMENT(A) +#endif + +// Defined on 10.6 and above. +#ifndef NS_FORMAT_FUNCTION + #define NS_FORMAT_FUNCTION(F,A) +#endif + +// Defined on 10.6 and above. +#ifndef CF_FORMAT_ARGUMENT + #define CF_FORMAT_ARGUMENT(A) +#endif + +// Defined on 10.6 and above. +#ifndef CF_FORMAT_FUNCTION + #define CF_FORMAT_FUNCTION(F,A) +#endif + +#ifndef GTM_NONNULL + #if defined(__has_attribute) + #if __has_attribute(nonnull) + #define GTM_NONNULL(x) __attribute__((nonnull x)) + #else + #define GTM_NONNULL(x) + #endif + #else + #define GTM_NONNULL(x) + #endif +#endif + +// Invalidates the initializer from which it's called. +#ifndef GTMInvalidateInitializer + #if __has_feature(objc_arc) + #define GTMInvalidateInitializer() \ + do { \ + [self class]; /* Avoid warning of dead store to |self|. */ \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #else + #define GTMInvalidateInitializer() \ + do { \ + [self release]; \ + _GTMDevAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) + #endif +#endif + +#ifndef GTMCFAutorelease + #if __has_feature(objc_arc) + #define GTMCFAutorelease(x) CFBridgingRelease(x) + #else + #define GTMCFAutorelease(x) ([(id)x autorelease]) + #endif +#endif + +#ifdef __OBJC__ + +// Declared here so that it can easily be used for logging tracking if +// necessary. See GTMUnitTestDevLog.h for details. +@class NSString; +GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2); + +// Macro to allow you to create NSStrings out of other macros. +// #define FOO foo +// NSString *fooString = GTM_NSSTRINGIFY(FOO); +#if !defined (GTM_NSSTRINGIFY) + #define GTM_NSSTRINGIFY_INNER(x) @#x + #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x) +#endif + +// Macro to allow fast enumeration when building for 10.5 or later, and +// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration +// does keys, so pick the right thing, nothing is done on the FastEnumeration +// side to be sure you're getting what you wanted. +#ifndef GTM_FOREACH_OBJECT + #if TARGET_OS_IPHONE + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (element in enumeration) + #define GTM_FOREACH_OBJECT(element, collection) \ + for (element in collection) + #define GTM_FOREACH_KEY(element, collection) \ + for (element in collection) + #else + #define GTM_FOREACH_ENUMEREE(element, enumeration) \ + for (NSEnumerator *_ ## element ## _enum = enumeration; \ + (element = [_ ## element ## _enum nextObject]) != nil; ) + #define GTM_FOREACH_OBJECT(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator]) + #define GTM_FOREACH_KEY(element, collection) \ + GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator]) + #endif +#endif + +// ============================================================================ + +// GTM_SEL_STRING is for specifying selector (usually property) names to KVC +// or KVO methods. +// In debug it will generate warnings for undeclared selectors if +// -Wunknown-selector is turned on. +// In release it will have no runtime overhead. +#ifndef GTM_SEL_STRING + #ifdef DEBUG + #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName)) + #else + #define GTM_SEL_STRING(selName) @#selName + #endif // DEBUG +#endif // GTM_SEL_STRING + +#endif // __OBJC__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h new file mode 100644 index 0000000000..c4fd140290 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h @@ -0,0 +1,504 @@ +// +// GTMLogger.h +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Key Abstractions +// ---------------- +// +// This file declares multiple classes and protocols that are used by the +// GTMLogger logging system. The 4 main abstractions used in this file are the +// following: +// +// * logger (GTMLogger) - The main logging class that users interact with. It +// has methods for logging at different levels and uses a log writer, a log +// formatter, and a log filter to get the job done. +// +// * log writer (GTMLogWriter) - Writes a given string to some log file, where +// a "log file" can be a physical file on disk, a POST over HTTP to some URL, +// or even some in-memory structure (e.g., a ring buffer). +// +// * log formatter (GTMLogFormatter) - Given a format string and arguments as +// a va_list, returns a single formatted NSString. A "formatted string" could +// be a string with the date prepended, a string with values in a CSV format, +// or even a string of XML. +// +// * log filter (GTMLogFilter) - Given a formatted log message as an NSString +// and the level at which the message is to be logged, this class will decide +// whether the given message should be logged or not. This is a flexible way +// to filter out messages logged at a certain level, messages that contain +// certain text, or filter nothing out at all. This gives the caller the +// flexibility to dynamically enable debug logging in Release builds. +// +// This file also declares some classes to handle the common log writer, log +// formatter, and log filter cases. Callers can also create their own writers, +// formatters, and filters and they can even build them on top of the ones +// declared here. Keep in mind that your custom writer/formatter/filter may be +// called from multiple threads, so it must be thread-safe. + +#import +#import "GTMDefines.h" + +// Predeclaration of used protocols that are declared later in this file. +@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter; + +// GTMLogger +// +// GTMLogger is the primary user-facing class for an object-oriented logging +// system. It is built on the concept of log formatters (GTMLogFormatter), log +// writers (GTMLogWriter), and log filters (GTMLogFilter). When a message is +// sent to a GTMLogger to log a message, the message is formatted using the log +// formatter, then the log filter is consulted to see if the message should be +// logged, and if so, the message is sent to the log writer to be written out. +// +// GTMLogger is intended to be a flexible and thread-safe logging solution. Its +// flexibility comes from the fact that GTMLogger instances can be customized +// with user defined formatters, filters, and writers. And these writers, +// filters, and formatters can be combined, stacked, and customized in arbitrary +// ways to suit the needs at hand. For example, multiple writers can be used at +// the same time, and a GTMLogger instance can even be used as another +// GTMLogger's writer. This allows for arbitrarily deep logging trees. +// +// A standard GTMLogger uses a writer that sends messages to standard out, a +// formatter that smacks a timestamp and a few other bits of interesting +// information on the message, and a filter that filters out debug messages from +// release builds. Using the standard log settings, a log message will look like +// the following: +// +// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] foo= +// +// The output contains the date and time of the log message, the name of the +// process followed by its process ID/thread ID, the log level at which the +// message was logged (in the previous example the level was 1: +// kGTMLoggerLevelDebug), and finally, the user-specified log message itself (in +// this case, the log message was @"foo=%@", foo). +// +// Multiple instances of GTMLogger can be created, each configured their own +// way. Though GTMLogger is not a singleton (in the GoF sense), it does provide +// access to a shared (i.e., globally accessible) GTMLogger instance. This makes +// it convenient for all code in a process to use the same GTMLogger instance. +// The shared GTMLogger instance can also be configured in an arbitrary, and +// these configuration changes will affect all code that logs through the shared +// instance. + +// +// Log Levels +// ---------- +// GTMLogger has 3 different log levels: Debug, Info, and Error. GTMLogger +// doesn't take any special action based on the log level; it simply forwards +// this information on to formatters, filters, and writers, each of which may +// optionally take action based on the level. Since log level filtering is +// performed at runtime, log messages are typically not filtered out at compile +// time. The exception to this rule is that calls to the GTMLoggerDebug() macro +// *ARE* filtered out of non-DEBUG builds. This is to be backwards compatible +// with behavior that many developers are currently used to. Note that this +// means that GTMLoggerDebug(@"hi") will be compiled out of Release builds, but +// [[GTMLogger sharedLogger] logDebug:@"hi"] will NOT be compiled out. +// +// Standard loggers are created with the GTMLogLevelFilter log filter, which +// filters out certain log messages based on log level, and some other settings. +// +// In addition to the -logDebug:, -logInfo:, and -logError: methods defined on +// GTMLogger itself, there are also C macros that make usage of the shared +// GTMLogger instance very convenient. These macros are: +// +// GTMLoggerDebug(...) +// GTMLoggerInfo(...) +// GTMLoggerError(...) +// +// Again, a notable feature of these macros is that GTMLogDebug() calls *will be +// compiled out of non-DEBUG builds*. +// +// Standard Loggers +// ---------------- +// GTMLogger has the concept of "standard loggers". A standard logger is simply +// a logger that is pre-configured with some standard/common writer, formatter, +// and filter combination. Standard loggers are created using the creation +// methods beginning with "standard". The alternative to a standard logger is a +// regular logger, which will send messages to stdout, with no special +// formatting, and no filtering. +// +// How do I use GTMLogger? +// ---------------------- +// The typical way you will want to use GTMLogger is to simply use the +// GTMLogger*() macros for logging from code. That way we can easily make +// changes to the GTMLogger class and simply update the macros accordingly. Only +// your application startup code (perhaps, somewhere in main()) should use the +// GTMLogger class directly in order to configure the shared logger, which all +// of the code using the macros will be using. Again, this is just the typical +// situation. +// +// To be complete, there are cases where you may want to use GTMLogger directly, +// or even create separate GTMLogger instances for some reason. That's fine, +// too. +// +// Examples +// -------- +// The following show some common GTMLogger use cases. +// +// 1. You want to log something as simply as possible. Also, this call will only +// appear in debug builds. In non-DEBUG builds it will be completely removed. +// +// GTMLoggerDebug(@"foo = %@", foo); +// +// 2. The previous example is similar to the following. The major difference is +// that the previous call (example 1) will be compiled out of Release builds +// but this statement will not be compiled out. +// +// [[GTMLogger sharedLogger] logDebug:@"foo = %@", foo]; +// +// 3. Send all logging output from the shared logger to a file. We do this by +// creating an NSFileHandle for writing associated with a file, and setting +// that file handle as the logger's writer. +// +// NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" +// create:YES]; +// [[GTMLogger sharedLogger] setWriter:f]; +// GTMLoggerError(@"hi"); // This will be sent to /tmp/f.log +// +// 4. Create a new GTMLogger that will log to a file. This example differs from +// the previous one because here we create a new GTMLogger that is different +// from the shared logger. +// +// GTMLogger *logger = [GTMLogger standardLoggerWithPath:@"/tmp/temp.log"]; +// [logger logInfo:@"hi temp log file"]; +// +// 5. Create a logger that writes to stdout and does NOT do any formatting to +// the log message. This might be useful, for example, when writing a help +// screen for a command-line tool to standard output. +// +// GTMLogger *logger = [GTMLogger logger]; +// [logger logInfo:@"%@ version 0.1 usage", progName]; +// +// 6. Send log output to stdout AND to a log file. The trick here is that +// NSArrays function as composite log writers, which means when an array is +// set as the log writer, it forwards all logging messages to all of its +// contained GTMLogWriters. +// +// // Create array of GTMLogWriters +// NSArray *writers = [NSArray arrayWithObjects: +// [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" create:YES], +// [NSFileHandle fileHandleWithStandardOutput], nil]; +// +// GTMLogger *logger = [GTMLogger standardLogger]; +// [logger setWriter:writers]; +// [logger logInfo:@"hi"]; // Output goes to stdout and /tmp/f.log +// +// For futher details on log writers, formatters, and filters, see the +// documentation below. +// +// NOTE: GTMLogger is application level logging. By default it does nothing +// with _GTMDevLog/_GTMDevAssert (see GTMDefines.h). An application can choose +// to bridge _GTMDevLog/_GTMDevAssert to GTMLogger by providing macro +// definitions in its prefix header (see GTMDefines.h for how one would do +// that). +// +@interface GTMLogger : NSObject { + @private + id writer_; + id formatter_; + id filter_; +} + +// +// Accessors for the shared logger instance +// + +// Returns a shared/global standard GTMLogger instance. Callers should typically +// use this method to get a GTMLogger instance, unless they explicitly want +// their own instance to configure for their own needs. This is the only method +// that returns a shared instance; all the rest return new GTMLogger instances. ++ (id)sharedLogger; + +// Sets the shared logger instance to |logger|. Future calls to +sharedLogger +// will return |logger| instead. ++ (void)setSharedLogger:(GTMLogger *)logger; + +// +// Creation methods +// + +// Returns a new autoreleased GTMLogger instance that will log to stdout, using +// the GTMLogStandardFormatter, and the GTMLogLevelFilter filter. ++ (id)standardLogger; + +// Same as +standardLogger, but logs to stderr. ++ (id)standardLoggerWithStderr; + +// Same as +standardLogger but levels >= kGTMLoggerLevelError are routed to +// stderr, everything else goes to stdout. ++ (id)standardLoggerWithStdoutAndStderr; + +// Returns a new standard GTMLogger instance with a log writer that will +// write to the file at |path|, and will use the GTMLogStandardFormatter and +// GTMLogLevelFilter classes. If |path| does not exist, it will be created. ++ (id)standardLoggerWithPath:(NSString *)path; + +// Returns an autoreleased GTMLogger instance that will use the specified +// |writer|, |formatter|, and |filter|. ++ (id)loggerWithWriter:(id)writer + formatter:(id)formatter + filter:(id)filter; + +// Returns an autoreleased GTMLogger instance that logs to stdout, with the +// basic formatter, and no filter. The returned logger differs from the logger +// returned by +standardLogger because this one does not do any filtering and +// does not do any special log formatting; this is the difference between a +// "regular" logger and a "standard" logger. ++ (id)logger; + +// Designated initializer. This method returns a GTMLogger initialized with the +// specified |writer|, |formatter|, and |filter|. See the setter methods below +// for what values will be used if nil is passed for a parameter. +- (id)initWithWriter:(id)writer + formatter:(id)formatter + filter:(id)filter; + +// +// Logging methods +// + +// Logs a message at the debug level (kGTMLoggerLevelDebug). +- (void)logDebug:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); +// Logs a message at the info level (kGTMLoggerLevelInfo). +- (void)logInfo:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); +// Logs a message at the error level (kGTMLoggerLevelError). +- (void)logError:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); +// Logs a message at the assert level (kGTMLoggerLevelAssert). +- (void)logAssert:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); + + +// +// Accessors +// + +// Accessor methods for the log writer. If the log writer is set to nil, +// [NSFileHandle fileHandleWithStandardOutput] is used. +- (id)writer; +- (void)setWriter:(id)writer; + +// Accessor methods for the log formatter. If the log formatter is set to nil, +// GTMLogBasicFormatter is used. This formatter will format log messages in a +// plain printf style. +- (id)formatter; +- (void)setFormatter:(id)formatter; + +// Accessor methods for the log filter. If the log filter is set to nil, +// GTMLogNoFilter is used, which allows all log messages through. +- (id)filter; +- (void)setFilter:(id)filter; + +@end // GTMLogger + + +// Helper functions that are used by the convenience GTMLogger*() macros that +// enable the logging of function names. +@interface GTMLogger (GTMLoggerMacroHelpers) +- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... + NS_FORMAT_FUNCTION(2, 3); +- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... + NS_FORMAT_FUNCTION(2, 3); +- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... + NS_FORMAT_FUNCTION(2, 3); +- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... + NS_FORMAT_FUNCTION(2, 3); +@end // GTMLoggerMacroHelpers + + +// The convenience macros are only defined if they haven't already been defined. +#ifndef GTMLoggerInfo + +// Convenience macros that log to the shared GTMLogger instance. These macros +// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug() +// calls will be compiled out of non-Debug builds. +#define GTMLoggerDebug(...) \ + [[GTMLogger sharedLogger] logFuncDebug:__func__ msg:__VA_ARGS__] +#define GTMLoggerInfo(...) \ + [[GTMLogger sharedLogger] logFuncInfo:__func__ msg:__VA_ARGS__] +#define GTMLoggerError(...) \ + [[GTMLogger sharedLogger] logFuncError:__func__ msg:__VA_ARGS__] +#define GTMLoggerAssert(...) \ + [[GTMLogger sharedLogger] logFuncAssert:__func__ msg:__VA_ARGS__] + +// If we're not in a debug build, remove the GTMLoggerDebug statements. This +// makes calls to GTMLoggerDebug "compile out" of Release builds +#ifndef DEBUG +#undef GTMLoggerDebug +#define GTMLoggerDebug(...) do {} while(0) +#endif + +#endif // !defined(GTMLoggerInfo) + +// Log levels. +typedef enum { + kGTMLoggerLevelUnknown, + kGTMLoggerLevelDebug, + kGTMLoggerLevelInfo, + kGTMLoggerLevelError, + kGTMLoggerLevelAssert, +} GTMLoggerLevel; + + +// +// Log Writers +// + +// Protocol to be implemented by a GTMLogWriter instance. +@protocol GTMLogWriter +// Writes the given log message to where the log writer is configured to write. +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level; +@end // GTMLogWriter + + +// Simple category on NSFileHandle that makes NSFileHandles valid log writers. +// This is convenient because something like, say, +fileHandleWithStandardError +// now becomes a valid log writer. Log messages are written to the file handle +// with a newline appended. +@interface NSFileHandle (GTMFileHandleLogWriter) +// Opens the file at |path| in append mode, and creates the file with |mode| +// if it didn't previously exist. ++ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode; +@end // NSFileHandle + + +// This category makes NSArray a GTMLogWriter that can be composed of other +// GTMLogWriters. This is the classic Composite GoF design pattern. When the +// GTMLogWriter -logMessage:level: message is sent to the array, the array +// forwards the message to all of its elements that implement the GTMLogWriter +// protocol. +// +// This is useful in situations where you would like to send log output to +// multiple log writers at the same time. Simply create an NSArray of the log +// writers you wish to use, then set the array as the "writer" for your +// GTMLogger instance. +@interface NSArray (GTMArrayCompositeLogWriter) +@end // GTMArrayCompositeLogWriter + + +// This category adapts the GTMLogger interface so that it can be used as a log +// writer; it's an "adapter" in the GoF Adapter pattern sense. +// +// This is useful when you want to configure a logger to log to a specific +// writer with a specific formatter and/or filter. But you want to also compose +// that with a different log writer that may have its own formatter and/or +// filter. +@interface GTMLogger (GTMLoggerLogWriter) +@end // GTMLoggerLogWriter + + +// +// Log Formatters +// + +// Protocol to be implemented by a GTMLogFormatter instance. +@protocol GTMLogFormatter +// Returns a formatted string using the format specified in |fmt| and the va +// args specified in |args|. +- (NSString *)stringForFunc:(NSString *)func + withFormat:(NSString *)fmt + valist:(va_list)args + level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0); +@end // GTMLogFormatter + + +// A basic log formatter that formats a string the same way that NSLog (or +// printf) would. It does not do anything fancy, nor does it add any data of its +// own. +@interface GTMLogBasicFormatter : NSObject + +// Helper method for prettying C99 __func__ and GCC __PRETTY_FUNCTION__ +- (NSString *)prettyNameForFunc:(NSString *)func; + +@end // GTMLogBasicFormatter + + +// A log formatter that formats the log string like the basic formatter, but +// also prepends a timestamp and some basic process info to the message, as +// shown in the following sample output. +// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] log mesage here +@interface GTMLogStandardFormatter : GTMLogBasicFormatter { + @private + NSDateFormatter *dateFormatter_; // yyyy-MM-dd HH:mm:ss.SSS + NSString *pname_; + pid_t pid_; +} +@end // GTMLogStandardFormatter + + +// +// Log Filters +// + +// Protocol to be imlemented by a GTMLogFilter instance. +@protocol GTMLogFilter +// Returns YES if |msg| at |level| should be filtered out; NO otherwise. +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level; +@end // GTMLogFilter + + +// A log filter that filters messages at the kGTMLoggerLevelDebug level out of +// non-debug builds. Messages at the kGTMLoggerLevelInfo level are also filtered +// out of non-debug builds unless GTMVerboseLogging is set in the environment or +// the processes's defaults. Messages at the kGTMLoggerLevelError level are +// never filtered. +@interface GTMLogLevelFilter : NSObject +@end // GTMLogLevelFilter + +// A simple log filter that does NOT filter anything out; +// -filterAllowsMessage:level will always return YES. This can be a convenient +// way to enable debug-level logging in release builds (if you so desire). +@interface GTMLogNoFilter : NSObject +@end // GTMLogNoFilter + + +// Base class for custom level filters. Not for direct use, use the minimum +// or maximum level subclasses below. +@interface GTMLogAllowedLevelFilter : NSObject { + @private + NSIndexSet *allowedLevels_; +} +@end + +// A log filter that allows you to set a minimum log level. Messages below this +// level will be filtered. +@interface GTMLogMininumLevelFilter : GTMLogAllowedLevelFilter + +// Designated initializer, logs at levels < |level| will be filtered. +- (id)initWithMinimumLevel:(GTMLoggerLevel)level; + +@end + +// A log filter that allows you to set a maximum log level. Messages whose level +// exceeds this level will be filtered. This is really only useful if you have +// a composite GTMLogger that is sending the other messages elsewhere. +@interface GTMLogMaximumLevelFilter : GTMLogAllowedLevelFilter + +// Designated initializer, logs at levels > |level| will be filtered. +- (id)initWithMaximumLevel:(GTMLoggerLevel)level; + +@end + + +// For subclasses only +@interface GTMLogger (PrivateMethods) + +- (void)logInternalFunc:(const char *)func + format:(NSString *)fmt + valist:(va_list)args + level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0); + +@end + diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m new file mode 100644 index 0000000000..ebc5836a25 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m @@ -0,0 +1,611 @@ +// +// GTMLogger.m +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMLogger.h" +#import +#import +#import +#import + + +#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) +// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting +// -Wmissing-format-attribute +// when the function is anything more complex than foo(NSString *fmt, ...). +// You see the error inside the function when you turn ... into va_args and +// attempt to call another function (like vsprintf for example). +// So we just shut off the warning for this file. We reenable it at the end. +#pragma GCC diagnostic ignored "-Wmissing-format-attribute" +#endif // !__clang__ + +// Reference to the shared GTMLogger instance. This is not a singleton, it's +// just an easy reference to one shared instance. +static GTMLogger *gSharedLogger = nil; + + +@implementation GTMLogger + +// Returns a pointer to the shared logger instance. If none exists, a standard +// logger is created and returned. ++ (id)sharedLogger { + @synchronized(self) { + if (gSharedLogger == nil) { + gSharedLogger = [[self standardLogger] retain]; + } + } + return [[gSharedLogger retain] autorelease]; +} + ++ (void)setSharedLogger:(GTMLogger *)logger { + @synchronized(self) { + [gSharedLogger autorelease]; + gSharedLogger = [logger retain]; + } +} + ++ (id)standardLogger { + // Don't trust NSFileHandle not to throw + @try { + id writer = [NSFileHandle fileHandleWithStandardOutput]; + id fr = [[[GTMLogStandardFormatter alloc] init] + autorelease]; + id filter = [[[GTMLogLevelFilter alloc] init] autorelease]; + return [[[self alloc] initWithWriter:writer + formatter:fr + filter:filter] autorelease]; + } + @catch (id e) { + // Ignored + } + return nil; +} + ++ (id)standardLoggerWithStderr { + // Don't trust NSFileHandle not to throw + @try { + id me = [self standardLogger]; + [me setWriter:[NSFileHandle fileHandleWithStandardError]]; + return me; + } + @catch (id e) { + // Ignored + } + return nil; +} + ++ (id)standardLoggerWithStdoutAndStderr { + // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor + // and create a composite logger that an outer "standard" logger can use + // as a writer. Our inner loggers should apply no formatting since the main + // logger does that and we want the caller to be able to change formatters + // or add writers without knowing the inner structure of our composite. + + // Don't trust NSFileHandle not to throw + @try { + GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] + autorelease]; + GTMLogger *stdoutLogger = + [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput] + formatter:formatter + filter:[[[GTMLogMaximumLevelFilter alloc] + initWithMaximumLevel:kGTMLoggerLevelInfo] + autorelease]]; + GTMLogger *stderrLogger = + [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError] + formatter:formatter + filter:[[[GTMLogMininumLevelFilter alloc] + initWithMinimumLevel:kGTMLoggerLevelError] + autorelease]]; + GTMLogger *compositeWriter = + [self loggerWithWriter:[NSArray arrayWithObjects: + stdoutLogger, stderrLogger, nil] + formatter:formatter + filter:[[[GTMLogNoFilter alloc] init] autorelease]]; + GTMLogger *outerLogger = [self standardLogger]; + [outerLogger setWriter:compositeWriter]; + return outerLogger; + } + @catch (id e) { + // Ignored + } + return nil; +} + ++ (id)standardLoggerWithPath:(NSString *)path { + @try { + NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644]; + if (fh == nil) return nil; + id me = [self standardLogger]; + [me setWriter:fh]; + return me; + } + @catch (id e) { + // Ignored + } + return nil; +} + ++ (id)loggerWithWriter:(id)writer + formatter:(id)formatter + filter:(id)filter { + return [[[self alloc] initWithWriter:writer + formatter:formatter + filter:filter] autorelease]; +} + ++ (id)logger { + return [[[self alloc] init] autorelease]; +} + +- (id)init { + return [self initWithWriter:nil formatter:nil filter:nil]; +} + +- (id)initWithWriter:(id)writer + formatter:(id)formatter + filter:(id)filter { + if ((self = [super init])) { + [self setWriter:writer]; + [self setFormatter:formatter]; + [self setFilter:filter]; + } + return self; +} + +- (void)dealloc { + // Unlikely, but |writer_| may be an NSFileHandle, which can throw + @try { + [formatter_ release]; + [filter_ release]; + [writer_ release]; + } + @catch (id e) { + // Ignored + } + [super dealloc]; +} + +- (id)writer { + return [[writer_ retain] autorelease]; +} + +- (void)setWriter:(id)writer { + @synchronized(self) { + [writer_ autorelease]; + writer_ = nil; + if (writer == nil) { + // Try to use stdout, but don't trust NSFileHandle + @try { + writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain]; + } + @catch (id e) { + // Leave |writer_| nil + } + } else { + writer_ = [writer retain]; + } + } +} + +- (id)formatter { + return [[formatter_ retain] autorelease]; +} + +- (void)setFormatter:(id)formatter { + @synchronized(self) { + [formatter_ autorelease]; + formatter_ = nil; + if (formatter == nil) { + @try { + formatter_ = [[GTMLogBasicFormatter alloc] init]; + } + @catch (id e) { + // Leave |formatter_| nil + } + } else { + formatter_ = [formatter retain]; + } + } +} + +- (id)filter { + return [[filter_ retain] autorelease]; +} + +- (void)setFilter:(id)filter { + @synchronized(self) { + [filter_ autorelease]; + filter_ = nil; + if (filter == nil) { + @try { + filter_ = [[GTMLogNoFilter alloc] init]; + } + @catch (id e) { + // Leave |filter_| nil + } + } else { + filter_ = [filter retain]; + } + } +} + +- (void)logDebug:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug]; + va_end(args); +} + +- (void)logInfo:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo]; + va_end(args); +} + +- (void)logError:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError]; + va_end(args); +} + +- (void)logAssert:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert]; + va_end(args); +} + +@end // GTMLogger + +@implementation GTMLogger (GTMLoggerMacroHelpers) + +- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug]; + va_end(args); +} + +- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo]; + va_end(args); +} + +- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError]; + va_end(args); +} + +- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert]; + va_end(args); +} + +@end // GTMLoggerMacroHelpers + +@implementation GTMLogger (PrivateMethods) + +- (void)logInternalFunc:(const char *)func + format:(NSString *)fmt + valist:(va_list)args + level:(GTMLoggerLevel)level { + // Primary point where logging happens, logging should never throw, catch + // everything. + @try { + NSString *fname = func ? [NSString stringWithUTF8String:func] : nil; + NSString *msg = [formatter_ stringForFunc:fname + withFormat:fmt + valist:args + level:level]; + if (msg && [filter_ filterAllowsMessage:msg level:level]) + [writer_ logMessage:msg level:level]; + } + @catch (id e) { + // Ignored + } +} + +@end // PrivateMethods + + +@implementation NSFileHandle (GTMFileHandleLogWriter) + ++ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode { + int fd = -1; + if (path) { + int flags = O_WRONLY | O_APPEND | O_CREAT; + fd = open([path fileSystemRepresentation], flags, mode); + } + if (fd == -1) return nil; + return [[[self alloc] initWithFileDescriptor:fd + closeOnDealloc:YES] autorelease]; +} + +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { + @synchronized(self) { + // Closed pipes should not generate exceptions in our caller. Catch here + // as well [GTMLogger logInternalFunc:...] so that an exception in this + // writer does not prevent other writers from having a chance. + @try { + NSString *line = [NSString stringWithFormat:@"%@\n", msg]; + [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]]; + } + @catch (id e) { + // Ignored + } + } +} + +@end // GTMFileHandleLogWriter + + +@implementation NSArray (GTMArrayCompositeLogWriter) + +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { + @synchronized(self) { + id child = nil; + GTM_FOREACH_OBJECT(child, self) { + if ([child conformsToProtocol:@protocol(GTMLogWriter)]) + [child logMessage:msg level:level]; + } + } +} + +@end // GTMArrayCompositeLogWriter + + +@implementation GTMLogger (GTMLoggerLogWriter) + +- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { + switch (level) { + case kGTMLoggerLevelDebug: + [self logDebug:@"%@", msg]; + break; + case kGTMLoggerLevelInfo: + [self logInfo:@"%@", msg]; + break; + case kGTMLoggerLevelError: + [self logError:@"%@", msg]; + break; + case kGTMLoggerLevelAssert: + [self logAssert:@"%@", msg]; + break; + default: + // Ignore the message. + break; + } +} + +@end // GTMLoggerLogWriter + + +@implementation GTMLogBasicFormatter + +- (NSString *)prettyNameForFunc:(NSString *)func { + NSString *name = [func stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; + NSString *function = @"(unknown)"; + if ([name length]) { + if (// Objective C __func__ and __PRETTY_FUNCTION__ + [name hasPrefix:@"-["] || [name hasPrefix:@"+["] || + // C++ __PRETTY_FUNCTION__ and other preadorned formats + [name hasSuffix:@")"]) { + function = name; + } else { + // Assume C99 __func__ + function = [NSString stringWithFormat:@"%@()", name]; + } + } + return function; +} + +- (NSString *)stringForFunc:(NSString *)func + withFormat:(NSString *)fmt + valist:(va_list)args + level:(GTMLoggerLevel)level { + // Performance note: We may want to do a quick check here to see if |fmt| + // contains a '%', and if not, simply return 'fmt'. + if (!(fmt && args)) return nil; + return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease]; +} + +@end // GTMLogBasicFormatter + + +@implementation GTMLogStandardFormatter + +- (id)init { + if ((self = [super init])) { + dateFormatter_ = [[NSDateFormatter alloc] init]; + [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; + pname_ = [[[NSProcessInfo processInfo] processName] copy]; + pid_ = [[NSProcessInfo processInfo] processIdentifier]; + if (!(dateFormatter_ && pname_)) { + [self release]; + return nil; + } + } + return self; +} + +- (void)dealloc { + [dateFormatter_ release]; + [pname_ release]; + [super dealloc]; +} + +- (NSString *)stringForFunc:(NSString *)func + withFormat:(NSString *)fmt + valist:(va_list)args + level:(GTMLoggerLevel)level { + NSString *tstamp = nil; + @synchronized (dateFormatter_) { + tstamp = [dateFormatter_ stringFromDate:[NSDate date]]; + } + return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@", + tstamp, pname_, pid_, pthread_self(), + level, [self prettyNameForFunc:func], + // |super| has guard for nil |fmt| and |args| + [super stringForFunc:func withFormat:fmt valist:args level:level]]; +} + +@end // GTMLogStandardFormatter + + +@implementation GTMLogLevelFilter + +// Check the environment and the user preferences for the GTMVerboseLogging key +// to see if verbose logging has been enabled. The environment variable will +// override the defaults setting, so check the environment first. +// COV_NF_START +static BOOL IsVerboseLoggingEnabled(void) { + static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging"; + NSString *value = [[[NSProcessInfo processInfo] environment] + objectForKey:kVerboseLoggingKey]; + if (value) { + // Emulate [NSString boolValue] for pre-10.5 + value = [value stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if ([[value uppercaseString] hasPrefix:@"Y"] || + [[value uppercaseString] hasPrefix:@"T"] || + [value intValue]) { + return YES; + } else { + return NO; + } + } + return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey]; +} +// COV_NF_END + +// In DEBUG builds, log everything. If we're not in a debug build we'll assume +// that we're in a Release build. +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { +#if defined(DEBUG) && DEBUG + return YES; +#endif + + BOOL allow = YES; + + switch (level) { + case kGTMLoggerLevelDebug: + allow = NO; + break; + case kGTMLoggerLevelInfo: + allow = IsVerboseLoggingEnabled(); + break; + case kGTMLoggerLevelError: + allow = YES; + break; + case kGTMLoggerLevelAssert: + allow = YES; + break; + default: + allow = YES; + break; + } + + return allow; +} + +@end // GTMLogLevelFilter + + +@implementation GTMLogNoFilter + +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { + return YES; // Allow everything through +} + +@end // GTMLogNoFilter + + +@implementation GTMLogAllowedLevelFilter + +// Private designated initializer +- (id)initWithAllowedLevels:(NSIndexSet *)levels { + self = [super init]; + if (self != nil) { + allowedLevels_ = [levels retain]; + // Cap min/max level + if (!allowedLevels_ || + // NSIndexSet is unsigned so only check the high bound, but need to + // check both first and last index because NSIndexSet appears to allow + // wraparound. + ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) || + ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) { + [self release]; + return nil; + } + } + return self; +} + +- (id)init { + // Allow all levels in default init + return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: + NSMakeRange(kGTMLoggerLevelUnknown, + (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]]; +} + +- (void)dealloc { + [allowedLevels_ release]; + [super dealloc]; +} + +- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { + return [allowedLevels_ containsIndex:level]; +} + +@end // GTMLogAllowedLevelFilter + + +@implementation GTMLogMininumLevelFilter + +- (id)initWithMinimumLevel:(GTMLoggerLevel)level { + return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: + NSMakeRange(level, + (kGTMLoggerLevelAssert - level + 1))]]; +} + +@end // GTMLogMininumLevelFilter + + +@implementation GTMLogMaximumLevelFilter + +- (id)initWithMaximumLevel:(GTMLoggerLevel)level { + return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: + NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]]; +} + +@end // GTMLogMaximumLevelFilter + +#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) +// See comment at top of file. +#pragma GCC diagnostic error "-Wmissing-format-attribute" +#endif // !__clang__ + diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h new file mode 100644 index 0000000000..0cea733e5d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h @@ -0,0 +1,61 @@ +// 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. + +// HTTPMultipartUpload: A multipart/form-data HTTP uploader. +// Each parameter pair is sent as a boundary +// Each file is sent with a name field in addition to the filename and data +// The data will be sent synchronously. + +#import + +@interface HTTPMultipartUpload : NSObject { + @protected + NSURL *url_; // The destination URL (STRONG) + NSMutableString *parameters_; // The JSON payload for sending data (STRONG) + NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG) + NSString *boundary_; // The boundary string (STRONG) + NSHTTPURLResponse *response_; // The response from the send (STRONG) +} + +- (id)initWithURL:(NSURL *)url; + +- (NSURL *)URL; + +- (void)setParameters:(NSMutableString *)parameters; +- (NSMutableString *)parameters; + +- (void)addFileAtPath:(NSString *)path name:(NSString *)name; +- (void)addFileContents:(NSData *)data name:(NSString *)name; +- (NSDictionary *)files; + +// Set the data and return the response +- (NSData *)send:(NSError **)error; +- (NSHTTPURLResponse *)response; + +@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m new file mode 100644 index 0000000000..d2480493f6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m @@ -0,0 +1,262 @@ +// 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. + +#import "HTTPMultipartUpload.h" +#import "GTMDefines.h" + +// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been +// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it +// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when +// using those SDKs. +static NSString *PercentEncodeNSString(NSString *key) { +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \ + (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ + defined(MAC_OS_X_VERSION_10_11) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) + return [key stringByAddingPercentEncodingWithAllowedCharacters: + [NSCharacterSet URLQueryAllowedCharacterSet]]; +#else + return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +#endif +} + +// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has +// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements +// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is +// available on iOS 7+. +static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, + NSURLResponse **out_response, + NSError **out_error) { +#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \ + (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ + defined(MAC_OS_X_VERSION_10_11) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) + __block NSData* result = nil; + __block NSError* error = nil; + __block NSURLResponse* response = nil; + dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0); + [[[NSURLSession sharedSession] + dataTaskWithRequest:req + completionHandler:^(NSData *data, + NSURLResponse *resp, + NSError *err) { + if (out_error) + error = [err retain]; + if (out_response) + response = [resp retain]; + if (err == nil) + result = [data retain]; + dispatch_semaphore_signal(wait_semaphone); + }] resume]; + dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER); + dispatch_release(wait_semaphone); + if (out_error) + *out_error = [error autorelease]; + if (out_response) + *out_response = [response autorelease]; + return [result autorelease]; +#else + return [NSURLConnection sendSynchronousRequest:req + returningResponse:out_response + error:out_error]; +#endif +} +@interface HTTPMultipartUpload(PrivateMethods) +- (NSString *)multipartBoundary; +// Each of the following methods will append the starting multipart boundary, +// but not the ending one. +- (NSData *)formDataForJSON:(NSString *)json; +- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name; +- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name; +@end + +@implementation HTTPMultipartUpload +//============================================================================= +#pragma mark - +#pragma mark || Private || +//============================================================================= +- (NSString *)multipartBoundary { + // The boundary has 27 '-' characters followed by 16 hex digits + return [NSString stringWithFormat:@"---------------------------%08X%08X", + rand(), rand()]; +} + +//============================================================================= +- (NSData *)formDataForJSON:(NSString *)json { + NSMutableData *data = [NSMutableData data]; + NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"extra\"; " + "filename=\"extra.json\"\r\nContent-Type: application/json\r\n\r\n"; + NSString *form = [NSString stringWithFormat:fmt, boundary_]; + + [data appendData:[form dataUsingEncoding:NSUTF8StringEncoding]]; + [data appendData:[json dataUsingEncoding:NSUTF8StringEncoding]]; + + return data; +} + +//============================================================================= +- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name { + NSMutableData *data = [NSMutableData data]; + NSString *escaped = PercentEncodeNSString(name); + NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; " + "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n"; + NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped]; + + [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; + [data appendData:contents]; + + return data; +} + +//============================================================================= +- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name { + NSData *contents = [NSData dataWithContentsOfFile:file]; + + return [self formDataForFileContents:contents name:name]; +} + +//============================================================================= +#pragma mark - +#pragma mark || Public || +//============================================================================= +- (id)initWithURL:(NSURL *)url { + if ((self = [super init])) { + url_ = [url copy]; + boundary_ = [[self multipartBoundary] retain]; + files_ = [[NSMutableDictionary alloc] init]; + } + + return self; +} + +//============================================================================= +- (void)dealloc { + [url_ release]; + [parameters_ release]; + [files_ release]; + [boundary_ release]; + [response_ release]; + + [super dealloc]; +} + +//============================================================================= +- (NSURL *)URL { + return url_; +} + +//============================================================================= +- (void)setParameters:(NSMutableString *)parameters { + if (parameters != parameters_) { + [parameters_ release]; + parameters_ = [parameters mutableCopy]; + } +} + +//============================================================================= +- (NSMutableString *)parameters { + return parameters_; +} + +//============================================================================= +- (void)addFileAtPath:(NSString *)path name:(NSString *)name { + [files_ setObject:path forKey:name]; +} + +//============================================================================= +- (void)addFileContents:(NSData *)data name:(NSString *)name { + [files_ setObject:data forKey:name]; +} + +//============================================================================= +- (NSDictionary *)files { + return files_; +} + +//============================================================================= +- (NSData *)send:(NSError **)error { + NSMutableURLRequest *req = + [[NSMutableURLRequest alloc] + initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:60.0]; + + NSMutableData *postBody = [NSMutableData data]; + + [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", + boundary_] forHTTPHeaderField:@"Content-type"]; + + // Add JSON parameters to the message + [postBody appendData:[self formDataForJSON:parameters_]]; + + // Add any files to the message + NSArray *fileNames = [files_ allKeys]; + for (NSString *name in fileNames) { + id fileOrData = [files_ objectForKey:name]; + NSData *fileData; + + // The object can be either the path to a file (NSString) or the contents + // of the file (NSData). + if ([fileOrData isKindOfClass:[NSData class]]) + fileData = [self formDataForFileContents:fileOrData name:name]; + else + fileData = [self formDataForFile:fileOrData name:name]; + + [postBody appendData:fileData]; + } + + NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; + [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]]; + + [req setHTTPBody:postBody]; + [req setHTTPMethod:@"POST"]; + + [response_ release]; + response_ = nil; + + NSData *data = nil; + if ([[req URL] isFileURL]) { + [[req HTTPBody] writeToURL:[req URL] options:0 error:error]; + } else { + NSURLResponse *response = nil; + data = SendSynchronousNSURLRequest(req, &response, error); + response_ = (NSHTTPURLResponse *)[response retain]; + } + [req release]; + + return data; +} + +//============================================================================= +- (NSHTTPURLResponse *)response { + return response_; +} + +@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h new file mode 100644 index 0000000000..e3d4a0fdbc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h @@ -0,0 +1,303 @@ +// 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. +// +// MachIPC.h +// +// Some helpful wrappers for using Mach IPC calls + +#ifndef MACH_IPC_H__ +#define MACH_IPC_H__ + +#import +#import +#import +#import + +#import + +//============================================================================== +// DISCUSSION: +// +// The three main classes of interest are +// +// MachMessage: a wrapper for a mach message of the following form +// mach_msg_header_t +// mach_msg_body_t +// optional descriptors +// optional extra message data +// +// MachReceiveMessage and MachSendMessage subclass MachMessage +// and are used instead of MachMessage which is an abstract base class +// +// ReceivePort: +// Represents a mach port for which we have receive rights +// +// MachPortSender: +// Represents a mach port for which we have send rights +// +// Here's an example to receive a message on a server port: +// +// // This creates our named server port +// ReceivePort receivePort("com.Google.MyService"); +// +// MachReceiveMessage message; +// kern_return_t result = receivePort.WaitForMessage(&message, 0); +// +// if (result == KERN_SUCCESS && message.GetMessageID() == 57) { +// mach_port_t task = message.GetTranslatedPort(0); +// mach_port_t thread = message.GetTranslatedPort(1); +// +// char *messageString = message.GetData(); +// +// printf("message string = %s\n", messageString); +// } +// +// Here is an example of using these classes to send a message to this port: +// +// // send to already named port +// MachPortSender sender("com.Google.MyService"); +// MachSendMessage message(57); // our message ID is 57 +// +// // add some ports to be translated for us +// message.AddDescriptor(mach_task_self()); // our task +// message.AddDescriptor(mach_thread_self()); // this thread +// +// char messageString[] = "Hello server!\n"; +// message.SetData(messageString, strlen(messageString)+1); +// +// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms +// + +namespace google_breakpad { +#ifndef PRINT_MACH_RESULT +#define PRINT_MACH_RESULT(result_, message_) \ + printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); +#endif + +//============================================================================== +// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) +// with convenient constructors and accessors +class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { + public: + // General-purpose constructor + MachMsgPortDescriptor(mach_port_t in_name, + mach_msg_type_name_t in_disposition) { + name = in_name; + pad1 = 0; + pad2 = 0; + disposition = in_disposition; + type = MACH_MSG_PORT_DESCRIPTOR; + } + + // For passing send rights to a port + MachMsgPortDescriptor(mach_port_t in_name) { + name = in_name; + pad1 = 0; + pad2 = 0; + disposition = MACH_MSG_TYPE_COPY_SEND; + type = MACH_MSG_PORT_DESCRIPTOR; + } + + // Copy constructor + MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { + name = desc.name; + pad1 = desc.pad1; + pad2 = desc.pad2; + disposition = desc.disposition; + type = desc.type; + } + + mach_port_t GetMachPort() const { + return name; + } + + mach_msg_type_name_t GetDisposition() const { + return disposition; + } + + // For convenience + operator mach_port_t() const { + return GetMachPort(); + } +}; + +//============================================================================== +// MachMessage: a wrapper for a mach message +// (mach_msg_header_t, mach_msg_body_t, extra data) +// +// This considerably simplifies the construction of a message for sending +// and the getting at relevant data and descriptors for the receiver. +// +// Currently the combined size of the descriptors plus data must be +// less than 1024. But as a benefit no memory allocation is necessary. +// +// TODO: could consider adding malloc() support for very large messages +// +// A MachMessage object is used by ReceivePort::WaitForMessage +// and MachPortSender::SendMessage +// +class MachMessage { + public: + + // The receiver of the message can retrieve the raw data this way + uint8_t *GetData() { + return GetDataLength() > 0 ? GetDataPacket()->data : NULL; + } + + uint32_t GetDataLength() { + return EndianU32_LtoN(GetDataPacket()->data_length); + } + + // The message ID may be used as a code identifying the type of message + void SetMessageID(int32_t message_id) { + GetDataPacket()->id = EndianU32_NtoL(message_id); + } + + int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } + + // Adds a descriptor (typically a mach port) to be translated + // returns true if successful, otherwise not enough space + bool AddDescriptor(const MachMsgPortDescriptor &desc); + + int GetDescriptorCount() const { return body.msgh_descriptor_count; } + MachMsgPortDescriptor *GetDescriptor(int n); + + // Convenience method which gets the mach port described by the descriptor + mach_port_t GetTranslatedPort(int n); + + // A simple message is one with no descriptors + bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } + + // Sets raw data for the message (returns false if not enough space) + bool SetData(void *data, int32_t data_length); + + protected: + // Consider this an abstract base class - must create an actual instance + // of MachReceiveMessage or MachSendMessage + + MachMessage() { + memset(this, 0, sizeof(MachMessage)); + } + + friend class ReceivePort; + friend class MachPortSender; + + // Represents raw data in our message + struct MessageDataPacket { + int32_t id; // little-endian + int32_t data_length; // little-endian + uint8_t data[1]; // actual size limited by sizeof(MachMessage) + }; + + MessageDataPacket* GetDataPacket(); + + void SetDescriptorCount(int n); + void SetDescriptor(int n, const MachMsgPortDescriptor &desc); + + // Returns total message size setting msgh_size in the header to this value + mach_msg_size_t CalculateSize(); + + mach_msg_header_t head; + mach_msg_body_t body; + uint8_t padding[1024]; // descriptors and data may be embedded here +}; + +//============================================================================== +// MachReceiveMessage and MachSendMessage are useful to separate the idea +// of a mach message being sent and being received, and adds increased type +// safety: +// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage +// MachPortSender::SendMessage() only accepts a MachSendMessage + +//============================================================================== +class MachReceiveMessage : public MachMessage { + public: + MachReceiveMessage() : MachMessage() {} +}; + +//============================================================================== +class MachSendMessage : public MachMessage { + public: + MachSendMessage(int32_t message_id); +}; + +//============================================================================== +// Represents a mach port for which we have receive rights +class ReceivePort { + public: + // Creates a new mach port for receiving messages and registers a name for it + explicit ReceivePort(const char *receive_port_name); + + // Given an already existing mach port, use it. We take ownership of the + // port and deallocate it in our destructor. + explicit ReceivePort(mach_port_t receive_port); + + // Create a new mach port for receiving messages + ReceivePort(); + + ~ReceivePort(); + + // Waits on the mach port until message received or timeout + kern_return_t WaitForMessage(MachReceiveMessage *out_message, + mach_msg_timeout_t timeout); + + // The underlying mach port that we wrap + mach_port_t GetPort() const { return port_; } + + private: + ReceivePort(const ReceivePort&); // disable copy c-tor + + mach_port_t port_; + kern_return_t init_result_; +}; + +//============================================================================== +// Represents a mach port for which we have send rights +class MachPortSender { + public: + // get a port with send rights corresponding to a named registered service + explicit MachPortSender(const char *receive_port_name); + + + // Given an already existing mach port, use it. + explicit MachPortSender(mach_port_t send_port); + + kern_return_t SendMessage(MachSendMessage &message, + mach_msg_timeout_t timeout); + + private: + MachPortSender(const MachPortSender&); // disable copy c-tor + + mach_port_t send_port_; + kern_return_t init_result_; +}; + +} // namespace google_breakpad + +#endif // MACH_IPC_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm new file mode 100644 index 0000000000..dc9773f77a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm @@ -0,0 +1,306 @@ +// 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. +// +// MachIPC.mm +// Wrapper for mach IPC calls + +#import +#import "MachIPC.h" +#include "common/mac/bootstrap_compat.h" + +namespace google_breakpad { +//============================================================================== +MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { + head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); + + // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() + head.msgh_local_port = MACH_PORT_NULL; + head.msgh_reserved = 0; + head.msgh_id = 0; + + SetDescriptorCount(0); // start out with no descriptors + + SetMessageID(message_id); + SetData(NULL, 0); // client may add data later +} + +//============================================================================== +// returns true if successful +bool MachMessage::SetData(void *data, + int32_t data_length) { + // first check to make sure we have enough space + size_t size = CalculateSize(); + size_t new_size = size + data_length; + + if (new_size > sizeof(MachMessage)) { + return false; // not enough space + } + + GetDataPacket()->data_length = EndianU32_NtoL(data_length); + if (data) memcpy(GetDataPacket()->data, data, data_length); + + CalculateSize(); + + return true; +} + +//============================================================================== +// calculates and returns the total size of the message +// Currently, the entire message MUST fit inside of the MachMessage +// messsage size <= sizeof(MachMessage) +mach_msg_size_t MachMessage::CalculateSize() { + size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); + + // add space for MessageDataPacket + int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; + size += 2*sizeof(int32_t) + alignedDataLength; + + // add space for descriptors + size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); + + head.msgh_size = static_cast(size); + + return head.msgh_size; +} + +//============================================================================== +MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { + size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); + MessageDataPacket *packet = + reinterpret_cast(padding + desc_size); + + return packet; +} + +//============================================================================== +void MachMessage::SetDescriptor(int n, + const MachMsgPortDescriptor &desc) { + MachMsgPortDescriptor *desc_array = + reinterpret_cast(padding); + desc_array[n] = desc; +} + +//============================================================================== +// returns true if successful otherwise there was not enough space +bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { + // first check to make sure we have enough space + int size = CalculateSize(); + size_t new_size = size + sizeof(MachMsgPortDescriptor); + + if (new_size > sizeof(MachMessage)) { + return false; // not enough space + } + + // unfortunately, we need to move the data to allow space for the + // new descriptor + u_int8_t *p = reinterpret_cast(GetDataPacket()); + bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); + + SetDescriptor(GetDescriptorCount(), desc); + SetDescriptorCount(GetDescriptorCount() + 1); + + CalculateSize(); + + return true; +} + +//============================================================================== +void MachMessage::SetDescriptorCount(int n) { + body.msgh_descriptor_count = n; + + if (n > 0) { + head.msgh_bits |= MACH_MSGH_BITS_COMPLEX; + } else { + head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; + } +} + +//============================================================================== +MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { + if (n < GetDescriptorCount()) { + MachMsgPortDescriptor *desc = + reinterpret_cast(padding); + return desc + n; + } + + return nil; +} + +//============================================================================== +mach_port_t MachMessage::GetTranslatedPort(int n) { + if (n < GetDescriptorCount()) { + return GetDescriptor(n)->GetMachPort(); + } + return MACH_PORT_NULL; +} + +#pragma mark - + +//============================================================================== +// create a new mach port for receiving messages and register a name for it +ReceivePort::ReceivePort(const char *receive_port_name) { + mach_port_t current_task = mach_task_self(); + + init_result_ = mach_port_allocate(current_task, + MACH_PORT_RIGHT_RECEIVE, + &port_); + + if (init_result_ != KERN_SUCCESS) + return; + + init_result_ = mach_port_insert_right(current_task, + port_, + port_, + MACH_MSG_TYPE_MAKE_SEND); + + if (init_result_ != KERN_SUCCESS) + return; + + mach_port_t task_bootstrap_port = 0; + init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port); + + if (init_result_ != KERN_SUCCESS) + return; + + init_result_ = breakpad::BootstrapRegister( + bootstrap_port, + const_cast(receive_port_name), + port_); +} + +//============================================================================== +// create a new mach port for receiving messages +ReceivePort::ReceivePort() { + mach_port_t current_task = mach_task_self(); + + init_result_ = mach_port_allocate(current_task, + MACH_PORT_RIGHT_RECEIVE, + &port_); + + if (init_result_ != KERN_SUCCESS) + return; + + init_result_ = mach_port_insert_right(current_task, + port_, + port_, + MACH_MSG_TYPE_MAKE_SEND); +} + +//============================================================================== +// Given an already existing mach port, use it. We take ownership of the +// port and deallocate it in our destructor. +ReceivePort::ReceivePort(mach_port_t receive_port) + : port_(receive_port), + init_result_(KERN_SUCCESS) { +} + +//============================================================================== +ReceivePort::~ReceivePort() { + if (init_result_ == KERN_SUCCESS) + mach_port_deallocate(mach_task_self(), port_); +} + +//============================================================================== +kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, + mach_msg_timeout_t timeout) { + if (!out_message) { + return KERN_INVALID_ARGUMENT; + } + + // return any error condition encountered in constructor + if (init_result_ != KERN_SUCCESS) + return init_result_; + + out_message->head.msgh_bits = 0; + out_message->head.msgh_local_port = port_; + out_message->head.msgh_remote_port = MACH_PORT_NULL; + out_message->head.msgh_reserved = 0; + out_message->head.msgh_id = 0; + + mach_msg_option_t options = MACH_RCV_MSG; + if (timeout != MACH_MSG_TIMEOUT_NONE) + options |= MACH_RCV_TIMEOUT; + kern_return_t result = mach_msg(&out_message->head, + options, + 0, + sizeof(MachMessage), + port_, + timeout, // timeout in ms + MACH_PORT_NULL); + + return result; +} + +#pragma mark - + +//============================================================================== +// get a port with send rights corresponding to a named registered service +MachPortSender::MachPortSender(const char *receive_port_name) { + mach_port_t task_bootstrap_port = 0; + init_result_ = task_get_bootstrap_port(mach_task_self(), + &task_bootstrap_port); + + if (init_result_ != KERN_SUCCESS) + return; + + init_result_ = bootstrap_look_up(task_bootstrap_port, + const_cast(receive_port_name), + &send_port_); +} + +//============================================================================== +MachPortSender::MachPortSender(mach_port_t send_port) + : send_port_(send_port), + init_result_(KERN_SUCCESS) { +} + +//============================================================================== +kern_return_t MachPortSender::SendMessage(MachSendMessage &message, + mach_msg_timeout_t timeout) { + if (message.head.msgh_size == 0) { + return KERN_INVALID_VALUE; // just for safety -- never should occur + }; + + if (init_result_ != KERN_SUCCESS) + return init_result_; + + message.head.msgh_remote_port = send_port_; + + kern_return_t result = mach_msg(&message.head, + MACH_SEND_MSG | MACH_SEND_TIMEOUT, + message.head.msgh_size, + 0, + MACH_PORT_NULL, + timeout, // timeout in ms + MACH_PORT_NULL); + + return result; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc new file mode 100644 index 0000000000..c0e4bac54b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc @@ -0,0 +1,264 @@ +// Copyright (c) 2012, 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 "common/mac/arch_utilities.h" + +#include +#include +#include +#include + +#ifndef CPU_SUBTYPE_ARM_V7S +#define CPU_SUBTYPE_ARM_V7S (static_cast(11)) +#endif // CPU_SUBTYPE_ARM_V7S + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif // CPU_TYPE_ARM64 + +#ifndef CPU_SUBTYPE_ARM64_ALL +#define CPU_SUBTYPE_ARM64_ALL (static_cast(0)) +#endif // CPU_SUBTYPE_ARM64_ALL + +#ifndef CPU_SUBTYPE_ARM64_E +#define CPU_SUBTYPE_ARM64_E (static_cast(2)) +#endif // CPU_SUBTYPE_ARM64_E + +namespace { + +const NXArchInfo* ArchInfo_arm64(cpu_subtype_t cpu_subtype) { + const char* name = NULL; + switch (cpu_subtype) { + case CPU_SUBTYPE_ARM64_ALL: + name = "arm64"; + break; + case CPU_SUBTYPE_ARM64_E: + name = "arm64e"; + break; + default: + return NULL; + } + + NXArchInfo* arm64 = new NXArchInfo; + *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7); + arm64->name = name; + arm64->cputype = CPU_TYPE_ARM64; + arm64->cpusubtype = cpu_subtype; + arm64->description = "arm 64"; + return arm64; +} + +const NXArchInfo* ArchInfo_armv7s() { + NXArchInfo* armv7s = new NXArchInfo; + *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7); + armv7s->name = "armv7s"; + armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S; + armv7s->description = "arm v7s"; + return armv7s; +} + +} // namespace + +namespace google_breakpad { + +const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) { + // TODO: Remove this when the OS knows about arm64. + if (!strcmp("arm64", arch_name)) + return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_ALL); + + if (!strcmp("arm64e", arch_name)) + return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_E); + + // TODO: Remove this when the OS knows about armv7s. + if (!strcmp("armv7s", arch_name)) + return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S); + + return NXGetArchInfoFromName(arch_name); +} + +const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype) { + // TODO: Remove this when the OS knows about arm64. + if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) { + static const NXArchInfo* arm64 = ArchInfo_arm64(cpu_subtype); + return arm64; + } + + if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_E) { + static const NXArchInfo* arm64e = ArchInfo_arm64(cpu_subtype); + return arm64e; + } + + // TODO: Remove this when the OS knows about armv7s. + if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) { + static const NXArchInfo* armv7s = ArchInfo_armv7s(); + return armv7s; + } + + return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); +} + +} // namespace google_breakpad + +#ifndef __APPLE__ +namespace { + +enum Architecture { + kArch_i386 = 0, + kArch_x86_64, + kArch_x86_64h, + kArch_arm, + kArch_arm64, + kArch_arm64e, + kArch_ppc, + // This must be last. + kNumArchitectures +}; + +// enum Architecture above and kKnownArchitectures below +// must be kept in sync. +const NXArchInfo kKnownArchitectures[] = { + { + "i386", + CPU_TYPE_I386, + CPU_SUBTYPE_I386_ALL, + NX_LittleEndian, + "Intel 80x86" + }, + { + "x86_64", + CPU_TYPE_X86_64, + CPU_SUBTYPE_X86_64_ALL, + NX_LittleEndian, + "Intel x86-64" + }, + { + "x86_64h", + CPU_TYPE_X86_64, + CPU_SUBTYPE_X86_64_H, + NX_LittleEndian, + "Intel x86-64h Haswell" + }, + { + "arm", + CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_ALL, + NX_LittleEndian, + "ARM" + }, + { + "arm64", + CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_ALL, + NX_LittleEndian, + "ARM64" + }, + { + "arm64e", + CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_E, + NX_LittleEndian, + "ARM64e" + }, + { + "ppc", + CPU_TYPE_POWERPC, + CPU_SUBTYPE_POWERPC_ALL, + NX_BigEndian, + "PowerPC" + } +}; + +} // namespace + +const NXArchInfo *NXGetLocalArchInfo(void) { + Architecture arch; +#if defined(__i386__) + arch = kArch_i386; +#elif defined(__x86_64__) + arch = kArch_x86_64; +#elif defined(__arm64) + arch = kArch_arm64; +#elif defined(__arm__) + arch = kArch_arm; +#elif defined(__powerpc__) + arch = kArch_ppc; +#else + #error "Unsupported CPU architecture" +#endif + return &kKnownArchitectures[arch]; +} + +const NXArchInfo *NXGetArchInfoFromName(const char *name) { + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (!strcmp(name, kKnownArchitectures[arch].name)) { + return &kKnownArchitectures[arch]; + } + } + return NULL; +} + +const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, + cpu_subtype_t cpusubtype) { + const NXArchInfo *candidate = NULL; + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (kKnownArchitectures[arch].cputype == cputype) { + if (kKnownArchitectures[arch].cpusubtype == cpusubtype) { + return &kKnownArchitectures[arch]; + } + if (!candidate) { + candidate = &kKnownArchitectures[arch]; + } + } + } + return candidate; +} + +struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, + cpu_subtype_t cpusubtype, + struct fat_arch *fat_archs, + uint32_t nfat_archs) { + struct fat_arch *candidate = NULL; + for (uint32_t f = 0; f < nfat_archs; ++f) { + if (fat_archs[f].cputype == cputype) { + if (fat_archs[f].cpusubtype == cpusubtype) { + return &fat_archs[f]; + } + if (!candidate) { + candidate = &fat_archs[f]; + } + } + } + return candidate; +} +#endif // !__APPLE__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h new file mode 100644 index 0000000000..397c1f5873 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h @@ -0,0 +1,47 @@ +// Copyright (c) 2012, 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. + +// arch_utilities.h: Utilities for architecture introspection for Mac platform. + +#ifndef COMMON_MAC_ARCH_UTILITIES_H__ +#define COMMON_MAC_ARCH_UTILITIES_H__ + +#include + +namespace google_breakpad { + +// Custom implementation of |NXGetArchInfoFromName| and +// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes. +const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name); +const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype); + +} // namespace google_breakpad + +#endif // COMMON_MAC_ARCH_UTILITIES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc new file mode 100644 index 0000000000..d875d95b5f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2012, 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 "common/mac/bootstrap_compat.h" + +namespace breakpad { + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +kern_return_t BootstrapRegister(mach_port_t bp, + name_t service_name, + mach_port_t sp) { + return bootstrap_register(bp, service_name, sp); +} +#pragma GCC diagnostic warning "-Wdeprecated-declarations" + +} // namesapce breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h new file mode 100644 index 0000000000..8ca7357c34 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012, 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 COMMON_MAC_BOOTSTRAP_COMPAT_H_ +#define COMMON_MAC_BOOTSTRAP_COMPAT_H_ + +#include + +namespace breakpad { + +// Wrapper for bootstrap_register to avoid deprecation warnings. +// +// In 10.6, it's possible to call bootstrap_check_in as the one-stop-shop for +// handling what bootstrap_register is used for. In 10.5, bootstrap_check_in +// can't check in a service whose name has not yet been registered, despite +// bootstrap_register being marked as deprecated in that OS release. Breakpad +// needs to register new service names, and in 10.5, calling +// bootstrap_register is the only way to achieve that. Attempts to call +// bootstrap_check_in for a new service name on 10.5 will result in +// BOOTSTRAP_UNKNOWN_SERVICE being returned rather than registration of the +// new service name. +kern_return_t BootstrapRegister(mach_port_t bp, + name_t service_name, + mach_port_t sp); + +} // namespace breakpad + +#endif // COMMON_MAC_BOOTSTRAP_COMPAT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h b/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h new file mode 100644 index 0000000000..b7bbc0b95b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h @@ -0,0 +1,73 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// byteswap.h: Overloaded functions for conveniently byteswapping values. + +#ifndef COMMON_MAC_BYTESWAP_H_ +#define COMMON_MAC_BYTESWAP_H_ + +#ifdef __APPLE__ +#include + +static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); } +static inline uint32_t ByteSwap(uint32_t v) { return OSSwapInt32(v); } +static inline uint64_t ByteSwap(uint64_t v) { return OSSwapInt64(v); } +static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); } +static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); } +static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); } + +#elif defined(__linux__) +// For NXByteOrder +#include +#include +#include +#include_next + +static inline uint16_t ByteSwap(uint16_t v) { return bswap_16(v); } +static inline uint32_t ByteSwap(uint32_t v) { return bswap_32(v); } +static inline uint64_t ByteSwap(uint64_t v) { return bswap_64(v); } +static inline int16_t ByteSwap(int16_t v) { return bswap_16(v); } +static inline int32_t ByteSwap(int32_t v) { return bswap_32(v); } +static inline int64_t ByteSwap(int64_t v) { return bswap_64(v); } + +static inline NXByteOrder NXHostByteOrder() { +#ifdef __LITTLE_ENDIAN + return NX_LittleEndian; +#else + return NX_BigEndian; +#endif +} + +#endif // __APPLE__ + +#endif // COMMON_MAC_BYTESWAP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc new file mode 100644 index 0000000000..3c48f23528 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc @@ -0,0 +1,679 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011, 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. + +// Author: Jim Blandy + +// dump_syms.cc: Create a symbol file for use with minidumps + +#include "common/mac/dump_syms.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/dwarf_cu_to_module.h" +#include "common/dwarf_line_to_module.h" +#include "common/dwarf_range_list_handler.h" +#include "common/mac/file_id.h" +#include "common/mac/arch_utilities.h" +#include "common/mac/macho_reader.h" +#include "common/module.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#include "common/stabs_reader.h" +#include "common/stabs_to_module.h" +#include "common/symbol_data.h" + +#ifndef CPU_TYPE_ARM +#define CPU_TYPE_ARM (static_cast(12)) +#endif // CPU_TYPE_ARM + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (static_cast(16777228)) +#endif // CPU_TYPE_ARM64 + +using dwarf2reader::ByteReader; +using google_breakpad::DwarfCUToModule; +using google_breakpad::DwarfLineToModule; +using google_breakpad::DwarfRangeListHandler; +using google_breakpad::FileID; +using google_breakpad::mach_o::FatReader; +using google_breakpad::mach_o::Section; +using google_breakpad::mach_o::Segment; +using google_breakpad::Module; +using google_breakpad::StabsReader; +using google_breakpad::StabsToModule; +using google_breakpad::scoped_ptr; +using std::make_pair; +using std::pair; +using std::string; +using std::vector; + +namespace { +// Return a vector with absolute paths to all the entries +// in directory (excluding . and ..). +vector list_directory(const string& directory) { + vector entries; + DIR* dir = opendir(directory.c_str()); + if (!dir) { + return entries; + } + + string path = directory; + if (path[path.length() - 1] != '/') { + path += '/'; + } + + struct dirent* entry = NULL; + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + entries.push_back(path + entry->d_name); + } + } + + closedir(dir); + return entries; +} +} + +namespace google_breakpad { + +bool DumpSymbols::Read(const string &filename) { + struct stat st; + if (stat(filename.c_str(), &st) == -1) { + fprintf(stderr, "Could not access object file %s: %s\n", + filename.c_str(), strerror(errno)); + return false; + } + + input_pathname_ = filename; + + // Does this filename refer to a dSYM bundle? + string contents_path = input_pathname_ + "/Contents/Resources/DWARF"; + if (S_ISDIR(st.st_mode) && + access(contents_path.c_str(), F_OK) == 0) { + // If there's one file under Contents/Resources/DWARF then use that, + // otherwise bail out. + const vector entries = list_directory(contents_path); + if (entries.size() == 0) { + fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", + input_pathname_.c_str()); + return false; + } + if (entries.size() > 1) { + fprintf(stderr, "Too many DWARF files in bundle: %s\n", + input_pathname_.c_str()); + return false; + } + + object_filename_ = entries[0]; + } else { + object_filename_ = input_pathname_; + } + + // Read the file's contents into memory. + bool read_ok = true; + string error; + if (stat(object_filename_.c_str(), &st) != -1) { + FILE* f = fopen(object_filename_.c_str(), "rb"); + if (f) { + contents_.reset(new uint8_t[st.st_size]); + off_t total = 0; + while (total < st.st_size && !feof(f)) { + size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f); + if (read == 0) { + if (ferror(f)) { + read_ok = false; + error = strerror(errno); + } + break; + } + total += read; + } + fclose(f); + } else { + error = strerror(errno); + } + } + + if (!read_ok) { + fprintf(stderr, "Error reading object file: %s: %s\n", + object_filename_.c_str(), + error.c_str()); + return false; + } + + // Get the list of object files present in the file. + FatReader::Reporter fat_reporter(object_filename_); + FatReader fat_reader(&fat_reporter); + if (!fat_reader.Read(&contents_[0], + st.st_size)) { + return false; + } + + // Get our own copy of fat_reader's object file list. + size_t object_files_count; + const SuperFatArch *object_files = + fat_reader.object_files(&object_files_count); + if (object_files_count == 0) { + fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", + object_filename_.c_str()); + return false; + } + object_files_.resize(object_files_count); + memcpy(&object_files_[0], object_files, + sizeof(SuperFatArch) * object_files_count); + + return true; +} + +bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype) { + // Find the best match for the architecture the user requested. + const SuperFatArch *best_match = FindBestMatchForArchitecture( + cpu_type, cpu_subtype); + if (!best_match) return false; + + // Record the selected object file. + selected_object_file_ = best_match; + return true; +} + +bool DumpSymbols::SetArchitecture(const std::string &arch_name) { + bool arch_set = false; + const NXArchInfo *arch_info = + google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); + if (arch_info) { + arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); + } + return arch_set; +} + +SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( + cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + // Check if all the object files can be converted to struct fat_arch. + bool can_convert_to_fat_arch = true; + vector fat_arch_vector; + for (vector::const_iterator it = object_files_.begin(); + it != object_files_.end(); + ++it) { + struct fat_arch arch; + bool success = it->ConvertToFatArch(&arch); + if (!success) { + can_convert_to_fat_arch = false; + break; + } + fat_arch_vector.push_back(arch); + } + + // If all the object files can be converted to struct fat_arch, use + // NXFindBestFatArch. + if (can_convert_to_fat_arch) { + const struct fat_arch *best_match + = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], + static_cast(fat_arch_vector.size())); + + for (size_t i = 0; i < fat_arch_vector.size(); ++i) { + if (best_match == &fat_arch_vector[i]) + return &object_files_[i]; + } + assert(best_match == NULL); + return NULL; + } + + // Check for an exact match with cpu_type and cpu_subtype. + for (vector::iterator it = object_files_.begin(); + it != object_files_.end(); + ++it) { + if (static_cast(it->cputype) == cpu_type && + static_cast(it->cpusubtype) == cpu_subtype) + return &*it; + } + + // No exact match found. + // TODO(erikchen): If it becomes necessary, we can copy the implementation of + // NXFindBestFatArch, located at + // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. + fprintf(stderr, "Failed to find an exact match for an object file with cpu " + "type: %d and cpu subtype: %d. Furthermore, at least one object file is " + "larger than 2**32.\n", cpu_type, cpu_subtype); + return NULL; +} + +string DumpSymbols::Identifier() { + FileID file_id(object_filename_.c_str()); + unsigned char identifier_bytes[16]; + cpu_type_t cpu_type = selected_object_file_->cputype; + cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype & ~CPU_SUBTYPE_MASK; + if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { + fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", + object_filename_.c_str()); + return ""; + } + + char identifier_string[40]; + FileID::ConvertIdentifierToString(identifier_bytes, identifier_string, + sizeof(identifier_string)); + + string compacted(identifier_string); + for(size_t i = compacted.find('-'); i != string::npos; + i = compacted.find('-', i)) + compacted.erase(i, 1); + + return compacted; +} + +// A range handler that accepts rangelist data parsed by +// dwarf2reader::RangeListReader and populates a range vector (typically +// owned by a function) with the results. +class DumpSymbols::DumperRangesHandler: + public DwarfCUToModule::RangesHandler { + public: + DumperRangesHandler(const uint8_t *buffer, uint64 size, + dwarf2reader::ByteReader* reader) + : buffer_(buffer), size_(size), reader_(reader) { } + + bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) { + DwarfRangeListHandler handler(base_address, ranges); + dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, + &handler); + + return rangelist_reader.ReadRangeList(offset); + } + + private: + const uint8_t *buffer_; + uint64 size_; + dwarf2reader::ByteReader* reader_; +}; + +// A line-to-module loader that accepts line number info parsed by +// dwarf2reader::LineInfo and populates a Module and a line vector +// with the results. +class DumpSymbols::DumperLineToModule: + public DwarfCUToModule::LineToModuleHandler { + public: + // Create a line-to-module converter using BYTE_READER. + DumperLineToModule(dwarf2reader::ByteReader *byte_reader) + : byte_reader_(byte_reader) { } + + void StartCompilationUnit(const string& compilation_dir) { + compilation_dir_ = compilation_dir; + } + + void ReadProgram(const uint8_t *program, uint64 length, + Module *module, vector *lines) { + DwarfLineToModule handler(module, compilation_dir_, lines); + dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); + parser.Start(); + } + private: + string compilation_dir_; + dwarf2reader::ByteReader *byte_reader_; // WEAK +}; + +bool DumpSymbols::CreateEmptyModule(scoped_ptr& module) { + // Select an object file, if SetArchitecture hasn't been called to set one + // explicitly. + if (!selected_object_file_) { + // If there's only one architecture, that's the one. + if (object_files_.size() == 1) + selected_object_file_ = &object_files_[0]; + else { + // Look for an object file whose architecture matches our own. + const NXArchInfo *local_arch = NXGetLocalArchInfo(); + if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { + fprintf(stderr, "%s: object file contains more than one" + " architecture, none of which match the current" + " architecture; specify an architecture explicitly" + " with '-a ARCH' to resolve the ambiguity\n", + object_filename_.c_str()); + return false; + } + } + } + + assert(selected_object_file_); + + // Find the name of the selected file's architecture, to appear in + // the MODULE record and in error messages. + const NXArchInfo *selected_arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType( + selected_object_file_->cputype, selected_object_file_->cpusubtype); + + const char *selected_arch_name = selected_arch_info->name; + if (strcmp(selected_arch_name, "i386") == 0) + selected_arch_name = "x86"; + + // Produce a name to use in error messages that includes the + // filename, and the architecture, if there is more than one. + selected_object_name_ = object_filename_; + if (object_files_.size() > 1) { + selected_object_name_ += ", architecture "; + selected_object_name_ + selected_arch_name; + } + + // Compute a module name, to appear in the MODULE record. + string module_name = google_breakpad::BaseName(object_filename_); + + // Choose an identifier string, to appear in the MODULE record. + string identifier = Identifier(); + if (identifier.empty()) + return false; + identifier += "0"; + + // Create a module to hold the debugging information. + module.reset(new Module(module_name, + "mac", + selected_arch_name, + identifier)); + return true; +} + +void DumpSymbols::ReadDwarf(google_breakpad::Module *module, + const mach_o::Reader &macho_reader, + const mach_o::SectionMap &dwarf_sections, + bool handle_inter_cu_refs) const { + // Build a byte reader of the appropriate endianness. + ByteReader byte_reader(macho_reader.big_endian() + ? dwarf2reader::ENDIANNESS_BIG + : dwarf2reader::ENDIANNESS_LITTLE); + + // Construct a context for this file. + DwarfCUToModule::FileContext file_context(selected_object_name_, + module, + handle_inter_cu_refs); + + // Build a dwarf2reader::SectionMap from our mach_o::SectionMap. + for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin(); + it != dwarf_sections.end(); ++it) { + file_context.AddSectionToSectionMap( + it->first, + it->second.contents.start, + it->second.contents.Size()); + } + + // Find the __debug_info section. + dwarf2reader::SectionMap::const_iterator debug_info_entry = + file_context.section_map().find("__debug_info"); + // There had better be a __debug_info section! + if (debug_info_entry == file_context.section_map().end()) { + fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n", + selected_object_name_.c_str()); + return; + } + const std::pair& debug_info_section = + debug_info_entry->second; + + // Build a line-to-module loader for the root handler to use. + DumperLineToModule line_to_module(&byte_reader); + + // Optional .debug_ranges reader + scoped_ptr ranges_handler; + dwarf2reader::SectionMap::const_iterator ranges_entry = + file_context.section_map().find("__debug_ranges"); + if (ranges_entry != file_context.section_map().end()) { + const std::pair& ranges_section = + ranges_entry->second; + ranges_handler.reset( + new DumperRangesHandler(ranges_section.first, ranges_section.second, + &byte_reader)); + } + + // Walk the __debug_info section, one compilation unit at a time. + uint64 debug_info_length = debug_info_section.second; + for (uint64 offset = 0; offset < debug_info_length;) { + // Make a handler for the root DIE that populates MODULE with the + // debug info. + DwarfCUToModule::WarningReporter reporter(selected_object_name_, + offset); + DwarfCUToModule root_handler(&file_context, &line_to_module, + ranges_handler.get(), &reporter); + // Make a Dwarf2Handler that drives our DIEHandler. + dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); + // Make a DWARF parser for the compilation unit at OFFSET. + dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_, + file_context.section_map(), + offset, + &byte_reader, + &die_dispatcher); + // Process the entire compilation unit; get the offset of the next. + offset += dwarf_reader.Start(); + } +} + +bool DumpSymbols::ReadCFI(google_breakpad::Module *module, + const mach_o::Reader &macho_reader, + const mach_o::Section §ion, + bool eh_frame) const { + // Find the appropriate set of register names for this file's + // architecture. + vector register_names; + switch (macho_reader.cpu_type()) { + case CPU_TYPE_X86: + register_names = DwarfCFIToModule::RegisterNames::I386(); + break; + case CPU_TYPE_X86_64: + register_names = DwarfCFIToModule::RegisterNames::X86_64(); + break; + case CPU_TYPE_ARM: + register_names = DwarfCFIToModule::RegisterNames::ARM(); + break; + case CPU_TYPE_ARM64: + register_names = DwarfCFIToModule::RegisterNames::ARM64(); + break; + default: { + const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType( + macho_reader.cpu_type(), macho_reader.cpu_subtype()); + fprintf(stderr, "%s: cannot convert DWARF call frame information for ", + selected_object_name_.c_str()); + if (arch) + fprintf(stderr, "architecture '%s'", arch->name); + else + fprintf(stderr, "architecture %d,%d", + macho_reader.cpu_type(), macho_reader.cpu_subtype()); + fprintf(stderr, " to Breakpad symbol file: no register name table\n"); + return false; + } + } + + // Find the call frame information and its size. + const uint8_t *cfi = section.contents.start; + size_t cfi_size = section.contents.Size(); + + // Plug together the parser, handler, and their entourages. + DwarfCFIToModule::Reporter module_reporter(selected_object_name_, + section.section_name); + DwarfCFIToModule handler(module, register_names, &module_reporter); + dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ? + dwarf2reader::ENDIANNESS_BIG : + dwarf2reader::ENDIANNESS_LITTLE); + byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4); + // At the moment, according to folks at Apple and some cursory + // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so + // this is the only base address the CFI parser will need. + byte_reader.SetCFIDataBase(section.address, cfi); + + dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_, + section.section_name); + dwarf2reader::CallFrameInfo parser(cfi, cfi_size, + &byte_reader, &handler, &dwarf_reporter, + eh_frame); + parser.Start(); + return true; +} + +// A LoadCommandHandler that loads whatever debugging data it finds into a +// Module. +class DumpSymbols::LoadCommandDumper: + public mach_o::Reader::LoadCommandHandler { + public: + // Create a load command dumper handling load commands from READER's + // file, and adding data to MODULE. + LoadCommandDumper(const DumpSymbols &dumper, + google_breakpad::Module *module, + const mach_o::Reader &reader, + SymbolData symbol_data, + bool handle_inter_cu_refs) + : dumper_(dumper), + module_(module), + reader_(reader), + symbol_data_(symbol_data), + handle_inter_cu_refs_(handle_inter_cu_refs) { } + + bool SegmentCommand(const mach_o::Segment &segment); + bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings); + + private: + const DumpSymbols &dumper_; + google_breakpad::Module *module_; // WEAK + const mach_o::Reader &reader_; + const SymbolData symbol_data_; + const bool handle_inter_cu_refs_; +}; + +bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) { + mach_o::SectionMap section_map; + if (!reader_.MapSegmentSections(segment, §ion_map)) + return false; + + if (segment.name == "__TEXT") { + module_->SetLoadAddress(segment.vmaddr); + if (symbol_data_ != NO_CFI) { + mach_o::SectionMap::const_iterator eh_frame = + section_map.find("__eh_frame"); + if (eh_frame != section_map.end()) { + // If there is a problem reading this, don't treat it as a fatal error. + dumper_.ReadCFI(module_, reader_, eh_frame->second, true); + } + } + return true; + } + + if (segment.name == "__DWARF") { + if (symbol_data_ != ONLY_CFI) { + dumper_.ReadDwarf(module_, reader_, section_map, handle_inter_cu_refs_); + } + if (symbol_data_ != NO_CFI) { + mach_o::SectionMap::const_iterator debug_frame + = section_map.find("__debug_frame"); + if (debug_frame != section_map.end()) { + // If there is a problem reading this, don't treat it as a fatal error. + dumper_.ReadCFI(module_, reader_, debug_frame->second, false); + } + } + } + + return true; +} + +bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries, + const ByteBuffer &strings) { + StabsToModule stabs_to_module(module_); + // Mac OS X STABS are never "unitized", and the size of the 'value' field + // matches the address size of the executable. + StabsReader stabs_reader(entries.start, entries.Size(), + strings.start, strings.Size(), + reader_.big_endian(), + reader_.bits_64() ? 8 : 4, + true, + &stabs_to_module); + if (!stabs_reader.Process()) + return false; + stabs_to_module.Finalize(); + return true; +} + +bool DumpSymbols::ReadSymbolData(Module** out_module) { + scoped_ptr module; + if (!CreateEmptyModule(module)) + return false; + + // Parse the selected object file. + mach_o::Reader::Reporter reporter(selected_object_name_); + mach_o::Reader reader(&reporter); + if (!reader.Read(&contents_[0] + + selected_object_file_->offset, + selected_object_file_->size, + selected_object_file_->cputype, + selected_object_file_->cpusubtype)) + return false; + + // Walk its load commands, and deal with whatever is there. + LoadCommandDumper load_command_dumper(*this, module.get(), reader, + symbol_data_, handle_inter_cu_refs_); + if (!reader.WalkLoadCommands(&load_command_dumper)) + return false; + + *out_module = module.release(); + + return true; +} + +bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { + Module* module = NULL; + + if (ReadSymbolData(&module) && module) { + bool res = module->Write(stream, symbol_data_); + delete module; + return res; + } + + return false; +} + +// Read the selected object file's debugging information, and write out the +// header only to |stream|. Return true on success; if an error occurs, report +// it and return false. +bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) { + scoped_ptr module; + if (!CreateEmptyModule(module)) + return false; + + return module->Write(stream, symbol_data_); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h new file mode 100644 index 0000000000..1e57f86ddd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h @@ -0,0 +1,196 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011, 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. + +// Author: Jim Blandy + +// dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for +// reading debugging information from Mach-O files and writing it out as a +// Breakpad symbol file. + +#include +#include +#include + +#include +#include +#include + +#include "common/byte_cursor.h" +#include "common/mac/macho_reader.h" +#include "common/mac/super_fat_arch.h" +#include "common/module.h" +#include "common/scoped_ptr.h" +#include "common/symbol_data.h" + +namespace google_breakpad { + +class DumpSymbols { + public: + DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs) + : symbol_data_(symbol_data), + handle_inter_cu_refs_(handle_inter_cu_refs), + input_pathname_(), + object_filename_(), + contents_(), + object_files_(), + selected_object_file_(), + selected_object_name_() { } + ~DumpSymbols() { + } + + // Prepare to read debugging information from |filename|. |filename| may be + // the name of a universal binary, a Mach-O file, or a dSYM bundle + // containing either of the above. On success, return true; if there is a + // problem reading |filename|, report it and return false. + bool Read(const std::string &filename); + + // If this dumper's file includes an object file for |cpu_type| and + // |cpu_subtype|, then select that object file for dumping, and return + // true. Otherwise, return false, and leave this dumper's selected + // architecture unchanged. + // + // By default, if this dumper's file contains only one object file, then + // the dumper will dump those symbols; and if it contains more than one + // object file, then the dumper will dump the object file whose + // architecture matches that of this dumper program. + bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + + // If this dumper's file includes an object file for |arch_name|, then select + // that object file for dumping, and return true. Otherwise, return false, + // and leave this dumper's selected architecture unchanged. + // + // By default, if this dumper's file contains only one object file, then + // the dumper will dump those symbols; and if it contains more than one + // object file, then the dumper will dump the object file whose + // architecture matches that of this dumper program. + bool SetArchitecture(const std::string &arch_name); + + // Return a pointer to an array of SuperFatArch structures describing the + // object files contained in this dumper's file. Set *|count| to the number + // of elements in the array. The returned array is owned by this DumpSymbols + // instance. + // + // If there are no available architectures, this function + // may return NULL. + const SuperFatArch* AvailableArchitectures(size_t *count) { + *count = object_files_.size(); + if (object_files_.size() > 0) + return &object_files_[0]; + return NULL; + } + + // Read the selected object file's debugging information, and write it out to + // |stream|. Return true on success; if an error occurs, report it and + // return false. + bool WriteSymbolFile(std::ostream &stream); + + // Read the selected object file's debugging information, and write out the + // header only to |stream|. Return true on success; if an error occurs, report + // it and return false. + bool WriteSymbolFileHeader(std::ostream &stream); + + // As above, but simply return the debugging information in module + // instead of writing it to a stream. The caller owns the resulting + // module object and must delete it when finished. + bool ReadSymbolData(Module** module); + + private: + // Used internally. + class DumperLineToModule; + class DumperRangesHandler; + class LoadCommandDumper; + + // This method behaves similarly to NXFindBestFatArch, but it supports + // SuperFatArch. + SuperFatArch* FindBestMatchForArchitecture( + cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + + // Return an identifier string for the file this DumpSymbols is dumping. + std::string Identifier(); + + + // Creates an empty module object. + bool CreateEmptyModule(scoped_ptr& module); + + // Read debugging information from |dwarf_sections|, which was taken from + // |macho_reader|, and add it to |module|. + void ReadDwarf(google_breakpad::Module *module, + const mach_o::Reader &macho_reader, + const mach_o::SectionMap &dwarf_sections, + bool handle_inter_cu_refs) const; + + // Read DWARF CFI or .eh_frame data from |section|, belonging to + // |macho_reader|, and record it in |module|. If |eh_frame| is true, + // then the data is .eh_frame-format data; otherwise, it is standard DWARF + // .debug_frame data. On success, return true; on failure, report + // the problem and return false. + bool ReadCFI(google_breakpad::Module *module, + const mach_o::Reader &macho_reader, + const mach_o::Section §ion, + bool eh_frame) const; + + // The selection of what type of symbol data to read/write. + const SymbolData symbol_data_; + + // Whether to handle references between compilation units. + const bool handle_inter_cu_refs_; + + // The name of the file or bundle whose symbols this will dump. + // This is the path given to Read, for use in error messages. + std::string input_pathname_; + + // The name of the file this DumpSymbols will actually read debugging + // information from. Normally, this is the same as input_pathname_, but if + // filename refers to a dSYM bundle, then this is the resource file + // within that bundle. + std::string object_filename_; + + // The complete contents of object_filename_, mapped into memory. + scoped_array contents_; + + // A vector of SuperFatArch structures describing the object files + // object_filename_ contains. If object_filename_ refers to a fat binary, + // this may have more than one element; if it refers to a Mach-O file, this + // has exactly one element. + vector object_files_; + + // The object file in object_files_ selected to dump, or NULL if + // SetArchitecture hasn't been called yet. + const SuperFatArch *selected_object_file_; + + // A string that identifies the selected object file, for use in error + // messages. This is usually object_filename_, but if that refers to a + // fat binary, it includes an indication of the particular architecture + // within that binary. + string selected_object_name_; +}; + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc new file mode 100644 index 0000000000..4661d5d625 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc @@ -0,0 +1,106 @@ +// 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. + +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// +// Author: Dan Waylonis + +#include +#include +#include +#include + +#include "common/mac/file_id.h" +#include "common/mac/macho_id.h" + +using MacFileUtilities::MachoID; + +namespace google_breakpad { + +FileID::FileID(const char *path) { + snprintf(path_, sizeof(path_), "%s", path); +} + +bool FileID::FileIdentifier(unsigned char identifier[16]) { + int fd = open(path_, O_RDONLY); + if (fd == -1) + return false; + + MD5Context md5; + MD5Init(&md5); + + // Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but + // doesn't seem to be an unreasonable size for the stack. + unsigned char buffer[4096 * 2]; + size_t buffer_size = sizeof(buffer); + while ((buffer_size = read(fd, buffer, buffer_size) > 0)) { + MD5Update(&md5, buffer, static_cast(buffer_size)); + } + + close(fd); + MD5Final(identifier, &md5); + + return true; +} + +bool FileID::MachoIdentifier(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]) { + MachoID macho(path_); + + if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier)) + return true; + + return macho.MD5(cpu_type, cpu_subtype, identifier); +} + +// static +void FileID::ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length) { + int buffer_idx = 0; + for (int idx = 0; (buffer_idx < buffer_length) && (idx < 16); ++idx) { + int hi = (identifier[idx] >> 4) & 0x0F; + int lo = (identifier[idx]) & 0x0F; + + if (idx == 4 || idx == 6 || idx == 8 || idx == 10) + buffer[buffer_idx++] = '-'; + + buffer[buffer_idx++] = + static_cast((hi >= 10) ? ('A' + hi - 10) : ('0' + hi)); + buffer[buffer_idx++] = + static_cast((lo >= 10) ? ('A' + lo - 10) : ('0' + lo)); + } + + // NULL terminate + buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h new file mode 100644 index 0000000000..5d60e84c9a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.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. + +// file_id.h: Return a unique identifier for a file +// +// Author: Dan Waylonis + +#ifndef COMMON_MAC_FILE_ID_H__ +#define COMMON_MAC_FILE_ID_H__ + +#include +#include + +namespace google_breakpad { + +class FileID { + public: + FileID(const char *path); + ~FileID() {} + + // Load the identifier for the file path specified in the constructor into + // |identifier|. Return false if the identifier could not be created for the + // file. + // The current implementation will return the MD5 hash of the file's bytes. + bool FileIdentifier(unsigned char identifier[16]); + + // Treat the file as a mach-o file that will contain one or more archicture. + // Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or + // CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h. + // If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is + // CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|. + // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| + // is not present in the file. + // Return the unique identifier in |identifier|. + // The current implementation will look for the (in order of priority): + // LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|. + bool MachoIdentifier(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); + + // Convert the |identifier| data to a NULL terminated string. The string will + // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE). + // The |buffer| should be at least 37 bytes long to receive all of the data + // and termination. Shorter buffers will contain truncated data. + static void ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length); + + private: + // Storage for the path specified + char path_[PATH_MAX]; +}; + +} // namespace google_breakpad + +#endif // COMMON_MAC_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc new file mode 100644 index 0000000000..245be82659 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2014, 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 +#include +#include + +namespace google_breakpad { + +void LaunchReporter(const char *reporter_executable_path, + const char *config_file_path) { + const char* argv[] = { reporter_executable_path, config_file_path, NULL }; + + // Launch the reporter + pid_t pid = fork(); + + if (pid == -1) { + perror("fork"); + fprintf(stderr, "Failed to fork reporter process\n"); + return; + } + + // If we're in the child, load in our new executable and run. + // The parent will not wait for the child to complete. + if (pid == 0) { + execv(argv[0], (char* const*)argv); + perror("exec"); + fprintf(stderr, + "Failed to launch reporter process from path %s\n", + reporter_executable_path); + unlink(config_file_path); // launch failed - get rid of config file + _exit(1); + } + + // Wait until the Reporter child process exits. + // + + // We'll use a timeout of one minute. + int timeout_count = 60; // 60 seconds + + while (timeout_count-- > 0) { + int status; + pid_t result = waitpid(pid, &status, WNOHANG); + + if (result == 0) { + // The child has not yet finished. + sleep(1); + } else if (result == -1) { + // error occurred. + break; + } else { + // child has finished + break; + } + } +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h new file mode 100644 index 0000000000..4531123c2d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h @@ -0,0 +1,43 @@ +// Copyright (c) 2014, 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 COMMON_MAC_LAUNCH_REPORTER_H__ +#define COMMON_MAC_LAUNCH_REPORTER_H__ + +namespace google_breakpad { + +// Launch the crash dump sender app. +// |reporter_executable_path| is the path to the sender executable. +// |config_file_path| is the path to the config file. +void LaunchReporter(const char *reporter_executable_path, + const char *config_file_path); + +} // namespace google_breakpad + +#endif // COMMON_MAC_LAUNCH_REPORTER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc new file mode 100644 index 0000000000..c396ad888d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc @@ -0,0 +1,369 @@ +// 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. + +// macho_id.cc: Functions to gather identifying information from a macho file +// +// See macho_id.h for documentation +// +// Author: Dan Waylonis + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/mac/macho_id.h" +#include "common/mac/macho_walker.h" +#include "common/mac/macho_utilities.h" + +namespace MacFileUtilities { + +using google_breakpad::MD5Init; +using google_breakpad::MD5Update; +using google_breakpad::MD5Final; + +MachoID::MachoID(const char *path) + : memory_(0), + memory_size_(0), + crc_(0), + md5_context_(), + update_function_(NULL) { + snprintf(path_, sizeof(path_), "%s", path); +} + +MachoID::MachoID(const char *path, void *memory, size_t size) + : memory_(memory), + memory_size_(size), + crc_(0), + md5_context_(), + update_function_(NULL) { + snprintf(path_, sizeof(path_), "%s", path); +} + +MachoID::~MachoID() { +} + +// The CRC info is from http://en.wikipedia.org/wiki/Adler-32 +// With optimizations from http://www.zlib.net/ + +// The largest prime smaller than 65536 +#define MOD_ADLER 65521 +// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1 +#define MAX_BLOCK 5552 + +void MachoID::UpdateCRC(unsigned char *bytes, size_t size) { +// Unrolled loops for summing +#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + // Split up the crc + uint32_t sum1 = crc_ & 0xFFFF; + uint32_t sum2 = (crc_ >> 16) & 0xFFFF; + + // Do large blocks + while (size >= MAX_BLOCK) { + size -= MAX_BLOCK; + int block_count = MAX_BLOCK / 16; + do { + DO16(bytes); + bytes += 16; + } while (--block_count); + sum1 %= MOD_ADLER; + sum2 %= MOD_ADLER; + } + + // Do remaining bytes + if (size) { + while (size >= 16) { + size -= 16; + DO16(bytes); + bytes += 16; + } + while (size--) { + sum1 += *bytes++; + sum2 += sum1; + } + sum1 %= MOD_ADLER; + sum2 %= MOD_ADLER; + crc_ = (sum2 << 16) | sum1; + } +} + +void MachoID::UpdateMD5(unsigned char *bytes, size_t size) { + MD5Update(&md5_context_, bytes, static_cast(size)); +} + +void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { + if (!update_function_ || !size) + return; + + // Read up to 4k bytes at a time + unsigned char buffer[4096]; + size_t buffer_size; + off_t file_offset = offset; + while (size > 0) { + if (size > sizeof(buffer)) { + buffer_size = sizeof(buffer); + size -= buffer_size; + } else { + buffer_size = size; + size = 0; + } + + if (!walker->ReadBytes(buffer, buffer_size, file_offset)) + return; + + (this->*update_function_)(buffer, buffer_size); + file_offset += buffer_size; + } +} + +bool MachoID::UUIDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char bytes[16]) { + struct breakpad_uuid_command uuid_cmd; + uuid_cmd.cmd = 0; + if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd)) + return false; + + // If we found the command, we'll have initialized the uuid_command + // structure + if (uuid_cmd.cmd == LC_UUID) { + memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid)); + return true; + } + + return false; +} + +bool MachoID::IDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]) { + struct dylib_command dylib_cmd; + dylib_cmd.cmd = 0; + if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd)) + return false; + + // If we found the command, we'll have initialized the dylib_command + // structure + if (dylib_cmd.cmd == LC_ID_DYLIB) { + // Take the hashed filename, version, and compatability version bytes + // to form the first 12 bytes, pad the rest with zeros + + // create a crude hash of the filename to generate the first 4 bytes + identifier[0] = 0; + identifier[1] = 0; + identifier[2] = 0; + identifier[3] = 0; + + for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) { + identifier[j%4] += path_[i]; + } + + identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF; + identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF; + identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF; + identifier[7] = dylib_cmd.dylib.current_version & 0xFF; + identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF; + identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF; + identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF; + identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF; + identifier[12] = (cpu_type >> 24) & 0xFF; + identifier[13] = (cpu_type >> 16) & 0xFF; + identifier[14] = (cpu_type >> 8) & 0xFF; + identifier[15] = cpu_type & 0xFF; + + return true; + } + + return false; +} + +uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + update_function_ = &MachoID::UpdateCRC; + crc_ = 0; + + if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) + return 0; + + return crc_; +} + +bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) { + update_function_ = &MachoID::UpdateMD5; + + MD5Init(&md5_context_); + + if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) + return false; + + MD5Final(identifier, &md5_context_); + return true; +} + +bool MachoID::WalkHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + MachoWalker::LoadCommandCallback callback, + void *context) { + if (memory_) { + MachoWalker walker(memory_, memory_size_, callback, context); + return walker.WalkHeader(cpu_type, cpu_subtype); + } else { + MachoWalker walker(path_, callback, context); + return walker.WalkHeader(cpu_type, cpu_subtype); + } +} + +// static +bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context) { + MachoID *macho_id = (MachoID *)context; + + if (cmd->cmd == LC_SEGMENT) { + struct segment_command seg; + + if (!walker->ReadBytes(&seg, sizeof(seg), offset)) + return false; + + if (swap) + breakpad_swap_segment_command(&seg); + + struct mach_header_64 header; + off_t header_offset; + + if (!walker->CurrentHeader(&header, &header_offset)) + return false; + + // Process segments that have sections: + // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) + offset += sizeof(struct segment_command); + struct section sec; + for (unsigned long i = 0; i < seg.nsects; ++i) { + if (!walker->ReadBytes(&sec, sizeof(sec), offset)) + return false; + + if (swap) + breakpad_swap_section(&sec, 1); + + // sections of type S_ZEROFILL are "virtual" and contain no data + // in the file itself + if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0) + macho_id->Update(walker, header_offset + sec.offset, sec.size); + + offset += sizeof(struct section); + } + } else if (cmd->cmd == LC_SEGMENT_64) { + struct segment_command_64 seg64; + + if (!walker->ReadBytes(&seg64, sizeof(seg64), offset)) + return false; + + if (swap) + breakpad_swap_segment_command_64(&seg64); + + struct mach_header_64 header; + off_t header_offset; + + if (!walker->CurrentHeader(&header, &header_offset)) + return false; + + // Process segments that have sections: + // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) + offset += sizeof(struct segment_command_64); + struct section_64 sec64; + for (unsigned long i = 0; i < seg64.nsects; ++i) { + if (!walker->ReadBytes(&sec64, sizeof(sec64), offset)) + return false; + + if (swap) + breakpad_swap_section_64(&sec64, 1); + + // sections of type S_ZEROFILL are "virtual" and contain no data + // in the file itself + if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0) + macho_id->Update(walker, + header_offset + sec64.offset, + (size_t)sec64.size); + + offset += sizeof(struct section_64); + } + } + + // Continue processing + return true; +} + +// static +bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context) { + if (cmd->cmd == LC_UUID) { + struct breakpad_uuid_command *uuid_cmd = + (struct breakpad_uuid_command *)context; + + if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command), + offset)) + return false; + + if (swap) + breakpad_swap_uuid_command(uuid_cmd); + + return false; + } + + // Continue processing + return true; +} + +// static +bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context) { + if (cmd->cmd == LC_ID_DYLIB) { + struct dylib_command *dylib_cmd = (struct dylib_command *)context; + + if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset)) + return false; + + if (swap) + breakpad_swap_dylib_command(dylib_cmd); + + return false; + } + + // Continue processing + return true; +} + +} // namespace MacFileUtilities diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h new file mode 100644 index 0000000000..1037549124 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h @@ -0,0 +1,131 @@ +// 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. + +// macho_id.h: Functions to gather identifying information from a macho file +// +// Author: Dan Waylonis + +#ifndef COMMON_MAC_MACHO_ID_H__ +#define COMMON_MAC_MACHO_ID_H__ + +#include +#include +#include + +#include "common/mac/macho_walker.h" +#include "common/md5.h" + +namespace MacFileUtilities { + +class MachoID { + public: + MachoID(const char *path); + MachoID(const char *path, void *memory, size_t size); + ~MachoID(); + + // For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID + // command. + // Return false if there isn't a LC_UUID command. + bool UUIDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); + + // For the given |cpu_type| and |cpu_subtype|, return a UUID from the + // LC_ID_DYLIB command. + // Return false if there isn't a LC_ID_DYLIB command. + bool IDCommand(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); + + // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the + // mach-o data segment(s). + // Return 0 on error (e.g., if the file is not a mach-o file) + uint32_t Adler32(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype); + + // For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o + // data segment(s). + // Return true on success, false otherwise + bool MD5(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + unsigned char identifier[16]); + + private: + // Signature of class member function to be called with data read from file + typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size); + + // Update the CRC value by examining |size| |bytes| and applying the algorithm + // to each byte. + void UpdateCRC(unsigned char *bytes, size_t size); + + // Update the MD5 value by examining |size| |bytes| and applying the algorithm + // to each byte. + void UpdateMD5(unsigned char *bytes, size_t size); + + // Bottleneck for update routines + void Update(MachoWalker *walker, off_t offset, size_t size); + + // Factory for the MachoWalker + bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, + MachoWalker::LoadCommandCallback callback, void *context); + + // The callback from the MachoWalker for CRC and MD5 + static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context); + + // The callback from the MachoWalker for LC_UUID + static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context); + + // The callback from the MachoWalker for LC_ID_DYLIB + static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, + bool swap, void *context); + + // File path + char path_[PATH_MAX]; + + // Memory region to read from + void *memory_; + + // Size of the memory region + size_t memory_size_; + + // The current crc value + uint32_t crc_; + + // The MD5 context + google_breakpad::MD5Context md5_context_; + + // The current update to call from the Update callback + UpdateFunction update_function_; +}; + +} // namespace MacFileUtilities + +#endif // COMMON_MAC_MACHO_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc new file mode 100644 index 0000000000..91e1fdd2b2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc @@ -0,0 +1,558 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and +// google_breakpad::Mach_O::Reader. See macho_reader.h for details. + +#include "common/mac/macho_reader.h" + +#include +#include +#include + +#include + +// Unfortunately, CPU_TYPE_ARM is not define for 10.4. +#if !defined(CPU_TYPE_ARM) +#define CPU_TYPE_ARM 12 +#endif + +#if !defined(CPU_TYPE_ARM_64) +#define CPU_TYPE_ARM_64 16777228 +#endif + +namespace google_breakpad { +namespace mach_o { + +// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its +// arguments, so you can't place expressions that do necessary work in +// the argument of an assert. Nor can you assign the result of the +// expression to a variable and assert that the variable's value is +// true: you'll get unused variable warnings when NDEBUG is #defined. +// +// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that +// the result is true if NDEBUG is not #defined. +#if defined(NDEBUG) +#define ASSERT_ALWAYS_EVAL(x) (x) +#else +#define ASSERT_ALWAYS_EVAL(x) assert(x) +#endif + +void FatReader::Reporter::BadHeader() { + fprintf(stderr, "%s: file is neither a fat binary file" + " nor a Mach-O object file\n", filename_.c_str()); +} + +void FatReader::Reporter::TooShort() { + fprintf(stderr, "%s: file too short for the data it claims to contain\n", + filename_.c_str()); +} + +void FatReader::Reporter::MisplacedObjectFile() { + fprintf(stderr, "%s: file too short for the object files it claims" + " to contain\n", filename_.c_str()); +} + +bool FatReader::Read(const uint8_t *buffer, size_t size) { + buffer_.start = buffer; + buffer_.end = buffer + size; + ByteCursor cursor(&buffer_); + + // Fat binaries always use big-endian, so read the magic number in + // that endianness. To recognize Mach-O magic numbers, which can use + // either endianness, check for both the proper and reversed forms + // of the magic numbers. + cursor.set_big_endian(true); + if (cursor >> magic_) { + if (magic_ == FAT_MAGIC) { + // How many object files does this fat binary contain? + uint32_t object_files_count; + if (!(cursor >> object_files_count)) { // nfat_arch + reporter_->TooShort(); + return false; + } + + // Read the list of object files. + object_files_.resize(object_files_count); + for (size_t i = 0; i < object_files_count; i++) { + struct fat_arch objfile; + + // Read this object file entry, byte-swapping as appropriate. + cursor >> objfile.cputype + >> objfile.cpusubtype + >> objfile.offset + >> objfile.size + >> objfile.align; + + SuperFatArch super_fat_arch(objfile); + object_files_[i] = super_fat_arch; + + if (!cursor) { + reporter_->TooShort(); + return false; + } + // Does the file actually have the bytes this entry refers to? + size_t fat_size = buffer_.Size(); + if (objfile.offset > fat_size || + objfile.size > fat_size - objfile.offset) { + reporter_->MisplacedObjectFile(); + return false; + } + } + + return true; + } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 || + magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) { + // If this is a little-endian Mach-O file, fix the cursor's endianness. + if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) + cursor.set_big_endian(false); + // Record the entire file as a single entry in the object file list. + object_files_.resize(1); + + // Get the cpu type and subtype from the Mach-O header. + if (!(cursor >> object_files_[0].cputype + >> object_files_[0].cpusubtype)) { + reporter_->TooShort(); + return false; + } + + object_files_[0].offset = 0; + object_files_[0].size = static_cast(buffer_.Size()); + // This alignment is correct for 32 and 64-bit x86 and ppc. + // See get_align in the lipo source for other architectures: + // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c + object_files_[0].align = 12; // 2^12 == 4096 + return true; + } + } + reporter_->BadHeader(); + return false; +} + +void Reader::Reporter::BadHeader() { + fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str()); +} + +void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype) { + fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected" + " type %d, subtype %d\n", + filename_.c_str(), cpu_type, cpu_subtype, + expected_cpu_type, expected_cpu_subtype); +} + +void Reader::Reporter::HeaderTruncated() { + fprintf(stderr, "%s: file does not contain a complete Mach-O header\n", + filename_.c_str()); +} + +void Reader::Reporter::LoadCommandRegionTruncated() { + fprintf(stderr, "%s: file too short to hold load command region" + " given in Mach-O header\n", filename_.c_str()); +} + +void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i, + LoadCommandType type) { + fprintf(stderr, "%s: file's header claims there are %zu" + " load commands, but load command #%zu", + filename_.c_str(), claimed, i); + if (type) fprintf(stderr, ", of type %d,", type); + fprintf(stderr, " extends beyond the end of the load command region\n"); +} + +void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) { + fprintf(stderr, "%s: the contents of load command #%zu, of type %d," + " extend beyond the size given in the load command's header\n", + filename_.c_str(), i, type); +} + +void Reader::Reporter::SectionsMissing(const string &name) { + fprintf(stderr, "%s: the load command for segment '%s'" + " is too short to hold the section headers it claims to have\n", + filename_.c_str(), name.c_str()); +} + +void Reader::Reporter::MisplacedSegmentData(const string &name) { + fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond" + " the end of the file\n", filename_.c_str(), name.c_str()); +} + +void Reader::Reporter::MisplacedSectionData(const string §ion, + const string &segment) { + fprintf(stderr, "%s: the section '%s' in segment '%s'" + " claims its contents lie outside the segment's contents\n", + filename_.c_str(), section.c_str(), segment.c_str()); +} + +void Reader::Reporter::MisplacedSymbolTable() { + fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol" + " table's contents are located beyond the end of the file\n", + filename_.c_str()); +} + +void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) { + fprintf(stderr, "%s: CPU type %d is not supported\n", + filename_.c_str(), cpu_type); +} + +bool Reader::Read(const uint8_t *buffer, + size_t size, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype) { + assert(!buffer_.start); + buffer_.start = buffer; + buffer_.end = buffer + size; + ByteCursor cursor(&buffer_, true); + uint32_t magic; + if (!(cursor >> magic)) { + reporter_->HeaderTruncated(); + return false; + } + + if (expected_cpu_type != CPU_TYPE_ANY) { + uint32_t expected_magic; + // validate that magic matches the expected cpu type + switch (expected_cpu_type) { + case CPU_TYPE_ARM: + case CPU_TYPE_I386: + expected_magic = MH_CIGAM; + break; + case CPU_TYPE_POWERPC: + expected_magic = MH_MAGIC; + break; + case CPU_TYPE_ARM_64: + case CPU_TYPE_X86_64: + expected_magic = MH_CIGAM_64; + break; + case CPU_TYPE_POWERPC64: + expected_magic = MH_MAGIC_64; + break; + default: + reporter_->UnsupportedCPUType(expected_cpu_type); + return false; + } + + if (expected_magic != magic) { + reporter_->BadHeader(); + return false; + } + } + + // Since the byte cursor is in big-endian mode, a reversed magic number + // always indicates a little-endian file, regardless of our own endianness. + switch (magic) { + case MH_MAGIC: big_endian_ = true; bits_64_ = false; break; + case MH_CIGAM: big_endian_ = false; bits_64_ = false; break; + case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break; + case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break; + default: + reporter_->BadHeader(); + return false; + } + cursor.set_big_endian(big_endian_); + uint32_t commands_size, reserved; + cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_ + >> commands_size >> flags_; + if (bits_64_) + cursor >> reserved; + if (!cursor) { + reporter_->HeaderTruncated(); + return false; + } + + if (expected_cpu_type != CPU_TYPE_ANY && + (expected_cpu_type != cpu_type_ || + expected_cpu_subtype != cpu_subtype_)) { + reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_, + expected_cpu_type, expected_cpu_subtype); + return false; + } + + cursor + .PointTo(&load_commands_.start, commands_size) + .PointTo(&load_commands_.end, 0); + if (!cursor) { + reporter_->LoadCommandRegionTruncated(); + return false; + } + + return true; +} + +bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { + ByteCursor list_cursor(&load_commands_, big_endian_); + + for (size_t index = 0; index < load_command_count_; ++index) { + // command refers to this load command alone, so that cursor will + // refuse to read past the load command's end. But since we haven't + // read the size yet, let command initially refer to the entire + // remainder of the load command series. + ByteBuffer command(list_cursor.here(), list_cursor.Available()); + ByteCursor cursor(&command, big_endian_); + + // Read the command type and size --- fields common to all commands. + uint32_t type, size; + if (!(cursor >> type)) { + reporter_->LoadCommandsOverrun(load_command_count_, index, 0); + return false; + } + if (!(cursor >> size) || size > command.Size()) { + reporter_->LoadCommandsOverrun(load_command_count_, index, type); + return false; + } + + // Now that we've read the length, restrict command's range to this + // load command only. + command.end = command.start + size; + + switch (type) { + case LC_SEGMENT: + case LC_SEGMENT_64: { + Segment segment; + segment.bits_64 = (type == LC_SEGMENT_64); + size_t word_size = segment.bits_64 ? 8 : 4; + cursor.CString(&segment.name, 16); + cursor + .Read(word_size, false, &segment.vmaddr) + .Read(word_size, false, &segment.vmsize) + .Read(word_size, false, &segment.fileoff) + .Read(word_size, false, &segment.filesize); + cursor >> segment.maxprot + >> segment.initprot + >> segment.nsects + >> segment.flags; + if (!cursor) { + reporter_->LoadCommandTooShort(index, type); + return false; + } + if (segment.fileoff > buffer_.Size() || + segment.filesize > buffer_.Size() - segment.fileoff) { + reporter_->MisplacedSegmentData(segment.name); + return false; + } + // Mach-O files in .dSYM bundles have the contents of the loaded + // segments removed, and their file offsets and file sizes zeroed + // out. To help us handle this special case properly, give such + // segments' contents NULL starting and ending pointers. + if (segment.fileoff == 0 && segment.filesize == 0) { + segment.contents.start = segment.contents.end = NULL; + } else { + segment.contents.start = buffer_.start + segment.fileoff; + segment.contents.end = segment.contents.start + segment.filesize; + } + // The section list occupies the remainder of this load command's space. + segment.section_list.start = cursor.here(); + segment.section_list.end = command.end; + + if (!handler->SegmentCommand(segment)) + return false; + break; + } + + case LC_SYMTAB: { + uint32_t symoff, nsyms, stroff, strsize; + cursor >> symoff >> nsyms >> stroff >> strsize; + if (!cursor) { + reporter_->LoadCommandTooShort(index, type); + return false; + } + // How big are the entries in the symbol table? + // sizeof(struct nlist_64) : sizeof(struct nlist), + // but be paranoid about alignment vs. target architecture. + size_t symbol_size = bits_64_ ? 16 : 12; + // How big is the entire symbol array? + size_t symbols_size = nsyms * symbol_size; + if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff || + stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) { + reporter_->MisplacedSymbolTable(); + return false; + } + ByteBuffer entries(buffer_.start + symoff, symbols_size); + ByteBuffer names(buffer_.start + stroff, strsize); + if (!handler->SymtabCommand(entries, names)) + return false; + break; + } + + default: { + if (!handler->UnknownCommand(type, command)) + return false; + break; + } + } + + list_cursor.set_here(command.end); + } + + return true; +} + +// A load command handler that looks for a segment of a given name. +class Reader::SegmentFinder : public LoadCommandHandler { + public: + // Create a load command handler that looks for a segment named NAME, + // and sets SEGMENT to describe it if found. + SegmentFinder(const string &name, Segment *segment) + : name_(name), segment_(segment), found_() { } + + // Return true if the traversal found the segment, false otherwise. + bool found() const { return found_; } + + bool SegmentCommand(const Segment &segment) { + if (segment.name == name_) { + *segment_ = segment; + found_ = true; + return false; + } + return true; + } + + private: + // The name of the segment our creator is looking for. + const string &name_; + + // Where we should store the segment if found. (WEAK) + Segment *segment_; + + // True if we found the segment. + bool found_; +}; + +bool Reader::FindSegment(const string &name, Segment *segment) const { + SegmentFinder finder(name, segment); + WalkLoadCommands(&finder); + return finder.found(); +} + +bool Reader::WalkSegmentSections(const Segment &segment, + SectionHandler *handler) const { + size_t word_size = segment.bits_64 ? 8 : 4; + ByteCursor cursor(&segment.section_list, big_endian_); + + for (size_t i = 0; i < segment.nsects; i++) { + Section section; + section.bits_64 = segment.bits_64; + uint64_t size, offset; + uint32_t dummy32; + cursor + .CString(§ion.section_name, 16) + .CString(§ion.segment_name, 16) + .Read(word_size, false, §ion.address) + .Read(word_size, false, &size) + .Read(sizeof(uint32_t), false, &offset) // clears high bits of |offset| + >> section.align + >> dummy32 + >> dummy32 + >> section.flags + >> dummy32 + >> dummy32; + if (section.bits_64) + cursor >> dummy32; + if (!cursor) { + reporter_->SectionsMissing(segment.name); + return false; + } + + // Even 64-bit Mach-O isn’t a true 64-bit format in that it doesn’t handle + // 64-bit file offsets gracefully. Segment load commands do contain 64-bit + // file offsets, but sections within do not. Because segments load + // contiguously, recompute each section’s file offset on the basis of its + // containing segment’s file offset and the difference between the section’s + // and segment’s load addresses. If truncation is detected, honor the + // recomputed offset. + if (segment.bits_64 && + segment.fileoff + segment.filesize > + std::numeric_limits::max()) { + const uint64_t section_offset_recomputed = + segment.fileoff + section.address - segment.vmaddr; + if (offset == static_cast(section_offset_recomputed)) { + offset = section_offset_recomputed; + } + } + + const uint32_t section_type = section.flags & SECTION_TYPE; + if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL || + section_type == S_GB_ZEROFILL) { + // Zero-fill sections have a size, but no contents. + section.contents.start = section.contents.end = NULL; + } else if (segment.contents.start == NULL && + segment.contents.end == NULL) { + // Mach-O files in .dSYM bundles have the contents of the loaded + // segments removed, and their file offsets and file sizes zeroed + // out. However, the sections within those segments still have + // non-zero sizes. There's no reason to call MisplacedSectionData in + // this case; the caller may just need the section's load + // address. But do set the contents' limits to NULL, for safety. + section.contents.start = section.contents.end = NULL; + } else { + if (offset < size_t(segment.contents.start - buffer_.start) || + offset > size_t(segment.contents.end - buffer_.start) || + size > size_t(segment.contents.end - buffer_.start - offset)) { + reporter_->MisplacedSectionData(section.section_name, + section.segment_name); + return false; + } + section.contents.start = buffer_.start + offset; + section.contents.end = section.contents.start + size; + } + if (!handler->HandleSection(section)) + return false; + } + return true; +} + +// A SectionHandler that builds a SectionMap for the sections within a +// given segment. +class Reader::SectionMapper: public SectionHandler { + public: + // Create a SectionHandler that populates MAP with an entry for + // each section it is given. + SectionMapper(SectionMap *map) : map_(map) { } + bool HandleSection(const Section §ion) { + (*map_)[section.section_name] = section; + return true; + } + private: + // The map under construction. (WEAK) + SectionMap *map_; +}; + +bool Reader::MapSegmentSections(const Segment &segment, + SectionMap *section_map) const { + section_map->clear(); + SectionMapper mapper(section_map); + return WalkSegmentSections(segment, &mapper); +} + +} // namespace mach_o +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h new file mode 100644 index 0000000000..145d17d1f2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h @@ -0,0 +1,464 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// macho_reader.h: A class for parsing Mach-O files. + +#ifndef BREAKPAD_COMMON_MAC_MACHO_READER_H_ +#define BREAKPAD_COMMON_MAC_MACHO_READER_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/byte_cursor.h" +#include "common/mac/super_fat_arch.h" + +namespace google_breakpad { +namespace mach_o { + +using std::map; +using std::string; +using std::vector; + +// The Mac headers don't specify particular types for these groups of +// constants, but defining them here provides some documentation +// value. We also give them the same width as the fields in which +// they appear, which makes them a bit easier to use with ByteCursors. +typedef uint32_t Magic; +typedef uint32_t FileType; +typedef uint32_t FileFlags; +typedef uint32_t LoadCommandType; +typedef uint32_t SegmentFlags; +typedef uint32_t SectionFlags; + +// A parser for fat binary files, used to store universal binaries. +// When applied to a (non-fat) Mach-O file, this behaves as if the +// file were a fat file containing a single object file. +class FatReader { + public: + + // A class for reporting errors found while parsing fat binary files. The + // default definitions of these methods print messages to stderr. + class Reporter { + public: + // Create a reporter that attributes problems to |filename|. + explicit Reporter(const string &filename) : filename_(filename) { } + + virtual ~Reporter() { } + + // The data does not begin with a fat binary or Mach-O magic number. + // This is a fatal error. + virtual void BadHeader(); + + // The Mach-O fat binary file ends abruptly, without enough space + // to contain an object file it claims is present. + virtual void MisplacedObjectFile(); + + // The file ends abruptly: either it is not large enough to hold a + // complete header, or the header implies that contents are present + // beyond the actual end of the file. + virtual void TooShort(); + + private: + // The filename to which the reader should attribute problems. + string filename_; + }; + + // Create a fat binary file reader that uses |reporter| to report problems. + explicit FatReader(Reporter *reporter) : reporter_(reporter) { } + + // Read the |size| bytes at |buffer| as a fat binary file. On success, + // return true; on failure, report the problem to reporter_ and return + // false. + // + // If the data is a plain Mach-O file, rather than a fat binary file, + // then the reader behaves as if it had found a fat binary file whose + // single object file is the Mach-O file. + bool Read(const uint8_t *buffer, size_t size); + + // Return an array of 'SuperFatArch' structures describing the + // object files present in this fat binary file. Set |size| to the + // number of elements in the array. + // + // Assuming Read returned true, the entries are validated: it is safe to + // assume that the offsets and sizes in each SuperFatArch refer to subranges + // of the bytes passed to Read. + // + // If there are no object files in this fat binary, then this + // function can return NULL. + // + // The array is owned by this FatReader instance; it will be freed when + // this FatReader is destroyed. + // + // This function returns a C-style array instead of a vector to make it + // possible to use the result with OS X functions like NXFindBestFatArch, + // so that the symbol dumper will behave consistently with other OS X + // utilities that work with fat binaries. + const SuperFatArch* object_files(size_t *count) const { + *count = object_files_.size(); + if (object_files_.size() > 0) + return &object_files_[0]; + return NULL; + } + + private: + // We use this to report problems parsing the file's contents. (WEAK) + Reporter *reporter_; + + // The contents of the fat binary or Mach-O file we're parsing. We do not + // own the storage it refers to. + ByteBuffer buffer_; + + // The magic number of this binary, in host byte order. + Magic magic_; + + // The list of object files in this binary. + // object_files_.size() == fat_header.nfat_arch + vector object_files_; +}; + +// A segment in a Mach-O file. All these fields have been byte-swapped as +// appropriate for use by the executing architecture. +struct Segment { + // The ByteBuffers below point into the bytes passed to the Reader that + // created this Segment. + + ByteBuffer section_list; // This segment's section list. + ByteBuffer contents; // This segment's contents. + + // This segment's name. + string name; + + // The address at which this segment should be loaded in memory. If + // bits_64 is false, only the bottom 32 bits of this value are valid. + uint64_t vmaddr; + + // The size of this segment when loaded into memory. This may be larger + // than contents.Size(), in which case the extra area will be + // initialized with zeros. If bits_64 is false, only the bottom 32 bits + // of this value are valid. + uint64_t vmsize; + + // The file offset and size of the segment in the Mach-O image. + uint64_t fileoff; + uint64_t filesize; + + // The maximum and initial VM protection of this segment's contents. + uint32_t maxprot; + uint32_t initprot; + + // The number of sections in section_list. + uint32_t nsects; + + // Flags describing this segment, from SegmentFlags. + uint32_t flags; + + // True if this is a 64-bit section; false if it is a 32-bit section. + bool bits_64; +}; + +// A section in a Mach-O file. All these fields have been byte-swapped as +// appropriate for use by the executing architecture. +struct Section { + // This section's contents. This points into the bytes passed to the + // Reader that created this Section. + ByteBuffer contents; + + // This section's name. + string section_name; // section[_64].sectname + // The name of the segment this section belongs to. + string segment_name; // section[_64].segname + + // The address at which this section's contents should be loaded in + // memory. If bits_64 is false, only the bottom 32 bits of this value + // are valid. + uint64_t address; + + // The contents of this section should be loaded into memory at an + // address which is a multiple of (two raised to this power). + uint32_t align; + + // Flags from SectionFlags describing the section's contents. + uint32_t flags; + + // We don't support reading relocations yet. + + // True if this is a 64-bit section; false if it is a 32-bit section. + bool bits_64; +}; + +// A map from section names to Sections. +typedef map SectionMap; + +// A reader for a Mach-O file. +// +// This does not handle fat binaries; see FatReader above. FatReader +// provides a friendly interface for parsing data that could be either a +// fat binary or a Mach-O file. +class Reader { + public: + + // A class for reporting errors found while parsing Mach-O files. The + // default definitions of these member functions print messages to + // stderr. + class Reporter { + public: + // Create a reporter that attributes problems to |filename|. + explicit Reporter(const string &filename) : filename_(filename) { } + virtual ~Reporter() { } + + // Reporter functions for fatal errors return void; the reader will + // definitely return an error to its caller after calling them + + // The data does not begin with a Mach-O magic number, or the magic + // number does not match the expected value for the cpu architecture. + // This is a fatal error. + virtual void BadHeader(); + + // The data contained in a Mach-O fat binary (|cpu_type|, |cpu_subtype|) + // does not match the expected CPU architecture + // (|expected_cpu_type|, |expected_cpu_subtype|). + virtual void CPUTypeMismatch(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype); + + // The file ends abruptly: either it is not large enough to hold a + // complete header, or the header implies that contents are present + // beyond the actual end of the file. + virtual void HeaderTruncated(); + + // The file's load command region, as given in the Mach-O header, is + // too large for the file. + virtual void LoadCommandRegionTruncated(); + + // The file's Mach-O header claims the file contains |claimed| load + // commands, but the I'th load command, of type |type|, extends beyond + // the end of the load command region, as given by the Mach-O header. + // If |type| is zero, the command's type was unreadable. + virtual void LoadCommandsOverrun(size_t claimed, size_t i, + LoadCommandType type); + + // The contents of the |i|'th load command, of type |type|, extend beyond + // the size given in the load command's header. + virtual void LoadCommandTooShort(size_t i, LoadCommandType type); + + // The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named + // |name| is too short to hold the sections that its header says it does. + // (This more specific than LoadCommandTooShort.) + virtual void SectionsMissing(const string &name); + + // The segment named |name| claims that its contents lie beyond the end + // of the file. + virtual void MisplacedSegmentData(const string &name); + + // The section named |section| in the segment named |segment| claims that + // its contents do not lie entirely within the segment. + virtual void MisplacedSectionData(const string §ion, + const string &segment); + + // The LC_SYMTAB command claims that symbol table contents are located + // beyond the end of the file. + virtual void MisplacedSymbolTable(); + + // An attempt was made to read a Mach-O file of the unsupported + // CPU architecture |cpu_type|. + virtual void UnsupportedCPUType(cpu_type_t cpu_type); + + private: + string filename_; + }; + + // A handler for sections parsed from a segment. The WalkSegmentSections + // member function accepts an instance of this class, and applies it to + // each section defined in a given segment. + class SectionHandler { + public: + virtual ~SectionHandler() { } + + // Called to report that the segment's section list contains |section|. + // This should return true if the iteration should continue, or false + // if it should stop. + virtual bool HandleSection(const Section §ion) = 0; + }; + + // A handler for the load commands in a Mach-O file. + class LoadCommandHandler { + public: + LoadCommandHandler() { } + virtual ~LoadCommandHandler() { } + + // When called from WalkLoadCommands, the following handler functions + // should return true if they wish to continue iterating over the load + // command list, or false if they wish to stop iterating. + // + // When called from LoadCommandIterator::Handle or Reader::Handle, + // these functions' return values are simply passed through to Handle's + // caller. + // + // The definitions provided by this base class simply return true; the + // default is to silently ignore sections whose member functions the + // subclass doesn't override. + + // COMMAND is load command we don't recognize. We provide only the + // command type and a ByteBuffer enclosing the command's data (If we + // cannot parse the command type or its size, we call + // reporter_->IncompleteLoadCommand instead.) + virtual bool UnknownCommand(LoadCommandType type, + const ByteBuffer &contents) { + return true; + } + + // The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment + // with the properties given in |segment|. + virtual bool SegmentCommand(const Segment &segment) { + return true; + } + + // The load command is LC_SYMTAB. |entries| holds the array of nlist + // entries, and |names| holds the strings the entries refer to. + virtual bool SymtabCommand(const ByteBuffer &entries, + const ByteBuffer &names) { + return true; + } + + // Add handler functions for more load commands here as needed. + }; + + // Create a Mach-O file reader that reports problems to |reporter|. + explicit Reader(Reporter *reporter) + : reporter_(reporter) { } + + // Read the given data as a Mach-O file. The reader retains pointers + // into the data passed, so the data should live as long as the reader + // does. On success, return true; on failure, return false. + // + // At most one of these functions should be invoked once on each Reader + // instance. + bool Read(const uint8_t *buffer, + size_t size, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype); + bool Read(const ByteBuffer &buffer, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype) { + return Read(buffer.start, + buffer.Size(), + expected_cpu_type, + expected_cpu_subtype); + } + + // Return this file's characteristics, as found in the Mach-O header. + cpu_type_t cpu_type() const { return cpu_type_; } + cpu_subtype_t cpu_subtype() const { return cpu_subtype_; } + FileType file_type() const { return file_type_; } + FileFlags flags() const { return flags_; } + + // Return true if this is a 64-bit Mach-O file, false if it is a 32-bit + // Mach-O file. + bool bits_64() const { return bits_64_; } + + // Return true if this is a big-endian Mach-O file, false if it is + // little-endian. + bool big_endian() const { return big_endian_; } + + // Apply |handler| to each load command in this Mach-O file, stopping when + // a handler function returns false. If we encounter a malformed load + // command, report it via reporter_ and return false. Return true if all + // load commands were parseable and all handlers returned true. + bool WalkLoadCommands(LoadCommandHandler *handler) const; + + // Set |segment| to describe the segment named |name|, if present. If + // found, |segment|'s byte buffers refer to a subregion of the bytes + // passed to Read. If we find the section, return true; otherwise, + // return false. + bool FindSegment(const string &name, Segment *segment) const; + + // Apply |handler| to each section defined in |segment|. If |handler| returns + // false, stop iterating and return false. If all calls to |handler| return + // true and we reach the end of the section list, return true. + bool WalkSegmentSections(const Segment &segment, SectionHandler *handler) + const; + + // Clear |section_map| and then populate it with a map of the sections + // in |segment|, from section names to Section structures. + // Each Section's contents refer to bytes in |segment|'s contents. + // On success, return true; if a problem occurs, report it and return false. + bool MapSegmentSections(const Segment &segment, SectionMap *section_map) + const; + + private: + // Used internally. + class SegmentFinder; + class SectionMapper; + + // We use this to report problems parsing the file's contents. (WEAK) + Reporter *reporter_; + + // The contents of the Mach-O file we're parsing. We do not own the + // storage it refers to. + ByteBuffer buffer_; + + // True if this file is big-endian. + bool big_endian_; + + // True if this file is a 64-bit Mach-O file. + bool bits_64_; + + // This file's cpu type and subtype. + cpu_type_t cpu_type_; // mach_header[_64].cputype + cpu_subtype_t cpu_subtype_; // mach_header[_64].cpusubtype + + // This file's type. + FileType file_type_; // mach_header[_64].filetype + + // The region of buffer_ occupied by load commands. + ByteBuffer load_commands_; + + // The number of load commands in load_commands_. + uint32_t load_command_count_; // mach_header[_64].ncmds + + // This file's header flags. + FileFlags flags_; +}; + +} // namespace mach_o +} // namespace google_breakpad + +#endif // BREAKPAD_COMMON_MAC_MACHO_READER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc new file mode 100644 index 0000000000..d8459d8cd4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc @@ -0,0 +1,1902 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader +// and google_breakpad::Mach_O::Reader. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/mac/macho_reader.h" +#include "common/test_assembler.h" + +namespace mach_o = google_breakpad::mach_o; +namespace test_assembler = google_breakpad::test_assembler; + +using mach_o::FatReader; +using mach_o::FileFlags; +using mach_o::FileType; +using mach_o::LoadCommandType; +using mach_o::Reader; +using mach_o::Section; +using mach_o::SectionMap; +using mach_o::Segment; +using test_assembler::Endianness; +using test_assembler::Label; +using test_assembler::kBigEndian; +using test_assembler::kLittleEndian; +using test_assembler::kUnsetEndian; +using google_breakpad::ByteBuffer; +using std::map; +using std::string; +using std::vector; +using testing::AllOf; +using testing::DoAll; +using testing::Field; +using testing::InSequence; +using testing::Matcher; +using testing::Return; +using testing::SaveArg; +using testing::Test; +using testing::_; + + +// Mock classes for the reader's various reporters and handlers. + +class MockFatReaderReporter: public FatReader::Reporter { + public: + MockFatReaderReporter(const string &filename) + : FatReader::Reporter(filename) { } + MOCK_METHOD0(BadHeader, void()); + MOCK_METHOD0(MisplacedObjectFile, void()); + MOCK_METHOD0(TooShort, void()); +}; + +class MockReaderReporter: public Reader::Reporter { + public: + MockReaderReporter(const string &filename) : Reader::Reporter(filename) { } + MOCK_METHOD0(BadHeader, void()); + MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype)); + MOCK_METHOD0(HeaderTruncated, void()); + MOCK_METHOD0(LoadCommandRegionTruncated, void()); + MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i, + LoadCommandType type)); + MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type)); + MOCK_METHOD1(SectionsMissing, void(const string &name)); + MOCK_METHOD1(MisplacedSegmentData, void(const string &name)); + MOCK_METHOD2(MisplacedSectionData, void(const string §ion, + const string &segment)); + MOCK_METHOD0(MisplacedSymbolTable, void()); + MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type)); +}; + +class MockLoadCommandHandler: public Reader::LoadCommandHandler { + public: + MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &)); + MOCK_METHOD1(SegmentCommand, bool(const Segment &)); + MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &)); +}; + +class MockSectionHandler: public Reader::SectionHandler { + public: + MOCK_METHOD1(HandleSection, bool(const Section §ion)); +}; + + +// Tests for mach_o::FatReader. + +// Since the effect of these functions is to write to stderr, the +// results of these tests must be inspected by hand. +TEST(FatReaderReporter, BadHeader) { + FatReader::Reporter reporter("filename"); + reporter.BadHeader(); +} + +TEST(FatReaderReporter, MisplacedObjectFile) { + FatReader::Reporter reporter("filename"); + reporter.MisplacedObjectFile(); +} + +TEST(FatReaderReporter, TooShort) { + FatReader::Reporter reporter("filename"); + reporter.TooShort(); +} + +TEST(MachOReaderReporter, BadHeader) { + Reader::Reporter reporter("filename"); + reporter.BadHeader(); +} + +TEST(MachOReaderReporter, CPUTypeMismatch) { + Reader::Reporter reporter("filename"); + reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, + CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); +} + +TEST(MachOReaderReporter, HeaderTruncated) { + Reader::Reporter reporter("filename"); + reporter.HeaderTruncated(); +} + +TEST(MachOReaderReporter, LoadCommandRegionTruncated) { + Reader::Reporter reporter("filename"); + reporter.LoadCommandRegionTruncated(); +} + +TEST(MachOReaderReporter, LoadCommandsOverrun) { + Reader::Reporter reporter("filename"); + reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB); + reporter.LoadCommandsOverrun(10, 9, 0); +} + +TEST(MachOReaderReporter, LoadCommandTooShort) { + Reader::Reporter reporter("filename"); + reporter.LoadCommandTooShort(11, LC_SYMTAB); +} + +TEST(MachOReaderReporter, SectionsMissing) { + Reader::Reporter reporter("filename"); + reporter.SectionsMissing("segment name"); +} + +TEST(MachOReaderReporter, MisplacedSegmentData) { + Reader::Reporter reporter("filename"); + reporter.MisplacedSegmentData("segment name"); +} + +TEST(MachOReaderReporter, MisplacedSectionData) { + Reader::Reporter reporter("filename"); + reporter.MisplacedSectionData("section name", "segment name"); +} + +TEST(MachOReaderReporter, MisplacedSymbolTable) { + Reader::Reporter reporter("filename"); + reporter.MisplacedSymbolTable(); +} + +TEST(MachOReaderReporter, UnsupportedCPUType) { + Reader::Reporter reporter("filename"); + reporter.UnsupportedCPUType(CPU_TYPE_HPPA); +} + +struct FatReaderFixture { + FatReaderFixture() + : fat(kBigEndian), + reporter("reporter filename"), + reader(&reporter), object_files() { + EXPECT_CALL(reporter, BadHeader()).Times(0); + EXPECT_CALL(reporter, TooShort()).Times(0); + + // here, start, and Mark are file offsets in 'fat'. + fat.start() = 0; + } + // Append a 'fat_arch' entry to 'fat', with the given field values. + void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype, + Label offset, Label size, uint32_t align) { + fat + .B32(type) + .B32(subtype) + .B32(offset) + .B32(size) + .B32(align); + } + // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and + // subtype have unrealistic values. + void AppendDummyArchEntries(int n) { + for (int i = 0; i < n; i++) + AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1); + } + void ReadFat(bool expect_parse_success = true) { + ASSERT_TRUE(fat.GetContents(&contents)); + fat_bytes = reinterpret_cast(contents.data()); + if (expect_parse_success) { + EXPECT_TRUE(reader.Read(fat_bytes, contents.size())); + size_t fat_files_count; + const SuperFatArch* fat_files = reader.object_files(&fat_files_count); + object_files.resize(fat_files_count); + for (size_t i = 0; i < fat_files_count; ++i) { + EXPECT_TRUE(fat_files[i].ConvertToFatArch(&object_files[i])); + } + } + else + EXPECT_FALSE(reader.Read(fat_bytes, contents.size())); + } + test_assembler::Section fat; + MockFatReaderReporter reporter; + FatReader reader; + string contents; + const uint8_t *fat_bytes; + vector object_files; +}; + +class FatReaderTest: public FatReaderFixture, public Test { }; + +TEST_F(FatReaderTest, BadMagic) { + EXPECT_CALL(reporter, BadHeader()).Times(1); + fat + .B32(0xcafed00d) // magic number (incorrect) + .B32(10); // number of architectures + AppendDummyArchEntries(10); + ReadFat(false); +} + +TEST_F(FatReaderTest, HeaderTooShort) { + EXPECT_CALL(reporter, TooShort()).Times(1); + fat + .B32(0xcafebabe); // magic number + ReadFat(false); +} + +TEST_F(FatReaderTest, ObjectListTooShort) { + EXPECT_CALL(reporter, TooShort()).Times(1); + fat + .B32(0xcafebabe) // magic number + .B32(10); // number of architectures + AppendDummyArchEntries(9); // nine dummy architecture entries... + fat // and a tenth, missing a byte at the end + .B32(0x3d46c8fc) // cpu type + .B32(0x8a7bfb01) // cpu subtype + .B32(0) // offset + .B32(0) // size + .Append(3, '*'); // one byte short of a four-byte alignment + ReadFat(false); +} + +TEST_F(FatReaderTest, DataTooShort) { + EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1); + Label arch_data; + fat + .B32(0xcafebabe) // magic number + .B32(1); // number of architectures + AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0); + fat + .Mark(&arch_data) // file data begins here + .Append(30, '*'); // only 30 bytes, not 40 as header claims + ReadFat(false); +} + +TEST_F(FatReaderTest, NoObjectFiles) { + fat + .B32(0xcafebabe) // magic number + .B32(0); // number of architectures + ReadFat(); + EXPECT_EQ(0U, object_files.size()); +} + +TEST_F(FatReaderTest, OneObjectFile) { + Label obj1_offset; + fat + .B32(0xcafebabe) // magic number + .B32(1); // number of architectures + // First object file list entry + AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2); + // First object file data + fat + .Mark(&obj1_offset) + .Append(0x42, '*'); // dummy contents + ReadFat(); + ASSERT_EQ(1U, object_files.size()); + EXPECT_EQ(0x5e3a6e91, object_files[0].cputype); + EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype); + EXPECT_EQ(obj1_offset.Value(), object_files[0].offset); + EXPECT_EQ(0x42U, object_files[0].size); + EXPECT_EQ(0x355b15b2U, object_files[0].align); +} + +TEST_F(FatReaderTest, ThreeObjectFiles) { + Label obj1, obj2, obj3; + fat + .B32(0xcafebabe) // magic number + .B32(3); // number of architectures + // Three object file list entries. + AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8); + AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd); + AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7); + fat + // First object file data + .Mark(&obj1) + .Append(0xfb4, '*') // dummy contents + // Second object file data + .Mark(&obj2) + .Append(0xc31, '%') // dummy contents + // Third object file data + .Mark(&obj3) + .Append(0x4b3, '^'); // dummy contents + + ReadFat(); + + ASSERT_EQ(3U, object_files.size()); + + // First object file. + EXPECT_EQ(0x0cb92c30, object_files[0].cputype); + EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype); + EXPECT_EQ(obj1.Value(), object_files[0].offset); + EXPECT_EQ(0xfb4U, object_files[0].size); + EXPECT_EQ(0x2615dbe8U, object_files[0].align); + + // Second object file. + EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype); + EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype); + EXPECT_EQ(obj2.Value(), object_files[1].offset); + EXPECT_EQ(0xc31U, object_files[1].size); + EXPECT_EQ(0x83af6ffdU, object_files[1].align); + + // Third object file. + EXPECT_EQ(0x3717276d, object_files[2].cputype); + EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype); + EXPECT_EQ(obj3.Value(), object_files[2].offset); + EXPECT_EQ(0x4b3U, object_files[2].size); + EXPECT_EQ(0x035267d7U, object_files[2].align); +} + +TEST_F(FatReaderTest, BigEndianMachO32) { + fat.set_endianness(kBigEndian); + fat + .D32(0xfeedface) // Mach-O file magic number + .D32(0x1a9d0518) // cpu type + .D32(0x1b779357) // cpu subtype + .D32(0x009df67e) // file type + .D32(0) // no load commands + .D32(0) // the load commands occupy no bytes + .D32(0x21987a99); // flags + + ReadFat(); + + // FatReader should treat a Mach-O file as if it were a fat binary file + // containing one object file --- the whole thing. + ASSERT_EQ(1U, object_files.size()); + EXPECT_EQ(0x1a9d0518, object_files[0].cputype); + EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); + EXPECT_EQ(0U, object_files[0].offset); + EXPECT_EQ(contents.size(), object_files[0].size); +} + +TEST_F(FatReaderTest, BigEndianMachO64) { + fat.set_endianness(kBigEndian); + fat + .D32(0xfeedfacf) // Mach-O 64-bit file magic number + .D32(0x5aff8487) // cpu type + .D32(0x4c6a57f7) // cpu subtype + .D32(0x4392d2c8) // file type + .D32(0) // no load commands + .D32(0) // the load commands occupy no bytes + .D32(0x1b033eea); // flags + + ReadFat(); + + // FatReader should treat a Mach-O file as if it were a fat binary file + // containing one object file --- the whole thing. + ASSERT_EQ(1U, object_files.size()); + EXPECT_EQ(0x5aff8487, object_files[0].cputype); + EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); + EXPECT_EQ(0U, object_files[0].offset); + EXPECT_EQ(contents.size(), object_files[0].size); +} + +TEST_F(FatReaderTest, LittleEndianMachO32) { + fat.set_endianness(kLittleEndian); + fat + .D32(0xfeedface) // Mach-O file magic number + .D32(0x1a9d0518) // cpu type + .D32(0x1b779357) // cpu subtype + .D32(0x009df67e) // file type + .D32(0) // no load commands + .D32(0) // the load commands occupy no bytes + .D32(0x21987a99); // flags + + ReadFat(); + + // FatReader should treat a Mach-O file as if it were a fat binary file + // containing one object file --- the whole thing. + ASSERT_EQ(1U, object_files.size()); + EXPECT_EQ(0x1a9d0518, object_files[0].cputype); + EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); + EXPECT_EQ(0U, object_files[0].offset); + EXPECT_EQ(contents.size(), object_files[0].size); +} + +TEST_F(FatReaderTest, LittleEndianMachO64) { + fat.set_endianness(kLittleEndian); + fat + .D32(0xfeedfacf) // Mach-O 64-bit file magic number + .D32(0x5aff8487) // cpu type + .D32(0x4c6a57f7) // cpu subtype + .D32(0x4392d2c8) // file type + .D32(0) // no load commands + .D32(0) // the load commands occupy no bytes + .D32(0x1b033eea); // flags + + ReadFat(); + + // FatReader should treat a Mach-O file as if it were a fat binary file + // containing one object file --- the whole thing. + ASSERT_EQ(1U, object_files.size()); + EXPECT_EQ(0x5aff8487, object_files[0].cputype); + EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); + EXPECT_EQ(0U, object_files[0].offset); + EXPECT_EQ(contents.size(), object_files[0].size); +} + +TEST_F(FatReaderTest, IncompleteMach) { + fat.set_endianness(kLittleEndian); + fat + .D32(0xfeedfacf) // Mach-O 64-bit file magic number + .D32(0x5aff8487); // cpu type + // Truncated! + + EXPECT_CALL(reporter, TooShort()).WillOnce(Return()); + + ReadFat(false); +} + + +// General mach_o::Reader tests. + +// Dynamically scoped configuration data. +class WithConfiguration { + public: + // Establish the given parameters as the default for SizedSections + // created within the dynamic scope of this instance. + WithConfiguration(Endianness endianness, size_t word_size) + : endianness_(endianness), word_size_(word_size), saved_(current_) { + current_ = this; + } + ~WithConfiguration() { current_ = saved_; } + static Endianness endianness() { + assert(current_); + return current_->endianness_; + } + static size_t word_size() { + assert(current_); + return current_->word_size_; + } + + private: + // The innermost WithConfiguration in whose dynamic scope we are + // currently executing. + static WithConfiguration *current_; + + // The innermost WithConfiguration whose dynamic scope encloses this + // WithConfiguration. + Endianness endianness_; + size_t word_size_; + WithConfiguration *saved_; +}; + +WithConfiguration *WithConfiguration::current_ = NULL; + +// A test_assembler::Section with a size that we can cite. The start(), +// Here() and Mark() member functions of a SizedSection always represent +// offsets within the overall file. +class SizedSection: public test_assembler::Section { + public: + // Construct a section of the given endianness and word size. + explicit SizedSection(Endianness endianness, size_t word_size) + : test_assembler::Section(endianness), word_size_(word_size) { + assert(word_size_ == 32 || word_size_ == 64); + } + SizedSection() + : test_assembler::Section(WithConfiguration::endianness()), + word_size_(WithConfiguration::word_size()) { + assert(word_size_ == 32 || word_size_ == 64); + } + + // Access/set this section's word size. + size_t word_size() const { return word_size_; } + void set_word_size(size_t word_size) { + assert(word_size_ == 32 || word_size_ == 64); + word_size_ = word_size; + } + + // Return a label representing the size this section will have when it + // is Placed in some containing section. + Label final_size() const { return final_size_; } + + // Append SECTION to the end of this section, and call its Finish member. + // Return a reference to this section. + SizedSection &Place(SizedSection *section) { + assert(section->endianness() == endianness()); + section->Finish(); + section->start() = Here(); + test_assembler::Section::Append(*section); + return *this; + } + + protected: + // Mark this section's contents as complete. For plain SizedSections, we + // set SECTION's start to its position in this section, and its final_size + // label to its current size. Derived classes can extend this as needed + // for their additional semantics. + virtual void Finish() { + final_size_ = Size(); + } + + // The word size for this data: either 32 or 64. + size_t word_size_; + + private: + // This section's final size, set when we are placed in some other + // SizedSection. + Label final_size_; +}; + +// A SizedSection that is loaded into memory at a particular address. +class LoadedSection: public SizedSection { + public: + explicit LoadedSection(Label address = Label()) : address_(address) { } + + // Return a label representing this section's address. + Label address() const { return address_; } + + // Placing a loaded section within a loaded section sets the relationship + // between their addresses. + LoadedSection &Place(LoadedSection *section) { + section->address() = address() + Size(); + SizedSection::Place(section); + return *this; + } + + protected: + // The address at which this section's contents will be loaded. + Label address_; +}; + +// A SizedSection representing a segment load command. +class SegmentLoadCommand: public SizedSection { + public: + SegmentLoadCommand() : section_count_(0) { } + + // Append a segment load command header with the given characteristics. + // The load command will refer to CONTENTS, which must be Placed in the + // file separately, at the desired position. Return a reference to this + // section. + SegmentLoadCommand &Header(const string &name, const LoadedSection &contents, + uint32_t maxprot, uint32_t initprot, + uint32_t flags) { + assert(contents.word_size() == word_size()); + D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64); + D32(final_size()); + AppendCString(name, 16); + Append(endianness(), word_size() / 8, contents.address()); + Append(endianness(), word_size() / 8, vmsize_); + Append(endianness(), word_size() / 8, contents.start()); + Append(endianness(), word_size() / 8, contents.final_size()); + D32(maxprot); + D32(initprot); + D32(final_section_count_); + D32(flags); + + content_final_size_ = contents.final_size(); + + return *this; + } + + // Return a label representing the size of this segment when loaded into + // memory. If this label is still undefined by the time we place this + // segment, it defaults to the final size of the segment's in-file + // contents. Return a reference to this load command. + Label &vmsize() { return vmsize_; } + + // Add a section entry with the given characteristics to this segment + // load command. Return a reference to this. The section entry will refer + // to CONTENTS, which must be Placed in the segment's contents + // separately, at the desired position. + SegmentLoadCommand &AppendSectionEntry(const string §ion_name, + const string &segment_name, + uint32_t alignment, uint32_t flags, + const LoadedSection &contents) { + AppendCString(section_name, 16); + AppendCString(segment_name, 16); + Append(endianness(), word_size() / 8, contents.address()); + Append(endianness(), word_size() / 8, contents.final_size()); + D32(contents.start()); + D32(alignment); + D32(0); // relocations start + D32(0); // relocations size + D32(flags); + D32(0x93656b95); // reserved1 + D32(0xc35a2473); // reserved2 + if (word_size() == 64) + D32(0x70284b95); // reserved3 + + section_count_++; + + return *this; + } + + protected: + void Finish() { + final_section_count_ = section_count_; + if (!vmsize_.IsKnownConstant()) + vmsize_ = content_final_size_; + SizedSection::Finish(); + } + + private: + // The number of sections that have been added to this segment so far. + size_t section_count_; + + // A label representing the final number of sections this segment will hold. + Label final_section_count_; + + // The size of the contents for this segment present in the file. + Label content_final_size_; + + // A label representing the size of this segment when loaded; this can be + // larger than the size of its file contents, the difference being + // zero-filled. If not set explicitly by calling set_vmsize, this is set + // equal to the size of the contents. + Label vmsize_; +}; + +// A SizedSection holding a list of Mach-O load commands. +class LoadCommands: public SizedSection { + public: + LoadCommands() : command_count_(0) { } + + // Return a label representing the final load command count. + Label final_command_count() const { return final_command_count_; } + + // Increment the command count; return a reference to this section. + LoadCommands &CountCommand() { + command_count_++; + return *this; + } + + // Place COMMAND, containing a load command, at the end of this section. + // Return a reference to this section. + LoadCommands &Place(SizedSection *section) { + SizedSection::Place(section); + CountCommand(); + return *this; + } + + protected: + // Mark this load command list as complete. + void Finish() { + SizedSection::Finish(); + final_command_count_ = command_count_; + } + + private: + // The number of load commands we have added to this file so far. + size_t command_count_; + + // A label representing the final command count. + Label final_command_count_; +}; + +// A SizedSection holding the contents of a Mach-O file. Within a +// MachOFile, the start, Here, and Mark members refer to file offsets. +class MachOFile: public SizedSection { + public: + MachOFile() { + start() = 0; + } + + // Create a Mach-O file header using the given characteristics and load + // command list. This Places COMMANDS immediately after the header. + // Return a reference to this section. + MachOFile &Header(LoadCommands *commands, + cpu_type_t cpu_type = CPU_TYPE_X86, + cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL, + FileType file_type = MH_EXECUTE, + uint32_t file_flags = (MH_TWOLEVEL | + MH_DYLDLINK | + MH_NOUNDEFS)) { + D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf); // magic number + D32(cpu_type); // cpu type + D32(cpu_subtype); // cpu subtype + D32(file_type); // file type + D32(commands->final_command_count()); // number of load commands + D32(commands->final_size()); // their size in bytes + D32(file_flags); // flags + if (word_size() == 64) + D32(0x55638b90); // reserved + Place(commands); + return *this; + } +}; + + +struct ReaderFixture { + ReaderFixture() + : reporter("reporter filename"), + reader(&reporter) { + EXPECT_CALL(reporter, BadHeader()).Times(0); + EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0); + EXPECT_CALL(reporter, HeaderTruncated()).Times(0); + EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0); + EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0); + EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0); + EXPECT_CALL(reporter, SectionsMissing(_)).Times(0); + EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0); + EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0); + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0); + EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0); + + EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0); + EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0); + } + + void ReadFile(MachOFile *file, + bool expect_parse_success, + cpu_type_t expected_cpu_type, + cpu_subtype_t expected_cpu_subtype) { + ASSERT_TRUE(file->GetContents(&file_contents)); + file_bytes = reinterpret_cast(file_contents.data()); + if (expect_parse_success) { + EXPECT_TRUE(reader.Read(file_bytes, + file_contents.size(), + expected_cpu_type, + expected_cpu_subtype)); + } else { + EXPECT_FALSE(reader.Read(file_bytes, + file_contents.size(), + expected_cpu_type, + expected_cpu_subtype)); + } + } + + string file_contents; + const uint8_t *file_bytes; + MockReaderReporter reporter; + Reader reader; + MockLoadCommandHandler load_command_handler; + MockSectionHandler section_handler; +}; + +class ReaderTest: public ReaderFixture, public Test { }; + +TEST_F(ReaderTest, BadMagic) { + WithConfiguration config(kLittleEndian, 32); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0x67bdebe1) // Not a proper magic number. + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); +} + +TEST_F(ReaderTest, MismatchedMagic) { + WithConfiguration config(kLittleEndian, 32); + const cpu_type_t kCPUType = CPU_TYPE_I386; + const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; + MachOFile file; + file + .D32(MH_CIGAM) // Right magic, but winds up wrong + // due to bitswapping + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); + ReadFile(&file, false, kCPUType, kCPUSubType); +} + +TEST_F(ReaderTest, ShortMagic) { + WithConfiguration config(kBigEndian, 32); + MachOFile file; + file + .D16(0xfeed); // magic number + // truncated! + EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); + ReadFile(&file, false, CPU_TYPE_ANY, 0); +} + +TEST_F(ReaderTest, ShortHeader) { + WithConfiguration config(kBigEndian, 32); + const cpu_type_t kCPUType = CPU_TYPE_ANY; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedface) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0); // they occupy no bytes + EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); +} + +TEST_F(ReaderTest, MismatchedCPU) { + WithConfiguration config(kBigEndian, 32); + const cpu_type_t kCPUType = CPU_TYPE_I386; + const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; + MachOFile file; + file + .D32(MH_MAGIC) // Right magic for PPC (once bitswapped) + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + EXPECT_CALL(reporter, + CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, + CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL)) + .WillOnce(Return()); + ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); +} + +TEST_F(ReaderTest, LittleEndian32Bit) { + WithConfiguration config(kLittleEndian, 32); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedface) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); + EXPECT_FALSE(reader.bits_64()); + EXPECT_FALSE(reader.big_endian()); + EXPECT_EQ(kCPUType, reader.cpu_type()); + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); +} + +TEST_F(ReaderTest, LittleEndian64Bit) { + WithConfiguration config(kLittleEndian, 64); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedfacf) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); + EXPECT_TRUE(reader.bits_64()); + EXPECT_FALSE(reader.big_endian()); + EXPECT_EQ(kCPUType, reader.cpu_type()); + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); +} + +TEST_F(ReaderTest, BigEndian32Bit) { + WithConfiguration config(kBigEndian, 32); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedface) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); + EXPECT_FALSE(reader.bits_64()); + EXPECT_TRUE(reader.big_endian()); + EXPECT_EQ(kCPUType, reader.cpu_type()); + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); +} + +TEST_F(ReaderTest, BigEndian64Bit) { + WithConfiguration config(kBigEndian, 64); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedfacf) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(0) // no load commands + .D32(0) // they occupy no bytes + .D32(0x80e71d64) // flags + .D32(0); // reserved + ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); + EXPECT_TRUE(reader.bits_64()); + EXPECT_TRUE(reader.big_endian()); + EXPECT_EQ(kCPUType, reader.cpu_type()); + EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); + EXPECT_EQ(FileType(0x149fc717), reader.file_type()); + EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); +} + + +// Load command tests. + +class LoadCommand: public ReaderFixture, public Test { }; + +TEST_F(LoadCommand, RegionTruncated) { + WithConfiguration config(kBigEndian, 64); + const cpu_type_t kCPUType = 0x46b760df; + const cpu_subtype_t kCPUSubType = 0x76a0e7f7; + MachOFile file; + file + .D32(0xfeedfacf) // magic number + .D32(kCPUType) // cpu type + .D32(kCPUSubType) // cpu subtype + .D32(0x149fc717) // file type + .D32(1) // one load command + .D32(40) // occupying 40 bytes + .D32(0x80e71d64) // flags + .D32(0) // reserved + .Append(20, 0); // load command region, not as long as + // Mach-O header promised + + EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return()); + + ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); +} + +TEST_F(LoadCommand, None) { + WithConfiguration config(kLittleEndian, 32); + LoadCommands load_commands; + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL); + + EXPECT_FALSE(reader.bits_64()); + EXPECT_FALSE(reader.big_endian()); + EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); + EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); + EXPECT_EQ(static_cast(MH_EXECUTE), reader.file_type()); + EXPECT_EQ(FileFlags(MH_TWOLEVEL | + MH_DYLDLINK | + MH_NOUNDEFS), + FileFlags(reader.flags())); + + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, Unknown) { + WithConfiguration config(kBigEndian, 32); + LoadCommands load_commands; + load_commands + .CountCommand() + .D32(0x33293d4a) // unknown load command + .D32(40) // total size in bytes + .Append(32, '*'); // dummy data + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_FALSE(reader.bits_64()); + EXPECT_TRUE(reader.big_endian()); + EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); + EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); + EXPECT_EQ(static_cast(MH_EXECUTE), reader.file_type()); + EXPECT_EQ(FileFlags(MH_TWOLEVEL | + MH_DYLDLINK | + MH_NOUNDEFS), + reader.flags()); + + ByteBuffer expected; + expected.start = file_bytes + load_commands.start().Value(); + expected.end = expected.start + load_commands.final_size().Value(); + EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a, + expected)) + .WillOnce(Return(true)); + + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, TypeIncomplete) { + WithConfiguration config(kLittleEndian, 32); + LoadCommands load_commands; + load_commands + .CountCommand() + .Append(3, 0); // load command type, incomplete + + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0)) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, LengthIncomplete) { + WithConfiguration config(kBigEndian, 64); + LoadCommands load_commands; + load_commands + .CountCommand() + .D32(LC_SEGMENT); // load command + // no length + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, ContentIncomplete) { + WithConfiguration config(kLittleEndian, 64); + LoadCommands load_commands; + load_commands + .CountCommand() + .D32(LC_SEGMENT) // load command + .D32(40) // total size in bytes + .Append(28, '*'); // not enough dummy data + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, SegmentBE32) { + WithConfiguration config(kBigEndian, 32); + LoadedSection segment; + segment.address() = 0x1891139c; + segment.Append(42, '*'); // segment contents + SegmentLoadCommand segment_command; + segment_command + .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd); + segment_command.vmsize() = 0xcb76584fU; + LoadCommands load_commands; + load_commands.Place(&segment_command); + MachOFile file; + file + .Header(&load_commands) + .Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_CALL(load_command_handler, SegmentCommand(_)) + .WillOnce(DoAll(SaveArg<0>(&actual_segment), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_FALSE(actual_segment.bits_64); + EXPECT_EQ("froon", actual_segment.name); + EXPECT_EQ(0x1891139cU, actual_segment.vmaddr); + EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); + EXPECT_EQ(0x94d6dd22U, actual_segment.maxprot); + EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); + EXPECT_EQ(0x990a16ddU, actual_segment.flags); + EXPECT_EQ(0U, actual_segment.nsects); + EXPECT_EQ(0U, actual_segment.section_list.Size()); + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); +} + +TEST_F(LoadCommand, SegmentLE32) { + WithConfiguration config(kLittleEndian, 32); + LoadedSection segment; + segment.address() = 0x4b877866; + segment.Append(42, '*'); // segment contents + SegmentLoadCommand segment_command; + segment_command + .Header("sixteenprecisely", segment, + 0x350759ed, 0x6cf5a62e, 0x990a16dd); + segment_command.vmsize() = 0xcb76584fU; + LoadCommands load_commands; + load_commands.Place(&segment_command); + MachOFile file; + file + .Header(&load_commands) + .Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_CALL(load_command_handler, SegmentCommand(_)) + .WillOnce(DoAll(SaveArg<0>(&actual_segment), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_FALSE(actual_segment.bits_64); + EXPECT_EQ("sixteenprecisely", actual_segment.name); + EXPECT_EQ(0x4b877866U, actual_segment.vmaddr); + EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); + EXPECT_EQ(0x350759edU, actual_segment.maxprot); + EXPECT_EQ(0x6cf5a62eU, actual_segment.initprot); + EXPECT_EQ(0x990a16ddU, actual_segment.flags); + EXPECT_EQ(0U, actual_segment.nsects); + EXPECT_EQ(0U, actual_segment.section_list.Size()); + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); +} + +TEST_F(LoadCommand, SegmentBE64) { + WithConfiguration config(kBigEndian, 64); + LoadedSection segment; + segment.address() = 0x79f484f77009e511ULL; + segment.Append(42, '*'); // segment contents + SegmentLoadCommand segment_command; + segment_command + .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220); + segment_command.vmsize() = 0x8d92397ce6248abaULL; + LoadCommands load_commands; + load_commands.Place(&segment_command); + MachOFile file; + file + .Header(&load_commands) + .Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_CALL(load_command_handler, SegmentCommand(_)) + .WillOnce(DoAll(SaveArg<0>(&actual_segment), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_EQ(true, actual_segment.bits_64); + EXPECT_EQ("froon", actual_segment.name); + EXPECT_EQ(0x79f484f77009e511ULL, actual_segment.vmaddr); + EXPECT_EQ(0x8d92397ce6248abaULL, actual_segment.vmsize); + EXPECT_EQ(0x42b45da5U, actual_segment.maxprot); + EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); + EXPECT_EQ(0xb2335220U, actual_segment.flags); + EXPECT_EQ(0U, actual_segment.nsects); + EXPECT_EQ(0U, actual_segment.section_list.Size()); + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); +} + +TEST_F(LoadCommand, SegmentLE64) { + WithConfiguration config(kLittleEndian, 64); + LoadedSection segment; + segment.address() = 0x50c0501dc5922d35ULL; + segment.Append(42, '*'); // segment contents + SegmentLoadCommand segment_command; + segment_command + .Header("sixteenprecisely", segment, + 0x917c339d, 0xdbc446fa, 0xb650b563); + segment_command.vmsize() = 0x84ae73e7c75469bfULL; + LoadCommands load_commands; + load_commands.Place(&segment_command); + MachOFile file; + file + .Header(&load_commands) + .Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_CALL(load_command_handler, SegmentCommand(_)) + .WillOnce(DoAll(SaveArg<0>(&actual_segment), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_EQ(true, actual_segment.bits_64); + EXPECT_EQ("sixteenprecisely", actual_segment.name); + EXPECT_EQ(0x50c0501dc5922d35ULL, actual_segment.vmaddr); + EXPECT_EQ(0x84ae73e7c75469bfULL, actual_segment.vmsize); + EXPECT_EQ(0x917c339dU, actual_segment.maxprot); + EXPECT_EQ(0xdbc446faU, actual_segment.initprot); + EXPECT_EQ(0xb650b563U, actual_segment.flags); + EXPECT_EQ(0U, actual_segment.nsects); + EXPECT_EQ(0U, actual_segment.section_list.Size()); + EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); +} + +TEST_F(LoadCommand, SegmentCommandTruncated) { + WithConfiguration config(kBigEndian, 32); + LoadedSection segment_contents; + segment_contents.Append(20, '*'); // lah di dah + SizedSection command; + command + .D32(LC_SEGMENT) // command type + .D32(command.final_size()) // command size + .AppendCString("too-short", 16) // segment name + .D32(0x9c759211) // vmaddr + .D32(segment_contents.final_size()) // vmsize + .D32(segment_contents.start()) // file offset + .D32(segment_contents.final_size()) // file size + .D32(0x56f28446) // max protection + .D32(0xe7910dcb) // initial protection + .D32(0) // no sections + .Append(3, 0); // flags (one byte short!) + LoadCommands load_commands; + load_commands.Place(&command); + MachOFile file; + file + .Header(&load_commands) + .Place(&segment_contents); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT)) + .WillOnce(Return()); + + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, SegmentBadContentOffset) { + WithConfiguration config(kLittleEndian, 32); + // Instead of letting a Place call set the segment's file offset and size, + // set them ourselves, to check that the parser catches invalid offsets + // instead of handing us bogus pointers. + LoadedSection segment; + segment.address() = 0x4db5489c; + segment.start() = 0x7e189e76; // beyond end of file + segment.final_size() = 0x98b9c3ab; + SegmentLoadCommand segment_command; + segment_command + .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f); + LoadCommands load_commands; + load_commands.Place(&segment_command); + MachOFile file; + file.Header(&load_commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen")) + .WillOnce(Return()); + + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(LoadCommand, ThreeLoadCommands) { + WithConfiguration config(kBigEndian, 32); + LoadedSection seg1, seg2, seg3; + SegmentLoadCommand cmd1, cmd2, cmd3; + + seg1.Append(128, '@'); + seg1.address() = 0xa7f61ef6; + cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87); + // Include some dummy data at the end of the load command. Since we + // didn't claim to have any sections, the reader should ignore this. But + // making sure the commands have different lengths ensures that we're + // using the right command's length to advance the LoadCommandIterator. + cmd1.Append(128, '!'); + + seg2.Append(42, '*'); + seg2.address() = 0xc70fc909; + cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30); + // More dummy data at the end of the load command. + cmd2.Append(32, '^'); + + seg3.Append(42, '%'); + seg3.address() = 0x46b3ab05; + cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b); + // More dummy data at the end of the load command. + cmd3.Append(64, '&'); + + LoadCommands load_commands; + load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); + + MachOFile file; + file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + { + InSequence s; + EXPECT_CALL(load_command_handler, + SegmentCommand(Field(&Segment::name, "head"))) + .WillOnce(Return(true)); + EXPECT_CALL(load_command_handler, + SegmentCommand(Field(&Segment::name, "thorax"))) + .WillOnce(Return(true)); + EXPECT_CALL(load_command_handler, + SegmentCommand(Field(&Segment::name, "abdomen"))) + .WillOnce(Return(true)); + } + + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); +} + +static inline Matcher MatchSection( + Matcher bits_64, + Matcher section_name, + Matcher segment_name, + Matcher address, + Matcher alignment, + Matcher flags, + Matcher contents) { + return AllOf(AllOf(Field(&Section::bits_64, bits_64), + Field(&Section::section_name, section_name), + Field(&Section::segment_name, segment_name), + Field(&Section::address, address)), + AllOf(Field(&Section::align, alignment), + Field(&Section::flags, flags), + Field(&Section::contents, contents))); +} + +static inline Matcher MatchSection( + Matcher bits_64, + Matcher section_name, + Matcher segment_name, + Matcher address) { + return AllOf(Field(&Section::bits_64, bits_64), + Field(&Section::section_name, section_name), + Field(&Section::segment_name, segment_name), + Field(&Section::address, address)); +} + +TEST_F(LoadCommand, OneSegmentTwoSections) { + WithConfiguration config(kBigEndian, 64); + + // Create some sections with some data. + LoadedSection section1, section2; + section1.Append("buddha's hand"); + section2.Append("kumquat"); + + // Create a segment to hold them. + LoadedSection segment; + segment.address() = 0xe1d0eeec; + segment.Place(§ion2).Place(§ion1); + + SegmentLoadCommand segment_command; + segment_command + .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2) + .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1) + .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2); + + LoadCommands commands; + commands.Place(&segment_command); + + MachOFile file; + file.Header(&commands).Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_CALL(load_command_handler, SegmentCommand(_)) + .WillOnce(DoAll(SaveArg<0>(&actual_segment), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + { + InSequence s; + ByteBuffer contents1; + contents1.start = file_bytes + section1.start().Value(); + contents1.end = contents1.start + section1.final_size().Value(); + EXPECT_EQ("buddha's hand", + string(reinterpret_cast(contents1.start), + contents1.Size())); + EXPECT_CALL(section_handler, + HandleSection(MatchSection(true, "mandarin", "kishu", + section1.address().Value(), 12, + 0x8cd4604bU, contents1))) + .WillOnce(Return(true)); + + ByteBuffer contents2; + contents2.start = file_bytes + section2.start().Value(); + contents2.end = contents2.start + section2.final_size().Value(); + EXPECT_EQ("kumquat", + string(reinterpret_cast(contents2.start), + contents2.Size())); + EXPECT_CALL(section_handler, + HandleSection(MatchSection(true, "bergamot", "cara cara", + section2.address().Value(), 12, + 0x98746efaU, contents2))) + .WillOnce(Return(true)); + } + + EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + +TEST_F(LoadCommand, MisplacedSectionBefore) { + WithConfiguration config(kLittleEndian, 64); + + // The segment. + LoadedSection segment; + segment.address() = 0x696d83cc; + segment.Append(10, '0'); + + // The contents of the following sections don't matter, because + // we're not really going to Place them in segment; we're just going + // to set all their labels by hand to get the (impossible) + // configurations we want. + + // A section whose starting offset is before that of its section. + LoadedSection before; + before.Append(10, '1'); + before.start() = segment.start() - 1; + before.address() = segment.address() - 1; + before.final_size() = before.Size(); + + SegmentLoadCommand command; + command + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) + .AppendSectionEntry("before", "segment", 0, 0x686c6921, before); + + LoadCommands commands; + commands.Place(&command); + + MachOFile file; + file.Header(&commands).Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); + + EXPECT_CALL(reporter, MisplacedSectionData("before", "segment")) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + +TEST_F(LoadCommand, MisplacedSectionAfter) { + WithConfiguration config(kLittleEndian, 64); + + // The segment. + LoadedSection segment; + segment.address() = 0x696d83cc; + segment.Append(10, '0'); + + // The contents of the following sections don't matter, because + // we're not really going to Place them in segment; we're just going + // to set all their labels by hand to get the (impossible) + // configurations we want. + + // A section whose starting offset is after the end of its section. + LoadedSection after; + after.Append(10, '2'); + after.start() = segment.start() + 11; + after.address() = segment.address() + 11; + after.final_size() = after.Size(); + + SegmentLoadCommand command; + command + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) + .AppendSectionEntry("after", "segment", 0, 0x2ee50124, after); + + LoadCommands commands; + commands.Place(&command); + + MachOFile file; + file.Header(&commands).Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); + + EXPECT_CALL(reporter, MisplacedSectionData("after", "segment")) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + +TEST_F(LoadCommand, MisplacedSectionTooBig) { + WithConfiguration config(kLittleEndian, 64); + + // The segment. + LoadedSection segment; + segment.address() = 0x696d83cc; + segment.Append(10, '0'); + + // The contents of the following sections don't matter, because + // we're not really going to Place them in segment; we're just going + // to set all their labels by hand to get the (impossible) + // configurations we want. + + // A section that extends beyond the end of its section. + LoadedSection too_big; + too_big.Append(10, '3'); + too_big.start() = segment.start() + 1; + too_big.address() = segment.address() + 1; + too_big.final_size() = too_big.Size(); + + SegmentLoadCommand command; + command + .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) + .AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big); + + LoadCommands commands; + commands.Place(&command); + + MachOFile file; + file.Header(&commands).Place(&segment); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); + + EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment")) + .WillOnce(Return()); + EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + + +// The segments in a .dSYM bundle's Mach-O file have their file offset +// and size set to zero, but the sections don't. The reader shouldn't +// report an error in this case. +TEST_F(LoadCommand, ZappedSegment) { + WithConfiguration config(kBigEndian, 32); + + // The segment. + LoadedSection segment; + segment.address() = 0x696d83cc; + segment.start() = 0; + segment.final_size() = 0; + + // The section. + LoadedSection section; + section.address() = segment.address(); + section.start() = 0; + section.final_size() = 1000; // extends beyond its segment + + SegmentLoadCommand command; + command + .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c) + .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section); + + LoadCommands commands; + commands.Place(&command); + + MachOFile file; + file.Header(&commands); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment)); + + ByteBuffer zapped_extent(NULL, 0); + EXPECT_CALL(section_handler, + HandleSection(MatchSection(false, "twitching", "zapped", + 0x696d83cc, 0, 0x93b3bd42, + zapped_extent))) + .WillOnce(Return(true)); + + EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); +} + +TEST_F(LoadCommand, MapSegmentSections) { + WithConfiguration config(kLittleEndian, 32); + + // Create some sections with some data. + LoadedSection section1, section2, section3, section4; + section1.Append("buddha's hand"); + section2.start() = 0; // Section 2 is an S_ZEROFILL section. + section2.final_size() = 0; + section3.Append("shasta gold"); + section4.Append("satsuma"); + + // Create two segments to hold them. + LoadedSection segment1, segment2; + segment1.address() = 0x13e6c8a9; + segment1.Place(§ion3).Place(§ion1); + segment2.set_word_size(64); + segment2.address() = 0x04d462e2; + segment2.Place(§ion4); + section2.address() = segment2.address() + segment2.Size(); + + SegmentLoadCommand segment_command1, segment_command2; + segment_command1 + .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64) + .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1) + .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3); + segment_command2.set_word_size(64); + segment_command2 + .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33) + .AppendSectionEntry("sixteenprecisely", "thorax", + 12, S_ZEROFILL, section2) + .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4); + + LoadCommands commands; + commands.Place(&segment_command1).Place(&segment_command2); + + MachOFile file; + file.Header(&commands).Place(&segment1).Place(&segment2); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment segment; + SectionMap section_map; + + EXPECT_FALSE(reader.FindSegment("smoot", &segment)); + + ASSERT_TRUE(reader.FindSegment("thorax", &segment)); + ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); + + EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome") + != section_map.end()); + EXPECT_FALSE(section_map.find("mandarin") != section_map.end()); + ASSERT_TRUE(section_map.find("cara cara") != section_map.end()); + EXPECT_THAT(section_map["cara cara"], + MatchSection(true, "cara cara", "thorax", 0x04d462e2)); + ASSERT_TRUE(section_map.find("sixteenprecisely") + != section_map.end()); + ByteBuffer sixteenprecisely_contents(NULL, 0); + EXPECT_THAT(section_map["sixteenprecisely"], + MatchSection(true, "sixteenprecisely", "thorax", + 0x04d462e2 + 7, 12, S_ZEROFILL, + sixteenprecisely_contents)); + + ASSERT_TRUE(reader.FindSegment("head", &segment)); + ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); + + ASSERT_TRUE(section_map.find("mandarin") != section_map.end()); + EXPECT_THAT(section_map["mandarin"], + MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11)); + ASSERT_TRUE(section_map.find("bergamot") != section_map.end()); + EXPECT_THAT(section_map["bergamot"], + MatchSection(false, "bergamot", "head", 0x13e6c8a9)); +} + +TEST_F(LoadCommand, FindSegment) { + WithConfiguration config(kBigEndian, 32); + + LoadedSection segment1, segment2, segment3; + segment1.address() = 0xb8ae5752; + segment1.Append("Some contents!"); + segment2.address() = 0xd6b0ce83; + segment2.Append("Different stuff."); + segment3.address() = 0x7374fd2a; + segment3.Append("Further materials."); + + SegmentLoadCommand cmd1, cmd2, cmd3; + cmd1.Header("first", segment1, 0xfadb6932, 0x175bf529, 0x0de790ad); + cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef); + cmd3.Header("third", segment3, 0xe172b39e, 0x86012f07, 0x080ac94d); + + LoadCommands commands; + commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); + + MachOFile file; + file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + Segment actual_segment; + + EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment)); + + EXPECT_TRUE(reader.FindSegment("second", &actual_segment)); + EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr); +} + + +// Symtab tests. + +// A StringAssembler is a class for generating .stabstr sections to present +// as input to the STABS parser. +class StringAssembler: public SizedSection { + public: + // Add the string S to this StringAssembler, and return the string's + // offset within this compilation unit's strings. + size_t Add(const string &s) { + size_t offset = Size(); + AppendCString(s); + return offset; + } +}; + +// A SymbolAssembler is a class for generating .stab sections to present as +// test input for the STABS parser. +class SymbolAssembler: public SizedSection { + public: + // Create a SymbolAssembler that uses StringAssembler for its strings. + explicit SymbolAssembler(StringAssembler *string_assembler) + : string_assembler_(string_assembler), + entry_count_(0) { } + + // Append a STAB entry to the end of this section with the given + // characteristics. NAME is the offset of this entry's name string within + // its compilation unit's portion of the .stabstr section; this can be a + // value generated by a StringAssembler. Return a reference to this + // SymbolAssembler. + SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, + Label value, Label name) { + D32(name); + D8(type); + D8(other); + D16(descriptor); + Append(endianness(), word_size_ / 8, value); + entry_count_++; + return *this; + } + + // As above, but automatically add NAME to our StringAssembler. + SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, + Label value, const string &name) { + return Symbol(type, other, descriptor, value, string_assembler_->Add(name)); + } + + private: + // The strings for our STABS entries. + StringAssembler *string_assembler_; + + // The number of entries in this compilation unit so far. + size_t entry_count_; +}; + +class Symtab: public ReaderFixture, public Test { }; + +TEST_F(Symtab, Symtab32) { + WithConfiguration config(kLittleEndian, 32); + + StringAssembler strings; + SymbolAssembler symbols(&strings); + symbols + .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu") + .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith"); + + SizedSection symtab_command; + symtab_command + .D32(LC_SYMTAB) // command + .D32(symtab_command.final_size()) // size + .D32(symbols.start()) // file offset of symbols + .D32(2) // symbol count + .D32(strings.start()) // file offset of strings + .D32(strings.final_size()); // strings size + + LoadCommands load_commands; + load_commands.Place(&symtab_command); + + MachOFile file; + file.Header(&load_commands).Place(&symbols).Place(&strings); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + ByteBuffer symbols_found, strings_found; + EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) + .WillOnce(DoAll(SaveArg<0>(&symbols_found), + SaveArg<1>(&strings_found), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_EQ(24U, symbols_found.Size()); + EXPECT_EQ(14U, strings_found.Size()); +} + +TEST_F(Symtab, Symtab64) { + WithConfiguration config(kBigEndian, 64); + + StringAssembler strings; + SymbolAssembler symbols(&strings); + symbols + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); + + SizedSection symtab_command; + symtab_command + .D32(LC_SYMTAB) // command + .D32(symtab_command.final_size()) // size + .D32(symbols.start()) // file offset of symbols + .D32(2) // symbol count + .D32(strings.start()) // file offset of strings + .D32(strings.final_size()); // strings size + + LoadCommands load_commands; + load_commands.Place(&symtab_command); + + MachOFile file; + file.Header(&load_commands).Place(&symbols).Place(&strings); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + ByteBuffer symbols_found, strings_found; + EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) + .WillOnce(DoAll(SaveArg<0>(&symbols_found), + SaveArg<1>(&strings_found), + Return(true))); + EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); + + EXPECT_EQ(32U, symbols_found.Size()); + EXPECT_EQ(8U, strings_found.Size()); +} + +TEST_F(Symtab, SymtabMisplacedSymbols) { + WithConfiguration config(kBigEndian, 32); + + StringAssembler strings; + SymbolAssembler symbols(&strings); + symbols + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); + + SizedSection symtab_command; + symtab_command + .D32(LC_SYMTAB) // command + .D32(symtab_command.final_size()) // size + .D32(symbols.start()) // file offset of symbols + .D32(3) // symbol count (too many) + .D32(strings.start()) // file offset of strings + .D32(strings.final_size()); // strings size + + LoadCommands load_commands; + load_commands.Place(&symtab_command); + + MachOFile file; + // Put symbols at end, so the excessive length will be noticed. + file.Header(&load_commands).Place(&strings).Place(&symbols); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + +TEST_F(Symtab, SymtabMisplacedStrings) { + WithConfiguration config(kLittleEndian, 32); + + StringAssembler strings; + SymbolAssembler symbols(&strings); + symbols + .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") + .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); + + SizedSection symtab_command; + symtab_command + .D32(LC_SYMTAB) // command + .D32(symtab_command.final_size()) // size + .D32(symbols.start()) // file offset of symbols + .D32(2) // symbol count + .D32(strings.start()) // file offset of strings + .D32(strings.final_size() + 1); // strings size (too long) + + LoadCommands load_commands; + load_commands.Place(&symtab_command); + + MachOFile file; + // Put strings at end, so the excessive length will be noticed. + file.Header(&load_commands).Place(&symbols).Place(&strings); + + ReadFile(&file, true, CPU_TYPE_ANY, 0); + + EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); + EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); +} + diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc new file mode 100644 index 0000000000..f56fe768c1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc @@ -0,0 +1,155 @@ +// 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. + +// macho_utilties.cc: Utilities for dealing with mach-o files +// +// Author: Dave Camp + +#include "common/mac/byteswap.h" +#include "common/mac/macho_utilities.h" + +#include +#include + +void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc) { + uc->cmd = ByteSwap(uc->cmd); + uc->cmdsize = ByteSwap(uc->cmdsize); +} + +void breakpad_swap_load_command(struct load_command *lc) { + lc->cmd = ByteSwap(lc->cmd); + lc->cmdsize = ByteSwap(lc->cmdsize); +} + +void breakpad_swap_dylib_command(struct dylib_command *dc) { + dc->cmd = ByteSwap(dc->cmd); + dc->cmdsize = ByteSwap(dc->cmdsize); + + dc->dylib.name.offset = ByteSwap(dc->dylib.name.offset); + dc->dylib.timestamp = ByteSwap(dc->dylib.timestamp); + dc->dylib.current_version = ByteSwap(dc->dylib.current_version); + dc->dylib.compatibility_version = ByteSwap(dc->dylib.compatibility_version); +} + +void breakpad_swap_segment_command(struct segment_command *sc) { + sc->cmd = ByteSwap(sc->cmd); + sc->cmdsize = ByteSwap(sc->cmdsize); + + sc->vmaddr = ByteSwap(sc->vmaddr); + sc->vmsize = ByteSwap(sc->vmsize); + sc->fileoff = ByteSwap(sc->fileoff); + sc->filesize = ByteSwap(sc->filesize); + sc->maxprot = ByteSwap(sc->maxprot); + sc->initprot = ByteSwap(sc->initprot); + sc->nsects = ByteSwap(sc->nsects); + sc->flags = ByteSwap(sc->flags); +} + +void breakpad_swap_segment_command_64(struct segment_command_64 *sg) { + sg->cmd = ByteSwap(sg->cmd); + sg->cmdsize = ByteSwap(sg->cmdsize); + + sg->vmaddr = ByteSwap(sg->vmaddr); + sg->vmsize = ByteSwap(sg->vmsize); + sg->fileoff = ByteSwap(sg->fileoff); + sg->filesize = ByteSwap(sg->filesize); + + sg->maxprot = ByteSwap(sg->maxprot); + sg->initprot = ByteSwap(sg->initprot); + sg->nsects = ByteSwap(sg->nsects); + sg->flags = ByteSwap(sg->flags); +} + +void breakpad_swap_fat_header(struct fat_header *fh) { + fh->magic = ByteSwap(fh->magic); + fh->nfat_arch = ByteSwap(fh->nfat_arch); +} + +void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs) { + for (uint32_t i = 0; i < narchs; ++i) { + fa[i].cputype = ByteSwap(fa[i].cputype); + fa[i].cpusubtype = ByteSwap(fa[i].cpusubtype); + fa[i].offset = ByteSwap(fa[i].offset); + fa[i].size = ByteSwap(fa[i].size); + fa[i].align = ByteSwap(fa[i].align); + } +} + +void breakpad_swap_mach_header(struct mach_header *mh) { + mh->magic = ByteSwap(mh->magic); + mh->cputype = ByteSwap(mh->cputype); + mh->cpusubtype = ByteSwap(mh->cpusubtype); + mh->filetype = ByteSwap(mh->filetype); + mh->ncmds = ByteSwap(mh->ncmds); + mh->sizeofcmds = ByteSwap(mh->sizeofcmds); + mh->flags = ByteSwap(mh->flags); +} + +void breakpad_swap_mach_header_64(struct mach_header_64 *mh) { + mh->magic = ByteSwap(mh->magic); + mh->cputype = ByteSwap(mh->cputype); + mh->cpusubtype = ByteSwap(mh->cpusubtype); + mh->filetype = ByteSwap(mh->filetype); + mh->ncmds = ByteSwap(mh->ncmds); + mh->sizeofcmds = ByteSwap(mh->sizeofcmds); + mh->flags = ByteSwap(mh->flags); + mh->reserved = ByteSwap(mh->reserved); +} + +void breakpad_swap_section(struct section *s, + uint32_t nsects) { + for (uint32_t i = 0; i < nsects; i++) { + s[i].addr = ByteSwap(s[i].addr); + s[i].size = ByteSwap(s[i].size); + + s[i].offset = ByteSwap(s[i].offset); + s[i].align = ByteSwap(s[i].align); + s[i].reloff = ByteSwap(s[i].reloff); + s[i].nreloc = ByteSwap(s[i].nreloc); + s[i].flags = ByteSwap(s[i].flags); + s[i].reserved1 = ByteSwap(s[i].reserved1); + s[i].reserved2 = ByteSwap(s[i].reserved2); + } +} + +void breakpad_swap_section_64(struct section_64 *s, + uint32_t nsects) { + for (uint32_t i = 0; i < nsects; i++) { + s[i].addr = ByteSwap(s[i].addr); + s[i].size = ByteSwap(s[i].size); + + s[i].offset = ByteSwap(s[i].offset); + s[i].align = ByteSwap(s[i].align); + s[i].reloff = ByteSwap(s[i].reloff); + s[i].nreloc = ByteSwap(s[i].nreloc); + s[i].flags = ByteSwap(s[i].flags); + s[i].reserved1 = ByteSwap(s[i].reserved1); + s[i].reserved2 = ByteSwap(s[i].reserved2); + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h new file mode 100644 index 0000000000..00563a77c8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.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. + +// macho_utilities.h: Utilities for dealing with mach-o files +// +// Author: Dave Camp + +#ifndef COMMON_MAC_MACHO_UTILITIES_H__ +#define COMMON_MAC_MACHO_UTILITIES_H__ + +#include +#include + +/* Some #defines and structs that aren't defined in older SDKs */ +#ifndef CPU_ARCH_ABI64 +# define CPU_ARCH_ABI64 0x01000000 +#endif + +#ifndef CPU_TYPE_X86 +# define CPU_TYPE_X86 CPU_TYPE_I386 +#endif + +#ifndef CPU_TYPE_POWERPC64 +# define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) +#endif + +#ifndef LC_UUID +# define LC_UUID 0x1b /* the uuid */ +#endif + +// The uuid_command struct/swap routines were added during the 10.4 series. +// Their presence isn't guaranteed. +struct breakpad_uuid_command { + uint32_t cmd; /* LC_UUID */ + uint32_t cmdsize; /* sizeof(struct uuid_command) */ + uint8_t uuid[16]; /* the 128-bit uuid */ +}; + +void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc); + +void breakpad_swap_load_command(struct load_command *lc); + +void breakpad_swap_dylib_command(struct dylib_command *dc); + +// Older SDKs defines thread_state_data_t as an int[] instead +// of the natural_t[] it should be. +typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX]; + +void breakpad_swap_segment_command(struct segment_command *sc); + +// The 64-bit swap routines were added during the 10.4 series, their +// presence isn't guaranteed. +void breakpad_swap_segment_command_64(struct segment_command_64 *sg); + +void breakpad_swap_fat_header(struct fat_header *fh); + +void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs); + +void breakpad_swap_mach_header(struct mach_header *mh); + +void breakpad_swap_mach_header_64(struct mach_header_64 *mh); + +void breakpad_swap_section(struct section *s, + uint32_t nsects); + +void breakpad_swap_section_64(struct section_64 *s, + uint32_t nsects); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc new file mode 100644 index 0000000000..a30f52c7e5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc @@ -0,0 +1,272 @@ +// 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. + +// macho_walker.cc: Iterate over the load commands in a mach-o file +// +// See macho_walker.h for documentation +// +// Author: Dan Waylonis + +#include +#include +#include +#include +#include +#include +#include + +#include "common/mac/byteswap.h" +#include "common/mac/macho_walker.h" +#include "common/mac/macho_utilities.h" + +namespace MacFileUtilities { + +MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, + void *context) + : file_(-1), + memory_(NULL), + memory_size_(0), + callback_(callback), + callback_context_(context), + current_header_(NULL), + current_header_size_(0), + current_header_offset_(0) { + file_ = open(path, O_RDONLY); +} + +MachoWalker::MachoWalker(void *memory, size_t size, + LoadCommandCallback callback, void *context) + : file_(-1), + memory_(memory), + memory_size_(size), + callback_(callback), + callback_context_(context), + current_header_(NULL), + current_header_size_(0), + current_header_offset_(0) { +} + +MachoWalker::~MachoWalker() { + if (file_ != -1) + close(file_); +} + +bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + cpu_type_t valid_cpu_type = cpu_type; + cpu_subtype_t valid_cpu_subtype = cpu_subtype; + // if |cpu_type| is 0, use the native cpu type. + if (cpu_type == 0) { + const NXArchInfo *arch = NXGetLocalArchInfo(); + assert(arch); + valid_cpu_type = arch->cputype; + valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; + } + off_t offset; + if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) { + if (cpu_type & CPU_ARCH_ABI64) + return WalkHeader64AtOffset(offset); + + return WalkHeaderAtOffset(offset); + } + + return false; +} + +bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { + if (memory_) { + if (offset < 0) + return false; + bool result = true; + if (offset + size > memory_size_) { + if (static_cast(offset) >= memory_size_) + return false; + size = memory_size_ - static_cast(offset); + result = false; + } + memcpy(buffer, static_cast(memory_) + offset, size); + return result; + } else { + return pread(file_, buffer, size, offset) == (ssize_t)size; + } +} + +bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { + if (current_header_) { + memcpy(header, current_header_, sizeof(mach_header_64)); + *offset = current_header_offset_; + return true; + } + + return false; +} + +bool MachoWalker::FindHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + off_t &offset) { + // Read the magic bytes that's common amongst all mach-o files + uint32_t magic; + if (!ReadBytes(&magic, sizeof(magic), 0)) + return false; + + offset = sizeof(magic); + + // Figure out what type of file we've got + bool is_fat = false; + if (magic == FAT_MAGIC || magic == FAT_CIGAM) { + is_fat = true; + } + else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 && + magic != MH_CIGAM_64) { + return false; + } + + if (!is_fat) { + // If we don't have a fat header, check if the cpu type matches the single + // header + struct mach_header header; + if (!ReadBytes(&header, sizeof(header), 0)) + return false; + + if (magic == MH_CIGAM || magic == MH_CIGAM_64) + breakpad_swap_mach_header(&header); + + header.cpusubtype &= ~CPU_SUBTYPE_MASK; + + if (cpu_type != header.cputype || + (cpu_subtype != CPU_SUBTYPE_MULTIPLE && + cpu_subtype != header.cpusubtype)) { + return false; + } + + offset = 0; + return true; + } else { + // Read the fat header and find an appropriate architecture + offset = 0; + struct fat_header fat; + if (!ReadBytes(&fat, sizeof(fat), offset)) + return false; + + if (NXHostByteOrder() != NX_BigEndian) + breakpad_swap_fat_header(&fat); + + offset += sizeof(fat); + + // Search each architecture for the desired one + struct fat_arch arch; + for (uint32_t i = 0; i < fat.nfat_arch; ++i) { + if (!ReadBytes(&arch, sizeof(arch), offset)) + return false; + + if (NXHostByteOrder() != NX_BigEndian) + breakpad_swap_fat_arch(&arch, 1); + + arch.cpusubtype &= ~CPU_SUBTYPE_MASK; + + if (arch.cputype == cpu_type && + (cpu_subtype == CPU_SUBTYPE_MULTIPLE || + arch.cpusubtype == cpu_subtype)) { + offset = arch.offset; + return true; + } + + offset += sizeof(arch); + } + } + + return false; +} + +bool MachoWalker::WalkHeaderAtOffset(off_t offset) { + struct mach_header header; + if (!ReadBytes(&header, sizeof(header), offset)) + return false; + + bool swap = (header.magic == MH_CIGAM); + if (swap) + breakpad_swap_mach_header(&header); + + // Copy the data into the mach_header_64 structure. Since the 32-bit and + // 64-bit only differ in the last field (reserved), this is safe to do. + struct mach_header_64 header64; + memcpy((void *)&header64, (const void *)&header, sizeof(header)); + header64.reserved = 0; + + current_header_ = &header64; + current_header_size_ = sizeof(header); // 32-bit, not 64-bit + current_header_offset_ = offset; + offset += current_header_size_; + bool result = WalkHeaderCore(offset, header.ncmds, swap); + current_header_ = NULL; + current_header_size_ = 0; + current_header_offset_ = 0; + return result; +} + +bool MachoWalker::WalkHeader64AtOffset(off_t offset) { + struct mach_header_64 header; + if (!ReadBytes(&header, sizeof(header), offset)) + return false; + + bool swap = (header.magic == MH_CIGAM_64); + if (swap) + breakpad_swap_mach_header_64(&header); + + current_header_ = &header; + current_header_size_ = sizeof(header); + current_header_offset_ = offset; + offset += current_header_size_; + bool result = WalkHeaderCore(offset, header.ncmds, swap); + current_header_ = NULL; + current_header_size_ = 0; + current_header_offset_ = 0; + return result; +} + +bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands, + bool swap) { + for (uint32_t i = 0; i < number_of_commands; ++i) { + struct load_command cmd; + if (!ReadBytes(&cmd, sizeof(cmd), offset)) + return false; + + if (swap) + breakpad_swap_load_command(&cmd); + + // Call the user callback + if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_)) + break; + + offset += cmd.cmdsize; + } + + return true; +} + +} // namespace MacFileUtilities diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h new file mode 100644 index 0000000000..dd535814a1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h @@ -0,0 +1,119 @@ +// 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. + +// macho_walker.h: Iterate over the load commands in a mach-o file +// +// Author: Dan Waylonis + +#ifndef COMMON_MAC_MACHO_WALKER_H__ +#define COMMON_MAC_MACHO_WALKER_H__ + +#include +#include +#include + +namespace MacFileUtilities { + +class MachoWalker { + public: + // A callback function executed when a new load command is read. If no + // further processing of load commands is desired, return false. Otherwise, + // return true. + // |cmd| is the current command, and |offset| is the location relative to the + // beginning of the file (not header) where the command was read. If |swap| + // is set, then any command data (other than the returned load_command) should + // be swapped when read + typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd, + off_t offset, bool swap, void *context); + + MachoWalker(const char *path, LoadCommandCallback callback, void *context); + MachoWalker(void *memory, size_t size, LoadCommandCallback callback, + void *context); + ~MachoWalker(); + + // Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type| + // is 0, then the native cpu type is used. Otherwise, accepted values are + // listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or + // CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is + // only done on |cpu_type|. + // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| + // is not present in the file. + bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + + // Read |size| bytes from the opened file at |offset| into |buffer| + bool ReadBytes(void *buffer, size_t size, off_t offset); + + // Return the current header and header offset + bool CurrentHeader(struct mach_header_64 *header, off_t *offset); + + private: + // Locate (if any) the header offset for |cpu_type| and return in |offset|. + // Return true if found, false otherwise. + bool FindHeader(cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype, + off_t &offset); + + // Process an individual header starting at |offset| from the start of the + // file. Return true if successful, false otherwise. + bool WalkHeaderAtOffset(off_t offset); + bool WalkHeader64AtOffset(off_t offset); + + // Bottleneck for walking the load commands + bool WalkHeaderCore(off_t offset, uint32_t number_of_commands, bool swap); + + // File descriptor to the opened file + int file_; + + // Memory location to read from. + void *memory_; + + // Size of the memory segment we can read from. + size_t memory_size_; + + // User specified callback & context + LoadCommandCallback callback_; + void *callback_context_; + + // Current header, size, and offset. The mach_header_64 is used for both + // 32-bit and 64-bit headers because they only differ in their last field + // (reserved). By adding the |current_header_size_| and the + // |current_header_offset_|, you can determine the offset in the file just + // after the header. + struct mach_header_64 *current_header_; + unsigned long current_header_size_; + off_t current_header_offset_; + + private: + MachoWalker(const MachoWalker &); + MachoWalker &operator=(const MachoWalker &); +}; + +} // namespace MacFileUtilities + +#endif // COMMON_MAC_MACHO_WALKER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build b/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build new file mode 100644 index 0000000000..23fc2207a4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build @@ -0,0 +1,27 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'arch_utilities.cc', + 'file_id.cc', + 'macho_id.cc', + 'macho_reader.cc', + 'macho_utilities.cc', + 'macho_walker.cc', +] + +SOURCES += [ + 'bootstrap_compat.cc', + 'HTTPMultipartUpload.m', + 'MachIPC.mm', + 'string_utilities.cc', +] + +Library('breakpad_mac_common_s') + +CMFLAGS += ['-std=c99'] + +include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h b/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h new file mode 100644 index 0000000000..d6d1bef971 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h @@ -0,0 +1,56 @@ +// Copyright (c) 2010 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. + +// Inline implementation of ScopedTaskSuspend, which suspends a Mach +// task for the duration of its scope. + +#ifndef GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ +#define GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ + +#include + +namespace google_breakpad { + +class ScopedTaskSuspend { + public: + explicit ScopedTaskSuspend(mach_port_t target) : target_(target) { + task_suspend(target_); + } + + ~ScopedTaskSuspend() { + task_resume(target_); + } + + private: + mach_port_t target_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc new file mode 100644 index 0000000000..07c0f42680 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc @@ -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. + +#include "common/scoped_ptr.h" +#include "common/mac/string_utilities.h" + +namespace MacStringUtils { + +using google_breakpad::scoped_array; + +std::string ConvertToString(CFStringRef str) { + CFIndex length = CFStringGetLength(str); + std::string result; + + if (!length) + return result; + + CFIndex maxUTF8Length = + CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + scoped_array buffer(new UInt8[maxUTF8Length + 1]); + CFIndex actualUTF8Length; + CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0, + false, buffer.get(), maxUTF8Length, &actualUTF8Length); + buffer[actualUTF8Length] = 0; + result.assign((const char *)buffer.get()); + + return result; +} + +unsigned int IntegerValueAtIndex(string &str, unsigned int idx) { + string digits("0123456789"), temp; + size_t start = 0; + size_t end; + size_t found = 0; + unsigned int result = 0; + + for (; found <= idx; ++found) { + end = str.find_first_not_of(digits, start); + + if (end == string::npos) + end = str.size(); + + temp = str.substr(start, end - start); + + if (found == idx) { + result = atoi(temp.c_str()); + } + + start = str.find_first_of(digits, end + 1); + + if (start == string::npos) + break; + } + + return result; +} + +} // namespace MacStringUtils diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h new file mode 100644 index 0000000000..6d89c834e7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h @@ -0,0 +1,52 @@ +// 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_utilities.h: Utilities for strings for Mac platform + +#ifndef COMMON_MAC_STRING_UTILITIES_H__ +#define COMMON_MAC_STRING_UTILITIES_H__ + +#include + +#include + +namespace MacStringUtils { + +using std::string; + +// Convert a CoreFoundation string into a std::string +string ConvertToString(CFStringRef str); + +// Return the idx'th decimal integer in str, separated by non-decimal-digits +// E.g., str = 10.4.8, idx = 1 -> 4 +unsigned int IntegerValueAtIndex(string &str, unsigned int idx); + +} // namespace MacStringUtils + +#endif // COMMON_MAC_STRING_UTILITIES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h b/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h new file mode 100644 index 0000000000..501c8652a1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h @@ -0,0 +1,88 @@ +// Copyright (c) 2015, 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. + +// Original author: Erik Chen + +// super_fat_arch.h: A class to handle 64-bit object files. Has conversions to +// and from struct fat_arch. + +#ifndef BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ +#define BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ + +#include +#include +#include + +// Similar to struct fat_arch, except size-related parameters support +// 64-bits. +class SuperFatArch { + public: + uint32_t cputype; + uint32_t cpusubtype; + uint64_t offset; + uint64_t size; + uint64_t align; + + SuperFatArch() : + cputype(0), + cpusubtype(0), + offset(0), + size(0), + align(0) { + } + + explicit SuperFatArch(const struct fat_arch &arch) : + cputype(arch.cputype), + cpusubtype(arch.cpusubtype), + offset(arch.offset), + size(arch.size), + align(arch.align) { + } + + // Returns false if the conversion cannot be made. + // If the conversion succeeds, the result is placed in |output_arch|. + bool ConvertToFatArch(struct fat_arch* output_arch) const { + if (offset > std::numeric_limits::max()) + return false; + if (size > std::numeric_limits::max()) + return false; + if (align > std::numeric_limits::max()) + return false; + struct fat_arch arch; + arch.cputype = cputype; + arch.cpusubtype = cpusubtype; + arch.offset = offset; + arch.size = size; + arch.align = align; + *output_arch = arch; + return true; + } +}; + +#endif // BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h new file mode 100644 index 0000000000..ce3d9022cd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h @@ -0,0 +1,1110 @@ +// +// GTMSenTestCase.h +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +// Portions of this file fall under the following license, marked with +// SENTE_BEGIN - SENTE_END +// +// Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. +// +// Use of this source code is governed by the following license: +// +// 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. +// +// 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 Sente SA 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. +// +// Note: this license is equivalent to the FreeBSD license. +// +// This notice may not be removed from this file. + +// Some extra test case macros that would have been convenient for SenTestingKit +// to provide. I didn't stick GTM in front of the Macro names, so that they would +// be easy to remember. + +#import "GTMDefines.h" + +#if (!GTM_IPHONE_SDK) || (GTM_IPHONE_USE_SENTEST) +#import +#else +#import +#ifdef __cplusplus +extern "C" { +#endif + +#if defined __clang__ +// gcc and gcc-llvm do not allow you to use STAssert(blah, nil) with nil +// as a description if you have the NS_FORMAT_FUNCTION on. +// clang however will not compile without warnings if you don't have it. +NSString *STComposeString(NSString *, ...) NS_FORMAT_FUNCTION(1, 2); +#else +NSString *STComposeString(NSString *, ...); +#endif // __clang__ + +#ifdef __cplusplus +} +#endif + +#endif // !GTM_IPHONE_SDK || GTM_IPHONE_USE_SENTEST + +// Generates a failure when a1 != noErr +// Args: +// a1: should be either an OSErr or an OSStatus +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNoErr(a1, description, ...) \ +do { \ + @try { \ + OSStatus a1value = (a1); \ + if (a1value != noErr) { \ + NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", (long)a1value, #a1]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when a1 != a2 +// Args: +// a1: received value. Should be either an OSErr or an OSStatus +// a2: expected value. Should be either an OSErr or an OSStatus +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertErr(a1, a2, description, ...) \ +do { \ + @try { \ + OSStatus a1value = (a1); \ + OSStatus a2value = (a2); \ + if (a1value != a2value) { \ + NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, (long)a2value, (long)a1value, #a1]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s) fails", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + + +// Generates a failure when a1 is NULL +// Args: +// a1: should be a pointer (use STAssertNotNil for an object) +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotNULL(a1, description, ...) \ +do { \ + @try { \ + __typeof__(a1) a1value = (a1); \ + if (a1value == (__typeof__(a1))NULL) { \ + NSString *_expression = [NSString stringWithFormat:@"((%s) != NULL)", #a1]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != NULL fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when a1 is not NULL +// Args: +// a1: should be a pointer (use STAssertNil for an object) +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNULL(a1, description, ...) \ +do { \ + @try { \ + __typeof__(a1) a1value = (a1); \ + if (a1value != (__typeof__(a1))NULL) { \ + NSString *_expression = [NSString stringWithFormat:@"((%s) == NULL)", #a1]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == NULL fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when a1 is equal to a2. This test is for C scalars, +// structs and unions. +// Args: +// a1: argument 1 +// a2: argument 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEquals(a1, a2, description, ...) \ +do { \ + @try { \ + if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ + if ([a1encoded isEqualToValue:a2encoded]) { \ + NSString *_expression = [NSString stringWithFormat:@"((%s) != (%s))", #a1, #a2]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + }\ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when a1 is equal to a2. This test is for objects. +// Args: +// a1: argument 1. object. +// a2: argument 2. object. +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualObjects(a1, a2, description, ...) \ +do { \ + @try {\ + id a1value = (a1); \ + id a2value = (a2); \ + if ( (strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \ + (strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \ + (![(id)a1value isEqual:(id)a2value]) ) continue; \ + [self failWithException:([NSException failureInEqualityBetweenObject:a1value \ + andObject:a2value \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + }\ + @catch (id anException) {\ + [self failWithException:([NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + }\ +} while(0) + +// Generates a failure when a1 is not 'op' to a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertOperation(a1, a2, op, description, ...) \ +do { \ + @try { \ + if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + if (!(a1value op a2value)) { \ + double a1DoubleValue = a1value; \ + double a2DoubleValue = a2value; \ + NSString *_expression = [NSString stringWithFormat:@"(%s (%lg) %s %s (%lg))", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \ + [self failWithException:([NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ + } \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException \ + failureInRaise:[NSString stringWithFormat:@"(%s) %s (%s)", #a1, #op, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when a1 is not > a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertGreaterThan(a1, a2, description, ...) \ + STAssertOperation(a1, a2, >, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not >= a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertGreaterThanOrEqual(a1, a2, description, ...) \ + STAssertOperation(a1, a2, >=, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not < a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertLessThan(a1, a2, description, ...) \ + STAssertOperation(a1, a2, <, description, ##__VA_ARGS__) + +// Generates a failure when a1 is not <= a2. This test is for C scalars. +// Args: +// a1: argument 1 +// a2: argument 2 +// op: operation +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertLessThanOrEqual(a1, a2, description, ...) \ + STAssertOperation(a1, a2, <=, description, ##__VA_ARGS__) + +// Generates a failure when string a1 is not equal to string a2. This call +// differs from STAssertEqualObjects in that strings that are different in +// composition (precomposed vs decomposed) will compare equal if their final +// representation is equal. +// ex O + umlaut decomposed is the same as O + umlaut composed. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertEqualStrings(a1, a2, description, ...) \ +do { \ + @try { \ + id a1value = (a1); \ + id a2value = (a2); \ + if (a1value == a2value) continue; \ + if ([a1value isKindOfClass:[NSString class]] && \ + [a2value isKindOfClass:[NSString class]] && \ + [a1value compare:a2value options:0] == NSOrderedSame) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ + andObject:a2value \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when string a1 is equal to string a2. This call +// differs from STAssertEqualObjects in that strings that are different in +// composition (precomposed vs decomposed) will compare equal if their final +// representation is equal. +// ex O + umlaut decomposed is the same as O + umlaut composed. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualStrings(a1, a2, description, ...) \ +do { \ + @try { \ + id a1value = (a1); \ + id a2value = (a2); \ + if ([a1value isKindOfClass:[NSString class]] && \ + [a2value isKindOfClass:[NSString class]] && \ + [a1value compare:a2value options:0] != NSOrderedSame) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ + andObject:a2value \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when c-string a1 is not equal to c-string a2. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertEqualCStrings(a1, a2, description, ...) \ +do { \ + @try { \ + const char* a1value = (a1); \ + const char* a2value = (a2); \ + if (a1value == a2value) continue; \ + if (strcmp(a1value, a2value) == 0) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject:[NSString stringWithUTF8String:a1value] \ + andObject:[NSString stringWithUTF8String:a2value] \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +// Generates a failure when c-string a1 is equal to c-string a2. +// Args: +// a1: string 1 +// a2: string 2 +// description: A format string as in the printf() function. Can be nil or +// an empty string but must be present. +// ...: A variable number of arguments to the format string. Can be absent. +#define STAssertNotEqualCStrings(a1, a2, description, ...) \ +do { \ + @try { \ + const char* a1value = (a1); \ + const char* a2value = (a2); \ + if (strcmp(a1value, a2value) != 0) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject:[NSString stringWithUTF8String:a1value] \ + andObject:[NSString stringWithUTF8String:a2value] \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. + This test is for GLKit types (GLKVector, GLKMatrix) where small differences + could make these items not exactly equal. Do not use this version directly. + Use the explicit STAssertEqualGLKVectors and STAssertEqualGLKMatrices defined + below. + _{a1 The GLKType on the left.} + _{a2 The GLKType on the right.} + _{accuracy The maximum difference between a1 and a2 for these values to be + considered equal.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ + +#define STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ...) \ +do { \ + @try { \ + if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ + } else { \ + __typeof__(a1) a1GLKValue = (a1); \ + __typeof__(a2) a2GLKValue = (a2); \ + __typeof__(accuracy) accuracyvalue = (accuracy); \ + float *a1FloatValue = ((float*)&a1GLKValue); \ + float *a2FloatValue = ((float*)&a2GLKValue); \ + for (size_t i = 0; i < sizeof(__typeof__(a1)) / sizeof(float); ++i) { \ + float a1value = a1FloatValue[i]; \ + float a2value = a2FloatValue[i]; \ + if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \ + NSMutableArray *strings = [NSMutableArray arrayWithCapacity:sizeof(a1) / sizeof(float)]; \ + NSString *string; \ + for (size_t j = 0; j < sizeof(__typeof__(a1)) / sizeof(float); ++j) { \ + string = [NSString stringWithFormat:@"(%0.3f == %0.3f)", a1FloatValue[j], a2FloatValue[j]]; \ + [strings addObject:string]; \ + } \ + string = [strings componentsJoinedByString:@", "]; \ + NSString *desc = STComposeString(description, ##__VA_ARGS__); \ + desc = [NSString stringWithFormat:@"%@ With Accuracy %0.3f: %@", string, (float)accuracyvalue, desc]; \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", desc]]; \ + break; \ + } \ + } \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +#define STAssertEqualGLKVectors(a1, a2, accuracy, description, ...) \ + STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) + +#define STAssertEqualGLKMatrices(a1, a2, accuracy, description, ...) \ + STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) + +#define STAssertEqualGLKQuaternions(a1, a2, accuracy, description, ...) \ + STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) + +#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST +// When not using the Xcode provided version, define everything ourselves. + +// SENTE_BEGIN +/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false + (or one is nil and the other is not). + _{a1 The object on the left.} + _{a2 The object on the right.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertEqualObjects(a1, a2, description, ...) \ +do { \ + @try { \ + id a1value = (a1); \ + id a2value = (a2); \ + if (a1value == a2value) continue; \ + if ((strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \ + (strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \ + [(id)a1value isEqual:(id)a2value]) continue; \ + [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ + andObject:a2value \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + + +/*" Generates a failure when a1 is not equal to a2. This test is for + C scalars, structs and unions. + _{a1 The argument on the left.} + _{a2 The argument on the right.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertEquals(a1, a2, description, ...) \ +do { \ + @try { \ + if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ + if (![a1encoded isEqualToValue:a2encoded]) { \ + [self failWithException:[NSException failureInEqualityBetweenValue:a1encoded \ + andValue:a2encoded \ + withAccuracy:nil \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + +#define STAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right)) + + +/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. + This test is for scalars such as floats and doubles where small differences + could make these items not exactly equal, but also works for all scalars. + _{a1 The scalar on the left.} + _{a2 The scalar on the right.} + _{accuracy The maximum difference between a1 and a2 for these values to be + considered equal.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ + +#define STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \ +do { \ + @try { \ + if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ + [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ + } else { \ + __typeof__(a1) a1value = (a1); \ + __typeof__(a2) a2value = (a2); \ + __typeof__(accuracy) accuracyvalue = (accuracy); \ + if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \ + NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ + NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ + NSValue *accuracyencoded = [NSValue value:&accuracyvalue withObjCType:@encode(__typeof__(accuracy))]; \ + [self failWithException:[NSException failureInEqualityBetweenValue:a1encoded \ + andValue:a2encoded \ + withAccuracy:accuracyencoded \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + + + +/*" Generates a failure unconditionally. + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STFail(description, ...) \ +[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]] + + + +/*" Generates a failure when a1 is not nil. + _{a1 An object.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNil(a1, description, ...) \ +do { \ + @try { \ + id a1value = (a1); \ + if (a1value != nil) { \ + NSString *_a1 = [NSString stringWithUTF8String:#a1]; \ + NSString *_expression = [NSString stringWithFormat:@"((%@) == nil)", _a1]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == nil fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + + +/*" Generates a failure when a1 is nil. + _{a1 An object.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNotNil(a1, description, ...) \ +do { \ + @try { \ + id a1value = (a1); \ + if (a1value == nil) { \ + NSString *_a1 = [NSString stringWithUTF8String:#a1]; \ + NSString *_expression = [NSString stringWithFormat:@"((%@) != nil)", _a1]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != nil fails", #a1] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while(0) + + +/*" Generates a failure when expression evaluates to false. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertTrue(expr, description, ...) \ +do { \ + BOOL _evaluatedExpression = (expr); \ + if (!_evaluatedExpression) { \ + NSString *_expression = [NSString stringWithUTF8String:#expr]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when expression evaluates to false and in addition will + generate error messages if an exception is encountered. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertTrueNoThrow(expr, description, ...) \ +do { \ + @try { \ + BOOL _evaluatedExpression = (expr); \ + if (!_evaluatedExpression) { \ + NSString *_expression = [NSString stringWithUTF8String:#expr]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:NO \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) ", #expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when the expression evaluates to true. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertFalse(expr, description, ...) \ +do { \ + BOOL _evaluatedExpression = (expr); \ + if (_evaluatedExpression) { \ + NSString *_expression = [NSString stringWithUTF8String:#expr]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:YES \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when the expression evaluates to true and in addition + will generate error messages if an exception is encountered. + _{expr The expression that is tested.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertFalseNoThrow(expr, description, ...) \ +do { \ + @try { \ + BOOL _evaluatedExpression = (expr); \ + if (_evaluatedExpression) { \ + NSString *_expression = [NSString stringWithUTF8String:#expr]; \ + [self failWithException:[NSException failureInCondition:_expression \ + isTrue:YES \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"!(%s) ", #expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when expression does not throw an exception. + _{expression The expression that is evaluated.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent. +"*/ +#define STAssertThrows(expr, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (id anException) { \ + continue; \ + } \ + [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:nil \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does not throw an exception of a + specific class. + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertThrowsSpecific(expr, specificException, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (specificException *anException) { \ + continue; \ + } \ + @catch (id anException) { \ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ + [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + } \ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ + [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:nil \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does not throw an exception of a + specific class with a specific name. Useful for those frameworks like + AppKit or Foundation that throw generic NSException w/specific names + (NSInvalidArgumentException, etc). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{aName The name of the specified exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} + +"*/ +#define STAssertThrowsSpecificNamed(expr, specificException, aName, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (specificException *anException) { \ + if ([aName isEqualToString:[anException name]]) continue; \ + NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description); \ + [self failWithException: \ + [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + } \ + @catch (id anException) { \ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ + [self failWithException: \ + [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ + continue; \ + } \ + NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ + [self failWithException: \ + [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:nil \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ +} while (0) + + +/*" Generates a failure when expression does throw an exception. + _{expression The expression that is evaluated.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNoThrow(expr, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (id anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ +} while (0) + + +/*" Generates a failure when expression does throw an exception of the specitied + class. Any other exception is okay (i.e. does not generate a failure). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} +"*/ +#define STAssertNoThrowSpecific(expr, specificException, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (specificException *anException) { \ + [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ + } \ + @catch (id anythingElse) { \ + ; \ + } \ +} while (0) + + +/*" Generates a failure when expression does throw an exception of a + specific class with a specific name. Useful for those frameworks like + AppKit or Foundation that throw generic NSException w/specific names + (NSInvalidArgumentException, etc). + _{expression The expression that is evaluated.} + _{specificException The specified class of the exception.} + _{aName The name of the specified exception.} + _{description A format string as in the printf() function. Can be nil or + an empty string but must be present.} + _{... A variable number of arguments to the format string. Can be absent.} + +"*/ +#define STAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...) \ +do { \ + @try { \ + (expr); \ + } \ + @catch (specificException *anException) { \ + if ([aName isEqualToString:[anException name]]) { \ + NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description); \ + [self failWithException: \ + [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ + exception:anException \ + inFile:[NSString stringWithUTF8String:__FILE__] \ + atLine:__LINE__ \ + withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ + } \ + continue; \ + } \ + @catch (id anythingElse) { \ + ; \ + } \ +} while (0) + + + +@interface NSException (GTMSenTestAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(3, 4); ++ (NSException *)failureInCondition:(NSString *)condition + isTrue:(BOOL)isTrue + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); ++ (NSException *)failureInEqualityBetweenObject:(id)left + andObject:(id)right + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); ++ (NSException *)failureInEqualityBetweenValue:(NSValue *)left + andValue:(NSValue *)right + withAccuracy:(NSValue *)accuracy + inFile:(NSString *)filename + atLine:(int) ineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(6, 7); ++ (NSException *)failureInRaise:(NSString *)expression + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(4, 5); ++ (NSException *)failureInRaise:(NSString *)expression + exception:(NSException *)exception + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); +@end + +// SENTE_END + +@protocol SenTestCase ++ (id)testCaseWithInvocation:(NSInvocation *)anInvocation; +- (id)initWithInvocation:(NSInvocation *)anInvocation; +- (void)setUp; +- (void)invokeTest; +- (void)tearDown; +- (void)performTest; +- (void)failWithException:(NSException*)exception; +- (NSInvocation *)invocation; +- (SEL)selector; ++ (NSArray *)testInvocations; +@end + +@interface SenTestCase : NSObject { + @private + NSInvocation *invocation_; +} +@end + +GTM_EXTERN NSString *const SenTestFailureException; + +GTM_EXTERN NSString *const SenTestFilenameKey; +GTM_EXTERN NSString *const SenTestLineNumberKey; + +#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST + +// All unittest cases in GTM should inherit from GTMTestCase. It makes sure +// to set up our logging system correctly to verify logging calls. +// See GTMUnitTestDevLog.h for details +@interface GTMTestCase : SenTestCase + +// Returns YES if this is an abstract testCase class as opposed to a concrete +// testCase class that you want tests run against. SenTestCase is not designed +// out of the box to handle an abstract class hierarchy descending from it with +// some concrete subclasses. In some cases we want all the "concrete" +// subclasses of an abstract subclass of SenTestCase to run a test, but we don't +// want that test to be run against an instance of an abstract subclass itself. +// By returning "YES" here, the tests defined by this class won't be run against +// an instance of this class. As an example class hierarchy: +// +// FooExtensionTestCase +// GTMTestCase <- ExtensionAbstractTestCase < +// BarExtensionTestCase +// +// So FooExtensionTestCase and BarExtensionTestCase inherit from +// ExtensionAbstractTestCase (and probably FooExtension and BarExtension inherit +// from a class named Extension). We want the tests in ExtensionAbstractTestCase +// to be run as part of FooExtensionTestCase and BarExtensionTestCase, but we +// don't want them run against ExtensionAbstractTestCase. The default +// implementation checks to see if the name of the class contains the word +// "AbstractTest" (case sensitive). ++ (BOOL)isAbstractTestCase; + +@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m new file mode 100644 index 0000000000..162f01e97c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m @@ -0,0 +1,428 @@ +// +// GTMSenTestCase.m +// +// Copyright 2007-2008 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +// + +#import "GTMSenTestCase.h" + +#import +#if GTM_IPHONE_SIMULATOR +#import +#endif + +#import "GTMObjC2Runtime.h" +#import "GTMUnitTestDevLog.h" + +#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST +#import + +@interface NSException (GTMSenTestPrivateAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + reason:(NSString *)reason; +@end + +@implementation NSException (GTMSenTestPrivateAdditions) ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + reason:(NSString *)reason { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey, + filename, SenTestFilenameKey, + nil]; + + return [self exceptionWithName:SenTestFailureException + reason:reason + userInfo:userInfo]; +} +@end + +@implementation NSException (GTMSenTestAdditions) + ++ (NSException *)failureInFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = testDescription; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInCondition:(NSString *)condition + isTrue:(BOOL)isTrue + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@", + condition, isTrue ? "false" : "true", testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInEqualityBetweenObject:(id)left + andObject:(id)right + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", + [left description], [right description], testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInEqualityBetweenValue:(NSValue *)left + andValue:(NSValue *)right + withAccuracy:(NSValue *)accuracy + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason; + if (accuracy) { + reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", + left, right, testDescription]; + } else { + reason = + [NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@", + left, right, accuracy, testDescription]; + } + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInRaise:(NSString *)expression + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@", + expression, testDescription]; + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + ++ (NSException *)failureInRaise:(NSString *)expression + exception:(NSException *)exception + inFile:(NSString *)filename + atLine:(int)lineNumber + withDescription:(NSString *)formatString, ... { + + NSString *testDescription = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + testDescription = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + + NSString *reason; + if ([[exception name] isEqualToString:SenTestFailureException]) { + // it's our exception, assume it has the right description on it. + reason = [exception reason]; + } else { + // not one of our exception, use the exceptions reason and our description + reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@", + expression, [exception reason], testDescription]; + } + + return [self failureInFile:filename atLine:lineNumber reason:reason]; +} + +@end + +NSString *STComposeString(NSString *formatString, ...) { + NSString *reason = @""; + if (formatString) { + va_list vl; + va_start(vl, formatString); + reason = + [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; + va_end(vl); + } + return reason; +} + +NSString *const SenTestFailureException = @"SenTestFailureException"; +NSString *const SenTestFilenameKey = @"SenTestFilenameKey"; +NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey"; + +@interface SenTestCase (SenTestCasePrivate) +// our method of logging errors ++ (void)printException:(NSException *)exception fromTestName:(NSString *)name; +@end + +@implementation SenTestCase ++ (id)testCaseWithInvocation:(NSInvocation *)anInvocation { + return [[[self alloc] initWithInvocation:anInvocation] autorelease]; +} + +- (id)initWithInvocation:(NSInvocation *)anInvocation { + if ((self = [super init])) { + invocation_ = [anInvocation retain]; + } + return self; +} + +- (void)dealloc { + [invocation_ release]; + [super dealloc]; +} + +- (void)failWithException:(NSException*)exception { + [exception raise]; +} + +- (void)setUp { +} + +- (void)performTest { + @try { + [self invokeTest]; + } @catch (NSException *exception) { + [[self class] printException:exception + fromTestName:NSStringFromSelector([self selector])]; + [exception raise]; + } +} + +- (NSInvocation *)invocation { + return invocation_; +} + +- (SEL)selector { + return [invocation_ selector]; +} + ++ (void)printException:(NSException *)exception fromTestName:(NSString *)name { + NSDictionary *userInfo = [exception userInfo]; + NSString *filename = [userInfo objectForKey:SenTestFilenameKey]; + NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey]; + NSString *className = NSStringFromClass([self class]); + if ([filename length] == 0) { + filename = @"Unknown.m"; + } + fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n", + [filename UTF8String], + (long)[lineNumber integerValue], + [className UTF8String], + [name UTF8String], + [[exception reason] UTF8String]); + fflush(stderr); +} + +- (void)invokeTest { + NSException *e = nil; + @try { + // Wrap things in autorelease pools because they may + // have an STMacro in their dealloc which may get called + // when the pool is cleaned up + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + // We don't log exceptions here, instead we let the person that called + // this log the exception. This ensures they are only logged once but the + // outer layers get the exceptions to report counts, etc. + @try { + [self setUp]; + @try { + NSInvocation *invocation = [self invocation]; +#if GTM_IPHONE_SIMULATOR + // We don't call [invocation invokeWithTarget:self]; because of + // Radar 8081169: NSInvalidArgumentException can't be caught + // It turns out that on iOS4 (and 3.2) exceptions thrown inside an + // [invocation invoke] on the simulator cannot be caught. + // http://openradar.appspot.com/8081169 + objc_msgSend(self, [invocation selector]); +#else + [invocation invokeWithTarget:self]; +#endif + } @catch (NSException *exception) { + e = [exception retain]; + } + [self tearDown]; + } @catch (NSException *exception) { + e = [exception retain]; + } + [pool release]; + } @catch (NSException *exception) { + e = [exception retain]; + } + if (e) { + [e autorelease]; + [e raise]; + } +} + +- (void)tearDown { +} + +- (NSString *)description { + // This matches the description OCUnit would return to you + return [NSString stringWithFormat:@"-[%@ %@]", [self class], + NSStringFromSelector([self selector])]; +} + +// Used for sorting methods below +static int MethodSort(id a, id b, void *context) { + NSInvocation *invocationA = a; + NSInvocation *invocationB = b; + const char *nameA = sel_getName([invocationA selector]); + const char *nameB = sel_getName([invocationB selector]); + return strcmp(nameA, nameB); +} + + ++ (NSArray *)testInvocations { + NSMutableArray *invocations = nil; + // Need to walk all the way up the parent classes collecting methods (in case + // a test is a subclass of another test). + Class senTestCaseClass = [SenTestCase class]; + for (Class currentClass = self; + currentClass && (currentClass != senTestCaseClass); + currentClass = class_getSuperclass(currentClass)) { + unsigned int methodCount; + Method *methods = class_copyMethodList(currentClass, &methodCount); + if (methods) { + // This handles disposing of methods for us even if an exception should fly. + [NSData dataWithBytesNoCopy:methods + length:sizeof(Method) * methodCount]; + if (!invocations) { + invocations = [NSMutableArray arrayWithCapacity:methodCount]; + } + for (size_t i = 0; i < methodCount; ++i) { + Method currMethod = methods[i]; + SEL sel = method_getName(currMethod); + char *returnType = NULL; + const char *name = sel_getName(sel); + // If it starts with test, takes 2 args (target and sel) and returns + // void run it. + if (strstr(name, "test") == name) { + returnType = method_copyReturnType(currMethod); + if (returnType) { + // This handles disposing of returnType for us even if an + // exception should fly. Length +1 for the terminator, not that + // the length really matters here, as we never reference inside + // the data block. + [NSData dataWithBytesNoCopy:returnType + length:strlen(returnType) + 1]; + } + } + // TODO: If a test class is a subclass of another, and they reuse the + // same selector name (ie-subclass overrides it), this current loop + // and test here will cause cause it to get invoked twice. To fix this + // the selector would have to be checked against all the ones already + // added, so it only gets done once. + if (returnType // True if name starts with "test" + && strcmp(returnType, @encode(void)) == 0 + && method_getNumberOfArguments(currMethod) == 2) { + NSMethodSignature *sig = [self instanceMethodSignatureForSelector:sel]; + NSInvocation *invocation + = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setSelector:sel]; + [invocations addObject:invocation]; + } + } + } + } + // Match SenTestKit and run everything in alphbetical order. + [invocations sortUsingFunction:MethodSort context:nil]; + return invocations; +} + +@end + +#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST + +@implementation GTMTestCase : SenTestCase +- (void)invokeTest { + NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; + Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog"); + if (devLogClass) { + [devLogClass performSelector:@selector(enableTracking)]; + [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; + + } + [super invokeTest]; + if (devLogClass) { + [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; + [devLogClass performSelector:@selector(disableTracking)]; + } + [localPool drain]; +} + ++ (BOOL)isAbstractTestCase { + NSString *name = NSStringFromClass(self); + return [name rangeOfString:@"AbstractTest"].location != NSNotFound; +} + ++ (NSArray *)testInvocations { + NSArray *invocations = nil; + if (![self isAbstractTestCase]) { + invocations = [super testInvocations]; + } + return invocations; +} + +@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/macros.h b/toolkit/crashreporter/google-breakpad/src/common/macros.h new file mode 100644 index 0000000000..14bb3f7bd3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/macros.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019, 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 BREAKPAD_COMMON_MACROS_H_ +#define BREAKPAD_COMMON_MACROS_H_ + +// Ensure that this macro definition stays in a private header file: clang +// suggests the first macro expanding to [[clang::fallthrough]] in its +// diagnostics, so if BP_FALLTHROUGH is visible in code depending on breakpad, +// clang would suggest BP_FALLTHROUGH for code depending on breakpad, instead of +// the client code's own fallthrough macro. +// TODO(thakis): Once everyone uses C++17, use its [[fallthrough]] instead. +#if defined(__clang__) +#define BP_FALLTHROUGH [[clang::fallthrough]] +#else +#define BP_FALLTHROUGH +#endif + +#endif // BREAKPAD_COMMON_MACROS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/md5.cc b/toolkit/crashreporter/google-breakpad/src/common/md5.cc new file mode 100644 index 0000000000..4f1ac8cad4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/md5.cc @@ -0,0 +1,251 @@ +/* + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include + +#include "common/md5.h" + +namespace google_breakpad { + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +static void MD5Transform(u32 buf[4], u32 const in[16]); + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + memcpy(&ctx->in[14], &ctx->bits[0], sizeof(u32)); + memcpy(&ctx->in[15], &ctx->bits[1], sizeof(u32)); + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(u32 buf[4], u32 const in[16]) +{ + u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +} // namespace google_breakpad + diff --git a/toolkit/crashreporter/google-breakpad/src/common/md5.h b/toolkit/crashreporter/google-breakpad/src/common/md5.h new file mode 100644 index 0000000000..2ab0ab95ae --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/md5.h @@ -0,0 +1,27 @@ +// Copyright 2007 Google Inc. All Rights Reserved. +// Author: liuli@google.com (Liu Li) +#ifndef COMMON_MD5_H__ +#define COMMON_MD5_H__ + +#include + +namespace google_breakpad { + +typedef uint32_t u32; +typedef uint8_t u8; + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void MD5Init(struct MD5Context *ctx); + +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len); + +void MD5Final(unsigned char digest[16], struct MD5Context *ctx); + +} // namespace google_breakpad + +#endif // COMMON_MD5_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_allocator.h b/toolkit/crashreporter/google-breakpad/src/common/memory_allocator.h new file mode 100644 index 0000000000..b7f9168c14 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/memory_allocator.h @@ -0,0 +1,252 @@ +// Copyright (c) 2009, 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_COMMON_MEMORY_ALLOCATOR_H_ +#define GOOGLE_BREAKPAD_COMMON_MEMORY_ALLOCATOR_H_ + +#include +#include +#include +#include + +#include +#include + +#if defined(MEMORY_SANITIZER) +#include +#endif + +#if defined(__APPLE__) || defined(__FreeBSD__) +#define sys_mmap mmap +#define sys_munmap munmap +#define MAP_ANONYMOUS MAP_ANON +#else +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace google_breakpad { + +// This is very simple allocator which fetches pages from the kernel directly. +// Thus, it can be used even when the heap may be corrupted. +// +// There is no free operation. The pages are only freed when the object is +// destroyed. +class PageAllocator { + public: + PageAllocator() + : page_size_(getpagesize()), + last_(NULL), + current_page_(NULL), + page_offset_(0), + pages_allocated_(0) { + } + + ~PageAllocator() { + FreeAll(); + } + + void *Alloc(size_t bytes) { + if (!bytes) + return NULL; + + if (current_page_ && page_size_ - page_offset_ >= bytes) { + uint8_t *const ret = current_page_ + page_offset_; + page_offset_ += bytes; + if (page_offset_ == page_size_) { + page_offset_ = 0; + current_page_ = NULL; + } + + return ret; + } + + const size_t pages = + (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; + uint8_t *const ret = GetNPages(pages); + if (!ret) + return NULL; + + page_offset_ = + (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % + page_size_; + current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; + + return ret + sizeof(PageHeader); + } + + // Checks whether the page allocator owns the passed-in pointer. + // This method exists for testing pursposes only. + bool OwnsPointer(const void* p) { + for (PageHeader* header = last_; header; header = header->next) { + const char* current = reinterpret_cast(header); + if ((p >= current) && (p < current + header->num_pages * page_size_)) + return true; + } + + return false; + } + + unsigned long pages_allocated() { return pages_allocated_; } + + private: + uint8_t *GetNPages(size_t num_pages) { + void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (a == MAP_FAILED) + return NULL; + +#if defined(MEMORY_SANITIZER) + // We need to indicate to MSan that memory allocated through sys_mmap is + // initialized, since linux_syscall_support.h doesn't have MSan hooks. + __msan_unpoison(a, page_size_ * num_pages); +#endif + + struct PageHeader *header = reinterpret_cast(a); + header->next = last_; + header->num_pages = num_pages; + last_ = header; + + pages_allocated_ += num_pages; + + return reinterpret_cast(a); + } + + void FreeAll() { + PageHeader *next; + + for (PageHeader *cur = last_; cur; cur = next) { + next = cur->next; + sys_munmap(cur, cur->num_pages * page_size_); + } + } + + struct PageHeader { + PageHeader *next; // pointer to the start of the next set of pages. + size_t num_pages; // the number of pages in this set. + }; + + const size_t page_size_; + PageHeader *last_; + uint8_t *current_page_; + size_t page_offset_; + unsigned long pages_allocated_; +}; + +// Wrapper to use with STL containers +template +struct PageStdAllocator { + using AllocatorTraits = std::allocator_traits>; + using value_type = typename AllocatorTraits::value_type; + using pointer = typename AllocatorTraits::pointer; + using difference_type = typename AllocatorTraits::difference_type; + using size_type = typename AllocatorTraits::size_type; + + explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator), + stackdata_(NULL), + stackdata_size_(0) + {} + + template PageStdAllocator(const PageStdAllocator& other) + : allocator_(other.allocator_), + stackdata_(nullptr), + stackdata_size_(0) + {} + + explicit PageStdAllocator(PageAllocator& allocator, + pointer stackdata, + size_type stackdata_size) : allocator_(allocator), + stackdata_(stackdata), + stackdata_size_(stackdata_size) + {} + + inline pointer allocate(size_type n, const void* = 0) { + const size_type size = sizeof(T) * n; + if (size <= stackdata_size_) { + return stackdata_; + } + return static_cast(allocator_.Alloc(size)); + } + + inline void deallocate(pointer, size_type) { + // The PageAllocator doesn't free. + } + + template struct rebind { + typedef PageStdAllocator other; + }; + + private: + // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will + // otherwise complain that `other.allocator_` is private in the constructor + // code. + template friend struct PageStdAllocator; + + PageAllocator& allocator_; + pointer stackdata_; + size_type stackdata_size_; +}; + +// A wasteful vector is a std::vector, except that it allocates memory from a +// PageAllocator. It's wasteful because, when resizing, it always allocates a +// whole new array since the PageAllocator doesn't support realloc. +template +class wasteful_vector : public std::vector > { + public: + wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) + : std::vector >(PageStdAllocator(*allocator)) { + std::vector >::reserve(size_hint); + } + protected: + wasteful_vector(PageStdAllocator allocator) + : std::vector >(allocator) {} +}; + +// auto_wasteful_vector allocates space on the stack for N entries to avoid +// using the PageAllocator for small data, while still allowing for larger data. +template +class auto_wasteful_vector : public wasteful_vector { + T stackdata_[N]; + public: + auto_wasteful_vector(PageAllocator* allocator) + : wasteful_vector( + PageStdAllocator(*allocator, + &stackdata_[0], + sizeof(stackdata_))) { + std::vector >::reserve(N); + } +}; + +} // namespace google_breakpad + +inline void* operator new(size_t nbytes, + google_breakpad::PageAllocator& allocator) { + return allocator.Alloc(nbytes); +} + +#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_ALLOCATOR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_allocator_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/memory_allocator_unittest.cc new file mode 100644 index 0000000000..43c86314c6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/memory_allocator_unittest.cc @@ -0,0 +1,124 @@ +// Copyright (c) 2009, 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 "breakpad_googletest_includes.h" +#include "common/memory_allocator.h" + +using namespace google_breakpad; + +namespace { +typedef testing::Test PageAllocatorTest; +} + +TEST(PageAllocatorTest, Setup) { + PageAllocator allocator; + EXPECT_EQ(0U, allocator.pages_allocated()); +} + +TEST(PageAllocatorTest, SmallObjects) { + PageAllocator allocator; + + EXPECT_EQ(0U, allocator.pages_allocated()); + for (unsigned i = 1; i < 1024; ++i) { + uint8_t *p = reinterpret_cast(allocator.Alloc(i)); + ASSERT_FALSE(p == NULL); + memset(p, 0, i); + } +} + +TEST(PageAllocatorTest, LargeObject) { + PageAllocator allocator; + + EXPECT_EQ(0U, allocator.pages_allocated()); + uint8_t *p = reinterpret_cast(allocator.Alloc(10000)); + ASSERT_FALSE(p == NULL); + EXPECT_EQ(3U, allocator.pages_allocated()); + for (unsigned i = 1; i < 10; ++i) { + uint8_t *p = reinterpret_cast(allocator.Alloc(i)); + ASSERT_FALSE(p == NULL); + memset(p, 0, i); + } +} + +namespace { +typedef testing::Test WastefulVectorTest; +} + +TEST(WastefulVectorTest, Setup) { + PageAllocator allocator_; + wasteful_vector v(&allocator_); + ASSERT_TRUE(v.empty()); + ASSERT_EQ(v.size(), 0u); +} + +TEST(WastefulVectorTest, Simple) { + PageAllocator allocator_; + EXPECT_EQ(0U, allocator_.pages_allocated()); + wasteful_vector v(&allocator_); + + for (unsigned i = 0; i < 256; ++i) { + v.push_back(i); + ASSERT_EQ(i, v.back()); + ASSERT_EQ(&v.back(), &v[i]); + } + ASSERT_FALSE(v.empty()); + ASSERT_EQ(v.size(), 256u); + EXPECT_EQ(1U, allocator_.pages_allocated()); + for (unsigned i = 0; i < 256; ++i) + ASSERT_EQ(v[i], i); +} + +TEST(WastefulVectorTest, UsesPageAllocator) { + PageAllocator allocator_; + wasteful_vector v(&allocator_); + EXPECT_EQ(1U, allocator_.pages_allocated()); + + v.push_back(1); + ASSERT_TRUE(allocator_.OwnsPointer(&v[0])); +} + +TEST(WastefulVectorTest, AutoWastefulVector) { + PageAllocator allocator_; + EXPECT_EQ(0U, allocator_.pages_allocated()); + + auto_wasteful_vector v(&allocator_); + EXPECT_EQ(0U, allocator_.pages_allocated()); + + v.push_back(1); + EXPECT_EQ(0U, allocator_.pages_allocated()); + EXPECT_FALSE(allocator_.OwnsPointer(&v[0])); + + v.resize(4); + EXPECT_EQ(0U, allocator_.pages_allocated()); + EXPECT_FALSE(allocator_.OwnsPointer(&v[0])); + + v.resize(10); + EXPECT_EQ(1U, allocator_.pages_allocated()); + EXPECT_TRUE(allocator_.OwnsPointer(&v[0])); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_range.h b/toolkit/crashreporter/google-breakpad/src/common/memory_range.h new file mode 100644 index 0000000000..41dd2da622 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/memory_range.h @@ -0,0 +1,145 @@ +// Copyright (c) 2011, 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_range.h: Define the google_breakpad::MemoryRange class, which +// is a lightweight wrapper with a pointer and a length to encapsulate +// a contiguous range of memory. + +#ifndef COMMON_MEMORY_RANGE_H_ +#define COMMON_MEMORY_RANGE_H_ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// A lightweight wrapper with a pointer and a length to encapsulate a +// contiguous range of memory. It provides helper methods for checked +// access of a subrange of the memory. Its implemementation does not +// allocate memory or call into libc functions, and is thus safer to use +// in a crashed environment. +class MemoryRange { + public: + MemoryRange() : data_(NULL), length_(0) {} + + MemoryRange(const void* data, size_t length) { + Set(data, length); + } + + // Returns true if this memory range contains no data. + bool IsEmpty() const { + // Set() guarantees that |length_| is zero if |data_| is NULL. + return length_ == 0; + } + + // Resets to an empty range. + void Reset() { + data_ = NULL; + length_ = 0; + } + + // Sets this memory range to point to |data| and its length to |length|. + void Set(const void* data, size_t length) { + data_ = reinterpret_cast(data); + // Always set |length_| to zero if |data_| is NULL. + length_ = data ? length : 0; + } + + // Returns true if this range covers a subrange of |sub_length| bytes + // at |sub_offset| bytes of this memory range, or false otherwise. + bool Covers(size_t sub_offset, size_t sub_length) const { + // The following checks verify that: + // 1. sub_offset is within [ 0 .. length_ - 1 ] + // 2. sub_offset + sub_length is within + // [ sub_offset .. length_ ] + return sub_offset < length_ && + sub_offset + sub_length >= sub_offset && + sub_offset + sub_length <= length_; + } + + // Returns a raw data pointer to a subrange of |sub_length| bytes at + // |sub_offset| bytes of this memory range, or NULL if the subrange + // is out of bounds. + const void* GetData(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL; + } + + // Same as the two-argument version of GetData() but uses sizeof(DataType) + // as the subrange length and returns an |DataType| pointer for convenience. + template + const DataType* GetData(size_t sub_offset) const { + return reinterpret_cast( + GetData(sub_offset, sizeof(DataType))); + } + + // Returns a raw pointer to the |element_index|-th element of an array + // of elements of length |element_size| starting at |sub_offset| bytes + // of this memory range, or NULL if the element is out of bounds. + const void* GetArrayElement(size_t element_offset, + size_t element_size, + unsigned element_index) const { + size_t sub_offset = element_offset + element_index * element_size; + return GetData(sub_offset, element_size); + } + + // Same as the three-argument version of GetArrayElement() but deduces + // the element size using sizeof(ElementType) and returns an |ElementType| + // pointer for convenience. + template + const ElementType* GetArrayElement(size_t element_offset, + unsigned element_index) const { + return reinterpret_cast( + GetArrayElement(element_offset, sizeof(ElementType), element_index)); + } + + // Returns a subrange of |sub_length| bytes at |sub_offset| bytes of + // this memory range, or an empty range if the subrange is out of bounds. + MemoryRange Subrange(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? + MemoryRange(data_ + sub_offset, sub_length) : MemoryRange(); + } + + // Returns a pointer to the beginning of this memory range. + const uint8_t* data() const { return data_; } + + // Returns the length, in bytes, of this memory range. + size_t length() const { return length_; } + + private: + // Pointer to the beginning of this memory range. + const uint8_t* data_; + + // Length, in bytes, of this memory range. + size_t length_; +}; + +} // namespace google_breakpad + +#endif // COMMON_MEMORY_RANGE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc new file mode 100644 index 0000000000..f6cf8c8b2a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc @@ -0,0 +1,193 @@ +// Copyright (c) 2011, 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_range_unittest.cc: Unit tests for google_breakpad::MemoryRange. + +#include "breakpad_googletest_includes.h" +#include "common/memory_range.h" + +using google_breakpad::MemoryRange; +using testing::Message; + +namespace { + +const uint32_t kBuffer[10] = { 0 }; +const size_t kBufferSize = sizeof(kBuffer); +const uint8_t* kBufferPointer = reinterpret_cast(kBuffer); + +// Test vectors for verifying Covers, GetData, and Subrange. +const struct { + bool valid; + size_t offset; + size_t length; +} kSubranges[] = { + { true, 0, 0 }, + { true, 0, 2 }, + { true, 0, kBufferSize }, + { true, 2, 0 }, + { true, 2, 4 }, + { true, 2, kBufferSize - 2 }, + { true, kBufferSize - 1, 1 }, + { false, kBufferSize, 0 }, + { false, kBufferSize, static_cast(-1) }, + { false, kBufferSize + 1, 0 }, + { false, static_cast(-1), 2 }, + { false, 1, kBufferSize }, + { false, kBufferSize - 1, 2 }, + { false, 0, static_cast(-1) }, + { false, 1, static_cast(-1) }, +}; +const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]); + +// Test vectors for verifying GetArrayElement. +const struct { + size_t offset; + size_t size; + size_t index; + const void* const pointer; +} kElements[] = { + // Valid array elemenets + { 0, 1, 0, kBufferPointer }, + { 0, 1, 1, kBufferPointer + 1 }, + { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 }, + { 0, 2, 1, kBufferPointer + 2 }, + { 0, 4, 2, kBufferPointer + 8 }, + { 0, 4, 9, kBufferPointer + 36 }, + { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, + // Invalid array elemenets + { 0, 1, kBufferSize, NULL }, + { 0, 4, 10, NULL }, + { kBufferSize - 1, 1, 1, NULL }, + { kBufferSize - 1, 2, 0, NULL }, + { kBufferSize, 1, 0, NULL }, +}; +const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); + +} // namespace + +TEST(MemoryRangeTest, DefaultConstructor) { + MemoryRange range; + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, ConstructorWithDataAndLength) { + MemoryRange range(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); +} + +TEST(MemoryRangeTest, Reset) { + MemoryRange range; + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); + + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, Set) { + MemoryRange range; + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Set(NULL, 0); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) { + MemoryRange range; + MemoryRange subrange = range.Subrange(0, 10); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); +} + +TEST(MemoryRangeTest, SubrangeAndGetData) { + MemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MemoryRange subrange = range.Subrange(sub_offset, sub_length); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MemoryRangeTest, GetDataWithTemplateType) { + MemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} + +TEST(MemoryRangeTest, GetArrayElement) { + MemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumElements; ++i) { + size_t element_offset = kElements[i].offset; + size_t element_size = kElements[i].size; + unsigned element_index = kElements[i].index; + const void* const element_pointer = kElements[i].pointer; + SCOPED_TRACE(Message() << "offset=" << element_offset + << ", size=" << element_size + << ", index=" << element_index); + EXPECT_EQ(element_pointer, range.GetArrayElement( + element_offset, element_size, element_index)); + } +} + +TEST(MemoryRangeTest, GetArrayElmentWithTemplateType) { + MemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h b/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h new file mode 100644 index 0000000000..5a7d5a6a87 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014, 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_COMMON_MINIDUMP_TYPE_HELPER_H_ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +struct MDTypeHelper; + +template <> +struct MDTypeHelper { + typedef MDRawDebug32 MDRawDebug; + typedef MDRawLinkMap32 MDRawLinkMap; +}; + +template <> +struct MDTypeHelper { + typedef MDRawDebug64 MDRawDebug; + typedef MDRawLinkMap64 MDRawLinkMap; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.cc b/toolkit/crashreporter/google-breakpad/src/common/module.cc new file mode 100644 index 0000000000..a3544029cb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/module.cc @@ -0,0 +1,387 @@ +// Copyright (c) 2011 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. + +// Original author: Jim Blandy + +// module.cc: Implement google_breakpad::Module. See module.h. + +#include "common/module.h" + +#include +#include +#include +#include + +#include +#include + +namespace google_breakpad { + +using std::dec; +using std::hex; + + +Module::Module(const string &name, const string &os, + const string &architecture, const string &id, + const string &code_id /* = "" */) : + name_(name), + os_(os), + architecture_(architecture), + id_(id), + code_id_(code_id), + load_address_(0) { } + +Module::~Module() { + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) + delete it->second; + for (FunctionSet::iterator it = functions_.begin(); + it != functions_.end(); ++it) { + delete *it; + } + for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); + it != stack_frame_entries_.end(); ++it) { + delete *it; + } + for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) + delete *it; +} + +void Module::SetLoadAddress(Address address) { + load_address_ = address; +} + +void Module::SetAddressRanges(const vector& ranges) { + address_ranges_ = ranges; +} + +void Module::AddFunction(Function *function) { + // FUNC lines must not hold an empty name, so catch the problem early if + // callers try to add one. + assert(!function->name.empty()); + + if (!AddressIsInModule(function->address)) { + return; + } + + // FUNCs are better than PUBLICs as they come with sizes, so remove an extern + // with the same address if present. + Extern ext(function->address); + ExternSet::iterator it_ext = externs_.find(&ext); + if (it_ext == externs_.end() && + architecture_ == "arm" && + (function->address & 0x1) == 0) { + // ARM THUMB functions have bit 0 set. ARM64 does not have THUMB. + Extern arm_thumb_ext(function->address | 0x1); + it_ext = externs_.find(&arm_thumb_ext); + } + if (it_ext != externs_.end()) { + delete *it_ext; + externs_.erase(it_ext); + } +#if _DEBUG + { + // There should be no other PUBLIC symbols that overlap with the function. + for (const Range& range : function->ranges) { + Extern debug_ext(range.address); + ExternSet::iterator it_debug = externs_.lower_bound(&ext); + assert(it_debug == externs_.end() || + (*it_debug)->address >= range.address + range.size); + } + } +#endif + + std::pair ret = functions_.insert(function); + if (!ret.second && (*ret.first != function)) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete function; + } +} + +void Module::AddFunctions(vector::iterator begin, + vector::iterator end) { + for (vector::iterator it = begin; it != end; ++it) + AddFunction(*it); +} + +void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { + if (!AddressIsInModule(stack_frame_entry->address)) { + return; + } + + std::pair ret = + stack_frame_entries_.insert(stack_frame_entry); + if (!ret.second) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete stack_frame_entry; + } +} + +void Module::AddExtern(Extern *ext) { + if (!AddressIsInModule(ext->address)) { + return; + } + + std::pair ret = externs_.insert(ext); + if (!ret.second) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete ext; + } +} + +void Module::GetFunctions(vector *vec, + vector::iterator i) { + vec->insert(i, functions_.begin(), functions_.end()); +} + +void Module::GetExterns(vector *vec, + vector::iterator i) { + vec->insert(i, externs_.begin(), externs_.end()); +} + +Module::File *Module::FindFile(const string &name) { + // A tricky bit here. The key of each map entry needs to be a + // pointer to the entry's File's name string. This means that we + // can't do the initial lookup with any operation that would create + // an empty entry for us if the name isn't found (like, say, + // operator[] or insert do), because such a created entry's key will + // be a pointer the string passed as our argument. Since the key of + // a map's value type is const, we can't fix it up once we've + // created our file. lower_bound does the lookup without doing an + // insertion, and returns a good hint iterator to pass to insert. + // Our "destiny" is where we belong, whether we're there or not now. + FileByNameMap::iterator destiny = files_.lower_bound(&name); + if (destiny == files_.end() + || *destiny->first != name) { // Repeated string comparison, boo hoo. + File *file = new File(name); + file->source_id = -1; + destiny = files_.insert(destiny, + FileByNameMap::value_type(&file->name, file)); + } + return destiny->second; +} + +Module::File *Module::FindFile(const char *name) { + string name_string = name; + return FindFile(name_string); +} + +Module::File *Module::FindExistingFile(const string &name) { + FileByNameMap::iterator it = files_.find(&name); + return (it == files_.end()) ? NULL : it->second; +} + +void Module::GetFiles(vector *vec) { + vec->clear(); + for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) + vec->push_back(it->second); +} + +void Module::GetStackFrameEntries(vector* vec) const { + vec->clear(); + vec->insert(vec->begin(), stack_frame_entries_.begin(), + stack_frame_entries_.end()); +} + +Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { + StackFrameEntry search; + search.address = address; + StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); + + if (it == stack_frame_entries_.begin()) + return NULL; + + it--; + if ((*it)->address <= address && address < (*it)->address + (*it)->size) + return *it; + + return NULL; +} + +void Module::AssignSourceIds() { + // First, give every source file an id of -1. + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + file_it->second->source_id = -1; + } + + // Next, mark all files actually cited by our functions' line number + // info, by setting each one's source id to zero. + for (FunctionSet::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); ++func_it) { + Function *func = *func_it; + for (vector::iterator line_it = func->lines.begin(); + line_it != func->lines.end(); ++line_it) + line_it->file->source_id = 0; + } + + // Finally, assign source ids to those files that have been marked. + // We could have just assigned source id numbers while traversing + // the line numbers, but doing it this way numbers the files in + // lexicographical order by name, which is neat. + int next_source_id = 0; + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + if (!file_it->second->source_id) + file_it->second->source_id = next_source_id++; + } +} + +bool Module::ReportError() { + fprintf(stderr, "error writing symbol file: %s\n", + strerror(errno)); + return false; +} + +bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { + for (RuleMap::const_iterator it = rule_map.begin(); + it != rule_map.end(); ++it) { + if (it != rule_map.begin()) + stream << ' '; + stream << it->first << ": " << it->second; + } + return stream.good(); +} + +bool Module::AddressIsInModule(Address address) const { + if (address_ranges_.empty()) { + return true; + } + for (const auto& segment : address_ranges_) { + if (address >= segment.address && + address < segment.address + segment.size) { + return true; + } + } + return false; +} + +bool Module::Write(std::ostream &stream, SymbolData symbol_data) { + stream << "MODULE " << os_ << " " << architecture_ << " " + << id_ << " " << name_ << "\n"; + if (!stream.good()) + return ReportError(); + + if (!code_id_.empty()) { + stream << "INFO CODE_ID " << code_id_ << "\n"; + } + + if (symbol_data != ONLY_CFI) { + AssignSourceIds(); + + // Write out files. + for (FileByNameMap::iterator file_it = files_.begin(); + file_it != files_.end(); ++file_it) { + File *file = file_it->second; + if (file->source_id >= 0) { + stream << "FILE " << file->source_id << " " << file->name << "\n"; + if (!stream.good()) + return ReportError(); + } + } + + // Write out functions and their lines. + for (FunctionSet::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); ++func_it) { + Function *func = *func_it; + vector::iterator line_it = func->lines.begin(); + for (auto range_it = func->ranges.cbegin(); + range_it != func->ranges.cend(); ++range_it) { + stream << "FUNC " << hex + << (range_it->address - load_address_) << " " + << range_it->size << " " + << func->parameter_size << " " + << func->name << dec << "\n"; + + if (!stream.good()) + return ReportError(); + + while ((line_it != func->lines.end()) && + (line_it->address >= range_it->address) && + (line_it->address < (range_it->address + range_it->size))) { + stream << hex + << (line_it->address - load_address_) << " " + << line_it->size << " " + << dec + << line_it->number << " " + << line_it->file->source_id << "\n"; + + if (!stream.good()) + return ReportError(); + + ++line_it; + } + } + } + + // Write out 'PUBLIC' records. + for (ExternSet::const_iterator extern_it = externs_.begin(); + extern_it != externs_.end(); ++extern_it) { + Extern *ext = *extern_it; + stream << "PUBLIC " << hex + << (ext->address - load_address_) << " 0 " + << ext->name << dec << "\n"; + } + } + + if (symbol_data != NO_CFI) { + // Write out 'STACK CFI INIT' and 'STACK CFI' records. + StackFrameEntrySet::const_iterator frame_it; + for (frame_it = stack_frame_entries_.begin(); + frame_it != stack_frame_entries_.end(); ++frame_it) { + StackFrameEntry *entry = *frame_it; + stream << "STACK CFI INIT " << hex + << (entry->address - load_address_) << " " + << entry->size << " " << dec; + if (!stream.good() + || !WriteRuleMap(entry->initial_rules, stream)) + return ReportError(); + + stream << "\n"; + + // Write out this entry's delta rules as 'STACK CFI' records. + for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); + delta_it != entry->rule_changes.end(); ++delta_it) { + stream << "STACK CFI " << hex + << (delta_it->first - load_address_) << " " << dec; + if (!stream.good() + || !WriteRuleMap(delta_it->second, stream)) + return ReportError(); + + stream << "\n"; + } + } + } + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.h b/toolkit/crashreporter/google-breakpad/src/common/module.h new file mode 100644 index 0000000000..3775860526 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/module.h @@ -0,0 +1,376 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// module.h: Define google_breakpad::Module. A Module holds debugging +// information, and can write that information out as a Breakpad +// symbol file. + +#ifndef COMMON_LINUX_MODULE_H__ +#define COMMON_LINUX_MODULE_H__ + +#include +#include +#include +#include +#include + +#include "common/symbol_data.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::set; +using std::vector; +using std::map; + +// A Module represents the contents of a module, and supports methods +// for adding information produced by parsing STABS or DWARF data +// --- possibly both from the same file --- and then writing out the +// unified contents as a Breakpad-format symbol file. +class Module { + public: + // The type of addresses and sizes in a symbol table. + typedef uint64_t Address; + struct File; + struct Function; + struct Line; + struct Extern; + + // Addresses appearing in File, Function, and Line structures are + // absolute, not relative to the the module's load address. That + // is, if the module were loaded at its nominal load address, the + // addresses would be correct. + + // A source file. + struct File { + explicit File(const string &name_input) : name(name_input), source_id(0) {} + + // The name of the source file. + const string name; + + // The file's source id. The Write member function clears this + // field and assigns source ids a fresh, so any value placed here + // before calling Write will be lost. + int source_id; + }; + + // An address range. + struct Range { + Range(const Address address_input, const Address size_input) : + address(address_input), size(size_input) { } + + Address address; + Address size; + }; + + // A function. + struct Function { + Function(const string &name_input, const Address &address_input) : + name(name_input), address(address_input), parameter_size(0) {} + + // For sorting by address. (Not style-guide compliant, but it's + // stupid not to put this in the struct.) + static bool CompareByAddress(const Function *x, const Function *y) { + return x->address < y->address; + } + + // The function's name. + string name; + + // The start address and the address ranges covered by the function. + const Address address; + vector ranges; + + // The function's parameter size. + Address parameter_size; + + // Source lines belonging to this function, sorted by increasing + // address. + vector lines; + }; + + // A source line. + struct Line { + // For sorting by address. (Not style-guide compliant, but it's + // stupid not to put this in the struct.) + static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { + return x.address < y.address; + } + + Address address, size; // The address and size of the line's code. + File *file; // The source file. + int number; // The source line number. + }; + + // An exported symbol. + struct Extern { + explicit Extern(const Address &address_input) : address(address_input) {} + const Address address; + string name; + }; + + // A map from register names to postfix expressions that recover + // their their values. This can represent a complete set of rules to + // follow at some address, or a set of changes to be applied to an + // extant set of rules. + typedef map RuleMap; + + // A map from addresses to RuleMaps, representing changes that take + // effect at given addresses. + typedef map RuleChangeMap; + + // A range of 'STACK CFI' stack walking information. An instance of + // this structure corresponds to a 'STACK CFI INIT' record and the + // subsequent 'STACK CFI' records that fall within its range. + struct StackFrameEntry { + // The starting address and number of bytes of machine code this + // entry covers. + Address address, size; + + // The initial register recovery rules, in force at the starting + // address. + RuleMap initial_rules; + + // A map from addresses to rule changes. To find the rules in + // force at a given address, start with initial_rules, and then + // apply the changes given in this map for all addresses up to and + // including the address you're interested in. + RuleChangeMap rule_changes; + }; + + struct FunctionCompare { + bool operator() (const Function *lhs, + const Function *rhs) const { + if (lhs->address == rhs->address) + return lhs->name < rhs->name; + return lhs->address < rhs->address; + } + }; + + struct ExternCompare { + bool operator() (const Extern *lhs, + const Extern *rhs) const { + return lhs->address < rhs->address; + } + }; + + struct StackFrameEntryCompare { + bool operator() (const StackFrameEntry* lhs, + const StackFrameEntry* rhs) const { + return lhs->address < rhs->address; + } + }; + + // Create a new module with the given name, operating system, + // architecture, and ID string. + Module(const string &name, const string &os, const string &architecture, + const string &id, const string &code_id = ""); + ~Module(); + + // Set the module's load address to LOAD_ADDRESS; addresses given + // for functions and lines will be written to the Breakpad symbol + // file as offsets from this address. Construction initializes this + // module's load address to zero: addresses written to the symbol + // file will be the same as they appear in the Function, Line, and + // StackFrameEntry structures. + // + // Note that this member function has no effect on addresses stored + // in the data added to this module; the Write member function + // simply subtracts off the load address from addresses before it + // prints them. Only the last load address given before calling + // Write is used. + void SetLoadAddress(Address load_address); + + // Sets address filtering on elements added to the module. This allows + // libraries with extraneous debug symbols to generate symbol files containing + // only relevant symbols. For example, an LLD-generated partition library may + // contain debug information pertaining to all partitions derived from a + // single "combined" library. Filtering applies only to elements added after + // this method is called. + void SetAddressRanges(const vector& ranges); + + // Add FUNCTION to the module. FUNCTION's name must not be empty. + // This module owns all Function objects added with this function: + // destroying the module destroys them as well. + void AddFunction(Function *function); + + // Add all the functions in [BEGIN,END) to the module. + // This module owns all Function objects added with this function: + // destroying the module destroys them as well. + void AddFunctions(vector::iterator begin, + vector::iterator end); + + // Add STACK_FRAME_ENTRY to the module. + // This module owns all StackFrameEntry objects added with this + // function: destroying the module destroys them as well. + void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); + + // Add PUBLIC to the module. + // This module owns all Extern objects added with this function: + // destroying the module destroys them as well. + void AddExtern(Extern *ext); + + // If this module has a file named NAME, return a pointer to it. If + // it has none, then create one and return a pointer to the new + // file. This module owns all File objects created using these + // functions; destroying the module destroys them as well. + File *FindFile(const string &name); + File *FindFile(const char *name); + + // If this module has a file named NAME, return a pointer to it. + // Otherwise, return NULL. + File *FindExistingFile(const string &name); + + // Insert pointers to the functions added to this module at I in + // VEC. The pointed-to Functions are still owned by this module. + // (Since this is effectively a copy of the function list, this is + // mostly useful for testing; other uses should probably get a more + // appropriate interface.) + void GetFunctions(vector *vec, vector::iterator i); + + // Insert pointers to the externs added to this module at I in + // VEC. The pointed-to Externs are still owned by this module. + // (Since this is effectively a copy of the extern list, this is + // mostly useful for testing; other uses should probably get a more + // appropriate interface.) + void GetExterns(vector *vec, vector::iterator i); + + // Clear VEC and fill it with pointers to the Files added to this + // module, sorted by name. The pointed-to Files are still owned by + // this module. (Since this is effectively a copy of the file list, + // this is mostly useful for testing; other uses should probably get + // a more appropriate interface.) + void GetFiles(vector *vec); + + // Clear VEC and fill it with pointers to the StackFrameEntry + // objects that have been added to this module. (Since this is + // effectively a copy of the stack frame entry list, this is mostly + // useful for testing; other uses should probably get + // a more appropriate interface.) + void GetStackFrameEntries(vector *vec) const; + + // If this module has a StackFrameEntry whose address range covers + // ADDRESS, return it. Otherwise return NULL. + StackFrameEntry* FindStackFrameEntryByAddress(Address address); + + // Find those files in this module that are actually referred to by + // functions' line number data, and assign them source id numbers. + // Set the source id numbers for all other files --- unused by the + // source line data --- to -1. We do this before writing out the + // symbol file, at which point we omit any unused files. + void AssignSourceIds(); + + // Call AssignSourceIds, and write this module to STREAM in the + // breakpad symbol format. Return true if all goes well, or false if + // an error occurs. This method writes out: + // - a header based on the values given to the constructor, + // If symbol_data is not ONLY_CFI then: + // - the source files added via FindFile, + // - the functions added via AddFunctions, each with its lines, + // - all public records, + // If symbol_data is not NO_CFI then: + // - all CFI records. + // Addresses in the output are all relative to the load address + // established by SetLoadAddress. + bool Write(std::ostream &stream, SymbolData symbol_data); + + string name() const { return name_; } + string os() const { return os_; } + string architecture() const { return architecture_; } + string identifier() const { return id_; } + string code_identifier() const { return code_id_; } + + private: + // Report an error that has occurred writing the symbol file, using + // errno to find the appropriate cause. Return false. + static bool ReportError(); + + // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' + // records, without a final newline. Return true if all goes well; + // if an error occurs, return false, and leave errno set. + static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream); + + // Returns true of the specified address resides with an specified address + // range, or if no ranges have been specified. + bool AddressIsInModule(Address address) const; + + // Module header entries. + string name_, os_, architecture_, id_, code_id_; + + // The module's nominal load address. Addresses for functions and + // lines are absolute, assuming the module is loaded at this + // address. + Address load_address_; + + // The set of valid address ranges of the module. If specified, attempts to + // add elements residing outside these ranges will be silently filtered. + vector address_ranges_; + + // Relation for maps whose keys are strings shared with some other + // structure. + struct CompareStringPtrs { + bool operator()(const string *x, const string *y) const { return *x < *y; } + }; + + // A map from filenames to File structures. The map's keys are + // pointers to the Files' names. + typedef map FileByNameMap; + + // A set containing Function structures, sorted by address. + typedef set FunctionSet; + + // A set containing Extern structures, sorted by address. + typedef set ExternSet; + + // A set containing StackFrameEntry structures, sorted by address. + typedef set StackFrameEntrySet; + + // The module owns all the files and functions that have been added + // to it; destroying the module frees the Files and Functions these + // point to. + FileByNameMap files_; // This module's source files. + FunctionSet functions_; // This module's functions. + + // The module owns all the call frame info entries that have been + // added to it. + StackFrameEntrySet stack_frame_entries_; + + // The module owns all the externs that have been added to it; + // destroying the module frees the Externs these point to. + ExternSet externs_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc new file mode 100644 index 0000000000..b855f186ba --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc @@ -0,0 +1,674 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// module_unittest.cc: Unit tests for google_breakpad::Module. + +#include +#include +#include +#include + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/module.h" +#include "common/using_std_string.h" + +using google_breakpad::Module; +using std::stringstream; +using std::vector; +using testing::ContainerEq; + +static Module::Function* generate_duplicate_function(const string &name) { + const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cULL; + const Module::Address DUP_SIZE = 0x200b26e605f99071ULL; + const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99ULL; + + Module::Function* function = new Module::Function(name, DUP_ADDRESS); + Module::Range range(DUP_ADDRESS, DUP_SIZE); + function->ranges.push_back(range); + function->parameter_size = DUP_PARAMETER_SIZE; + return function; +} + +#define MODULE_NAME "name with spaces" +#define MODULE_OS "os-name" +#define MODULE_ARCH "architecture" +#define MODULE_ID "id-string" +#define MODULE_CODE_ID "code-id-string" + +TEST(Write, Header) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", + contents.c_str()); +} + +TEST(Write, HeaderCodeId) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID); + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "INFO CODE_ID code-id-string\n", + contents.c_str()); +} + +TEST(Write, OneLineFunc) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + Module::File* file = m.FindFile("file_name.cc"); + Module::Function* function = new Module::Function( + "function_name", 0xe165bf8023b9d9abULL); + Module::Range range(0xe165bf8023b9d9abULL, 0x1e4bb0eb1cbf5b09ULL); + function->ranges.push_back(range); + function->parameter_size = 0x772beee89114358aULL; + Module::Line line = { 0xe165bf8023b9d9abULL, 0x1e4bb0eb1cbf5b09ULL, + file, 67519080 }; + function->lines.push_back(line); + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 file_name.cc\n" + "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" + " function_name\n" + "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", + contents.c_str()); +} + +TEST(Write, RelativeLoadAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Some source files. We will expect to see them in lexicographic order. + Module::File* file1 = m.FindFile("filename-b.cc"); + Module::File* file2 = m.FindFile("filename-a.cc"); + + // A function. + Module::Function* function = new Module::Function( + "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3ULL); + Module::Range range(0xbec774ea5dd935f3ULL, 0x2922088f98d3f6fcULL); + function->ranges.push_back(range); + function->parameter_size = 0xe5e9aa008bd5f0d0ULL; + + // Some source lines. The module should not sort these. + Module::Line line1 = { 0xbec774ea5dd935f3ULL, 0x1c2be6d6c5af2611ULL, + file1, 41676901 }; + Module::Line line2 = { 0xdaf35bc123885c04ULL, 0xcf621b8d324d0ebULL, + file2, 67519080 }; + function->lines.push_back(line2); + function->lines.push_back(line1); + + m.AddFunction(function); + + // Some stack information. + Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + entry->address = 0x30f9e5c83323973dULL; + entry->size = 0x49fc9ca7c7c13dc2ULL; + entry->initial_rules[".cfa"] = "he was a handsome man"; + entry->initial_rules["and"] = "what i want to know is"; + entry->rule_changes[0x30f9e5c83323973eULL]["how"] = + "do you like your blueeyed boy"; + entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; + m.AddStackFrameEntry(entry); + + // Set the load address. Doing this after adding all the data to + // the module must work fine. + m.SetLoadAddress(0x2ab698b0b6407073ULL); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename-a.cc\n" + "FILE 1 filename-b.cc\n" + "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" + " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" + "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" + "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" + "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" + " .cfa: he was a handsome man" + " and: what i want to know is\n" + "STACK CFI 6434d177ce326cb" + " Mister: Death" + " how: do you like your blueeyed boy\n", + contents.c_str()); +} + +TEST(Write, OmitUnusedFiles) { + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Create some source files. + Module::File* file1 = m.FindFile("filename1"); + m.FindFile("filename2"); // not used by any line + Module::File* file3 = m.FindFile("filename3"); + + // Create a function. + Module::Function* function = new Module::Function( + "function_name", 0x9b926d464f0b9384ULL); + Module::Range range(0x9b926d464f0b9384ULL, 0x4f524a4ba795e6a6ULL); + function->ranges.push_back(range); + function->parameter_size = 0xbbe8133a6641c9b7ULL; + + // Source files that refer to some files, but not others. + Module::Line line1 = { 0xab415089485e1a20ULL, 0x126e3124979291f2ULL, + file1, 137850127 }; + Module::Line line2 = { 0xb2675b5c3c2ed33fULL, 0x1df77f5551dbd68cULL, + file3, 28113549 }; + function->lines.push_back(line1); + function->lines.push_back(line2); + m.AddFunction(function); + + m.AssignSourceIds(); + + vector vec; + m.GetFiles(&vec); + EXPECT_EQ((size_t) 3, vec.size()); + EXPECT_STREQ("filename1", vec[0]->name.c_str()); + EXPECT_NE(-1, vec[0]->source_id); + // Expect filename2 not to be used. + EXPECT_STREQ("filename2", vec[1]->name.c_str()); + EXPECT_EQ(-1, vec[1]->source_id); + EXPECT_STREQ("filename3", vec[2]->name.c_str()); + EXPECT_NE(-1, vec[2]->source_id); + + stringstream s; + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename1\n" + "FILE 1 filename3\n" + "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" + " function_name\n" + "ab415089485e1a20 126e3124979291f2 137850127 0\n" + "b2675b5c3c2ed33f 1df77f5551dbd68c 28113549 1\n", + contents.c_str()); +} + +TEST(Write, NoCFI) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Some source files. We will expect to see them in lexicographic order. + Module::File* file1 = m.FindFile("filename.cc"); + + // A function. + Module::Function* function = new Module::Function( + "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3ULL); + Module::Range range(0xbec774ea5dd935f3ULL, 0x2922088f98d3f6fcULL); + function->ranges.push_back(range); + function->parameter_size = 0xe5e9aa008bd5f0d0ULL; + + // Some source lines. The module should not sort these. + Module::Line line1 = { 0xbec774ea5dd935f3ULL, 0x1c2be6d6c5af2611ULL, + file1, 41676901 }; + function->lines.push_back(line1); + + m.AddFunction(function); + + // Some stack information. + Module::StackFrameEntry* entry = new Module::StackFrameEntry(); + entry->address = 0x30f9e5c83323973dULL; + entry->size = 0x49fc9ca7c7c13dc2ULL; + entry->initial_rules[".cfa"] = "he was a handsome man"; + entry->initial_rules["and"] = "what i want to know is"; + entry->rule_changes[0x30f9e5c83323973eULL]["how"] = + "do you like your blueeyed boy"; + entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; + m.AddStackFrameEntry(entry); + + // Set the load address. Doing this after adding all the data to + // the module must work fine. + m.SetLoadAddress(0x2ab698b0b6407073ULL); + + m.Write(s, NO_CFI); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FILE 0 filename.cc\n" + "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" + " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" + "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", + contents.c_str()); +} + +TEST(Construct, AddFunctions) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function* function1 = new Module::Function( + "_without_form", 0xd35024aa7ca7da5cULL); + Module::Range r1(0xd35024aa7ca7da5cULL, 0x200b26e605f99071ULL); + function1->ranges.push_back(r1); + function1->parameter_size = 0xf14ac4fed48c4a99ULL; + + Module::Function* function2 = new Module::Function( + "_and_void", 0x2987743d0b35b13fULL); + Module::Range r2(0x2987743d0b35b13fULL, 0xb369db048deb3010ULL); + function2->ranges.push_back(r2); + function2->parameter_size = 0x938e556cb5a79988ULL; + + // Put them in a vector. + vector vec; + vec.push_back(function1); + vec.push_back(function2); + + m.AddFunctions(vec.begin(), vec.end()); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" + " _and_void\n" + "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); + + // Check that m.GetFunctions returns the functions we expect. + vec.clear(); + m.GetFunctions(&vec, vec.end()); + EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); + EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); + EXPECT_EQ((size_t) 2, vec.size()); +} + +TEST(Construct, AddFrames) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // First STACK CFI entry, with no initial rules or deltas. + Module::StackFrameEntry* entry1 = new Module::StackFrameEntry(); + entry1->address = 0xddb5f41285aa7757ULL; + entry1->size = 0x1486493370dc5073ULL; + m.AddStackFrameEntry(entry1); + + // Second STACK CFI entry, with initial rules but no deltas. + Module::StackFrameEntry* entry2 = new Module::StackFrameEntry(); + entry2->address = 0x8064f3af5e067e38ULL; + entry2->size = 0x0de2a5ee55509407ULL; + entry2->initial_rules[".cfa"] = "I think that I shall never see"; + entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; + entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; + m.AddStackFrameEntry(entry2); + + // Third STACK CFI entry, with initial rules and deltas. + Module::StackFrameEntry* entry3 = new Module::StackFrameEntry(); + entry3->address = 0x5e8d0db0a7075c6cULL; + entry3->size = 0x1c7edb12a7aea229ULL; + entry3->initial_rules[".cfa"] = "Whose woods are these"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = + "the village though"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + "he will not see me stopping here"; + entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = + "his house is in"; + entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = + "I think I know"; + m.AddStackFrameEntry(entry3); + + // Check that Write writes STACK CFI records properly. + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" + " .cfa: Whose woods are these\n" + "STACK CFI 36682fad3763ffff" + " .cfa: I think I know" + " stromboli: his house is in\n" + "STACK CFI 47ceb0f63c269d7f" + " calzone: the village though" + " cannoli: he will not see me stopping here\n" + "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" + " .cfa: I think that I shall never see" + " cannoli: a tree whose hungry mouth is prest" + " stromboli: a poem lovely as a tree\n" + "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", + contents.c_str()); + + // Check that GetStackFrameEntries works. + vector entries; + m.GetStackFrameEntries(&entries); + ASSERT_EQ(3U, entries.size()); + // Check first entry. + EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); + EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); + Module::RuleMap entry1_initial; + entry1_initial[".cfa"] = "Whose woods are these"; + EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); + Module::RuleChangeMap entry1_changes; + entry1_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; + entry1_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; + entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; + entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + "he will not see me stopping here"; + EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); + // Check second entry. + EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); + EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); + ASSERT_EQ(3U, entries[1]->initial_rules.size()); + Module::RuleMap entry2_initial; + entry2_initial[".cfa"] = "I think that I shall never see"; + entry2_initial["stromboli"] = "a poem lovely as a tree"; + entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; + EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); + ASSERT_EQ(0U, entries[1]->rule_changes.size()); + // Check third entry. + EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); + EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); + ASSERT_EQ(0U, entries[2]->initial_rules.size()); + ASSERT_EQ(0U, entries[2]->rule_changes.size()); +} + +TEST(Construct, UniqueFiles) { + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + Module::File* file1 = m.FindFile("foo"); + Module::File* file2 = m.FindFile(string("bar")); + Module::File* file3 = m.FindFile(string("foo")); + Module::File* file4 = m.FindFile("bar"); + EXPECT_NE(file1, file2); + EXPECT_EQ(file1, file3); + EXPECT_EQ(file2, file4); + EXPECT_EQ(file1, m.FindExistingFile("foo")); + EXPECT_TRUE(m.FindExistingFile("baz") == NULL); +} + +TEST(Construct, DuplicateFunctions) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function* function1 = generate_duplicate_function("_without_form"); + Module::Function* function2 = generate_duplicate_function("_without_form"); + + m.AddFunction(function1); + m.AddFunction(function2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); +} + +TEST(Construct, FunctionsWithSameAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two functions. + Module::Function* function1 = generate_duplicate_function("_without_form"); + Module::Function* function2 = generate_duplicate_function("_and_void"); + + m.AddFunction(function1); + m.AddFunction(function2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _and_void\n" + "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" + " _without_form\n", + contents.c_str()); +} + +// Externs should be written out as PUBLIC records, sorted by +// address. +TEST(Construct, Externs) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two externs. + Module::Extern* extern1 = new Module::Extern(0xffff); + extern1->name = "_abc"; + Module::Extern* extern2 = new Module::Extern(0xaaaa); + extern2->name = "_xyz"; + + m.AddExtern(extern1); + m.AddExtern(extern2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " + MODULE_ID " " MODULE_NAME "\n" + "PUBLIC aaaa 0 _xyz\n" + "PUBLIC ffff 0 _abc\n", + contents.c_str()); +} + +// Externs with the same address should only keep the first entry +// added. +TEST(Construct, DuplicateExterns) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two externs. + Module::Extern* extern1 = new Module::Extern(0xffff); + extern1->name = "_xyz"; + Module::Extern* extern2 = new Module::Extern(0xffff); + extern2->name = "_abc"; + + m.AddExtern(extern1); + m.AddExtern(extern2); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " + MODULE_ID " " MODULE_NAME "\n" + "PUBLIC ffff 0 _xyz\n", + contents.c_str()); +} + +// If there exists an extern and a function at the same address, only write +// out the FUNC entry. +TEST(Construct, FunctionsAndExternsWithSameAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Two externs. + Module::Extern* extern1 = new Module::Extern(0xabc0); + extern1->name = "abc"; + Module::Extern* extern2 = new Module::Extern(0xfff0); + extern2->name = "xyz"; + + m.AddExtern(extern1); + m.AddExtern(extern2); + + Module::Function* function = new Module::Function("_xyz", 0xfff0); + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); + function->parameter_size = 0; + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " + MODULE_ID " " MODULE_NAME "\n" + "FUNC fff0 10 0 _xyz\n" + "PUBLIC abc0 0 abc\n", + contents.c_str()); +} + +// If there exists an extern and a function at the same address, only write +// out the FUNC entry. For ARM THUMB, the extern that comes from the ELF +// symbol section has bit 0 set. +TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID); + + // Two THUMB externs. + Module::Extern* thumb_extern1 = new Module::Extern(0xabc1); + thumb_extern1->name = "thumb_abc"; + Module::Extern* thumb_extern2 = new Module::Extern(0xfff1); + thumb_extern2->name = "thumb_xyz"; + + Module::Extern* arm_extern1 = new Module::Extern(0xcc00); + arm_extern1->name = "arm_func"; + + m.AddExtern(thumb_extern1); + m.AddExtern(thumb_extern2); + m.AddExtern(arm_extern1); + + // The corresponding function from the DWARF debug data have the actual + // address. + Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0); + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); + function->parameter_size = 0; + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " arm " + MODULE_ID " " MODULE_NAME "\n" + "FUNC fff0 10 0 _thumb_xyz\n" + "PUBLIC abc1 0 thumb_abc\n" + "PUBLIC cc00 0 arm_func\n", + contents.c_str()); +} + +TEST(Write, OutOfRangeAddresses) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // Specify an allowed address range, representing a PT_LOAD segment in a + // module. + vector address_ranges = { + Module::Range(0x2000ULL, 0x1000ULL), + }; + m.SetAddressRanges(address_ranges); + + // Add three stack frames (one lower, one in, and one higher than the allowed + // address range). Only the middle frame should be captured. + Module::StackFrameEntry* entry1 = new Module::StackFrameEntry(); + entry1->address = 0x1000ULL; + entry1->size = 0x100ULL; + m.AddStackFrameEntry(entry1); + Module::StackFrameEntry* entry2 = new Module::StackFrameEntry(); + entry2->address = 0x2000ULL; + entry2->size = 0x100ULL; + m.AddStackFrameEntry(entry2); + Module::StackFrameEntry* entry3 = new Module::StackFrameEntry(); + entry3->address = 0x3000ULL; + entry3->size = 0x100ULL; + m.AddStackFrameEntry(entry3); + + // Add a function outside the allowed range. + Module::File* file = m.FindFile("file_name.cc"); + Module::Function* function = new Module::Function( + "function_name", 0x4000ULL); + Module::Range range(0x4000ULL, 0x1000ULL); + function->ranges.push_back(range); + function->parameter_size = 0x100ULL; + Module::Line line = { 0x4000ULL, 0x100ULL, file, 67519080 }; + function->lines.push_back(line); + m.AddFunction(function); + + // Add an extern outside the allowed range. + Module::Extern* extern1 = new Module::Extern(0x5000ULL); + extern1->name = "_xyz"; + m.AddExtern(extern1); + + m.Write(s, ALL_SYMBOL_DATA); + + EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" + "STACK CFI INIT 2000 100 \n", + s.str().c_str()); +} + +TEST(Lookup, StackFrameEntries) { + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); + + // First STACK CFI entry, with no initial rules or deltas. + Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); + entry1->address = 0x2000; + entry1->size = 0x900; + m.AddStackFrameEntry(entry1); + + // Second STACK CFI entry, with initial rules but no deltas. + Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); + entry2->address = 0x3000; + entry2->size = 0x900; + entry2->initial_rules[".cfa"] = "I think that I shall never see"; + entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; + entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; + m.AddStackFrameEntry(entry2); + + // Third STACK CFI entry, with initial rules and deltas. + Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); + entry3->address = 0x1000; + entry3->size = 0x900; + entry3->initial_rules[".cfa"] = "Whose woods are these"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = + "the village though"; + entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = + "he will not see me stopping here"; + entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = + "his house is in"; + entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = + "I think I know"; + m.AddStackFrameEntry(entry3); + + Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); + EXPECT_EQ(entry3, s); + s = m.FindStackFrameEntryByAddress(0x18FF); + EXPECT_EQ(entry3, s); + + s = m.FindStackFrameEntryByAddress(0x1900); + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); + s = m.FindStackFrameEntryByAddress(0x1A00); + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); + + s = m.FindStackFrameEntryByAddress(0x2000); + EXPECT_EQ(entry1, s); + s = m.FindStackFrameEntryByAddress(0x28FF); + EXPECT_EQ(entry1, s); + + s = m.FindStackFrameEntryByAddress(0x3000); + EXPECT_EQ(entry2, s); + s = m.FindStackFrameEntryByAddress(0x38FF); + EXPECT_EQ(entry2, s); + + s = m.FindStackFrameEntryByAddress(0x3900); + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); + s = m.FindStackFrameEntryByAddress(0x3A00); + EXPECT_EQ((Module::StackFrameEntry*)NULL, s); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/moz.build b/toolkit/crashreporter/google-breakpad/src/common/moz.build new file mode 100644 index 0000000000..d3b55045d1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/moz.build @@ -0,0 +1,19 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + 'convert_UTF.cc', + 'string_conversion.cc', +] + +if CONFIG['OS_ARCH'] == 'Darwin': + UNIFIED_SOURCES += [ + 'md5.cc', + ] + +Library('breakpad_common_s') + +include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/path_helper.cc b/toolkit/crashreporter/google-breakpad/src/common/path_helper.cc new file mode 100644 index 0000000000..61a6e31846 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/path_helper.cc @@ -0,0 +1,55 @@ +// Copyright 2017, 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 "common/path_helper.h" + +#include +#include +#include +#include + +namespace google_breakpad { + +string BaseName(const string& path) { + char* path_tmp = strdup(path.c_str()); + assert(path_tmp); + string result(basename(path_tmp)); + free(path_tmp); + return result; +} + +string DirName(const string& path) { + char* path_tmp = strdup(path.c_str()); + assert(path_tmp); + string result(dirname(path_tmp)); + free(path_tmp); + return result; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/path_helper.h b/toolkit/crashreporter/google-breakpad/src/common/path_helper.h new file mode 100644 index 0000000000..2166ba018a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/path_helper.h @@ -0,0 +1,44 @@ +// Copyright 2017, 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_COMMON_PATH_HELPER_H +#define GOOGLE_BREAKPAD_COMMON_PATH_HELPER_H + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +string BaseName(const string& path); +string DirName(const string& path); + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_PATH_HELPER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h b/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h new file mode 100644 index 0000000000..d137c18681 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h @@ -0,0 +1,404 @@ +// Copyright 2013 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. + +// Scopers help you manage ownership of a pointer, helping you easily manage the +// a pointer within a scope, and automatically destroying the pointer at the +// end of a scope. There are two main classes you will use, which correspond +// to the operators new/delete and new[]/delete[]. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. +// +// { +// scoped_ptr foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. +// +// Example usage (scoped_array): +// { +// scoped_array foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } + +#ifndef COMMON_SCOPED_PTR_H_ +#define COMMON_SCOPED_PTR_H_ + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class, and its closely-related brethren, +// scoped_array, scoped_ptr_malloc. + +#include +#include +#include + +namespace google_breakpad { + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr is thread-compatible, and once you +// dereference it, you get the threadsafety guarantees of T. +// +// The size of a scoped_ptr is small: +// sizeof(scoped_ptr) == sizeof(C*) +template +class scoped_ptr { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with new. + explicit scoped_ptr(C* p = NULL) : ptr_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_ptr() { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != ptr_) { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + ptr_ = p; + } + } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + C* get() const { return ptr_; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return ptr_ == p; } + bool operator!=(C* p) const { return ptr_ != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + C* tmp = ptr_; + ptr_ = p2.ptr_; + p2.ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + private: + C* ptr_; + + // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't + // make sense, and if C2 == C, it still doesn't make sense because you should + // never have the same object owned by two different scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; + + // Disallow evil constructors + scoped_ptr(const scoped_ptr&); + void operator=(const scoped_ptr&); +}; + +// Free functions +template +void swap(scoped_ptr& p1, scoped_ptr& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_ptr& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_ptr& p2) { + return p1 != p2.get(); +} + +// scoped_array is like scoped_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// scoped_array is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether two scoped_array refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return array_ == p; } + bool operator!=(C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + +// Free functions +template +void swap(scoped_array& p1, scoped_array& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_array& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_array& p2) { + return p1 != p2.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 +class scoped_ptr_malloc { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with an allocator that matches the + // Free functor. For the default Free functor, this is malloc, calloc, or + // realloc. + explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} + + // Destructor. If there is a C object, call the Free functor. + ~scoped_ptr_malloc() { + reset(); + } + + // Reset. Calls the Free functor on the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (ptr_ != p) { + FreeProc free_proc; + free_proc(ptr_); + ptr_ = p; + } + } + + // Get the current object. + // operator* and operator-> will cause an assert() failure if there is + // no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + + C* get() const { + return ptr_; + } + + // Comparison operators. + // These return whether a scoped_ptr_malloc and a plain pointer refer + // to the same object, not just to two different but equal objects. + // For compatibility with the boost-derived implementation, these + // take non-const arguments. + bool operator==(C* p) const { + return ptr_ == p; + } + + bool operator!=(C* p) const { + return ptr_ != p; + } + + // Swap two scoped pointers. + void swap(scoped_ptr_malloc & b) { + C* tmp = b.ptr_; + b.ptr_ = ptr_; + ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* tmp = ptr_; + ptr_ = NULL; + return tmp; + } + + private: + C* ptr_; + + // no reason to use these: each scoped_ptr_malloc should have its own object + template + bool operator==(scoped_ptr_malloc const& p) const; + template + bool operator!=(scoped_ptr_malloc const& p) const; + + // Disallow evil constructors + scoped_ptr_malloc(const scoped_ptr_malloc&); + void operator=(const scoped_ptr_malloc&); +}; + +template inline +void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { + a.swap(b); +} + +template inline +bool operator==(C* p, const scoped_ptr_malloc& b) { + return p == b.get(); +} + +template inline +bool operator!=(C* p, const scoped_ptr_malloc& b) { + return p != b.get(); +} + +} // namespace google_breakpad + +#endif // COMMON_SCOPED_PTR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc new file mode 100644 index 0000000000..e0a74ceeb4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc @@ -0,0 +1,45 @@ +// 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. + +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +namespace { + +// In C++98 (ISO 14882), section 9.5.1 says that a union cannot have a member +// with a non-trivial ctor, copy ctor, dtor, or assignment operator. Use this +// property to ensure that Entry remains POD. +union Compile_Assert { + NonAllocatingMap<1, 1, 1>::Entry Compile_Assert__entry_must_be_pod; +}; + +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h new file mode 100644 index 0000000000..9484920537 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h @@ -0,0 +1,279 @@ +// 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. + +#ifndef COMMON_SIMPLE_STRING_DICTIONARY_H_ +#define COMMON_SIMPLE_STRING_DICTIONARY_H_ + +#include +#include + +#include "common/basictypes.h" + +namespace google_breakpad { + +// Opaque type for the serialized representation of a NonAllocatingMap. One is +// created in NonAllocatingMap::Serialize and can be deserialized using one of +// the constructors. +struct SerializedNonAllocatingMap; + +// NonAllocatingMap is an implementation of a map/dictionary collection that +// uses a fixed amount of storage, so that it does not perform any dynamic +// allocations for its operations. +// +// The actual map storage (the Entry) is guaranteed to be POD, so that it can +// be transmitted over various IPC mechanisms. +// +// The template parameters control the amount of storage used for the key, +// value, and map. The KeySize and ValueSize are measured in bytes, not glyphs, +// and includes space for a \0 byte. This gives space for KeySize-1 and +// ValueSize-1 characters in an entry. NumEntries is the total number of +// entries that will fit in the map. +template +class NonAllocatingMap { + public: + // Constant and publicly accessible versions of the template parameters. + static const size_t key_size = KeySize; + static const size_t value_size = ValueSize; + static const size_t num_entries = NumEntries; + + // An Entry object is a single entry in the map. If the key is a 0-length + // NUL-terminated string, the entry is empty. + struct Entry { + char key[KeySize]; + char value[ValueSize]; + + bool is_active() const { + return key[0] != '\0'; + } + }; + + // An Iterator can be used to iterate over all the active entries in a + // NonAllocatingMap. + class Iterator { + public: + explicit Iterator(const NonAllocatingMap& map) + : map_(map), + current_(0) { + } + + // Returns the next entry in the map, or NULL if at the end of the + // collection. + const Entry* Next() { + while (current_ < map_.num_entries) { + const Entry* entry = &map_.entries_[current_++]; + if (entry->is_active()) { + return entry; + } + } + return NULL; + } + + private: + const NonAllocatingMap& map_; + size_t current_; + + DISALLOW_COPY_AND_ASSIGN(Iterator); + }; + + NonAllocatingMap() : entries_() { + } + + NonAllocatingMap(const NonAllocatingMap& other) { + *this = other; + } + + NonAllocatingMap& operator=(const NonAllocatingMap& other) { + assert(other.key_size == key_size); + assert(other.value_size == value_size); + assert(other.num_entries == num_entries); + if (other.key_size == key_size && other.value_size == value_size && + other.num_entries == num_entries) { + memcpy(entries_, other.entries_, sizeof(entries_)); + } + return *this; + } + + // Constructs a map from its serialized form. |map| should be the out + // parameter from Serialize() and |size| should be its return value. + NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) { + assert(size == sizeof(entries_)); + if (size == sizeof(entries_)) { + memcpy(entries_, map, size); + } + } + + // Returns the number of active key/value pairs. The upper limit for this + // is NumEntries. + size_t GetCount() const { + size_t count = 0; + for (size_t i = 0; i < num_entries; ++i) { + if (entries_[i].is_active()) { + ++count; + } + } + return count; + } + + // Given |key|, returns its corresponding |value|. |key| must not be NULL. If + // the key is not found, NULL is returned. + const char* GetValueForKey(const char* key) const { + assert(key); + if (!key) + return NULL; + + size_t index = GetEntryIndexForKey(key); + if (index == num_entries) + return NULL; + + return entries_[index].value; + } + + // Stores |value| into |key|, replacing the existing value if |key| is + // already present. |key| must not be NULL. If |value| is NULL, the key is + // removed from the map. If there is no more space in the map, then the + // operation silently fails. Returns an index into the map that can be used + // to quickly access the entry, or |num_entries| on failure or when clearing + // a key with a null value. + size_t SetKeyValue(const char* key, const char* value) { + if (!value) { + RemoveKey(key); + return num_entries; + } + + assert(key); + if (!key) + return num_entries; + + // Key must not be an empty string. + assert(key[0] != '\0'); + if (key[0] == '\0') + return num_entries; + + size_t entry_index = GetEntryIndexForKey(key); + + // If it does not yet exist, attempt to insert it. + if (entry_index == num_entries) { + for (size_t i = 0; i < num_entries; ++i) { + if (!entries_[i].is_active()) { + entry_index = i; + Entry* entry = &entries_[i]; + + strncpy(entry->key, key, key_size); + entry->key[key_size - 1] = '\0'; + + break; + } + } + } + + // If the map is out of space, entry will be NULL. + if (entry_index == num_entries) + return num_entries; + +#ifndef NDEBUG + // Sanity check that the key only appears once. + int count = 0; + for (size_t i = 0; i < num_entries; ++i) { + if (strncmp(entries_[i].key, key, key_size) == 0) + ++count; + } + assert(count == 1); +#endif + + strncpy(entries_[entry_index].value, value, value_size); + entries_[entry_index].value[value_size - 1] = '\0'; + + return entry_index; + } + + // Sets a value for a key that has already been set with SetKeyValue(), using + // the index returned from that function. + void SetValueAtIndex(size_t index, const char* value) { + assert(index < num_entries); + if (index >= num_entries) + return; + + Entry* entry = &entries_[index]; + assert(entry->key[0] != '\0'); + + strncpy(entry->value, value, value_size); + entry->value[value_size - 1] = '\0'; + } + + // Given |key|, removes any associated value. |key| must not be NULL. If + // the key is not found, this is a noop. This invalidates the index + // returned by SetKeyValue(). + bool RemoveKey(const char* key) { + assert(key); + if (!key) + return false; + + return RemoveAtIndex(GetEntryIndexForKey(key)); + } + + // Removes a value and key using an index that was returned from + // SetKeyValue(). After a call to this function, the index is invalidated. + bool RemoveAtIndex(size_t index) { + if (index >= num_entries) + return false; + + entries_[index].key[0] = '\0'; + entries_[index].value[0] = '\0'; + return true; + } + + // Places a serialized version of the map into |map| and returns the size. + // Both of these should be passed to the deserializing constructor. Note that + // the serialized |map| is scoped to the lifetime of the non-serialized + // instance of this class. The |map| can be copied across IPC boundaries. + size_t Serialize(const SerializedNonAllocatingMap** map) const { + *map = reinterpret_cast(entries_); + return sizeof(entries_); + } + + private: + size_t GetEntryIndexForKey(const char* key) const { + for (size_t i = 0; i < num_entries; ++i) { + if (strncmp(key, entries_[i].key, key_size) == 0) { + return i; + } + } + return num_entries; + } + + Entry entries_[NumEntries]; +}; + +// For historical reasons this specialized version is available with the same +// size factors as a previous implementation. +typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary; + +} // namespace google_breakpad + +#endif // COMMON_SIMPLE_STRING_DICTIONARY_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc new file mode 100644 index 0000000000..e7b8fd7632 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc @@ -0,0 +1,339 @@ +// 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. + +#include "breakpad_googletest_includes.h" +#include "common/simple_string_dictionary.h" + +namespace google_breakpad { + +TEST(NonAllocatingMapTest, Entry) { + typedef NonAllocatingMap<5, 9, 15> TestMap; + TestMap map; + + const TestMap::Entry* entry = TestMap::Iterator(map).Next(); + EXPECT_FALSE(entry); + + // Try setting a key/value and then verify. + map.SetKeyValue("key1", "value1"); + entry = TestMap::Iterator(map).Next(); + ASSERT_TRUE(entry); + EXPECT_STREQ(entry->key, "key1"); + EXPECT_STREQ(entry->value, "value1"); + + // Try setting a new value. + map.SetKeyValue("key1", "value3"); + EXPECT_STREQ(entry->value, "value3"); + + // Make sure the key didn't change. + EXPECT_STREQ(entry->key, "key1"); + + // Clear the entry and verify the key and value are empty strings. + map.RemoveKey("key1"); + EXPECT_FALSE(entry->is_active()); + EXPECT_EQ(strlen(entry->key), 0u); + EXPECT_EQ(strlen(entry->value), 0u); +} + +TEST(NonAllocatingMapTest, SimpleStringDictionary) { + // Make a new dictionary + SimpleStringDictionary dict; + + // Set three distinct values on three keys + dict.SetKeyValue("key1", "value1"); + dict.SetKeyValue("key2", "value2"); + dict.SetKeyValue("key3", "value3"); + + EXPECT_NE(dict.GetValueForKey("key1"), "value1"); + EXPECT_NE(dict.GetValueForKey("key2"), "value2"); + EXPECT_NE(dict.GetValueForKey("key3"), "value3"); + EXPECT_EQ(dict.GetCount(), 3u); + // try an unknown key + EXPECT_FALSE(dict.GetValueForKey("key4")); + + // Remove a key + dict.RemoveKey("key3"); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict.GetValueForKey("key3")); + + // Remove by setting value to NULL + dict.SetKeyValue("key2", NULL); + + // Now make sure it's not there anymore + EXPECT_FALSE(dict.GetValueForKey("key2")); +} + +TEST(NonAllocatingMapTest, CopyAndAssign) { + NonAllocatingMap<10, 10, 10> map; + map.SetKeyValue("one", "a"); + map.SetKeyValue("two", "b"); + map.SetKeyValue("three", "c"); + map.RemoveKey("two"); + EXPECT_EQ(2u, map.GetCount()); + + // Test copy. + NonAllocatingMap<10, 10, 10> map_copy(map); + EXPECT_EQ(2u, map_copy.GetCount()); + EXPECT_STREQ("a", map_copy.GetValueForKey("one")); + EXPECT_STREQ("c", map_copy.GetValueForKey("three")); + map_copy.SetKeyValue("four", "d"); + EXPECT_STREQ("d", map_copy.GetValueForKey("four")); + EXPECT_FALSE(map.GetValueForKey("four")); + + // Test assign. + NonAllocatingMap<10, 10, 10> map_assign; + map_assign = map; + EXPECT_EQ(2u, map_assign.GetCount()); + EXPECT_STREQ("a", map_assign.GetValueForKey("one")); + EXPECT_STREQ("c", map_assign.GetValueForKey("three")); + map_assign.SetKeyValue("four", "d"); + EXPECT_STREQ("d", map_assign.GetValueForKey("four")); + EXPECT_FALSE(map.GetValueForKey("four")); + + map.RemoveKey("one"); + EXPECT_FALSE(map.GetValueForKey("one")); + EXPECT_STREQ("a", map_copy.GetValueForKey("one")); + EXPECT_STREQ("a", map_assign.GetValueForKey("one")); +} + +// Add a bunch of values to the dictionary, remove some entries in the middle, +// and then add more. +TEST(NonAllocatingMapTest, Iterator) { + SimpleStringDictionary* dict = new SimpleStringDictionary(); + ASSERT_TRUE(dict); + + char key[SimpleStringDictionary::key_size]; + char value[SimpleStringDictionary::value_size]; + + const int kDictionaryCapacity = SimpleStringDictionary::num_entries; + const int kPartitionIndex = kDictionaryCapacity - 5; + + // We assume at least this size in the tests below + ASSERT_GE(kDictionaryCapacity, 64); + + // We'll keep track of the number of key/value pairs we think should + // be in the dictionary + int expectedDictionarySize = 0; + + // Set a bunch of key/value pairs like key0/value0, key1/value1, ... + for (int i = 0; i < kPartitionIndex; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize = kPartitionIndex; + + // set a couple of the keys twice (with the same value) - should be nop + dict->SetKeyValue("key2", "value2"); + dict->SetKeyValue("key4", "value4"); + dict->SetKeyValue("key15", "value15"); + + // Remove some random elements in the middle + dict->RemoveKey("key7"); + dict->RemoveKey("key18"); + dict->RemoveKey("key23"); + dict->RemoveKey("key31"); + expectedDictionarySize -= 4; // we just removed four key/value pairs + + // Set some more key/value pairs like key59/value59, key60/value60, ... + for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { + sprintf(key, "key%d", i); + sprintf(value, "value%d", i); + dict->SetKeyValue(key, value); + } + expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; + + // Now create an iterator on the dictionary + SimpleStringDictionary::Iterator iter(*dict); + + // We then verify that it iterates through exactly the number of + // key/value pairs we expect, and that they match one-for-one with what we + // would expect. The ordering of the iteration does not matter... + + // used to keep track of number of occurrences found for key/value pairs + int count[kDictionaryCapacity]; + memset(count, 0, sizeof(count)); + + int totalCount = 0; + + const SimpleStringDictionary::Entry* entry; + while ((entry = iter.Next())) { + totalCount++; + + // Extract keyNumber from a string of the form key + int keyNumber; + sscanf(entry->key, "key%d", &keyNumber); + + // Extract valueNumber from a string of the form value + int valueNumber; + sscanf(entry->value, "value%d", &valueNumber); + + // The value number should equal the key number since that's how we set them + EXPECT_EQ(keyNumber, valueNumber); + + // Key and value numbers should be in proper range: + // 0 <= keyNumber < kDictionaryCapacity + bool isKeyInGoodRange = + (keyNumber >= 0 && keyNumber < kDictionaryCapacity); + bool isValueInGoodRange = + (valueNumber >= 0 && valueNumber < kDictionaryCapacity); + EXPECT_TRUE(isKeyInGoodRange); + EXPECT_TRUE(isValueInGoodRange); + + if (isKeyInGoodRange && isValueInGoodRange) { + ++count[keyNumber]; + } + } + + // Make sure each of the key/value pairs showed up exactly one time, except + // for the ones which we removed. + for (size_t i = 0; i < kDictionaryCapacity; ++i) { + // Skip over key7, key18, key23, and key31, since we removed them + if (!(i == 7 || i == 18 || i == 23 || i == 31)) { + EXPECT_EQ(count[i], 1); + } + } + + // Make sure the number of iterations matches the expected dictionary size. + EXPECT_EQ(totalCount, expectedDictionarySize); +} + + +TEST(NonAllocatingMapTest, AddRemove) { + NonAllocatingMap<5, 7, 6> map; + map.SetKeyValue("rob", "ert"); + map.SetKeyValue("mike", "pink"); + map.SetKeyValue("mark", "allays"); + + EXPECT_EQ(3u, map.GetCount()); + EXPECT_STREQ("ert", map.GetValueForKey("rob")); + EXPECT_STREQ("pink", map.GetValueForKey("mike")); + EXPECT_STREQ("allays", map.GetValueForKey("mark")); + + map.RemoveKey("mike"); + + EXPECT_EQ(2u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("mike")); + + map.SetKeyValue("mark", "mal"); + EXPECT_EQ(2u, map.GetCount()); + EXPECT_STREQ("mal", map.GetValueForKey("mark")); + + map.RemoveKey("mark"); + EXPECT_EQ(1u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("mark")); +} + +TEST(NonAllocatingMapTest, Serialize) { + typedef NonAllocatingMap<4, 5, 7> TestMap; + TestMap map; + map.SetKeyValue("one", "abc"); + map.SetKeyValue("two", "def"); + map.SetKeyValue("tre", "hig"); + + EXPECT_STREQ("abc", map.GetValueForKey("one")); + EXPECT_STREQ("def", map.GetValueForKey("two")); + EXPECT_STREQ("hig", map.GetValueForKey("tre")); + + const SerializedNonAllocatingMap* serialized; + size_t size = map.Serialize(&serialized); + + SerializedNonAllocatingMap* serialized_copy = + reinterpret_cast(malloc(size)); + ASSERT_TRUE(serialized_copy); + memcpy(serialized_copy, serialized, size); + + TestMap deserialized(serialized_copy, size); + free(serialized_copy); + + EXPECT_EQ(3u, deserialized.GetCount()); + EXPECT_STREQ("abc", deserialized.GetValueForKey("one")); + EXPECT_STREQ("def", deserialized.GetValueForKey("two")); + EXPECT_STREQ("hig", deserialized.GetValueForKey("tre")); +} + +// Running out of space shouldn't crash. +TEST(NonAllocatingMapTest, OutOfSpace) { + NonAllocatingMap<3, 2, 2> map; + map.SetKeyValue("a", "1"); + map.SetKeyValue("b", "2"); + map.SetKeyValue("c", "3"); + EXPECT_EQ(2u, map.GetCount()); + EXPECT_FALSE(map.GetValueForKey("c")); +} + +TEST(NonAllocatingMapTest, ByIndex) { + NonAllocatingMap<10, 10, 3> map; + + size_t index1 = map.SetKeyValue("test", "one"); + EXPECT_TRUE(index1 >= 0 && index1 <= map.num_entries); + + size_t index2 = map.SetKeyValue("moo", "foo"); + EXPECT_TRUE(index2 >= 0 && index2 <= map.num_entries); + EXPECT_NE(index1, index2); + + size_t index3 = map.SetKeyValue("blob", "kebab"); + EXPECT_TRUE(index3 >= 0 && index3 <= map.num_entries); + EXPECT_NE(index2, index3); + + size_t index4 = map.SetKeyValue("nogo", "full"); + EXPECT_TRUE(index4 == map.num_entries); + + EXPECT_STREQ("one", map.GetValueForKey("test")); + EXPECT_STREQ("foo", map.GetValueForKey("moo")); + EXPECT_STREQ("kebab", map.GetValueForKey("blob")); + + map.SetValueAtIndex(index2, "booo"); + EXPECT_STREQ("booo", map.GetValueForKey("moo")); + + EXPECT_TRUE(map.RemoveAtIndex(index1)); + EXPECT_FALSE(map.GetValueForKey("test")); + + EXPECT_FALSE(map.RemoveAtIndex(map.num_entries)); + EXPECT_FALSE(map.RemoveAtIndex(9999)); +} + +#ifndef NDEBUG + +TEST(NonAllocatingMapTest, NullKey) { + NonAllocatingMap<4, 6, 6> map; + ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), ""); + + map.SetKeyValue("hi", "there"); + ASSERT_DEATH(map.GetValueForKey(NULL), ""); + EXPECT_STREQ("there", map.GetValueForKey("hi")); + + ASSERT_DEATH(map.GetValueForKey(NULL), ""); + map.RemoveKey("hi"); + EXPECT_EQ(0u, map.GetCount()); +} + +#endif // !NDEBUG + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc new file mode 100644 index 0000000000..168d0b2879 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc @@ -0,0 +1,681 @@ +// Copyright (c) 2010 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. + +// Author: Alfred Peng + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/scoped_ptr.h" +#include "common/solaris/dump_symbols.h" +#include "common/solaris/file_id.h" +#include "common/solaris/guid_creator.h" + +// This namespace contains helper functions. +namespace { + +using std::make_pair; + +#if defined(_LP64) +typedef Elf64_Sym Elf_Sym; +#else +typedef Elf32_Sym Elf_Sym; +#endif + +// Symbol table entry from stabs. Sun CC specific. +struct slist { + // String table index. + unsigned int n_strx; + // Stab type. + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; + +// Symbol table entry +struct SymbolEntry { + // Offset from the start of the file. + GElf_Addr offset; + // Function size. + GElf_Word size; +}; + +// Infomation of a line. +struct LineInfo { + // Offset from start of the function. + // Load from stab symbol. + GElf_Off rva_to_func; + // Offset from base of the loading binary. + GElf_Off rva_to_base; + // Size of the line. + // The first line: equals to rva_to_func. + // The other lines: the difference of rva_to_func of the line and + // rva_to_func of the previous N_SLINE. + uint32_t size; + // Line number. + uint32_t line_num; +}; + +// Information of a function. +struct FuncInfo { + // Name of the function. + const char *name; + // Offset from the base of the loading address. + GElf_Off rva_to_base; + // Virtual address of the function. + // Load from stab symbol. + GElf_Addr addr; + // Size of the function. + // Equal to rva_to_func of the last function line. + uint32_t size; + // Total size of stack parameters. + uint32_t stack_param_size; + // Line information array. + std::vector line_info; +}; + +// Information of a source file. +struct SourceFileInfo { + // Name of the source file. + const char *name; + // Starting address of the source file. + GElf_Addr addr; + // Id of the source file. + int source_id; + // Functions information. + std::vector func_info; +}; + +struct CompareString { + bool operator()(const char *s1, const char *s2) const { + return strcmp(s1, s2) < 0; + } +}; + +typedef std::map SymbolMap; + +// Information of a symbol table. +// This is the root of all types of symbol. +struct SymbolInfo { + std::vector source_file_info; + // Symbols information. + SymbolMap symbol_entries; +}; + +// Stab section name. +const char *kStabName = ".stab"; + +// Stab str section name. +const char *kStabStrName = ".stabstr"; + +// Symtab section name. +const char *kSymtabName = ".symtab"; + +// Strtab section name. +const char *kStrtabName = ".strtab"; + +// Default buffer lenght for demangle. +const int demangleLen = 20000; + +// Offset to the string table. +uint64_t stringOffset = 0; + +// Update the offset to the start of the string index of the next +// object module for every N_ENDM stabs. +inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { + while ((--cur_list)->n_strx == 0) ; + stringOffset += cur_list->n_strx; + + char *temp = stabstr + stringOffset; + while (*temp != '\0') { + ++stringOffset; + ++temp; + } + // Skip the extra '\0' + ++stringOffset; +} + +// Demangle using demangle library on Solaris. +std::string Demangle(const char *mangled) { + int status = 0; + std::string str(mangled); + char *demangled = (char *)malloc(demangleLen); + + if (!demangled) { + fprintf(stderr, "no enough memory.\n"); + goto out; + } + + if ((status = cplus_demangle(mangled, demangled, demangleLen)) == + DEMANGLE_ESPACE) { + fprintf(stderr, "incorrect demangle.\n"); + goto out; + } + + str = demangled; + free(demangled); + +out: + return str; +} + +bool WriteFormat(int fd, const char *fmt, ...) { + va_list list; + char buffer[4096]; + ssize_t expected, written; + va_start(list, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, list); + expected = strlen(buffer); + written = write(fd, buffer, strlen(buffer)); + va_end(list); + return expected == written; +} + +bool IsValidElf(const GElf_Ehdr *elf_header) { + return memcmp(elf_header, ELFMAG, SELFMAG) == 0; +} + +static bool FindSectionByName(Elf *elf, const char *name, + int shstrndx, + GElf_Shdr *shdr) { + assert(name != NULL); + + if (strlen(name) == 0) + return false; + + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { + fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); + return false; + } + + const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); + if (!section_name) { + fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); + continue; + } + + if (strcmp(section_name, name) == 0) + return true; + } + + return false; +} + +// The parameter size is used for FPO-optimized code, and +// this is all tied up with the debugging data for Windows x86. +// Set it to 0 on Solaris. +int LoadStackParamSize(struct slist *list, + struct slist *list_end, + struct FuncInfo *func_info) { + struct slist *cur_list = list; + int step = 1; + while (cur_list < list_end && cur_list->n_type == N_PSYM) { + ++cur_list; + ++step; + } + + func_info->stack_param_size = 0; + return step; +} + +int LoadLineInfo(struct slist *list, + struct slist *list_end, + struct FuncInfo *func_info) { + struct slist *cur_list = list; + do { + // Skip non line information. + while (cur_list < list_end && cur_list->n_type != N_SLINE) { + // Only exit when got another function, or source file, or end stab. + if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || + cur_list->n_type == N_ENDM) { + return cur_list - list; + } + ++cur_list; + } + struct LineInfo line; + while (cur_list < list_end && cur_list->n_type == N_SLINE) { + line.rva_to_func = cur_list->n_value; + // n_desc is a signed short + line.line_num = (unsigned short)cur_list->n_desc; + func_info->line_info.push_back(line); + ++cur_list; + } + if (cur_list == list_end && cur_list->n_type == N_ENDM) + break; + } while (list < list_end); + + return cur_list - list; +} + +int LoadFuncSymbols(struct slist *list, + struct slist *list_end, + char *stabstr, + GElf_Word base, + struct SourceFileInfo *source_file_info) { + struct slist *cur_list = list; + assert(cur_list->n_type == N_SO); + ++cur_list; + + source_file_info->func_info.clear(); + while (cur_list < list_end) { + // Go until the function symbol. + while (cur_list < list_end && cur_list->n_type != N_FUN) { + if (cur_list->n_type == N_SO) { + return cur_list - list; + } + ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + continue; + } + while (cur_list->n_type == N_FUN) { + struct FuncInfo func_info; + memset(&func_info, 0, sizeof(func_info)); + func_info.name = stabstr + cur_list->n_strx + stringOffset; + // The n_value field is always 0 from stab generated by Sun CC. + // TODO(Alfred): Find the correct value. + func_info.addr = cur_list->n_value; + ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && + cur_list->n_type != N_FUN) { + // Stack parameter size. + cur_list += LoadStackParamSize(cur_list, list_end, &func_info); + // Line info. + cur_list += LoadLineInfo(cur_list, list_end, &func_info); + } + if (cur_list < list_end && cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + // Functions in this module should have address bigger than the module + // starting address. + // + // These two values are always 0 with Sun CC. + // TODO(Alfred): Get the correct value or remove the condition statement. + if (func_info.addr >= source_file_info->addr) { + source_file_info->func_info.push_back(func_info); + } + } + } + return cur_list - list; +} + +// Compute size and rva information based on symbols loaded from stab section. +bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { + std::vector *sorted_files = + &(symbols->source_file_info); + SymbolMap *symbol_entries = &(symbols->symbol_entries); + for (size_t i = 0; i < sorted_files->size(); ++i) { + struct SourceFileInfo &source_file = (*sorted_files)[i]; + std::vector *sorted_functions = &(source_file.func_info); + int func_size = sorted_functions->size(); + + for (size_t j = 0; j < func_size; ++j) { + struct FuncInfo &func_info = (*sorted_functions)[j]; + int line_count = func_info.line_info.size(); + + // Discard the ending part of the name. + std::string func_name(func_info.name); + std::string::size_type last_colon = func_name.find_first_of(':'); + if (last_colon != std::string::npos) + func_name = func_name.substr(0, last_colon); + + // Fine the symbol offset from the loading address and size by name. + SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); + if (it->second) { + func_info.rva_to_base = it->second->offset; + func_info.size = (line_count == 0) ? 0 : it->second->size; + } else { + func_info.rva_to_base = 0; + func_info.size = 0; + } + + // Compute function and line size. + for (size_t k = 0; k < line_count; ++k) { + struct LineInfo &line_info = func_info.line_info[k]; + + line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; + if (k == line_count - 1) { + line_info.size = func_info.size - line_info.rva_to_func; + } else { + struct LineInfo &next_line = func_info.line_info[k + 1]; + line_info.size = next_line.rva_to_func - line_info.rva_to_func; + } + } // for each line. + } // for each function. + } // for each source file. + for (SymbolMap::iterator it = symbol_entries->begin(); + it != symbol_entries->end(); ++it) { + free(it->second); + } + return true; +} + +bool LoadAllSymbols(const GElf_Shdr *stab_section, + const GElf_Shdr *stabstr_section, + GElf_Word base, + struct SymbolInfo *symbols) { + if (stab_section == NULL || stabstr_section == NULL) + return false; + + char *stabstr = + reinterpret_cast(stabstr_section->sh_offset + base); + struct slist *lists = + reinterpret_cast(stab_section->sh_offset + base); + int nstab = stab_section->sh_size / sizeof(struct slist); + int source_id = 0; + + // First pass, load all symbols from the object file. + for (int i = 0; i < nstab; ) { + int step = 1; + struct slist *cur_list = lists + i; + if (cur_list->n_type == N_SO) { + // FUNC
+ struct SourceFileInfo source_file_info; + source_file_info.name = stabstr + cur_list->n_strx + stringOffset; + // The n_value field is always 0 from stab generated by Sun CC. + // TODO(Alfred): Find the correct value. + source_file_info.addr = cur_list->n_value; + if (strchr(source_file_info.name, '.')) + source_file_info.source_id = source_id++; + else + source_file_info.source_id = -1; + step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, + base, &source_file_info); + symbols->source_file_info.push_back(source_file_info); + } + i += step; + } + // Second pass, compute the size of functions and lines. + return ComputeSizeAndRVA(symbols); +} + +bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, + void *obj_base) { + GElf_Word base = reinterpret_cast(obj_base); + + const GElf_Shdr *sections = + reinterpret_cast(elf_header->e_shoff + base); + GElf_Shdr stab_section; + if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, + &stab_section)) { + fprintf(stderr, "Stab section not found.\n"); + return false; + } + GElf_Shdr stabstr_section; + if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx, + &stabstr_section)) { + fprintf(stderr, "Stabstr section not found.\n"); + return false; + } + GElf_Shdr symtab_section; + if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, + &symtab_section)) { + fprintf(stderr, "Symtab section not found.\n"); + return false; + } + GElf_Shdr strtab_section; + if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, + &strtab_section)) { + fprintf(stderr, "Strtab section not found.\n"); + return false; + } + + Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); + for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { + struct SymbolEntry *symbol_entry = + (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); + const char *name = reinterpret_cast( + strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); + symbol_entry->offset = symbol->st_value; + symbol_entry->size = symbol->st_size; + symbols->symbol_entries.insert(make_pair(name, symbol_entry)); + ++symbol; + } + + + // Load symbols. + return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); +} + +bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { + const char *arch_name = NULL; + if (arch == EM_386) + arch_name = "x86"; + else if (arch == EM_X86_64) + arch_name = "x86_64"; + else if (arch == EM_SPARC32PLUS) + arch_name = "SPARC_32+"; + else { + printf("Please add more ARCH support\n"); + return false; + } + + unsigned char identifier[16]; + google_breakpad::FileID file_id(obj_file.c_str()); + if (file_id.ElfFileIdentifier(identifier)) { + char identifier_str[40]; + file_id.ConvertIdentifierToString(identifier, + identifier_str, sizeof(identifier_str)); + std::string filename = obj_file; + size_t slash_pos = obj_file.find_last_of("/"); + if (slash_pos != std::string::npos) + filename = obj_file.substr(slash_pos + 1); + return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name, + identifier_str, filename.c_str()); + } + return false; +} + +bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { + if (symbols.source_file_info[i].source_id != -1) { + const char *name = symbols.source_file_info[i].name; + if (!WriteFormat(fd, "FILE %d %s\n", + symbols.source_file_info[i].source_id, name)) + return false; + } + } + return true; +} + +bool WriteOneFunction(int fd, int source_id, + const struct FuncInfo &func_info){ + // Discard the ending part of the name. + std::string func_name(func_info.name); + std::string::size_type last_colon = func_name.find_last_of(':'); + if (last_colon != std::string::npos) + func_name = func_name.substr(0, last_colon); + func_name = Demangle(func_name.c_str()); + + if (func_info.size <= 0) + return true; + + // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). + if (WriteFormat(fd, "FUNC %llx %x %d %s\n", + (long long)func_info.rva_to_base, + func_info.size, + func_info.stack_param_size, + func_name.c_str())) { + for (size_t i = 0; i < func_info.line_info.size(); ++i) { + const struct LineInfo &line_info = func_info.line_info[i]; + if (line_info.line_num == 0) + return true; + if (!WriteFormat(fd, "%llx %x %d %d\n", + (long long)line_info.rva_to_base, + line_info.size, + line_info.line_num, + source_id)) + return false; + } + return true; + } + return false; +} + +bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { + const struct SourceFileInfo &file_info = symbols.source_file_info[i]; + for (size_t j = 0; j < file_info.func_info.size(); ++j) { + const struct FuncInfo &func_info = file_info.func_info[j]; + if (!WriteOneFunction(fd, file_info.source_id, func_info)) + return false; + } + } + return true; +} + +bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { + return WriteSourceFileInfo(fd, symbols) && + WriteFunctionInfo(fd, symbols); +} + +// +// FDWrapper +// +// Wrapper class to make sure opened file is closed. +// +class FDWrapper { + public: + explicit FDWrapper(int fd) : + fd_(fd) { + } + ~FDWrapper() { + if (fd_ != -1) + close(fd_); + } + int get() { + return fd_; + } + int release() { + int fd = fd_; + fd_ = -1; + return fd; + } + private: + int fd_; +}; + +// +// MmapWrapper +// +// Wrapper class to make sure mapped regions are unmapped. +// +class MmapWrapper { + public: + MmapWrapper(void *mapped_address, size_t mapped_size) : + base_(mapped_address), size_(mapped_size) { + } + ~MmapWrapper() { + if (base_ != NULL) { + assert(size_ > 0); + munmap((char *)base_, size_); + } + } + void release() { + base_ = NULL; + size_ = 0; + } + + private: + void *base_; + size_t size_; +}; + +} // namespace + +namespace google_breakpad { + +class AutoElfEnder { + public: + AutoElfEnder(Elf *elf) : elf_(elf) {} + ~AutoElfEnder() { if (elf_) elf_end(elf_); } + private: + Elf *elf_; +}; + + +bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { + if (elf_version(EV_CURRENT) == EV_NONE) { + fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); + return false; + } + + int obj_fd = open(obj_file.c_str(), O_RDONLY); + if (obj_fd < 0) + return false; + FDWrapper obj_fd_wrapper(obj_fd); + struct stat st; + if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) + return false; + void *obj_base = mmap(NULL, st.st_size, + PROT_READ, MAP_PRIVATE, obj_fd, 0); + if (obj_base == MAP_FAILED) + return false; + MmapWrapper map_wrapper(obj_base, st.st_size); + GElf_Ehdr elf_header; + Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); + AutoElfEnder elfEnder(elf); + + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); + return false; + } + + if (!IsValidElf(&elf_header)) { + fprintf(stderr, "header magic doesn't match\n"); + return false; + } + struct SymbolInfo symbols; + if (!LoadSymbols(elf, &elf_header, &symbols, obj_base)) + return false; + // Write to symbol file. + if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) && + DumpStabSymbols(sym_fd, symbols)) + return true; + + return false; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h new file mode 100644 index 0000000000..7f4baadcfc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h @@ -0,0 +1,49 @@ +// 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. +// +// dump_symbols.cc: Implements a Solaris stab debugging format dumper. +// +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_DUMP_SYMBOLS_H__ +#define COMMON_SOLARIS_DUMP_SYMBOLS_H__ + +#include + +namespace google_breakpad { + +class DumpSymbols { + public: + bool WriteSymbolFile(const std::string &obj_file, + int sym_fd); +}; + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc new file mode 100644 index 0000000000..643a14629d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc @@ -0,0 +1,197 @@ +// 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. + +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// +// Author: Alfred Peng + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common/md5.h" +#include "common/solaris/file_id.h" +#include "common/solaris/message_output.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class AutoElfEnder { + public: + AutoElfEnder(Elf *elf) : elf_(elf) {} + ~AutoElfEnder() { if (elf_) elf_end(elf_); } + private: + Elf *elf_; +}; + +// Find the text section in elf object file. +// Return the section start address and the size. +static bool FindElfTextSection(int fd, const void *elf_base, + const void **text_start, + int *text_size) { + assert(text_start); + assert(text_size); + + *text_start = NULL; + *text_size = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) { + print_message2(2, "elf_version() failed: %s\n", elf_errmsg(0)); + return false; + } + + GElf_Ehdr elf_header; + lseek(fd, 0L, 0); + Elf *elf = elf_begin(fd, ELF_C_READ, NULL); + AutoElfEnder elfEnder(elf); + + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1)); + return false; + } + + if (elf_header.e_ident[EI_MAG0] != ELFMAG0 || + elf_header.e_ident[EI_MAG1] != ELFMAG1 || + elf_header.e_ident[EI_MAG2] != ELFMAG2 || + elf_header.e_ident[EI_MAG3] != ELFMAG3) { + print_message1(2, "header magic doesn't match\n"); + return false; + } + + static const char kTextSectionName[] = ".text"; + const GElf_Shdr *text_section = NULL; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) { + print_message2(2, "failed to read section header: %s\n", elf_errmsg(0)); + return false; + } + + if (shdr.sh_type == SHT_PROGBITS) { + const char *section_name = elf_strptr(elf, elf_header.e_shstrndx, + shdr.sh_name); + if (!section_name) { + print_message2(2, "Section name error: %s\n", elf_errmsg(-1)); + continue; + } + + if (strcmp(section_name, kTextSectionName) == 0) { + text_section = &shdr; + break; + } + } + } + if (text_section != NULL && text_section->sh_size > 0) { + *text_start = (char *)elf_base + text_section->sh_offset; + *text_size = text_section->sh_size; + return true; + } + + return false; +} + +FileID::FileID(const char *path) { + strcpy(path_, path); +} + +class AutoCloser { + public: + AutoCloser(int fd) : fd_(fd) {} + ~AutoCloser() { if (fd_) close(fd_); } + private: + int fd_; +}; + +bool FileID::ElfFileIdentifier(unsigned char identifier[16]) { + int fd = 0; + if ((fd = open(path_, O_RDONLY)) < 0) + return false; + + AutoCloser autocloser(fd); + struct stat st; + if (fstat(fd, &st) != 0 || st.st_size <= 0) + return false; + + void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (base == MAP_FAILED) + return false; + + bool success = false; + const void *text_section = NULL; + int text_size = 0; + + if (FindElfTextSection(fd, base, &text_section, &text_size)) { + MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, (const unsigned char *)text_section, text_size); + MD5Final(identifier, &md5); + success = true; + } + + munmap((char *)base, st.st_size); + return success; +} + +// static +bool FileID::ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length) { + if (buffer_length < 34) + return false; + + int buffer_idx = 0; + for (int idx = 0; idx < 16; ++idx) { + int hi = (identifier[idx] >> 4) & 0x0F; + int lo = (identifier[idx]) & 0x0F; + + buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; + buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; + } + + // Add an extra "0" by the end. + buffer[buffer_idx++] = '0'; + + // NULL terminate + buffer[buffer_idx] = 0; + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h new file mode 100644 index 0000000000..375e857512 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h @@ -0,0 +1,66 @@ +// 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. + +// file_id.h: Return a unique identifier for a file +// +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_FILE_ID_H__ +#define COMMON_SOLARIS_FILE_ID_H__ + +#include + +namespace google_breakpad { + +class FileID { + public: + FileID(const char *path); + ~FileID() {}; + + // Load the identifier for the elf file path specified in the constructor into + // |identifier|. Return false if the identifier could not be created for the + // file. + // The current implementation will return the MD5 hash of the file's bytes. + bool ElfFileIdentifier(unsigned char identifier[16]); + + // Convert the |identifier| data to a NULL terminated string. The string will + // be formatted as a MDCVInfoPDB70 struct. + // The |buffer| should be at least 34 bytes long to receive all of the data + // and termination. Shorter buffers will return false. + static bool ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length); + + private: + // Storage for the path specified + char path_[PATH_MAX]; +}; + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc new file mode 100644 index 0000000000..e9e6c6f5d2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc @@ -0,0 +1,84 @@ +// 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. + +// Author: Alfred Peng + +#include +#include + +#include +#include +#include + +#include "common/solaris/guid_creator.h" + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID. This should be OK since +// we don't expect crash to happen very offen. +// +class GUIDGenerator { + public: + GUIDGenerator() { + srandom(time(NULL)); + } + + bool CreateGUID(GUID *guid) const { + guid->data1 = random(); + guid->data2 = (uint16_t)(random()); + guid->data3 = (uint16_t)(random()); + *reinterpret_cast(&guid->data4[0]) = random(); + *reinterpret_cast(&guid->data4[4]) = random(); + return true; + } +}; + +// Guid generator. +const GUIDGenerator kGuidGenerator; + +bool CreateGUID(GUID *guid) { + return kGuidGenerator.CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, int buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + *reinterpret_cast(&(guid->data4[0])), + *reinterpret_cast(&(guid->data4[4]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h new file mode 100644 index 0000000000..4aee3a1c24 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h @@ -0,0 +1,50 @@ +// 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. + +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_GUID_CREATOR_H__ +#define COMMON_SOLARIS_GUID_CREATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x" +// Length of GUID string. Don't count the ending '\0'. +#define kGUIDStringLength 36 + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, int buf_len); + +#endif // COMMON_SOLARIS_GUID_CREATOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h new file mode 100644 index 0000000000..3e3b1d4652 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h @@ -0,0 +1,54 @@ +// 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. + +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_MESSAGE_OUTPUT_H__ +#define COMMON_SOLARIS_MESSAGE_OUTPUT_H__ + +namespace google_breakpad { + +const int MESSAGE_MAX = 1000; + +// Message output macros. +// snprintf doesn't operate heap on Solaris, while printf and fprintf do. +// Use snprintf here to avoid heap allocation. +#define print_message1(std, message) \ + char buffer[MESSAGE_MAX]; \ + int len = snprintf(buffer, MESSAGE_MAX, message); \ + write(std, buffer, len) + +#define print_message2(std, message, para) \ + char buffer[MESSAGE_MAX]; \ + int len = snprintf(buffer, MESSAGE_MAX, message, para); \ + write(std, buffer, len); + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_MESSAGE_OUTPUT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc new file mode 100644 index 0000000000..6019fc7ee2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc @@ -0,0 +1,315 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// This file implements the google_breakpad::StabsReader class. +// See stabs_reader.h. + +#include "common/stabs_reader.h" + +#include +#include +#include + +#include + +#include "common/using_std_string.h" + +using std::vector; + +namespace google_breakpad { + +StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer, + bool big_endian, size_t value_size) + : value_size_(value_size), cursor_(buffer, big_endian) { + // Actually, we could handle weird sizes just fine, but they're + // probably mistakes --- expressed in bits, say. + assert(value_size == 4 || value_size == 8); + entry_.index = 0; + Fetch(); +} + +void StabsReader::EntryIterator::Fetch() { + cursor_ + .Read(4, false, &entry_.name_offset) + .Read(1, false, &entry_.type) + .Read(1, false, &entry_.other) + .Read(2, false, &entry_.descriptor) + .Read(value_size_, false, &entry_.value); + entry_.at_end = !cursor_; +} + +StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, + const uint8_t *stabstr, size_t stabstr_size, + bool big_endian, size_t value_size, bool unitized, + StabsHandler *handler) + : entries_(stab, stab_size), + strings_(stabstr, stabstr_size), + iterator_(&entries_, big_endian, value_size), + unitized_(unitized), + handler_(handler), + string_offset_(0), + next_cu_string_offset_(0), + current_source_file_(NULL) { } + +const char *StabsReader::SymbolString() { + ptrdiff_t offset = string_offset_ + iterator_->name_offset; + if (offset < 0 || (size_t) offset >= strings_.Size()) { + handler_->Warning("symbol %d: name offset outside the string section\n", + iterator_->index); + // Return our null string, to keep our promise about all names being + // taken from the string section. + offset = 0; + } + return reinterpret_cast(strings_.start + offset); +} + +bool StabsReader::Process() { + while (!iterator_->at_end) { + if (iterator_->type == N_SO) { + if (! ProcessCompilationUnit()) + return false; + } else if (iterator_->type == N_UNDF && unitized_) { + // In unitized STABS (including Linux STABS, and pretty much anything + // else that puts STABS data in sections), at the head of each + // compilation unit's entries there is an N_UNDF stab giving the + // number of symbols in the compilation unit, and the number of bytes + // that compilation unit's strings take up in the .stabstr section. + // Each CU's strings are separate; the n_strx values are offsets + // within the current CU's portion of the .stabstr section. + // + // As an optimization, the GNU linker combines all the + // compilation units into one, with a single N_UNDF at the + // beginning. However, other linkers, like Gold, do not perform + // this optimization. + string_offset_ = next_cu_string_offset_; + next_cu_string_offset_ = iterator_->value; + ++iterator_; + } +#if defined(HAVE_MACH_O_NLIST_H) + // Export symbols in Mach-O binaries look like this. + // This is necessary in order to be able to dump symbols + // from OS X system libraries. + else if ((iterator_->type & N_STAB) == 0 && + (iterator_->type & N_TYPE) == N_SECT) { + ProcessExtern(); + } +#endif + else { + ++iterator_; + } + } + return true; +} + +bool StabsReader::ProcessCompilationUnit() { + assert(!iterator_->at_end && iterator_->type == N_SO); + + // There may be an N_SO entry whose name ends with a slash, + // indicating the directory in which the compilation occurred. + // The build directory defaults to NULL. + const char *build_directory = NULL; + { + const char *name = SymbolString(); + if (name[0] && name[strlen(name) - 1] == '/') { + build_directory = name; + ++iterator_; + } + } + + // We expect to see an N_SO entry with a filename next, indicating + // the start of the compilation unit. + { + if (iterator_->at_end || iterator_->type != N_SO) + return true; + const char *name = SymbolString(); + if (name[0] == '\0') { + // This seems to be a stray end-of-compilation-unit marker; + // consume it, but don't report the end, since we didn't see a + // beginning. + ++iterator_; + return true; + } + current_source_file_ = name; + } + + if (! handler_->StartCompilationUnit(current_source_file_, + iterator_->value, + build_directory)) + return false; + + ++iterator_; + + // The STABS documentation says that some compilers may emit + // additional N_SO entries with names immediately following the + // first, and that they should be ignored. However, the original + // Breakpad STABS reader doesn't ignore them, so we won't either. + + // Process the body of the compilation unit, up to the next N_SO. + while (!iterator_->at_end && iterator_->type != N_SO) { + if (iterator_->type == N_FUN) { + if (! ProcessFunction()) + return false; + } else if (iterator_->type == N_SLINE) { + // Mac OS X STABS place SLINE records before functions. + Line line; + // The value of an N_SLINE entry that appears outside a function is + // the absolute address of the line. + line.address = iterator_->value; + line.filename = current_source_file_; + // The n_desc of a N_SLINE entry is the line number. It's a + // signed 16-bit field; line numbers from 32768 to 65535 are + // stored as n-65536. + line.number = (uint16_t) iterator_->descriptor; + queued_lines_.push_back(line); + ++iterator_; + } else if (iterator_->type == N_SOL) { + current_source_file_ = SymbolString(); + ++iterator_; + } else { + // Ignore anything else. + ++iterator_; + } + } + + // An N_SO with an empty name indicates the end of the compilation + // unit. Default to zero. + uint64_t ending_address = 0; + if (!iterator_->at_end) { + assert(iterator_->type == N_SO); + const char *name = SymbolString(); + if (name[0] == '\0') { + ending_address = iterator_->value; + ++iterator_; + } + } + + if (! handler_->EndCompilationUnit(ending_address)) + return false; + + queued_lines_.clear(); + + return true; +} + +bool StabsReader::ProcessFunction() { + assert(!iterator_->at_end && iterator_->type == N_FUN); + + uint64_t function_address = iterator_->value; + // The STABS string for an N_FUN entry is the name of the function, + // followed by a colon, followed by type information for the + // function. We want to pass the name alone to StartFunction. + const char *stab_string = SymbolString(); + const char *name_end = strchr(stab_string, ':'); + if (! name_end) + name_end = stab_string + strlen(stab_string); + string name(stab_string, name_end - stab_string); + if (! handler_->StartFunction(name, function_address)) + return false; + ++iterator_; + + // If there were any SLINE records given before the function, report them now. + for (vector::const_iterator it = queued_lines_.begin(); + it != queued_lines_.end(); it++) { + if (!handler_->Line(it->address, it->filename, it->number)) + return false; + } + queued_lines_.clear(); + + while (!iterator_->at_end) { + if (iterator_->type == N_SO || iterator_->type == N_FUN) + break; + else if (iterator_->type == N_SLINE) { + // The value of an N_SLINE entry is the offset of the line from + // the function's start address. + uint64_t line_address = function_address + iterator_->value; + // The n_desc of a N_SLINE entry is the line number. It's a + // signed 16-bit field; line numbers from 32768 to 65535 are + // stored as n-65536. + uint16_t line_number = iterator_->descriptor; + if (! handler_->Line(line_address, current_source_file_, line_number)) + return false; + ++iterator_; + } else if (iterator_->type == N_SOL) { + current_source_file_ = SymbolString(); + ++iterator_; + } else + // Ignore anything else. + ++iterator_; + } + + // We've reached the end of the function. See if we can figure out its + // ending address. + uint64_t ending_address = 0; + if (!iterator_->at_end) { + assert(iterator_->type == N_SO || iterator_->type == N_FUN); + if (iterator_->type == N_FUN) { + const char *symbol_name = SymbolString(); + if (symbol_name[0] == '\0') { + // An N_FUN entry with no name is a terminator for this function; + // its value is the function's size. + ending_address = function_address + iterator_->value; + ++iterator_; + } else { + // An N_FUN entry with a name is the next function, and we can take + // its value as our ending address. Don't advance the iterator, as + // we'll use this symbol to start the next function as well. + ending_address = iterator_->value; + } + } else { + // An N_SO entry could be an end-of-compilation-unit marker, or the + // start of the next compilation unit, but in either case, its value + // is our ending address. We don't advance the iterator; + // ProcessCompilationUnit will decide what to do with this symbol. + ending_address = iterator_->value; + } + } + + if (! handler_->EndFunction(ending_address)) + return false; + + return true; +} + +bool StabsReader::ProcessExtern() { +#if defined(HAVE_MACH_O_NLIST_H) + assert(!iterator_->at_end && + (iterator_->type & N_STAB) == 0 && + (iterator_->type & N_TYPE) == N_SECT); +#endif + + // TODO(mark): only do symbols in the text section? + if (!handler_->Extern(SymbolString(), iterator_->value)) + return false; + + ++iterator_; + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h new file mode 100644 index 0000000000..98ee2dd53b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h @@ -0,0 +1,325 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// stabs_reader.h: Define StabsReader, a parser for STABS debugging +// information. A description of the STABS debugging format can be +// found at: +// +// http://sourceware.org/gdb/current/onlinedocs/stabs_toc.html +// +// The comments here assume you understand the format. +// +// This parser can handle big-endian and little-endian data, and the symbol +// values may be either 32 or 64 bits long. It handles both STABS in +// sections (as used on Linux) and STABS appearing directly in an +// a.out-like symbol table (as used in Darwin OS X Mach-O files). + +#ifndef COMMON_STABS_READER_H__ +#define COMMON_STABS_READER_H__ + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_MACH_O_NLIST_H +#include +#elif defined(HAVE_A_OUT_H) +#include +#endif + +#include +#include + +#include "common/byte_cursor.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +class StabsHandler; + +class StabsReader { + public: + // Create a reader for the STABS debug information whose .stab section is + // being traversed by ITERATOR, and whose .stabstr section is referred to + // by STRINGS. The reader will call the member functions of HANDLER to + // report the information it finds, when the reader's 'Process' member + // function is called. + // + // BIG_ENDIAN should be true if the entries in the .stab section are in + // big-endian form, or false if they are in little-endian form. + // + // VALUE_SIZE should be either 4 or 8, indicating the size of the 'value' + // field in each entry in bytes. + // + // UNITIZED should be true if the STABS data is stored in units with + // N_UNDF headers. This is usually the case for STABS stored in sections, + // like .stab/.stabstr, and usually not the case for STABS stored in the + // actual symbol table; UNITIZED should be true when parsing Linux stabs, + // false when parsing Mac OS X STABS. For details, see: + // http://sourceware.org/gdb/current/onlinedocs/stabs/Stab-Section-Basics.html + // + // Note that, in ELF, the .stabstr section should be found using the + // 'sh_link' field of the .stab section header, not by name. + StabsReader(const uint8_t *stab, size_t stab_size, + const uint8_t *stabstr, size_t stabstr_size, + bool big_endian, size_t value_size, bool unitized, + StabsHandler *handler); + + // Process the STABS data, calling the handler's member functions to + // report what we find. While the handler functions return true, + // continue to process until we reach the end of the section. If we + // processed the entire section and all handlers returned true, + // return true. If any handler returned false, return false. + // + // This is only meant to be called once per StabsReader instance; + // resuming a prior processing pass that stopped abruptly isn't supported. + bool Process(); + + private: + + // An class for walking arrays of STABS entries. This isolates the main + // STABS reader from the exact format (size; endianness) of the entries + // themselves. + class EntryIterator { + public: + // The contents of a STABS entry, adjusted for the host's endianness, + // word size, 'struct nlist' layout, and so on. + struct Entry { + // True if this iterator has reached the end of the entry array. When + // this is set, the other members of this structure are not valid. + bool at_end; + + // The number of this entry within the list. + size_t index; + + // The current entry's name offset. This is the offset within the + // current compilation unit's strings, as establish by the N_UNDF entries. + size_t name_offset; + + // The current entry's type, 'other' field, descriptor, and value. + unsigned char type; + unsigned char other; + short descriptor; + uint64_t value; + }; + + // Create a EntryIterator walking the entries in BUFFER. Treat the + // entries as big-endian if BIG_ENDIAN is true, as little-endian + // otherwise. Assume each entry has a 'value' field whose size is + // VALUE_SIZE. + // + // This would not be terribly clean to extend to other format variations, + // but it's enough to handle Linux and Mac, and we'd like STABS to die + // anyway. + // + // For the record: on Linux, STABS entry values are always 32 bits, + // regardless of the architecture address size (don't ask me why); on + // Mac, they are 32 or 64 bits long. Oddly, the section header's entry + // size for a Linux ELF .stab section varies according to the ELF class + // from 12 to 20 even as the actual entries remain unchanged. + EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size); + + // Move to the next entry. This function's behavior is undefined if + // at_end() is true when it is called. + EntryIterator &operator++() { Fetch(); entry_.index++; return *this; } + + // Dereferencing this iterator produces a reference to an Entry structure + // that holds the current entry's values. The entry is owned by this + // EntryIterator, and will be invalidated at the next call to operator++. + const Entry &operator*() const { return entry_; } + const Entry *operator->() const { return &entry_; } + + private: + // Read the STABS entry at cursor_, and set entry_ appropriately. + void Fetch(); + + // The size of entries' value field, in bytes. + size_t value_size_; + + // A byte cursor traversing buffer_. + ByteCursor cursor_; + + // Values for the entry this iterator refers to. + Entry entry_; + }; + + // A source line, saved to be reported later. + struct Line { + uint64_t address; + const char *filename; + int number; + }; + + // Return the name of the current symbol. + const char *SymbolString(); + + // Process a compilation unit starting at symbol_. Return true + // to continue processing, or false to abort. + bool ProcessCompilationUnit(); + + // Process a function in current_source_file_ starting at symbol_. + // Return true to continue processing, or false to abort. + bool ProcessFunction(); + + // Process an exported function symbol. + // Return true to continue processing, or false to abort. + bool ProcessExtern(); + + // The STABS entries being parsed. + ByteBuffer entries_; + + // The string section to which the entries refer. + ByteBuffer strings_; + + // The iterator walking the STABS entries. + EntryIterator iterator_; + + // True if the data is "unitized"; see the explanation in the comment for + // StabsReader::StabsReader. + bool unitized_; + + StabsHandler *handler_; + + // The offset of the current compilation unit's strings within stabstr_. + size_t string_offset_; + + // The value string_offset_ should have for the next compilation unit, + // as established by N_UNDF entries. + size_t next_cu_string_offset_; + + // The current source file name. + const char *current_source_file_; + + // Mac OS X STABS place SLINE records before functions; we accumulate a + // vector of these until we see the FUN record, and then report them + // after the StartFunction call. + std::vector queued_lines_; +}; + +// Consumer-provided callback structure for the STABS reader. Clients +// of the STABS reader provide an instance of this structure. The +// reader then invokes the member functions of that instance to report +// the information it finds. +// +// The default definitions of the member functions do nothing, and return +// true so processing will continue. +class StabsHandler { + public: + StabsHandler() { } + virtual ~StabsHandler() { } + + // Some general notes about the handler callback functions: + + // Processing proceeds until the end of the .stabs section, or until + // one of these functions returns false. + + // The addresses given are as reported in the STABS info, without + // regard for whether the module may be loaded at different + // addresses at different times (a shared library, say). When + // processing STABS from an ELF shared library, the addresses given + // all assume the library is loaded at its nominal load address. + // They are *not* offsets from the nominal load address. If you + // want offsets, you must subtract off the library's nominal load + // address. + + // The arguments to these functions named FILENAME are all + // references to strings stored in the .stabstr section. Because + // both the Linux and Solaris linkers factor out duplicate strings + // from the .stabstr section, the consumer can assume that if two + // FILENAME values are different addresses, they represent different + // file names. + // + // Thus, it's safe to use (say) std::map, which does + // string address comparisons, not string content comparisons. + // Since all the strings are in same array of characters --- the + // .stabstr section --- comparing their addresses produces + // predictable, if not lexicographically meaningful, results. + + // Begin processing a compilation unit whose main source file is + // named FILENAME, and whose base address is ADDRESS. If + // BUILD_DIRECTORY is non-NULL, it is the name of the build + // directory in which the compilation occurred. + virtual bool StartCompilationUnit(const char *filename, uint64_t address, + const char *build_directory) { + return true; + } + + // Finish processing the compilation unit. If ADDRESS is non-zero, + // it is the ending address of the compilation unit. If ADDRESS is + // zero, then the compilation unit's ending address is not + // available, and the consumer must infer it by other means. + virtual bool EndCompilationUnit(uint64_t address) { return true; } + + // Begin processing a function named NAME, whose starting address is + // ADDRESS. This function belongs to the compilation unit that was + // most recently started but not ended. + // + // Note that, unlike filenames, NAME is not a pointer into the + // .stabstr section; this is because the name as it appears in the + // STABS data is followed by type information. The value passed to + // StartFunction is the function name alone. + // + // In languages that use name mangling, like C++, NAME is mangled. + virtual bool StartFunction(const string &name, uint64_t address) { + return true; + } + + // Finish processing the function. If ADDRESS is non-zero, it is + // the ending address for the function. If ADDRESS is zero, then + // the function's ending address is not available, and the consumer + // must infer it by other means. + virtual bool EndFunction(uint64_t address) { return true; } + + // Report that the code at ADDRESS is attributable to line NUMBER of + // the source file named FILENAME. The caller must infer the ending + // address of the line. + virtual bool Line(uint64_t address, const char *filename, int number) { + return true; + } + + // Report that an exported function NAME is present at ADDRESS. + // The size of the function is unknown. + virtual bool Extern(const string &name, uint64_t address) { + return true; + } + + // Report a warning. FORMAT is a printf-like format string, + // specifying how to format the subsequent arguments. + virtual void Warning(const char *format, ...) = 0; +}; + +} // namespace google_breakpad + +#endif // COMMON_STABS_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc new file mode 100644 index 0000000000..a84da1c4ca --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc @@ -0,0 +1,611 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/stabs_reader.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" + +using ::testing::Eq; +using ::testing::InSequence; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::Test; +using ::testing::_; +using google_breakpad::StabsHandler; +using google_breakpad::StabsReader; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using std::map; + +namespace { + +// A StringAssembler is a class for generating .stabstr sections to present +// as input to the STABS parser. +class StringAssembler: public Section { + public: + StringAssembler() : in_cu_(false) { StartCU(); } + + // Add the string S to this StringAssembler, and return the string's + // offset within this compilation unit's strings. If S has been added + // already, this returns the offset of its first instance. + size_t Add(const string &s) { + map::iterator it = added_.find(s); + if (it != added_.end()) + return it->second; + size_t offset = Size() - cu_start_; + AppendCString(s); + added_[s] = offset; + return offset; + } + + // Start a fresh compilation unit string collection. + void StartCU() { + // Ignore duplicate calls to StartCU. Our test data don't always call + // StartCU at all, meaning that our constructor has to take care of it, + // meaning that tests that *do* call StartCU call it twice at the + // beginning. This is not worth smoothing out. + if (in_cu_) return; + + added_.clear(); + cu_start_ = Size(); + + // Each compilation unit's strings start with an empty string. + AppendCString(""); + added_[""] = 0; + + in_cu_ = true; + } + + // Finish off the current CU's strings. + size_t EndCU() { + assert(in_cu_); + in_cu_ = false; + return Size() - cu_start_; + } + + private: + // The offset of the start of this compilation unit's strings. + size_t cu_start_; + + // True if we're in a CU. + bool in_cu_; + + // A map from the strings that have been added to this section to + // their starting indices within their compilation unit. + map added_; +}; + +// A StabsAssembler is a class for generating .stab sections to present as +// test input for the STABS parser. +class StabsAssembler: public Section { + public: + // Create a StabsAssembler that uses StringAssembler for its strings. + StabsAssembler(StringAssembler *string_assembler) + : Section(string_assembler->endianness()), + string_assembler_(string_assembler), + value_size_(0), + entry_count_(0), + cu_header_(NULL) { } + ~StabsAssembler() { assert(!cu_header_); } + + // Accessor and setter for value_size_. + size_t value_size() const { return value_size_; } + StabsAssembler &set_value_size(size_t value_size) { + value_size_ = value_size; + return *this; + } + + // Append a STAB entry to the end of this section with the given + // characteristics. NAME is the offset of this entry's name string within + // its compilation unit's portion of the .stabstr section; this can be a + // value generated by a StringAssembler. Return a reference to this + // StabsAssembler. + StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, + Label value, Label name) { + D32(name); + D8(type); + D8(other); + D16(descriptor); + Append(endianness(), value_size_, value); + entry_count_++; + return *this; + } + + // As above, but automatically add NAME to our StringAssembler. + StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, + Label value, const string &name) { + return Stab(type, other, descriptor, value, string_assembler_->Add(name)); + } + + // Start a compilation unit named NAME, with an N_UNDF symbol to start + // it, and its own portion of the string section. Return a reference to + // this StabsAssembler. + StabsAssembler &StartCU(const string &name) { + assert(!cu_header_); + cu_header_ = new CUHeader; + string_assembler_->StartCU(); + entry_count_ = 0; + return Stab(N_UNDF, 0, + cu_header_->final_entry_count, + cu_header_->final_string_size, + string_assembler_->Add(name)); + } + + // Close off the current compilation unit. Return a reference to this + // StabsAssembler. + StabsAssembler &EndCU() { + assert(cu_header_); + cu_header_->final_entry_count = entry_count_; + cu_header_->final_string_size = string_assembler_->EndCU(); + delete cu_header_; + cu_header_ = NULL; + return *this; + } + + private: + // Data used in a compilation unit header STAB that we won't know until + // we've finished the compilation unit. + struct CUHeader { + // The final number of entries this compilation unit will hold. + Label final_entry_count; + + // The final size of this compilation unit's strings. + Label final_string_size; + }; + + // The strings for our STABS entries. + StringAssembler *string_assembler_; + + // The size of the 'value' field of stabs entries in this section. + size_t value_size_; + + // The number of entries in this compilation unit so far. + size_t entry_count_; + + // Header labels for this compilation unit, if we've started one but not + // finished it. + CUHeader *cu_header_; +}; + +class MockStabsReaderHandler: public StabsHandler { + public: + MOCK_METHOD3(StartCompilationUnit, + bool(const char *, uint64_t, const char *)); + MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); + MOCK_METHOD2(StartFunction, bool(const string &, uint64_t)); + MOCK_METHOD1(EndFunction, bool(uint64_t)); + MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); + MOCK_METHOD2(Extern, bool(const string &, uint64_t)); + void Warning(const char *format, ...) { MockWarning(format); } + MOCK_METHOD1(MockWarning, void(const char *)); +}; + +struct StabsFixture { + StabsFixture() : stabs(&strings), unitized(true) { } + + // Create a StabsReader to parse the mock stabs data in stabs and + // strings, and pass the parsed information to mock_handler. Use the + // endianness and value size of stabs to parse the data. If all goes + // well, return the result of calling the reader's Process member + // function. Otherwise, return false. + bool ApplyHandlerToMockStabsData() { + string stabs_contents, stabstr_contents; + if (!stabs.GetContents(&stabs_contents) || + !strings.GetContents(&stabstr_contents)) + return false; + + // Run the parser on the test input, passing whatever we find to HANDLER. + StabsReader reader( + reinterpret_cast(stabs_contents.data()), + stabs_contents.size(), + reinterpret_cast(stabstr_contents.data()), + stabstr_contents.size(), + stabs.endianness() == kBigEndian, stabs.value_size(), unitized, + &mock_handler); + return reader.Process(); + } + + StringAssembler strings; + StabsAssembler stabs; + bool unitized; + MockStabsReaderHandler mock_handler; +}; + +class Stabs: public StabsFixture, public Test { }; + +TEST_F(Stabs, MockStabsInput) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + stabs + .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/") + .Stab(N_FUN, 83, 50010, 0x91a5353fU, + "not the SO with source file name we expected ") + .Stab(N_SO, 165, 24791, 0xfe69d23cU, "") + .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/") + .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c") + .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for") + .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1") + .Stab(N_BINCL, 150, 15694, 0xef65c659U, + "something to ignore in a FUN body") + .Stab(N_SLINE, 147, 4967, 0xd904b3f, "") + .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h") + .Stab(N_SLINE, 130, 24610, 0x90f145b, "") + .Stab(N_FUN, 45, 32441, 0xbf27cf93U, + "fun2:some stabs type info here:to trim from the name") + .Stab(N_SLINE, 138, 39002, 0x8148b87, "") + .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c") + .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "") + .Stab(N_SO, 167, 4647, 0xd04b7448U, "") + .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "") + .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c") + .Stab(N_SO, 218, 12447, 0x11cfe4b5U, ""); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U, + StrEq("builddir1/"))) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), + 0x11759f10U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, AbruptCU) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, AbruptFunction) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c") + .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, NoCU) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(8); + stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/"); + + EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) + .Times(0); + EXPECT_CALL(mock_handler, StartFunction(_, _)) + .Times(0); + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, NoCUEnd) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c") + .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c"); + + { + InSequence s; + + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On systems that store STABS in sections, string offsets are relative to +// the beginning of that compilation unit's strings, marked with N_UNDF +// symbols; see the comments for StabsReader::StabsReader. +TEST_F(Stabs, Unitized) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs + .StartCU("antimony") + .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony") + .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic") + .Stab(N_SO, 124, 37175, 0x80b0014cU, "") + .EndCU() + .StartCU("aluminum") + .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum") + .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium") + .Stab(N_SO, 178, 56949, 0xbffff983U, "") + .EndCU(); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xbffff983U)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On systems that store STABS entries in the real symbol table, the N_UNDF +// entries have no special meaning, and shouldn't mess up the string +// indices. +TEST_F(Stabs, NonUnitized) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + unitized = false; + stabs + .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") + .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") + .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania") + .Stab(N_SO, 221, 41976, 0x21a97352, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("Tanzania"), + 0x11a97352, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, FunctionEnd) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(8); + stabs + .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit") + // This function is terminated by the start of the next function. + .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1") + // This function is terminated by an explicit end-of-function stab, + // whose value is a size in bytes. + .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2") + .Stab(N_FUN, 14, 36749, 0xc1ab, "") + // This function is terminated by the end of the compilation unit. + .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3") + .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("compilation unit"), + 0x52a830d644cd6942ULL, NULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +// On Mac OS X, SLINE records can appear before the FUN stab to which they +// belong, and their values are absolute addresses, not offsets. +TEST_F(Stabs, LeadingLine) { + stabs.set_endianness(kBigEndian); + stabs.set_value_size(4); + stabs + .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/") + .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit") + .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name") + .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "") + .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "") + .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga") + .Stab(N_FUN, 218, 16113, 0x5798, "") + .Stab(N_SO, 52, 53058, 0xd4af4415, ""); + + { + InSequence s; + EXPECT_CALL(mock_handler, + StartCompilationUnit(StrEq("compilation unit"), + 0x4c7e3bf4, StrEq("build directory/"))) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + StartFunction(Eq("rutabaga"), 0xce1b98fa)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0x4cb3d7e0, StrEq("source file name"), 20015)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Line(0x4cba8b88, StrEq("source file name"), 43802)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415)) + .WillOnce(Return(true)); + } + + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + + +#if defined(HAVE_MACH_O_NLIST_H) +// These tests have no meaning on non-Mach-O-based systems, as +// only Mach-O uses N_SECT to represent public symbols. +TEST_F(Stabs, OnePublicSymbol) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + + const uint32_t kExpectedAddress = 0x9000; + const string kExpectedFunctionName("public_function"); + stabs + .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName); + + { + InSequence s; + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName), + kExpectedAddress)) + .WillOnce(Return(true)); + } + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +TEST_F(Stabs, TwoPublicSymbols) { + stabs.set_endianness(kLittleEndian); + stabs.set_value_size(4); + + const uint32_t kExpectedAddress1 = 0xB0B0B0B0; + const string kExpectedFunctionName1("public_function"); + const uint32_t kExpectedAddress2 = 0xF0F0F0F0; + const string kExpectedFunctionName2("something else"); + stabs + .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1) + .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2); + + { + InSequence s; + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName1), + kExpectedAddress1)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_handler, + Extern(StrEq(kExpectedFunctionName2), + kExpectedAddress2)) + .WillOnce(Return(true)); + } + ASSERT_TRUE(ApplyHandlerToMockStabsData()); +} + +#endif + +} // anonymous namespace diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc new file mode 100644 index 0000000000..049a6cc63e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dump_stabs.cc --- implement the StabsToModule class. + +#include +#include +#include +#include + +#include + +#include "common/stabs_to_module.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +// Demangle using abi call. +// Older GCC may not support it. +static string Demangle(const string &mangled) { + int status = 0; + char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); + if (status == 0 && demangled != NULL) { + string str(demangled); + free(demangled); + return str; + } + return string(mangled); +} + +StabsToModule::~StabsToModule() { + // Free any functions we've accumulated but not added to the module. + for (vector::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); func_it++) + delete *func_it; + // Free any function that we're currently within. + delete current_function_; +} + +bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, + const char *build_directory) { + assert(!in_compilation_unit_); + in_compilation_unit_ = true; + current_source_file_name_ = name; + current_source_file_ = module_->FindFile(name); + comp_unit_base_address_ = address; + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::EndCompilationUnit(uint64_t address) { + assert(in_compilation_unit_); + in_compilation_unit_ = false; + comp_unit_base_address_ = 0; + current_source_file_ = NULL; + current_source_file_name_ = NULL; + if (address) + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::StartFunction(const string &name, + uint64_t address) { + assert(!current_function_); + Module::Function *f = new Module::Function(Demangle(name), address); + Module::Range r(address, 0); // We compute this in StabsToModule::Finalize(). + f->ranges.push_back(r); + f->parameter_size = 0; // We don't provide this information. + current_function_ = f; + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::EndFunction(uint64_t address) { + assert(current_function_); + // Functions in this compilation unit should have address bigger + // than the compilation unit's starting address. There may be a lot + // of duplicated entries for functions in the STABS data. We will + // count on the Module to remove the duplicates. + if (current_function_->address >= comp_unit_base_address_) + functions_.push_back(current_function_); + else + delete current_function_; + current_function_ = NULL; + if (address) + boundaries_.push_back(static_cast(address)); + return true; +} + +bool StabsToModule::Line(uint64_t address, const char *name, int number) { + assert(current_function_); + assert(current_source_file_); + if (name != current_source_file_name_) { + current_source_file_ = module_->FindFile(name); + current_source_file_name_ = name; + } + Module::Line line; + line.address = address; + line.size = 0; // We compute this in StabsToModule::Finalize(). + line.file = current_source_file_; + line.number = number; + current_function_->lines.push_back(line); + return true; +} + +bool StabsToModule::Extern(const string &name, uint64_t address) { + Module::Extern *ext = new Module::Extern(address); + // Older libstdc++ demangle implementations can crash on unexpected + // input, so be careful about what gets passed in. + if (name.compare(0, 3, "__Z") == 0) { + ext->name = Demangle(name.substr(1)); + } else if (name[0] == '_') { + ext->name = name.substr(1); + } else { + ext->name = name; + } + module_->AddExtern(ext); + return true; +} + +void StabsToModule::Warning(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + +void StabsToModule::Finalize() { + // Sort our boundary list, so we can search it quickly. + sort(boundaries_.begin(), boundaries_.end()); + // Sort all functions by address, just for neatness. + sort(functions_.begin(), functions_.end(), + Module::Function::CompareByAddress); + + for (vector::const_iterator func_it = functions_.begin(); + func_it != functions_.end(); + func_it++) { + Module::Function *f = *func_it; + // Compute the function f's size. + vector::const_iterator boundary + = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); + if (boundary != boundaries_.end()) + f->ranges[0].size = *boundary - f->address; + else + // If this is the last function in the module, and the STABS + // reader was unable to give us its ending address, then assign + // it a bogus, very large value. This will happen at most once + // per module: since we've added all functions' addresses to the + // boundary table, only one can be the last. + f->ranges[0].size = kFallbackSize; + + // Compute sizes for each of the function f's lines --- if it has any. + if (!f->lines.empty()) { + stable_sort(f->lines.begin(), f->lines.end(), + Module::Line::CompareByAddress); + vector::iterator last_line = f->lines.end() - 1; + for (vector::iterator line_it = f->lines.begin(); + line_it != last_line; line_it++) + line_it[0].size = line_it[1].address - line_it[0].address; + // Compute the size of the last line from f's end address. + last_line->size = + (f->ranges[0].address + f->ranges[0].size) - last_line->address; + } + } + // Now that everything has a size, add our functions to the module, and + // dispose of our private list. + module_->AddFunctions(functions_.begin(), functions_.end()); + functions_.clear(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h new file mode 100644 index 0000000000..5e04fa7927 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h @@ -0,0 +1,143 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dump_stabs.h: Define the StabsToModule class, which receives +// STABS debugging information from a parser and adds it to a Breakpad +// symbol file. + +#ifndef BREAKPAD_COMMON_STABS_TO_MODULE_H_ +#define BREAKPAD_COMMON_STABS_TO_MODULE_H_ + +#include + +#include +#include + +#include "common/module.h" +#include "common/stabs_reader.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::vector; + +// A StabsToModule is a handler that receives parsed STABS debugging +// information from a StabsReader, and uses that to populate +// a Module. (All classes are in the google_breakpad namespace.) A +// Module represents the contents of a Breakpad symbol file, and knows +// how to write itself out as such. A StabsToModule thus acts as +// the bridge between STABS and Breakpad data. +// When processing Darwin Mach-O files, this also receives public linker +// symbols, like those found in system libraries. +class StabsToModule: public google_breakpad::StabsHandler { + public: + // Receive parsed debugging information from a StabsReader, and + // store it all in MODULE. + StabsToModule(Module *module) : + module_(module), + in_compilation_unit_(false), + comp_unit_base_address_(0), + current_function_(NULL), + current_source_file_(NULL), + current_source_file_name_(NULL) { } + ~StabsToModule(); + + // The standard StabsHandler virtual member functions. + bool StartCompilationUnit(const char *name, uint64_t address, + const char *build_directory); + bool EndCompilationUnit(uint64_t address); + bool StartFunction(const string &name, uint64_t address); + bool EndFunction(uint64_t address); + bool Line(uint64_t address, const char *name, int number); + bool Extern(const string &name, uint64_t address); + void Warning(const char *format, ...); + + // Do any final processing necessary to make module_ contain all the + // data provided by the STABS reader. + // + // Because STABS does not provide reliable size information for + // functions and lines, we need to make a pass over the data after + // processing all the STABS to compute those sizes. We take care of + // that here. + void Finalize(); + + private: + + // An arbitrary, but very large, size to use for functions whose + // size we can't compute properly. + static const uint64_t kFallbackSize = 0x10000000; + + // The module we're contributing debugging info to. + Module *module_; + + // The functions we've generated so far. We don't add these to + // module_ as we parse them. Instead, we wait until we've computed + // their ending address, and their lines' ending addresses. + // + // We could just stick them in module_ from the outset, but if + // module_ already contains data gathered from other debugging + // formats, that would complicate the size computation. + vector functions_; + + // Boundary addresses. STABS doesn't necessarily supply sizes for + // functions and lines, so we need to compute them ourselves by + // finding the next object. + vector boundaries_; + + // True if we are currently within a compilation unit: we have gotten a + // StartCompilationUnit call, but no matching EndCompilationUnit call + // yet. We use this for sanity checks. + bool in_compilation_unit_; + + // The base address of the current compilation unit. We use this to + // recognize functions we should omit from the symbol file. (If you + // know the details of why we omit these, please patch this + // comment.) + Module::Address comp_unit_base_address_; + + // The function we're currently contributing lines to. + Module::Function *current_function_; + + // The last Module::File we got a line number in. + Module::File *current_source_file_; + + // The pointer in the .stabstr section of the name that + // current_source_file_ is built from. This allows us to quickly + // recognize when the current line is in the same file as the + // previous one (which it usually is). + const char *current_source_file_name_; +}; + +} // namespace google_breakpad + +#endif // BREAKPAD_COMMON_STABS_TO_MODULE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc new file mode 100644 index 0000000000..aae0047667 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2010 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. + +// Original author: Jim Blandy + +// dump_stabs_unittest.cc: Unit tests for StabsToModule. + +#include + +#include "breakpad_googletest_includes.h" +#include "common/stabs_to_module.h" + +using google_breakpad::Module; +using google_breakpad::StabsToModule; +using std::vector; + +TEST(StabsToModule, SimpleCU) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a simple compilation unit that defines a function with + // one line. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0x9f4d1271e50db93bLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0xfde4abbed390c394LL)); + EXPECT_TRUE(h.Line(0xfde4abbed390c394LL, "source-file-name", 174823314)); + EXPECT_TRUE(h.EndFunction(0xfde4abbed390c3a4LL)); + EXPECT_TRUE(h.EndCompilationUnit(0xfee4abbed390c3a4LL)); + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("source-file-name"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ((size_t) 1, functions.size()); + Module::Function *function = functions[0]; + EXPECT_STREQ("function", function->name.c_str()); + EXPECT_EQ(0xfde4abbed390c394LL, function->address); + EXPECT_EQ(0x10U, function->ranges[0].size); + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ((size_t) 1, function->lines.size()); + Module::Line *line = &function->lines[0]; + EXPECT_EQ(0xfde4abbed390c394LL, line->address); + EXPECT_EQ(0x10U, line->size); // derived from EndFunction + EXPECT_TRUE(line->file == file); + EXPECT_EQ(174823314, line->number); +} + +#ifdef __GNUC__ +// Function name mangling can vary by compiler, so only run mangled-name +// tests on GCC for simplicity's sake. +TEST(StabsToModule, Externs) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a few Extern symbols. + EXPECT_TRUE(h.Extern("_foo", 0xffff)); + EXPECT_TRUE(h.Extern("__Z21dyldGlobalLockAcquirev", 0xaaaa)); + EXPECT_TRUE(h.Extern("_MorphTableGetNextMorphChain", 0x1111)); + h.Finalize(); + + // Now check to see what has been added to the Module. + vector externs; + m.GetExterns(&externs, externs.end()); + ASSERT_EQ((size_t) 3, externs.size()); + Module::Extern *extern1 = externs[0]; + EXPECT_STREQ("MorphTableGetNextMorphChain", extern1->name.c_str()); + EXPECT_EQ((Module::Address)0x1111, extern1->address); + Module::Extern *extern2 = externs[1]; + EXPECT_STREQ("dyldGlobalLockAcquire()", extern2->name.c_str()); + EXPECT_EQ((Module::Address)0xaaaa, extern2->address); + Module::Extern *extern3 = externs[2]; + EXPECT_STREQ("foo", extern3->name.c_str()); + EXPECT_EQ((Module::Address)0xffff, extern3->address); +} +#endif // __GNUC__ + +TEST(StabsToModule, DuplicateFunctionNames) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Compilation unit with one function, mangled name. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda36ecf7f46cLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("funcfoo", + 0xf2cfda36ecf7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.StartFunction("funcfoo", + 0xf2cfda36ecf7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); + + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("compilation-unit"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ(1U, functions.size()); + + Module::Function *function = functions[0]; + EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address); + EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ(0U, function->lines.size()); +} + +TEST(InferSizes, LineSize) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Feed in a simple compilation unit that defines a function with + // one line. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xb4513962eff94e92LL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0xb4513962eff94e92LL)); + EXPECT_TRUE(h.Line(0xb4513962eff94e92LL, "source-file-name-1", 77396614)); + EXPECT_TRUE(h.Line(0xb4513963eff94e92LL, "source-file-name-2", 87660088)); + EXPECT_TRUE(h.EndFunction(0)); // unknown function end address + EXPECT_TRUE(h.EndCompilationUnit(0)); // unknown CU end address + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit-2", 0xb4523963eff94e92LL, + "build-directory-2")); // next boundary + EXPECT_TRUE(h.EndCompilationUnit(0)); + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file1 = m.FindExistingFile("source-file-name-1"); + ASSERT_TRUE(file1 != NULL); + Module::File *file2 = m.FindExistingFile("source-file-name-2"); + ASSERT_TRUE(file2 != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ((size_t) 1, functions.size()); + + Module::Function *function = functions[0]; + EXPECT_STREQ("function", function->name.c_str()); + EXPECT_EQ(0xb4513962eff94e92LL, function->address); + EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ((size_t) 2, function->lines.size()); + + Module::Line *line1 = &function->lines[0]; + EXPECT_EQ(0xb4513962eff94e92LL, line1->address); + EXPECT_EQ(0x100000000ULL, line1->size); // derived from EndFunction + EXPECT_TRUE(line1->file == file1); + EXPECT_EQ(77396614, line1->number); + + Module::Line *line2 = &function->lines[1]; + EXPECT_EQ(0xb4513963eff94e92LL, line2->address); + EXPECT_EQ(0x1000000000000ULL, line2->size); // derived from EndFunction + EXPECT_TRUE(line2->file == file2); + EXPECT_EQ(87660088, line2->number); +} + +#ifdef __GNUC__ +// Function name mangling can vary by compiler, so only run mangled-name +// tests on GCC for simplicity's sake. +TEST(FunctionNames, Mangled) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // Compilation unit with one function, mangled name. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda63cef7f46cLL, + "build-directory")); + EXPECT_TRUE(h.StartFunction("_ZNSt6vectorIySaIyEE9push_backERKy", + 0xf2cfda63cef7f46dLL)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); + + h.Finalize(); + + // Now check to see what has been added to the Module. + Module::File *file = m.FindExistingFile("compilation-unit"); + ASSERT_TRUE(file != NULL); + + vector functions; + m.GetFunctions(&functions, functions.end()); + ASSERT_EQ(1U, functions.size()); + + Module::Function *function = functions[0]; + // This is GCC-specific, but we shouldn't be seeing STABS data anywhere + // but Linux. + EXPECT_STREQ("std::vector >::" + "push_back(unsigned long long const&)", + function->name.c_str()); + EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); + EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size + EXPECT_EQ(0U, function->parameter_size); + ASSERT_EQ(0U, function->lines.size()); +} +#endif // __GNUC__ + +// The GNU toolchain can omit functions that are not used; however, +// when it does so, it doesn't clean up the debugging information that +// refers to them. In STABS, this results in compilation units whose +// SO addresses are zero. +TEST(Omitted, Function) { + Module m("name", "os", "arch", "id"); + StabsToModule h(&m); + + // The StartCompilationUnit and EndCompilationUnit calls may both have an + // address of zero if the compilation unit has had sections removed. + EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0, "build-directory")); + EXPECT_TRUE(h.StartFunction("function", 0x2a133596)); + EXPECT_TRUE(h.EndFunction(0)); + EXPECT_TRUE(h.EndCompilationUnit(0)); +} + +// TODO --- if we actually cared about STABS. Even without these we've +// got full coverage of non-failure source lines in dump_stabs.cc. + +// Line size from next line +// Line size from function end +// Line size from next function start +// line size from cu end +// line size from next cu start +// fallback size is something plausible + +// function size from function end +// function size from next function start +// function size from cu end +// function size from next cu start +// fallback size is something plausible + +// omitting functions outside the compilation unit's address range +// zero-line, one-line, many-line functions diff --git a/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h new file mode 100644 index 0000000000..a3dd50aab6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h @@ -0,0 +1,43 @@ +// Copyright (c) 2016, 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_COMMON_STDIO_WRAPPER_H +#define GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H + +#include + +#if defined(_MSC_VER) && MSC_VER < 1900 +#include + +#define snprintf _snprintf +typedef SSIZE_T ssize_t; +#endif + + +#endif // GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc new file mode 100644 index 0000000000..11d60a3664 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc @@ -0,0 +1,155 @@ +// 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 + +#include "common/convert_UTF.h" +#include "common/scoped_ptr.h" +#include "common/string_conversion.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::vector; + +void UTF8ToUTF16(const char *in, vector *out) { + size_t source_length = strlen(in); + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity(); + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + 1; + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2; + out[0] = out[1] = 0; + + // Process one character at a time + while (1) { + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) + return static_cast(source_ptr - reinterpret_cast(in)); + + // Add another character to the input stream and try again + source_ptr = reinterpret_cast(in); + ++source_end_ptr; + + if (source_end_ptr > reinterpret_cast(in) + in_length) + break; + } + + return 0; +} + +void UTF32ToUTF16(const wchar_t *in, vector *out) { + size_t source_length = wcslen(in); + const UTF32 *source_ptr = reinterpret_cast(in); + const UTF32 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity(); + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) { + const UTF32 *source_ptr = reinterpret_cast(&in); + const UTF32 *source_end_ptr = source_ptr + 1; + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2; + out[0] = out[1] = 0; + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result != conversionOK) { + out[0] = out[1] = 0; + } +} + +static inline uint16_t Swap(uint16_t value) { + return (value >> 8) | static_cast(value << 8); +} + +string UTF16ToUTF8(const vector &in, bool swap) { + const UTF16 *source_ptr = &in[0]; + scoped_array source_buffer; + + // If we're to swap, we need to make a local copy and swap each byte pair + if (swap) { + int idx = 0; + source_buffer.reset(new uint16_t[in.size()]); + UTF16 *source_buffer_ptr = source_buffer.get(); + for (vector::const_iterator it = in.begin(); + it != in.end(); ++it, ++idx) + source_buffer_ptr[idx] = Swap(*it); + + source_ptr = source_buffer.get(); + } + + // The maximum expansion would be 4x the size of the input string. + const UTF16 *source_end_ptr = source_ptr + in.size(); + size_t target_capacity = in.size() * 4; + scoped_array target_buffer(new UTF8[target_capacity]); + UTF8 *target_ptr = target_buffer.get(); + UTF8 *target_end_ptr = target_ptr + target_capacity; + ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) { + const char *targetPtr = reinterpret_cast(target_buffer.get()); + return targetPtr; + } + + return ""; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h new file mode 100644 index 0000000000..b9ba96a2e1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h @@ -0,0 +1,68 @@ +// 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 +#include + +#include "common/using_std_string.h" +#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 *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, uint16_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 *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, uint16_t out[2]); + +// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting. +string UTF16ToUTF8(const vector &in, bool swap); + +} // namespace google_breakpad + +#endif // COMMON_STRING_CONVERSION_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/string_conversion_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/string_conversion_unittest.cc new file mode 100644 index 0000000000..e9f9b55d95 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/string_conversion_unittest.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2019, 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_unittest.cc: Unit tests for google_breakpad::UTF* helpers. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/string_conversion.h" + +using google_breakpad::UTF8ToUTF16; +using google_breakpad::UTF8ToUTF16Char; +using google_breakpad::UTF16ToUTF8; +using std::vector; + +TEST(StringConversionTest, UTF8ToUTF16) { + const char in[] = "aßc"; + vector out; + vector exp{'a', 0xdf, 'c', 0}; + UTF8ToUTF16(in, &out); + EXPECT_EQ(4u, out.size()); + EXPECT_EQ(exp, out); +} + +TEST(StringConversionTest, UTF8ToUTF16Char) { + const char in[] = "a"; + uint16_t out[3] = {0xff, 0xff, 0xff}; + EXPECT_EQ(1, UTF8ToUTF16Char(in, 1, out)); + EXPECT_EQ('a', out[0]); + EXPECT_EQ(0, out[1]); + EXPECT_EQ(0xff, out[2]); +} + +TEST(StringConversionTest, UTF16ToUTF8) { + vector in{'a', 0xdf, 'c', 0}; + EXPECT_EQ("aßc", UTF16ToUTF8(in, false)); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h b/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h new file mode 100644 index 0000000000..2cf15a855d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h @@ -0,0 +1,42 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2013 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 COMMON_SYMBOL_DATA_H_ +#define COMMON_SYMBOL_DATA_H_ + +// Control what data is used from the symbol file. +enum SymbolData { + ALL_SYMBOL_DATA, + NO_CFI, + ONLY_CFI +}; + +#endif // COMMON_SYMBOL_DATA_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc new file mode 100644 index 0000000000..1e783b45c5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc @@ -0,0 +1,359 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// test_assembler.cc: Implementation of google_breakpad::TestAssembler. +// See test_assembler.h for details. + +#include "common/test_assembler.h" + +#include +#include + +#include + +namespace google_breakpad { +namespace test_assembler { + +using std::back_insert_iterator; + +Label::Label() : value_(new Binding()) { } +Label::Label(uint64_t value) : value_(new Binding(value)) { } +Label::Label(const Label &label) { + value_ = label.value_; + value_->Acquire(); +} +Label::~Label() { + if (value_->Release()) delete value_; +} + +Label &Label::operator=(uint64_t value) { + value_->Set(NULL, value); + return *this; +} + +Label &Label::operator=(const Label &label) { + value_->Set(label.value_, 0); + return *this; +} + +Label Label::operator+(uint64_t addend) const { + Label l; + l.value_->Set(this->value_, addend); + return l; +} + +Label Label::operator-(uint64_t subtrahend) const { + Label l; + l.value_->Set(this->value_, -subtrahend); + return l; +} + +// When NDEBUG is #defined, assert doesn't evaluate its argument. This +// means you can't simply use assert to check the return value of a +// function with necessary side effects. +// +// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether +// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts +// that x is true. +#ifdef NDEBUG +#define ALWAYS_EVALUATE_AND_ASSERT(x) x +#else +#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) +#endif + +uint64_t Label::operator-(const Label &label) const { + uint64_t offset; + ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); + return offset; +} + +uint64_t Label::Value() const { + uint64_t v = 0; + ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v)); + return v; +}; + +bool Label::IsKnownConstant(uint64_t *value_p) const { + Binding *base; + uint64_t addend; + value_->Get(&base, &addend); + if (base != NULL) return false; + if (value_p) *value_p = addend; + return true; +} + +bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const +{ + Binding *label_base, *this_base; + uint64_t label_addend, this_addend; + label.value_->Get(&label_base, &label_addend); + value_->Get(&this_base, &this_addend); + // If this and label are related, Get will find their final + // common ancestor, regardless of how indirect the relation is. This + // comparison also handles the constant vs. constant case. + if (this_base != label_base) return false; + if (offset_p) *offset_p = this_addend - label_addend; + return true; +} + +Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } + +Label::Binding::Binding(uint64_t addend) + : base_(NULL), addend_(addend), reference_count_(1) { } + +Label::Binding::~Binding() { + assert(reference_count_ == 0); + if (base_ && base_ != this && base_->Release()) + delete base_; +} + +void Label::Binding::Set(Binding *binding, uint64_t addend) { + if (!base_ && !binding) { + // We're equating two constants. This could be okay. + assert(addend_ == addend); + } else if (!base_) { + // We are a known constant, but BINDING may not be, so turn the + // tables and try to set BINDING's value instead. + binding->Set(NULL, addend_ - addend); + } else { + if (binding) { + // Find binding's final value. Since the final value is always either + // completely unconstrained or a constant, never a reference to + // another variable (otherwise, it wouldn't be final), this + // guarantees we won't create cycles here, even for code like this: + // l = m, m = n, n = l; + uint64_t binding_addend; + binding->Get(&binding, &binding_addend); + addend += binding_addend; + } + + // It seems likely that setting a binding to itself is a bug + // (although I can imagine this might turn out to be helpful to + // permit). + assert(binding != this); + + if (base_ != this) { + // Set the other bindings on our chain as well. Note that this + // is sufficient even though binding relationships form trees: + // All binding operations traverse their chains to the end, and + // all bindings related to us share some tail of our chain, so + // they will see the changes we make here. + base_->Set(binding, addend - addend_); + // We're not going to use base_ any more. + if (base_->Release()) delete base_; + } + + // Adopt BINDING as our base. Note that it should be correct to + // acquire here, after the release above, even though the usual + // reference-counting rules call for acquiring first, and then + // releasing: the self-reference assertion above should have + // complained if BINDING were 'this' or anywhere along our chain, + // so we didn't release BINDING. + if (binding) binding->Acquire(); + base_ = binding; + addend_ = addend; + } +} + +void Label::Binding::Get(Binding **base, uint64_t *addend) { + if (base_ && base_ != this) { + // Recurse to find the end of our reference chain (the root of our + // tree), and then rewrite every binding along the chain to refer + // to it directly, adjusting addends appropriately. (This is why + // this member function isn't this-const.) + Binding *final_base; + uint64_t final_addend; + base_->Get(&final_base, &final_addend); + if (final_base) final_base->Acquire(); + if (base_->Release()) delete base_; + base_ = final_base; + addend_ += final_addend; + } + *base = base_; + *addend = addend_; +} + +template +static inline void InsertEndian(test_assembler::Endianness endianness, + size_t size, uint64_t number, Inserter dest) { + assert(size > 0); + if (endianness == kLittleEndian) { + for (size_t i = 0; i < size; i++) { + *dest++ = (char) (number & 0xff); + number >>= 8; + } + } else { + assert(endianness == kBigEndian); + // The loop condition is odd, but it's correct for size_t. + for (size_t i = size - 1; i < size; i--) + *dest++ = (char) ((number >> (i * 8)) & 0xff); + } +} + +Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { + InsertEndian(endianness, size, number, + back_insert_iterator(contents_)); + return *this; +} + +Section &Section::Append(Endianness endianness, size_t size, + const Label &label) { + // If this label's value is known, there's no reason to waste an + // entry in references_ on it. + uint64_t value; + if (label.IsKnownConstant(&value)) + return Append(endianness, size, value); + + // This will get caught when the references are resolved, but it's + // nicer to find out earlier. + assert(endianness != kUnsetEndian); + + references_.push_back(Reference(contents_.size(), endianness, size, label)); + contents_.append(size, 0); + return *this; +} + +#define ENDIANNESS_L kLittleEndian +#define ENDIANNESS_B kBigEndian +#define ENDIANNESS(e) ENDIANNESS_ ## e + +#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + Section &Section::e ## bits(uint ## bits ## _t v) { \ + InsertEndian(ENDIANNESS(e), bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } + +#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ + Section &Section::e ## bits(const Label &v) { \ + return Append(ENDIANNESS(e), bits / 8, v); \ + } + +// Define L16, B32, and friends. +#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) + +DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); +DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); +DEFINE_SHORT_APPEND_ENDIAN(L, 16); +DEFINE_SHORT_APPEND_ENDIAN(L, 32); +DEFINE_SHORT_APPEND_ENDIAN(L, 64); +DEFINE_SHORT_APPEND_ENDIAN(B, 16); +DEFINE_SHORT_APPEND_ENDIAN(B, 32); +DEFINE_SHORT_APPEND_ENDIAN(B, 64); + +#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + Section &Section::D ## bits(uint ## bits ## _t v) { \ + InsertEndian(endianness_, bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } +#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ + Section &Section::D ## bits(const Label &v) { \ + return Append(endianness_, bits / 8, v); \ + } +#define DEFINE_SHORT_APPEND_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) + +DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) +DEFINE_SHORT_APPEND_DEFAULT(16); +DEFINE_SHORT_APPEND_DEFAULT(32); +DEFINE_SHORT_APPEND_DEFAULT(64); + +Section &Section::Append(const Section §ion) { + size_t base = contents_.size(); + contents_.append(section.contents_); + for (vector::const_iterator it = section.references_.begin(); + it != section.references_.end(); it++) + references_.push_back(Reference(base + it->offset, it->endianness, + it->size, it->label)); + return *this; +} + +Section &Section::LEB128(long long value) { + while (value < -0x40 || 0x3f < value) { + contents_ += (value & 0x7f) | 0x80; + if (value < 0) + value = (value >> 7) | ~(((unsigned long long) -1) >> 7); + else + value = (value >> 7); + } + contents_ += value & 0x7f; + return *this; +} + +Section &Section::ULEB128(uint64_t value) { + while (value > 0x7f) { + contents_ += (value & 0x7f) | 0x80; + value = (value >> 7); + } + contents_ += value; + return *this; +} + +Section &Section::Align(size_t alignment, uint8_t pad_byte) { + // ALIGNMENT must be a power of two. + assert(((alignment - 1) & alignment) == 0); + size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); + contents_.append(new_size - contents_.size(), pad_byte); + assert((contents_.size() & (alignment - 1)) == 0); + return *this; +} + +void Section::Clear() { + contents_.clear(); + references_.clear(); +} + +bool Section::GetContents(string *contents) { + // For each label reference, find the label's value, and patch it into + // the section's contents. + for (size_t i = 0; i < references_.size(); i++) { + Reference &r = references_[i]; + uint64_t value; + if (!r.label.IsKnownConstant(&value)) { + fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); + return false; + } + assert(r.offset < contents_.size()); + assert(contents_.size() - r.offset >= r.size); + InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); + } + contents->clear(); + std::swap(contents_, *contents); + references_.clear(); + return true; +} + +} // namespace test_assembler +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h new file mode 100644 index 0000000000..373dbebacd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h @@ -0,0 +1,484 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// test-assembler.h: interface to class for building complex binary streams. + +// To test the Breakpad symbol dumper and processor thoroughly, for +// all combinations of host system and minidump processor +// architecture, we need to be able to easily generate complex test +// data like debugging information and minidump files. +// +// For example, if we want our unit tests to provide full code +// coverage for stack walking, it may be difficult to persuade the +// compiler to generate every possible sort of stack walking +// information that we want to support; there are probably DWARF CFI +// opcodes that GCC never emits. Similarly, if we want to test our +// error handling, we will need to generate damaged minidumps or +// debugging information that (we hope) the client or compiler will +// never produce on its own. +// +// google_breakpad::TestAssembler provides a predictable and +// (relatively) simple way to generate complex formatted data streams +// like minidumps and CFI. Furthermore, because TestAssembler is +// portable, developers without access to (say) Visual Studio or a +// SPARC assembler can still work on test data for those targets. + +#ifndef PROCESSOR_TEST_ASSEMBLER_H_ +#define PROCESSOR_TEST_ASSEMBLER_H_ + +#include +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::list; +using std::vector; + +namespace test_assembler { + +// A Label represents a value not yet known that we need to store in a +// section. As long as all the labels a section refers to are defined +// by the time we retrieve its contents as bytes, we can use undefined +// labels freely in that section's construction. +// +// A label can be in one of three states: +// - undefined, +// - defined as the sum of some other label and a constant, or +// - a constant. +// +// A label's value never changes, but it can accumulate constraints. +// Adding labels and integers is permitted, and yields a label. +// Subtracting a constant from a label is permitted, and also yields a +// label. Subtracting two labels that have some relationship to each +// other is permitted, and yields a constant. +// +// For example: +// +// Label a; // a's value is undefined +// Label b; // b's value is undefined +// { +// Label c = a + 4; // okay, even though a's value is unknown +// b = c + 4; // also okay; b is now a+8 +// } +// Label d = b - 2; // okay; d == a+6, even though c is gone +// d.Value(); // error: d's value is not yet known +// d - a; // is 6, even though their values are not known +// a = 12; // now b == 20, and d == 18 +// d.Value(); // 18: no longer an error +// b.Value(); // 20 +// d = 10; // error: d is already defined. +// +// Label objects' lifetimes are unconstrained: notice that, in the +// above example, even though a and b are only related through c, and +// c goes out of scope, the assignment to a sets b's value as well. In +// particular, it's not necessary to ensure that a Label lives beyond +// Sections that refer to it. +class Label { + public: + Label(); // An undefined label. + Label(uint64_t value); // A label with a fixed value + Label(const Label &value); // A label equal to another. + ~Label(); + + // Return this label's value; it must be known. + // + // Providing this as a cast operator is nifty, but the conversions + // happen in unexpected places. In particular, ISO C++ says that + // Label + size_t becomes ambigious, because it can't decide whether + // to convert the Label to a uint64_t and then to a size_t, or use + // the overloaded operator that returns a new label, even though the + // former could fail if the label is not yet defined and the latter won't. + uint64_t Value() const; + + Label &operator=(uint64_t value); + Label &operator=(const Label &value); + Label operator+(uint64_t addend) const; + Label operator-(uint64_t subtrahend) const; + uint64_t operator-(const Label &subtrahend) const; + + // We could also provide == and != that work on undefined, but + // related, labels. + + // Return true if this label's value is known. If VALUE_P is given, + // set *VALUE_P to the known value if returning true. + bool IsKnownConstant(uint64_t *value_p = NULL) const; + + // Return true if the offset from LABEL to this label is known. If + // OFFSET_P is given, set *OFFSET_P to the offset when returning true. + // + // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m', + // except that it also returns a value indicating whether the + // subtraction is possible given what we currently know of l and m. + // It can be possible even if we don't know l and m's values. For + // example: + // + // Label l, m; + // m = l + 10; + // l.IsKnownConstant(); // false + // m.IsKnownConstant(); // false + // uint64_t d; + // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10. + // l-m // -10 + // m-l // 10 + // m.Value() // error: m's value is not known + bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; + + private: + // A label's value, or if that is not yet known, how the value is + // related to other labels' values. A binding may be: + // - a known constant, + // - constrained to be equal to some other binding plus a constant, or + // - unconstrained, and free to take on any value. + // + // Many labels may point to a single binding, and each binding may + // refer to another, so bindings and labels form trees whose leaves + // are labels, whose interior nodes (and roots) are bindings, and + // where links point from children to parents. Bindings are + // reference counted, allowing labels to be lightweight, copyable, + // assignable, placed in containers, and so on. + class Binding { + public: + Binding(); + Binding(uint64_t addend); + ~Binding(); + + // Increment our reference count. + void Acquire() { reference_count_++; }; + // Decrement our reference count, and return true if it is zero. + bool Release() { return --reference_count_ == 0; } + + // Set this binding to be equal to BINDING + ADDEND. If BINDING is + // NULL, then set this binding to the known constant ADDEND. + // Update every binding on this binding's chain to point directly + // to BINDING, or to be a constant, with addends adjusted + // appropriately. + void Set(Binding *binding, uint64_t value); + + // Return what we know about the value of this binding. + // - If this binding's value is a known constant, set BASE to + // NULL, and set ADDEND to its value. + // - If this binding is not a known constant but related to other + // bindings, set BASE to the binding at the end of the relation + // chain (which will always be unconstrained), and set ADDEND to the + // value to add to that binding's value to get this binding's + // value. + // - If this binding is unconstrained, set BASE to this, and leave + // ADDEND unchanged. + void Get(Binding **base, uint64_t *addend); + + private: + // There are three cases: + // + // - A binding representing a known constant value has base_ NULL, + // and addend_ equal to the value. + // + // - A binding representing a completely unconstrained value has + // base_ pointing to this; addend_ is unused. + // + // - A binding whose value is related to some other binding's + // value has base_ pointing to that other binding, and addend_ + // set to the amount to add to that binding's value to get this + // binding's value. We only represent relationships of the form + // x = y+c. + // + // Thus, the bind_ links form a chain terminating in either a + // known constant value or a completely unconstrained value. Most + // operations on bindings do path compression: they change every + // binding on the chain to point directly to the final value, + // adjusting addends as appropriate. + Binding *base_; + uint64_t addend_; + + // The number of Labels and Bindings pointing to this binding. + // (When a binding points to itself, indicating a completely + // unconstrained binding, that doesn't count as a reference.) + int reference_count_; + }; + + // This label's value. + Binding *value_; +}; + +inline Label operator+(uint64_t a, const Label &l) { return l + a; } +// Note that int-Label isn't defined, as negating a Label is not an +// operation we support. + +// Conventions for representing larger numbers as sequences of bytes. +enum Endianness { + kBigEndian, // Big-endian: the most significant byte comes first. + kLittleEndian, // Little-endian: the least significant byte comes first. + kUnsetEndian, // used internally +}; + +// A section is a sequence of bytes, constructed by appending bytes +// to the end. Sections have a convenient and flexible set of member +// functions for appending data in various formats: big-endian and +// little-endian signed and unsigned values of different sizes; +// LEB128 and ULEB128 values (see below), and raw blocks of bytes. +// +// If you need to append a value to a section that is not convenient +// to compute immediately, you can create a label, append the +// label's value to the section, and then set the label's value +// later, when it's convenient to do so. Once a label's value is +// known, the section class takes care of updating all previously +// appended references to it. +// +// Once all the labels to which a section refers have had their +// values determined, you can get a copy of the section's contents +// as a string. +// +// Note that there is no specified "start of section" label. This is +// because there are typically several different meanings for "the +// start of a section": the offset of the section within an object +// file, the address in memory at which the section's content appear, +// and so on. It's up to the code that uses the Section class to +// keep track of these explicitly, as they depend on the application. +class Section { + public: + Section(Endianness endianness = kUnsetEndian) + : endianness_(endianness) { }; + + // A base class destructor should be either public and virtual, + // or protected and nonvirtual. + virtual ~Section() { }; + + // Set the default endianness of this section to ENDIANNESS. This + // sets the behavior of the D appending functions. If the + // assembler's default endianness was set, this is the + void set_endianness(Endianness endianness) { + endianness_ = endianness; + } + + // Return the default endianness of this section. + Endianness endianness() const { return endianness_; } + + // Append the SIZE bytes at DATA or the contents of STRING to the + // end of this section. Return a reference to this section. + Section &Append(const uint8_t *data, size_t size) { + contents_.append(reinterpret_cast(data), size); + return *this; + }; + Section &Append(const string &data) { + contents_.append(data); + return *this; + }; + + // Append SIZE copies of BYTE to the end of this section. Return a + // reference to this section. + Section &Append(size_t size, uint8_t byte) { + contents_.append(size, (char) byte); + return *this; + } + + // Append NUMBER to this section. ENDIANNESS is the endianness to + // use to write the number. SIZE is the length of the number in + // bytes. Return a reference to this section. + Section &Append(Endianness endianness, size_t size, uint64_t number); + Section &Append(Endianness endianness, size_t size, const Label &label); + + // Append SECTION to the end of this section. The labels SECTION + // refers to need not be defined yet. + // + // Note that this has no effect on any Labels' values, or on + // SECTION. If placing SECTION within 'this' provides new + // constraints on existing labels' values, then it's up to the + // caller to fiddle with those labels as needed. + Section &Append(const Section §ion); + + // Append the contents of DATA as a series of bytes terminated by + // a NULL character. + Section &AppendCString(const string &data) { + Append(data); + contents_ += '\0'; + return *this; + } + + // Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes + // long, pad with '\0' characters. + Section &AppendCString(const string &data, size_t size) { + contents_.append(data, 0, size); + if (data.size() < size) + Append(size - data.size(), 0); + return *this; + } + + // Append VALUE or LABEL to this section, with the given bit width and + // endianness. Return a reference to this section. + // + // The names of these functions have the form : + // is either 'L' (little-endian, least significant byte first), + // 'B' (big-endian, most significant byte first), or + // 'D' (default, the section's default endianness) + // is 8, 16, 32, or 64. + // + // Since endianness doesn't matter for a single byte, all the + // =8 functions are equivalent. + // + // These can be used to write both signed and unsigned values, as + // the compiler will properly sign-extend a signed value before + // passing it to the function, at which point the function's + // behavior is the same either way. + Section &L8(uint8_t value) { contents_ += value; return *this; } + Section &B8(uint8_t value) { contents_ += value; return *this; } + Section &D8(uint8_t value) { contents_ += value; return *this; } + Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), + &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), + &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); + Section &L8(const Label &label), &L16(const Label &label), + &L32(const Label &label), &L64(const Label &label), + &B8(const Label &label), &B16(const Label &label), + &B32(const Label &label), &B64(const Label &label), + &D8(const Label &label), &D16(const Label &label), + &D32(const Label &label), &D64(const Label &label); + + // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. + // + // The signed LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between -0x40 and 0x3f, then its signed LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its signed LEB128 representation is (N & 0x7f) | + // 0x80, followed by the signed LEB128 representation of N / 128, + // rounded towards negative infinity. + // + // In other words, we break VALUE into groups of seven bits, put + // them in little-endian order, and then write them as eight-bit + // bytes with the high bit on all but the last. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &LEB128(long long value); + + // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. + // + // The unsigned LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between 0 and 0x7f, then its unsigned LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | + // 0x80, followed by the unsigned LEB128 representation of N / + // 128, rounded towards negative infinity. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &ULEB128(uint64_t value); + + // Jump to the next location aligned on an ALIGNMENT-byte boundary, + // relative to the start of the section. Fill the gap with PAD_BYTE. + // ALIGNMENT must be a power of two. Return a reference to this + // section. + Section &Align(size_t alignment, uint8_t pad_byte = 0); + + // Clear the contents of this section. + void Clear(); + + // Return the current size of the section. + size_t Size() const { return contents_.size(); } + + // Return a label representing the start of the section. + // + // It is up to the user whether this label represents the section's + // position in an object file, the section's address in memory, or + // what have you; some applications may need both, in which case + // this simple-minded interface won't be enough. This class only + // provides a single start label, for use with the Here and Mark + // member functions. + // + // Ideally, we'd provide this in a subclass that actually knows more + // about the application at hand and can provide an appropriate + // collection of start labels. But then the appending member + // functions like Append and D32 would return a reference to the + // base class, not the derived class, and the chaining won't work. + // Since the only value here is in pretty notation, that's a fatal + // flaw. + Label start() const { return start_; } + + // Return a label representing the point at which the next Appended + // item will appear in the section, relative to start(). + Label Here() const { return start_ + Size(); } + + // Set *LABEL to Here, and return a reference to this section. + Section &Mark(Label *label) { *label = Here(); return *this; } + + // If there are no undefined label references left in this + // section, set CONTENTS to the contents of this section, as a + // string, and clear this section. Return true on success, or false + // if there were still undefined labels. + bool GetContents(string *contents); + + private: + // Used internally. A reference to a label's value. + struct Reference { + Reference(size_t set_offset, Endianness set_endianness, size_t set_size, + const Label &set_label) + : offset(set_offset), endianness(set_endianness), size(set_size), + label(set_label) { } + + // The offset of the reference within the section. + size_t offset; + + // The endianness of the reference. + Endianness endianness; + + // The size of the reference. + size_t size; + + // The label to which this is a reference. + Label label; + }; + + // The default endianness of this section. + Endianness endianness_; + + // The contents of the section. + string contents_; + + // References to labels within those contents. + vector references_; + + // A label referring to the beginning of the section. + Label start_; +}; + +} // namespace test_assembler +} // namespace google_breakpad + +#endif // PROCESSOR_TEST_ASSEMBLER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc new file mode 100644 index 0000000000..94b5a5ce5f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc @@ -0,0 +1,1662 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" + +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using testing::Test; + +TEST(ConstructLabel, Simple) { + Label l; +} + +TEST(ConstructLabel, Undefined) { + Label l; + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(ConstructLabelDeathTest, Undefined) { + Label l; + ASSERT_DEATH(l.Value(), "IsKnownConstant\\(&v\\)"); +} + +TEST(ConstructLabel, Constant) { + Label l(0x060b9f974eaf301eULL); + uint64_t v; + EXPECT_TRUE(l.IsKnownConstant(&v)); + EXPECT_EQ(v, 0x060b9f974eaf301eULL); + EXPECT_EQ(l.Value(), 0x060b9f974eaf301eULL); +} + +TEST(ConstructLabel, Copy) { + Label l; + Label m(l); + uint64_t v; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &v)); + EXPECT_EQ(0U, v); +} + +// The left-hand-side of a label assignment can be either +// unconstrained, related, or known. The right-hand-side can be any of +// those, or an integer. +TEST(Assignment, UnconstrainedToUnconstrained) { + Label l, m; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, UnconstrainedToRelated) { + Label l, m, n; + l = n; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, UnconstrainedToKnown) { + Label l, m; + l = 0x8fd16e55b20a39c1ULL; + l = m; + EXPECT_EQ(0U, l-m); + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); + EXPECT_EQ(0U, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x8fd16e55b20a39c1ULL, m.Value()); +} + +TEST(Assignment, RelatedToUnconstrained) { + Label l, m, n; + m = n; + l = m; + EXPECT_EQ(0U, l-n); + EXPECT_TRUE(l.IsKnownOffsetFrom(n)); + uint64_t d; + EXPECT_TRUE(l.IsKnownOffsetFrom(n, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, RelatedToRelated) { + Label l, m, n, o; + l = n; + m = o; + l = m; + EXPECT_EQ(0U, n-o); + EXPECT_TRUE(n.IsKnownOffsetFrom(o)); + uint64_t d; + EXPECT_TRUE(n.IsKnownOffsetFrom(o, &d)); + EXPECT_EQ(0U, d); + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(Assignment, RelatedToKnown) { + Label l, m, n; + m = n; + l = 0xd2011f8c82ad56f2ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, m.Value()); + EXPECT_TRUE(n.IsKnownConstant()); + EXPECT_EQ(0xd2011f8c82ad56f2ULL, n.Value()); +} + +TEST(Assignment, KnownToUnconstrained) { + Label l, m; + m = 0x50b024c0d6073887ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x50b024c0d6073887ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x50b024c0d6073887ULL, m.Value()); +} + +TEST(Assignment, KnownToRelated) { + Label l, m, n; + l = n; + m = 0x5348883655c727e5ULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, m.Value()); + EXPECT_TRUE(n.IsKnownConstant()); + EXPECT_EQ(0x5348883655c727e5ULL, n.Value()); +} + +TEST(Assignment, KnownToKnown) { + Label l, m; + l = 0x36c209c20987564eULL; + m = 0x36c209c20987564eULL; + l = m; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x36c209c20987564eULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x36c209c20987564eULL, m.Value()); +} + +TEST(Assignment, ConstantToUnconstrained) { + Label l; + l = 0xc02495f4d7f5a957ULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xc02495f4d7f5a957ULL, l.Value()); +} + +TEST(Assignment, ConstantToRelated) { + Label l, m; + l = m; + l = 0x4577901cf275488dULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0x4577901cf275488dULL, l.Value()); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x4577901cf275488dULL, m.Value()); +} + +TEST(Assignment, ConstantToKnown) { + Label l; + l = 0xec0b9c369b7e8ea7ULL; + l = 0xec0b9c369b7e8ea7ULL; + EXPECT_TRUE(l.IsKnownConstant()); + EXPECT_EQ(0xec0b9c369b7e8ea7ULL, l.Value()); +} + +TEST(AssignmentDeathTest, Self) { + Label l; + ASSERT_DEATH(l = l, "binding != this"); +} + +TEST(AssignmentDeathTest, IndirectCycle) { + Label l, m, n; + l = m; + m = n; + ASSERT_DEATH(n = l, "binding != this"); +} + +TEST(AssignmentDeathTest, Cycle) { + Label l, m, n, o; + l = m; + m = n; + o = n; + ASSERT_DEATH(o = l, "binding != this"); +} + +TEST(Addition, LabelConstant) { + Label l, m; + m = l + 0x5248d93e8bbe9497ULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x5248d93e8bbe9497ULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Addition, ConstantLabel) { + Label l, m; + m = 0xf51e94e00d6e3c84ULL + l; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0xf51e94e00d6e3c84ULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Addition, KnownLabelConstant) { + Label l, m; + l = 0x16286307042ce0d8ULL; + m = l + 0x3fdddd91306719d7ULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x3fdddd91306719d7ULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x16286307042ce0d8ULL + 0x3fdddd91306719d7ULL, m.Value()); +} + +TEST(Addition, ConstantKnownLabel) { + Label l, m; + l = 0x50f62d0cdd1031deULL; + m = 0x1b13462d8577c538ULL + l; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(0x1b13462d8577c538ULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x50f62d0cdd1031deULL + 0x1b13462d8577c538ULL, m.Value()); +} + +TEST(Subtraction, LabelConstant) { + Label l, m; + m = l - 0x0620884d21d3138eULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(-0x0620884d21d3138eULL, d); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(Subtraction, KnownLabelConstant) { + Label l, m; + l = 0x6237fbaf9ef7929eULL; + m = l - 0x317730995d2ab6eeULL; + EXPECT_TRUE(m.IsKnownOffsetFrom(l)); + uint64_t d; + EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); + EXPECT_EQ(-0x317730995d2ab6eeULL, d); + EXPECT_TRUE(m.IsKnownConstant()); + EXPECT_EQ(0x6237fbaf9ef7929eULL - 0x317730995d2ab6eeULL, m.Value()); +} + +TEST(SubtractionDeathTest, LabelLabel) { + Label l, m; + ASSERT_DEATH(l - m, "IsKnownOffsetFrom\\(label, &offset\\)"); +} + +TEST(Subtraction, LabelLabel) { + Label l, m; + l = m + 0x7fa77ec63e28a17aULL; + EXPECT_EQ(0x7fa77ec63e28a17aULL, l - m); + EXPECT_EQ(-0x7fa77ec63e28a17aULL, m - l); +} + +TEST(IsKnownConstant, Undefined) { + Label l; + EXPECT_FALSE(l.IsKnownConstant()); +} + +TEST(IsKnownConstant, RelatedLabel) { + Label l, m; + l = m; + EXPECT_FALSE(l.IsKnownConstant()); + EXPECT_FALSE(m.IsKnownConstant()); +} + +TEST(IsKnownConstant, Constant) { + Label l; + l = 0xf374b1bdd6a22576ULL; + EXPECT_TRUE(l.IsKnownConstant()); +} + +TEST(IsKnownOffsetFrom, Unrelated) { + Label l, m; + EXPECT_FALSE(l.IsKnownOffsetFrom(m)); +} + +TEST(IsKnownOffsetFrom, Related) { + Label l, m; + l = m; + EXPECT_TRUE(l.IsKnownOffsetFrom(m)); +} + +// Test the construction of chains of related labels, and the +// propagation of values through them. +// +// Although the relations between labels are supposed to behave +// symmetrically --- that is, 'a = b' should put a and b in +// indistinguishable states --- there's a distinction made internally +// between the target (a) and the source (b). +// +// So there are five test axes to cover: +// +// - Do we construct the chain with assignment ("Assign") or with constructors +// ("Construct")? +// +// - Do we set the value of the label at the start of the chain +// ("Start") or the label at the end ("End")? +// +// - Are we testing the propagation of a relationship between variable +// values ("Relation"), or the propagation of a known constant value +// ("Value")? +// +// - Do we set the value before building the chain ("Before") or after +// the chain has been built ("After")? +// +// - Do we add new relationships to the end of the existing chain +// ("Forward") or to the beginning ("Backward")? +// +// Of course, "Construct" and "Backward" can't be combined, which +// eliminates eight combinations, and "Construct", "End", and "Before" +// can't be combined, which eliminates two more, so there are are 22 +// combinations, not 32. + +TEST(LabelChain, AssignStartRelationBeforeForward) { + Label a, b, c, d; + Label x; + a = x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationBeforeBackward) { + Label a, b, c, d; + Label x; + a = x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationAfterForward) { + Label a, b, c, d; + Label x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartRelationAfterBackward) { + Label a, b, c, d; + Label x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, AssignStartValueBeforeForward) { + Label a, b, c, d; + a = 0xa131200190546ac2ULL; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0xa131200190546ac2ULL + 0x111U, d.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0x11U, c.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0x1U, b.Value()); + EXPECT_EQ(0xa131200190546ac2ULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueBeforeBackward) { + Label a, b, c, d; + a = 0x8da17e1670ad4fa2ULL; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x111U, d.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x11U, c.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x1U, b.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueAfterForward) { + Label a, b, c, d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + a = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x111U, d.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x11U, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0x1U, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignStartValueAfterBackward) { + Label a, b, c, d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + a = 0xc86ca1d97ab5df6eULL; + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x111U, d.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x11U, c.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x1U, b.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0U, a.Value()); +} + +TEST(LabelChain, AssignEndRelationBeforeForward) { + Label a, b, c, d; + Label x; + x = d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0U, d-x); +} + +TEST(LabelChain, AssignEndRelationBeforeBackward) { + Label a, b, c, d; + Label x; + x = d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0U, d-x); +} + +TEST(LabelChain, AssignEndRelationAfterForward) { + Label a, b, c, d; + Label x; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, AssignEndRelationAfterBackward) { + Label a, b, c, d; + Label x; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, AssignEndValueBeforeForward) { + Label a, b, c, d; + d = 0xa131200190546ac2ULL; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + EXPECT_EQ(0xa131200190546ac2ULL - 0x111, a.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x110, b.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x100, c.Value()); + EXPECT_EQ(0xa131200190546ac2ULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueBeforeBackward) { + Label a, b, c, d; + d = 0x8da17e1670ad4fa2ULL; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x111, a.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x110, b.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x100, c.Value()); + EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueAfterForward) { + Label a, b, c, d; + b = a + 0x1; + c = b + 0x10; + d = c + 0x100; + d = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); +} + +TEST(LabelChain, AssignEndValueAfterBackward) { + Label a, b, c, d; + d = c + 0x100; + c = b + 0x10; + b = a + 0x1; + d = 0xc86ca1d97ab5df6eULL; + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x111, a.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x110, b.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x100, c.Value()); + EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x000, d.Value()); +} + +TEST(LabelChain, ConstructStartRelationBeforeForward) { + Label x; + Label a(x); + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, ConstructStartRelationAfterForward) { + Label x; + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + a = x; + EXPECT_EQ(0x111U, d-x); + EXPECT_EQ(0x11U, c-x); + EXPECT_EQ(0x1U, b-x); + EXPECT_EQ(0U, a-x); +} + +TEST(LabelChain, ConstructStartValueBeforeForward) { + Label a(0x5d234d177d01ccc8ULL); + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x111U, d.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x011U, c.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x001U, b.Value()); + EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x000U, a.Value()); +} + +TEST(LabelChain, ConstructStartValueAfterForward) { + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + a = 0xded85d54586e84fcULL; + EXPECT_EQ(0xded85d54586e84fcULL + 0x111U, d.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x011U, c.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x001U, b.Value()); + EXPECT_EQ(0xded85d54586e84fcULL + 0x000U, a.Value()); +} + +TEST(LabelChain, ConstructEndRelationAfterForward) { + Label x; + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + x = d; + EXPECT_EQ(-(uint64_t)0x111U, a-x); + EXPECT_EQ(-(uint64_t)0x110U, b-x); + EXPECT_EQ(-(uint64_t)0x100U, c-x); + EXPECT_EQ(-(uint64_t)0x000U, d-x); +} + +TEST(LabelChain, ConstructEndValueAfterForward) { + Label a; + Label b(a + 0x1); + Label c(b + 0x10); + Label d(c + 0x100); + d = 0x99b8f51bafd41adaULL; + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); + EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); +} + +TEST(LabelTree, KnownValue) { + Label l, m, n, o, p; + l = m; + m = n; + o = p; + p = n; + l = 0x536b5de3d468a1b5ULL; + EXPECT_EQ(0x536b5de3d468a1b5ULL, o.Value()); +} + +TEST(LabelTree, Related) { + Label l, m, n, o, p; + l = m - 1; + m = n - 10; + o = p + 100; + p = n + 1000; + EXPECT_EQ(1111U, o - l); +} + +TEST(EquationDeathTest, EqualConstants) { + Label m = 0x0d3962f280f07d24ULL; + Label n = 0x0d3962f280f07d24ULL; + m = n; // no death expected +} + +TEST(EquationDeathTest, EqualIndirectConstants) { + Label m = 0xa347f1e5238fe6a1ULL; + Label n; + Label o = n; + n = 0xa347f1e5238fe6a1ULL; + n = m; // no death expected +} + +TEST(EquationDeathTest, ConstantClash) { + Label m = 0xd4cc0f4f630ec741ULL; + Label n = 0x934cd2d8254fc3eaULL; + ASSERT_DEATH(m = n, "addend_ == addend"); +} + +TEST(EquationDeathTest, IndirectConstantClash) { + Label m = 0xd4cc0f4f630ec741ULL; + Label n, o; + n = o; + o = 0xcfbe3b83ac49ce86ULL; + ASSERT_DEATH(m = n, "addend_ == addend"); +} + +// Assigning to a related label may free the next Binding on its +// chain. This test always passes; it is interesting to memory +// checkers and coverage analysis. +TEST(LabelReferenceCount, AssignmentFree) { + Label l; + { + Label m; + l = m; + } + // This should free m's Binding. + l = 0xca8bae92f0376d4fULL; + ASSERT_EQ(0xca8bae92f0376d4fULL, l.Value()); +} + +// Finding the value of a label may free the Binding it refers to. This test +// always passes; it is interesting to memory checkers and coverage analysis. +TEST(LabelReferenceCount, FindValueFree) { + Label l; + { + Label m, n; + l = m; + m = n; + n = 0x7a0b0c576672daafULL; + // At this point, l's Binding refers to m's Binding, which refers + // to n's binding. + } + // Now, l is the only reference keeping the three Bindings alive. + // Resolving its value should free l's and m's original bindings. + ASSERT_EQ(0x7a0b0c576672daafULL, l.Value()); +} + +TEST(ConstructSection, Simple) { + Section s; +} + +TEST(ConstructSection, WithEndian) { + Section s(kBigEndian); +} + +// A fixture class for TestAssembler::Section tests. +class SectionFixture { + public: + Section section; + string contents; + static const uint8_t data[]; + static const size_t data_size; +}; + +const uint8_t SectionFixture::data[] = { + 0x87, 0x4f, 0x43, 0x67, 0x30, 0xd0, 0xd4, 0x0e +}; + +#define I0() +#define I1(a) { a } +#define I2(a,b) { a,b } +#define I3(a,b,c) { a,b,c } +#define I4(a,b,c,d) { a,b,c,d } +#define I5(a,b,c,d,e) { a,b,c,d,e } +#define I6(a,b,c,d,e,f) { a,b,c,d,e,f } +#define I7(a,b,c,d,e,f,g) { a,b,c,d,e,f,g } +#define I8(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h } +#define I9(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i } +#define ASSERT_BYTES(s, b) \ + do \ + { \ + static const uint8_t expected_bytes[] = b; \ + ASSERT_EQ(sizeof(expected_bytes), s.size()); \ + ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \ + sizeof(expected_bytes)) == 0); \ + } \ + while(0) + +class Append: public SectionFixture, public Test { }; + +TEST_F(Append, Bytes) { + section.Append(data, sizeof(data)); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(sizeof(data), contents.size()); + EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); +} + +TEST_F(Append, BytesTwice) { + section.Append(data, sizeof(data)); + section.Append(data, sizeof(data)); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(2 * sizeof(data), contents.size()); + ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); + ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data), + (const char *) data, sizeof(data))); +} + +TEST_F(Append, String) { + string s1 = "howdy "; + string s2 = "there"; + section.Append(s1); + section.Append(s2); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_STREQ(contents.c_str(), "howdy there"); +} + +TEST_F(Append, CString) { + section.AppendCString("howdy"); + section.AppendCString(""); + section.AppendCString("there"); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("howdy\0\0there\0", 13), contents); +} + +TEST_F(Append, CStringSize) { + section.AppendCString("howdy", 3); + section.AppendCString("there", 5); + section.AppendCString("fred", 6); + section.AppendCString("natalie", 0); + section.AppendCString("", 10); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("howtherefred\0\0\0\0\0\0\0\0\0\0\0\0", 24), contents); +} + +TEST_F(Append, RepeatedBytes) { + section.Append((size_t) 10, '*'); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_STREQ(contents.c_str(), "**********"); +} + +TEST_F(Append, GeneralLE1) { + section.Append(kLittleEndian, 1, 42); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); +} + +TEST_F(Append, GeneralLE2) { + section.Append(kLittleEndian, 2, 0x15a1); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0xa1, 0x15)); +} + +TEST_F(Append, GeneralLE3) { + section.Append(kLittleEndian, 3, 0x59ae8d); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); +} + +TEST_F(Append, GeneralLE4) { + section.Append(kLittleEndian, 4, 0x51603c56); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); +} + +TEST_F(Append, GeneralLE5) { + section.Append(kLittleEndian, 5, 0x385e2803b4ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); +} + +TEST_F(Append, GeneralLE6) { + section.Append(kLittleEndian, 6, 0xc7db9534dd1fULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); +} + +TEST_F(Append, GeneralLE7) { + section.Append(kLittleEndian, 7, 0x1445c9f1b843e6ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); +} + +TEST_F(Append, GeneralLE8) { + section.Append(kLittleEndian, 8, 0xaf48019dfe5c01e5ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); +} + +TEST_F(Append, GeneralBE1) { + section.Append(kBigEndian, 1, 0xd0ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(0xd0)); +} + +TEST_F(Append, GeneralBE2) { + section.Append(kBigEndian, 2, 0x2e7eULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2e, 0x7e)); +} + +TEST_F(Append, GeneralBE3) { + section.Append(kBigEndian, 3, 0x37dad6ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); +} + +TEST_F(Append, GeneralBE4) { + section.Append(kBigEndian, 4, 0x715935c7ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); +} + +TEST_F(Append, GeneralBE5) { + section.Append(kBigEndian, 5, 0x42baeb02b7ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); +} + +TEST_F(Append, GeneralBE6) { + section.Append(kBigEndian, 6, 0xf1cdf10e7b18ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); +} + +TEST_F(Append, GeneralBE7) { + section.Append(kBigEndian, 7, 0xf50a724f0b0d20ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); +} + +TEST_F(Append, GeneralBE8) { + section.Append(kBigEndian, 8, 0xa6b2cb5e98dc9c16ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); +} + +TEST_F(Append, GeneralLE1Label) { + Label l; + section.Append(kLittleEndian, 1, l); + l = 42; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); +} + +TEST_F(Append, GeneralLE2Label) { + Label l; + section.Append(kLittleEndian, 2, l); + l = 0x15a1; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0xa1, 0x15)); +} + +TEST_F(Append, GeneralLE3Label) { + Label l; + section.Append(kLittleEndian, 3, l); + l = 0x59ae8d; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); +} + +TEST_F(Append, GeneralLE4Label) { + Label l; + section.Append(kLittleEndian, 4, l); + l = 0x51603c56; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); +} + +TEST_F(Append, GeneralLE5Label) { + Label l; + section.Append(kLittleEndian, 5, l); + l = 0x385e2803b4ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); +} + +TEST_F(Append, GeneralLE6Label) { + Label l; + section.Append(kLittleEndian, 6, l); + l = 0xc7db9534dd1fULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); +} + +TEST_F(Append, GeneralLE7Label) { + Label l; + section.Append(kLittleEndian, 7, l); + l = 0x1445c9f1b843e6ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); +} + +TEST_F(Append, GeneralLE8Label) { + Label l; + section.Append(kLittleEndian, 8, l); + l = 0xaf48019dfe5c01e5ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); +} + +TEST_F(Append, GeneralBE1Label) { + Label l; + section.Append(kBigEndian, 1, l); + l = 0xd0ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(0xd0)); +} + +TEST_F(Append, GeneralBE2Label) { + Label l; + section.Append(kBigEndian, 2, l); + l = 0x2e7eULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2e, 0x7e)); +} + +TEST_F(Append, GeneralBE3Label) { + Label l; + section.Append(kBigEndian, 3, l); + l = 0x37dad6ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); +} + +TEST_F(Append, GeneralBE4Label) { + Label l; + section.Append(kBigEndian, 4, l); + l = 0x715935c7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); +} + +TEST_F(Append, GeneralBE5Label) { + Label l; + section.Append(kBigEndian, 5, l); + l = 0x42baeb02b7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); +} + +TEST_F(Append, GeneralBE6Label) { + Label l; + section.Append(kBigEndian, 6, l); + l = 0xf1cdf10e7b18ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); +} + +TEST_F(Append, GeneralBE7Label) { + Label l; + section.Append(kBigEndian, 7, l); + l = 0xf50a724f0b0d20ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); +} + +TEST_F(Append, GeneralBE8Label) { + Label l; + section.Append(kBigEndian, 8, l); + l = 0xa6b2cb5e98dc9c16ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); +} + +TEST_F(Append, B8) { + section.Append(1, 0x2a); + section.B8(0xd3U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xd3)); +} + +TEST_F(Append, B8Label) { + Label l; + section.Append(1, 0x2a); + section.B8(l); + l = 0x4bU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x4b)); +} + +TEST_F(Append, B16) { + section.Append(1, 0x2a); + section.B16(0x472aU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x47, 0x2a)); +} + +TEST_F(Append, B16Label) { + Label l; + section.Append(1, 0x2a); + section.B16(l); + l = 0x55e8U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x55, 0xe8)); +} + +TEST_F(Append, B32) { + section.Append(1, 0x2a); + section.B32(0xbd412cbcU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xbd, 0x41, 0x2c, 0xbc)); +} + +TEST_F(Append, B32Label) { + Label l; + section.Append(1, 0x2a); + section.B32(l); + l = 0x208e37d5U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x20, 0x8e, 0x37, 0xd5)); +} + +TEST_F(Append, B64) { + section.Append(1, 0x2a); + section.B64(0x3402a013111e68adULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x34, 0x02, 0xa0, 0x13, 0x11, 0x1e, 0x68, 0xad)); +} + +TEST_F(Append, B64Label) { + Label l; + section.Append(1, 0x2a); + section.B64(l); + l = 0x355dbfbb4ac6d57fULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x35, 0x5d, 0xbf, 0xbb, 0x4a, 0xc6, 0xd5, 0x7f)); +} + +TEST_F(Append, L8) { + section.Append(1, 0x2a); + section.L8(0x26U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x26)); +} + +TEST_F(Append, L8Label) { + Label l; + section.Append(1, 0x2a); + section.L8(l); + l = 0xa8U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xa8)); +} + +TEST_F(Append, L16) { + section.Append(1, 0x2a); + section.L16(0xca6dU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x6d, 0xca)); +} + +TEST_F(Append, L16Label) { + Label l; + section.Append(1, 0x2a); + section.L16(l); + l = 0xd21fU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x1f, 0xd2)); +} + +TEST_F(Append, L32) { + section.Append(1, 0x2a); + section.L32(0x558f6181U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x81, 0x61, 0x8f, 0x55)); +} + +TEST_F(Append, L32Label) { + Label l; + section.Append(1, 0x2a); + section.L32(l); + l = 0x4b810f82U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x82, 0x0f, 0x81, 0x4b)); +} + +TEST_F(Append, L64) { + section.Append(1, 0x2a); + section.L64(0x564384f7579515bfULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xbf, 0x15, 0x95, 0x57, 0xf7, 0x84, 0x43, 0x56)); +} + +TEST_F(Append, L64Label) { + Label l; + section.Append(1, 0x2a); + section.L64(l); + l = 0x424b1d020667c8dbULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xdb, 0xc8, 0x67, 0x06, 0x02, 0x1d, 0x4b, 0x42)); +} + +TEST_F(Append, D8Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D8(0xe6U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xe6)); +} + +TEST_F(Append, D8BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D8(l); + l = 0xeeU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0xee)); +} + +TEST_F(Append, D16Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D16(0x83b1U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x83, 0xb1)); +} + +TEST_F(Append, D16BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D16(l); + l = 0x5b55U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x5b, 0x55)); +} + +TEST_F(Append, D32Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D32(0xd0b0e431U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xd0, 0xb0, 0xe4, 0x31)); +} + +TEST_F(Append, D32BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D32(l); + l = 0x312fb340U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x31, 0x2f, 0xb3, 0x40)); +} + +TEST_F(Append, D64Big) { + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D64(0xb109843500dbcb16ULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xb1, 0x09, 0x84, 0x35, 0x00, 0xdb, 0xcb, 0x16)); +} + +TEST_F(Append, D64BigLabel) { + Label l; + section.set_endianness(kBigEndian); + section.Append(1, 0x2a); + section.D64(l); + l = 0x9a0d61b70f671fd7ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x9a, 0x0d, 0x61, 0xb7, 0x0f, 0x67, 0x1f, 0xd7)); +} + +TEST_F(Append, D8Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D8(0x42U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x42)); +} + +TEST_F(Append, D8LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D8(l); + l = 0x05U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I2(0x2a, 0x05)); +} + +TEST_F(Append, D16Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D16(0xc5c5U); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0xc5, 0xc5)); +} + +TEST_F(Append, D16LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D16(l); + l = 0xb620U; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I3(0x2a, 0x20, 0xb6)); +} + +TEST_F(Append, D32Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D32(0x1a87d0feU); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0xfe, 0xd0, 0x87, 0x1a)); +} + +TEST_F(Append, D32LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D32(l); + l = 0xb8012d6bU; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I5(0x2a, 0x6b, 0x2d, 0x01, 0xb8)); +} + +TEST_F(Append, D64Little) { + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D64(0x42de75c61375a1deULL); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0xde, 0xa1, 0x75, 0x13, 0xc6, 0x75, 0xde, 0x42)); +} + +TEST_F(Append, D64LittleLabel) { + Label l; + section.set_endianness(kLittleEndian); + section.Append(1, 0x2a); + section.D64(l); + l = 0x8b3bececf3fb5312ULL; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, + I9(0x2a, 0x12, 0x53, 0xfb, 0xf3, 0xec, 0xec, 0x3b, 0x8b)); +} + +TEST_F(Append, Variety) { + Label a, b, c, d, e, f, g, h; + section.Append(kBigEndian, 1, a) + .Append(kLittleEndian, 8, h) + .Append(kBigEndian, 1, 0x8bULL) + .Append(kLittleEndian, 8, 0x0ea56540448f4439ULL) + .Append(kBigEndian, 2, b) + .Append(kLittleEndian, 7, g) + .Append(kBigEndian, 2, 0xcf15ULL) + .Append(kLittleEndian, 7, 0x29694f04c5724aULL) + .Append(kBigEndian, 3, c) + .Append(kLittleEndian, 6, f) + .Append(kBigEndian, 3, 0x8c3ffdULL) + .Append(kLittleEndian, 6, 0x6f11ba80187aULL) + .Append(kBigEndian, 4, d) + .Append(kLittleEndian, 5, e) + .Append(kBigEndian, 4, 0x2fda2472ULL) + .Append(kLittleEndian, 5, 0x0aa02d423fULL) + .Append(kBigEndian, 5, e) + .Append(kLittleEndian, 4, d) + .Append(kBigEndian, 5, 0x53ba432138ULL) + .Append(kLittleEndian, 4, 0xf139ae60ULL) + .Append(kBigEndian, 6, f) + .Append(kLittleEndian, 3, c) + .Append(kBigEndian, 6, 0x168e436af716ULL) + .Append(kLittleEndian, 3, 0x3ef189ULL) + .Append(kBigEndian, 7, g) + .Append(kLittleEndian, 2, b) + .Append(kBigEndian, 7, 0xacd4ef233e47d9ULL) + .Append(kLittleEndian, 2, 0x5311ULL) + .Append(kBigEndian, 8, h) + .Append(kLittleEndian, 1, a) + .Append(kBigEndian, 8, 0x4668d5f1c93637a1ULL) + .Append(kLittleEndian, 1, 0x65ULL); + a = 0x79ac9bd8aa256b35ULL; + b = 0x22d13097ef86c91cULL; + c = 0xf204968b0a05862fULL; + d = 0x163177f15a0eb4ecULL; + e = 0xbd1b0f1d977f2246ULL; + f = 0x2b0842eee83c6461ULL; + g = 0x92f4b928a4bf875eULL; + h = 0x61a199a8f7286ba6ULL; + ASSERT_EQ(8 * 18U, section.Size()); + ASSERT_TRUE(section.GetContents(&contents)); + + static const uint8_t expected[] = { + 0x35, 0xa6, 0x6b, 0x28, 0xf7, 0xa8, 0x99, 0xa1, 0x61, + 0x8b, 0x39, 0x44, 0x8f, 0x44, 0x40, 0x65, 0xa5, 0x0e, + 0xc9, 0x1c, 0x5e, 0x87, 0xbf, 0xa4, 0x28, 0xb9, 0xf4, + 0xcf, 0x15, 0x4a, 0x72, 0xc5, 0x04, 0x4f, 0x69, 0x29, + 0x05, 0x86, 0x2f, 0x61, 0x64, 0x3c, 0xe8, 0xee, 0x42, + 0x8c, 0x3f, 0xfd, 0x7a, 0x18, 0x80, 0xba, 0x11, 0x6f, + 0x5a, 0x0e, 0xb4, 0xec, 0x46, 0x22, 0x7f, 0x97, 0x1d, + 0x2f, 0xda, 0x24, 0x72, 0x3f, 0x42, 0x2d, 0xa0, 0x0a, + 0x1d, 0x97, 0x7f, 0x22, 0x46, 0xec, 0xb4, 0x0e, 0x5a, + 0x53, 0xba, 0x43, 0x21, 0x38, 0x60, 0xae, 0x39, 0xf1, + 0x42, 0xee, 0xe8, 0x3c, 0x64, 0x61, 0x2f, 0x86, 0x05, + 0x16, 0x8e, 0x43, 0x6a, 0xf7, 0x16, 0x89, 0xf1, 0x3e, + 0xf4, 0xb9, 0x28, 0xa4, 0xbf, 0x87, 0x5e, 0x1c, 0xc9, + 0xac, 0xd4, 0xef, 0x23, 0x3e, 0x47, 0xd9, 0x11, 0x53, + 0x61, 0xa1, 0x99, 0xa8, 0xf7, 0x28, 0x6b, 0xa6, 0x35, + 0x46, 0x68, 0xd5, 0xf1, 0xc9, 0x36, 0x37, 0xa1, 0x65, + }; + + ASSERT_TRUE(0 == memcmp(contents.data(), expected, sizeof(expected))); +} + +TEST_F(Append, Section) { + section.Append("murder"); + { + Section middle; + middle.Append(" she"); + section.Append(middle); + } + section.Append(" wrote"); + EXPECT_EQ(16U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_STREQ(contents.c_str(), "murder she wrote"); +} + +TEST_F(Append, SectionRefs) { + section.Append("sugar "); + Label l; + { + Section middle; + Label m; + middle.B32(m); + section.Append(middle); + m = 0x66726565; + } + section.Append(" jazz"); + EXPECT_EQ(15U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_STREQ(contents.c_str(), "sugar free jazz"); +} + +TEST_F(Append, LEB128_0) { + section.LEB128(0); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\0", 1), contents); +} + +TEST_F(Append, LEB128_0x3f) { + section.LEB128(0x3f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x3f", 1), contents); +} + +TEST_F(Append, LEB128_0x40) { + section.LEB128(0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xc0\x00", 2), contents); +} + +TEST_F(Append, LEB128_0x7f) { + section.LEB128(0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x00", 2), contents); +} + +TEST_F(Append, LEB128_0x80) { + section.LEB128(0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x01", 2), contents); +} + +TEST_F(Append, LEB128_0xff) { + section.LEB128(0xff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x01", 2), contents); +} + +TEST_F(Append, LEB128_0x1fff) { + section.LEB128(0x1fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x3f", 2), contents); +} + +TEST_F(Append, LEB128_0x2000) { + section.LEB128(0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\xc0\x00", 3), contents); +} + +TEST_F(Append, LEB128_n1) { + section.LEB128(-1); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x7f", 1), contents); +} + +TEST_F(Append, LEB128_n0x40) { + section.LEB128(-0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x40", 1), contents); +} + +TEST_F(Append, LEB128_n0x41) { + section.LEB128(-0x41); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xbf\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x7f) { + section.LEB128(-0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x81\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x80) { + section.LEB128(-0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x7f", 2), contents); +} + +TEST_F(Append, LEB128_n0x2000) { + section.LEB128(-0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x40", 2), contents); +} + +TEST_F(Append, LEB128_n0x2001) { + section.LEB128(-0x2001); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\xbf\x7f", 3), contents); +} + +TEST_F(Append,ULEB128_0) { + section.ULEB128(0); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\0", 1), contents); +} + +TEST_F(Append,ULEB128_1) { + section.ULEB128(1); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x01", 1), contents); +} + +TEST_F(Append,ULEB128_0x3f) { + section.ULEB128(0x3f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x3f", 1), contents); +} + +TEST_F(Append,ULEB128_0x40) { + section.ULEB128(0x40); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x40", 1), contents); +} + +TEST_F(Append,ULEB128_0x7f) { + section.ULEB128(0x7f); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x7f", 1), contents); +} + +TEST_F(Append,ULEB128_0x80) { + section.ULEB128(0x80); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x01", 2), contents); +} + +TEST_F(Append,ULEB128_0xff) { + section.ULEB128(0xff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x01", 2), contents); +} + +TEST_F(Append,ULEB128_0x100) { + section.ULEB128(0x100); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x02", 2), contents); +} + +TEST_F(Append,ULEB128_0x1fff) { + section.ULEB128(0x1fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x3f", 2), contents); +} + +TEST_F(Append,ULEB128_0x2000) { + section.ULEB128(0x2000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x40", 2), contents); +} + +TEST_F(Append,ULEB128_0x3fff) { + section.ULEB128(0x3fff); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xff\x7f", 2), contents); +} + +TEST_F(Append,ULEB128_0x4000) { + section.ULEB128(0x4000); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x80\x01", 3), contents); +} + +TEST_F(Append,ULEB128_12857) { + section.ULEB128(12857); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\xb9\x64", 2), contents); +} + +TEST_F(Append, LEBChain) { + section.LEB128(-0x80).ULEB128(12857).Append("*"); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x80\x7f\xb9\x64*", 5), contents); +} + + +class GetContents: public SectionFixture, public Test { }; + +TEST_F(GetContents, Undefined) { + Label l; + section.Append(kLittleEndian, 8, l); + ASSERT_FALSE(section.GetContents(&contents)); +} + +TEST_F(GetContents, ClearsContents) { + section.Append((size_t) 10, '*'); + EXPECT_EQ(10U, section.Size()); + EXPECT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(0U, section.Size()); +} + +TEST_F(GetContents, ClearsReferences) { + Label l; + section.Append(kBigEndian, 1, l); + l = 42; + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_BYTES(contents, I1(42)); + ASSERT_TRUE(section.GetContents(&contents)); // should not die +} + +class Miscellanea: public SectionFixture, public Test { }; + +TEST_F(Miscellanea, Clear) { + section.Append("howdy"); + Label l; + section.L32(l); + EXPECT_EQ(9U, section.Size()); + section.Clear(); + EXPECT_EQ(0U, section.Size()); + l = 0x8d231bf0U; + ASSERT_TRUE(section.GetContents(&contents)); // should not die +} + +TEST_F(Miscellanea, Align) { + section.Append("*"); + EXPECT_EQ(1U, section.Size()); + section.Align(4).Append("*"); + EXPECT_EQ(5U, section.Size()); + section.Append("*").Align(2); + EXPECT_EQ(6U, section.Size()); +} + +TEST_F(Miscellanea, AlignPad) { + section.Append("*"); + EXPECT_EQ(1U, section.Size()); + section.Align(4, ' ').Append("*"); + EXPECT_EQ(5U, section.Size()); + section.Append("*").Align(2, ' '); + EXPECT_EQ(6U, section.Size()); + ASSERT_TRUE(section.GetContents(&contents)); + ASSERT_EQ(string("* **"), contents); +} + +TEST_F(Miscellanea, StartHereMark) { + Label m; + section.Append(42, ' ').Mark(&m).Append(13, '+'); + EXPECT_EQ(42U, m - section.start()); + EXPECT_EQ(42U + 13U, section.Here() - section.start()); + EXPECT_FALSE(section.start().IsKnownConstant()); + EXPECT_FALSE(m.IsKnownConstant()); + EXPECT_FALSE(section.Here().IsKnownConstant()); +} + +TEST_F(Miscellanea, Endianness) { + section.set_endianness(kBigEndian); + EXPECT_EQ(kBigEndian, section.endianness()); + section.set_endianness(kLittleEndian); + EXPECT_EQ(kLittleEndian, section.endianness()); +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h b/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h new file mode 100644 index 0000000000..05538f961b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h @@ -0,0 +1,676 @@ +// -*- mode: c++ -*- + +// Test data for pairing functions and lines. +// +// For a pair of functions that are adjacent (10,20),(20,25) and a +// pair that are not (10,15),(20,25), we include a test case for every +// possible arrangement of two lines relative to those functions. We +// include cases only for non-empty ranges, since empty functions and +// lines are dropped before we do any pairing. +// +// Each test case is represented by a macro call of the form: +// +// PAIRING(func1_start, func1_end, func2_start, func2_end, +// line1_start, line1_end, line2_start, line2_end, +// func1_num_lines, func2_num_lines, +// func1_line1_start, func1_line1_end, +// func1_line2_start, func1_line2_end, +// func2_line1_start, func2_line1_end, +// func2_line2_start, func2_line2_end, +// uncovered_funcs, uncovered_lines) +// +// where: +// - funcN_{start,end} is the range of the N'th function +// - lineN_{start,end} is the range of the N'th function +// - funcN_num_lines is the number of source lines that should be +// paired with the N'th function +// - funcN_lineM_{start,end} is the range of the M'th line +// paired with the N'th function, where 0,0 indicates that +// there should be no such line paired +// - uncovered_funcs is the number of functions with area that is +// uncovered by any line, and +// - uncovered_lines is the reverse. + +// func1 func2 line1 line2 num pairing1 pairing2 uncovered +PAIRING(10, 20, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #0 +PAIRING(10, 20, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #1 +PAIRING(10, 20, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #2 +PAIRING(10, 20, 20, 25, 6, 7, 7, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #3 +PAIRING(10, 20, 20, 25, 6, 7, 7, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #4 +PAIRING(10, 20, 20, 25, 6, 7, 7, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #5 +PAIRING(10, 20, 20, 25, 6, 7, 7, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #6 +PAIRING(10, 20, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #7 +PAIRING(10, 20, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #8 +PAIRING(10, 20, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #9 +PAIRING(10, 20, 20, 25, 6, 7, 8, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #10 +PAIRING(10, 20, 20, 25, 6, 7, 8, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #11 +PAIRING(10, 20, 20, 25, 6, 7, 8, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #12 +PAIRING(10, 20, 20, 25, 6, 7, 8, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #13 +PAIRING(10, 20, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #14 +PAIRING(10, 20, 20, 25, 6, 7, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #15 +PAIRING(10, 20, 20, 25, 6, 7, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #16 +PAIRING(10, 20, 20, 25, 6, 7, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #17 +PAIRING(10, 20, 20, 25, 6, 7, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #18 +PAIRING(10, 20, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #19 +PAIRING(10, 20, 20, 25, 6, 7, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #20 +PAIRING(10, 20, 20, 25, 6, 7, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #21 +PAIRING(10, 20, 20, 25, 6, 7, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #22 +PAIRING(10, 20, 20, 25, 6, 7, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #23 +PAIRING(10, 20, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #24 +PAIRING(10, 20, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #25 +PAIRING(10, 20, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #26 +PAIRING(10, 20, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #27 +PAIRING(10, 20, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #28 +PAIRING(10, 20, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #29 +PAIRING(10, 20, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #30 +PAIRING(10, 20, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #31 +PAIRING(10, 20, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #32 +PAIRING(10, 20, 20, 25, 6, 10, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #33 +PAIRING(10, 20, 20, 25, 6, 10, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #34 +PAIRING(10, 20, 20, 25, 6, 10, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #35 +PAIRING(10, 20, 20, 25, 6, 10, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #36 +PAIRING(10, 20, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #37 +PAIRING(10, 20, 20, 25, 6, 10, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #38 +PAIRING(10, 20, 20, 25, 6, 10, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #39 +PAIRING(10, 20, 20, 25, 6, 10, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #40 +PAIRING(10, 20, 20, 25, 6, 10, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #41 +PAIRING(10, 20, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #42 +PAIRING(10, 20, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #43 +PAIRING(10, 20, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #44 +PAIRING(10, 20, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #45 +PAIRING(10, 20, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #46 +PAIRING(10, 20, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #47 +PAIRING(10, 20, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #48 +PAIRING(10, 20, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #49 +PAIRING(10, 20, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #50 +PAIRING(10, 20, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 1) // #51 +PAIRING(10, 20, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 1) // #52 +PAIRING(10, 20, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #53 +PAIRING(10, 20, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 2) // #54 +PAIRING(10, 20, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #55 +PAIRING(10, 20, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 1) // #56 +PAIRING(10, 20, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 1) // #57 +PAIRING(10, 20, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #58 +PAIRING(10, 20, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 2) // #59 +PAIRING(10, 20, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #60 +PAIRING(10, 20, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #61 +PAIRING(10, 20, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #62 +PAIRING(10, 20, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #63 +PAIRING(10, 20, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #64 +PAIRING(10, 20, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #65 +PAIRING(10, 20, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #66 +PAIRING(10, 20, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #67 +PAIRING(10, 20, 20, 25, 6, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #68 +PAIRING(10, 20, 20, 25, 6, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #69 +PAIRING(10, 20, 20, 25, 6, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #70 +PAIRING(10, 20, 20, 25, 6, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 1) // #71 +PAIRING(10, 20, 20, 25, 6, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #72 +PAIRING(10, 20, 20, 25, 6, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 2) // #73 +PAIRING(10, 20, 20, 25, 6, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #74 +PAIRING(10, 20, 20, 25, 6, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #75 +PAIRING(10, 20, 20, 25, 6, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 1) // #76 +PAIRING(10, 20, 20, 25, 6, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #77 +PAIRING(10, 20, 20, 25, 6, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 2) // #78 +PAIRING(10, 20, 20, 25, 6, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 1) // #79 +PAIRING(10, 20, 20, 25, 6, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #80 +PAIRING(10, 20, 20, 25, 6, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 2) // #81 +PAIRING(10, 20, 20, 25, 6, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #82 +PAIRING(10, 20, 20, 25, 6, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #83 +PAIRING(10, 20, 20, 25, 6, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #84 +PAIRING(10, 20, 20, 25, 6, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #85 +PAIRING(10, 20, 20, 25, 6, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #86 +PAIRING(10, 20, 20, 25, 6, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #87 +PAIRING(10, 20, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #88 +PAIRING(10, 20, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 0) // #89 +PAIRING(10, 20, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 0) // #90 +PAIRING(10, 20, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 0) // #91 +PAIRING(10, 20, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #92 +PAIRING(10, 20, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #93 +PAIRING(10, 20, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 0) // #94 +PAIRING(10, 20, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 0) // #95 +PAIRING(10, 20, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 0) // #96 +PAIRING(10, 20, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #97 +PAIRING(10, 20, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #98 +PAIRING(10, 20, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #99 +PAIRING(10, 20, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #100 +PAIRING(10, 20, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #101 +PAIRING(10, 20, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #102 +PAIRING(10, 20, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #103 +PAIRING(10, 20, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #104 +PAIRING(10, 20, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #105 +PAIRING(10, 20, 20, 25, 10, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 0) // #106 +PAIRING(10, 20, 20, 25, 10, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 0) // #107 +PAIRING(10, 20, 20, 25, 10, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #108 +PAIRING(10, 20, 20, 25, 10, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 0) // #109 +PAIRING(10, 20, 20, 25, 10, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 0) // #110 +PAIRING(10, 20, 20, 25, 10, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #111 +PAIRING(10, 20, 20, 25, 10, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #112 +PAIRING(10, 20, 20, 25, 10, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #113 +PAIRING(10, 20, 20, 25, 10, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 0) // #114 +PAIRING(10, 20, 20, 25, 10, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 0) // #115 +PAIRING(10, 20, 20, 25, 10, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #116 +PAIRING(10, 20, 20, 25, 10, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 0) // #117 +PAIRING(10, 20, 20, 25, 10, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 0) // #118 +PAIRING(10, 20, 20, 25, 10, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #119 +PAIRING(10, 20, 20, 25, 10, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #120 +PAIRING(10, 20, 20, 25, 10, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #121 +PAIRING(10, 20, 20, 25, 10, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #122 +PAIRING(10, 20, 20, 25, 10, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #123 +PAIRING(10, 20, 20, 25, 10, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #124 +PAIRING(10, 20, 20, 25, 10, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #125 +PAIRING(10, 20, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #126 +PAIRING(10, 20, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 20, 0, 0, 0, 0, 2, 0) // #127 +PAIRING(10, 20, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 20, 20, 21, 0, 0, 2, 0) // #128 +PAIRING(10, 20, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 0) // #129 +PAIRING(10, 20, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 1) // #130 +PAIRING(10, 20, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #131 +PAIRING(10, 20, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 20, 0, 0, 0, 0, 2, 0) // #132 +PAIRING(10, 20, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 20, 20, 21, 0, 0, 2, 0) // #133 +PAIRING(10, 20, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 0) // #134 +PAIRING(10, 20, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 1) // #135 +PAIRING(10, 20, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #136 +PAIRING(10, 20, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #137 +PAIRING(10, 20, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #138 +PAIRING(10, 20, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #139 +PAIRING(10, 20, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #140 +PAIRING(10, 20, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #141 +PAIRING(10, 20, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #142 +PAIRING(10, 20, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #143 +PAIRING(10, 20, 20, 25, 11, 20, 20, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 0) // #144 +PAIRING(10, 20, 20, 25, 11, 20, 20, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 0) // #145 +PAIRING(10, 20, 20, 25, 11, 20, 20, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #146 +PAIRING(10, 20, 20, 25, 11, 20, 21, 22, 1, 1, 11, 20, 0, 0, 21, 22, 0, 0, 2, 0) // #147 +PAIRING(10, 20, 20, 25, 11, 20, 21, 25, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 0) // #148 +PAIRING(10, 20, 20, 25, 11, 20, 21, 26, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 1) // #149 +PAIRING(10, 20, 20, 25, 11, 20, 25, 26, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #150 +PAIRING(10, 20, 20, 25, 11, 20, 26, 27, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #151 +PAIRING(10, 20, 20, 25, 11, 21, 21, 22, 1, 2, 11, 20, 0, 0, 20, 21, 21, 22, 2, 0) // #152 +PAIRING(10, 20, 20, 25, 11, 21, 21, 25, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 0) // #153 +PAIRING(10, 20, 20, 25, 11, 21, 21, 26, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 1) // #154 +PAIRING(10, 20, 20, 25, 11, 21, 22, 23, 1, 2, 11, 20, 0, 0, 20, 21, 22, 23, 2, 0) // #155 +PAIRING(10, 20, 20, 25, 11, 21, 22, 25, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 0) // #156 +PAIRING(10, 20, 20, 25, 11, 21, 22, 26, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 1) // #157 +PAIRING(10, 20, 20, 25, 11, 21, 25, 26, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #158 +PAIRING(10, 20, 20, 25, 11, 21, 26, 27, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #159 +PAIRING(10, 20, 20, 25, 11, 25, 25, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #160 +PAIRING(10, 20, 20, 25, 11, 25, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #161 +PAIRING(10, 20, 20, 25, 11, 26, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #162 +PAIRING(10, 20, 20, 25, 11, 26, 27, 28, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #163 +PAIRING(10, 20, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #164 +PAIRING(10, 20, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #165 +PAIRING(10, 20, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #166 +PAIRING(10, 20, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #167 +PAIRING(10, 20, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #168 +PAIRING(10, 20, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #169 +PAIRING(10, 20, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #170 +PAIRING(10, 20, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #171 +PAIRING(10, 20, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #172 +PAIRING(10, 20, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #173 +PAIRING(10, 20, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #174 +PAIRING(10, 20, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #175 +PAIRING(10, 20, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #176 +PAIRING(10, 20, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #177 +PAIRING(10, 20, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #178 +PAIRING(10, 20, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #179 +PAIRING(10, 20, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #180 +PAIRING(10, 20, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #181 +PAIRING(10, 20, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #182 +PAIRING(10, 20, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #183 +PAIRING(10, 20, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #184 +PAIRING(10, 20, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #185 +PAIRING(10, 20, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #186 +PAIRING(10, 20, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #187 +PAIRING(10, 20, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #188 +PAIRING(10, 20, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #189 +PAIRING(10, 20, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #190 +PAIRING(10, 20, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #191 +PAIRING(10, 15, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #192 +PAIRING(10, 15, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #193 +PAIRING(10, 15, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #194 +PAIRING(10, 15, 20, 25, 6, 7, 7, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #195 +PAIRING(10, 15, 20, 25, 6, 7, 7, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #196 +PAIRING(10, 15, 20, 25, 6, 7, 7, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #197 +PAIRING(10, 15, 20, 25, 6, 7, 7, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #198 +PAIRING(10, 15, 20, 25, 6, 7, 7, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #199 +PAIRING(10, 15, 20, 25, 6, 7, 7, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #200 +PAIRING(10, 15, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #201 +PAIRING(10, 15, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #202 +PAIRING(10, 15, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #203 +PAIRING(10, 15, 20, 25, 6, 7, 8, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #204 +PAIRING(10, 15, 20, 25, 6, 7, 8, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #205 +PAIRING(10, 15, 20, 25, 6, 7, 8, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #206 +PAIRING(10, 15, 20, 25, 6, 7, 8, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #207 +PAIRING(10, 15, 20, 25, 6, 7, 8, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #208 +PAIRING(10, 15, 20, 25, 6, 7, 8, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #209 +PAIRING(10, 15, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #210 +PAIRING(10, 15, 20, 25, 6, 7, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #211 +PAIRING(10, 15, 20, 25, 6, 7, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #212 +PAIRING(10, 15, 20, 25, 6, 7, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #213 +PAIRING(10, 15, 20, 25, 6, 7, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #214 +PAIRING(10, 15, 20, 25, 6, 7, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #215 +PAIRING(10, 15, 20, 25, 6, 7, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #216 +PAIRING(10, 15, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #217 +PAIRING(10, 15, 20, 25, 6, 7, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #218 +PAIRING(10, 15, 20, 25, 6, 7, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #219 +PAIRING(10, 15, 20, 25, 6, 7, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #220 +PAIRING(10, 15, 20, 25, 6, 7, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #221 +PAIRING(10, 15, 20, 25, 6, 7, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #222 +PAIRING(10, 15, 20, 25, 6, 7, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #223 +PAIRING(10, 15, 20, 25, 6, 7, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #224 +PAIRING(10, 15, 20, 25, 6, 7, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #225 +PAIRING(10, 15, 20, 25, 6, 7, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #226 +PAIRING(10, 15, 20, 25, 6, 7, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #227 +PAIRING(10, 15, 20, 25, 6, 7, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #228 +PAIRING(10, 15, 20, 25, 6, 7, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #229 +PAIRING(10, 15, 20, 25, 6, 7, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #230 +PAIRING(10, 15, 20, 25, 6, 7, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #231 +PAIRING(10, 15, 20, 25, 6, 7, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #232 +PAIRING(10, 15, 20, 25, 6, 7, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #233 +PAIRING(10, 15, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #234 +PAIRING(10, 15, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #235 +PAIRING(10, 15, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #236 +PAIRING(10, 15, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #237 +PAIRING(10, 15, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #238 +PAIRING(10, 15, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #239 +PAIRING(10, 15, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #240 +PAIRING(10, 15, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #241 +PAIRING(10, 15, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #242 +PAIRING(10, 15, 20, 25, 6, 10, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #243 +PAIRING(10, 15, 20, 25, 6, 10, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #244 +PAIRING(10, 15, 20, 25, 6, 10, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #245 +PAIRING(10, 15, 20, 25, 6, 10, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #246 +PAIRING(10, 15, 20, 25, 6, 10, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #247 +PAIRING(10, 15, 20, 25, 6, 10, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #248 +PAIRING(10, 15, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #249 +PAIRING(10, 15, 20, 25, 6, 10, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #250 +PAIRING(10, 15, 20, 25, 6, 10, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #251 +PAIRING(10, 15, 20, 25, 6, 10, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #252 +PAIRING(10, 15, 20, 25, 6, 10, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #253 +PAIRING(10, 15, 20, 25, 6, 10, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #254 +PAIRING(10, 15, 20, 25, 6, 10, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #255 +PAIRING(10, 15, 20, 25, 6, 10, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #256 +PAIRING(10, 15, 20, 25, 6, 10, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #257 +PAIRING(10, 15, 20, 25, 6, 10, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #258 +PAIRING(10, 15, 20, 25, 6, 10, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #259 +PAIRING(10, 15, 20, 25, 6, 10, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #260 +PAIRING(10, 15, 20, 25, 6, 10, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #261 +PAIRING(10, 15, 20, 25, 6, 10, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #262 +PAIRING(10, 15, 20, 25, 6, 10, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #263 +PAIRING(10, 15, 20, 25, 6, 10, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #264 +PAIRING(10, 15, 20, 25, 6, 10, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #265 +PAIRING(10, 15, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #266 +PAIRING(10, 15, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #267 +PAIRING(10, 15, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #268 +PAIRING(10, 15, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #269 +PAIRING(10, 15, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #270 +PAIRING(10, 15, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #271 +PAIRING(10, 15, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #272 +PAIRING(10, 15, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #273 +PAIRING(10, 15, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #274 +PAIRING(10, 15, 20, 25, 6, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #275 +PAIRING(10, 15, 20, 25, 6, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 2) // #276 +PAIRING(10, 15, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #277 +PAIRING(10, 15, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 2) // #278 +PAIRING(10, 15, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #279 +PAIRING(10, 15, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #280 +PAIRING(10, 15, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #281 +PAIRING(10, 15, 20, 25, 6, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #282 +PAIRING(10, 15, 20, 25, 6, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 2) // #283 +PAIRING(10, 15, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #284 +PAIRING(10, 15, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 2) // #285 +PAIRING(10, 15, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #286 +PAIRING(10, 15, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #287 +PAIRING(10, 15, 20, 25, 6, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #288 +PAIRING(10, 15, 20, 25, 6, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #289 +PAIRING(10, 15, 20, 25, 6, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #290 +PAIRING(10, 15, 20, 25, 6, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #291 +PAIRING(10, 15, 20, 25, 6, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #292 +PAIRING(10, 15, 20, 25, 6, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #293 +PAIRING(10, 15, 20, 25, 6, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #294 +PAIRING(10, 15, 20, 25, 6, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #295 +PAIRING(10, 15, 20, 25, 6, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #296 +PAIRING(10, 15, 20, 25, 6, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #297 +PAIRING(10, 15, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #298 +PAIRING(10, 15, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #299 +PAIRING(10, 15, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #300 +PAIRING(10, 15, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #301 +PAIRING(10, 15, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #302 +PAIRING(10, 15, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #303 +PAIRING(10, 15, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #304 +PAIRING(10, 15, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #305 +PAIRING(10, 15, 20, 25, 6, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #306 +PAIRING(10, 15, 20, 25, 6, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #307 +PAIRING(10, 15, 20, 25, 6, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #308 +PAIRING(10, 15, 20, 25, 6, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #309 +PAIRING(10, 15, 20, 25, 6, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #310 +PAIRING(10, 15, 20, 25, 6, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #311 +PAIRING(10, 15, 20, 25, 6, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #312 +PAIRING(10, 15, 20, 25, 6, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #313 +PAIRING(10, 15, 20, 25, 6, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #314 +PAIRING(10, 15, 20, 25, 6, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #315 +PAIRING(10, 15, 20, 25, 6, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #316 +PAIRING(10, 15, 20, 25, 6, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #317 +PAIRING(10, 15, 20, 25, 6, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #318 +PAIRING(10, 15, 20, 25, 6, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #319 +PAIRING(10, 15, 20, 25, 6, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #320 +PAIRING(10, 15, 20, 25, 6, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #321 +PAIRING(10, 15, 20, 25, 6, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #322 +PAIRING(10, 15, 20, 25, 6, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #323 +PAIRING(10, 15, 20, 25, 6, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #324 +PAIRING(10, 15, 20, 25, 6, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #325 +PAIRING(10, 15, 20, 25, 6, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #326 +PAIRING(10, 15, 20, 25, 6, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #327 +PAIRING(10, 15, 20, 25, 6, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #328 +PAIRING(10, 15, 20, 25, 6, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #329 +PAIRING(10, 15, 20, 25, 6, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #330 +PAIRING(10, 15, 20, 25, 6, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #331 +PAIRING(10, 15, 20, 25, 6, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #332 +PAIRING(10, 15, 20, 25, 6, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #333 +PAIRING(10, 15, 20, 25, 6, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #334 +PAIRING(10, 15, 20, 25, 6, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #335 +PAIRING(10, 15, 20, 25, 6, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #336 +PAIRING(10, 15, 20, 25, 6, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #337 +PAIRING(10, 15, 20, 25, 6, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #338 +PAIRING(10, 15, 20, 25, 6, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #339 +PAIRING(10, 15, 20, 25, 6, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #340 +PAIRING(10, 15, 20, 25, 6, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #341 +PAIRING(10, 15, 20, 25, 6, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #342 +PAIRING(10, 15, 20, 25, 6, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #343 +PAIRING(10, 15, 20, 25, 6, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #344 +PAIRING(10, 15, 20, 25, 6, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #345 +PAIRING(10, 15, 20, 25, 6, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #346 +PAIRING(10, 15, 20, 25, 6, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #347 +PAIRING(10, 15, 20, 25, 6, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #348 +PAIRING(10, 15, 20, 25, 6, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #349 +PAIRING(10, 15, 20, 25, 6, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #350 +PAIRING(10, 15, 20, 25, 6, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #351 +PAIRING(10, 15, 20, 25, 6, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #352 +PAIRING(10, 15, 20, 25, 6, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #353 +PAIRING(10, 15, 20, 25, 6, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #354 +PAIRING(10, 15, 20, 25, 6, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #355 +PAIRING(10, 15, 20, 25, 6, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #356 +PAIRING(10, 15, 20, 25, 6, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #357 +PAIRING(10, 15, 20, 25, 6, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #358 +PAIRING(10, 15, 20, 25, 6, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #359 +PAIRING(10, 15, 20, 25, 6, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #360 +PAIRING(10, 15, 20, 25, 6, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #361 +PAIRING(10, 15, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #362 +PAIRING(10, 15, 20, 25, 10, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #363 +PAIRING(10, 15, 20, 25, 10, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #364 +PAIRING(10, 15, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #365 +PAIRING(10, 15, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 1) // #366 +PAIRING(10, 15, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #367 +PAIRING(10, 15, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #368 +PAIRING(10, 15, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #369 +PAIRING(10, 15, 20, 25, 10, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #370 +PAIRING(10, 15, 20, 25, 10, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #371 +PAIRING(10, 15, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #372 +PAIRING(10, 15, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 1) // #373 +PAIRING(10, 15, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #374 +PAIRING(10, 15, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #375 +PAIRING(10, 15, 20, 25, 10, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #376 +PAIRING(10, 15, 20, 25, 10, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #377 +PAIRING(10, 15, 20, 25, 10, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #378 +PAIRING(10, 15, 20, 25, 10, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #379 +PAIRING(10, 15, 20, 25, 10, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #380 +PAIRING(10, 15, 20, 25, 10, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #381 +PAIRING(10, 15, 20, 25, 10, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #382 +PAIRING(10, 15, 20, 25, 10, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #383 +PAIRING(10, 15, 20, 25, 10, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #384 +PAIRING(10, 15, 20, 25, 10, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #385 +PAIRING(10, 15, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #386 +PAIRING(10, 15, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #387 +PAIRING(10, 15, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #388 +PAIRING(10, 15, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #389 +PAIRING(10, 15, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #390 +PAIRING(10, 15, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #391 +PAIRING(10, 15, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #392 +PAIRING(10, 15, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #393 +PAIRING(10, 15, 20, 25, 10, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #394 +PAIRING(10, 15, 20, 25, 10, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #395 +PAIRING(10, 15, 20, 25, 10, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #396 +PAIRING(10, 15, 20, 25, 10, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #397 +PAIRING(10, 15, 20, 25, 10, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #398 +PAIRING(10, 15, 20, 25, 10, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #399 +PAIRING(10, 15, 20, 25, 10, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #400 +PAIRING(10, 15, 20, 25, 10, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #401 +PAIRING(10, 15, 20, 25, 10, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #402 +PAIRING(10, 15, 20, 25, 10, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #403 +PAIRING(10, 15, 20, 25, 10, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #404 +PAIRING(10, 15, 20, 25, 10, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #405 +PAIRING(10, 15, 20, 25, 10, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #406 +PAIRING(10, 15, 20, 25, 10, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #407 +PAIRING(10, 15, 20, 25, 10, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #408 +PAIRING(10, 15, 20, 25, 10, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #409 +PAIRING(10, 15, 20, 25, 10, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #410 +PAIRING(10, 15, 20, 25, 10, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #411 +PAIRING(10, 15, 20, 25, 10, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #412 +PAIRING(10, 15, 20, 25, 10, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #413 +PAIRING(10, 15, 20, 25, 10, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #414 +PAIRING(10, 15, 20, 25, 10, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #415 +PAIRING(10, 15, 20, 25, 10, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #416 +PAIRING(10, 15, 20, 25, 10, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #417 +PAIRING(10, 15, 20, 25, 10, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #418 +PAIRING(10, 15, 20, 25, 10, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #419 +PAIRING(10, 15, 20, 25, 10, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #420 +PAIRING(10, 15, 20, 25, 10, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #421 +PAIRING(10, 15, 20, 25, 10, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #422 +PAIRING(10, 15, 20, 25, 10, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #423 +PAIRING(10, 15, 20, 25, 10, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #424 +PAIRING(10, 15, 20, 25, 10, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #425 +PAIRING(10, 15, 20, 25, 10, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #426 +PAIRING(10, 15, 20, 25, 10, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #427 +PAIRING(10, 15, 20, 25, 10, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #428 +PAIRING(10, 15, 20, 25, 10, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #429 +PAIRING(10, 15, 20, 25, 10, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #430 +PAIRING(10, 15, 20, 25, 10, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #431 +PAIRING(10, 15, 20, 25, 10, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #432 +PAIRING(10, 15, 20, 25, 10, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #433 +PAIRING(10, 15, 20, 25, 10, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #434 +PAIRING(10, 15, 20, 25, 10, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #435 +PAIRING(10, 15, 20, 25, 10, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #436 +PAIRING(10, 15, 20, 25, 10, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #437 +PAIRING(10, 15, 20, 25, 10, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #438 +PAIRING(10, 15, 20, 25, 10, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #439 +PAIRING(10, 15, 20, 25, 10, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #440 +PAIRING(10, 15, 20, 25, 10, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #441 +PAIRING(10, 15, 20, 25, 10, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #442 +PAIRING(10, 15, 20, 25, 10, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #443 +PAIRING(10, 15, 20, 25, 10, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #444 +PAIRING(10, 15, 20, 25, 10, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #445 +PAIRING(10, 15, 20, 25, 10, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #446 +PAIRING(10, 15, 20, 25, 10, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #447 +PAIRING(10, 15, 20, 25, 10, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #448 +PAIRING(10, 15, 20, 25, 10, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #449 +PAIRING(10, 15, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #450 +PAIRING(10, 15, 20, 25, 11, 12, 12, 15, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #451 +PAIRING(10, 15, 20, 25, 11, 12, 12, 16, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 1) // #452 +PAIRING(10, 15, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #453 +PAIRING(10, 15, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 15, 20, 21, 0, 0, 2, 1) // #454 +PAIRING(10, 15, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #455 +PAIRING(10, 15, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #456 +PAIRING(10, 15, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #457 +PAIRING(10, 15, 20, 25, 11, 12, 13, 15, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #458 +PAIRING(10, 15, 20, 25, 11, 12, 13, 16, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 1) // #459 +PAIRING(10, 15, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #460 +PAIRING(10, 15, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 15, 20, 21, 0, 0, 2, 1) // #461 +PAIRING(10, 15, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #462 +PAIRING(10, 15, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #463 +PAIRING(10, 15, 20, 25, 11, 12, 15, 16, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #464 +PAIRING(10, 15, 20, 25, 11, 12, 15, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #465 +PAIRING(10, 15, 20, 25, 11, 12, 15, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #466 +PAIRING(10, 15, 20, 25, 11, 12, 15, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #467 +PAIRING(10, 15, 20, 25, 11, 12, 15, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #468 +PAIRING(10, 15, 20, 25, 11, 12, 16, 17, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #469 +PAIRING(10, 15, 20, 25, 11, 12, 16, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #470 +PAIRING(10, 15, 20, 25, 11, 12, 16, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #471 +PAIRING(10, 15, 20, 25, 11, 12, 16, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #472 +PAIRING(10, 15, 20, 25, 11, 12, 16, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #473 +PAIRING(10, 15, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #474 +PAIRING(10, 15, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #475 +PAIRING(10, 15, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #476 +PAIRING(10, 15, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #477 +PAIRING(10, 15, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #478 +PAIRING(10, 15, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #479 +PAIRING(10, 15, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #480 +PAIRING(10, 15, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #481 +PAIRING(10, 15, 20, 25, 11, 15, 15, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #482 +PAIRING(10, 15, 20, 25, 11, 15, 15, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #483 +PAIRING(10, 15, 20, 25, 11, 15, 15, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #484 +PAIRING(10, 15, 20, 25, 11, 15, 15, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #485 +PAIRING(10, 15, 20, 25, 11, 15, 15, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #486 +PAIRING(10, 15, 20, 25, 11, 15, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #487 +PAIRING(10, 15, 20, 25, 11, 15, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #488 +PAIRING(10, 15, 20, 25, 11, 15, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #489 +PAIRING(10, 15, 20, 25, 11, 15, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #490 +PAIRING(10, 15, 20, 25, 11, 15, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #491 +PAIRING(10, 15, 20, 25, 11, 15, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #492 +PAIRING(10, 15, 20, 25, 11, 15, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #493 +PAIRING(10, 15, 20, 25, 11, 15, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #494 +PAIRING(10, 15, 20, 25, 11, 15, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #495 +PAIRING(10, 15, 20, 25, 11, 15, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #496 +PAIRING(10, 15, 20, 25, 11, 15, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #497 +PAIRING(10, 15, 20, 25, 11, 15, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #498 +PAIRING(10, 15, 20, 25, 11, 15, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #499 +PAIRING(10, 15, 20, 25, 11, 16, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #500 +PAIRING(10, 15, 20, 25, 11, 16, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #501 +PAIRING(10, 15, 20, 25, 11, 16, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #502 +PAIRING(10, 15, 20, 25, 11, 16, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #503 +PAIRING(10, 15, 20, 25, 11, 16, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #504 +PAIRING(10, 15, 20, 25, 11, 16, 17, 18, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #505 +PAIRING(10, 15, 20, 25, 11, 16, 17, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #506 +PAIRING(10, 15, 20, 25, 11, 16, 17, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #507 +PAIRING(10, 15, 20, 25, 11, 16, 17, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #508 +PAIRING(10, 15, 20, 25, 11, 16, 17, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #509 +PAIRING(10, 15, 20, 25, 11, 16, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #510 +PAIRING(10, 15, 20, 25, 11, 16, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #511 +PAIRING(10, 15, 20, 25, 11, 16, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #512 +PAIRING(10, 15, 20, 25, 11, 16, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 1) // #513 +PAIRING(10, 15, 20, 25, 11, 16, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #514 +PAIRING(10, 15, 20, 25, 11, 16, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 2) // #515 +PAIRING(10, 15, 20, 25, 11, 16, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #516 +PAIRING(10, 15, 20, 25, 11, 16, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #517 +PAIRING(10, 15, 20, 25, 11, 20, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #518 +PAIRING(10, 15, 20, 25, 11, 20, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #519 +PAIRING(10, 15, 20, 25, 11, 20, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #520 +PAIRING(10, 15, 20, 25, 11, 20, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #521 +PAIRING(10, 15, 20, 25, 11, 20, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #522 +PAIRING(10, 15, 20, 25, 11, 20, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #523 +PAIRING(10, 15, 20, 25, 11, 20, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #524 +PAIRING(10, 15, 20, 25, 11, 20, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #525 +PAIRING(10, 15, 20, 25, 11, 21, 21, 22, 1, 2, 11, 15, 0, 0, 20, 21, 21, 22, 2, 1) // #526 +PAIRING(10, 15, 20, 25, 11, 21, 21, 25, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 1) // #527 +PAIRING(10, 15, 20, 25, 11, 21, 21, 26, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 2) // #528 +PAIRING(10, 15, 20, 25, 11, 21, 22, 23, 1, 2, 11, 15, 0, 0, 20, 21, 22, 23, 2, 1) // #529 +PAIRING(10, 15, 20, 25, 11, 21, 22, 25, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 1) // #530 +PAIRING(10, 15, 20, 25, 11, 21, 22, 26, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 2) // #531 +PAIRING(10, 15, 20, 25, 11, 21, 25, 26, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #532 +PAIRING(10, 15, 20, 25, 11, 21, 26, 27, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #533 +PAIRING(10, 15, 20, 25, 11, 25, 25, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #534 +PAIRING(10, 15, 20, 25, 11, 25, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #535 +PAIRING(10, 15, 20, 25, 11, 26, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #536 +PAIRING(10, 15, 20, 25, 11, 26, 27, 28, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #537 +PAIRING(10, 15, 20, 25, 15, 16, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #538 +PAIRING(10, 15, 20, 25, 15, 16, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #539 +PAIRING(10, 15, 20, 25, 15, 16, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #540 +PAIRING(10, 15, 20, 25, 15, 16, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #541 +PAIRING(10, 15, 20, 25, 15, 16, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #542 +PAIRING(10, 15, 20, 25, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #543 +PAIRING(10, 15, 20, 25, 15, 16, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #544 +PAIRING(10, 15, 20, 25, 15, 16, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #545 +PAIRING(10, 15, 20, 25, 15, 16, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #546 +PAIRING(10, 15, 20, 25, 15, 16, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #547 +PAIRING(10, 15, 20, 25, 15, 16, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #548 +PAIRING(10, 15, 20, 25, 15, 16, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #549 +PAIRING(10, 15, 20, 25, 15, 16, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #550 +PAIRING(10, 15, 20, 25, 15, 16, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #551 +PAIRING(10, 15, 20, 25, 15, 16, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #552 +PAIRING(10, 15, 20, 25, 15, 16, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #553 +PAIRING(10, 15, 20, 25, 15, 16, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #554 +PAIRING(10, 15, 20, 25, 15, 16, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #555 +PAIRING(10, 15, 20, 25, 15, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #556 +PAIRING(10, 15, 20, 25, 15, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #557 +PAIRING(10, 15, 20, 25, 15, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #558 +PAIRING(10, 15, 20, 25, 15, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #559 +PAIRING(10, 15, 20, 25, 15, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #560 +PAIRING(10, 15, 20, 25, 15, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #561 +PAIRING(10, 15, 20, 25, 15, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #562 +PAIRING(10, 15, 20, 25, 15, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #563 +PAIRING(10, 15, 20, 25, 15, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #564 +PAIRING(10, 15, 20, 25, 15, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #565 +PAIRING(10, 15, 20, 25, 15, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #566 +PAIRING(10, 15, 20, 25, 15, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #567 +PAIRING(10, 15, 20, 25, 15, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #568 +PAIRING(10, 15, 20, 25, 15, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #569 +PAIRING(10, 15, 20, 25, 15, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #570 +PAIRING(10, 15, 20, 25, 15, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #571 +PAIRING(10, 15, 20, 25, 15, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #572 +PAIRING(10, 15, 20, 25, 15, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #573 +PAIRING(10, 15, 20, 25, 15, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #574 +PAIRING(10, 15, 20, 25, 15, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #575 +PAIRING(10, 15, 20, 25, 16, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #576 +PAIRING(10, 15, 20, 25, 16, 17, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #577 +PAIRING(10, 15, 20, 25, 16, 17, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #578 +PAIRING(10, 15, 20, 25, 16, 17, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #579 +PAIRING(10, 15, 20, 25, 16, 17, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #580 +PAIRING(10, 15, 20, 25, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #581 +PAIRING(10, 15, 20, 25, 16, 17, 18, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #582 +PAIRING(10, 15, 20, 25, 16, 17, 18, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #583 +PAIRING(10, 15, 20, 25, 16, 17, 18, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #584 +PAIRING(10, 15, 20, 25, 16, 17, 18, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #585 +PAIRING(10, 15, 20, 25, 16, 17, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #586 +PAIRING(10, 15, 20, 25, 16, 17, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #587 +PAIRING(10, 15, 20, 25, 16, 17, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #588 +PAIRING(10, 15, 20, 25, 16, 17, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #589 +PAIRING(10, 15, 20, 25, 16, 17, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #590 +PAIRING(10, 15, 20, 25, 16, 17, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #591 +PAIRING(10, 15, 20, 25, 16, 17, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #592 +PAIRING(10, 15, 20, 25, 16, 17, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #593 +PAIRING(10, 15, 20, 25, 16, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #594 +PAIRING(10, 15, 20, 25, 16, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #595 +PAIRING(10, 15, 20, 25, 16, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #596 +PAIRING(10, 15, 20, 25, 16, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #597 +PAIRING(10, 15, 20, 25, 16, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #598 +PAIRING(10, 15, 20, 25, 16, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #599 +PAIRING(10, 15, 20, 25, 16, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #600 +PAIRING(10, 15, 20, 25, 16, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #601 +PAIRING(10, 15, 20, 25, 16, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #602 +PAIRING(10, 15, 20, 25, 16, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #603 +PAIRING(10, 15, 20, 25, 16, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #604 +PAIRING(10, 15, 20, 25, 16, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #605 +PAIRING(10, 15, 20, 25, 16, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #606 +PAIRING(10, 15, 20, 25, 16, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #607 +PAIRING(10, 15, 20, 25, 16, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #608 +PAIRING(10, 15, 20, 25, 16, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #609 +PAIRING(10, 15, 20, 25, 16, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #610 +PAIRING(10, 15, 20, 25, 16, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #611 +PAIRING(10, 15, 20, 25, 16, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #612 +PAIRING(10, 15, 20, 25, 16, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #613 +PAIRING(10, 15, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #614 +PAIRING(10, 15, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #615 +PAIRING(10, 15, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #616 +PAIRING(10, 15, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #617 +PAIRING(10, 15, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #618 +PAIRING(10, 15, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #619 +PAIRING(10, 15, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #620 +PAIRING(10, 15, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #621 +PAIRING(10, 15, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #622 +PAIRING(10, 15, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #623 +PAIRING(10, 15, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #624 +PAIRING(10, 15, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #625 +PAIRING(10, 15, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #626 +PAIRING(10, 15, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #627 +PAIRING(10, 15, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #628 +PAIRING(10, 15, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #629 +PAIRING(10, 15, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #630 +PAIRING(10, 15, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #631 +PAIRING(10, 15, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #632 +PAIRING(10, 15, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #633 +PAIRING(10, 15, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #634 +PAIRING(10, 15, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #635 +PAIRING(10, 15, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #636 +PAIRING(10, 15, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #637 +PAIRING(10, 15, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #638 +PAIRING(10, 15, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #639 +PAIRING(10, 15, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #640 +PAIRING(10, 15, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #641 diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h b/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h new file mode 100644 index 0000000000..1df88db8bd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h @@ -0,0 +1,100 @@ +// Copyright (c) 2011, 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. + +// Utility class for creating a temporary directory for unit tests +// that is deleted in the destructor. +#ifndef GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR +#define GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR + +#include +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" + +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#include "common/android/testing/mkdtemp.h" +#endif + +namespace google_breakpad { + +class AutoTempDir { + public: + AutoTempDir() { + char temp_dir[] = TEMPDIR "/breakpad.XXXXXX"; + EXPECT_TRUE(mkdtemp(temp_dir) != NULL); + path_.assign(temp_dir); + } + + ~AutoTempDir() { + DeleteRecursively(path_); + } + + const string& path() const { + return path_; + } + + private: + void DeleteRecursively(const string& path) { + // First remove any files in the dir + DIR* dir = opendir(path.c_str()); + if (!dir) + return; + + dirent* entry; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + string entry_path = path + "/" + entry->d_name; + struct stat stats; + EXPECT_TRUE(lstat(entry_path.c_str(), &stats) == 0); + if (S_ISDIR(stats.st_mode)) + DeleteRecursively(entry_path); + else + EXPECT_TRUE(unlink(entry_path.c_str()) == 0); + } + EXPECT_TRUE(closedir(dir) == 0); + EXPECT_TRUE(rmdir(path.c_str()) == 0); + } + + // prevent copy construction and assignment + AutoTempDir(const AutoTempDir&); + AutoTempDir& operator=(const AutoTempDir&); + + string path_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc new file mode 100644 index 0000000000..1c041777cb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2011, 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. + +// file_utils.cc: Implement utility functions for file manipulation. +// See file_utils.h for details. + +#include +#include +#include +#include +#include + +#include "common/linux/eintr_wrapper.h" +#include "common/tests/file_utils.h" + +namespace google_breakpad { + +bool CopyFile(const char* from_path, const char* to_path) { + int infile = HANDLE_EINTR(open(from_path, O_RDONLY)); + if (infile < 0) { + perror("open"); + return false; + } + + int outfile = HANDLE_EINTR(creat(to_path, 0666)); + if (outfile < 0) { + perror("creat"); + if (IGNORE_EINTR(close(infile)) < 0) { + perror("close"); + } + return false; + } + + char buffer[1024]; + bool result = true; + + while (result) { + ssize_t bytes_read = HANDLE_EINTR(read(infile, buffer, sizeof(buffer))); + if (bytes_read < 0) { + perror("read"); + result = false; + break; + } + if (bytes_read == 0) + break; + ssize_t bytes_written_per_read = 0; + do { + ssize_t bytes_written_partial = HANDLE_EINTR(write( + outfile, + &buffer[bytes_written_per_read], + bytes_read - bytes_written_per_read)); + if (bytes_written_partial < 0) { + perror("write"); + result = false; + break; + } + bytes_written_per_read += bytes_written_partial; + } while (bytes_written_per_read < bytes_read); + } + + if (IGNORE_EINTR(close(infile)) == -1) { + perror("close"); + result = false; + } + if (IGNORE_EINTR(close(outfile)) == -1) { + perror("close"); + result = false; + } + + return result; +} + +bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size) { + int fd = HANDLE_EINTR(open(path, O_RDONLY)); + if (fd == -1) { + perror("open"); + return false; + } + + bool ok = true; + if (buffer && buffer_size && *buffer_size > 0) { + memset(buffer, 0, sizeof(*buffer_size)); + *buffer_size = HANDLE_EINTR(read(fd, buffer, *buffer_size)); + if (*buffer_size == -1) { + perror("read"); + ok = false; + } + } + if (IGNORE_EINTR(close(fd)) == -1) { + perror("close"); + ok = false; + } + return ok; +} + +bool WriteFile(const char* path, const void* buffer, size_t buffer_size) { + int fd = HANDLE_EINTR(open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU)); + if (fd == -1) { + perror("open"); + return false; + } + + bool ok = true; + if (buffer) { + size_t bytes_written_total = 0; + ssize_t bytes_written_partial = 0; + const char* data = reinterpret_cast(buffer); + while (bytes_written_total < buffer_size) { + bytes_written_partial = + HANDLE_EINTR(write(fd, data + bytes_written_total, + buffer_size - bytes_written_total)); + if (bytes_written_partial < 0) { + perror("write"); + ok = false; + break; + } + bytes_written_total += bytes_written_partial; + } + } + if (IGNORE_EINTR(close(fd)) == -1) { + perror("close"); + ok = false; + } + return ok; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h new file mode 100644 index 0000000000..c98a9bfa8b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h @@ -0,0 +1,52 @@ +// Copyright (c) 2011, 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. + +// file_utils.h: Define utility functions for file manipulation, which +// are used for testing. + +#ifndef COMMON_TESTS_FILE_UTILS_H_ +#define COMMON_TESTS_FILE_UTILS_H_ + +namespace google_breakpad { + +// Copies a file from |from_path| to |to_path|. Returns true on success. +bool CopyFile(const char* from_path, const char* to_path); + +// Reads the content of a file at |path| into |buffer|. |buffer_size| specifies +// the size of |buffer| in bytes and returns the number of bytes read from the +// file on success. Returns true on success. +bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size); + +// Writes |buffer_size| bytes of the content in |buffer| to a file at |path|. +// Returns true on success. +bool WriteFile(const char* path, const void* buffer, size_t buffer_size); + +} // namespace google_breakpad + +#endif // COMMON_TESTS_FILE_UTILS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/unordered.h b/toolkit/crashreporter/google-breakpad/src/common/unordered.h new file mode 100644 index 0000000000..c9cbd58546 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/unordered.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 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 this file to use unordered_map and unordered_set. If tr1 +// or C++11 is not available, you can switch to using hash_set and +// hash_map by defining BP_USE_HASH_SET. + +#ifndef COMMON_UNORDERED_H_ +#define COMMON_UNORDERED_H_ + +#if defined(BP_USE_HASH_SET) +#include +#include + +// For hash. +#include "util/hash/hash.h" + +template > +struct unordered_map : public __gnu_cxx::hash_map {}; +template > +struct unordered_set : public __gnu_cxx::hash_set {}; + +#elif defined(_LIBCPP_VERSION) // c++11 +#include +#include +using std::unordered_map; +using std::unordered_set; + +#else // Fallback to tr1::unordered +#include +#include +using std::tr1::unordered_map; +using std::tr1::unordered_set; +#endif + +#endif // COMMON_UNORDERED_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h b/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h new file mode 100644 index 0000000000..13c1da59cc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h @@ -0,0 +1,65 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2012, 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. + +// Original author: Ivan Penkov + +// using_std_string.h: Allows building this code in environments where +// global string (::string) exists. +// +// The problem: +// ------------- +// Let's say you want to build this code in an environment where a global +// string type is defined (i.e. ::string). Now, let's suppose that ::string +// is different that std::string and you'd like to have the option to easily +// choose between the two string types. Ideally you'd like to control which +// string type is chosen by simply #defining an identifier. +// +// The solution: +// ------------- +// #define HAS_GLOBAL_STRING somewhere in a global header file and then +// globally replace std::string with string. Then include this header +// file everywhere where string is used. If you want to revert back to +// using std::string, simply remove the #define (HAS_GLOBAL_STRING). + +#ifndef THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ +#define THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ + +#ifdef HAS_GLOBAL_STRING + typedef ::string google_breakpad_string; +#else + using std::string; + typedef std::string google_breakpad_string; +#endif + +// Inicates that type google_breakpad_string is defined +#define HAS_GOOGLE_BREAKPAD_STRING + +#endif // THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp b/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp new file mode 100644 index 0000000000..5f7594b161 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp @@ -0,0 +1,112 @@ +# Copyright 2013 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. + +{ + 'includes': [ + '../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'dia_sdk', + 'type': 'none', + 'all_dependent_settings': { + 'include_dirs': [ + '<(DEPTH)', + '$(VSInstallDir)/DIA SDK/include', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalDependencies': [ + 'diaguids.lib', + 'imagehlp.lib', + ], + }, + }, + 'configurations': { + 'x86_Base': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalLibraryDirectories': + ['$(VSInstallDir)/DIA SDK/lib'], + }, + }, + }, + 'x64_Base': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalLibraryDirectories': + ['$(VSInstallDir)/DIA SDK/lib/amd64'], + }, + }, + }, + }, + }, + }, + { + 'target_name': 'common_windows_lib', + 'type': 'static_library', + 'sources': [ + 'dia_util.cc', + 'dia_util.h', + 'guid_string.cc', + 'guid_string.h', + 'http_upload.cc', + 'http_upload.h', + 'module_info.h', + 'omap.cc', + 'omap.h', + 'omap_internal.h', + 'pdb_source_line_writer.cc', + 'pdb_source_line_writer.h', + 'pe_source_line_writer.cc', + 'pe_source_line_writer.h', + 'pe_util.h', + 'pe_util.cc', + 'string_utils.cc', + 'string_utils-inl.h', + 'symbol_collector_client.cc', + 'symbol_collector_client.h', + ], + 'dependencies': [ + 'dia_sdk', + ], + }, + { + 'target_name': 'common_windows_unittests', + 'type': 'executable', + 'sources': [ + 'omap_unittest.cc', + ], + 'dependencies': [ + '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', + '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', + 'common_windows_lib', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc new file mode 100644 index 0000000000..ed8cb5b658 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc @@ -0,0 +1,92 @@ +// Copyright 2013 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 "common/windows/dia_util.h" + +#include + +namespace google_breakpad { + +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream) { + CComPtr enum_debug_streams; + if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) { + fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n"); + return false; + } + + CComPtr temp_debug_stream; + ULONG fetched = 0; + while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) && + fetched == 1) { + CComBSTR stream_name; + if (FAILED(temp_debug_stream->get_name(&stream_name))) { + fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n"); + return false; + } + + // Found the stream? + if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) { + *debug_stream = temp_debug_stream.Detach(); + return true; + } + + temp_debug_stream.Release(); + } + + // No table was found. + return false; +} + +bool FindTable(REFIID iid, IDiaSession* session, void** table) { + // Get the table enumerator. + CComPtr enum_tables; + if (FAILED(session->getEnumTables(&enum_tables))) { + fprintf(stderr, "IDiaSession::getEnumTables failed\n"); + return false; + } + + // Iterate through the tables. + CComPtr temp_table; + ULONG fetched = 0; + while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) && + fetched == 1) { + void* temp = NULL; + if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) { + *table = temp; + return true; + } + temp_table.Release(); + } + + // The table was not found. + return false; +} + +} // namespace google_breakpad \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h new file mode 100644 index 0000000000..b9e0df2d56 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h @@ -0,0 +1,64 @@ +// Copyright 2013 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. + +// Utilities for loading debug streams and tables from a PDB file. + +#ifndef COMMON_WINDOWS_DIA_UTIL_H_ +#define COMMON_WINDOWS_DIA_UTIL_H_ + +#include +#include + +namespace google_breakpad { + +// Find the debug stream of the given |name| in the given |session|. Returns +// true on success, false on error of if the stream does not exist. On success +// the stream will be returned via |debug_stream|. +bool FindDebugStream(const wchar_t* name, + IDiaSession* session, + IDiaEnumDebugStreamData** debug_stream); + +// Finds the first table implementing the COM interface with ID |iid| in the +// given |session|. Returns true on success, false on error or if no such +// table is found. On success the table will be returned via |table|. +bool FindTable(REFIID iid, IDiaSession* session, void** table); + +// A templated version of FindTable. Finds the first table implementing type +// |InterfaceType| in the given |session|. Returns true on success, false on +// error or if no such table is found. On success the table will be returned via +// |table|. +template +bool FindTable(IDiaSession* session, InterfaceType** table) { + return FindTable(__uuidof(InterfaceType), + session, + reinterpret_cast(table)); +} + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_DIA_UTIL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc new file mode 100644 index 0000000000..b7f877e66e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc @@ -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. + +// guid_string.cc: Convert GUIDs to strings. +// +// See guid_string.h for documentation. + +#include + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/guid_string.h" + +namespace google_breakpad { + +// static +wstring GUIDString::GUIDToWString(GUID *guid) { + wchar_t guid_string[37]; + swprintf( + guid_string, sizeof(guid_string) / sizeof(guid_string[0]), + L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + + // remove when VC++7.1 is no longer supported + guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; + + return wstring(guid_string); +} + +// static +wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) { + wchar_t guid_string[33]; + swprintf( + guid_string, sizeof(guid_string) / sizeof(guid_string[0]), + L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], + guid->Data4[3], guid->Data4[4], guid->Data4[5], + guid->Data4[6], guid->Data4[7]); + + // remove when VC++7.1 is no longer supported + guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; + + return wstring(guid_string); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h new file mode 100644 index 0000000000..48a5c1d370 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.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 + +#include + +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_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc new file mode 100644 index 0000000000..5df17e1a88 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc @@ -0,0 +1,493 @@ +// 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 + +// Disable exception handler warnings. +#pragma warning(disable:4530) + +#include +#include + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/http_upload.h" + +namespace { + using std::string; + using std::wstring; + using std::map; + using std::vector; + using std::ifstream; + using std::ios; + + const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; + + // Helper class which closes an internet handle when it goes away + class AutoInternetHandle { + public: + explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {} + ~AutoInternetHandle() { + if (handle_) { + InternetCloseHandle(handle_); + } + } + + HINTERNET get() { return handle_; } + + private: + HINTERNET handle_; + }; + + wstring UTF8ToWide(const string &utf8) { + if (utf8.length() == 0) { + return wstring(); + } + + // compute the length of the buffer we'll need + int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); + + if (charcount == 0) { + return wstring(); + } + + // convert + wchar_t* buf = new wchar_t[charcount]; + MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount); + wstring result(buf); + delete[] buf; + return result; + } + + string WideToMBCP(const wstring &wide, unsigned int cp) { + if (wide.length() == 0) { + return string(); + } + + // compute the length of the buffer we'll need + int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1, + NULL, 0, NULL, NULL); + if (charcount == 0) { + return string(); + } + + // convert + char *buf = new char[charcount]; + WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount, + NULL, NULL); + + string result(buf); + delete[] buf; + return result; + } + + bool GetFileContents(const wstring &filename, vector *contents) { + bool rv = false; + // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a + // wchar_t* filename, so use _wfopen directly in that case. For VC8 and + // later, _wfopen has been deprecated in favor of _wfopen_s, which does + // not exist in earlier versions, so let the ifstream open the file itself. + // GCC doesn't support wide file name and opening on FILE* requires ugly + // hacks, so fallback to multi byte file. +#ifdef _MSC_VER + ifstream file; + file.open(filename.c_str(), ios::binary); +#else // GCC + ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary); +#endif // _MSC_VER >= 1400 + if (file.is_open()) { + file.seekg(0, ios::end); + std::streamoff length = file.tellg(); + // Check for loss of data when converting lenght from std::streamoff into + // std::vector::size_type + std::vector::size_type vector_size = + static_cast::size_type>(length); + if (static_cast(vector_size) == length) { + contents->resize(vector_size); + if (length != 0) { + file.seekg(0, ios::beg); + file.read(&((*contents)[0]), length); + } + rv = true; + } + file.close(); + } + return rv; + } + + // Converts a UTF16 string to UTF8. + string WideToUTF8(const wstring &wide) { + return WideToMBCP(wide, CP_UTF8); + } + + bool ReadResponse(HINTERNET request, wstring *response) { + bool has_content_length_header = false; + wchar_t content_length[32]; + DWORD content_length_size = sizeof(content_length); + DWORD claimed_size = 0; + string response_body; + + if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH, + static_cast(&content_length), + &content_length_size, 0)) { + has_content_length_header = true; + claimed_size = wcstol(content_length, NULL, 10); + response_body.reserve(claimed_size); + } + + DWORD bytes_available; + DWORD total_read = 0; + BOOL return_code; + + while (((return_code = InternetQueryDataAvailable(request, &bytes_available, + 0, 0)) != 0) && bytes_available > 0) { + vector response_buffer(bytes_available); + DWORD size_read; + + return_code = InternetReadFile(request, + &response_buffer[0], + bytes_available, &size_read); + + if (return_code && size_read > 0) { + total_read += size_read; + response_body.append(&response_buffer[0], size_read); + } + else { + break; + } + } + + bool succeeded = return_code && (!has_content_length_header || + (total_read == claimed_size)); + if (succeeded && response) { + *response = UTF8ToWide(response_body); + } + + return succeeded; + } + + bool SendRequestInner( + const wstring& url, + const wstring& http_method, + const wstring& content_type_header, + const string& request_body, + int* timeout_ms, + wstring* response_body, + int* response_code) { + if (response_code) { + *response_code = 0; + } + + // Break up the URL and make sure we can handle it + wchar_t scheme[16], host[256], path[1024]; + URL_COMPONENTS components; + memset(&components, 0, sizeof(components)); + components.dwStructSize = sizeof(components); + components.lpszScheme = scheme; + components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]); + components.lpszHostName = host; + components.dwHostNameLength = sizeof(host) / sizeof(host[0]); + components.lpszUrlPath = path; + components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); + if (!InternetCrackUrl(url.c_str(), static_cast(url.size()), + 0, &components)) { + DWORD err = GetLastError(); + wprintf(L"%d\n", err); + return false; + } + bool secure = false; + if (wcscmp(scheme, L"https") == 0) { + secure = true; + } + else if (wcscmp(scheme, L"http") != 0) { + return false; + } + + AutoInternetHandle internet(InternetOpen(kUserAgent, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, // proxy name + NULL, // proxy bypass + 0)); // flags + if (!internet.get()) { + return false; + } + + AutoInternetHandle connection(InternetConnect(internet.get(), + host, + components.nPort, + NULL, // user name + NULL, // password + INTERNET_SERVICE_HTTP, + 0, // flags + NULL)); // context + if (!connection.get()) { + return false; + } + + DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0; + http_open_flags |= INTERNET_FLAG_NO_COOKIES; + AutoInternetHandle request(HttpOpenRequest(connection.get(), + http_method.c_str(), + path, + NULL, // version + NULL, // referer + NULL, // agent type + http_open_flags, + NULL)); // context + if (!request.get()) { + return false; + } + + if (!content_type_header.empty()) { + HttpAddRequestHeaders(request.get(), + content_type_header.c_str(), + static_cast(-1), + HTTP_ADDREQ_FLAG_ADD); + } + + if (timeout_ms) { + if (!InternetSetOption(request.get(), + INTERNET_OPTION_SEND_TIMEOUT, + timeout_ms, + sizeof(*timeout_ms))) { + fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); + } + + if (!InternetSetOption(request.get(), + INTERNET_OPTION_RECEIVE_TIMEOUT, + timeout_ms, + sizeof(*timeout_ms))) { + fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); + } + } + + if (!HttpSendRequest(request.get(), NULL, 0, + const_cast(request_body.data()), + static_cast(request_body.size()))) { + return false; + } + + // The server indicates a successful upload with HTTP status 200. + wchar_t http_status[4]; + DWORD http_status_size = sizeof(http_status); + if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, + static_cast(&http_status), &http_status_size, + 0)) { + return false; + } + + int http_response = wcstol(http_status, NULL, 10); + if (response_code) { + *response_code = http_response; + } + + bool result = (http_response == 200); + + if (result) { + result = ReadResponse(request.get(), response_body); + } + + return result; + } + + wstring GenerateMultipartBoundary() { + // The boundary has 27 '-' characters followed by 16 hex digits + static const wchar_t kBoundaryPrefix[] = L"---------------------------"; + static const int kBoundaryLength = 27 + 16 + 1; + + // Generate some random numbers to fill out the boundary + int r0 = rand(); + int r1 = rand(); + + wchar_t temp[kBoundaryLength]; + swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1); + + // remove when VC++7.1 is no longer supported + temp[kBoundaryLength - 1] = L'\0'; + + return wstring(temp); + } + + wstring GenerateMultipartPostRequestHeader(const wstring &boundary) { + wstring header = L"Content-Type: multipart/form-data; boundary="; + header += boundary; + return header; + } + + bool AppendFileToRequestBody( + const wstring& file_part_name, + const wstring& filename, + string* request_body) { + string file_part_name_utf8 = WideToUTF8(file_part_name); + if (file_part_name_utf8.empty()) { + return false; + } + + string filename_utf8 = WideToUTF8(filename); + if (filename_utf8.empty()) { + return false; + } + + request_body->append("Content-Disposition: form-data; " + "name=\"" + file_part_name_utf8 + "\"; " + "filename=\"" + filename_utf8 + "\"\r\n"); + request_body->append("Content-Type: application/octet-stream\r\n"); + request_body->append("\r\n"); + + vector contents; + if (!GetFileContents(filename, &contents)) { + return false; + } + + if (!contents.empty()) { + request_body->append(&(contents[0]), contents.size()); + } + request_body->append("\r\n"); + + return true; + } + + bool GenerateRequestBody(const string ¶meters, + const map &files, + const wstring &boundary, + string *request_body) { + string boundary_str = WideToUTF8(boundary); + if (boundary_str.empty()) { + return false; + } + + request_body->clear(); + + // Append the extra data as a single JSON form entry + request_body->append("--" + boundary_str + "\r\n"); + request_body->append( + "Content-Disposition: form-data; " + "name=\"extra\"; " + "filename=\"extra.json\"\r\n"); + request_body->append("Content-Type: application/json\r\n"); + request_body->append("\r\n"); + + if (!parameters.empty()) { + request_body->append(parameters); + } + request_body->append("\r\n"); + + // Now append each upload file as a binary (octet-stream) part + for (map::const_iterator pos = files.begin(); + pos != files.end(); ++pos) { + request_body->append("--" + boundary_str + "\r\n"); + + if (!AppendFileToRequestBody(pos->first, pos->second, request_body)) { + return false; + } + } + request_body->append("--" + boundary_str + "--\r\n"); + return true; + } +} + +namespace google_breakpad { + bool HTTPUpload::SendPutRequest( + const wstring& url, + const wstring& path, + int* timeout_ms, + wstring* response_body, + int* response_code) { + string request_body; + if (!AppendFileToRequestBody(L"symbol_file", path, &request_body)) { + return false; + } + + return SendRequestInner( + url, + L"PUT", + L"", + request_body, + timeout_ms, + response_body, + response_code); + } + + bool HTTPUpload::SendGetRequest( + const wstring& url, + int* timeout_ms, + wstring* response_body, + int* response_code) { + return SendRequestInner( + url, + L"GET", + L"", + "", + timeout_ms, + response_body, + response_code); + } + + bool HTTPUpload::SendMultipartPostRequest( + const wstring& url, + const string& parameters, + const map& files, + int* timeout_ms, + wstring* response_body, + int* response_code) { + wstring boundary = GenerateMultipartBoundary(); + wstring content_type_header = GenerateMultipartPostRequestHeader(boundary); + + string request_body; + if (!GenerateRequestBody(parameters, files, boundary, &request_body)) { + return false; + } + + return SendRequestInner( + url, + L"POST", + content_type_header, + request_body, + timeout_ms, + response_body, + response_code); + } + + bool HTTPUpload::SendSimplePostRequest( + const wstring& url, + const wstring& body, + const wstring& content_type, + int *timeout_ms, + wstring *response_body, + int *response_code) { + return SendRequestInner( + url, + L"POST", + content_type, + WideToUTF8(body), + timeout_ms, + response_body, + response_code); + } +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h new file mode 100644 index 0000000000..1e47f5829f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.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 +// parameters encoded in a JSON string, 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 +#include + +#include + +namespace google_breakpad { + +using std::map; +using std::string; +using std::wstring; + +class HTTPUpload { + public: + // Sends a PUT request containing the data in |path| to the given + // URL. + // 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 SendPutRequest( + const wstring& url, + const wstring& path, + int* timeout_ms, + wstring* response_body, + int* response_code); + + // Sends a GET request to the given URL. + // 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 SendGetRequest( + const wstring& url, + int* timeout_ms, + wstring* response_body, + int* response_code); + + // Sends the given sets of parameters and files as a multipart POST + // request to the given URL. + // Each key in |files| is the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an . + // Parameters are specified as a JSON-encoded string in |parameters|. + // 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 SendMultipartPostRequest( + const wstring& url, + const string& parameters, + const map& files, + int *timeout_ms, + wstring *response_body, + int *response_code); + + // Sends a POST request, with the body set to |body|, to the given URL. + // 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 SendSimplePostRequest( + const wstring& url, + const wstring& body, + const wstring& content_type, + int *timeout_ms, + wstring *response_body, + int *response_code); + + private: + // 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_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/module_info.h b/toolkit/crashreporter/google-breakpad/src/common/windows/module_info.h new file mode 100644 index 0000000000..3dccc80882 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/module_info.h @@ -0,0 +1,75 @@ +// Copyright (c) 2019, 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 COMMON_WINDOWS_MODULE_INFO_H_ +#define COMMON_WINDOWS_MODULE_INFO_H_ + +#include + +namespace google_breakpad { + +using std::wstring; +// A structure that carries information that identifies a module. +struct PDBModuleInfo { +public: + // The basename of the pe/pdb file from which information was loaded. + wstring debug_file; + + // The module's identifier. For recent pe/pdb files, the identifier consists + // of the pe/pdb's guid, in uppercase hexadecimal form without any dashes + // or separators, followed immediately by the pe/pdb's age, also in + // uppercase hexadecimal form. For older pe/pdb files which have no guid, + // the identifier is the pe/pdb's 32-bit signature value, in zero-padded + // hexadecimal form, followed immediately by the pe/pdb's age, in lowercase + // hexadecimal form. + wstring debug_identifier; + + // A string identifying the cpu that the pe/pdb is associated with. + // Currently, this may be "x86" or "unknown". + wstring cpu; +}; + +// A structure that carries information that identifies a PE file, +// either an EXE or a DLL. +struct PEModuleInfo { + // The basename of the PE file. + wstring code_file; + + // The PE file's code identifier, which consists of its timestamp + // and file size concatenated together into a single hex string. + // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and + // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp + // documentation.) This is not well documented, if it's documented + // at all, but it's what symstore does and what DbgHelp supports. + wstring code_identifier; +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_MODULE_INFO_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild b/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild new file mode 100644 index 0000000000..5fcdae5a35 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +lobjs_common = [ + 'guid_string.cc', + 'string_utils.cc', +] + +subdir = 'toolkit/crashreporter/google-breakpad/src/common/windows' +objs_common = [ + '/%s/%s' % (subdir, s) for s in lobjs_common +] diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc new file mode 100644 index 0000000000..ba3ce86b8b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc @@ -0,0 +1,716 @@ +// Copyright 2013 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. + +// This contains a suite of tools for transforming symbol information when +// when that information has been extracted from a PDB containing OMAP +// information. + +// OMAP information is a lightweight description of a mapping between two +// address spaces. It consists of two streams, each of them a vector 2-tuples. +// The OMAPTO stream contains tuples of the form +// +// (RVA in transformed image, RVA in original image) +// +// while the OMAPFROM stream contains tuples of the form +// +// (RVA in original image, RVA in transformed image) +// +// The entries in each vector are sorted by the first value of the tuple, and +// the lengths associated with a mapping are implicit as the distance between +// two successive addresses in the vector. + +// Consider a trivial 10-byte function described by the following symbol: +// +// Function: RVA 0x00001000, length 10, "foo" +// +// Now consider the same function, but with 5-bytes of instrumentation injected +// at offset 5. The OMAP streams describing this would look like: +// +// OMAPTO : [ [0x00001000, 0x00001000], +// [0x00001005, 0xFFFFFFFF], +// [0x0000100a, 0x00001005] ] +// OMAPFROM: [ [0x00001000, 0x00001000], +// [0x00001005, 0x0000100a] ] +// +// In this case the injected code has been marked as not originating in the +// source image, and thus it will have no symbol information at all. However, +// the injected code may also be associated with an original address range; +// for example, when prepending instrumentation to a basic block the +// instrumentation can be labelled as originating from the same source BB such +// that symbol resolution will still find the appropriate source code line +// number. In this case the OMAP stream would look like: +// +// OMAPTO : [ [0x00001000, 0x00001000], +// [0x00001005, 0x00001005], +// [0x0000100a, 0x00001005] ] +// OMAPFROM: [ [0x00001000, 0x00001000], +// [0x00001005, 0x0000100a] ] +// +// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the +// instrumented image. It would first run this through the OMAPTO table and +// translate that address to 0x00001005. It would then lookup the symbol +// at that address and return the symbol for the function "foo". This is the +// correct result. +// +// However, if we query DIA for the length and address of the symbol it will +// tell us that it has length 10 and is at RVA 0x00001000. The location is +// correct, but the length doesn't take into account the 5-bytes of injected +// code. Symbol resolution works (starting from an instrumented address, +// mapping to an original address, and looking up a symbol), but the symbol +// metadata is incorrect. +// +// If we dump the symbols using DIA they will have their addresses +// appropriately transformed and reflect positions in the instrumented image. +// However, if we try to do a lookup using those symbols resolution can fail. +// For example, the address 0x0000100a will not map to the symbol for "foo", +// because DIA tells us it is at location 0x00001000 (correct) with length +// 10 (incorrect). The problem is one of order of operations: in this case +// we're attempting symbol resolution by looking up an instrumented address +// in the table of translated symbols. +// +// One way to handle this is to dump the OMAP information as part of the +// breakpad symbols. This requires the rest of the toolchain to be aware of +// OMAP information and to use it when present prior to performing lookup. The +// other option is to properly transform the symbols (updating length as well as +// position) so that resolution will work as expected for translated addresses. +// This is transparent to the rest of the toolchain. + +#include "common/windows/omap.h" + +#include + +#include +#include +#include + +#include "common/windows/dia_util.h" + +namespace google_breakpad { + +namespace { + +static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO"; +static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM"; + +// Dependending on where this is used in breakpad we sometimes get min/max from +// windef, and other times from algorithm. To get around this we simply +// define our own min/max functions. +template +const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; } +template +const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; } + +// It makes things more readable to have two different OMAP types. We cast +// normal OMAPs into these. They must be the same size as the OMAP structure +// for this to work, hence the static asserts. +struct OmapOrigToTran { + DWORD rva_original; + DWORD rva_transformed; +}; +struct OmapTranToOrig { + DWORD rva_transformed; + DWORD rva_original; +}; +static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP), + "OmapOrigToTran must have same size as OMAP."); +static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP), + "OmapTranToOrig must have same size as OMAP."); +typedef std::vector OmapFromTable; +typedef std::vector OmapToTable; + +// Used for sorting and searching through a Mapping. +bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) { + if (lhs.rva_original < rhs.rva_original) + return true; + if (lhs.rva_original > rhs.rva_original) + return false; + return lhs.length < rhs.length; +} +bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) { + if (lhs.rva_transformed < rhs.rva_transformed) + return true; + if (lhs.rva_transformed > rhs.rva_transformed) + return false; + return lhs.length < rhs.length; +} + +// Used for searching through the EndpointIndexMap. +bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { + return ei1.endpoint < ei2.endpoint; +} + +// Finds the debug stream with the given |name| in the given |session|, and +// populates |table| with its contents. Casts the data directly into OMAP +// structs. +bool FindAndLoadOmapTable(const wchar_t* name, + IDiaSession* session, + OmapTable* table) { + assert(name != NULL); + assert(session != NULL); + assert(table != NULL); + + CComPtr stream; + if (!FindDebugStream(name, session, &stream)) + return false; + assert(stream.p != NULL); + + LONG count = 0; + if (FAILED(stream->get_Count(&count))) { + fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream " + "\"%ws\"\n", name); + return false; + } + + // Get the length of the stream in bytes. + DWORD bytes_read = 0; + ULONG count_read = 0; + if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { + fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " + "length of stream \"%ws\"\n", name); + return false; + } + + // Ensure it's consistent with the OMAP data type. + DWORD bytes_expected = count * sizeof(OmapTable::value_type); + if (count * sizeof(OmapTable::value_type) != bytes_read) { + fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name); + return false; + } + + // Read the table. + table->resize(count); + bytes_read = 0; + count_read = 0; + if (FAILED(stream->Next(count, bytes_expected, &bytes_read, + reinterpret_cast(&table->at(0)), + &count_read))) { + fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " + "data from stream \"%ws\"\n", name); + return false; + } + + return true; +} + +// This determines the original image length by looking through the segment +// table. +bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { + assert(session != NULL); + assert(image_length != NULL); + + CComPtr enum_segments; + if (!FindTable(session, &enum_segments)) + return false; + assert(enum_segments.p != NULL); + + DWORD temp_image_length = 0; + CComPtr segment; + ULONG fetched = 0; + while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && + fetched == 1) { + assert(segment.p != NULL); + + DWORD rva = 0; + DWORD length = 0; + DWORD frame = 0; + if (FAILED(segment->get_relativeVirtualAddress(&rva)) || + FAILED(segment->get_length(&length)) || + FAILED(segment->get_frame(&frame))) { + fprintf(stderr, "Failed to get basic properties for IDiaSegment\n"); + return false; + } + + if (frame > 0) { + DWORD segment_end = rva + length; + if (segment_end > temp_image_length) + temp_image_length = segment_end; + } + segment.Release(); + } + + *image_length = temp_image_length; + return true; +} + +// Detects regions of the original image that have been removed in the +// transformed image, and sets the 'removed' property on all mapped ranges +// immediately preceding a gap. The mapped ranges must be sorted by +// 'rva_original'. +void FillInRemovedLengths(Mapping* mapping) { + assert(mapping != NULL); + + // Find and fill gaps. We do this with two sweeps. We first sweep forward + // looking for gaps. When we identify a gap we then sweep forward with a + // second scan and set the 'removed' property for any intervals that + // immediately precede the gap. + // + // Gaps are typically between two successive intervals, but not always: + // + // Range 1: --------------- + // Range 2: ------- + // Range 3: ------------- + // Gap : ****** + // + // In the above example the gap is between range 1 and range 3. A forward + // sweep finds the gap, and a second forward sweep identifies that range 1 + // immediately precedes the gap and sets its 'removed' property. + + size_t fill = 0; + DWORD rva_front = 0; + for (size_t find = 0; find < mapping->size(); ++find) { +#ifndef NDEBUG + // We expect the mapped ranges to be sorted by 'rva_original'. + if (find > 0) { + assert(mapping->at(find - 1).rva_original <= + mapping->at(find).rva_original); + } +#endif + + if (rva_front < mapping->at(find).rva_original) { + // We've found a gap. Fill it in by setting the 'removed' property for + // any affected intervals. + DWORD removed = mapping->at(find).rva_original - rva_front; + for (; fill < find; ++fill) { + if (mapping->at(fill).rva_original + mapping->at(fill).length != + rva_front) { + continue; + } + + // This interval ends right where the gap starts. It needs to have its + // 'removed' information filled in. + mapping->at(fill).removed = removed; + } + } + + // Advance the front that indicates the covered portion of the image. + rva_front = mapping->at(find).rva_original + mapping->at(find).length; + } +} + +// Builds a unified view of the mapping between the original and transformed +// image space by merging OMAPTO and OMAPFROM data. +void BuildMapping(const OmapData& omap_data, Mapping* mapping) { + assert(mapping != NULL); + + mapping->clear(); + + if (omap_data.omap_from.empty() || omap_data.omap_to.empty()) + return; + + // The names 'omap_to' and 'omap_from' are awfully confusing, so we make + // ourselves more explicit here. This cast is only safe because the underlying + // types have the exact same size. + const OmapToTable& tran2orig = + reinterpret_cast(omap_data.omap_to); + const OmapFromTable& orig2tran = reinterpret_cast( + omap_data.omap_from); + + // Handle the range of data at the beginning of the image. This is not usually + // specified by the OMAP data. + if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) { + DWORD header_transformed = tran2orig[0].rva_transformed; + DWORD header_original = orig2tran[0].rva_original; + DWORD header = Min(header_transformed, header_original); + + MappedRange mr = {}; + mr.length = header; + mr.injected = header_transformed - header; + mr.removed = header_original - header; + mapping->push_back(mr); + } + + // Convert the implied lengths to explicit lengths, and infer which content + // has been injected into the transformed image. Injected content is inferred + // as regions of the transformed address space that does not map back to + // known valid content in the original image. + for (size_t i = 0; i < tran2orig.size(); ++i) { + const OmapTranToOrig& o1 = tran2orig[i]; + + // This maps to content that is outside the original image, thus it + // describes injected content. We can skip this entry. + if (o1.rva_original >= omap_data.length_original) + continue; + + // Calculate the length of the current OMAP entry. This is implicit as the + // distance between successive |rva| values, capped at the end of the + // original image. + DWORD length = 0; + if (i + 1 < tran2orig.size()) { + const OmapTranToOrig& o2 = tran2orig[i + 1]; + + // We expect the table to be sorted by rva_transformed. + assert(o1.rva_transformed <= o2.rva_transformed); + + length = o2.rva_transformed - o1.rva_transformed; + if (o1.rva_original + length > omap_data.length_original) { + length = omap_data.length_original - o1.rva_original; + } + } else { + length = omap_data.length_original - o1.rva_original; + } + + // Zero-length entries don't describe anything and can be ignored. + if (length == 0) + continue; + + // Any gaps in the transformed address-space are due to injected content. + if (!mapping->empty()) { + MappedRange& prev_mr = mapping->back(); + prev_mr.injected += o1.rva_transformed - + (prev_mr.rva_transformed + prev_mr.length); + } + + MappedRange mr = {}; + mr.rva_original = o1.rva_original; + mr.rva_transformed = o1.rva_transformed; + mr.length = length; + mapping->push_back(mr); + } + + // Sort based on the original image addresses. + std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess); + + // Fill in the 'removed' lengths by looking for gaps in the coverage of the + // original address space. + FillInRemovedLengths(mapping); + + return; +} + +void BuildEndpointIndexMap(ImageMap* image_map) { + assert(image_map != NULL); + + if (image_map->mapping.size() == 0) + return; + + const Mapping& mapping = image_map->mapping; + EndpointIndexMap& eim = image_map->endpoint_index_map; + + // Get the unique set of interval endpoints. + std::set endpoints; + for (size_t i = 0; i < mapping.size(); ++i) { + endpoints.insert(mapping[i].rva_original); + endpoints.insert(mapping[i].rva_original + + mapping[i].length + + mapping[i].removed); + } + + // Use the endpoints to initialize the secondary search structure for the + // mapping. + eim.resize(endpoints.size()); + std::set::const_iterator it = endpoints.begin(); + for (size_t i = 0; it != endpoints.end(); ++it, ++i) { + eim[i].endpoint = *it; + eim[i].index = mapping.size(); + } + + // For each endpoint we want the smallest index of any interval containing + // it. We iterate over the intervals and update the indices associated with + // each interval endpoint contained in the current interval. In the general + // case of an arbitrary set of intervals this is O(n^2), but the structure of + // OMAP data makes this O(n). + for (size_t i = 0; i < mapping.size(); ++i) { + EndpointIndex ei1 = { mapping[i].rva_original, 0 }; + EndpointIndexMap::iterator it1 = std::lower_bound( + eim.begin(), eim.end(), ei1, EndpointIndexLess); + + EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length + + mapping[i].removed, 0 }; + EndpointIndexMap::iterator it2 = std::lower_bound( + eim.begin(), eim.end(), ei2, EndpointIndexLess); + + for (; it1 != it2; ++it1) + it1->index = Min(i, it1->index); + } +} + +void BuildSubsequentRVAMap(const OmapData &omap_data, + std::map *subsequent) { + assert(subsequent->empty()); + const OmapFromTable &orig2tran = + reinterpret_cast(omap_data.omap_from); + + if (orig2tran.empty()) + return; + + for (size_t i = 0; i < orig2tran.size() - 1; ++i) { + // Expect that orig2tran is sorted. + if (orig2tran[i].rva_original >= orig2tran[i + 1].rva_original) { + fprintf(stderr, "OMAP 'from' table unexpectedly unsorted\n"); + subsequent->clear(); + return; + } + subsequent->insert(std::make_pair(orig2tran[i].rva_original, + orig2tran[i + 1].rva_original)); + } +} + +// Clips the given mapped range. +void ClipMappedRangeOriginal(const AddressRange& clip_range, + MappedRange* mapped_range) { + assert(mapped_range != NULL); + + // The clipping range is entirely outside of the mapped range. + if (clip_range.end() <= mapped_range->rva_original || + mapped_range->rva_original + mapped_range->length + + mapped_range->removed <= clip_range.rva) { + mapped_range->length = 0; + mapped_range->injected = 0; + mapped_range->removed = 0; + return; + } + + // Clip the left side. + if (mapped_range->rva_original < clip_range.rva) { + DWORD clip_left = clip_range.rva - mapped_range->rva_original; + mapped_range->rva_original += clip_left; + mapped_range->rva_transformed += clip_left; + + if (clip_left > mapped_range->length) { + // The left clipping boundary entirely erases the content section of the + // range. + DWORD trim = clip_left - mapped_range->length; + mapped_range->length = 0; + mapped_range->injected -= Min(trim, mapped_range->injected); + // We know that trim <= mapped_range->remove. + mapped_range->removed -= trim; + } else { + // The left clipping boundary removes some, but not all, of the content. + // As such it leaves the removed/injected component intact. + mapped_range->length -= clip_left; + } + } + + // Clip the right side. + DWORD end_original = mapped_range->rva_original + mapped_range->length; + if (clip_range.end() < end_original) { + // The right clipping boundary lands in the 'content' section of the range, + // entirely clearing the injected/removed portion. + DWORD clip_right = end_original - clip_range.end(); + mapped_range->length -= clip_right; + mapped_range->injected = 0; + mapped_range->removed = 0; + return; + } else { + // The right clipping boundary is outside of the content, but may affect + // the removed/injected portion of the range. + DWORD end_removed = end_original + mapped_range->removed; + if (clip_range.end() < end_removed) + mapped_range->removed = clip_range.end() - end_original; + + DWORD end_injected = end_original + mapped_range->injected; + if (clip_range.end() < end_injected) + mapped_range->injected = clip_range.end() - end_original; + } + + return; +} + +} // namespace + +int AddressRange::Compare(const AddressRange& rhs) const { + if (end() <= rhs.rva) + return -1; + if (rhs.end() <= rva) + return 1; + return 0; +} + +bool GetOmapDataAndDisableTranslation(IDiaSession* session, + OmapData* omap_data) { + assert(session != NULL); + assert(omap_data != NULL); + + CComPtr address_map; + if (FAILED(session->QueryInterface(&address_map))) { + fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); + return false; + } + assert(address_map.p != NULL); + + BOOL omap_enabled = FALSE; + if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { + fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n"); + return false; + } + + if (!omap_enabled) { + // We indicate the non-presence of OMAP data by returning empty tables. + omap_data->omap_from.clear(); + omap_data->omap_to.clear(); + omap_data->length_original = 0; + return true; + } + + // OMAP data is present. Disable translation. + if (FAILED(address_map->put_addressMapEnabled(FALSE))) { + fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n"); + return false; + } + + // Read the OMAP streams. + if (!FindAndLoadOmapTable(kOmapFromDebugStreamName, + session, + &omap_data->omap_from)) { + return false; + } + if (!FindAndLoadOmapTable(kOmapToDebugStreamName, + session, + &omap_data->omap_to)) { + return false; + } + + // Get the lengths of the address spaces. + if (!GetOriginalImageLength(session, &omap_data->length_original)) + return false; + + return true; +} + +void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { + assert(image_map != NULL); + + BuildMapping(omap_data, &image_map->mapping); + BuildEndpointIndexMap(image_map); + BuildSubsequentRVAMap(omap_data, &image_map->subsequent_rva_block); +} + +void MapAddressRange(const ImageMap& image_map, + const AddressRange& original_range, + AddressRangeVector* mapped_ranges) { + assert(mapped_ranges != NULL); + + const Mapping& map = image_map.mapping; + + // Handle the trivial case of an empty image_map. This means that there is + // no transformation to be applied, and we can simply return the original + // range. + if (map.empty()) { + mapped_ranges->push_back(original_range); + return; + } + + // If we get a query of length 0 we need to handle it by using a non-zero + // query length. + AddressRange query_range(original_range); + if (query_range.length == 0) + query_range.length = 1; + + // Find the range of intervals that can potentially intersect our query range. + size_t imin = 0; + size_t imax = 0; + { + // The index of the earliest possible range that can affect is us done by + // searching through the secondary indexing structure. + const EndpointIndexMap& eim = image_map.endpoint_index_map; + EndpointIndex q1 = { query_range.rva, 0 }; + EndpointIndexMap::const_iterator it1 = std::lower_bound( + eim.begin(), eim.end(), q1, EndpointIndexLess); + if (it1 == eim.end()) { + imin = map.size(); + } else { + // Backup to find the interval that contains our query point. + if (it1 != eim.begin() && query_range.rva < it1->endpoint) + --it1; + imin = it1->index; + } + + // The first range that can't possibly intersect us is found by searching + // through the image map directly as it is already sorted by interval start + // point. + MappedRange q2 = { query_range.end(), 0 }; + Mapping::const_iterator it2 = std::lower_bound( + map.begin(), map.end(), q2, MappedRangeOriginalLess); + imax = it2 - map.begin(); + } + + // Find all intervals that intersect the query range. + Mapping temp_map; + for (size_t i = imin; i < imax; ++i) { + MappedRange mr = map[i]; + ClipMappedRangeOriginal(query_range, &mr); + if (mr.length + mr.injected > 0) + temp_map.push_back(mr); + } + + // If there are no intersecting ranges then the query range has been removed + // from the image in question. + if (temp_map.empty()) + return; + + // Sort based on transformed addresses. + std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess); + + // Zero-length queries can't actually be merged. We simply output the set of + // unique RVAs that correspond to the query RVA. + if (original_range.length == 0) { + mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0)); + for (size_t i = 1; i < temp_map.size(); ++i) { + if (temp_map[i].rva_transformed > mapped_ranges->back().rva) + mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0)); + } + return; + } + + // Merge any ranges that are consecutive in the mapped image. We merge over + // injected content if it makes ranges contiguous, but we ignore any injected + // content at the tail end of a range. This allows us to detect symbols that + // have been lengthened by injecting content in the middle. However, it + // misses the case where content has been injected at the head or the tail. + // The problem is that it doesn't know whether to attribute it to the + // preceding or following symbol. It is up to the author of the transform to + // output explicit OMAP info in these cases to ensure full coverage of the + // transformed address space. + DWORD rva_begin = temp_map[0].rva_transformed; + DWORD rva_cur_content = rva_begin + temp_map[0].length; + DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected; + for (size_t i = 1; i < temp_map.size(); ++i) { + if (rva_cur_injected < temp_map[i].rva_transformed) { + // This marks the end of a continuous range in the image. Output the + // current range and start a new one. + if (rva_begin < rva_cur_content) { + mapped_ranges->push_back( + AddressRange(rva_begin, rva_cur_content - rva_begin)); + } + rva_begin = temp_map[i].rva_transformed; + } + + rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length; + rva_cur_injected = rva_cur_content + temp_map[i].injected; + } + + // Output the range in progress. + if (rva_begin < rva_cur_content) { + mapped_ranges->push_back( + AddressRange(rva_begin, rva_cur_content - rva_begin)); + } + + return; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h new file mode 100644 index 0000000000..bc293afb51 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h @@ -0,0 +1,72 @@ +// Copyright 2013 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. + +// Provides an API for mapping symbols through OMAP information, if a PDB file +// is augmented with it. This allows breakpad to work with addresses in +// transformed images by transforming the symbols themselves, rather than +// transforming addresses prior to querying symbols (the way it is typically +// done by Windows-native tools, including the DIA). + +#ifndef COMMON_WINDOWS_OMAP_H_ +#define COMMON_WINDOWS_OMAP_H_ + +#include "common/windows/omap_internal.h" + +namespace google_breakpad { + +// If the given session contains OMAP data this extracts it, populating +// |omap_data|, and then disabling automatic translation for the session. +// OMAP data is present in the PDB if |omap_data| is not empty. This returns +// true on success, false otherwise. +bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session, + OmapData* omap_data); + +// Given raw OMAP data builds an ImageMap. This can be used to query individual +// image ranges using MapAddressRange. +// |omap_data|| is the OMAP data extracted from the PDB. +// |image_map| will be populated with a description of the image mapping. If +// |omap_data| is empty then this will also be empty. +void BuildImageMap(const OmapData& omap_data, ImageMap* image_map); + +// Given an address range in the original image space determines how exactly it +// has been tranformed. +// |omap_data| is the OMAP data extracted from the PDB, which must not be +// empty. +// |original_range| is the address range in the original image being queried. +// |mapped_ranges| will be populated with a full description of the mapping. +// They may be disjoint in the transformed image so a vector is needed to +// fully represent the mapping. This will be appended to if it is not +// empty. If |omap_data| is empty then |mapped_ranges| will simply be +// populated with a copy of |original_range| (the identity transform). +void MapAddressRange(const ImageMap& image_map, + const AddressRange& original_range, + AddressRangeVector* mapped_ranges); + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_OMAP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h new file mode 100644 index 0000000000..2a4713d934 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h @@ -0,0 +1,140 @@ +// Copyright 2013 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. + +// Declares internal implementation details for functionality in omap.h and +// omap.cc. + +#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H_ +#define COMMON_WINDOWS_OMAP_INTERNAL_H_ + +#include +#include + +#include +#include + +namespace google_breakpad { + +// The OMAP struct is defined by debughlp.h, which doesn't play nicely with +// imagehlp.h. We simply redefine it. +struct OMAP { + DWORD rva; + DWORD rvaTo; +}; +static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure."); +typedef std::vector OmapTable; + +// This contains the OMAP data extracted from an image. +struct OmapData { + // The table of OMAP entries describing the transformation from the + // original image to the transformed image. + OmapTable omap_from; + // The table of OMAP entries describing the transformation from the + // instrumented image to the original image. + OmapTable omap_to; + // The length of the original untransformed image. + DWORD length_original; + + OmapData() : length_original(0) { } +}; + +// This represents a range of addresses in an image. +struct AddressRange { + DWORD rva; + DWORD length; + + AddressRange() : rva(0), length(0) { } + AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { } + + // Returns the end address of this range. + DWORD end() const { return rva + length; } + + // Addreses only compare as less-than or greater-than if they are not + // overlapping. Otherwise, they compare equal. + int Compare(const AddressRange& rhs) const; + bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; } + bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; } + + // Equality operators compare exact values. + bool operator==(const AddressRange& rhs) const { + return rva == rhs.rva && length == rhs.length; + } + bool operator!=(const AddressRange& rhs) const { return !((*this) == rhs); } +}; + +typedef std::vector AddressRangeVector; + +// This represents an address range in an original image, and its corresponding +// range in the transformed image. +struct MappedRange { + // An address in the original image. + DWORD rva_original; + // The corresponding addresses in the transformed image. + DWORD rva_transformed; + // The length of the address range. + DWORD length; + // It is possible for code to be injected into a transformed image, for which + // there is no corresponding code in the original image. If this range of + // transformed image is immediately followed by such injected code we maintain + // a record of its length here. + DWORD injected; + // It is possible for code to be removed from the original image. This happens + // for things like padding between blocks. There is no actual content lost, + // but the spacing between items may be lost. This keeps track of any removed + // content immediately following the |original| range. + DWORD removed; +}; +// A vector of mapped ranges is used as a more useful representation of +// OMAP data. +typedef std::vector Mapping; + +// Used as a secondary search structure accompanying a Mapping. +struct EndpointIndex { + DWORD endpoint; + size_t index; +}; +typedef std::vector EndpointIndexMap; + +// An ImageMap is vector of mapped ranges, plus a secondary index into it for +// doing interval searches. (An interval tree would also work, but is overkill +// because we don't need insertion and deletion.) +struct ImageMap { + // This is a description of the mapping between original and transformed + // image, sorted by addresses in the original image. + Mapping mapping; + // For all interval endpoints in |mapping| this stores the minimum index of + // an interval in |mapping| that contains the endpoint. Useful for doing + // interval intersection queries. + EndpointIndexMap endpoint_index_map; + + std::map subsequent_rva_block; +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_OMAP_INTERNAL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc new file mode 100644 index 0000000000..7fe66bd406 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc @@ -0,0 +1,329 @@ +// Copyright 2013 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. + +// Unittests for OMAP related functions. + +#include "common/windows/omap.h" + +#include "breakpad_googletest_includes.h" + +namespace google_breakpad { + +// Equality operators for ContainerEq. These must be outside of the anonymous +// namespace in order for them to be found. +bool operator==(const MappedRange& mr1, const MappedRange& mr2) { + return mr1.rva_original == mr2.rva_original && + mr1.rva_transformed == mr2.rva_transformed && + mr1.length == mr2.length && + mr1.injected == mr2.injected && + mr1.removed == mr2.removed; +} +bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) { + return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index; +} + +// Pretty printers for more meaningful error messages. Also need to be outside +// the anonymous namespace. +std::ostream& operator<<(std::ostream& os, const MappedRange& mr) { + os << "MappedRange(rva_original=" << mr.rva_original + << ", rva_transformed=" << mr.rva_transformed + << ", length=" << mr.length + << ", injected=" << mr.injected + << ", removed=" << mr.removed << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) { + os << "EndpointIndex(endpoint=" << ei.endpoint + << ", index=" << ei.index << ")"; + return os; +} +std::ostream& operator<<(std::ostream& os, const AddressRange& ar) { + os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")"; + return os; +} + +namespace { + +OMAP CreateOmap(DWORD rva, DWORD rvaTo) { + OMAP o = { rva, rvaTo }; + return o; +} + +MappedRange CreateMappedRange(DWORD rva_original, + DWORD rva_transformed, + DWORD length, + DWORD injected, + DWORD removed) { + MappedRange mr = { rva_original, rva_transformed, length, injected, removed }; + return mr; +} + +EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) { + EndpointIndex ei = { endpoint, index }; + return ei; +} + +// (C is removed) +// Original : A B C D E F G H +// Transformed: A B D F E * H1 G1 G2 H2 +// (* is injected, G is copied, H is split) +// A is implied. + +// Layout of the original image. +const AddressRange B(100, 15); +const AddressRange C(B.end(), 10); +const AddressRange D(C.end(), 25); +const AddressRange E(D.end(), 10); +const AddressRange F(E.end(), 40); +const AddressRange G(F.end(), 3); +const AddressRange H(G.end(), 7); + +// Layout of the transformed image. +const AddressRange Bt(100, 15); +const AddressRange Dt(Bt.end(), 20); // D is shortened. +const AddressRange Ft(Dt.end(), F.length); +const AddressRange Et(Ft.end(), E.length); +const AddressRange injected(Et.end(), 5); +const AddressRange H1t(injected.end(), 4); // H is split. +const AddressRange G1t(H1t.end(), G.length); // G is copied. +const AddressRange G2t(G1t.end(), G.length); // G is copied. +const AddressRange H2t(G2t.end(), 3); // H is split. + +class BuildImageMapTest : public testing::Test { + public: + static const DWORD kInvalidAddress = 0xFFFFFFFF; + + void InitOmapData() { + omap_data.length_original = H.end(); + + // Build the OMAPTO vector (from transformed to original). + omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva)); + omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva)); + omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva)); + omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva)); + omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress)); + omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva)); + omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva)); + omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length)); + omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress)); + + // Build the OMAPFROM vector (from original to transformed). + omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva)); + omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress)); + omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva)); + omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva)); + omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva)); + omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva)); + omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress)); + } + + OmapData omap_data; +}; + +} // namespace + +TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) { + ASSERT_EQ(0u, omap_data.omap_from.size()); + ASSERT_EQ(0u, omap_data.omap_to.size()); + ASSERT_EQ(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_EQ(0u, image_map.mapping.size()); + EXPECT_EQ(0u, image_map.endpoint_index_map.size()); +} + +TEST_F(BuildImageMapTest, ImageMapIsCorrect) { + InitOmapData(); + ASSERT_LE(0u, omap_data.omap_from.size()); + ASSERT_LE(0u, omap_data.omap_to.size()); + ASSERT_LE(0u, omap_data.length_original); + + ImageMap image_map; + BuildImageMap(omap_data, &image_map); + EXPECT_LE(9u, image_map.mapping.size()); + EXPECT_LE(9u, image_map.endpoint_index_map.size()); + + Mapping mapping; + mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0)); + // C is removed, and it originally comes immediately after B. + mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length)); + // D is shortened by a length of 5. + mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5)); + // The injected content comes immediately after E in the transformed image. + mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length, + 0)); + mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0)); + // G is copied so creates two entries. + mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0)); + mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0)); + // H is split, so create two entries. + mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0)); + mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length, + 0, 0)); + EXPECT_THAT(mapping, + testing::ContainerEq(image_map.mapping)); + + EndpointIndexMap endpoint_index_map; + endpoint_index_map.push_back(CreateEndpointIndex(0, 0)); + endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1)); + endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2)); + endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3)); + endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4)); + // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7. + endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5)); + // H is split so we expect 2 endpoints to show up attributed to it. + endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7)); + endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8)); + endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9)); + EXPECT_THAT(endpoint_index_map, + testing::ContainerEq(image_map.endpoint_index_map)); +} + +namespace { + +class MapAddressRangeTest : public BuildImageMapTest { + public: + typedef BuildImageMapTest Super; + virtual void SetUp() { + Super::SetUp(); + InitOmapData(); + BuildImageMap(omap_data, &image_map); + } + + ImageMap image_map; + + private: + using BuildImageMapTest::InitOmapData; + using BuildImageMapTest::omap_data; +}; + +} // namespace + +TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) { + ImageMap im; + AddressRangeVector mapped_ranges; + AddressRange ar(0, 1024); + MapAddressRange(im, ar, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_EQ(ar, mapped_ranges[0]); +} + +TEST_F(MapAddressRangeTest, MapOutOfImage) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapIdentity) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, B, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(B)); +} + +TEST_F(MapAddressRangeTest, MapReorderedContiguous) { + AddressRangeVector mapped_ranges; + + AddressRange DEF(D.rva, F.end() - D.rva); + MapAddressRange(image_map, DEF, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange DFEt(Dt.rva, Et.end() - Dt.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt)); +} + +TEST_F(MapAddressRangeTest, MapEmptySingle) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapEmptyCopied) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0), + AddressRange(G2t.rva, 0))); +} + +TEST_F(MapAddressRangeTest, MapCopiedContiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, G, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre( + AddressRange(G1t.rva, G2t.end() - G1t.rva))); +} + +TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, H, &mapped_ranges); + EXPECT_EQ(2u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t)); +} + +TEST_F(MapAddressRangeTest, MapInjected) { + AddressRangeVector mapped_ranges; + + AddressRange EFGH(E.rva, H.end() - E.rva); + MapAddressRange(image_map, EFGH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt)); +} + +TEST_F(MapAddressRangeTest, MapRemovedEntirely) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, C, &mapped_ranges); + EXPECT_EQ(0u, mapped_ranges.size()); +} + +TEST_F(MapAddressRangeTest, MapRemovedPartly) { + AddressRangeVector mapped_ranges; + MapAddressRange(image_map, D, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt)); +} + +TEST_F(MapAddressRangeTest, MapFull) { + AddressRangeVector mapped_ranges; + + AddressRange AH(0, H.end()); + MapAddressRange(image_map, AH, &mapped_ranges); + EXPECT_EQ(1u, mapped_ranges.size()); + + AddressRange AHt(0, H2t.end()); + EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt)); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc new file mode 100644 index 0000000000..4030a2e953 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc @@ -0,0 +1,1194 @@ +// 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 "common/windows/pdb_source_line_writer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "common/windows/dia_util.h" +#include "common/windows/guid_string.h" +#include "common/windows/pe_util.h" +#include "common/windows/string_utils-inl.h" + +// This constant may be missing from DbgHelp.h. See the documentation for +// IDiaSymbol::get_undecoratedNameEx. +#ifndef UNDNAME_NO_ECSU +#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. +#endif // UNDNAME_NO_ECSU + +namespace google_breakpad { + +namespace { + +using std::vector; + +// The symbol (among possibly many) selected to represent an rva. +struct SelectedSymbol { + SelectedSymbol(const CComPtr& symbol, bool is_public) + : symbol(symbol), is_public(is_public), is_multiple(false) {} + + // The symbol to use for an rva. + CComPtr symbol; + // Whether this is a public or function symbol. + bool is_public; + // Whether the rva has multiple associated symbols. An rva will correspond to + // multiple symbols in the case of linker identical symbol folding. + bool is_multiple; +}; + +// Maps rva to the symbol to use for that address. +typedef std::map SymbolMap; + +// Record this in the map as the selected symbol for the rva if it satisfies the +// necessary conditions. +void MaybeRecordSymbol(DWORD rva, + const CComPtr symbol, + bool is_public, + SymbolMap* map) { + SymbolMap::iterator loc = map->find(rva); + if (loc == map->end()) { + map->insert(std::make_pair(rva, SelectedSymbol(symbol, is_public))); + return; + } + + // Prefer function symbols to public symbols. + if (is_public && !loc->second.is_public) { + return; + } + + loc->second.is_multiple = true; + + // Take the 'least' symbol by lexicographical order of the decorated name. We + // use the decorated rather than undecorated name because computing the latter + // is expensive. + BSTR current_name, new_name; + loc->second.symbol->get_name(¤t_name); + symbol->get_name(&new_name); + if (wcscmp(new_name, current_name) < 0) { + loc->second.symbol = symbol; + loc->second.is_public = is_public; + } +} + + + +bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) { + DWORD a_section, a_offset, b_section, b_offset; + if (FAILED(a->get_addressSection(&a_section)) || + FAILED(a->get_addressOffset(&a_offset)) || + FAILED(b->get_addressSection(&b_section)) || + FAILED(b->get_addressOffset(&b_offset))) + return false; + return a_section == b_section && a_offset == b_offset; +} + +bool CreateDiaDataSourceInstance(CComPtr &data_source) { + if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) { + return true; + } + + class DECLSPEC_UUID("B86AE24D-BF2F-4ac9-B5A2-34B14E4CE11D") DiaSource100; + class DECLSPEC_UUID("761D3BCD-1304-41D5-94E8-EAC54E4AC172") DiaSource110; + class DECLSPEC_UUID("3BFCEA48-620F-4B6B-81F7-B9AF75454C7D") DiaSource120; + class DECLSPEC_UUID("E6756135-1E65-4D17-8576-610761398C3C") DiaSource140; + + // If the CoCreateInstance call above failed, msdia*.dll is not registered. + // We can try loading the DLL corresponding to the #included DIA SDK, but + // the DIA headers don't provide a version. Lets try to figure out which DIA + // version we're compiling against by comparing CLSIDs. + const wchar_t *msdia_dll = nullptr; + if (CLSID_DiaSource == _uuidof(DiaSource100)) { + msdia_dll = L"msdia100.dll"; + } else if (CLSID_DiaSource == _uuidof(DiaSource110)) { + msdia_dll = L"msdia110.dll"; + } else if (CLSID_DiaSource == _uuidof(DiaSource120)) { + msdia_dll = L"msdia120.dll"; + } else if (CLSID_DiaSource == _uuidof(DiaSource140)) { + msdia_dll = L"msdia140.dll"; + } + + if (msdia_dll && + SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, + reinterpret_cast(&data_source)))) { + return true; + } + + return false; +} + +} // namespace + +PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { +} + +PDBSourceLineWriter::~PDBSourceLineWriter() { + Close(); +} + +bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) { + if (code_file_.empty()) { + code_file_ = exe_file; + return true; + } + // Setting a different code file path is an error. It is success only if the + // file paths are the same. + return exe_file == code_file_; +} + +bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { + Close(); + code_file_.clear(); + + if (FAILED(CoInitialize(NULL))) { + fprintf(stderr, "CoInitialize failed\n"); + return false; + } + + CComPtr data_source; + if (!CreateDiaDataSourceInstance(data_source)) { + const int kGuidSize = 64; + wchar_t classid[kGuidSize] = {0}; + StringFromGUID2(CLSID_DiaSource, classid, kGuidSize); + fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed " + "(msdia*.dll unregistered?)\n", classid); + return false; + } + + switch (format) { + case PDB_FILE: + if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { + fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str()); + return false; + } + break; + case EXE_FILE: + if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { + fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str()); + return false; + } + code_file_ = file; + break; + case ANY_FILE: + if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { + if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { + fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n", + file.c_str()); + return false; + } + code_file_ = file; + } + break; + default: + fprintf(stderr, "Unknown file format\n"); + return false; + } + + if (FAILED(data_source->openSession(&session_))) { + fprintf(stderr, "openSession failed\n"); + } + + return true; +} + +bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { + // The line number format is: + // + CComPtr line; + ULONG count; + + while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { + DWORD rva; + if (FAILED(line->get_relativeVirtualAddress(&rva))) { + fprintf(stderr, "failed to get line rva\n"); + return false; + } + + DWORD length; + if (FAILED(line->get_length(&length))) { + fprintf(stderr, "failed to get line code length\n"); + return false; + } + + DWORD dia_source_id; + if (FAILED(line->get_sourceFileId(&dia_source_id))) { + fprintf(stderr, "failed to get line source file id\n"); + return false; + } + // duplicate file names are coalesced to share one ID + DWORD source_id = GetRealFileID(dia_source_id); + + DWORD line_num; + if (FAILED(line->get_lineNumber(&line_num))) { + fprintf(stderr, "failed to get line number\n"); + return false; + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, length), &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + fprintf(output_, "%lx %lx %lu %lu\n", ranges[i].rva, ranges[i].length, + line_num, source_id); + } + line.Release(); + } + return true; +} + +bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, + IDiaSymbol *block, + bool has_multiple_symbols) { + // The function format is: + // FUNC
+ DWORD rva; + if (FAILED(block->get_relativeVirtualAddress(&rva))) { + fprintf(stderr, "couldn't get rva\n"); + return false; + } + + ULONGLONG length; + if (FAILED(block->get_length(&length))) { + fprintf(stderr, "failed to get function length\n"); + return false; + } + + if (length == 0) { + // Silently ignore zero-length functions, which can infrequently pop up. + return true; + } + + CComBSTR name; + int stack_param_size; + if (!GetSymbolFunctionName(function, &name, &stack_param_size)) { + return false; + } + + // If the decorated name didn't give the parameter size, try to + // calculate it. + if (stack_param_size < 0) { + stack_param_size = GetFunctionStackParamSize(function); + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, static_cast(length)), + &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + const char* optional_multiple_field = has_multiple_symbols ? "m " : ""; + fprintf(output_, "FUNC %s%lx %lx %x %ws\n", optional_multiple_field, + ranges[i].rva, ranges[i].length, stack_param_size, name.m_str); + } + + CComPtr lines; + if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { + return false; + } + + if (!PrintLines(lines)) { + return false; + } + return true; +} + +bool PDBSourceLineWriter::PrintSourceFiles() { + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComPtr compilands; + if (FAILED(global->findChildren(SymTagCompiland, NULL, + nsNone, &compilands))) { + fprintf(stderr, "findChildren failed\n"); + return false; + } + + CComPtr compiland; + ULONG count; + while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { + CComPtr source_files; + if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { + return false; + } + CComPtr file; + while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) { + DWORD file_id; + if (FAILED(file->get_uniqueId(&file_id))) { + return false; + } + + CComBSTR file_name; + if (FAILED(file->get_fileName(&file_name))) { + return false; + } + + wstring file_name_string(file_name); + if (!FileIDIsCached(file_name_string)) { + // this is a new file name, cache it and output a FILE line. + CacheFileID(file_name_string, file_id); + fwprintf(output_, L"FILE %d %ws\n", file_id, file_name_string.c_str()); + } else { + // this file name has already been seen, just save this + // ID for later lookup. + StoreDuplicateFileID(file_name_string, file_id); + } + file.Release(); + } + compiland.Release(); + } + return true; +} + +bool PDBSourceLineWriter::PrintFunctions() { + ULONG count = 0; + DWORD rva = 0; + CComPtr global; + HRESULT hr; + + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComPtr symbols = NULL; + + // Find all function symbols first. + SymbolMap rva_symbol; + hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols); + + if (SUCCEEDED(hr)) { + CComPtr symbol = NULL; + + while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { + if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { + // Potentially record this as the canonical symbol for this rva. + MaybeRecordSymbol(rva, symbol, false, &rva_symbol); + } else { + fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); + return false; + } + + symbol.Release(); + } + + symbols.Release(); + } + + // Find all public symbols and record public symbols that are not also private + // symbols. + hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols); + + if (SUCCEEDED(hr)) { + CComPtr symbol = NULL; + + while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { + if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { + // Potentially record this as the canonical symbol for this rva. + MaybeRecordSymbol(rva, symbol, true, &rva_symbol); + } else { + fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); + return false; + } + + symbol.Release(); + } + + symbols.Release(); + } + + // For each rva, dump the selected symbol at the address. + SymbolMap::iterator it; + for (it = rva_symbol.begin(); it != rva_symbol.end(); ++it) { + CComPtr symbol = it->second.symbol; + // Only print public symbols if there is no function symbol for the address. + if (!it->second.is_public) { + if (!PrintFunction(symbol, symbol, it->second.is_multiple)) + return false; + } else { + if (!PrintCodePublicSymbol(symbol, it->second.is_multiple)) + return false; + } + } + + // When building with PGO, the compiler can split functions into + // "hot" and "cold" blocks, and move the "cold" blocks out to separate + // pages, so the function can be noncontiguous. To find these blocks, + // we have to iterate over all the compilands, and then find blocks + // that are children of them. We can then find the lexical parents + // of those blocks and print out an extra FUNC line for blocks + // that are not contained in their parent functions. + CComPtr compilands; + if (FAILED(global->findChildren(SymTagCompiland, NULL, + nsNone, &compilands))) { + fprintf(stderr, "findChildren failed on the global\n"); + return false; + } + + CComPtr compiland; + while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { + CComPtr blocks; + if (FAILED(compiland->findChildren(SymTagBlock, NULL, + nsNone, &blocks))) { + fprintf(stderr, "findChildren failed on a compiland\n"); + return false; + } + + CComPtr block; + while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) { + // find this block's lexical parent function + CComPtr parent; + DWORD tag; + if (SUCCEEDED(block->get_lexicalParent(&parent)) && + SUCCEEDED(parent->get_symTag(&tag)) && + tag == SymTagFunction) { + // now get the block's offset and the function's offset and size, + // and determine if the block is outside of the function + DWORD func_rva, block_rva; + ULONGLONG func_length; + if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) && + SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) && + SUCCEEDED(parent->get_length(&func_length))) { + if (block_rva < func_rva || block_rva > (func_rva + func_length)) { + if (!PrintFunction(parent, block, false)) { + return false; + } + } + } + } + parent.Release(); + block.Release(); + } + blocks.Release(); + compiland.Release(); + } + + global.Release(); + return true; +} + +#undef max + +bool PDBSourceLineWriter::PrintFrameDataUsingPDB() { + // It would be nice if it were possible to output frame data alongside the + // associated function, as is done with line numbers, but the DIA API + // doesn't make it possible to get the frame data in that way. + + CComPtr frame_data_enum; + if (!FindTable(session_, &frame_data_enum)) + return false; + + DWORD last_type = std::numeric_limits::max(); + DWORD last_rva = std::numeric_limits::max(); + DWORD last_code_size = 0; + DWORD last_prolog_size = std::numeric_limits::max(); + + CComPtr frame_data; + ULONG count = 0; + while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) && + count == 1) { + DWORD type; + if (FAILED(frame_data->get_type(&type))) + return false; + + DWORD rva; + if (FAILED(frame_data->get_relativeVirtualAddress(&rva))) + return false; + + DWORD code_size; + if (FAILED(frame_data->get_lengthBlock(&code_size))) + return false; + + DWORD prolog_size; + if (FAILED(frame_data->get_lengthProlog(&prolog_size))) + return false; + + // parameter_size is the size of parameters passed on the stack. If any + // parameters are not passed on the stack (such as in registers), their + // sizes will not be included in parameter_size. + DWORD parameter_size; + if (FAILED(frame_data->get_lengthParams(¶meter_size))) + return false; + + DWORD saved_register_size; + if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size))) + return false; + + DWORD local_size; + if (FAILED(frame_data->get_lengthLocals(&local_size))) + return false; + + // get_maxStack can return S_FALSE, just use 0 in that case. + DWORD max_stack_size = 0; + if (FAILED(frame_data->get_maxStack(&max_stack_size))) + return false; + + // get_programString can return S_FALSE, indicating that there is no + // program string. In that case, check whether %ebp is used. + HRESULT program_string_result; + CComBSTR program_string; + if (FAILED(program_string_result = frame_data->get_program( + &program_string))) { + return false; + } + + // get_allocatesBasePointer can return S_FALSE, treat that as though + // %ebp is not used. + BOOL allocates_base_pointer = FALSE; + if (program_string_result != S_OK) { + if (FAILED(frame_data->get_allocatesBasePointer( + &allocates_base_pointer))) { + return false; + } + } + + // Only print out a line if type, rva, code_size, or prolog_size have + // changed from the last line. It is surprisingly common (especially in + // system library PDBs) for DIA to return a series of identical + // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86, + // this check reduces the size of the dumped symbol file by a third. + if (type != last_type || rva != last_rva || code_size != last_code_size || + prolog_size != last_prolog_size) { + // The prolog and the code portions of the frame have to be treated + // independently as they may have independently changed in size, or may + // even have been split. + // NOTE: If epilog size is ever non-zero, we have to do something + // similar with it. + + // Figure out where the prolog bytes have landed. + AddressRangeVector prolog_ranges; + if (prolog_size > 0) { + MapAddressRange(image_map_, AddressRange(rva, prolog_size), + &prolog_ranges); + } + + // And figure out where the code bytes have landed. + AddressRangeVector code_ranges; + MapAddressRange(image_map_, + AddressRange(rva + prolog_size, + code_size - prolog_size), + &code_ranges); + + struct FrameInfo { + DWORD rva; + DWORD code_size; + DWORD prolog_size; + }; + std::vector frame_infos; + + // Special case: The prolog and the code bytes remain contiguous. This is + // only done for compactness of the symbol file, and we could actually + // be outputting independent frame info for the prolog and code portions. + if (prolog_ranges.size() == 1 && code_ranges.size() == 1 && + prolog_ranges[0].end() == code_ranges[0].rva) { + FrameInfo fi = { prolog_ranges[0].rva, + prolog_ranges[0].length + code_ranges[0].length, + prolog_ranges[0].length }; + frame_infos.push_back(fi); + } else { + // Otherwise we output the prolog and code frame info independently. + for (size_t i = 0; i < prolog_ranges.size(); ++i) { + FrameInfo fi = { prolog_ranges[i].rva, + prolog_ranges[i].length, + prolog_ranges[i].length }; + frame_infos.push_back(fi); + } + for (size_t i = 0; i < code_ranges.size(); ++i) { + FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 }; + frame_infos.push_back(fi); + } + } + + for (size_t i = 0; i < frame_infos.size(); ++i) { + const FrameInfo& fi(frame_infos[i]); + fprintf(output_, "STACK WIN %lx %lx %lx %lx %x %lx %lx %lx %lx %d ", + type, fi.rva, fi.code_size, fi.prolog_size, + 0 /* epilog_size */, parameter_size, saved_register_size, + local_size, max_stack_size, program_string_result == S_OK); + if (program_string_result == S_OK) { + fprintf(output_, "%ws\n", program_string.m_str); + } else { + fprintf(output_, "%d\n", allocates_base_pointer); + } + } + + last_type = type; + last_rva = rva; + last_code_size = code_size; + last_prolog_size = prolog_size; + } + + frame_data.Release(); + } + + return true; +} + +bool PDBSourceLineWriter::PrintFrameDataUsingEXE() { + if (code_file_.empty() && !FindPEFile()) { + fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); + return false; + } + + return PrintPEFrameData(code_file_, output_); +} + +bool PDBSourceLineWriter::PrintFrameData() { + PDBModuleInfo info; + if (GetModuleInfo(&info) && info.cpu == L"x86_64") { + return PrintFrameDataUsingEXE(); + } else { + return PrintFrameDataUsingPDB(); + } + return false; +} + +bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol, + bool has_multiple_symbols) { + BOOL is_code; + if (FAILED(symbol->get_code(&is_code))) { + return false; + } + if (!is_code) { + return true; + } + + DWORD rva; + if (FAILED(symbol->get_relativeVirtualAddress(&rva))) { + return false; + } + + CComBSTR name; + int stack_param_size; + if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) { + return false; + } + + AddressRangeVector ranges; + MapAddressRange(image_map_, AddressRange(rva, 1), &ranges); + for (size_t i = 0; i < ranges.size(); ++i) { + const char* optional_multiple_field = has_multiple_symbols ? "m " : ""; + fprintf(output_, "PUBLIC %s%lx %x %ws\n", optional_multiple_field, + ranges[i].rva, stack_param_size > 0 ? stack_param_size : 0, + name.m_str); + } + + // Now walk the function in the original untranslated space, asking DIA + // what function is at that location, stepping through OMAP blocks. If + // we're still in the same function, emit another entry, because the + // symbol could have been split into multiple pieces. If we've gotten to + // another symbol in the original address space, then we're done for + // this symbol. See https://crbug.com/678874. + for (;;) { + // This steps to the next block in the original image. Simply doing + // rva++ would also be correct, but would emit tons of unnecessary + // entries. + rva = image_map_.subsequent_rva_block[rva]; + if (rva == 0) + break; + + CComPtr next_sym = NULL; + LONG displacement; + if (FAILED(session_->findSymbolByRVAEx(rva, SymTagPublicSymbol, &next_sym, + &displacement))) { + break; + } + + if (!SymbolsMatch(symbol, next_sym)) + break; + + AddressRangeVector next_ranges; + MapAddressRange(image_map_, AddressRange(rva, 1), &next_ranges); + for (size_t i = 0; i < next_ranges.size(); ++i) { + fprintf(output_, "PUBLIC %lx %x %ws\n", next_ranges[i].rva, + stack_param_size > 0 ? stack_param_size : 0, name.m_str); + } + } + + return true; +} + +bool PDBSourceLineWriter::PrintPDBInfo() { + PDBModuleInfo info; + if (!GetModuleInfo(&info)) { + return false; + } + + // Hard-code "windows" for the OS because that's the only thing that makes + // sense for PDB files. (This might not be strictly correct for Windows CE + // support, but we don't care about that at the moment.) + fprintf(output_, "MODULE windows %ws %ws %ws\n", + info.cpu.c_str(), info.debug_identifier.c_str(), + info.debug_file.c_str()); + + return true; +} + +bool PDBSourceLineWriter::PrintPEInfo() { + PEModuleInfo info; + if (!GetPEInfo(&info)) { + return false; + } + + fprintf(output_, "INFO CODE_ID %ws %ws\n", + info.code_identifier.c_str(), + info.code_file.c_str()); + return true; +} + +// wcstol_positive_strict is sort of like wcstol, but much stricter. string +// should be a buffer pointing to a null-terminated string containing only +// decimal digits. If the entire string can be converted to an integer +// without overflowing, and there are no non-digit characters before the +// result is set to the value and this function returns true. Otherwise, +// this function returns false. This is an alternative to the strtol, atoi, +// and scanf families, which are not as strict about input and in some cases +// don't provide a good way for the caller to determine if a conversion was +// successful. +static bool wcstol_positive_strict(wchar_t *string, int *result) { + int value = 0; + for (wchar_t *c = string; *c != '\0'; ++c) { + int last_value = value; + value *= 10; + // Detect overflow. + if (value / 10 != last_value || value < 0) { + return false; + } + if (*c < '0' || *c > '9') { + return false; + } + unsigned int c_value = *c - '0'; + last_value = value; + value += c_value; + // Detect overflow. + if (value < last_value) { + return false; + } + // Forbid leading zeroes unless the string is just "0". + if (value == 0 && *(c+1) != '\0') { + return false; + } + } + *result = value; + return true; +} + +bool PDBSourceLineWriter::FindPEFile() { + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + fprintf(stderr, "get_globalScope failed\n"); + return false; + } + + CComBSTR symbols_file; + if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) { + wstring file(symbols_file); + + // Look for an EXE or DLL file. + const wchar_t *extensions[] = { L"exe", L"dll" }; + for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { + size_t dot_pos = file.find_last_of(L"."); + if (dot_pos != wstring::npos) { + file.replace(dot_pos + 1, wstring::npos, extensions[i]); + // Check if this file exists. + if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) { + code_file_ = file; + return true; + } + } + } + } + + return false; +} + +// static +bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, + BSTR *name, + int *stack_param_size) { + *stack_param_size = -1; + const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_FUNCTION_RETURNS | + UNDNAME_NO_ALLOCATION_MODEL | + UNDNAME_NO_ALLOCATION_LANGUAGE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_ACCESS_SPECIFIERS | + UNDNAME_NO_THROW_SIGNATURES | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_RETURN_UDT_MODEL | + UNDNAME_NO_ECSU; + + // Use get_undecoratedNameEx to get readable C++ names with arguments. + if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) { + if (function->get_name(name) != S_OK) { + fprintf(stderr, "failed to get function name\n"); + return false; + } + + // It's possible for get_name to return an empty string, so + // special-case that. + if (wcscmp(*name, L"") == 0) { + SysFreeString(*name); + // dwarf_cu_to_module.cc uses "", so match that. + *name = SysAllocString(L""); + return true; + } + + // If a name comes from get_name because no undecorated form existed, + // it's already formatted properly to be used as output. Don't do any + // additional processing. + // + // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's. + // This will result in calling get_name for some C++ symbols, so + // all of the parameter and return type information may not be included in + // the name string. + } else { + // C++ uses a bogus "void" argument for functions and methods that don't + // take any parameters. Take it out of the undecorated name because it's + // ugly and unnecessary. + const wchar_t *replace_string = L"(void)"; + const size_t replace_length = wcslen(replace_string); + const wchar_t *replacement_string = L"()"; + size_t length = wcslen(*name); + if (length >= replace_length) { + wchar_t *name_end = *name + length - replace_length; + if (wcscmp(name_end, replace_string) == 0) { + WindowsStringUtils::safe_wcscpy(name_end, replace_length, + replacement_string); + length = wcslen(*name); + } + } + + // Undecorate names used for stdcall and fastcall. These names prefix + // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it + // with '@' followed by the number of bytes of parameters, in decimal. + // If such a name is found, take note of the size and undecorate it. + // Only do this for names that aren't C++, which is determined based on + // whether the undecorated name contains any ':' or '(' characters. + if (!wcschr(*name, ':') && !wcschr(*name, '(') && + (*name[0] == '_' || *name[0] == '@')) { + wchar_t *last_at = wcsrchr(*name + 1, '@'); + if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) { + // If this function adheres to the fastcall convention, it accepts up + // to the first 8 bytes of parameters in registers (%ecx and %edx). + // We're only interested in the stack space used for parameters, so + // so subtract 8 and don't let the size go below 0. + if (*name[0] == '@') { + if (*stack_param_size > 8) { + *stack_param_size -= 8; + } else { + *stack_param_size = 0; + } + } + + // Undecorate the name by moving it one character to the left in its + // buffer, and terminating it where the last '@' had been. + WindowsStringUtils::safe_wcsncpy(*name, length, + *name + 1, last_at - *name - 1); + } else if (*name[0] == '_') { + // This symbol's name is encoded according to the cdecl rules. The + // name doesn't end in a '@' character followed by a decimal positive + // integer, so it's not a stdcall name. Strip off the leading + // underscore. + WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length); + } + } + } + + return true; +} + +// static +int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) { + // This implementation is highly x86-specific. + + // Gather the symbols corresponding to data. + CComPtr data_children; + if (FAILED(function->findChildren(SymTagData, NULL, nsNone, + &data_children))) { + return 0; + } + + // lowest_base is the lowest %ebp-relative byte offset used for a parameter. + // highest_end is one greater than the highest offset (i.e. base + length). + // Stack parameters are assumed to be contiguous, because in reality, they + // are. + int lowest_base = INT_MAX; + int highest_end = INT_MIN; + + CComPtr child; + DWORD count; + while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) { + // If any operation fails at this point, just proceed to the next child. + // Use the next_child label instead of continue because child needs to + // be released before it's reused. Declare constructable/destructable + // types early to avoid gotos that cross initializations. + CComPtr child_type; + + // DataIsObjectPtr is only used for |this|. Because |this| can be passed + // as a stack parameter, look for it in addition to traditional + // parameters. + DWORD child_kind; + if (FAILED(child->get_dataKind(&child_kind)) || + (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) { + goto next_child; + } + + // Only concentrate on register-relative parameters. Parameters may also + // be enregistered (passed directly in a register), but those don't + // consume any stack space, so they're not of interest. + DWORD child_location_type; + if (FAILED(child->get_locationType(&child_location_type)) || + child_location_type != LocIsRegRel) { + goto next_child; + } + + // Of register-relative parameters, the only ones that make any sense are + // %ebp- or %esp-relative. Note that MSVC's debugging information always + // gives parameters as %ebp-relative even when a function doesn't use a + // traditional frame pointer and stack parameters are accessed relative to + // %esp, so just look for %ebp-relative parameters. If you wanted to + // access parameters, you'd probably want to treat these %ebp-relative + // offsets as if they were relative to %esp before a function's prolog + // executed. + DWORD child_register; + if (FAILED(child->get_registerId(&child_register)) || + child_register != CV_REG_EBP) { + goto next_child; + } + + LONG child_register_offset; + if (FAILED(child->get_offset(&child_register_offset))) { + goto next_child; + } + + // IDiaSymbol::get_type can succeed but still pass back a NULL value. + if (FAILED(child->get_type(&child_type)) || !child_type) { + goto next_child; + } + + ULONGLONG child_length; + if (FAILED(child_type->get_length(&child_length))) { + goto next_child; + } + + // Extra scope to avoid goto jumping over variable initialization + { + int child_end = child_register_offset + static_cast(child_length); + if (child_register_offset < lowest_base) { + lowest_base = child_register_offset; + } + if (child_end > highest_end) { + highest_end = child_end; + } + } + +next_child: + child.Release(); + } + + int param_size = 0; + // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest + // possible address to find a stack parameter before executing a function's + // prolog (see above). Some optimizations cause parameter offsets to be + // lower than 4, but we're not concerned with those because we're only + // looking for parameters contained in addresses higher than where the + // return address is stored. + if (lowest_base < 4) { + lowest_base = 4; + } + if (highest_end > lowest_base) { + // All stack parameters are pushed as at least 4-byte quantities. If the + // last type was narrower than 4 bytes, promote it. This assumes that all + // parameters' offsets are 4-byte-aligned, which is always the case. Only + // worry about the last type, because we're not summing the type sizes, + // just looking at the lowest and highest offsets. + int remainder = highest_end % 4; + if (remainder) { + highest_end += 4 - remainder; + } + + param_size = highest_end - lowest_base; + } + + return param_size; +} + +bool PDBSourceLineWriter::WriteSymbols(FILE *symbol_file) { + output_ = symbol_file; + + // Load the OMAP information, and disable auto-translation of addresses in + // preference of doing it ourselves. + OmapData omap_data; + if (!GetOmapDataAndDisableTranslation(session_, &omap_data)) + return false; + BuildImageMap(omap_data, &image_map_); + + bool ret = PrintPDBInfo(); + // This is not a critical piece of the symbol file. + PrintPEInfo(); + ret = ret && + PrintSourceFiles() && + PrintFunctions() && + PrintFrameData(); + + output_ = NULL; + return ret; +} + +void PDBSourceLineWriter::Close() { + if (session_ != nullptr) { + session_.Release(); + } +} + +bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { + if (!info) { + return false; + } + + info->debug_file.clear(); + info->debug_identifier.clear(); + info->cpu.clear(); + + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) { + return false; + } + + DWORD machine_type; + // get_machineType can return S_FALSE. + if (global->get_machineType(&machine_type) == S_OK) { + // The documentation claims that get_machineType returns a value from + // the CV_CPU_TYPE_e enumeration, but that's not the case. + // Instead, it returns one of the IMAGE_FILE_MACHINE values as + // defined here: + // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx + info->cpu = FileHeaderMachineToCpuString(static_cast(machine_type)); + } else { + // Unexpected, but handle gracefully. + info->cpu = L"unknown"; + } + + // DWORD* and int* are not compatible. This is clean and avoids a cast. + DWORD age; + if (FAILED(global->get_age(&age))) { + return false; + } + + bool uses_guid; + if (!UsesGUID(&uses_guid)) { + return false; + } + + if (uses_guid) { + GUID guid; + if (FAILED(global->get_guid(&guid))) { + return false; + } + + info->debug_identifier = GenerateDebugIdentifier(age, guid); + } else { + DWORD signature; + if (FAILED(global->get_signature(&signature))) { + return false; + } + + info->debug_identifier = GenerateDebugIdentifier(age, signature); + } + + CComBSTR debug_file_string; + if (FAILED(global->get_symbolsFileName(&debug_file_string))) { + return false; + } + info->debug_file = + WindowsStringUtils::GetBaseName(wstring(debug_file_string)); + + return true; +} + +bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { + if (!info) { + return false; + } + + if (code_file_.empty() && !FindPEFile()) { + fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); + return false; + } + + return ReadPEInfo(code_file_, info); +} + +bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { + if (!uses_guid) + return false; + + CComPtr global; + if (FAILED(session_->get_globalScope(&global))) + return false; + + GUID guid; + if (FAILED(global->get_guid(&guid))) + return false; + + DWORD signature; + if (FAILED(global->get_signature(&signature))) + return false; + + // There are two possibilities for guid: either it's a real 128-bit GUID + // as identified in a code module by a new-style CodeView record, or it's + // a 32-bit signature (timestamp) as identified by an old-style record. + // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h. + // + // Because DIA doesn't provide a way to directly determine whether a module + // uses a GUID or a 32-bit signature, this code checks whether the first 32 + // bits of guid are the same as the signature, and if the rest of guid is + // zero. If so, then with a pretty high degree of certainty, there's an + // old-style CodeView record in use. This method will only falsely find an + // an old-style CodeView record if a real 128-bit GUID has its first 32 + // bits set the same as the module's signature (timestamp) and the rest of + // the GUID is set to 0. This is highly unlikely. + + GUID signature_guid = {signature}; // 0-initializes other members + *uses_guid = !IsEqualGUID(guid, signature_guid); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h new file mode 100644 index 0000000000..c0adf29f24 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h @@ -0,0 +1,226 @@ +// 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 COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ +#define COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ + +#include + +#include +#include + +#include "common/windows/module_info.h" +#include "common/windows/omap.h" + +struct IDiaEnumLineNumbers; +struct IDiaSession; +struct IDiaSymbol; + +namespace google_breakpad { + +using std::wstring; +using std::unordered_map; + +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); + + // Closes the current pdb file and its associated resources. + void Close(); + + // Sets the code file full path. This is optional for 32-bit modules. It is + // also optional for 64-bit modules when there is an executable file stored + // in the same directory as the PDB file. It is only required for 64-bit + // modules when the executable file is not in the same location as the PDB + // file and it must be called after Open() and before WriteMap(). + // If Open() was called for an executable file, then it is an error to call + // SetCodeFile() with a different file path and it will return false. + bool SetCodeFile(const wstring &exe_file); + + // Writes a Breakpad symbol file from the current pdb file to |symbol_file|. + // Returns true on success. + bool WriteSymbols(FILE *symbol_file); + + // Retrieves information about the module's debugging file. Returns + // true on success and false on failure. + bool GetModuleInfo(PDBModuleInfo *info); + + // Retrieves information about the module's PE file. Returns + // true on success and false on failure. + bool GetPEInfo(PEModuleInfo *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. + // block can be the same object as function, or it can be a reference to a + // code block that is lexically part of this function, but resides at a + // separate address. If has_multiple_symbols is true, this function's + // instructions correspond to multiple symbols. Returns true on success. + bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block, + bool has_multiple_symbols); + + // 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. For x86 data stored in + // .pdb files. Returns true on success. + bool PrintFrameDataUsingPDB(); + + // Outputs all of the frame information necessary to construct stack + // backtraces in the absence of frame pointers. For x64 data stored in + // .exe, .dll files. Returns true on success. + bool PrintFrameDataUsingEXE(); + + // 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. If + // has_multiple_symbols is true, the symbol corresponds to a code address and + // the instructions correspond to multiple symbols. + bool PrintCodePublicSymbol(IDiaSymbol *symbol, bool has_multiple_symbols); + + // Outputs a line identifying the PDB file that is being dumped, along with + // its uuid and age. + bool PrintPDBInfo(); + + // Outputs a line identifying the PE file corresponding to the PDB + // file that is being dumped, along with its code identifier, + // which consists of its timestamp and file size. + bool PrintPEInfo(); + + // Returns true if this filename has already been seen, + // and an ID is stored for it, or false if it has not. + bool FileIDIsCached(const wstring &file) { + return unique_files_.find(file) != unique_files_.end(); + } + + // Cache this filename and ID for later reuse. + void CacheFileID(const wstring &file, DWORD id) { + unique_files_[file] = id; + } + + // Store this ID in the cache as a duplicate for this filename. + void StoreDuplicateFileID(const wstring &file, DWORD id) { + unordered_map::iterator iter = unique_files_.find(file); + if (iter != unique_files_.end()) { + // map this id to the previously seen one + file_ids_[id] = iter->second; + } + } + + // Given a file's unique ID, return the ID that should be used to + // reference it. There may be multiple files with identical filenames + // but different unique IDs. The cache attempts to coalesce these into + // one ID per unique filename. + DWORD GetRealFileID(DWORD id) { + unordered_map::iterator iter = file_ids_.find(id); + if (iter == file_ids_.end()) + return id; + return iter->second; + } + + // Find the PE file corresponding to the loaded PDB file, and + // set the code_file_ member. Returns false on failure. + bool FindPEFile(); + + // 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 filename of the PE file corresponding to the currently-open + // pdb file. + wstring code_file_; + + // The session for the currently-open pdb file. + CComPtr session_; + + // The current output file for this WriteMap invocation. + FILE *output_; + + // There may be many duplicate filenames with different IDs. + // This maps from the DIA "unique ID" to a single ID per unique + // filename. + unordered_map file_ids_; + // This maps unique filenames to file IDs. + unordered_map unique_files_; + + // This is used for calculating post-transform symbol addresses and lengths. + ImageMap image_map_; + + // Disallow copy ctor and operator= + PDBSourceLineWriter(const PDBSourceLineWriter&); + void operator=(const PDBSourceLineWriter&); +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.cc new file mode 100644 index 0000000000..cb6cc71396 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2019, 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 "common/windows/pe_source_line_writer.h" + +#include "common/windows/pe_util.h" + +namespace google_breakpad { +PESourceLineWriter::PESourceLineWriter(const wstring& pe_file) : + pe_file_(pe_file) { +} + +PESourceLineWriter::~PESourceLineWriter() { +} + +bool PESourceLineWriter::WriteSymbols(FILE* symbol_file) { + PDBModuleInfo module_info; + if (!GetModuleInfo(&module_info)) { + return false; + } + // Hard-code "windows" for the OS because that's the only thing that makes + // sense for PDB files. (This might not be strictly correct for Windows CE + // support, but we don't care about that at the moment.) + fprintf(symbol_file, "MODULE windows %ws %ws %ws\n", + module_info.cpu.c_str(), module_info.debug_identifier.c_str(), + module_info.debug_file.c_str()); + + PEModuleInfo pe_info; + if (!GetPEInfo(&pe_info)) { + return false; + } + fprintf(symbol_file, "INFO CODE_ID %ws %ws\n", + pe_info.code_identifier.c_str(), + pe_info.code_file.c_str()); + + if (!PrintPEFrameData(pe_file_, symbol_file)) { + return false; + } + + return true; +} + +bool PESourceLineWriter::GetModuleInfo(PDBModuleInfo* info) { + return ReadModuleInfo(pe_file_, info); +} + +bool PESourceLineWriter::GetPEInfo(PEModuleInfo* info) { + return ReadPEInfo(pe_file_, info); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.h b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.h new file mode 100644 index 0000000000..2bf1d4fd2b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_source_line_writer.h @@ -0,0 +1,69 @@ +// Copyright (c) 2019, 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 COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ +#define COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ + +#include + +#include "common/basictypes.h" +#include "common/windows/module_info.h" + +namespace google_breakpad { + +using std::wstring; + +// PESourceLineWriter uses a pe file produced by Visual C++ to output +// a line/address map for use with BasicSourceLineResolver. +// NOTE: Only supports PE32+ format, ie. a 64bit PE file. +class PESourceLineWriter { +public: + explicit PESourceLineWriter(const wstring& pe_file); + ~PESourceLineWriter(); + + // Writes Breakpad symbols from the pe file to |symbol_file|. + // Returns true on success. + bool WriteSymbols(FILE* symbol_file); + + // Retrieves information about the module. Returns true on success. + bool GetModuleInfo(PDBModuleInfo* info); + + // Retrieves information about the module's PE file. Returns + // true on success. + bool GetPEInfo(PEModuleInfo* info); + +private: + const wstring pe_file_; + + DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter); +}; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_PE_SOURCE_LINE_WRITER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.cc new file mode 100644 index 0000000000..6fa63fa3b5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.cc @@ -0,0 +1,407 @@ +// Copyright (c) 2019, 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 "pe_util.h" + +#include +#include +#include +#include + +#include + +#include "common/windows/string_utils-inl.h" +#include "common/windows/guid_string.h" + +namespace { + +/* + * Not defined in WinNT.h for some reason. Definitions taken from: + * http://uninformed.org/index.cgi?v=4&a=1&p=13 + * + */ +typedef unsigned char UBYTE; + +#if !defined(_WIN64) +#define UNW_FLAG_EHANDLER 0x01 +#define UNW_FLAG_UHANDLER 0x02 +#define UNW_FLAG_CHAININFO 0x04 +#endif + +union UnwindCode { + struct { + UBYTE offset_in_prolog; + UBYTE unwind_operation_code : 4; + UBYTE operation_info : 4; + }; + USHORT frame_offset; +}; + +enum UnwindOperationCodes { + UWOP_PUSH_NONVOL = 0, /* info == register number */ + UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */ + UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */ + UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ + UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */ + UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */ + // XXX: these are missing from MSDN! + // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm + UWOP_SAVE_XMM, + UWOP_SAVE_XMM_FAR, + UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */ + UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */ + UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */ +}; + +// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx +// Note: some fields removed as we don't use them. +struct UnwindInfo { + UBYTE version : 3; + UBYTE flags : 5; + UBYTE size_of_prolog; + UBYTE count_of_codes; + UBYTE frame_register : 4; + UBYTE frame_offset : 4; + UnwindCode unwind_code[1]; +}; + +struct CV_INFO_PDB70 { + ULONG cv_signature; + GUID signature; + ULONG age; + CHAR pdb_filename[ANYSIZE_ARRAY]; +}; + +#define CV_SIGNATURE_RSDS 'SDSR' + +// A helper class to scope a PLOADED_IMAGE. +class AutoImage { +public: + explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} + ~AutoImage() { + if (img_) + ImageUnload(img_); + } + + operator PLOADED_IMAGE() { return img_; } + PLOADED_IMAGE operator->() { return img_; } + +private: + PLOADED_IMAGE img_; +}; +} // namespace + +namespace google_breakpad { + +using std::unique_ptr; +using google_breakpad::GUIDString; + +bool ReadModuleInfo(const wstring & pe_file, PDBModuleInfo * info) { + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to load %s\n", img_file.c_str()); + return false; + } + + info->cpu = FileHeaderMachineToCpuString( + img->FileHeader->FileHeader.Machine); + + PIMAGE_OPTIONAL_HEADER64 optional_header = + &(reinterpret_cast(img->FileHeader))->OptionalHeader; + + // Search debug directories for a guid signature & age + DWORD debug_rva = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + DWORD debug_size = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + PIMAGE_DEBUG_DIRECTORY debug_directories = + static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + debug_rva, + &img->LastRvaSection)); + + for (DWORD i = 0; i < debug_size / sizeof(*debug_directories); i++) { + if (debug_directories[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW || + debug_directories[i].SizeOfData < sizeof(CV_INFO_PDB70)) { + continue; + } + + struct CV_INFO_PDB70* cv_info = static_cast(ImageRvaToVa( + img->FileHeader, + img->MappedAddress, + debug_directories[i].AddressOfRawData, + &img->LastRvaSection)); + if (cv_info->cv_signature != CV_SIGNATURE_RSDS) { + continue; + } + + info->debug_identifier = GenerateDebugIdentifier(cv_info->age, + cv_info->signature); + + // This code assumes that the pdb_filename is stored as ASCII without + // multibyte characters, but it's not clear if that's true. + size_t debug_file_length = strnlen_s(cv_info->pdb_filename, MAX_PATH); + if (debug_file_length < 0 || debug_file_length >= MAX_PATH) { + fprintf(stderr, "PE debug directory is corrupt.\n"); + return false; + } + std::string debug_file(cv_info->pdb_filename, debug_file_length); + if (!WindowsStringUtils::safe_mbstowcs(debug_file, &info->debug_file)) { + fprintf(stderr, "PDB filename '%s' contains unrecognized characters.\n", + debug_file.c_str()); + return false; + } + info->debug_file = WindowsStringUtils::GetBaseName(info->debug_file); + + return true; + } + + fprintf(stderr, "Image is missing debug information.\n"); + return false; +} + +bool ReadPEInfo(const wstring & pe_file, PEModuleInfo * info) { + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to open PE file: %S\n", pe_file.c_str()); + return false; + } + + info->code_file = WindowsStringUtils::GetBaseName(pe_file); + + // The date and time that the file was created by the linker. + DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; + // The size of the file in bytes, including all headers. + DWORD SizeOfImage = 0; + PIMAGE_OPTIONAL_HEADER64 opt = + &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; + if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // 64-bit PE file. + SizeOfImage = opt->SizeOfImage; + } + else { + // 32-bit PE file. + SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; + } + wchar_t code_identifier[32]; + swprintf(code_identifier, + sizeof(code_identifier) / sizeof(code_identifier[0]), + L"%08X%X", TimeDateStamp, SizeOfImage); + info->code_identifier = code_identifier; + + return true; +} + +bool PrintPEFrameData(const wstring & pe_file, FILE * out_file) +{ + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + string img_file; + if (!WindowsStringUtils::safe_wcstombs(pe_file, &img_file)) { + fprintf(stderr, "Image path '%S' contains unrecognized characters.\n", + pe_file.c_str()); + return false; + } + + AutoImage img(ImageLoad((PSTR)img_file.c_str(), NULL)); + if (!img) { + fprintf(stderr, "Failed to load %s\n", img_file.c_str()); + return false; + } + PIMAGE_OPTIONAL_HEADER64 optional_header = + &(reinterpret_cast(img->FileHeader))->OptionalHeader; + if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + fprintf(stderr, "Not a PE32+ image\n"); + return false; + } + + // Read Exception Directory + DWORD exception_rva = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; + DWORD exception_size = optional_header-> + DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; + PIMAGE_RUNTIME_FUNCTION_ENTRY funcs = + static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + exception_rva, + &img->LastRvaSection)); + for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) { + DWORD unwind_rva = funcs[i].UnwindInfoAddress; + // handle chaining + while (unwind_rva & 0x1) { + unwind_rva ^= 0x1; + PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = + static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + unwind_rva, + &img->LastRvaSection)); + unwind_rva = chained_func->UnwindInfoAddress; + } + + UnwindInfo *unwind_info = static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + unwind_rva, + &img->LastRvaSection)); + + DWORD stack_size = 8; // minimal stack size is 8 for RIP + DWORD rip_offset = 8; + do { + for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) { + UnwindCode *unwind_code = &unwind_info->unwind_code[c]; + switch (unwind_code->unwind_operation_code) { + case UWOP_PUSH_NONVOL: { + stack_size += 8; + break; + } + case UWOP_ALLOC_LARGE: { + if (unwind_code->operation_info == 0) { + c++; + if (c < unwind_info->count_of_codes) + stack_size += (unwind_code + 1)->frame_offset * 8; + } + else { + c += 2; + if (c < unwind_info->count_of_codes) + stack_size += (unwind_code + 1)->frame_offset | + ((unwind_code + 2)->frame_offset << 16); + } + break; + } + case UWOP_ALLOC_SMALL: { + stack_size += unwind_code->operation_info * 8 + 8; + break; + } + case UWOP_SET_FPREG: + case UWOP_SAVE_XMM: + case UWOP_SAVE_XMM_FAR: + break; + case UWOP_SAVE_NONVOL: + case UWOP_SAVE_XMM128: { + c++; // skip slot with offset + break; + } + case UWOP_SAVE_NONVOL_FAR: + case UWOP_SAVE_XMM128_FAR: { + c += 2; // skip 2 slots with offset + break; + } + case UWOP_PUSH_MACHFRAME: { + if (unwind_code->operation_info) { + stack_size += 88; + } + else { + stack_size += 80; + } + rip_offset += 80; + break; + } + } + } + if (unwind_info->flags & UNW_FLAG_CHAININFO) { + PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = + reinterpret_cast( + (unwind_info->unwind_code + + ((unwind_info->count_of_codes + 1) & ~1))); + + unwind_info = static_cast( + ImageRvaToVa(img->FileHeader, + img->MappedAddress, + chained_func->UnwindInfoAddress, + &img->LastRvaSection)); + } + else { + unwind_info = NULL; + } + } while (unwind_info); + fprintf(out_file, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n", + funcs[i].BeginAddress, + funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); + fprintf(out_file, "STACK CFI %lx .cfa: $rsp %lu +\n", + funcs[i].BeginAddress, stack_size); + } + + return true; +} + +wstring GenerateDebugIdentifier(DWORD age, GUID signature) +{ + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t age_string[9]; + swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]), + L"%x", age); + + // remove when VC++7.1 is no longer supported + age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0'; + + wstring debug_identifier = GUIDString::GUIDToSymbolServerWString(&signature); + debug_identifier.append(age_string); + + return debug_identifier; +} + +wstring GenerateDebugIdentifier(DWORD age, DWORD signature) +{ + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + wchar_t identifier_string[17]; + swprintf(identifier_string, + sizeof(identifier_string) / sizeof(identifier_string[0]), + L"%08X%x", signature, age); + + // remove when VC++7.1 is no longer supported + identifier_string[sizeof(identifier_string) / + sizeof(identifier_string[0]) - 1] = L'\0'; + + return wstring(identifier_string); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.h b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.h new file mode 100644 index 0000000000..634ba29343 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/pe_util.h @@ -0,0 +1,78 @@ +// Copyright (c) 2019, 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 COMMON_WINDOWS_PE_UTIL_H_ +#define COMMON_WINDOWS_PE_UTIL_H_ + +#include + +#include "common/windows/module_info.h" + +namespace google_breakpad { + +using std::wstring; + +// Reads |pe_file| and populates |info|. Returns true on success. +// Only supports PE32+ format, ie. a 64bit PE file. +// Will fail if |pe_file| does not contain a valid CodeView record. +bool ReadModuleInfo(const wstring& pe_file, PDBModuleInfo* info); + +// Reads |pe_file| and populates |info|. Returns true on success. +bool ReadPEInfo(const wstring& pe_file, PEModuleInfo* info); + +// Reads |pe_file| and prints frame data (aka. unwind info) to |out_file|. +// Only supports PE32+ format, ie. a 64bit PE file. +bool PrintPEFrameData(const wstring& pe_file, FILE* out_file); + +// Combines a GUID |signature| and DWORD |age| to create a Breakpad debug +// identifier. +wstring GenerateDebugIdentifier(DWORD age, GUID signature); + +// Combines a DWORD |signature| and DWORD |age| to create a Breakpad debug +// identifier. +wstring GenerateDebugIdentifier(DWORD age, DWORD signature); + +// Converts |machine| enum value to the corresponding string used by Breakpad. +// The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h. +constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) { + switch (machine) { + case IMAGE_FILE_MACHINE_I386: { + return L"x86"; + } + case IMAGE_FILE_MACHINE_IA64: + case IMAGE_FILE_MACHINE_AMD64: { + return L"x86_64"; + } + default: { return L"unknown"; } + } +} + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_PE_UTIL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h new file mode 100644 index 0000000000..9b63607268 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h @@ -0,0 +1,142 @@ +// 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 +#include + +#include + +// 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); + + // The inverse of safe_mbstowcs. + static bool safe_wcstombs(const wstring &wcs, string *mbs); + + // 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_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc new file mode 100644 index 0000000000..272800035c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc @@ -0,0 +1,133 @@ +// 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 +#include + +#include "common/windows/string_utils-inl.h" + +namespace google_breakpad { + +// static +wstring WindowsStringUtils::GetBaseName(const wstring &filename) { + wstring base_name(filename); + size_t slash_pos = base_name.find_last_of(L"/\\"); + if (slash_pos != wstring::npos) { + base_name.erase(0, slash_pos + 1); + } + return base_name; +} + +// static +bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { + assert(wcs); + + // First, determine the length of the destination buffer. + size_t wcs_length; + +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) { + return false; + } + assert(wcs_length > 0); +#else // _MSC_VER >= 1400 + if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) == (size_t)-1) { + return false; + } + + // Leave space for the 0-terminator. + ++wcs_length; +#endif // _MSC_VER >= 1400 + + std::vector wcs_v(wcs_length); + + // Now, convert. +#if _MSC_VER >= 1400 // MSVC 2005/8 + if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(), + _TRUNCATE)) != 0) { + return false; + } +#else // _MSC_VER >= 1400 + if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) == (size_t)-1) { + return false; + } + + // Ensure presence of 0-terminator. + wcs_v[wcs_length - 1] = '\0'; +#endif // _MSC_VER >= 1400 + + *wcs = &wcs_v[0]; + return true; +} + +// static +bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) { + assert(mbs); + + // First, determine the length of the destination buffer. + size_t mbs_length; + +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) { + return false; + } + assert(mbs_length > 0); +#else // _MSC_VER >= 1400 + if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) == (size_t)-1) { + return false; + } + + // Leave space for the 0-terminator. + ++mbs_length; +#endif // _MSC_VER >= 1400 + + std::vector mbs_v(mbs_length); + + // Now, convert. +#if _MSC_VER >= 1400 // MSVC 2005/8 + if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(), + _TRUNCATE)) != 0) { + return false; + } +#else // _MSC_VER >= 1400 + if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) == (size_t)-1) { + return false; + } + + // Ensure presence of 0-terminator. + mbs_v[mbs_length - 1] = '\0'; +#endif // _MSC_VER >= 1400 + + *mbs = &mbs_v[0]; + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.cc new file mode 100644 index 0000000000..30c663ed37 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.cc @@ -0,0 +1,155 @@ +#include "common/windows/symbol_collector_client.h" + +#include + +#include + +#include "common/windows/http_upload.h" + +namespace google_breakpad { + + // static + bool SymbolCollectorClient::CreateUploadUrl( + wstring& api_url, + wstring& api_key, + UploadUrlResponse *uploadUrlResponse) { + wstring url = api_url + + L"/v1/uploads:create" + L"?key=" + api_key; + wstring response; + int response_code; + + if (!HTTPUpload::SendSimplePostRequest( + url, + L"", + L"", + NULL, + &response, + &response_code)) { + wprintf(L"Failed to create upload url.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + + // Note camel-case rather than underscores. + std::wregex upload_url_regex(L"\"uploadUrl\": \"([^\"]+)\""); + std::wregex upload_key_regex(L"\"uploadKey\": \"([^\"]+)\""); + + std::wsmatch upload_url_match; + if (!std::regex_search(response, upload_url_match, upload_url_regex) || + upload_url_match.size() != 2) { + wprintf(L"Failed to parse create url response."); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + wstring upload_url = upload_url_match[1].str(); + + std::wsmatch upload_key_match; + if (!std::regex_search(response, upload_key_match, upload_key_regex) || + upload_key_match.size() != 2) { + wprintf(L"Failed to parse create url response."); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + wstring upload_key = upload_key_match[1].str(); + + uploadUrlResponse->upload_url = upload_url; + uploadUrlResponse->upload_key = upload_key; + return true; + } + + // static + CompleteUploadResult SymbolCollectorClient::CompleteUpload( + wstring& api_url, + wstring& api_key, + const wstring& upload_key, + const wstring& debug_file, + const wstring& debug_id) { + wstring url = api_url + + L"/v1/uploads/" + upload_key + L":complete" + L"?key=" + api_key; + wstring body = + L"{ symbol_id: {" + L"debug_file: \"" + debug_file + L"\", " + L"debug_id: \"" + debug_id + L"\" " + L"} }"; + wstring response; + int response_code; + + if (!HTTPUpload::SendSimplePostRequest( + url, + body, + L"application/json", + NULL, + &response, + &response_code)) { + wprintf(L"Failed to complete upload.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + + std::wregex result_regex(L"\"result\": \"([^\"]+)\""); + std::wsmatch result_match; + if (!std::regex_search(response, result_match, result_regex) || + result_match.size() != 2) { + wprintf(L"Failed to parse complete upload response."); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + wstring result = result_match[1].str(); + + if (result.compare(L"DUPLICATE_DATA") == 0) { + return CompleteUploadResult::DuplicateData; + } + + return CompleteUploadResult::Ok; + } + + // static + SymbolStatus SymbolCollectorClient::CheckSymbolStatus( + wstring& api_url, + wstring& api_key, + const wstring& debug_file, + const wstring& debug_id) { + wstring response; + int response_code; + wstring url = api_url + + L"/v1/symbols/" + debug_file + L"/" + debug_id + L":checkStatus" + L"?key=" + api_key; + + if (!HTTPUpload::SendGetRequest( + url, + NULL, + &response, + &response_code)) { + wprintf(L"Failed to check symbol status.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + + std::wregex status_regex(L"\"status\": \"([^\"]+)\""); + std::wsmatch status_match; + if (!std::regex_search(response, status_match, status_regex) || + status_match.size() != 2) { + wprintf(L"Failed to parse check symbol status response."); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + wstring status = status_match[1].str(); + + return (status.compare(L"FOUND") == 0) ? + SymbolStatus::Found : + SymbolStatus::Missing; + } + +} // namespace google_breakpad \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.h b/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.h new file mode 100644 index 0000000000..30e0cb3230 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/windows/symbol_collector_client.h @@ -0,0 +1,89 @@ +// Copyright (c) 2019, 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 COMMON_WINDOWS_SYMBOL_COLLECTOR_CLIENT_H_ +#define COMMON_WINDOWS_SYMBOL_COLLECTOR_CLIENT_H_ + +#include + +namespace google_breakpad { + + using std::wstring; + + struct UploadUrlResponse { + // URL at which to HTTP PUT symbol file. + wstring upload_url; + // Unique key used to complete upload of symbol file. + wstring upload_key; + }; + + enum SymbolStatus { + Found, + Missing, + Unknown + }; + + enum CompleteUploadResult { + Ok, + DuplicateData, + Error + }; + + // Client to interact with sym-upload-v2 API server via HTTP/REST. + class SymbolCollectorClient { + public: + // Returns a URL at which a symbol file can be HTTP PUT without + // authentication, along with an upload key that can be used to + // complete the upload process with CompleteUpload. + static bool CreateUploadUrl( + wstring& api_url, + wstring& api_key, + UploadUrlResponse *uploadUrlResponse); + + // Notify the API that symbol file upload is finished and its contents + // are ready to be read and/or used for further processing. + static CompleteUploadResult CompleteUpload( + wstring& api_url, + wstring& api_key, + const wstring& upload_key, + const wstring& debug_file, + const wstring& debug_id); + + // Returns whether or not a symbol file corresponding to the debug_file/ + // debug_id pair is already present in symbol storage. + static SymbolStatus CheckSymbolStatus( + wstring& api_url, + wstring& api_key, + const wstring& debug_file, + const wstring& debug_id); + }; + +} // namespace google_breakpad + +#endif // COMMON_WINDOWS_SYMBOL_COLLECTOR_CLIENT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/config.h.in b/toolkit/crashreporter/google-breakpad/src/config.h.in new file mode 100644 index 0000000000..0553a24b34 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/config.h.in @@ -0,0 +1,94 @@ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `arc4random' function. */ +#undef HAVE_ARC4RANDOM + +/* Define to 1 if you have the header file. */ +#undef HAVE_A_OUT_H + +/* define if the compiler supports basic C++11 syntax */ +#undef HAVE_CXX11 + +/* Define to 1 if you have the `getcontext' function. */ +#undef HAVE_GETCONTEXT + +/* Define to 1 if you have the `getrandom' function. */ +#undef HAVE_GETRANDOM + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RANDOM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Fallback definition for old systems */ +#undef O_CLOEXEC + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/breakpad_types.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/breakpad_types.h new file mode 100644 index 0000000000..d8828043ff --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/breakpad_types.h @@ -0,0 +1,68 @@ +/* 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 uintN_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__ + +#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \ + !defined(__STDC_FORMAT_MACROS) +#error "inttypes.h has already been included before this header file, but " +#error "without __STDC_FORMAT_MACROS defined." +#endif + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ +#include + +typedef struct { + uint64_t high; + uint64_t low; +} uint128_struct; + +typedef uint64_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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_amd64.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_amd64.h new file mode 100644 index 0000000000..4256706d77 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_amd64.h @@ -0,0 +1,235 @@ +/* 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 { + uint16_t control_word; + uint16_t status_word; + uint8_t tag_word; + uint8_t reserved1; + uint16_t error_opcode; + uint32_t error_offset; + uint16_t error_selector; + uint16_t reserved2; + uint32_t data_offset; + uint16_t data_selector; + uint16_t reserved3; + uint32_t mx_csr; + uint32_t mx_csr_mask; + uint128_struct float_registers[8]; + uint128_struct xmm_registers[16]; + uint8_t reserved4[96]; +} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */ + +#define MD_CONTEXT_AMD64_VR_COUNT 26 + +typedef struct { + /* + * Register parameter home addresses. + */ + uint64_t p1_home; + uint64_t p2_home; + uint64_t p3_home; + uint64_t p4_home; + uint64_t p5_home; + uint64_t p6_home; + + /* The next field determines the layout of the structure, and which parts + * of it are populated */ + uint32_t context_flags; + uint32_t mx_csr; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t cs; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */ + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + + /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t ss; + uint32_t eflags; + + /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rsp; + + /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rip; + + /* The next set of registers are included with + * MD_CONTEXT_AMD64_FLOATING_POINT + */ + union { + MDXmmSaveArea32AMD64 flt_save; + struct { + uint128_struct header[2]; + uint128_struct legacy[8]; + uint128_struct xmm0; + uint128_struct xmm1; + uint128_struct xmm2; + uint128_struct xmm3; + uint128_struct xmm4; + uint128_struct xmm5; + uint128_struct xmm6; + uint128_struct xmm7; + uint128_struct xmm8; + uint128_struct xmm9; + uint128_struct xmm10; + uint128_struct xmm11; + uint128_struct xmm12; + uint128_struct xmm13; + uint128_struct xmm14; + uint128_struct xmm15; + } sse_registers; + }; + + uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT]; + uint64_t vector_control; + + /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t debug_control; + uint64_t last_branch_to_rip; + uint64_t last_branch_from_rip; + uint64_t last_exception_to_rip; + uint64_t last_exception_from_rip; + +} MDRawContextAMD64; /* CONTEXT */ + +/* For (MDRawContextAMD64).context_flags. These values indicate the type of + * context stored in the structure. The high 24 bits identify the CPU, the + * low 8 bits identify the type of context saved. */ +#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */ +#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 */ +#define MD_CONTEXT_AMD64_XSTATE (MD_CONTEXT_AMD64 | 0x00000040) + /* CONTEXT_XSTATE */ + +/* 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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm.h new file mode 100644 index 0000000000..6a71138337 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm.h @@ -0,0 +1,151 @@ +/* Copyright (c) 2009, 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 ARM. 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 that all members are aligned on their natural boundaries. + * 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. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Julian Seward + */ + +/* + * ARM support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ + +#define MD_FLOATINGSAVEAREA_ARM_FPR_COUNT 32 +#define MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT 8 + +/* + * Note that these structures *do not* map directly to the CONTEXT + * structure defined in WinNT.h in the Windows Mobile SDK. That structure + * does not accomodate VFPv3, and I'm unsure if it was ever used in the + * wild anyway, as Windows CE only seems to produce "cedumps" which + * are not exactly minidumps. + */ +typedef struct { + uint64_t fpscr; /* FPU status register */ + + /* 32 64-bit floating point registers, d0 .. d31. */ + uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT]; + + /* Miscellaneous control words */ + uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT]; +} MDFloatingSaveAreaARM; + +#define MD_CONTEXT_ARM_GPR_COUNT 16 + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint32_t context_flags; + + /* 16 32-bit integer registers, r0 .. r15 + * Note the following fixed uses: + * r13 is the stack pointer + * r14 is the link register + * r15 is the program counter + */ + uint32_t iregs[MD_CONTEXT_ARM_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM float_save; + +} MDRawContextARM; + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARMRegisterNumbers { + MD_CONTEXT_ARM_REG_IOS_FP = 7, + MD_CONTEXT_ARM_REG_FP = 11, + MD_CONTEXT_ARM_REG_SP = 13, + MD_CONTEXT_ARM_REG_LR = 14, + MD_CONTEXT_ARM_REG_PC = 15 +}; + +/* For (MDRawContextARM).context_flags. These values indicate the type of + * context stored in the structure. */ +/* CONTEXT_ARM from the Windows CE 5.0 SDK. This value isn't correct + * because this bit can be used for flags. Presumably this value was + * never actually used in minidumps, but only in "CEDumps" which + * are a whole parallel minidump file format for Windows CE. + * Therefore, Breakpad defines its own value for ARM CPUs. + */ +#define MD_CONTEXT_ARM_OLD 0x00000040 +/* This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM 0x40000000 +#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002) +#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004) + +#define MD_CONTEXT_ARM_FULL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#define MD_CONTEXT_ARM_ALL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm64.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm64.h new file mode 100644 index 0000000000..a94962009e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_arm64.h @@ -0,0 +1,192 @@ +/* Copyright 2013 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 ARM. 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 that all members are aligned on their natural boundaries. + * 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. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Colin Blundell + */ + +/* + * ARM64 support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ + +#include "google_breakpad/common/breakpad_types.h" + +#define MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT 32 +#define MD_CONTEXT_ARM64_GPR_COUNT 33 + +typedef struct { + /* 32 128-bit floating point registers, d0 .. d31. */ + uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT]; + + uint32_t fpcr; /* FPU control register */ + uint32_t fpsr; /* FPU status register */ +} MDFloatingSaveAreaARM64; + +/* For (MDRawContextARM64).context_flags. These values indicate the type of + * context stored in the structure. */ +#define MD_CONTEXT_ARM64 0x00400000 +#define MD_CONTEXT_ARM64_CONTROL (MD_CONTEXT_ARM64 | 0x00000001) +#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002) +#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004) +#define MD_CONTEXT_ARM64_DEBUG (MD_CONTEXT_ARM64 | 0x00000008) +#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_CONTROL | \ + MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) +#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_FULL | MD_CONTEXT_ARM64_DEBUG) + +/* Use the same 32-bit alignment when accessing these structures from 64-bit + * code as is used natively in 32-bit code. */ +#pragma pack(push, 4) + +typedef struct { + /* Determines which fields of this struct are populated */ + uint32_t context_flags; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* 33 64-bit integer registers, x0 .. x31 + the PC + * Note the following fixed uses: + * x29 is the frame pointer + * x30 is the link register + * x31 is the stack pointer + * The PC is effectively x32. + */ + uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT]; + + /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM64 float_save; + + uint32_t bcr[8]; + uint64_t bvr[8]; + uint32_t wcr[2]; + uint64_t wvr[2]; +} MDRawContextARM64; + +typedef struct { + uint32_t fpsr; /* FPU status register */ + uint32_t fpcr; /* FPU control register */ + + /* 32 128-bit floating point registers, d0 .. d31. */ + uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT]; +} MDFloatingSaveAreaARM64_Old; + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint64_t context_flags; + + /* 33 64-bit integer registers, x0 .. x31 + the PC + * Note the following fixed uses: + * x29 is the frame pointer + * x30 is the link register + * x31 is the stack pointer + * The PC is effectively x32. + */ + uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM64_Old float_save; + +} MDRawContextARM64_Old; + +#pragma pack(pop) + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARM64RegisterNumbers { + MD_CONTEXT_ARM64_REG_FP = 29, + MD_CONTEXT_ARM64_REG_LR = 30, + MD_CONTEXT_ARM64_REG_SP = 31, + MD_CONTEXT_ARM64_REG_PC = 32 +}; + +/* For (MDRawContextARM64_Old).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_ARM64_OLD is Breakpad-defined. + * This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM64_OLD 0x80000000 +#define MD_CONTEXT_ARM64_INTEGER_OLD (MD_CONTEXT_ARM64_OLD | 0x00000002) +#define MD_CONTEXT_ARM64_FLOATING_POINT_OLD (MD_CONTEXT_ARM64_OLD | 0x00000004) + +#define MD_CONTEXT_ARM64_FULL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \ + MD_CONTEXT_ARM64_FLOATING_POINT_OLD) + +#define MD_CONTEXT_ARM64_ALL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \ + MD_CONTEXT_ARM64_FLOATING_POINT_OLD) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_mips.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_mips.h new file mode 100644 index 0000000000..f4e2b5891c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_mips.h @@ -0,0 +1,176 @@ +/* Copyright (c) 2013, 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 MIPS. 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 that all members are aligned on their natural boundaries. + * 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. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Chris Dearman + */ + +/* + * MIPS support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ + +#define MD_CONTEXT_MIPS_GPR_COUNT 32 +#define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32 +#define MD_CONTEXT_MIPS_DSP_COUNT 3 + +/* + * Note that these structures *do not* map directly to the CONTEXT + * structure defined in WinNT.h in the Windows Mobile SDK. That structure + * does not accomodate VFPv3, and I'm unsure if it was ever used in the + * wild anyway, as Windows CE only seems to produce "cedumps" which + * are not exactly minidumps. + */ +typedef struct { + /* 32 64-bit floating point registers, f0..f31 */ + uint64_t regs[MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT]; + + uint32_t fpcsr; /* FPU status register. */ + uint32_t fir; /* FPU implementation register. */ +} MDFloatingSaveAreaMIPS; + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated. + */ + uint32_t context_flags; + uint32_t _pad0; + + /* 32 64-bit integer registers, r0..r31. + * Note the following fixed uses: + * r29 is the stack pointer. + * r31 is the return address. + */ + uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT]; + + /* multiply/divide result. */ + uint64_t mdhi, mdlo; + + /* DSP accumulators. */ + uint32_t hi[MD_CONTEXT_MIPS_DSP_COUNT]; + uint32_t lo[MD_CONTEXT_MIPS_DSP_COUNT]; + uint32_t dsp_control; + uint32_t _pad1; + + uint64_t epc; + uint64_t badvaddr; + uint32_t status; + uint32_t cause; + + /* The next field is included with MD_CONTEXT_MIPS_FLOATING_POINT. */ + MDFloatingSaveAreaMIPS float_save; + +} MDRawContextMIPS; + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDMIPSRegisterNumbers { + MD_CONTEXT_MIPS_REG_S0 = 16, + MD_CONTEXT_MIPS_REG_S1 = 17, + MD_CONTEXT_MIPS_REG_S2 = 18, + MD_CONTEXT_MIPS_REG_S3 = 19, + MD_CONTEXT_MIPS_REG_S4 = 20, + MD_CONTEXT_MIPS_REG_S5 = 21, + MD_CONTEXT_MIPS_REG_S6 = 22, + MD_CONTEXT_MIPS_REG_S7 = 23, + MD_CONTEXT_MIPS_REG_GP = 28, + MD_CONTEXT_MIPS_REG_SP = 29, + MD_CONTEXT_MIPS_REG_FP = 30, + MD_CONTEXT_MIPS_REG_RA = 31, +}; + +/* For (MDRawContextMIPS).context_flags. These values indicate the type of + * context stored in the structure. */ +/* CONTEXT_MIPS from the Windows CE 5.0 SDK. This value isn't correct + * because this bit can be used for flags. Presumably this value was + * never actually used in minidumps, but only in "CEDumps" which + * are a whole parallel minidump file format for Windows CE. + * Therefore, Breakpad defines its own value for MIPS CPUs. + */ +#define MD_CONTEXT_MIPS 0x00040000 +#define MD_CONTEXT_MIPS_INTEGER (MD_CONTEXT_MIPS | 0x00000002) +#define MD_CONTEXT_MIPS_FLOATING_POINT (MD_CONTEXT_MIPS | 0x00000004) +#define MD_CONTEXT_MIPS_DSP (MD_CONTEXT_MIPS | 0x00000008) + +#define MD_CONTEXT_MIPS_FULL (MD_CONTEXT_MIPS_INTEGER | \ + MD_CONTEXT_MIPS_FLOATING_POINT | \ + MD_CONTEXT_MIPS_DSP) + +#define MD_CONTEXT_MIPS_ALL (MD_CONTEXT_MIPS_INTEGER | \ + MD_CONTEXT_MIPS_FLOATING_POINT \ + MD_CONTEXT_MIPS_DSP) + +/** + * Breakpad defines for MIPS64 + */ +#define MD_CONTEXT_MIPS64 0x00080000 +#define MD_CONTEXT_MIPS64_INTEGER (MD_CONTEXT_MIPS64 | 0x00000002) +#define MD_CONTEXT_MIPS64_FLOATING_POINT (MD_CONTEXT_MIPS64 | 0x00000004) +#define MD_CONTEXT_MIPS64_DSP (MD_CONTEXT_MIPS64 | 0x00000008) + +#define MD_CONTEXT_MIPS64_FULL (MD_CONTEXT_MIPS64_INTEGER | \ + MD_CONTEXT_MIPS64_FLOATING_POINT | \ + MD_CONTEXT_MIPS64_DSP) + +#define MD_CONTEXT_MIPS64_ALL (MD_CONTEXT_MIPS64_INTEGER | \ + MD_CONTEXT_MIPS64_FLOATING_POINT \ + MD_CONTEXT_MIPS64_DSP) + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc.h new file mode 100644 index 0000000000..fcc85cd9b0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc.h @@ -0,0 +1,159 @@ +/* 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__ + +/* Use the same 32-bit alignment when accessing these structures from 64-bit + * code as is used natively in 32-bit code. */ +#pragma pack(push, 4) + +#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32 + +typedef struct { + /* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used + * here for precise sizing. */ + uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT]; + uint32_t fpscr_pad; + uint32_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. */ + uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT]; + uint128_struct save_vscr; /* Status/control */ + uint32_t save_pad5[4]; + uint32_t save_vrvalid; /* Indicates which vector registers are saved */ + uint32_t save_pad6[7]; +} MDVectorSaveAreaPPC; /* ppc_vector_state */ + + +#define MD_CONTEXT_PPC_GPR_COUNT 32 + +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. */ + uint32_t context_flags; + + uint32_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint32_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. */ + uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT]; + uint32_t cr; /* Condition */ + uint32_t xer; /* Integer (fiXed-point) exception */ + uint32_t lr; /* Link */ + uint32_t ctr; /* Count */ + uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */ + uint32_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 */ + +/* Indices into gpr for registers with a dedicated or conventional purpose. */ +enum MDPPCRegisterNumbers { + MD_CONTEXT_PPC_REG_SP = 1 +}; + +#pragma pack(pop) + +/* 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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h new file mode 100644 index 0000000000..61f4193865 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h @@ -0,0 +1,134 @@ +/* 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. */ + uint64_t context_flags; + + uint64_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint64_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. */ + uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT]; + uint64_t cr; /* Condition */ + uint64_t xer; /* Integer (fiXed-point) exception */ + uint64_t lr; /* Link */ + uint64_t ctr; /* Count */ + uint64_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 */ + +/* Indices into gpr for registers with a dedicated or conventional purpose. */ +enum MDPPC64RegisterNumbers { + MD_CONTEXT_PPC64_REG_SP = 1 +}; + +/* 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_PPC64 0x01000000 +#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001) +#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008) +#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020) + +#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE +#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \ + MD_CONTEXT_PPC64_FLOATING_POINT | \ + MD_CONTEXT_PPC64_VECTOR) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_sparc.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_sparc.h new file mode 100644 index 0000000000..95c08b1743 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_sparc.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 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 */ + uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT]; + + uint64_t filler; + uint64_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 + */ + uint32_t context_flags; + uint32_t flag_pad; + /* + * General register access (SPARC). + * Don't confuse definitions here with definitions in . + * 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) + */ + uint64_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 + */ + uint64_t ccr; + + uint64_t pc; /* Program Counter register (PC) */ + uint64_t npc; /* Next Program Counter register (nPC) */ + uint64_t y; /* Y register (Y) */ + + /* Address Space Identifier register (ASI) for SPARC V9 + * WIM for SPARC V7/V8 + */ + uint64_t asi; + + /* Floating-Point Registers State register (FPRS) for SPARC V9 + * TBR for for SPARC V7/V8 + */ + uint64_t fprs; + + /* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */ + MDFloatingSaveAreaSPARC float_save; + +} MDRawContextSPARC; /* CONTEXT_SPARC */ + +/* Indices into g_r for registers with a dedicated or conventional purpose. */ +enum MDSPARCRegisterNumbers { + MD_CONTEXT_SPARC_REG_SP = 14 +}; + +/* 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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_x86.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_x86.h new file mode 100644 index 0000000000..e09cb7cb52 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_cpu_x86.h @@ -0,0 +1,174 @@ +/* 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 { + uint32_t control_word; + uint32_t status_word; + uint32_t tag_word; + uint32_t error_offset; + uint32_t error_selector; + uint32_t data_offset; + uint32_t data_selector; + + /* register_area contains eight 80-bit (x87 "long double") quantities for + * floating-point registers %st0 (%mm0) through %st7 (%mm7). */ + uint8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE]; + uint32_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 */ + uint32_t context_flags; + + /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */ + uint32_t dr0; + uint32_t dr1; + uint32_t dr2; + uint32_t dr3; + uint32_t dr6; + uint32_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 */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */ + uint32_t edi; + uint32_t esi; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + + /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */ + uint32_t ebp; + uint32_t eip; + uint32_t cs; /* WinNT.h says "must be sanitized" */ + uint32_t eflags; /* WinNT.h says "must be sanitized" */ + uint32_t esp; + uint32_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." */ + uint8_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 24 bits identify the CPU, the + * low 8 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_XSTATE (MD_CONTEXT_X86 | 0x00000040) + /* CONTEXT_XSTATE */ + +#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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_fuchsia.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_fuchsia.h new file mode 100644 index 0000000000..f26a8a2ae0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_fuchsia.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2019, 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_fuchsia.h: A definition of exception codes for Fuchsia. + * + * Author: Ivan Penkov */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_FUCHSIA_H_ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_FUCHSIA_H_ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +// Based on zircon/system/public/zircon/syscalls/exception.h +typedef enum { + // Architectural exceptions + MD_EXCEPTION_CODE_FUCHSIA_GENERAL = 0x8, + MD_EXCEPTION_CODE_FUCHSIA_FATAL_PAGE_FAULT = 0x108, + MD_EXCEPTION_CODE_FUCHSIA_UNDEFINED_INSTRUCTION = 0x208, + MD_EXCEPTION_CODE_FUCHSIA_SW_BREAKPOINT = 0x308, + MD_EXCEPTION_CODE_FUCHSIA_HW_BREAKPOINT = 0x408, + MD_EXCEPTION_CODE_FUCHSIA_UNALIGNED_ACCESS = 0x508, + // + // Synthetic exceptions + MD_EXCEPTION_CODE_FUCHSIA_THREAD_STARTING = 0x8008, + MD_EXCEPTION_CODE_FUCHSIA_THREAD_EXITING = 0x8108, + MD_EXCEPTION_CODE_FUCHSIA_POLICY_ERROR = 0x8208, + MD_EXCEPTION_CODE_FUCHSIA_PROCESS_STARTING = 0x8308, +} MDExceptionCodeFuchsia; + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_FUCHSIA_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_linux.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_linux.h new file mode 100644 index 0000000000..19e2f2588c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_linux.h @@ -0,0 +1,129 @@ +/* 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 + +#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 */ + MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception, + dump requested. */ +} MDExceptionCodeLinux; + +/* For (MDException).exception_flags. These values come from + * asm-generic/siginfo.h. + */ +typedef enum { + /* Generic */ + MD_EXCEPTION_FLAG_LIN_SI_USER = 0, + MD_EXCEPTION_FLAG_LIN_SI_KERNEL = 0x80, + + /* SIGILL */ + MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC = 1, + MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN = 2, + MD_EXCEPTION_FLAG_LIN_ILL_ILLADR = 3, + MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP = 4, + MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC = 5, + MD_EXCEPTION_FLAG_LIN_ILL_PRVREG = 6, + MD_EXCEPTION_FLAG_LIN_ILL_COPROC = 7, + MD_EXCEPTION_FLAG_LIN_ILL_BADSTK = 8, + + /* SIGFPE */ + MD_EXCEPTION_FLAG_LIN_FPE_INTDIV = 1, + MD_EXCEPTION_FLAG_LIN_FPE_INTOVF = 2, + MD_EXCEPTION_FLAG_LIN_FPE_FLTDIV = 3, + MD_EXCEPTION_FLAG_LIN_FPE_FLTOVF = 4, + MD_EXCEPTION_FLAG_LIN_FPE_FLTUND = 5, + MD_EXCEPTION_FLAG_LIN_FPE_FLTRES = 6, + MD_EXCEPTION_FLAG_LIN_FPE_FLTINV = 7, + MD_EXCEPTION_FLAG_LIN_FPE_FLTSUB = 8, + + /* SIGSEGV */ + MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR = 1, + MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR = 2, + MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR = 3, + MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR = 4, + + /* SIGBUS */ + MD_EXCEPTION_FLAG_LIN_BUS_ADRALN = 1, + MD_EXCEPTION_FLAG_LIN_BUS_ADRERR = 2, + MD_EXCEPTION_FLAG_LIN_BUS_OBJERR = 3, + MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AR = 4, + MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO = 5, +} MDExceptionFlagLinux; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_mac.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_mac.h new file mode 100644 index 0000000000..b26d6c0af0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_mac.h @@ -0,0 +1,314 @@ +/* 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 + +#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 */ + MD_EXCEPTION_MAC_RESOURCE = 11, + /* EXC_RESOURCE */ + MD_EXCEPTION_MAC_GUARD = 12, + /* EXC_GUARD */ + MD_EXCEPTION_MAC_SIMULATED = 0x43507378 + /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */ +} 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 */ + MD_EXCEPTION_CODE_MAC_CODESIGN_ERROR = 50, + /* KERN_CODESIGN_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 */ + /* Custom values */ + MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */ + + /* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */ + MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */ + MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */ + MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on arm */ + MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */ + + /* 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; + +// The following definitions were taken from Darwin/XNU kernel sources. +// See https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/exc_resource.h + +typedef enum MDMacExcResourceType { + MD_MAC_EXC_RESOURCE_TYPE_CPU = 1, + MD_MAC_EXC_RESOURCE_TYPE_WAKEUPS = 2, + MD_MAC_EXC_RESOURCE_TYPE_MEMORY = 3, + MD_MAC_EXC_RESOURCE_TYPE_IO = 4, + MD_MAC_EXC_RESOURCE_TYPE_THREADS = 5 +} MDMacExcResourceType; + +typedef enum MDMacExcResourceFlavorCpu { + MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR = 1, + MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR_FATAL = 2 +} MDMacExcResourceFlavorCpu; + +typedef enum MDMacExcResourceFlavorWakeup { + MD_MAC_EXC_RESOURCE_FLAVOR_WAKEUPS_MONITOR = 1, +} MDMacExcResourceFlavorWakeup; + +typedef enum MDMacExcResourceFlavorMemory { + MD_MAC_EXC_RESOURCE_FLAVOR_HIGH_WATERMARK = 1, +} MDMacExcResourceFlavorMemory; + +typedef enum MDMacExcResourceIOFlavor { + MD_MAC_EXC_RESOURCE_FLAVOR_IO_PHYSICAL_WRITES = 1, + MD_MAC_EXC_RESOURCE_FLAVOR_IO_LOGICAL_WRITES = 2, +} MDMacExcResourceIOFlavor; + +typedef enum MDMacExcResourceThreadsFlavor { + MD_MAC_EXC_RESOURCE_FLAVOR_THREADS_HIGH_WATERMARK = 1, +} MDMacExcResourceThreadsFlavor; + +// See https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/exc_guard.h + +typedef enum MDMacExcGuardType { + MD_MAC_EXC_GUARD_TYPE_NONE = 0x0, + MD_MAC_EXC_GUARD_TYPE_MACH_PORT = 0x1, + MD_MAC_EXC_GUARD_TYPE_FD = 0x2, + MD_MAC_EXC_GUARD_TYPE_USER = 0x3, + MD_MAC_EXC_GUARD_TYPE_VN = 0x4, + MD_MAC_EXC_GUARD_TYPE_VIRT_MEMORY = 0x5 +} MDMacExcGuardType; + +// See https://github.com/apple/darwin-xnu/osfmk/mach/port.h + +typedef enum MDMacExcGuardMachPortFlavor { + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_DESTROY = 1u << 0, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS = 1u << 1, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT = 1u << 2, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_UNGUARDED = 1u << 3, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INCORRECT_GUARD = 1u << 4, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE = 1u << 5, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_STRICT_REPLY = 1u << 6, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MSG_FILTERED = 1u << 7, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_RIGHT = 1u << 8, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_NAME = 1u << 9, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_VALUE = 1u << 10, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_ARGUMENT = 1u << 11, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RIGHT_EXISTS = 1u << 12, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_NO_SPACE = 1u << 13, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_FAILURE = 1u << 14, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_RESOURCE = 1u << 15, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_REPLY = 1u << 16, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_VOUCHER = 1u << 17, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_RIGHT = 1u << 18, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_INVALID_NAME = 1u << 19, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_GUARDED_DESC = 1u << 20, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS_NON_FATAL = 1u << 21, + MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE_NON_FATAL = 1u << 22, +} MDMacExcGuardMachPortFlavor; + +// See https://github.com/apple/darwin-xnu/blob/main/bsd/sys/guarded.h + +typedef enum MDMacExcGuardFDFlavor { + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_CLOSE = 1u << 0, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_DUP = 1u << 1, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_NOCLOEXEC = 1u << 2, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_SOCKET_IPC = 1u << 3, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_FILEPORT = 1u << 4, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_MISMATCH = 1u << 5, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE = 1u << 6 +} MDMacExcGuardFDFlavor; + + +typedef enum MDMacExcGuardVNFlavor { + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_TO = 1u << 0, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_FROM = 1u << 1, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_UNLINK = 1u << 2, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE_OTHER = 1u << 3, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_TRUNC_OTHER = 1u << 4, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_LINK = 1u << 5, + MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_EXCHDATA = 1u << 6, +} MDMacExcGuardVNFlavor; + +// See https://github.com/apple/darwin-xnu/osfmk/mach/vm_statistics.h + +typedef enum MDMacExcGuardVirtMemoryFlavor { + MD_MAC_EXC_GUARD_VIRT_MEMORY_FLAVOR_GUARD_EXC_DEALLOC_GAP = 1u << 0 +} MDMacExcGuardVirtMemoryFlavor; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_ps3.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_ps3.h new file mode 100644 index 0000000000..adff5a6bbc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_ps3.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2013, 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_ps3.h: A definition of exception codes for + * PS3 */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +typedef enum { + MD_EXCEPTION_CODE_PS3_UNKNOWN = 0, + MD_EXCEPTION_CODE_PS3_TRAP_EXCEP = 1, + MD_EXCEPTION_CODE_PS3_PRIV_INSTR = 2, + MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR = 3, + MD_EXCEPTION_CODE_PS3_INSTR_STORAGE = 4, + MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT = 5, + MD_EXCEPTION_CODE_PS3_DATA_STORAGE = 6, + MD_EXCEPTION_CODE_PS3_DATA_SEGMENT = 7, + MD_EXCEPTION_CODE_PS3_FLOAT_POINT = 8, + MD_EXCEPTION_CODE_PS3_DABR_MATCH = 9, + MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP = 10, + MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS = 11, + MD_EXCEPTION_CODE_PS3_COPRO_ALIGN = 12, + MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM = 13, + MD_EXCEPTION_CODE_PS3_COPRO_ERR = 14, + MD_EXCEPTION_CODE_PS3_COPRO_FIR = 15, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT = 16, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE = 17, + MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR = 18, + MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR = 19, + MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN = 20, + MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS = 21, + MD_EXCEPTION_CODE_PS3_GRAPHIC = 22 +} MDExceptionCodePS3; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_solaris.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_solaris.h new file mode 100644 index 0000000000..f18ddf4247 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_solaris.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 + +#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 occurred */ + 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__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_win32.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_win32.h new file mode 100644 index 0000000000..159f53f663 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_exception_win32.h @@ -0,0 +1,5575 @@ +/* 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 + +#include "google_breakpad/common/breakpad_types.h" + + +/* For (MDException).exception_code. These values come from WinBase.h */ +typedef enum { + 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_BAD_FUNCTION_TABLE = 0xc00000ff, + /* EXCEPTION_BAD_FUNCTION_TABLE */ + MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194, + /* EXCEPTION_POSSIBLE_DEADLOCK */ + MD_EXCEPTION_OUT_OF_MEMORY = 0xe0000008, + /* Exception thrown by Chromium allocators to indicate OOM. + See base/process/memory.h in Chromium for rationale. */ + MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363, + /* Per http://support.microsoft.com/kb/185294, + generated by Visual C++ compiler */ + MD_EXCEPTION_CODE_WIN_SIMULATED = 0x0517a7ed + /* Fake exception code used by Crashpad's + CrashpadClient::DumpWithoutCrash. */ +} MDExceptionCodeWin; + + +/* For (MDException).exception_information[2], when (MDException).exception_code + * is MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR. This describes the underlying reason + * for the error. These values come from ntstatus.h. + * + * The content of this enum was created from ntstatus.h in the 10 SDK + * (version 10.0.19041.0) with + * + * egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h + * | tr -d '\r' + * | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' + * | sort + * | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2 = \1,@' + * + * With easy copy to clipboard with + * | xclip -selection c # on linux + * | clip # on windows + * | pbcopy # on mac */ +typedef enum { + MD_NTSTATUS_WIN_STATUS_SUCCESS = 0x00000000, + MD_NTSTATUS_WIN_STATUS_WAIT_0 = 0x00000000, + MD_NTSTATUS_WIN_STATUS_WAIT_1 = 0x00000001, + MD_NTSTATUS_WIN_STATUS_WAIT_2 = 0x00000002, + MD_NTSTATUS_WIN_STATUS_WAIT_3 = 0x00000003, + MD_NTSTATUS_WIN_STATUS_WAIT_63 = 0x0000003F, + MD_NTSTATUS_WIN_STATUS_ABANDONED = 0x00000080, + MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_0 = 0x00000080, + MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63 = 0x000000BF, + MD_NTSTATUS_WIN_STATUS_USER_APC = 0x000000C0, + MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE = 0x000000FF, + MD_NTSTATUS_WIN_STATUS_KERNEL_APC = 0x00000100, + MD_NTSTATUS_WIN_STATUS_ALERTED = 0x00000101, + MD_NTSTATUS_WIN_STATUS_TIMEOUT = 0x00000102, + MD_NTSTATUS_WIN_STATUS_PENDING = 0x00000103, + MD_NTSTATUS_WIN_STATUS_REPARSE = 0x00000104, + MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES = 0x00000105, + MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED = 0x00000106, + MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED = 0x00000107, + MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS = 0x00000108, + MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED = 0x00000109, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED = 0x0000010A, + MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP = 0x0000010B, + MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR = 0x0000010C, + MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT = 0x0000010D, + MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED = 0x0000010E, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION = 0x00000110, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO = 0x00000111, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE = 0x00000112, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE = 0x00000113, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE = 0x00000114, + MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED = 0x00000115, + MD_NTSTATUS_WIN_STATUS_CRASH_DUMP = 0x00000116, + MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS = 0x00000117, + MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT = 0x00000118, + MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED = 0x00000119, + MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE = 0x00000120, + MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY = 0x00000121, + MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE = 0x00000122, + MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB = 0x00000123, + MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB = 0x00000124, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY = 0x00000125, + MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY = 0x00000126, + MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED = 0x00000127, + MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED = 0x00000128, + MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED = 0x00000129, + MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS = 0x0000012A, + MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS = 0x0000012B, + MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH = 0x0000012C, + MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH = 0x0000012D, + MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH = 0x0000012E, + MD_NTSTATUS_WIN_STATUS_GHOSTED = 0x0000012F, + MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN = 0x00000130, + MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY = 0x00000202, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY = 0x00000210, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL = 0x00000211, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA = 0x00000212, + MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY = 0x00000213, + MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT = 0x00000214, + MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE = 0x00000215, + MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED = 0x00000216, + MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK = 0x00000367, + MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL = 0x00000368, + MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED = 0x00010001, + MD_NTSTATUS_WIN_DBG_CONTINUE = 0x00010002, + MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE = 0x001C0001, + MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE = 0x00293000, + MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE = 0x00293001, + MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS = 0x00350059, + MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED = 0x00E70000, + MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE = 0x00E70001, + MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE = 0x00E70002, + MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT = 0x00E70003, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS = 0x40000000, + MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED = 0x40000001, + MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE = 0x40000002, + MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE = 0x40000003, + MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED = 0x40000004, + MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION = 0x40000005, + MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY = 0x40000006, + MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY = 0x40000007, + MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES = 0x40000008, + MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED = 0x40000009, + MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP = 0x4000000A, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY = 0x4000000B, + MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT = 0x4000000C, + MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD = 0x4000000D, + MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH = 0x4000000E, + MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL = 0x4000000F, + MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED = 0x40000010, + MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED = 0x40000011, + MD_NTSTATUS_WIN_STATUS_EVENT_DONE = 0x40000012, + MD_NTSTATUS_WIN_STATUS_EVENT_PENDING = 0x40000013, + MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM = 0x40000014, + MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT = 0x40000015, + MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE = 0x40000016, + MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED = 0x40000017, + MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION = 0x40000018, + MD_NTSTATUS_WIN_STATUS_WAS_LOCKED = 0x40000019, + MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR = 0x4000001A, + MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32 = 0x4000001B, + MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE = 0x4000001C, + MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE = 0x4000001D, + MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP = 0x4000001E, + MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT = 0x4000001F, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE = 0x40000020, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE = 0x40000021, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN = 0x40000022, + MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE = 0x40000023, + MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED = 0x40000024, + MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED = 0x40000025, + MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED = 0x40000026, + MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED = 0x40000027, + MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB = 0x40000028, + MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH = 0x40000029, + MD_NTSTATUS_WIN_STATUS_HIBERNATED = 0x4000002A, + MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION = 0x4000002B, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED = 0x4000002C, + MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES = 0x4000002D, + MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED = 0x4000002E, + MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION = 0x4000002F, + MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST = 0x40000030, + MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 0x40000031, + MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY = 0x40000032, + MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE = 0x40000033, + MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED = 0x40000034, + MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY = 0x40000035, + MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE = 0x40000036, + MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED = 0x40000037, + MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM = 0x40000294, + MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN = 0x40000370, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED = 0x40000807, + MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART = 0x4000A144, + MD_NTSTATUS_WIN_DBG_REPLY_LATER = 0x40010001, + MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE = 0x40010002, + MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD = 0x40010003, + MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS = 0x40010004, + MD_NTSTATUS_WIN_DBG_CONTROL_C = 0x40010005, + MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C = 0x40010006, + MD_NTSTATUS_WIN_DBG_RIPEXCEPTION = 0x40010007, + MD_NTSTATUS_WIN_DBG_CONTROL_BREAK = 0x40010008, + MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION = 0x40010009, + MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C = 0x4001000A, + MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY = 0x40020056, + MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE = 0x400200AF, + MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT = 0x400A0004, + MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT = 0x400A0005, + MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT = 0x4015000D, + MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE = 0x40190001, + MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED = 0x40190034, + MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED = 0x40190035, + MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART = 0x401A000C, + MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST = 0x401B00EC, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED = 0x401E000A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION = 0x401E0201, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED = 0x401E0307, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE = 0x401E031E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY = 0x401E034B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET = 0x401E034C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED = 0x401E0351, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS = 0x401E042F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED = 0x401E0437, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY = 0x401E0439, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED = 0x401E043A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS = 0x401E043C, + MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED = 0x40230001, + MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT = 0x40292023, + MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION = 0x80000001, + MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT = 0x80000002, + MD_NTSTATUS_WIN_STATUS_BREAKPOINT = 0x80000003, + MD_NTSTATUS_WIN_STATUS_SINGLE_STEP = 0x80000004, + MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW = 0x80000005, + MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES = 0x80000006, + MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER = 0x80000007, + MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED = 0x8000000A, + MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE = 0x8000000B, + MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE = 0x8000000C, + MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY = 0x8000000D, + MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY = 0x8000000E, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF = 0x8000000F, + MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE = 0x80000010, + MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY = 0x80000011, + MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS = 0x80000012, + MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME = 0x80000013, + MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT = 0x80000014, + MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG = 0x80000015, + MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED = 0x80000016, + MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION = 0x80000017, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY = 0x80000018, + MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES = 0x8000001A, + MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED = 0x8000001B, + MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED = 0x8000001C, + MD_NTSTATUS_WIN_STATUS_BUS_RESET = 0x8000001D, + MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA = 0x8000001E, + MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA = 0x8000001F, + MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK = 0x80000020, + MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED = 0x80000021, + MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED = 0x80000022, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES = 0x80000023, + MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES = 0x80000024, + MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED = 0x80000025, + MD_NTSTATUS_WIN_STATUS_LONGJUMP = 0x80000026, + MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED = 0x80000027, + MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED = 0x80000028, + MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE = 0x80000029, + MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED = 0x8000002A, + MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE = 0x8000002B, + MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE = 0x8000002C, + MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK = 0x8000002D, + MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK = 0x8000002E, + MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION = 0x8000002F, + MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS = 0x80000030, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED = 0x80000031, + MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE = 0x80000032, + MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT = 0x80000033, + MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING = 0x80000288, + MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN = 0x80000289, + MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR = 0x80000803, + MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED = 0x8000A127, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH = 0x8000CF00, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE = 0x8000CF04, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS = 0x8000CF05, + MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED = 0x80010001, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP = 0x80130001, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN = 0x80130002, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE = 0x80130003, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE = 0x80130004, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER = 0x80130005, + MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG = 0x80190009, + MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA = 0x80190029, + MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN = 0x80190031, + MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT = 0x80190041, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 0x80190042, + MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED = 0x801B00EB, + MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL = 0x801C0001, + MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA = 0x80210001, + MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE = 0x80210002, + MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED = 0x80370001, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION = 0x80380001, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION = 0x80380002, + MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED = 0x80390001, + MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED = 0x80390003, + MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR = 0x803A0001, + MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK = 0x803F0001, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED = 0x80430006, + MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL = 0xC0000001, + MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED = 0xC0000002, + MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS = 0xC0000003, + MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH = 0xC0000004, + MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION = 0xC0000005, + MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR = 0xC0000006, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA = 0xC0000007, + MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE = 0xC0000008, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK = 0xC0000009, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC = 0xC000000A, + MD_NTSTATUS_WIN_STATUS_INVALID_CID = 0xC000000B, + MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED = 0xC000000C, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER = 0xC000000D, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE = 0xC000000E, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE = 0xC000000F, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST = 0xC0000010, + MD_NTSTATUS_WIN_STATUS_END_OF_FILE = 0xC0000011, + MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME = 0xC0000012, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE = 0xC0000013, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA = 0xC0000014, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR = 0xC0000015, + MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016, + MD_NTSTATUS_WIN_STATUS_NO_MEMORY = 0xC0000017, + MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES = 0xC0000018, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW = 0xC0000019, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM = 0xC000001A, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION = 0xC000001B, + MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE = 0xC000001C, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION = 0xC000001D, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE = 0xC000001E, + MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE = 0xC000001F, + MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION = 0xC0000020, + MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED = 0xC0000021, + MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED = 0xC0000022, + MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL = 0xC0000023, + MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024, + MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION = 0xC0000025, + MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION = 0xC0000026, + MD_NTSTATUS_WIN_STATUS_UNWIND = 0xC0000027, + MD_NTSTATUS_WIN_STATUS_BAD_STACK = 0xC0000028, + MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET = 0xC0000029, + MD_NTSTATUS_WIN_STATUS_NOT_LOCKED = 0xC000002A, + MD_NTSTATUS_WIN_STATUS_PARITY_ERROR = 0xC000002B, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM = 0xC000002C, + MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED = 0xC000002D, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES = 0xC000002E, + MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG = 0xC000002F, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX = 0xC0000030, + MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER = 0xC0000031, + MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR = 0xC0000032, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID = 0xC0000033, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION = 0xC0000035, + MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB = 0xC0000036, + MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED = 0xC0000037, + MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED = 0xC0000038, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID = 0xC0000039, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B, + MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN = 0xC000003C, + MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR = 0xC000003D, + MD_NTSTATUS_WIN_STATUS_DATA_ERROR = 0xC000003E, + MD_NTSTATUS_WIN_STATUS_CRC_ERROR = 0xC000003F, + MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG = 0xC0000040, + MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED = 0xC0000041, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE = 0xC0000042, + MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION = 0xC0000043, + MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED = 0xC0000044, + MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION = 0xC0000045, + MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED = 0xC0000046, + MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED = 0xC0000047, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET = 0xC0000048, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE = 0xC0000049, + MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED = 0xC000004A, + MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING = 0xC000004B, + MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT = 0xC000004C, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP = 0xC000004D, + MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION = 0xC000004E, + MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED = 0xC000004F, + MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE = 0xC0000050, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY = 0xC0000051, + MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE = 0xC0000052, + MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR = 0xC0000053, + MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT = 0xC0000054, + MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED = 0xC0000055, + MD_NTSTATUS_WIN_STATUS_DELETE_PENDING = 0xC0000056, + MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED = 0xC0000057, + MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION = 0xC0000058, + MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH = 0xC0000059, + MD_NTSTATUS_WIN_STATUS_INVALID_OWNER = 0xC000005A, + MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP = 0xC000005B, + MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN = 0xC000005C, + MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY = 0xC000005D, + MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS = 0xC000005E, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION = 0xC000005F, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE = 0xC0000060, + MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD = 0xC0000061, + MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME = 0xC0000062, + MD_NTSTATUS_WIN_STATUS_USER_EXISTS = 0xC0000063, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER = 0xC0000064, + MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS = 0xC0000065, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP = 0xC0000066, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP = 0xC0000067, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP = 0xC0000068, + MD_NTSTATUS_WIN_STATUS_LAST_ADMIN = 0xC0000069, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD = 0xC000006A, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD = 0xC000006B, + MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION = 0xC000006C, + MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE = 0xC000006D, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION = 0xC000006E, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS = 0xC000006F, + MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION = 0xC0000070, + MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED = 0xC0000071, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED = 0xC0000072, + MD_NTSTATUS_WIN_STATUS_NONE_MAPPED = 0xC0000073, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED = 0xC0000074, + MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED = 0xC0000075, + MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY = 0xC0000076, + MD_NTSTATUS_WIN_STATUS_INVALID_ACL = 0xC0000077, + MD_NTSTATUS_WIN_STATUS_INVALID_SID = 0xC0000078, + MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR = 0xC0000079, + MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND = 0xC000007A, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT = 0xC000007B, + MD_NTSTATUS_WIN_STATUS_NO_TOKEN = 0xC000007C, + MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL = 0xC000007D, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED = 0xC000007E, + MD_NTSTATUS_WIN_STATUS_DISK_FULL = 0xC000007F, + MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED = 0xC0000080, + MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED = 0xC0000081, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED = 0xC0000082, + MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED = 0xC0000083, + MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY = 0xC0000084, + MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED = 0xC0000085, + MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL = 0xC0000086, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED = 0xC0000087, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA = 0xC0000088, + MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND = 0xC0000089, + MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND = 0xC000008A, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND = 0xC000008B, + MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED = 0xC000008C, + MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND = 0xC000008D, + MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO = 0xC000008E, + MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT = 0xC000008F, + MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION = 0xC0000090, + MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW = 0xC0000091, + MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK = 0xC0000092, + MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW = 0xC0000093, + MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094, + MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW = 0xC0000095, + MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES = 0xC0000097, + MD_NTSTATUS_WIN_STATUS_FILE_INVALID = 0xC0000098, + MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED = 0xC0000099, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES = 0xC000009A, + MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND = 0xC000009B, + MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR = 0xC000009C, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED = 0xC000009D, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE = 0xC000009E, + MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE = 0xC000009F, + MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED = 0xC00000A0, + MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA = 0xC00000A1, + MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED = 0xC00000A2, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY = 0xC00000A3, + MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES = 0xC00000A4, + MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL = 0xC00000A5, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS = 0xC00000A6, + MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS = 0xC00000A7, + MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE = 0xC00000A8, + MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD = 0xC00000A9, + MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT = 0xC00000AA, + MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE = 0xC00000AB, + MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE = 0xC00000AC, + MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE = 0xC00000AD, + MD_NTSTATUS_WIN_STATUS_PIPE_BUSY = 0xC00000AE, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION = 0xC00000AF, + MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED = 0xC00000B0, + MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING = 0xC00000B1, + MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED = 0xC00000B2, + MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING = 0xC00000B3, + MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE = 0xC00000B4, + MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT = 0xC00000B5, + MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED = 0xC00000B6, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED = 0xC00000B7, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED = 0xC00000B8, + MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET = 0xC00000B9, + MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED = 0xC00000BB, + MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING = 0xC00000BC, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME = 0xC00000BD, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH = 0xC00000BE, + MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY = 0xC00000BF, + MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST = 0xC00000C0, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS = 0xC00000C1, + MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR = 0xC00000C2, + MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE = 0xC00000C3, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR = 0xC00000C4, + MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER = 0xC00000C5, + MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL = 0xC00000C6, + MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE = 0xC00000C7, + MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED = 0xC00000C8, + MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED = 0xC00000C9, + MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED = 0xC00000CA, + MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE = 0xC00000CB, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME = 0xC00000CC, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES = 0xC00000CD, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS = 0xC00000CE, + MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED = 0xC00000CF, + MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED = 0xC00000D0, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED = 0xC00000D1, + MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT = 0xC00000D2, + MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT = 0xC00000D3, + MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE = 0xC00000D4, + MD_NTSTATUS_WIN_STATUS_FILE_RENAMED = 0xC00000D5, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED = 0xC00000D6, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT = 0xC00000D7, + MD_NTSTATUS_WIN_STATUS_CANT_WAIT = 0xC00000D8, + MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY = 0xC00000D9, + MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO = 0xC00000DA, + MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF = 0xC00000DB, + MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE = 0xC00000DC, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE = 0xC00000DD, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE = 0xC00000DE, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN = 0xC00000DF, + MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS = 0xC00000E0, + MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED = 0xC00000E1, + MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED = 0xC00000E2, + MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL = 0xC00000E3, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION = 0xC00000E4, + MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR = 0xC00000E5, + MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED = 0xC00000E6, + MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT = 0xC00000E7, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER = 0xC00000E8, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR = 0xC00000E9, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR = 0xC00000EA, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR = 0xC00000EB, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR = 0xC00000EC, + MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS = 0xC00000ED, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS = 0xC00000EE, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1 = 0xC00000EF, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2 = 0xC00000F0, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3 = 0xC00000F1, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4 = 0xC00000F2, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5 = 0xC00000F3, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6 = 0xC00000F4, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7 = 0xC00000F5, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8 = 0xC00000F6, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9 = 0xC00000F7, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10 = 0xC00000F8, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11 = 0xC00000F9, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12 = 0xC00000FA, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED = 0xC00000FB, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED = 0xC00000FC, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW = 0xC00000FD, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE = 0xC00000FE, + MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE = 0xC00000FF, + MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND = 0xC0000100, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101, + MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR = 0xC0000102, + MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY = 0xC0000103, + MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE = 0xC0000104, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION = 0xC0000105, + MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG = 0xC0000106, + MD_NTSTATUS_WIN_STATUS_FILES_OPEN = 0xC0000107, + MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE = 0xC0000108, + MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND = 0xC0000109, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING = 0xC000010A, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE = 0xC000010B, + MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION = 0xC000010C, + MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE = 0xC000010D, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED = 0xC000010E, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT = 0xC000010F, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST = 0xC0000110, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED = 0xC0000111, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER = 0xC0000112, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND = 0xC0000113, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID = 0xC0000114, + MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE = 0xC0000115, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR = 0xC0000116, + MD_NTSTATUS_WIN_STATUS_NO_LDT = 0xC0000117, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE = 0xC0000118, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET = 0xC0000119, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR = 0xC000011A, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT = 0xC000011B, + MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE = 0xC000011C, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE = 0xC000011D, + MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO = 0xC000011E, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES = 0xC000011F, + MD_NTSTATUS_WIN_STATUS_CANCELLED = 0xC0000120, + MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE = 0xC0000121, + MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME = 0xC0000122, + MD_NTSTATUS_WIN_STATUS_FILE_DELETED = 0xC0000123, + MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT = 0xC0000124, + MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP = 0xC0000125, + MD_NTSTATUS_WIN_STATUS_SPECIAL_USER = 0xC0000126, + MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP = 0xC0000127, + MD_NTSTATUS_WIN_STATUS_FILE_CLOSED = 0xC0000128, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS = 0xC0000129, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS = 0xC000012A, + MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE = 0xC000012B, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED = 0xC000012C, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT = 0xC000012D, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT = 0xC000012E, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ = 0xC000012F, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT = 0xC0000130, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16 = 0xC0000131, + MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT = 0xC0000132, + MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC = 0xC0000133, + MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED = 0xC0000134, + MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND = 0xC0000135, + MD_NTSTATUS_WIN_STATUS_OPEN_FAILED = 0xC0000136, + MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED = 0xC0000137, + MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND = 0xC0000138, + MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139, + MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT = 0xC000013A, + MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT = 0xC000013B, + MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT = 0xC000013C, + MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES = 0xC000013D, + MD_NTSTATUS_WIN_STATUS_LINK_FAILED = 0xC000013E, + MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT = 0xC000013F, + MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION = 0xC0000140, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS = 0xC0000141, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED = 0xC0000142, + MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE = 0xC0000143, + MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION = 0xC0000144, + MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE = 0xC0000145, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED = 0xC0000146, + MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE = 0xC0000147, + MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL = 0xC0000148, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE = 0xC0000149, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT = 0xC000014A, + MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN = 0xC000014B, + MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT = 0xC000014C, + MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED = 0xC000014D, + MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR = 0xC000014E, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME = 0xC000014F, + MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED = 0xC0000150, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS = 0xC0000151, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS = 0xC0000152, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS = 0xC0000153, + MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS = 0xC0000154, + MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED = 0xC0000155, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS = 0xC0000156, + MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG = 0xC0000157, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR = 0xC0000158, + MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE = 0xC0000159, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS = 0xC000015A, + MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015B, + MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE = 0xC000015C, + MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED = 0xC000015D, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR = 0xC000015E, + MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER = 0xC000015F, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY = 0xC0000160, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER = 0xC0000161, + MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER = 0xC0000162, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER = 0xC0000163, + MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME = 0xC0000164, + MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND = 0xC0000165, + MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER = 0xC0000166, + MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR = 0xC0000167, + MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS = 0xC0000168, + MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED = 0xC0000169, + MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED = 0xC000016A, + MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED = 0xC000016B, + MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY = 0xC000016C, + MD_NTSTATUS_WIN_STATUS_FT_ORPHANING = 0xC000016D, + MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT = 0xC000016E, + MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE = 0xC0000172, + MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH = 0xC0000173, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED = 0xC0000174, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA = 0xC0000175, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA = 0xC0000176, + MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW = 0xC0000177, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA = 0xC0000178, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER = 0xC000017A, + MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER = 0xC000017B, + MD_NTSTATUS_WIN_STATUS_KEY_DELETED = 0xC000017C, + MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE = 0xC000017D, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS = 0xC000017E, + MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED = 0xC000017F, + MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN = 0xC0000180, + MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE = 0xC0000181, + MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR = 0xC0000182, + MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR = 0xC0000183, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE = 0xC0000184, + MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR = 0xC0000185, + MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR = 0xC0000186, + MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER = 0xC0000187, + MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL = 0xC0000188, + MD_NTSTATUS_WIN_STATUS_TOO_LATE = 0xC0000189, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET = 0xC000018A, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT = 0xC000018B, + MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE = 0xC000018C, + MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE = 0xC000018D, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT = 0xC000018E, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START = 0xC000018F, + MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE = 0xC0000190, + MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED = 0xC0000191, + MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED = 0xC0000192, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED = 0xC0000193, + MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK = 0xC0000194, + MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT = 0xC0000195, + MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT = 0xC0000196, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED = 0xC0000197, + MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xC0000198, + MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xC0000199, + MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT = 0xC000019A, + MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT = 0xC000019B, + MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED = 0xC000019C, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL = 0xC000019D, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0xC000019E, + MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0xC000019F, + MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT = 0xC00001A0, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE = 0xC00001A1, + MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION = 0xC00001A2, + MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3, + MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4, + MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER = 0xC00001A5, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES = 0xC00001A6, + MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE = 0xC00001A7, + MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED = 0xC00001A8, + MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED = 0xC00001A9, + MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE = 0xC00001AA, + MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS = 0xC00001AB, + MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT = 0xC00001AC, + MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION = 0xC00001AD, + MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB = 0xC00001AE, + MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID = 0xC00001AF, + MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA = 0xC00001B0, + MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE = 0xC00001B1, + MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION = 0xC00001B2, + MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION = 0xC0000201, + MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY = 0xC0000202, + MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED = 0xC0000203, + MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND = 0xC0000204, + MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, + MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE = 0xC0000206, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT = 0xC0000207, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD = 0xC0000208, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES = 0xC0000209, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS = 0xC000020A, + MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED = 0xC000020B, + MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED = 0xC000020C, + MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET = 0xC000020D, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES = 0xC000020E, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED = 0xC000020F, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT = 0xC0000210, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE = 0xC0000211, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH = 0xC0000212, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED = 0xC0000213, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID = 0xC0000214, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE = 0xC0000215, + MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION = 0xC0000216, + MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION = 0xC0000217, + MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE = 0xC0000218, + MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED = 0xC0000219, + MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED = 0xC000021A, + MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED = 0xC000021B, + MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND = 0xC000021C, + MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR = 0xC000021D, + MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT = 0xC000021E, + MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH = 0xC000021F, + MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT = 0xC0000220, + MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH = 0xC0000221, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA = 0xC0000222, + MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID = 0xC0000223, + MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE = 0xC0000224, + MD_NTSTATUS_WIN_STATUS_NOT_FOUND = 0xC0000225, + MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM = 0xC0000226, + MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE = 0xC0000227, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ = 0xC0000228, + MD_NTSTATUS_WIN_STATUS_FAIL_CHECK = 0xC0000229, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID = 0xC000022A, + MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS = 0xC000022B, + MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE = 0xC000022C, + MD_NTSTATUS_WIN_STATUS_RETRY = 0xC000022D, + MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE = 0xC000022E, + MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET = 0xC000022F, + MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND = 0xC0000230, + MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW = 0xC0000231, + MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT = 0xC0000232, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND = 0xC0000233, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234, + MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE = 0xC0000235, + MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED = 0xC0000236, + MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT = 0xC0000237, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED = 0xC0000238, + MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED = 0xC0000239, + MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID = 0xC000023A, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE = 0xC000023B, + MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE = 0xC000023C, + MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE = 0xC000023D, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE = 0xC000023E, + MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE = 0xC000023F, + MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED = 0xC0000240, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED = 0xC0000241, + MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER = 0xC0000242, + MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE = 0xC0000243, + MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED = 0xC0000244, + MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET = 0xC0000245, + MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT = 0xC0000246, + MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION = 0xC0000247, + MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION = 0xC0000248, + MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH = 0xC0000249, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO = 0xC0000250, + MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT = 0xC0000251, + MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT = 0xC0000252, + MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST = 0xC0000253, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1 = 0xC0000254, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2 = 0xC0000255, + MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT = 0xC0000256, + MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED = 0xC0000257, + MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE = 0xC0000258, + MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED = 0xC0000259, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT = 0xC000025A, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT = 0xC000025B, + MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT = 0xC000025C, + MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE = 0xC000025E, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION = 0xC000025F, + MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE = 0xC0000260, + MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH = 0xC0000261, + MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND = 0xC0000262, + MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND = 0xC0000263, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED = 0xC0000264, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS = 0xC0000265, + MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT = 0xC0000266, + MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE = 0xC0000267, + MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION = 0xC0000268, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION = 0xC0000269, + MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION = 0xC000026A, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF = 0xC000026B, + MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD = 0xC000026C, + MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE = 0xC000026D, + MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED = 0xC000026E, + MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR = 0xC000026F, + MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK = 0xC0000270, + MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE = 0xC0000271, + MD_NTSTATUS_WIN_STATUS_NO_MATCH = 0xC0000272, + MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES = 0xC0000273, + MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT = 0xC0000275, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID = 0xC0000276, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH = 0xC0000277, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID = 0xC0000278, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG = 0xC000027A, + MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION = 0xC000027B, + MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION = 0xC000027C, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED = 0xC0000280, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281, + MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT = 0xC0000282, + MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY = 0xC0000283, + MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL = 0xC0000284, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS = 0xC0000285, + MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT = 0xC0000286, + MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED = 0xC0000287, + MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED = 0xC000028A, + MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED = 0xC000028B, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND = 0xC000028C, + MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY = 0xC000028D, + MD_NTSTATUS_WIN_STATUS_NO_EFS = 0xC000028E, + MD_NTSTATUS_WIN_STATUS_WRONG_EFS = 0xC000028F, + MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS = 0xC0000290, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED = 0xC0000291, + MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT = 0xC0000292, + MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED = 0xC0000293, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND = 0xC0000295, + MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND = 0xC0000296, + MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND = 0xC0000297, + MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN = 0xC0000298, + MD_NTSTATUS_WIN_STATUS_SHARED_POLICY = 0xC0000299, + MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND = 0xC000029A, + MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS = 0xC000029B, + MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED = 0xC000029C, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE = 0xC000029D, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR = 0xC000029E, + MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE = 0xC000029F, + MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH = 0xC00002A0, + MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE = 0xC00002A1, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX = 0xC00002A2, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED = 0xC00002A3, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS = 0xC00002A4, + MD_NTSTATUS_WIN_STATUS_DS_BUSY = 0xC00002A5, + MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE = 0xC00002A6, + MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED = 0xC00002A7, + MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS = 0xC00002A8, + MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER = 0xC00002A9, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR = 0xC00002AA, + MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION = 0xC00002AB, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF = 0xC00002AC, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN = 0xC00002AD, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS = 0xC00002AE, + MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED = 0xC00002AF, + MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE = 0xC00002B0, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED = 0xC00002B1, + MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT = 0xC00002B2, + MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY = 0xC00002B3, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS = 0xC00002B4, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS = 0xC00002B5, + MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED = 0xC00002B6, + MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS = 0xC00002B7, + MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE = 0xC00002B8, + MD_NTSTATUS_WIN_STATUS_NOINTERFACE = 0xC00002B9, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED = 0xC00002BA, + MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED = 0xC00002C1, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP = 0xC00002C2, + MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED = 0xC00002C3, + MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE = 0xC00002C4, + MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR = 0xC00002C5, + MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY = 0xC00002C6, + MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE = 0xC00002C7, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM = 0xC00002C8, + MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION = 0xC00002C9, + MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL = 0xC00002CA, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE = 0xC00002CB, + MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED = 0xC00002CC, + MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION = 0xC00002CD, + MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION = 0xC00002CE, + MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED = 0xC00002CF, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID = 0xC00002D0, + MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE = 0xC00002D1, + MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED = 0xC00002D2, + MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID = 0xC00002D3, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE = 0xC00002D4, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 0xC00002D5, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 0xC00002D6, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D7, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 0xC00002D8, + MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D9, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 0xC00002DA, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 0xC00002DB, + MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS = 0xC00002DC, + MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED = 0xC00002DD, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER = 0xC00002DE, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD = 0xC00002DF, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY = 0xC00002E0, + MD_NTSTATUS_WIN_STATUS_DS_CANT_START = 0xC00002E1, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE = 0xC00002E2, + MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE = 0xC00002E3, + MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED = 0xC00002E4, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 0xC00002E5, + MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS = 0xC00002E6, + MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 0xC00002E7, + MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION = 0xC00002E8, + MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED = 0xC00002E9, + MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE = 0xC00002EA, + MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN = 0xC00002EB, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE = 0xC00002EC, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE = 0xC00002ED, + MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED = 0xC00002EE, + MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY = 0xC00002EF, + MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND = 0xC00002F0, + MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES = 0xC00002F1, + MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE = 0xC00002F2, + MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID = 0xC00002F3, + MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED = 0xC00002F4, + MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC = 0xC00002F5, + MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED = 0xC00002F6, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS = 0xC00002F7, + MD_NTSTATUS_WIN_STATUS_NO_PA_DATA = 0xC00002F8, + MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH = 0xC00002F9, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED = 0xC00002FA, + MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST = 0xC00002FB, + MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER = 0xC00002FC, + MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE = 0xC00002FD, + MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS = 0xC00002FE, + MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS = 0xC00002FF, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS = 0xC0000300, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED = 0xC0000301, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED = 0xC0000302, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED = 0xC0000303, + MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED = 0xC0000304, + MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE = 0xC0000305, + MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE = 0xC0000306, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT = 0xC0000307, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED = 0xC0000308, + MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR = 0xC0000309, + MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH = 0xC000030A, + MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED = 0xC000030B, + MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED = 0xC000030C, + MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION = 0xC000030D, + MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE = 0xC0000320, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321, + MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY = 0xC0000322, + MD_NTSTATUS_WIN_STATUS_HOST_DOWN = 0xC0000350, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH = 0xC0000351, + MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG = 0xC0000352, + MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET = 0xC0000353, + MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE = 0xC0000354, + MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE = 0xC0000355, + MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED = 0xC0000356, + MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT = 0xC0000357, + MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 0xC0000358, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32 = 0xC0000359, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64 = 0xC000035A, + MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS = 0xC000035B, + MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED = 0xC000035C, + MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK = 0xC000035D, + MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED = 0xC000035E, + MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER = 0xC000035F, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT = 0xC0000361, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH = 0xC0000362, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER = 0xC0000363, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER = 0xC0000364, + MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY = 0xC0000365, + MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR = 0xC0000366, + MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED = 0xC0000368, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER = 0xC0000369, + MD_NTSTATUS_WIN_STATUS_MCA_OCCURED = 0xC000036A, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL = 0xC000036B, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED = 0xC000036C, + MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR = 0xC000036D, + MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE = 0xC000036E, + MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL = 0xC000036F, + MD_NTSTATUS_WIN_STATUS_NO_SECRETS = 0xC0000371, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 0xC0000372, + MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH = 0xC0000373, + MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION = 0xC0000374, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN = 0xC0000380, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED = 0xC0000381, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED = 0xC0000382, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD = 0xC0000383, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER = 0xC0000384, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE = 0xC0000385, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET = 0xC0000386, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR = 0xC0000387, + MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED = 0xC0000388, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED = 0xC0000389, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED = 0xC000038A, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C = 0xC000038B, + MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE = 0xC000038C, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED = 0xC000038D, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD = 0xC000038E, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT = 0xC000038F, + MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED = 0xC0000401, + MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED = 0xC0000402, + MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED = 0xC0000403, + MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE = 0xC0000404, + MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND = 0xC0000405, + MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR = 0xC0000406, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE = 0xC0000407, + MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED = 0xC0000408, + MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN = 0xC0000409, + MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT = 0xC000040A, + MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE = 0xC000040B, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC = 0xC000040C, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC = 0xC000040D, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED = 0xC000040E, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED = 0xC000040F, + MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED = 0xC0000410, + MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE = 0xC0000411, + MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED = 0xC0000412, + MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED = 0xC0000413, + MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED = 0xC0000414, + MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD = 0xC0000415, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 0xC0000416, + MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER = 0xC0000417, + MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED = 0xC0000418, + MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST = 0xC0000419, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST = 0xC000041A, + MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST = 0xC000041B, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME = 0xC000041C, + MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION = 0xC000041D, + MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE = 0xC0000420, + MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP = 0xC0000421, + MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK = 0xC0000423, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED = 0xC0000424, + MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED = 0xC0000425, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED = 0xC0000426, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION = 0xC0000427, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH = 0xC0000428, + MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE = 0xC0000429, + MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE = 0xC000042A, + MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B, + MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED = 0xC000042C, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT = 0xC000042D, + MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE = 0xC000042F, + MD_NTSTATUS_WIN_STATUS_BEYOND_VDL = 0xC0000432, + MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS = 0xC0000433, + MD_NTSTATUS_WIN_STATUS_PTE_CHANGED = 0xC0000434, + MD_NTSTATUS_WIN_STATUS_PURGE_FAILED = 0xC0000435, + MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION = 0xC0000440, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 0xC0000441, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER = 0xC0000442, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 0xC0000443, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 0xC0000444, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE = 0xC0000445, + MD_NTSTATUS_WIN_STATUS_INVALID_LABEL = 0xC0000446, + MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED = 0xC0000450, + MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE = 0xC0000451, + MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND = 0xC0000452, + MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION = 0xC0000453, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES = 0xC0000454, + MD_NTSTATUS_WIN_STATUS_INVALID_SESSION = 0xC0000455, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION = 0xC0000456, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION = 0xC0000457, + MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT = 0xC0000458, + MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED = 0xC0000459, + MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED = 0xC0000460, + MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED = 0xC0000461, + MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION = 0xC0000462, + MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED = 0xC0000463, + MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE = 0xC0000464, + MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN = 0xC0000465, + MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE = 0xC0000466, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE = 0xC0000467, + MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES = 0xC0000468, + MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING = 0xC0000469, + MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY = 0xC000046A, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE = 0xC000046B, + MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED = 0xC000046C, + MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED = 0xC000046D, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 0xC000046E, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL = 0xC000046F, + MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR = 0xC0000470, + MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION = 0xC0000471, + MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED = 0xC0000472, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS = 0xC0000473, + MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT = 0xC0000474, + MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST = 0xC0000475, + MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS = 0xC0000476, + MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH = 0xC0000477, + MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED = 0xC0000478, + MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE = 0xC0000479, + MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED = 0xC000047A, + MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED = 0xC000047B, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED = 0xC000047C, + MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT = 0xC000047D, + MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION = 0xC000047E, + MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN = 0xC000047F, + MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE = 0xC0000480, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED = 0xC0000481, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT = 0xC0000482, + MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR = 0xC0000483, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID = 0xC0000484, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID = 0xC0000485, + MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH = 0xC0000486, + MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE = 0xC0000487, + MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS = 0xC0000488, + MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION = 0xC0000489, + MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY = 0xC000048A, + MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE = 0xC000048B, + MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES = 0xC000048C, + MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES = 0xC000048D, + MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP = 0xC000048E, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE = 0xC000048F, + MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS = 0xC0000490, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND = 0xC0000491, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND = 0xC0000492, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE = 0xC0000493, + MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED = 0xC0000494, + MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING = 0xC0000495, + MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL = 0xC0000496, + MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE = 0xC0000497, + MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE = 0xC0000499, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX = 0xC000049A, + MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED = 0xC000049B, + MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS = 0xC000049C, + MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED = 0xC000049D, + MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE = 0xC000049E, + MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED = 0xC000049F, + MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING = 0xC00004A0, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED = 0xC00004A1, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION = 0xC00004A2, + MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL = 0xC00004A3, + MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED = 0xC00004A4, + MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND = 0xC00004A5, + MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED = 0xC00004A6, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED = 0xC00004A7, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET = 0xC00004A8, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE = 0xC00004A9, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER = 0xC00004AA, + MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE = 0xC00004AB, + MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT = 0xC00004AC, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID = 0xC00004AD, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST = 0xC00004AE, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS = 0xC00004AF, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY = 0xC00004B0, + MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME = 0xC00004B1, + MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE = 0xC00004B2, + MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR = 0xC00004B3, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED = 0xC00004B4, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT = 0xC00004B5, + MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED = 0xC00004B6, + MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED = 0xC00004B7, + MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG = 0xC00004B8, + MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES = 0xC00004B9, + MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH = 0xC00004BA, + MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES = 0xC00004BD, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME = 0xC0000500, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX = 0xC0000501, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK = 0xC0000502, + MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS = 0xC0000503, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE = 0xC0000504, + MD_NTSTATUS_WIN_STATUS_INVALID_CAP = 0xC0000505, + MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS = 0xC0000506, + MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG = 0xC0000507, + MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED = 0xC0000508, + MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER = 0xC0000509, + MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE = 0xC000050A, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B, + MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT = 0xC000050C, + MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME = 0xC000050D, + MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID = 0xC000050E, + MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY = 0xC000050F, + MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED = 0xC0000510, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED = 0xC0000511, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING = 0xC0000512, + MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE = 0xC0000513, + MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED = 0xC0000514, + MD_NTSTATUS_WIN_STATUS_INTERRUPTED = 0xC0000515, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING = 0xC0000516, + MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION = 0xC0000602, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED = 0xC0000603, + MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED = 0xC0000604, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED = 0xC0000605, + MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION = 0xC0000606, + MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED = 0xC000060A, + MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION = 0xC000060B, + MD_NTSTATUS_WIN_STATUS_PORT_CLOSED = 0xC0000700, + MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST = 0xC0000701, + MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE = 0xC0000702, + MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED = 0xC0000703, + MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH = 0xC0000704, + MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705, + MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE = 0xC0000706, + MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED = 0xC0000707, + MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE = 0xC0000708, + MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR = 0xC0000709, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION = 0xC000070A, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED = 0xC000070B, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED = 0xC000070C, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED = 0xC000070D, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED = 0xC000070E, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION = 0xC000070F, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING = 0xC0000710, + MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING = 0xC0000711, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED = 0xC0000712, + MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION = 0xC0000713, + MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE = 0xC0000714, + MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED = 0xC0000715, + MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION = 0xC0000716, + MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION = 0xC0000717, + MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED = 0xC0000718, + MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH = 0xC0000719, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B, + MD_NTSTATUS_WIN_STATUS_INVALID_THREAD = 0xC000071C, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION = 0xC000071D, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK = 0xC000071E, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG = 0xC000071F, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK = 0xC0000720, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721, + MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED = 0xC0000722, + MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE = 0xC0000723, + MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE = 0xC0000724, + MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE = 0xC0000725, + MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE = 0xC0000726, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED = 0xC0000800, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801, + MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED = 0xC0000802, + MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED = 0xC0000804, + MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS = 0xC0000805, + MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY = 0xC0000806, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL = 0xC0000808, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL = 0xC0000809, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED = 0xC000080A, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE = 0xC000080B, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL = 0xC000080C, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED = 0xC000080D, + MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED = 0xC000080E, + MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS = 0xC000080F, + MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE = 0xC0000810, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS = 0xC0000811, + MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT = 0xC0000901, + MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED = 0xC0000902, + MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE = 0xC0000903, + MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE = 0xC0000904, + MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED = 0xC0000905, + MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED = 0xC0000906, + MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED = 0xC0000907, + MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE = 0xC0000908, + MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK = 0xC0000909, + MD_NTSTATUS_WIN_STATUS_BAD_KEY = 0xC000090A, + MD_NTSTATUS_WIN_STATUS_BAD_DATA = 0xC000090B, + MD_NTSTATUS_WIN_STATUS_NO_KEY = 0xC000090C, + MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED = 0xC0000910, + MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION = 0xC0009898, + MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE = 0xC000A000, + MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED = 0xC000A001, + MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH = 0xC000A002, + MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION = 0xC000A003, + MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION = 0xC000A004, + MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION = 0xC000A005, + MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED = 0xC000A006, + MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE = 0xC000A007, + MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN = 0xC000A008, + MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW = 0xC000A010, + MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW = 0xC000A011, + MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED = 0xC000A012, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED = 0xC000A013, + MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED = 0xC000A014, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082, + MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR = 0xC000A083, + MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR = 0xC000A084, + MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT = 0xC000A085, + MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE = 0xC000A086, + MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 0xC000A087, + MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND = 0xC000A088, + MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE = 0xC000A089, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED = 0xC000A100, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT = 0xC000A101, + MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED = 0xC000A121, + MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID = 0xC000A122, + MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED = 0xC000A123, + MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET = 0xC000A124, + MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED = 0xC000A125, + MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE = 0xC000A126, + MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL = 0xC000A141, + MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING = 0xC000A142, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT = 0xC000A143, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 0xC000A145, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS = 0xC000A146, + MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER = 0xC000A200, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER = 0xC000A201, + MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH = 0xC000A202, + MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED = 0xC000A203, + MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED = 0xC000A204, + MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND = 0xC000A281, + MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED = 0xC000A282, + MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT = 0xC000A283, + MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED = 0xC000A284, + MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED = 0xC000A285, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4, + MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT = 0xC000A2A5, + MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT = 0xC000A2A6, + MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT = 0xC000A2A7, + MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT = 0xC000C001, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE = 0xC000CE01, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT = 0xC000CE02, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY = 0xC000CE03, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN = 0xC000CE04, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION = 0xC000CE05, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT = 0xC000CF00, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING = 0xC000CF01, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT = 0xC000CF02, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE = 0xC000CF03, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED = 0xC000CF06, + MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE = 0xC000CF07, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC = 0xC000CF08, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED = 0xC000CF09, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED = 0xC000CF0A, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST = 0xC000CF0B, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME = 0xC000CF0C, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY = 0xC000CF0D, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED = 0xC000CF0E, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED = 0xC000CF0F, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES = 0xC000CF10, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE = 0xC000CF11, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL = 0xC000CF12, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT = 0xC000CF13, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE = 0xC000CF14, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED = 0xC000CF15, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED = 0xC000CF16, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT = 0xC000CF17, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED = 0xC000CF18, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS = 0xC000CF19, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT = 0xC000CF1A, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED = 0xC000CF1B, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED = 0xC000CF1D, + MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT = 0xC000CF1E, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT = 0xC000CF1F, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED = 0xC000CF20, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS = 0xC000F500, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED = 0xC000F501, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED = 0xC000F502, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED = 0xC000F503, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR = 0xC000F504, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER = 0xC000F505, + MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE = 0xC0010001, + MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE = 0xC0010002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING = 0xC0020001, + MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING = 0xC0020003, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004, + MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID = 0xC0020006, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT = 0xC0020007, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR = 0xC0020008, + MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND = 0xC0020009, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT = 0xC002000A, + MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND = 0xC002000B, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED = 0xC002000C, + MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED = 0xC002000D, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING = 0xC002000E, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED = 0xC002000F, + MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING = 0xC0020010, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE = 0xC0020011, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF = 0xC0020012, + MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS = 0xC0020013, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS = 0xC0020014, + MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT = 0xC0020015, + MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES = 0xC0020016, + MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE = 0xC0020017, + MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY = 0xC0020018, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS = 0xC0020019, + MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE = 0xC002001A, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED = 0xC002001B, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE = 0xC002001C, + MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR = 0xC002001D, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN = 0xC002001F, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE = 0xC0020021, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG = 0xC0020022, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND = 0xC0020023, + MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME = 0xC0020024, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX = 0xC0020025, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX = 0xC0020026, + MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS = 0xC0020028, + MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT = 0xC0020029, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE = 0xC002002A, + MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL = 0xC002002B, + MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG = 0xC002002C, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND = 0xC002002D, + MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE = 0xC002002E, + MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH = 0xC002002F, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE = 0xC0020030, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL = 0xC0020031, + MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY = 0xC0020032, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE = 0xC0020033, + MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY = 0xC0020034, + MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP = 0xC0020035, + MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED = 0xC0020036, + MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT = 0xC0020037, + MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME = 0xC0020038, + MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION = 0xC0020039, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS = 0xC002003A, + MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED = 0xC002003B, + MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND = 0xC002003C, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS = 0xC002003D, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND = 0xC002003E, + MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE = 0xC002003F, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID = 0xC0020040, + MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT = 0xC0020041, + MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE = 0xC0020042, + MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR = 0xC0020043, + MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE = 0xC0020044, + MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR = 0xC0020045, + MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO = 0xC0020046, + MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW = 0xC0020047, + MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW = 0xC0020048, + MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS = 0xC0020049, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS = 0xC002004A, + MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND = 0xC002004B, + MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE = 0xC002004C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT = 0xC002004D, + MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES = 0xC002004F, + MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED = 0xC0020050, + MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE = 0xC0020051, + MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE = 0xC0020052, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL = 0xC0020053, + MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME = 0xC0020054, + MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR = 0xC0020055, + MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR = 0xC0020057, + MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED = 0xC0020058, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE = 0xC0020062, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL = 0xC0020063, + MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED = 0xC0020064, + MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED = 0xC0020065, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES = 0xC0030001, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL = 0xC0030002, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE = 0xC0030003, + MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT = 0xC0030004, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH = 0xC0030005, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED = 0xC0030006, + MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH = 0xC0030007, + MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE = 0xC0030008, + MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER = 0xC0030009, + MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE = 0xC003000A, + MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL = 0xC003000B, + MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA = 0xC003000C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION = 0xC0030059, + MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION = 0xC003005A, + MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION = 0xC003005B, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT = 0xC003005C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION = 0xC003005D, + MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION = 0xC003005E, + MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED = 0xC003005F, + MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR = 0xC0030060, + MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY = 0xC0030061, + MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE = 0xC0040035, + MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED = 0xC0040036, + MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED = 0xC0040037, + MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID = 0xC0040038, + MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED = 0xC0040039, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID = 0xC00A0001, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD = 0xC00A0002, + MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND = 0xC00A0003, + MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING = 0xC00A0006, + MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF = 0xC00A0007, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND = 0xC00A0008, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME = 0xC00A0009, + MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR = 0xC00A000A, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT = 0xC00A000B, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER = 0xC00A000C, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE = 0xC00A000D, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY = 0xC00A000E, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE = 0xC00A000F, + MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR = 0xC00A0010, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID = 0xC00A0012, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE = 0xC00A0013, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED = 0xC00A0014, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND = 0xC00A0015, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION = 0xC00A0016, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY = 0xC00A0017, + MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE = 0xC00A0018, + MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID = 0xC00A0022, + MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE = 0xC00A0024, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT = 0xC00A0026, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT = 0xC00A0027, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT = 0xC00A0028, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED = 0xC00A002A, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED = 0xC00A002B, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD = 0xC00A002E, + MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND = 0xC00A002F, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID = 0xC00A0030, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED = 0xC00A0031, + MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR = 0xC00A0032, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET = 0xC00A0033, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE = 0xC00A0034, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE = 0xC00A0035, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING = 0xC00A0036, + MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED = 0xC00A0037, + MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR = 0xC00A0038, + MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS = 0xC00A0039, + MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR = 0xC00A003A, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND = 0xC00B0001, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE = 0xC00B0002, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG = 0xC00B0003, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME = 0xC00B0004, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME = 0xC00B0005, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED = 0xC00B0006, + MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP = 0xC00B0007, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE = 0xC0130001, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS = 0xC0130002, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS = 0xC0130003, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND = 0xC0130004, + MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND = 0xC0130005, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS = 0xC0130006, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND = 0xC0130007, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS = 0xC0130008, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND = 0xC0130009, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST = 0xC013000A, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER = 0xC013000B, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN = 0xC013000C, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE = 0xC013000D, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER = 0xC013000E, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS = 0xC013000F, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK = 0xC0130010, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS = 0xC0130011, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP = 0xC0130012, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED = 0xC0130013, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED = 0xC0130014, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT = 0xC0130015, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL = 0xC0130016, + MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED = 0xC0130017, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH = 0xC0130018, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL = 0xC0130019, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS = 0xC0130020, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR = 0xC0130021, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED = 0xC0130022, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED = 0xC0130023, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING = 0xC0130024, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS = 0xC0130025, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL = 0xC0130026, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS = 0xC0130027, + MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT = 0xC0130028, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE = 0xC0130029, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR = 0xC0130030, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED = 0xC0130031, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE = 0xC0140001, + MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW = 0xC0140002, + MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED = 0xC0140003, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX = 0xC0140004, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT = 0xC0140005, + MD_NTSTATUS_WIN_STATUS_ACPI_FATAL = 0xC0140006, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME = 0xC0140007, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE = 0xC0140008, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE = 0xC0140009, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE = 0xC014000A, + MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT = 0xC014000B, + MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED = 0xC014000C, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE = 0xC014000D, + MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION = 0xC014000E, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA = 0xC014000F, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION = 0xC0140010, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE = 0xC0140011, + MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK = 0xC0140012, + MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED = 0xC0140013, + MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED = 0xC0140014, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL = 0xC0140015, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED = 0xC0140016, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER = 0xC0140017, + MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS = 0xC0140018, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE = 0xC0140019, + MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED = 0xC0140020, + MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED = 0xC0140021, + MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND = 0xC0150001, + MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX = 0xC0150002, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT = 0xC0150003, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND = 0xC0150004, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR = 0xC0150005, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR = 0xC0150006, + MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED = 0xC0150007, + MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND = 0xC0150008, + MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT = 0xC0150009, + MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE = 0xC015000A, + MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED = 0xC015000B, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING = 0xC015000C, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET = 0xC015000E, + MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION = 0xC015000F, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION = 0xC0150010, + MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION = 0xC0150011, + MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 0xC0150012, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED = 0xC0150013, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK = 0xC0150014, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION = 0xC0150015, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 0xC0150016, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 0xC0150017, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 0xC0150018, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR = 0xC0150019, + MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT = 0xC015001A, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH = 0xC015001B, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 0xC015001C, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT = 0xC015001D, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 0xC015001E, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY = 0xC015001F, + MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED = 0xC0150020, + MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH = 0xC0150021, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG = 0xC0150022, + MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED = 0xC0150023, + MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE = 0xC0150024, + MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED = 0xC0150025, + MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED = 0xC0150026, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING = 0xC0150027, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT = 0xC0190001, + MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION = 0xC0190002, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE = 0xC0190003, + MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED = 0xC0190004, + MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE = 0xC0190005, + MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT = 0xC0190006, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED = 0xC0190007, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM = 0xC0190008, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE = 0xC019000A, + MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE = 0xC019000B, + MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH = 0xC019000C, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS = 0xC019000F, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED = 0xC0190010, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND = 0xC0190011, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS = 0xC0190012, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID = 0xC0190013, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED = 0xC0190014, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED = 0xC0190015, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED = 0xC0190016, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER = 0xC0190017, + MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID = 0xC0190018, + MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED = 0xC0190019, + MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS = 0xC0190021, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND = 0xC0190022, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID = 0xC0190023, + MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xC0190024, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xC0190025, + MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xC0190026, + MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID = 0xC0190028, + MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED = 0xC0190030, + MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED = 0xC0190032, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR = 0xC0190033, + MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT = 0xC0190036, + MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xC0190037, + MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY = 0xC0190038, + MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY = 0xC0190039, + MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST = 0xC019003A, + MD_NTSTATUS_WIN_STATUS_TM_VOLATILE = 0xC019003B, + MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED = 0xC019003C, + MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT = 0xC019003D, + MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION = 0xC019003E, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xC019003F, + MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xC0190040, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION = 0xC0190043, + MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xC0190044, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN = 0xC0190045, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS = 0xC0190046, + MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME = 0xC0190047, + MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES = 0xC0190048, + MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION = 0xC0190049, + MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH = 0xC019004A, + MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION = 0xC019004B, + MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK = 0xC019004C, + MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS = 0xC019004D, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND = 0xC019004E, + MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND = 0xC019004F, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND = 0xC0190050, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND = 0xC0190051, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE = 0xC0190052, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 0xC0190053, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT = 0xC0190054, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED = 0xC0190055, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 0xC0190056, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED = 0xC0190057, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG = 0xC0190058, + MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION = 0xC0190059, + MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 0xC019005A, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED = 0xC019005B, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH = 0xC019005C, + MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT = 0xC019005D, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH = 0xC019005E, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR = 0xC019005F, + MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE = 0xC0190060, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED = 0xC0190061, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID = 0xC01A0001, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID = 0xC01A0002, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED = 0xC01A0003, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE = 0xC01A0004, + MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE = 0xC01A0005, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED = 0xC01A0006, + MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID = 0xC01A0007, + MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID = 0xC01A0008, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION = 0xC01A0009, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID = 0xC01A000A, + MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID = 0xC01A000B, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT = 0xC01A000D, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID = 0xC01A000E, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT = 0xC01A000F, + MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID = 0xC01A0010, + MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE = 0xC01A0011, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED = 0xC01A0012, + MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG = 0xC01A0013, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED = 0xC01A0014, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED = 0xC01A0015, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID = 0xC01A0016, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT = 0xC01A0017, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL = 0xC01A0018, + MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT = 0xC01A0019, + MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID = 0xC01A001A, + MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID = 0xC01A001B, + MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID = 0xC01A001C, + MD_NTSTATUS_WIN_STATUS_LOG_FULL = 0xC01A001D, + MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED = 0xC01A001E, + MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED = 0xC01A001F, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS = 0xC01A0020, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS = 0xC01A0021, + MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL = 0xC01A0022, + MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS = 0xC01A0023, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED = 0xC01A0024, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED = 0xC01A0025, + MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS = 0xC01A0026, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED = 0xC01A0027, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED = 0xC01A0028, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED = 0xC01A0029, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID = 0xC01A002A, + MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID = 0xC01A002B, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED = 0xC01A002C, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED = 0xC01A002D, + MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY = 0xC01A002E, + MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED = 0xC01A002F, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION = 0xC01A0030, + MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD = 0xC01B00EA, + MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED = 0xC01C0001, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED = 0xC01C0002, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST = 0xC01C0003, + MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO = 0xC01C0004, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST = 0xC01C0005, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION = 0xC01C0006, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED = 0xC01C0007, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY = 0xC01C0008, + MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP = 0xC01C0009, + MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR = 0xC01C000A, + MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT = 0xC01C000B, + MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL = 0xC01C000C, + MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY = 0xC01C000D, + MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED = 0xC01C000E, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH = 0xC01C000F, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH = 0xC01C0010, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION = 0xC01C0011, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION = 0xC01C0012, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND = 0xC01C0013, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND = 0xC01C0014, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND = 0xC01C0015, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND = 0xC01C0016, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION = 0xC01C0017, + MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS = 0xC01C0018, + MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT = 0xC01C0019, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED = 0xC01C001A, + MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED = 0xC01C001B, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED = 0xC01C001C, + MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY = 0xC01C0020, + MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY = 0xC01C0023, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR = 0xC01D0001, + MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT = 0xC01D0002, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM = 0xC01D0003, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK = 0xC01D0004, + MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED = 0xC01D0005, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK = 0xC01D0006, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK = 0xC01D0007, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA = 0xC01D0008, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK = 0xC01D0009, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE = 0xC01D000A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER = 0xC01E0000, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER = 0xC01E0001, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER = 0xC01E0002, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET = 0xC01E0003, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL = 0xC01E0004, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED = 0xC01E0005, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED = 0xC01E0007, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH = 0xC01E0009, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE = 0xC01E000D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED = 0xC01E000E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW = 0xC01E000F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND = 0xC01E0010, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED = 0xC01E0011, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN = 0xC01E0012, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED = 0xC01E0013, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY = 0xC01E0102, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID = 0xC01E0106, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED = 0xC01E0108, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION = 0xC01E0109, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE = 0xC01E0110, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION = 0xC01E0111, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED = 0xC01E0112, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE = 0xC01E0113, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE = 0xC01E0114, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE = 0xC01E0115, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST = 0xC01E0116, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE = 0xC01E0200, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY = 0xC01E0300, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED = 0xC01E0301, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED = 0xC01E0302, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN = 0xC01E0303, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE = 0xC01E0304, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET = 0xC01E0305, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED = 0xC01E0306, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET = 0xC01E0308, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET = 0xC01E0309, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY = 0xC01E030A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION = 0xC01E030B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION = 0xC01E030C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE = 0xC01E0310, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE = 0xC01E0311, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET = 0xC01E0312, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY = 0xC01E0313, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET = 0xC01E0314, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET = 0xC01E0315, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET = 0xC01E0316, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET = 0xC01E0317, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET = 0xC01E0318, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH = 0xC01E0319, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY = 0xC01E031A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET = 0xC01E031B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE = 0xC01E031C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET = 0xC01E031D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET = 0xC01E031F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET = 0xC01E0320, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET = 0xC01E0321, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE = 0xC01E0322, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN = 0xC01E0323, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE = 0xC01E0324, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION = 0xC01E0325, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES = 0xC01E0326, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY = 0xC01E0327, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE = 0xC01E0328, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET = 0xC01E0329, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET = 0xC01E032A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR = 0xC01E032B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET = 0xC01E032C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET = 0xC01E032D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE = 0xC01E032E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE = 0xC01E032F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED = 0xC01E0330, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE = 0xC01E0331, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE = 0xC01E0332, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET = 0xC01E0333, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER = 0xC01E0334, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR = 0xC01E0335, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN = 0xC01E0336, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY = 0xC01E0337, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED = 0xC01E0338, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY = 0xC01E0339, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE = 0xC01E033A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE = 0xC01E033B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE = 0xC01E033C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT = 0xC01E033D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS = 0xC01E033E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE = 0xC01E033F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY = 0xC01E0340, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT = 0xC01E0341, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE = 0xC01E0342, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN = 0xC01E0343, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL = 0xC01E0344, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION = 0xC01E0345, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED = 0xC01E0346, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP = 0xC01E0347, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED = 0xC01E0348, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED = 0xC01E0349, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET = 0xC01E034A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON = 0xC01E034D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE = 0xC01E034E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE = 0xC01E034F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS = 0xC01E0350, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING = 0xC01E0352, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED = 0xC01E0353, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS = 0xC01E0354, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT = 0xC01E0355, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM = 0xC01E0356, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN = 0xC01E0357, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT = 0xC01E0358, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED = 0xC01E0359, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION = 0xC01E035A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE = 0xC01E035B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET = 0xC01E035C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED = 0xC01E0400, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED = 0xC01E0401, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER = 0xC01E0430, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED = 0xC01E0431, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED = 0xC01E0432, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY = 0xC01E0433, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED = 0xC01E0434, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON = 0xC01E0435, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE = 0xC01E0436, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER = 0xC01E0438, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED = 0xC01E043B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED = 0xC01E0500, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED = 0xC01E0501, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED = 0xC01E0502, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS = 0xC01E0503, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST = 0xC01E0505, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR = 0xC01E050B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE = 0xC01E050C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH = 0xC01E050E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED = 0xC01E050F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED = 0xC01E0510, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED = 0xC01E0511, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM = 0xC01E0512, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP = 0xC01E0513, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP = 0xC01E0514, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA = 0xC01E0515, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET = 0xC01E0516, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH = 0xC01E0517, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE = 0xC01E0518, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS = 0xC01E051A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS = 0xC01E051C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST = 0xC01E051D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR = 0xC01E051E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS = 0xC01E051F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED = 0xC01E0520, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST = 0xC01E0521, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED = 0xC01E0580, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST = 0xC01E0581, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA = 0xC01E0582, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA = 0xC01E0583, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED = 0xC01E0584, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA = 0xC01E0585, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE = 0xC01E0586, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING = 0xC01E0587, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR = 0xC01E0588, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND = 0xC01E0589, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH = 0xC01E058A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM = 0xC01E058B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE = 0xC01E058C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS = 0xC01E058D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED = 0xC01E05E0, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E05E1, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E05E2, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E05E3, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER = 0xC01E05E4, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E05E5, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL = 0xC01E05E6, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR = 0xC01E05E7, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E05E8, + MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME = 0xC0210000, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED = 0xC0210001, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION = 0xC0210002, + MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL = 0xC0210003, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS = 0xC0210004, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE = 0xC0210005, + MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED = 0xC0210006, + MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED = 0xC0210007, + MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE = 0xC0210008, + MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED = 0xC0210009, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA = 0xC021000A, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND = 0xC021000B, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME = 0xC021000C, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR = 0xC021000D, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR = 0xC021000E, + MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE = 0xC021000F, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE = 0xC0210010, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION = 0xC0210011, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME = 0xC0210012, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND = 0xC0210013, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID = 0xC0210014, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK = 0xC0210015, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED = 0xC0210016, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO = 0xC0210017, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR = 0xC0210018, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK = 0xC0210019, + MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID = 0xC021001A, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION = 0xC021001B, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG = 0xC021001C, + MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED = 0xC021001D, + MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED = 0xC021001E, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER = 0xC021001F, + MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY = 0xC0210020, + MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED = 0xC0210021, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS = 0xC0210022, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED = 0xC0210023, + MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY = 0xC0210024, + MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED = 0xC0210025, + MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE = 0xC0210026, + MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED = 0xC0210027, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED = 0xC0210028, + MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG = 0xC0210029, + MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE = 0xC021002A, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL = 0xC0210030, + MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID = 0xC0210031, + MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210032, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210033, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK = 0xC0210034, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER = 0xC0210035, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING = 0xC0210036, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE = 0xC0210037, + MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED = 0xC0210038, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED = 0xC0210039, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE = 0xC021003A, + MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT = 0xC021003B, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT = 0xC021003C, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME = 0xC021003D, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED = 0xC021003E, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED = 0xC021003F, + MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED = 0xC0210040, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND = 0xC0220001, + MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND = 0xC0220002, + MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND = 0xC0220003, + MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND = 0xC0220004, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND = 0xC0220005, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006, + MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND = 0xC0220007, + MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND = 0xC0220008, + MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS = 0xC0220009, + MD_NTSTATUS_WIN_STATUS_FWP_IN_USE = 0xC022000A, + MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS = 0xC022000B, + MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION = 0xC022000C, + MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS = 0xC022000D, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS = 0xC022000E, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED = 0xC022000F, + MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED = 0xC0220010, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN = 0xC0220011, + MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT = 0xC0220012, + MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED = 0xC0220013, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER = 0xC0220014, + MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY = 0xC0220015, + MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH = 0xC0220016, + MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT = 0xC0220017, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS = 0xC0220018, + MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED = 0xC0220019, + MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH = 0xC022001A, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE = 0xC022001B, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER = 0xC022001C, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR = 0xC022001D, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS = 0xC022001E, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK = 0xC022001F, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE = 0xC0220020, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL = 0xC0220021, + MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY = 0xC0220022, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME = 0xC0220023, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE = 0xC0220024, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT = 0xC0220025, + MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH = 0xC0220026, + MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH = 0xC0220027, + MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS = 0xC0220028, + MD_NTSTATUS_WIN_STATUS_FWP_RESERVED = 0xC0220029, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION = 0xC022002A, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD = 0xC022002B, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER = 0xC022002C, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER = 0xC022002D, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER = 0xC022002E, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT = 0xC022002F, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD = 0xC0220030, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP = 0xC0220031, + MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED = 0xC0220032, + MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH = 0xC0220033, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH = 0xC0220034, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER = 0xC0220035, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS = 0xC0220036, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED = 0xC0220037, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM = 0xC0220038, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM = 0xC0220039, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM = 0xC022003A, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION = 0xC022003B, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD = 0xC022003C, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT = 0xC022003D, + MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY = 0xC022003E, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED = 0xC022003F, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL = 0xC0220040, + MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED = 0xC0220041, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME = 0xC0220042, + MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON = 0xC0220043, + MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING = 0xC0220044, + MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY = 0xC0220100, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING = 0xC0220101, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE = 0xC0220102, + MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND = 0xC0220103, + MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP = 0xC0220104, + MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING = 0xC0230002, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION = 0xC0230004, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS = 0xC0230005, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND = 0xC0230006, + MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED = 0xC0230007, + MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED = 0xC0230008, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL = 0xC0230009, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS = 0xC023000A, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND = 0xC023000B, + MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED = 0xC023000C, + MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS = 0xC023000D, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET = 0xC023000F, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST = 0xC0230010, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY = 0xC0230011, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH = 0xC0230014, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA = 0xC0230015, + MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT = 0xC0230016, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID = 0xC0230017, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED = 0xC0230018, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA = 0xC0230019, + MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE = 0xC023001A, + MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND = 0xC023001B, + MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE = 0xC023001C, + MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED = 0xC023001D, + MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT = 0xC023001E, + MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED = 0xC023001F, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS = 0xC0230022, + MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED = 0xC023002A, + MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND = 0xC023002B, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION = 0xC023002C, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT = 0xC023002D, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE = 0xC023002E, + MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE = 0xC023002F, + MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED = 0xC0230030, + MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES = 0xC0230031, + MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED = 0xC02300BB, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY = 0xC023100F, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE = 0xC0232001, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE = 0xC0232005, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE = 0xC0232006, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED = 0xC0232007, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED = 0xC0232008, + MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE = 0xC0240000, + MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE = 0xC0240001, + MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK = 0xC0290000, + MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL = 0xC0290001, + MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX = 0xC0290002, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER = 0xC0290003, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE = 0xC0290004, + MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED = 0xC0290005, + MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED = 0xC0290006, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED = 0xC0290007, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD = 0xC0290008, + MD_NTSTATUS_WIN_STATUS_TPM_FAIL = 0xC0290009, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL = 0xC029000A, + MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED = 0xC029000B, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE = 0xC029000C, + MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND = 0xC029000D, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC = 0xC029000E, + MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL = 0xC029000F, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO = 0xC0290010, + MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE = 0xC0290011, + MD_NTSTATUS_WIN_STATUS_TPM_NOSRK = 0xC0290012, + MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB = 0xC0290013, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET = 0xC0290014, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES = 0xC0290015, + MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM = 0xC0290016, + MD_NTSTATUS_WIN_STATUS_TPM_SIZE = 0xC0290017, + MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL = 0xC0290018, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE = 0xC0290019, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD = 0xC029001A, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR = 0xC029001B, + MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST = 0xC029001C, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL = 0xC029001D, + MD_NTSTATUS_WIN_STATUS_TPM_BADTAG = 0xC029001E, + MD_NTSTATUS_WIN_STATUS_TPM_IOERROR = 0xC029001F, + MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR = 0xC0290020, + MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR = 0xC0290021, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE = 0xC0290022, + MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT = 0xC0290023, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE = 0xC0290024, + MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE = 0xC0290025, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT = 0xC0290026, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG = 0xC0290027, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY = 0xC0290028, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION = 0xC0290029, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME = 0xC029002A, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE = 0xC029002B, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE = 0xC029002C, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE = 0xC029002D, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION = 0xC029002E, + MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT = 0xC029002F, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL = 0xC0290030, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL = 0xC0290031, + MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE = 0xC0290032, + MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL = 0xC0290033, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE = 0xC0290034, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE = 0xC0290035, + MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS = 0xC0290036, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY = 0xC0290037, + MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION = 0xC0290038, + MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN = 0xC0290039, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED = 0xC029003A, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT = 0xC029003B, + MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED = 0xC029003C, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY = 0xC029003D, + MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY = 0xC029003E, + MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE = 0xC029003F, + MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT = 0xC0290040, + MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED = 0xC0290041, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES = 0xC0290042, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE = 0xC0290043, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL = 0xC0290044, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER = 0xC0290045, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE = 0xC0290046, + MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP = 0xC0290047, + MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES = 0xC0290048, + MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR = 0xC0290049, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING = 0xC029004A, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK = 0xC029004B, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY = 0xC029004C, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN = 0xC029004D, + MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE = 0xC029004E, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL = 0xC029004F, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES = 0xC0290050, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0 = 0xC0290051, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1 = 0xC0290052, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS = 0xC0290053, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS = 0xC0290054, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE = 0xC0290055, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY = 0xC0290056, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W = 0xC0290057, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE = 0xC0290058, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE = 0xC0290059, + MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT = 0xC029005A, + MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS = 0xC029005B, + MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE = 0xC029005C, + MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION = 0xC029005D, + MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE = 0xC029005E, + MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY = 0xC029005F, + MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK = 0xC0290061, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE = 0xC0290062, + MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE = 0xC0290063, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC = 0xC0290081, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES = 0xC0290082, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH = 0xC0290083, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE = 0xC0290084, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY = 0xC0290085, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE = 0xC0290087, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF = 0xC0290088, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE = 0xC0290089, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE = 0xC029008A, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE = 0xC029008B, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF = 0xC029008C, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE = 0xC029008D, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL = 0xC029008E, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE = 0xC029008F, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP = 0xC0290090, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME = 0xC0290092, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE = 0xC0290095, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC = 0xC0290096, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG = 0xC0290097, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR = 0xC0290098, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT = 0xC029009A, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE = 0xC029009B, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY = 0xC029009C, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL = 0xC029009D, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY = 0xC029009F, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET = 0xC02900A0, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS = 0xC02900A1, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH = 0xC02900A2, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED = 0xC02900A3, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC = 0xC02900A4, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING = 0xC02900A5, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE = 0xC02900A6, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT = 0xC02900A7, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE = 0xC0290100, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE = 0xC0290101, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE = 0xC0290103, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE = 0xC029010B, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC = 0xC0290119, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED = 0xC0290120, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE = 0xC0290121, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE = 0xC0290123, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE = 0xC0290124, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING = 0xC0290125, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY = 0xC0290126, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR = 0xC0290127, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED = 0xC0290128, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE = 0xC029012D, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS = 0xC029012E, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE = 0xC029012F, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT = 0xC0290130, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED = 0xC0290131, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE = 0xC0290142, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE = 0xC0290143, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE = 0xC0290144, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT = 0xC0290145, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE = 0xC0290146, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE = 0xC0290147, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED = 0xC0290148, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION = 0xC0290149, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED = 0xC029014A, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE = 0xC029014B, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED = 0xC029014C, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT = 0xC0290150, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH = 0xC0290151, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT = 0xC0290152, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST = 0xC0290153, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT = 0xC0290154, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE = 0xC0290155, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED = 0xC0290400, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE = 0xC0290401, + MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE = 0xC0290402, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED = 0xC0290403, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED = 0xC0290404, + MD_NTSTATUS_WIN_STATUS_TPM_RETRY = 0xC0290800, + MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST = 0xC0290801, + MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST = 0xC0290802, + MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING = 0xC0290803, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED = 0xC0291001, + MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS = 0xC0291002, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND = 0xC0291003, + MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED = 0xC0291004, + MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER = 0xC0291005, + MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED = 0xC0291006, + MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK = 0xC0292000, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY = 0xC0292001, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE = 0xC0292002, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER = 0xC0292003, + MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED = 0xC0292004, + MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED = 0xC0292005, + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL = 0xC0292006, + MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR = 0xC0292007, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED = 0xC0292008, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED = 0xC0292009, + MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND = 0xC029200A, + MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND = 0xC029200B, + MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED = 0xC029200C, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND = 0xC029200D, + MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT = 0xC029200E, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED = 0xC029200F, + MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION = 0xC0292010, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED = 0xC0292011, + MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET = 0xC0292012, + MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND = 0xC0292013, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED = 0xC0292014, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED = 0xC0292015, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID = 0xC0292016, + MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR = 0xC0292017, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED = 0xC0292018, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK = 0xC0292019, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY = 0xC029201A, + MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT = 0xC029201B, + MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED = 0xC029201C, + MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED = 0xC029201D, + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH = 0xC029201E, + MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED = 0xC029201F, + MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING = 0xC0292020, + MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED = 0xC0292021, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED = 0xC0292022, + MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT = 0xC0293002, + MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE = 0xC0293003, + MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT = 0xC0293004, + MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD = 0xC0293005, + MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED = 0xC0294000, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE = 0xC0350002, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT = 0xC0350003, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT = 0xC0350004, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER = 0xC0350005, + MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED = 0xC0350006, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE = 0xC0350007, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED = 0xC0350008, + MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY = 0xC0350009, + MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE = 0xC035000A, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY = 0xC035000B, + MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP = 0xC035000C, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID = 0xC035000D, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX = 0xC035000E, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID = 0xC0350011, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID = 0xC0350012, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS = 0xC0350013, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED = 0xC0350014, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE = 0xC0350015, + MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED = 0xC0350016, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE = 0xC0350017, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE = 0xC0350018, + MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE = 0xC0350019, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO = 0xC035001A, + MD_NTSTATUS_WIN_STATUS_HV_NO_DATA = 0xC035001B, + MD_NTSTATUS_WIN_STATUS_HV_INACTIVE = 0xC035001C, + MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES = 0xC035001D, + MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE = 0xC035001E, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER = 0xC0350033, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS = 0xC0350038, + MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR = 0xC035003C, + MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR = 0xC035003D, + MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT = 0xC035003E, + MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED = 0xC035003F, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX = 0xC0350041, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE = 0xC0350050, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE = 0xC0350051, + MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED = 0xC0350055, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID = 0xC0350057, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE = 0xC0350058, + MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID = 0xC0350060, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID = 0xC035006F, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE = 0xC0350070, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED = 0xC0350071, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE = 0xC0350072, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY = 0xC0350073, + MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED = 0xC0350074, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY = 0xC0350075, + MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT = 0xC0351000, + MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI = 0xC0360001, + MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002, + MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA = 0xC0360003, + MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED = 0xC0360004, + MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET = 0xC0360005, + MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006, + MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP = 0xC0360007, + MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP = 0xC0360008, + MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP = 0xC0360009, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK = 0xC0368000, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST = 0xC0368001, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET = 0xC0368002, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED = 0xC0368003, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES = 0xC0368004, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 0xC0368005, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 0xC0368006, + MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER = 0xC0370001, + MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS = 0xC0370002, + MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL = 0xC0370003, + MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT = 0xC0370004, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME = 0xC0370005, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG = 0xC0370006, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG = 0xC0370007, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS = 0xC0370008, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST = 0xC0370009, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND = 0xC037000A, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS = 0xC037000B, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT = 0xC037000C, + MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED = 0xC037000D, + MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED = 0xC037000E, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS = 0xC037000F, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX = 0xC0370010, + MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED = 0xC0370011, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE = 0xC0370012, + MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW = 0xC0370013, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE = 0xC0370014, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE = 0xC0370015, + MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE = 0xC0370016, + MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED = 0xC0370017, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE = 0xC0370018, + MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED = 0xC0370019, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED = 0xC037001A, + MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED = 0xC037001B, + MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING = 0xC037001C, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE = 0xC037001D, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT = 0xC037001E, + MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED = 0xC037001F, + MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET = 0xC0370020, + MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED = 0xC0370021, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET = 0xC0370022, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED = 0xC0370023, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL = 0xC0370024, + MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE = 0xC0370025, + MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT = 0xC0370026, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT = 0xC0370027, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM = 0xC0370028, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE = 0xC0370029, + MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED = 0xC037002A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL = 0xC0380001, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED = 0xC0380002, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC = 0xC0380003, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED = 0xC0380004, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME = 0xC0380005, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE = 0xC0380006, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC = 0xC0380007, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID = 0xC0380008, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID = 0xC0380009, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER = 0xC038000A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID = 0xC038000B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS = 0xC038000C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED = 0xC038000D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL = 0xC038000E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS = 0xC038000F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS = 0xC0380010, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING = 0xC0380011, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY = 0xC0380012, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE = 0xC0380013, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED = 0xC0380014, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID = 0xC0380015, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED = 0xC0380016, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS = 0xC0380017, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES = 0xC0380018, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED = 0xC0380019, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED = 0xC038001A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS = 0xC038001B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION = 0xC038001C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED = 0xC038001D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION = 0xC038001E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH = 0xC038001F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED = 0xC0380020, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID = 0xC0380021, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS = 0xC0380022, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC = 0xC0380023, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE = 0xC0380024, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID = 0xC0380025, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING = 0xC0380026, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED = 0xC0380027, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING = 0xC0380028, + MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED = 0xC0380029, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS = 0xC038002A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER = 0xC038002B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET = 0xC038002C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID = 0xC038002D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID = 0xC038002E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE = 0xC038002F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID = 0xC0380030, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID = 0xC0380031, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID = 0xC0380032, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE = 0xC0380033, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM = 0xC0380034, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM = 0xC0380035, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID = 0xC0380036, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED = 0xC0380037, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC = 0xC0380038, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE = 0xC0380039, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID = 0xC038003A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE = 0xC038003B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING = 0xC038003C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING = 0xC038003D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID = 0xC038003E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5 = 0xC038003F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE = 0xC0380040, + MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID = 0xC0380041, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS = 0xC0380042, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS = 0xC0380043, + MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE = 0xC0380044, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK = 0xC0380045, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID = 0xC0380046, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID = 0xC0380047, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE = 0xC0380048, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED = 0xC0380049, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED = 0xC038004A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE = 0xC038004B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED = 0xC038004C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID = 0xC038004D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE = 0xC038004E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK = 0xC038004F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE = 0xC0380050, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE = 0xC0380051, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK = 0xC0380052, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED = 0xC0380053, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID = 0xC0380054, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID = 0xC0380055, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED = 0xC0380056, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED = 0xC0380057, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES = 0xC0380058, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT = 0xC0380059, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID = 0xC038005A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED = 0xC038005B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED = 0xC038005C, + MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS = 0xC0390002, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING = 0xC03A0001, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH = 0xC03A0002, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT = 0xC03A0003, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN = 0xC03A0004, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION = 0xC03A0005, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH = 0xC03A0006, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION = 0xC03A0007, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT = 0xC03A0008, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE = 0xC03A0009, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT = 0xC03A000A, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE = 0xC03A000B, + MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH = 0xC03A000C, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND = 0xC03A000D, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH = 0xC03A000E, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH = 0xC03A000F, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE = 0xC03A0010, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE = 0xC03A0011, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE = 0xC03A0012, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE = 0xC03A0013, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND = 0xC03A0014, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK = 0xC03A0015, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED = 0xC03A0016, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH = 0xC03A0017, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED = 0xC03A0018, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT = 0xC03A0019, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION = 0xC03A001A, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE = 0xC03A001B, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE = 0xC03A001C, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE = 0xC03A001D, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED = 0xC03A001E, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE = 0xC03A001F, + MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED = 0xC03A0020, + MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE = 0xC03A0021, + MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE = 0xC03A0022, + MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE = 0xC03A0023, + MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE = 0xC03A0024, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL = 0xC03A0028, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID = 0xC03A0029, + MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED = 0xC03A002A, + MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION = 0xC03A0030, + MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA = 0xC03A0031, + MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE = 0xC03A0032, + MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE = 0xC03A0033, + MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND = 0xC0400001, + MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY = 0xC0400002, + MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL = 0xC0400003, + MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL = 0xC0400004, + MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED = 0xC0400005, + MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY = 0xC0400006, + MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION = 0xC0410001, + MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION = 0xC0410002, + MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION = 0xC0410003, + MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP = 0xC0410004, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE = 0xC0420001, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED = 0xC0420002, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED = 0xC0420003, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU = 0xC0420004, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION = 0xC0420005, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED = 0xC0420006, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET = 0xC0420007, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION = 0xC0420008, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL = 0xC0420009, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND = 0xC042000A, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG = 0xC042000B, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0xC042000C, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH = 0xC042000D, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY = 0xC042000E, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION = 0xC042000F, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE = 0xC0420010, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES = 0xC0420011, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR = 0xC0421000, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED = 0xC0430001, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION = 0xC0430002, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY = 0xC0430003, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 0xC0430004, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED = 0xC0430005, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED = 0xC0430007, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED = 0xC0430008, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN = 0xC0430009, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION = 0xC043000A, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH = 0xC043000B, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED = 0xC043000C, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH = 0xC043000D, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING = 0xC043000E, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY = 0xC043000F, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY = 0xC0430010, + MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND = 0xC0440001, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST = 0xC0440002, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED = 0xC0440003, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED = 0xC0440004, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY = 0xC0440005, + MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED = 0xC0450000, + MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE = 0xC0450001, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID = 0xC0500003, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT = 0xC0500004, + MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED = 0xC0510001, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED = 0xC05C0000, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE = 0xC05CFF00, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE = 0xC05CFF01, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED = 0xC05CFF02, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED = 0xC05CFF03, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED = 0xC05CFF04, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED = 0xC05CFF05, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED = 0xC05CFF06, + MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT = 0xC05CFF07, + MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE = 0xC05CFF08, + MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH = 0xC05CFF09, + MD_NTSTATUS_WIN_STATUS_VHD_SHARED = 0xC05CFF0A, + MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR = 0xC05CFF0B, + MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND = 0xC05CFF0C, + MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP = 0xC05D0000, + MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT = 0xC05D0001, + MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED = 0xC05D0002, + MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID = 0xC0E70001, + MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID = 0xC0E70003, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID = 0xC0E70004, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID = 0xC0E70006, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID = 0xC0E70007, + MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID = 0xC0E70009, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID = 0xC0E7000A, + MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES = 0xC0E7000B, + MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR = 0xC0E7000C, + MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID = 0xC0E7000D, + MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID = 0xC0E7000E, + MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID = 0xC0E7000F, + MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID = 0xC0E70010, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID = 0xC0E70011, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID = 0xC0E70012, + MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE = 0xC0E70013, + MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED = 0xC0E70014, + MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION = 0xC0E70015, + MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA = 0xC0E70016, + MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL = 0xC0E70017, + MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY = 0xC0E70018, + MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY = 0xC0E70019, + MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY = 0xC0E7001A, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY = 0xC0E7001B, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT = 0xC0E7001C, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA = 0xC0E7001D, + MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE = 0xC0E7001E, + MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID = 0xC0E7001F, + MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY = 0xC0E70020, + MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND = 0xC0E80000, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED = 0xC0E90001, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION = 0xC0E90002, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY = 0xC0E90003, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED = 0xC0E90004, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES = 0xC0E90005, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED = 0xC0E90006, + MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND = 0xC0EA0001, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND = 0xC0EA0002, + MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING = 0xC0EA0003, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE = 0xC0EA0004, + MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID = 0xC0EA0005, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED = 0xC0EA0006, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE = 0xC0EA0007, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED = 0xC0EA0008, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE = 0xC0EA0009, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH = 0xC0EA000A, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED = 0xC0EB0001, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID = 0xC0EB0002, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED = 0xC0EB0003, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED = 0xC0EB0004, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND = 0xC0EB0005, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE = 0xC0EB0006, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED = 0xC0EB0007, + MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED = 0xC0EC0000, + MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED = 0xC0EC0001, + MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION = 0xC0EC0002, + MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION = 0xC0EC0003, + MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE = 0xC0EC0004, + MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR = 0xC0EC0005, + MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH = 0xC0EC0006, + MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER = 0xC0EC0007, +} MDNTStatusCodeWin; + +// These constants are defined in the MSDN documentation of +// the EXCEPTION_RECORD structure. +typedef enum { + MD_ACCESS_VIOLATION_WIN_READ = 0, + MD_ACCESS_VIOLATION_WIN_WRITE = 1, + MD_ACCESS_VIOLATION_WIN_EXEC = 8 +} MDAccessViolationTypeWin; + +// These constants are defined in the MSDN documentation of +// the EXCEPTION_RECORD structure. +typedef enum { + MD_IN_PAGE_ERROR_WIN_READ = 0, + MD_IN_PAGE_ERROR_WIN_WRITE = 1, + MD_IN_PAGE_ERROR_WIN_EXEC = 8 +} MDInPageErrorTypeWin; + +/* For (MDException).exception_information[0], when (MDException).exception_code + * is MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN. This describes the underlying + * reason for the crash. These values come from winnt.h. + * + * The content of this enum was created from winnt.h in the 10 SDK + * (version 10.0.19041.0) with + * + * egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h + * | tr -d '\r' + * | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' + * | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_FAST_FAIL_WIN_\2 = \1,@' */ +typedef enum { + MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION = 0, + MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE = 1, + MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE = 2, + MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY = 3, + MD_FAST_FAIL_WIN_INCORRECT_STACK = 4, + MD_FAST_FAIL_WIN_INVALID_ARG = 5, + MD_FAST_FAIL_WIN_GS_COOKIE_INIT = 6, + MD_FAST_FAIL_WIN_FATAL_APP_EXIT = 7, + MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE = 8, + MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS = 9, + MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE = 10, + MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE = 11, + MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH = 12, + MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT = 13, + MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT = 14, + MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER = 18, + MD_FAST_FAIL_WIN_MRDATA_MODIFIED = 19, + MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE = 20, + MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN = 21, + MD_FAST_FAIL_WIN_CRYPTO_LIBRARY = 22, + MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT = 23, + MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE = 24, + MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE = 25, + MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL = 26, + MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED = 27, + MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS = 28, + MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE = 29, + MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD = 30, + MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED = 31, + MD_FAST_FAIL_WIN_APCS_DISABLED = 32, + MD_FAST_FAIL_WIN_INVALID_IDLE_STATE = 33, + MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE = 34, + MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION = 35, + MD_FAST_FAIL_WIN_INVALID_LOCK_STATE = 36, + MD_FAST_FAIL_WIN_GUARD_JUMPTABLE = 37, + MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET = 38, + MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT = 39, + MD_FAST_FAIL_WIN_INVALID_THREAD = 40, + MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER = 41, + MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION = 42, + MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED = 43, + MD_FAST_FAIL_WIN_GUARD_SS_FAILURE = 44, + MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE = 45, + MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE = 46, + MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK = 47, + MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED = 48, + MD_FAST_FAIL_WIN_INVALID_IAT = 49, + MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION = 50, + MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION = 51, + MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED = 52, + MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE = 53, + MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON = 54, + MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED = 55, + MD_FAST_FAIL_WIN_UNEXPECTED_CALL = 56, + MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS = 57, + MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR = 58, + MD_FAST_FAIL_WIN_FLAGS_CORRUPTION = 59, + MD_FAST_FAIL_WIN_VEH_CORRUPTION = 60, + MD_FAST_FAIL_WIN_ETW_CORRUPTION = 61, + MD_FAST_FAIL_WIN_RIO_ABORT = 62, + MD_FAST_FAIL_WIN_INVALID_PFN = 63, +} MDFastFailWin; + +/* For various (MDException).exception_information entries. This describes the +* underlying reason for the crash. These values come from winerror.h. + * + * The content of this enum was created from winnt.h in the 10 SDK + * (version 10.0.19041.0) with + * + * egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h + * | tr -d '\r' + * | sed -r 's@#define ERROR_([A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' + * | sort -n + * | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_ERROR_WIN_\2 = \1,@' */ +typedef enum { + MD_ERROR_WIN_SUCCESS = 0, + MD_ERROR_WIN_INVALID_FUNCTION = 1, + MD_ERROR_WIN_FILE_NOT_FOUND = 2, + MD_ERROR_WIN_PATH_NOT_FOUND = 3, + MD_ERROR_WIN_TOO_MANY_OPEN_FILES = 4, + MD_ERROR_WIN_ACCESS_DENIED = 5, + MD_ERROR_WIN_INVALID_HANDLE = 6, + MD_ERROR_WIN_ARENA_TRASHED = 7, + MD_ERROR_WIN_NOT_ENOUGH_MEMORY = 8, + MD_ERROR_WIN_INVALID_BLOCK = 9, + MD_ERROR_WIN_BAD_ENVIRONMENT = 10, + MD_ERROR_WIN_BAD_FORMAT = 11, + MD_ERROR_WIN_INVALID_ACCESS = 12, + MD_ERROR_WIN_INVALID_DATA = 13, + MD_ERROR_WIN_OUTOFMEMORY = 14, + MD_ERROR_WIN_INVALID_DRIVE = 15, + MD_ERROR_WIN_CURRENT_DIRECTORY = 16, + MD_ERROR_WIN_NOT_SAME_DEVICE = 17, + MD_ERROR_WIN_NO_MORE_FILES = 18, + MD_ERROR_WIN_WRITE_PROTECT = 19, + MD_ERROR_WIN_BAD_UNIT = 20, + MD_ERROR_WIN_NOT_READY = 21, + MD_ERROR_WIN_BAD_COMMAND = 22, + MD_ERROR_WIN_CRC = 23, + MD_ERROR_WIN_BAD_LENGTH = 24, + MD_ERROR_WIN_SEEK = 25, + MD_ERROR_WIN_NOT_DOS_DISK = 26, + MD_ERROR_WIN_SECTOR_NOT_FOUND = 27, + MD_ERROR_WIN_OUT_OF_PAPER = 28, + MD_ERROR_WIN_WRITE_FAULT = 29, + MD_ERROR_WIN_READ_FAULT = 30, + MD_ERROR_WIN_GEN_FAILURE = 31, + MD_ERROR_WIN_SHARING_VIOLATION = 32, + MD_ERROR_WIN_LOCK_VIOLATION = 33, + MD_ERROR_WIN_WRONG_DISK = 34, + MD_ERROR_WIN_SHARING_BUFFER_EXCEEDED = 36, + MD_ERROR_WIN_HANDLE_EOF = 38, + MD_ERROR_WIN_HANDLE_DISK_FULL = 39, + MD_ERROR_WIN_NOT_SUPPORTED = 50, + MD_ERROR_WIN_REM_NOT_LIST = 51, + MD_ERROR_WIN_DUP_NAME = 52, + MD_ERROR_WIN_BAD_NETPATH = 53, + MD_ERROR_WIN_NETWORK_BUSY = 54, + MD_ERROR_WIN_DEV_NOT_EXIST = 55, + MD_ERROR_WIN_TOO_MANY_CMDS = 56, + MD_ERROR_WIN_ADAP_HDW_ERR = 57, + MD_ERROR_WIN_BAD_NET_RESP = 58, + MD_ERROR_WIN_UNEXP_NET_ERR = 59, + MD_ERROR_WIN_BAD_REM_ADAP = 60, + MD_ERROR_WIN_PRINTQ_FULL = 61, + MD_ERROR_WIN_NO_SPOOL_SPACE = 62, + MD_ERROR_WIN_PRINT_CANCELLED = 63, + MD_ERROR_WIN_NETNAME_DELETED = 64, + MD_ERROR_WIN_NETWORK_ACCESS_DENIED = 65, + MD_ERROR_WIN_BAD_DEV_TYPE = 66, + MD_ERROR_WIN_BAD_NET_NAME = 67, + MD_ERROR_WIN_TOO_MANY_NAMES = 68, + MD_ERROR_WIN_TOO_MANY_SESS = 69, + MD_ERROR_WIN_SHARING_PAUSED = 70, + MD_ERROR_WIN_REQ_NOT_ACCEP = 71, + MD_ERROR_WIN_REDIR_PAUSED = 72, + MD_ERROR_WIN_FILE_EXISTS = 80, + MD_ERROR_WIN_CANNOT_MAKE = 82, + MD_ERROR_WIN_FAIL_I24 = 83, + MD_ERROR_WIN_OUT_OF_STRUCTURES = 84, + MD_ERROR_WIN_ALREADY_ASSIGNED = 85, + MD_ERROR_WIN_INVALID_PASSWORD = 86, + MD_ERROR_WIN_INVALID_PARAMETER = 87, + MD_ERROR_WIN_NET_WRITE_FAULT = 88, + MD_ERROR_WIN_NO_PROC_SLOTS = 89, + MD_ERROR_WIN_TOO_MANY_SEMAPHORES = 100, + MD_ERROR_WIN_EXCL_SEM_ALREADY_OWNED = 101, + MD_ERROR_WIN_SEM_IS_SET = 102, + MD_ERROR_WIN_TOO_MANY_SEM_REQUESTS = 103, + MD_ERROR_WIN_INVALID_AT_INTERRUPT_TIME = 104, + MD_ERROR_WIN_SEM_OWNER_DIED = 105, + MD_ERROR_WIN_SEM_USER_LIMIT = 106, + MD_ERROR_WIN_DISK_CHANGE = 107, + MD_ERROR_WIN_DRIVE_LOCKED = 108, + MD_ERROR_WIN_BROKEN_PIPE = 109, + MD_ERROR_WIN_OPEN_FAILED = 110, + MD_ERROR_WIN_BUFFER_OVERFLOW = 111, + MD_ERROR_WIN_DISK_FULL = 112, + MD_ERROR_WIN_NO_MORE_SEARCH_HANDLES = 113, + MD_ERROR_WIN_INVALID_TARGET_HANDLE = 114, + MD_ERROR_WIN_INVALID_CATEGORY = 117, + MD_ERROR_WIN_INVALID_VERIFY_SWITCH = 118, + MD_ERROR_WIN_BAD_DRIVER_LEVEL = 119, + MD_ERROR_WIN_CALL_NOT_IMPLEMENTED = 120, + MD_ERROR_WIN_SEM_TIMEOUT = 121, + MD_ERROR_WIN_INSUFFICIENT_BUFFER = 122, + MD_ERROR_WIN_INVALID_NAME = 123, + MD_ERROR_WIN_INVALID_LEVEL = 124, + MD_ERROR_WIN_NO_VOLUME_LABEL = 125, + MD_ERROR_WIN_MOD_NOT_FOUND = 126, + MD_ERROR_WIN_PROC_NOT_FOUND = 127, + MD_ERROR_WIN_WAIT_NO_CHILDREN = 128, + MD_ERROR_WIN_CHILD_NOT_COMPLETE = 129, + MD_ERROR_WIN_DIRECT_ACCESS_HANDLE = 130, + MD_ERROR_WIN_NEGATIVE_SEEK = 131, + MD_ERROR_WIN_SEEK_ON_DEVICE = 132, + MD_ERROR_WIN_IS_JOIN_TARGET = 133, + MD_ERROR_WIN_IS_JOINED = 134, + MD_ERROR_WIN_IS_SUBSTED = 135, + MD_ERROR_WIN_NOT_JOINED = 136, + MD_ERROR_WIN_NOT_SUBSTED = 137, + MD_ERROR_WIN_JOIN_TO_JOIN = 138, + MD_ERROR_WIN_SUBST_TO_SUBST = 139, + MD_ERROR_WIN_JOIN_TO_SUBST = 140, + MD_ERROR_WIN_SUBST_TO_JOIN = 141, + MD_ERROR_WIN_BUSY_DRIVE = 142, + MD_ERROR_WIN_SAME_DRIVE = 143, + MD_ERROR_WIN_DIR_NOT_ROOT = 144, + MD_ERROR_WIN_DIR_NOT_EMPTY = 145, + MD_ERROR_WIN_IS_SUBST_PATH = 146, + MD_ERROR_WIN_IS_JOIN_PATH = 147, + MD_ERROR_WIN_PATH_BUSY = 148, + MD_ERROR_WIN_IS_SUBST_TARGET = 149, + MD_ERROR_WIN_SYSTEM_TRACE = 150, + MD_ERROR_WIN_INVALID_EVENT_COUNT = 151, + MD_ERROR_WIN_TOO_MANY_MUXWAITERS = 152, + MD_ERROR_WIN_INVALID_LIST_FORMAT = 153, + MD_ERROR_WIN_LABEL_TOO_LONG = 154, + MD_ERROR_WIN_TOO_MANY_TCBS = 155, + MD_ERROR_WIN_SIGNAL_REFUSED = 156, + MD_ERROR_WIN_DISCARDED = 157, + MD_ERROR_WIN_NOT_LOCKED = 158, + MD_ERROR_WIN_BAD_THREADID_ADDR = 159, + MD_ERROR_WIN_BAD_ARGUMENTS = 160, + MD_ERROR_WIN_BAD_PATHNAME = 161, + MD_ERROR_WIN_SIGNAL_PENDING = 162, + MD_ERROR_WIN_MAX_THRDS_REACHED = 164, + MD_ERROR_WIN_LOCK_FAILED = 167, + MD_ERROR_WIN_BUSY = 170, + MD_ERROR_WIN_DEVICE_SUPPORT_IN_PROGRESS = 171, + MD_ERROR_WIN_CANCEL_VIOLATION = 173, + MD_ERROR_WIN_ATOMIC_LOCKS_NOT_SUPPORTED = 174, + MD_ERROR_WIN_INVALID_SEGMENT_NUMBER = 180, + MD_ERROR_WIN_INVALID_ORDINAL = 182, + MD_ERROR_WIN_ALREADY_EXISTS = 183, + MD_ERROR_WIN_INVALID_FLAG_NUMBER = 186, + MD_ERROR_WIN_SEM_NOT_FOUND = 187, + MD_ERROR_WIN_INVALID_STARTING_CODESEG = 188, + MD_ERROR_WIN_INVALID_STACKSEG = 189, + MD_ERROR_WIN_INVALID_MODULETYPE = 190, + MD_ERROR_WIN_INVALID_EXE_SIGNATURE = 191, + MD_ERROR_WIN_EXE_MARKED_INVALID = 192, + MD_ERROR_WIN_BAD_EXE_FORMAT = 193, + MD_ERROR_WIN_INVALID_MINALLOCSIZE = 195, + MD_ERROR_WIN_DYNLINK_FROM_INVALID_RING = 196, + MD_ERROR_WIN_IOPL_NOT_ENABLED = 197, + MD_ERROR_WIN_INVALID_SEGDPL = 198, + MD_ERROR_WIN_RING2SEG_MUST_BE_MOVABLE = 200, + MD_ERROR_WIN_RELOC_CHAIN_XEEDS_SEGLIM = 201, + MD_ERROR_WIN_INFLOOP_IN_RELOC_CHAIN = 202, + MD_ERROR_WIN_ENVVAR_NOT_FOUND = 203, + MD_ERROR_WIN_NO_SIGNAL_SENT = 205, + MD_ERROR_WIN_FILENAME_EXCED_RANGE = 206, + MD_ERROR_WIN_RING2_STACK_IN_USE = 207, + MD_ERROR_WIN_META_EXPANSION_TOO_LONG = 208, + MD_ERROR_WIN_INVALID_SIGNAL_NUMBER = 209, + MD_ERROR_WIN_THREAD_1_INACTIVE = 210, + MD_ERROR_WIN_LOCKED = 212, + MD_ERROR_WIN_TOO_MANY_MODULES = 214, + MD_ERROR_WIN_NESTING_NOT_ALLOWED = 215, + MD_ERROR_WIN_EXE_MACHINE_TYPE_MISMATCH = 216, + MD_ERROR_WIN_EXE_CANNOT_MODIFY_SIGNED_BINARY = 217, + MD_ERROR_WIN_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 218, + MD_ERROR_WIN_FILE_CHECKED_OUT = 220, + MD_ERROR_WIN_CHECKOUT_REQUIRED = 221, + MD_ERROR_WIN_BAD_FILE_TYPE = 222, + MD_ERROR_WIN_FILE_TOO_LARGE = 223, + MD_ERROR_WIN_FORMS_AUTH_REQUIRED = 224, + MD_ERROR_WIN_VIRUS_INFECTED = 225, + MD_ERROR_WIN_VIRUS_DELETED = 226, + MD_ERROR_WIN_PIPE_LOCAL = 229, + MD_ERROR_WIN_BAD_PIPE = 230, + MD_ERROR_WIN_PIPE_BUSY = 231, + MD_ERROR_WIN_NO_DATA = 232, + MD_ERROR_WIN_PIPE_NOT_CONNECTED = 233, + MD_ERROR_WIN_MORE_DATA = 234, + MD_ERROR_WIN_NO_WORK_DONE = 235, + MD_ERROR_WIN_VC_DISCONNECTED = 240, + MD_ERROR_WIN_INVALID_EA_NAME = 254, + MD_ERROR_WIN_EA_LIST_INCONSISTENT = 255, + MD_ERROR_WIN_NO_MORE_ITEMS = 259, + MD_ERROR_WIN_CANNOT_COPY = 266, + MD_ERROR_WIN_DIRECTORY = 267, + MD_ERROR_WIN_EAS_DIDNT_FIT = 275, + MD_ERROR_WIN_EA_FILE_CORRUPT = 276, + MD_ERROR_WIN_EA_TABLE_FULL = 277, + MD_ERROR_WIN_INVALID_EA_HANDLE = 278, + MD_ERROR_WIN_EAS_NOT_SUPPORTED = 282, + MD_ERROR_WIN_NOT_OWNER = 288, + MD_ERROR_WIN_TOO_MANY_POSTS = 298, + MD_ERROR_WIN_PARTIAL_COPY = 299, + MD_ERROR_WIN_OPLOCK_NOT_GRANTED = 300, + MD_ERROR_WIN_INVALID_OPLOCK_PROTOCOL = 301, + MD_ERROR_WIN_DISK_TOO_FRAGMENTED = 302, + MD_ERROR_WIN_DELETE_PENDING = 303, + MD_ERROR_WIN_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 304, + MD_ERROR_WIN_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 305, + MD_ERROR_WIN_SECURITY_STREAM_IS_INCONSISTENT = 306, + MD_ERROR_WIN_INVALID_LOCK_RANGE = 307, + MD_ERROR_WIN_IMAGE_SUBSYSTEM_NOT_PRESENT = 308, + MD_ERROR_WIN_NOTIFICATION_GUID_ALREADY_DEFINED = 309, + MD_ERROR_WIN_INVALID_EXCEPTION_HANDLER = 310, + MD_ERROR_WIN_DUPLICATE_PRIVILEGES = 311, + MD_ERROR_WIN_NO_RANGES_PROCESSED = 312, + MD_ERROR_WIN_NOT_ALLOWED_ON_SYSTEM_FILE = 313, + MD_ERROR_WIN_DISK_RESOURCES_EXHAUSTED = 314, + MD_ERROR_WIN_INVALID_TOKEN = 315, + MD_ERROR_WIN_DEVICE_FEATURE_NOT_SUPPORTED = 316, + MD_ERROR_WIN_MR_MID_NOT_FOUND = 317, + MD_ERROR_WIN_SCOPE_NOT_FOUND = 318, + MD_ERROR_WIN_UNDEFINED_SCOPE = 319, + MD_ERROR_WIN_INVALID_CAP = 320, + MD_ERROR_WIN_DEVICE_UNREACHABLE = 321, + MD_ERROR_WIN_DEVICE_NO_RESOURCES = 322, + MD_ERROR_WIN_DATA_CHECKSUM_ERROR = 323, + MD_ERROR_WIN_INTERMIXED_KERNEL_EA_OPERATION = 324, + MD_ERROR_WIN_FILE_LEVEL_TRIM_NOT_SUPPORTED = 326, + MD_ERROR_WIN_OFFSET_ALIGNMENT_VIOLATION = 327, + MD_ERROR_WIN_INVALID_FIELD_IN_PARAMETER_LIST = 328, + MD_ERROR_WIN_OPERATION_IN_PROGRESS = 329, + MD_ERROR_WIN_BAD_DEVICE_PATH = 330, + MD_ERROR_WIN_TOO_MANY_DESCRIPTORS = 331, + MD_ERROR_WIN_SCRUB_DATA_DISABLED = 332, + MD_ERROR_WIN_NOT_REDUNDANT_STORAGE = 333, + MD_ERROR_WIN_RESIDENT_FILE_NOT_SUPPORTED = 334, + MD_ERROR_WIN_COMPRESSED_FILE_NOT_SUPPORTED = 335, + MD_ERROR_WIN_DIRECTORY_NOT_SUPPORTED = 336, + MD_ERROR_WIN_NOT_READ_FROM_COPY = 337, + MD_ERROR_WIN_FT_WRITE_FAILURE = 338, + MD_ERROR_WIN_FT_DI_SCAN_REQUIRED = 339, + MD_ERROR_WIN_INVALID_KERNEL_INFO_VERSION = 340, + MD_ERROR_WIN_INVALID_PEP_INFO_VERSION = 341, + MD_ERROR_WIN_OBJECT_NOT_EXTERNALLY_BACKED = 342, + MD_ERROR_WIN_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 343, + MD_ERROR_WIN_COMPRESSION_NOT_BENEFICIAL = 344, + MD_ERROR_WIN_STORAGE_TOPOLOGY_ID_MISMATCH = 345, + MD_ERROR_WIN_BLOCKED_BY_PARENTAL_CONTROLS = 346, + MD_ERROR_WIN_BLOCK_TOO_MANY_REFERENCES = 347, + MD_ERROR_WIN_MARKED_TO_DISALLOW_WRITES = 348, + MD_ERROR_WIN_ENCLAVE_FAILURE = 349, + MD_ERROR_WIN_FAIL_NOACTION_REBOOT = 350, + MD_ERROR_WIN_FAIL_SHUTDOWN = 351, + MD_ERROR_WIN_FAIL_RESTART = 352, + MD_ERROR_WIN_MAX_SESSIONS_REACHED = 353, + MD_ERROR_WIN_NETWORK_ACCESS_DENIED_EDP = 354, + MD_ERROR_WIN_DEVICE_HINT_NAME_BUFFER_TOO_SMALL = 355, + MD_ERROR_WIN_EDP_POLICY_DENIES_OPERATION = 356, + MD_ERROR_WIN_EDP_DPL_POLICY_CANT_BE_SATISFIED = 357, + MD_ERROR_WIN_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT = 358, + MD_ERROR_WIN_DEVICE_IN_MAINTENANCE = 359, + MD_ERROR_WIN_NOT_SUPPORTED_ON_DAX = 360, + MD_ERROR_WIN_DAX_MAPPING_EXISTS = 361, + MD_ERROR_WIN_CLOUD_FILE_PROVIDER_NOT_RUNNING = 362, + MD_ERROR_WIN_CLOUD_FILE_METADATA_CORRUPT = 363, + MD_ERROR_WIN_CLOUD_FILE_METADATA_TOO_LARGE = 364, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE = 365, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH = 366, + MD_ERROR_WIN_CHILD_PROCESS_BLOCKED = 367, + MD_ERROR_WIN_STORAGE_LOST_DATA_PERSISTENCE = 368, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE = 369, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT = 370, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_BUSY = 371, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN = 372, + MD_ERROR_WIN_GDI_HANDLE_LEAK = 373, + MD_ERROR_WIN_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS = 374, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED = 375, + MD_ERROR_WIN_NOT_A_CLOUD_FILE = 376, + MD_ERROR_WIN_CLOUD_FILE_NOT_IN_SYNC = 377, + MD_ERROR_WIN_CLOUD_FILE_ALREADY_CONNECTED = 378, + MD_ERROR_WIN_CLOUD_FILE_NOT_SUPPORTED = 379, + MD_ERROR_WIN_CLOUD_FILE_INVALID_REQUEST = 380, + MD_ERROR_WIN_CLOUD_FILE_READ_ONLY_VOLUME = 381, + MD_ERROR_WIN_CLOUD_FILE_CONNECTED_PROVIDER_ONLY = 382, + MD_ERROR_WIN_CLOUD_FILE_VALIDATION_FAILED = 383, + MD_ERROR_WIN_SMB1_NOT_AVAILABLE = 384, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION = 385, + MD_ERROR_WIN_CLOUD_FILE_AUTHENTICATION_FAILED = 386, + MD_ERROR_WIN_CLOUD_FILE_INSUFFICIENT_RESOURCES = 387, + MD_ERROR_WIN_CLOUD_FILE_NETWORK_UNAVAILABLE = 388, + MD_ERROR_WIN_CLOUD_FILE_UNSUCCESSFUL = 389, + MD_ERROR_WIN_CLOUD_FILE_NOT_UNDER_SYNC_ROOT = 390, + MD_ERROR_WIN_CLOUD_FILE_IN_USE = 391, + MD_ERROR_WIN_CLOUD_FILE_PINNED = 392, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_ABORTED = 393, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_CORRUPT = 394, + MD_ERROR_WIN_CLOUD_FILE_ACCESS_DENIED = 395, + MD_ERROR_WIN_CLOUD_FILE_INCOMPATIBLE_HARDLINKS = 396, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_LOCK_CONFLICT = 397, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_CANCELED = 398, + MD_ERROR_WIN_EXTERNAL_SYSKEY_NOT_SUPPORTED = 399, + MD_ERROR_WIN_THREAD_MODE_ALREADY_BACKGROUND = 400, + MD_ERROR_WIN_THREAD_MODE_NOT_BACKGROUND = 401, + MD_ERROR_WIN_PROCESS_MODE_ALREADY_BACKGROUND = 402, + MD_ERROR_WIN_PROCESS_MODE_NOT_BACKGROUND = 403, + MD_ERROR_WIN_CLOUD_FILE_PROVIDER_TERMINATED = 404, + MD_ERROR_WIN_NOT_A_CLOUD_SYNC_ROOT = 405, + MD_ERROR_WIN_FILE_PROTECTED_UNDER_DPL = 406, + MD_ERROR_WIN_VOLUME_NOT_CLUSTER_ALIGNED = 407, + MD_ERROR_WIN_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND = 408, + MD_ERROR_WIN_APPX_FILE_NOT_ENCRYPTED = 409, + MD_ERROR_WIN_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED = 410, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET = 411, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE = 412, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER = 413, + MD_ERROR_WIN_LINUX_SUBSYSTEM_NOT_PRESENT = 414, + MD_ERROR_WIN_FT_READ_FAILURE = 415, + MD_ERROR_WIN_STORAGE_RESERVE_ID_INVALID = 416, + MD_ERROR_WIN_STORAGE_RESERVE_DOES_NOT_EXIST = 417, + MD_ERROR_WIN_STORAGE_RESERVE_ALREADY_EXISTS = 418, + MD_ERROR_WIN_STORAGE_RESERVE_NOT_EMPTY = 419, + MD_ERROR_WIN_NOT_A_DAX_VOLUME = 420, + MD_ERROR_WIN_NOT_DAX_MAPPABLE = 421, + MD_ERROR_WIN_TIME_SENSITIVE_THREAD = 422, + MD_ERROR_WIN_DPL_NOT_SUPPORTED_FOR_USER = 423, + MD_ERROR_WIN_CASE_DIFFERING_NAMES_IN_DIR = 424, + MD_ERROR_WIN_FILE_NOT_SUPPORTED = 425, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_TIMEOUT = 426, + MD_ERROR_WIN_NO_TASK_QUEUE = 427, + MD_ERROR_WIN_SRC_SRV_DLL_LOAD_FAILED = 428, + MD_ERROR_WIN_NOT_SUPPORTED_WITH_BTT = 429, + MD_ERROR_WIN_ENCRYPTION_DISABLED = 430, + MD_ERROR_WIN_ENCRYPTING_METADATA_DISALLOWED = 431, + MD_ERROR_WIN_CANT_CLEAR_ENCRYPTION_FLAG = 432, + MD_ERROR_WIN_NO_SUCH_DEVICE = 433, + MD_ERROR_WIN_CLOUD_FILE_DEHYDRATION_DISALLOWED = 434, + MD_ERROR_WIN_FILE_SNAP_IN_PROGRESS = 435, + MD_ERROR_WIN_FILE_SNAP_USER_SECTION_NOT_SUPPORTED = 436, + MD_ERROR_WIN_FILE_SNAP_MODIFY_NOT_SUPPORTED = 437, + MD_ERROR_WIN_FILE_SNAP_IO_NOT_COORDINATED = 438, + MD_ERROR_WIN_FILE_SNAP_UNEXPECTED_ERROR = 439, + MD_ERROR_WIN_FILE_SNAP_INVALID_PARAMETER = 440, + MD_ERROR_WIN_UNSATISFIED_DEPENDENCIES = 441, + MD_ERROR_WIN_CASE_SENSITIVE_PATH = 442, + MD_ERROR_WIN_UNEXPECTED_NTCACHEMANAGER_ERROR = 443, + MD_ERROR_WIN_LINUX_SUBSYSTEM_UPDATE_REQUIRED = 444, + MD_ERROR_WIN_DLP_POLICY_WARNS_AGAINST_OPERATION = 445, + MD_ERROR_WIN_DLP_POLICY_DENIES_OPERATION = 446, + MD_ERROR_WIN_DLP_POLICY_SILENTLY_FAIL = 449, + MD_ERROR_WIN_CAPAUTHZ_NOT_DEVUNLOCKED = 450, + MD_ERROR_WIN_CAPAUTHZ_CHANGE_TYPE = 451, + MD_ERROR_WIN_CAPAUTHZ_NOT_PROVISIONED = 452, + MD_ERROR_WIN_CAPAUTHZ_NOT_AUTHORIZED = 453, + MD_ERROR_WIN_CAPAUTHZ_NO_POLICY = 454, + MD_ERROR_WIN_CAPAUTHZ_DB_CORRUPTED = 455, + MD_ERROR_WIN_CAPAUTHZ_SCCD_INVALID_CATALOG = 456, + MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_AUTH_ENTITY = 457, + MD_ERROR_WIN_CAPAUTHZ_SCCD_PARSE_ERROR = 458, + MD_ERROR_WIN_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED = 459, + MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH = 460, + MD_ERROR_WIN_CIMFS_IMAGE_CORRUPT = 470, + MD_ERROR_WIN_PNP_QUERY_REMOVE_DEVICE_TIMEOUT = 480, + MD_ERROR_WIN_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT = 481, + MD_ERROR_WIN_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT = 482, + MD_ERROR_WIN_DEVICE_HARDWARE_ERROR = 483, + MD_ERROR_WIN_INVALID_ADDRESS = 487, + MD_ERROR_WIN_HAS_SYSTEM_CRITICAL_FILES = 488, + MD_ERROR_WIN_USER_PROFILE_LOAD = 500, + MD_ERROR_WIN_ARITHMETIC_OVERFLOW = 534, + MD_ERROR_WIN_PIPE_CONNECTED = 535, + MD_ERROR_WIN_PIPE_LISTENING = 536, + MD_ERROR_WIN_VERIFIER_STOP = 537, + MD_ERROR_WIN_ABIOS_ERROR = 538, + MD_ERROR_WIN_WX86_WARNING = 539, + MD_ERROR_WIN_WX86_ERROR = 540, + MD_ERROR_WIN_TIMER_NOT_CANCELED = 541, + MD_ERROR_WIN_UNWIND = 542, + MD_ERROR_WIN_BAD_STACK = 543, + MD_ERROR_WIN_INVALID_UNWIND_TARGET = 544, + MD_ERROR_WIN_INVALID_PORT_ATTRIBUTES = 545, + MD_ERROR_WIN_PORT_MESSAGE_TOO_LONG = 546, + MD_ERROR_WIN_INVALID_QUOTA_LOWER = 547, + MD_ERROR_WIN_DEVICE_ALREADY_ATTACHED = 548, + MD_ERROR_WIN_INSTRUCTION_MISALIGNMENT = 549, + MD_ERROR_WIN_PROFILING_NOT_STARTED = 550, + MD_ERROR_WIN_PROFILING_NOT_STOPPED = 551, + MD_ERROR_WIN_COULD_NOT_INTERPRET = 552, + MD_ERROR_WIN_PROFILING_AT_LIMIT = 553, + MD_ERROR_WIN_CANT_WAIT = 554, + MD_ERROR_WIN_CANT_TERMINATE_SELF = 555, + MD_ERROR_WIN_UNEXPECTED_MM_CREATE_ERR = 556, + MD_ERROR_WIN_UNEXPECTED_MM_MAP_ERROR = 557, + MD_ERROR_WIN_UNEXPECTED_MM_EXTEND_ERR = 558, + MD_ERROR_WIN_BAD_FUNCTION_TABLE = 559, + MD_ERROR_WIN_NO_GUID_TRANSLATION = 560, + MD_ERROR_WIN_INVALID_LDT_SIZE = 561, + MD_ERROR_WIN_INVALID_LDT_OFFSET = 563, + MD_ERROR_WIN_INVALID_LDT_DESCRIPTOR = 564, + MD_ERROR_WIN_TOO_MANY_THREADS = 565, + MD_ERROR_WIN_THREAD_NOT_IN_PROCESS = 566, + MD_ERROR_WIN_PAGEFILE_QUOTA_EXCEEDED = 567, + MD_ERROR_WIN_LOGON_SERVER_CONFLICT = 568, + MD_ERROR_WIN_SYNCHRONIZATION_REQUIRED = 569, + MD_ERROR_WIN_NET_OPEN_FAILED = 570, + MD_ERROR_WIN_IO_PRIVILEGE_FAILED = 571, + MD_ERROR_WIN_CONTROL_C_EXIT = 572, + MD_ERROR_WIN_MISSING_SYSTEMFILE = 573, + MD_ERROR_WIN_UNHANDLED_EXCEPTION = 574, + MD_ERROR_WIN_APP_INIT_FAILURE = 575, + MD_ERROR_WIN_PAGEFILE_CREATE_FAILED = 576, + MD_ERROR_WIN_INVALID_IMAGE_HASH = 577, + MD_ERROR_WIN_NO_PAGEFILE = 578, + MD_ERROR_WIN_ILLEGAL_FLOAT_CONTEXT = 579, + MD_ERROR_WIN_NO_EVENT_PAIR = 580, + MD_ERROR_WIN_DOMAIN_CTRLR_CONFIG_ERROR = 581, + MD_ERROR_WIN_ILLEGAL_CHARACTER = 582, + MD_ERROR_WIN_UNDEFINED_CHARACTER = 583, + MD_ERROR_WIN_FLOPPY_VOLUME = 584, + MD_ERROR_WIN_BIOS_FAILED_TO_CONNECT_INTERRUPT = 585, + MD_ERROR_WIN_BACKUP_CONTROLLER = 586, + MD_ERROR_WIN_MUTANT_LIMIT_EXCEEDED = 587, + MD_ERROR_WIN_FS_DRIVER_REQUIRED = 588, + MD_ERROR_WIN_CANNOT_LOAD_REGISTRY_FILE = 589, + MD_ERROR_WIN_DEBUG_ATTACH_FAILED = 590, + MD_ERROR_WIN_SYSTEM_PROCESS_TERMINATED = 591, + MD_ERROR_WIN_DATA_NOT_ACCEPTED = 592, + MD_ERROR_WIN_VDM_HARD_ERROR = 593, + MD_ERROR_WIN_DRIVER_CANCEL_TIMEOUT = 594, + MD_ERROR_WIN_REPLY_MESSAGE_MISMATCH = 595, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA = 596, + MD_ERROR_WIN_CLIENT_SERVER_PARAMETERS_INVALID = 597, + MD_ERROR_WIN_NOT_TINY_STREAM = 598, + MD_ERROR_WIN_STACK_OVERFLOW_READ = 599, + MD_ERROR_WIN_CONVERT_TO_LARGE = 600, + MD_ERROR_WIN_FOUND_OUT_OF_SCOPE = 601, + MD_ERROR_WIN_ALLOCATE_BUCKET = 602, + MD_ERROR_WIN_MARSHALL_OVERFLOW = 603, + MD_ERROR_WIN_INVALID_VARIANT = 604, + MD_ERROR_WIN_BAD_COMPRESSION_BUFFER = 605, + MD_ERROR_WIN_AUDIT_FAILED = 606, + MD_ERROR_WIN_TIMER_RESOLUTION_NOT_SET = 607, + MD_ERROR_WIN_INSUFFICIENT_LOGON_INFO = 608, + MD_ERROR_WIN_BAD_DLL_ENTRYPOINT = 609, + MD_ERROR_WIN_BAD_SERVICE_ENTRYPOINT = 610, + MD_ERROR_WIN_IP_ADDRESS_CONFLICT1 = 611, + MD_ERROR_WIN_IP_ADDRESS_CONFLICT2 = 612, + MD_ERROR_WIN_REGISTRY_QUOTA_LIMIT = 613, + MD_ERROR_WIN_NO_CALLBACK_ACTIVE = 614, + MD_ERROR_WIN_PWD_TOO_SHORT = 615, + MD_ERROR_WIN_PWD_TOO_RECENT = 616, + MD_ERROR_WIN_PWD_HISTORY_CONFLICT = 617, + MD_ERROR_WIN_UNSUPPORTED_COMPRESSION = 618, + MD_ERROR_WIN_INVALID_HW_PROFILE = 619, + MD_ERROR_WIN_INVALID_PLUGPLAY_DEVICE_PATH = 620, + MD_ERROR_WIN_QUOTA_LIST_INCONSISTENT = 621, + MD_ERROR_WIN_EVALUATION_EXPIRATION = 622, + MD_ERROR_WIN_ILLEGAL_DLL_RELOCATION = 623, + MD_ERROR_WIN_DLL_INIT_FAILED_LOGOFF = 624, + MD_ERROR_WIN_VALIDATE_CONTINUE = 625, + MD_ERROR_WIN_NO_MORE_MATCHES = 626, + MD_ERROR_WIN_RANGE_LIST_CONFLICT = 627, + MD_ERROR_WIN_SERVER_SID_MISMATCH = 628, + MD_ERROR_WIN_CANT_ENABLE_DENY_ONLY = 629, + MD_ERROR_WIN_FLOAT_MULTIPLE_FAULTS = 630, + MD_ERROR_WIN_FLOAT_MULTIPLE_TRAPS = 631, + MD_ERROR_WIN_NOINTERFACE = 632, + MD_ERROR_WIN_DRIVER_FAILED_SLEEP = 633, + MD_ERROR_WIN_CORRUPT_SYSTEM_FILE = 634, + MD_ERROR_WIN_COMMITMENT_MINIMUM = 635, + MD_ERROR_WIN_PNP_RESTART_ENUMERATION = 636, + MD_ERROR_WIN_SYSTEM_IMAGE_BAD_SIGNATURE = 637, + MD_ERROR_WIN_PNP_REBOOT_REQUIRED = 638, + MD_ERROR_WIN_INSUFFICIENT_POWER = 639, + MD_ERROR_WIN_MULTIPLE_FAULT_VIOLATION = 640, + MD_ERROR_WIN_SYSTEM_SHUTDOWN = 641, + MD_ERROR_WIN_PORT_NOT_SET = 642, + MD_ERROR_WIN_DS_VERSION_CHECK_FAILURE = 643, + MD_ERROR_WIN_RANGE_NOT_FOUND = 644, + MD_ERROR_WIN_NOT_SAFE_MODE_DRIVER = 646, + MD_ERROR_WIN_FAILED_DRIVER_ENTRY = 647, + MD_ERROR_WIN_DEVICE_ENUMERATION_ERROR = 648, + MD_ERROR_WIN_MOUNT_POINT_NOT_RESOLVED = 649, + MD_ERROR_WIN_INVALID_DEVICE_OBJECT_PARAMETER = 650, + MD_ERROR_WIN_MCA_OCCURED = 651, + MD_ERROR_WIN_DRIVER_DATABASE_ERROR = 652, + MD_ERROR_WIN_SYSTEM_HIVE_TOO_LARGE = 653, + MD_ERROR_WIN_DRIVER_FAILED_PRIOR_UNLOAD = 654, + MD_ERROR_WIN_VOLSNAP_PREPARE_HIBERNATE = 655, + MD_ERROR_WIN_HIBERNATION_FAILURE = 656, + MD_ERROR_WIN_PWD_TOO_LONG = 657, + MD_ERROR_WIN_FILE_SYSTEM_LIMITATION = 665, + MD_ERROR_WIN_ASSERTION_FAILURE = 668, + MD_ERROR_WIN_ACPI_ERROR = 669, + MD_ERROR_WIN_WOW_ASSERTION = 670, + MD_ERROR_WIN_PNP_BAD_MPS_TABLE = 671, + MD_ERROR_WIN_PNP_TRANSLATION_FAILED = 672, + MD_ERROR_WIN_PNP_IRQ_TRANSLATION_FAILED = 673, + MD_ERROR_WIN_PNP_INVALID_ID = 674, + MD_ERROR_WIN_WAKE_SYSTEM_DEBUGGER = 675, + MD_ERROR_WIN_HANDLES_CLOSED = 676, + MD_ERROR_WIN_EXTRANEOUS_INFORMATION = 677, + MD_ERROR_WIN_RXACT_COMMIT_NECESSARY = 678, + MD_ERROR_WIN_MEDIA_CHECK = 679, + MD_ERROR_WIN_GUID_SUBSTITUTION_MADE = 680, + MD_ERROR_WIN_STOPPED_ON_SYMLINK = 681, + MD_ERROR_WIN_LONGJUMP = 682, + MD_ERROR_WIN_PLUGPLAY_QUERY_VETOED = 683, + MD_ERROR_WIN_UNWIND_CONSOLIDATE = 684, + MD_ERROR_WIN_REGISTRY_HIVE_RECOVERED = 685, + MD_ERROR_WIN_DLL_MIGHT_BE_INSECURE = 686, + MD_ERROR_WIN_DLL_MIGHT_BE_INCOMPATIBLE = 687, + MD_ERROR_WIN_DBG_EXCEPTION_NOT_HANDLED = 688, + MD_ERROR_WIN_DBG_REPLY_LATER = 689, + MD_ERROR_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE = 690, + MD_ERROR_WIN_DBG_TERMINATE_THREAD = 691, + MD_ERROR_WIN_DBG_TERMINATE_PROCESS = 692, + MD_ERROR_WIN_DBG_CONTROL_C = 693, + MD_ERROR_WIN_DBG_PRINTEXCEPTION_C = 694, + MD_ERROR_WIN_DBG_RIPEXCEPTION = 695, + MD_ERROR_WIN_DBG_CONTROL_BREAK = 696, + MD_ERROR_WIN_DBG_COMMAND_EXCEPTION = 697, + MD_ERROR_WIN_OBJECT_NAME_EXISTS = 698, + MD_ERROR_WIN_THREAD_WAS_SUSPENDED = 699, + MD_ERROR_WIN_IMAGE_NOT_AT_BASE = 700, + MD_ERROR_WIN_RXACT_STATE_CREATED = 701, + MD_ERROR_WIN_SEGMENT_NOTIFICATION = 702, + MD_ERROR_WIN_BAD_CURRENT_DIRECTORY = 703, + MD_ERROR_WIN_FT_READ_RECOVERY_FROM_BACKUP = 704, + MD_ERROR_WIN_FT_WRITE_RECOVERY = 705, + MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH = 706, + MD_ERROR_WIN_RECEIVE_PARTIAL = 707, + MD_ERROR_WIN_RECEIVE_EXPEDITED = 708, + MD_ERROR_WIN_RECEIVE_PARTIAL_EXPEDITED = 709, + MD_ERROR_WIN_EVENT_DONE = 710, + MD_ERROR_WIN_EVENT_PENDING = 711, + MD_ERROR_WIN_CHECKING_FILE_SYSTEM = 712, + MD_ERROR_WIN_FATAL_APP_EXIT = 713, + MD_ERROR_WIN_PREDEFINED_HANDLE = 714, + MD_ERROR_WIN_WAS_UNLOCKED = 715, + MD_ERROR_WIN_SERVICE_NOTIFICATION = 716, + MD_ERROR_WIN_WAS_LOCKED = 717, + MD_ERROR_WIN_LOG_HARD_ERROR = 718, + MD_ERROR_WIN_ALREADY_WIN32 = 719, + MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH_EXE = 720, + MD_ERROR_WIN_NO_YIELD_PERFORMED = 721, + MD_ERROR_WIN_TIMER_RESUME_IGNORED = 722, + MD_ERROR_WIN_ARBITRATION_UNHANDLED = 723, + MD_ERROR_WIN_CARDBUS_NOT_SUPPORTED = 724, + MD_ERROR_WIN_MP_PROCESSOR_MISMATCH = 725, + MD_ERROR_WIN_HIBERNATED = 726, + MD_ERROR_WIN_RESUME_HIBERNATION = 727, + MD_ERROR_WIN_FIRMWARE_UPDATED = 728, + MD_ERROR_WIN_DRIVERS_LEAKING_LOCKED_PAGES = 729, + MD_ERROR_WIN_WAKE_SYSTEM = 730, + MD_ERROR_WIN_WAIT_1 = 731, + MD_ERROR_WIN_WAIT_2 = 732, + MD_ERROR_WIN_WAIT_3 = 733, + MD_ERROR_WIN_WAIT_63 = 734, + MD_ERROR_WIN_ABANDONED_WAIT_0 = 735, + MD_ERROR_WIN_ABANDONED_WAIT_63 = 736, + MD_ERROR_WIN_USER_APC = 737, + MD_ERROR_WIN_KERNEL_APC = 738, + MD_ERROR_WIN_ALERTED = 739, + MD_ERROR_WIN_ELEVATION_REQUIRED = 740, + MD_ERROR_WIN_REPARSE = 741, + MD_ERROR_WIN_OPLOCK_BREAK_IN_PROGRESS = 742, + MD_ERROR_WIN_VOLUME_MOUNTED = 743, + MD_ERROR_WIN_RXACT_COMMITTED = 744, + MD_ERROR_WIN_NOTIFY_CLEANUP = 745, + MD_ERROR_WIN_PRIMARY_TRANSPORT_CONNECT_FAILED = 746, + MD_ERROR_WIN_PAGE_FAULT_TRANSITION = 747, + MD_ERROR_WIN_PAGE_FAULT_DEMAND_ZERO = 748, + MD_ERROR_WIN_PAGE_FAULT_COPY_ON_WRITE = 749, + MD_ERROR_WIN_PAGE_FAULT_GUARD_PAGE = 750, + MD_ERROR_WIN_PAGE_FAULT_PAGING_FILE = 751, + MD_ERROR_WIN_CACHE_PAGE_LOCKED = 752, + MD_ERROR_WIN_CRASH_DUMP = 753, + MD_ERROR_WIN_BUFFER_ALL_ZEROS = 754, + MD_ERROR_WIN_REPARSE_OBJECT = 755, + MD_ERROR_WIN_RESOURCE_REQUIREMENTS_CHANGED = 756, + MD_ERROR_WIN_TRANSLATION_COMPLETE = 757, + MD_ERROR_WIN_NOTHING_TO_TERMINATE = 758, + MD_ERROR_WIN_PROCESS_NOT_IN_JOB = 759, + MD_ERROR_WIN_PROCESS_IN_JOB = 760, + MD_ERROR_WIN_VOLSNAP_HIBERNATE_READY = 761, + MD_ERROR_WIN_FSFILTER_OP_COMPLETED_SUCCESSFULLY = 762, + MD_ERROR_WIN_INTERRUPT_VECTOR_ALREADY_CONNECTED = 763, + MD_ERROR_WIN_INTERRUPT_STILL_CONNECTED = 764, + MD_ERROR_WIN_WAIT_FOR_OPLOCK = 765, + MD_ERROR_WIN_DBG_EXCEPTION_HANDLED = 766, + MD_ERROR_WIN_DBG_CONTINUE = 767, + MD_ERROR_WIN_CALLBACK_POP_STACK = 768, + MD_ERROR_WIN_COMPRESSION_DISABLED = 769, + MD_ERROR_WIN_CANTFETCHBACKWARDS = 770, + MD_ERROR_WIN_CANTSCROLLBACKWARDS = 771, + MD_ERROR_WIN_ROWSNOTRELEASED = 772, + MD_ERROR_WIN_BAD_ACCESSOR_FLAGS = 773, + MD_ERROR_WIN_ERRORS_ENCOUNTERED = 774, + MD_ERROR_WIN_NOT_CAPABLE = 775, + MD_ERROR_WIN_REQUEST_OUT_OF_SEQUENCE = 776, + MD_ERROR_WIN_VERSION_PARSE_ERROR = 777, + MD_ERROR_WIN_BADSTARTPOSITION = 778, + MD_ERROR_WIN_MEMORY_HARDWARE = 779, + MD_ERROR_WIN_DISK_REPAIR_DISABLED = 780, + MD_ERROR_WIN_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 781, + MD_ERROR_WIN_SYSTEM_POWERSTATE_TRANSITION = 782, + MD_ERROR_WIN_SYSTEM_POWERSTATE_COMPLEX_TRANSITION = 783, + MD_ERROR_WIN_MCA_EXCEPTION = 784, + MD_ERROR_WIN_ACCESS_AUDIT_BY_POLICY = 785, + MD_ERROR_WIN_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 786, + MD_ERROR_WIN_ABANDON_HIBERFILE = 787, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 788, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 789, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 790, + MD_ERROR_WIN_BAD_MCFG_TABLE = 791, + MD_ERROR_WIN_DISK_REPAIR_REDIRECTED = 792, + MD_ERROR_WIN_DISK_REPAIR_UNSUCCESSFUL = 793, + MD_ERROR_WIN_CORRUPT_LOG_OVERFULL = 794, + MD_ERROR_WIN_CORRUPT_LOG_CORRUPTED = 795, + MD_ERROR_WIN_CORRUPT_LOG_UNAVAILABLE = 796, + MD_ERROR_WIN_CORRUPT_LOG_DELETED_FULL = 797, + MD_ERROR_WIN_CORRUPT_LOG_CLEARED = 798, + MD_ERROR_WIN_ORPHAN_NAME_EXHAUSTED = 799, + MD_ERROR_WIN_OPLOCK_SWITCHED_TO_NEW_HANDLE = 800, + MD_ERROR_WIN_CANNOT_GRANT_REQUESTED_OPLOCK = 801, + MD_ERROR_WIN_CANNOT_BREAK_OPLOCK = 802, + MD_ERROR_WIN_OPLOCK_HANDLE_CLOSED = 803, + MD_ERROR_WIN_NO_ACE_CONDITION = 804, + MD_ERROR_WIN_INVALID_ACE_CONDITION = 805, + MD_ERROR_WIN_FILE_HANDLE_REVOKED = 806, + MD_ERROR_WIN_IMAGE_AT_DIFFERENT_BASE = 807, + MD_ERROR_WIN_ENCRYPTED_IO_NOT_POSSIBLE = 808, + MD_ERROR_WIN_FILE_METADATA_OPTIMIZATION_IN_PROGRESS = 809, + MD_ERROR_WIN_QUOTA_ACTIVITY = 810, + MD_ERROR_WIN_HANDLE_REVOKED = 811, + MD_ERROR_WIN_CALLBACK_INVOKE_INLINE = 812, + MD_ERROR_WIN_CPU_SET_INVALID = 813, + MD_ERROR_WIN_ENCLAVE_NOT_TERMINATED = 814, + MD_ERROR_WIN_ENCLAVE_VIOLATION = 815, + MD_ERROR_WIN_EA_ACCESS_DENIED = 994, + MD_ERROR_WIN_OPERATION_ABORTED = 995, + MD_ERROR_WIN_IO_INCOMPLETE = 996, + MD_ERROR_WIN_IO_PENDING = 997, + MD_ERROR_WIN_NOACCESS = 998, + MD_ERROR_WIN_SWAPERROR = 999, + MD_ERROR_WIN_STACK_OVERFLOW = 1001, + MD_ERROR_WIN_INVALID_MESSAGE = 1002, + MD_ERROR_WIN_CAN_NOT_COMPLETE = 1003, + MD_ERROR_WIN_INVALID_FLAGS = 1004, + MD_ERROR_WIN_UNRECOGNIZED_VOLUME = 1005, + MD_ERROR_WIN_FILE_INVALID = 1006, + MD_ERROR_WIN_FULLSCREEN_MODE = 1007, + MD_ERROR_WIN_NO_TOKEN = 1008, + MD_ERROR_WIN_BADDB = 1009, + MD_ERROR_WIN_BADKEY = 1010, + MD_ERROR_WIN_CANTOPEN = 1011, + MD_ERROR_WIN_CANTREAD = 1012, + MD_ERROR_WIN_CANTWRITE = 1013, + MD_ERROR_WIN_REGISTRY_RECOVERED = 1014, + MD_ERROR_WIN_REGISTRY_CORRUPT = 1015, + MD_ERROR_WIN_REGISTRY_IO_FAILED = 1016, + MD_ERROR_WIN_NOT_REGISTRY_FILE = 1017, + MD_ERROR_WIN_KEY_DELETED = 1018, + MD_ERROR_WIN_NO_LOG_SPACE = 1019, + MD_ERROR_WIN_KEY_HAS_CHILDREN = 1020, + MD_ERROR_WIN_CHILD_MUST_BE_VOLATILE = 1021, + MD_ERROR_WIN_NOTIFY_ENUM_DIR = 1022, + MD_ERROR_WIN_DEPENDENT_SERVICES_RUNNING = 1051, + MD_ERROR_WIN_INVALID_SERVICE_CONTROL = 1052, + MD_ERROR_WIN_SERVICE_REQUEST_TIMEOUT = 1053, + MD_ERROR_WIN_SERVICE_NO_THREAD = 1054, + MD_ERROR_WIN_SERVICE_DATABASE_LOCKED = 1055, + MD_ERROR_WIN_SERVICE_ALREADY_RUNNING = 1056, + MD_ERROR_WIN_INVALID_SERVICE_ACCOUNT = 1057, + MD_ERROR_WIN_SERVICE_DISABLED = 1058, + MD_ERROR_WIN_CIRCULAR_DEPENDENCY = 1059, + MD_ERROR_WIN_SERVICE_DOES_NOT_EXIST = 1060, + MD_ERROR_WIN_SERVICE_CANNOT_ACCEPT_CTRL = 1061, + MD_ERROR_WIN_SERVICE_NOT_ACTIVE = 1062, + MD_ERROR_WIN_FAILED_SERVICE_CONTROLLER_CONNECT = 1063, + MD_ERROR_WIN_EXCEPTION_IN_SERVICE = 1064, + MD_ERROR_WIN_DATABASE_DOES_NOT_EXIST = 1065, + MD_ERROR_WIN_SERVICE_SPECIFIC_ERROR = 1066, + MD_ERROR_WIN_PROCESS_ABORTED = 1067, + MD_ERROR_WIN_SERVICE_DEPENDENCY_FAIL = 1068, + MD_ERROR_WIN_SERVICE_LOGON_FAILED = 1069, + MD_ERROR_WIN_SERVICE_START_HANG = 1070, + MD_ERROR_WIN_INVALID_SERVICE_LOCK = 1071, + MD_ERROR_WIN_SERVICE_MARKED_FOR_DELETE = 1072, + MD_ERROR_WIN_SERVICE_EXISTS = 1073, + MD_ERROR_WIN_ALREADY_RUNNING_LKG = 1074, + MD_ERROR_WIN_SERVICE_DEPENDENCY_DELETED = 1075, + MD_ERROR_WIN_BOOT_ALREADY_ACCEPTED = 1076, + MD_ERROR_WIN_SERVICE_NEVER_STARTED = 1077, + MD_ERROR_WIN_DUPLICATE_SERVICE_NAME = 1078, + MD_ERROR_WIN_DIFFERENT_SERVICE_ACCOUNT = 1079, + MD_ERROR_WIN_CANNOT_DETECT_DRIVER_FAILURE = 1080, + MD_ERROR_WIN_CANNOT_DETECT_PROCESS_ABORT = 1081, + MD_ERROR_WIN_NO_RECOVERY_PROGRAM = 1082, + MD_ERROR_WIN_SERVICE_NOT_IN_EXE = 1083, + MD_ERROR_WIN_NOT_SAFEBOOT_SERVICE = 1084, + MD_ERROR_WIN_END_OF_MEDIA = 1100, + MD_ERROR_WIN_FILEMARK_DETECTED = 1101, + MD_ERROR_WIN_BEGINNING_OF_MEDIA = 1102, + MD_ERROR_WIN_SETMARK_DETECTED = 1103, + MD_ERROR_WIN_NO_DATA_DETECTED = 1104, + MD_ERROR_WIN_PARTITION_FAILURE = 1105, + MD_ERROR_WIN_INVALID_BLOCK_LENGTH = 1106, + MD_ERROR_WIN_DEVICE_NOT_PARTITIONED = 1107, + MD_ERROR_WIN_UNABLE_TO_LOCK_MEDIA = 1108, + MD_ERROR_WIN_UNABLE_TO_UNLOAD_MEDIA = 1109, + MD_ERROR_WIN_MEDIA_CHANGED = 1110, + MD_ERROR_WIN_BUS_RESET = 1111, + MD_ERROR_WIN_NO_MEDIA_IN_DRIVE = 1112, + MD_ERROR_WIN_NO_UNICODE_TRANSLATION = 1113, + MD_ERROR_WIN_DLL_INIT_FAILED = 1114, + MD_ERROR_WIN_SHUTDOWN_IN_PROGRESS = 1115, + MD_ERROR_WIN_NO_SHUTDOWN_IN_PROGRESS = 1116, + MD_ERROR_WIN_IO_DEVICE = 1117, + MD_ERROR_WIN_SERIAL_NO_DEVICE = 1118, + MD_ERROR_WIN_IRQ_BUSY = 1119, + MD_ERROR_WIN_MORE_WRITES = 1120, + MD_ERROR_WIN_COUNTER_TIMEOUT = 1121, + MD_ERROR_WIN_FLOPPY_ID_MARK_NOT_FOUND = 1122, + MD_ERROR_WIN_FLOPPY_WRONG_CYLINDER = 1123, + MD_ERROR_WIN_FLOPPY_UNKNOWN_ERROR = 1124, + MD_ERROR_WIN_FLOPPY_BAD_REGISTERS = 1125, + MD_ERROR_WIN_DISK_RECALIBRATE_FAILED = 1126, + MD_ERROR_WIN_DISK_OPERATION_FAILED = 1127, + MD_ERROR_WIN_DISK_RESET_FAILED = 1128, + MD_ERROR_WIN_EOM_OVERFLOW = 1129, + MD_ERROR_WIN_NOT_ENOUGH_SERVER_MEMORY = 1130, + MD_ERROR_WIN_POSSIBLE_DEADLOCK = 1131, + MD_ERROR_WIN_MAPPED_ALIGNMENT = 1132, + MD_ERROR_WIN_SET_POWER_STATE_VETOED = 1140, + MD_ERROR_WIN_SET_POWER_STATE_FAILED = 1141, + MD_ERROR_WIN_TOO_MANY_LINKS = 1142, + MD_ERROR_WIN_OLD_WIN_VERSION = 1150, + MD_ERROR_WIN_APP_WRONG_OS = 1151, + MD_ERROR_WIN_SINGLE_INSTANCE_APP = 1152, + MD_ERROR_WIN_RMODE_APP = 1153, + MD_ERROR_WIN_INVALID_DLL = 1154, + MD_ERROR_WIN_NO_ASSOCIATION = 1155, + MD_ERROR_WIN_DDE_FAIL = 1156, + MD_ERROR_WIN_DLL_NOT_FOUND = 1157, + MD_ERROR_WIN_NO_MORE_USER_HANDLES = 1158, + MD_ERROR_WIN_MESSAGE_SYNC_ONLY = 1159, + MD_ERROR_WIN_SOURCE_ELEMENT_EMPTY = 1160, + MD_ERROR_WIN_DESTINATION_ELEMENT_FULL = 1161, + MD_ERROR_WIN_ILLEGAL_ELEMENT_ADDRESS = 1162, + MD_ERROR_WIN_MAGAZINE_NOT_PRESENT = 1163, + MD_ERROR_WIN_DEVICE_REINITIALIZATION_NEEDED = 1164, + MD_ERROR_WIN_DEVICE_REQUIRES_CLEANING = 1165, + MD_ERROR_WIN_DEVICE_DOOR_OPEN = 1166, + MD_ERROR_WIN_DEVICE_NOT_CONNECTED = 1167, + MD_ERROR_WIN_NOT_FOUND = 1168, + MD_ERROR_WIN_NO_MATCH = 1169, + MD_ERROR_WIN_SET_NOT_FOUND = 1170, + MD_ERROR_WIN_POINT_NOT_FOUND = 1171, + MD_ERROR_WIN_NO_TRACKING_SERVICE = 1172, + MD_ERROR_WIN_NO_VOLUME_ID = 1173, + MD_ERROR_WIN_UNABLE_TO_REMOVE_REPLACED = 1175, + MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT = 1176, + MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT_2 = 1177, + MD_ERROR_WIN_JOURNAL_DELETE_IN_PROGRESS = 1178, + MD_ERROR_WIN_JOURNAL_NOT_ACTIVE = 1179, + MD_ERROR_WIN_POTENTIAL_FILE_FOUND = 1180, + MD_ERROR_WIN_JOURNAL_ENTRY_DELETED = 1181, + MD_ERROR_WIN_VRF_CFG_AND_IO_ENABLED = 1183, + MD_ERROR_WIN_PARTITION_TERMINATING = 1184, + MD_ERROR_WIN_SHUTDOWN_IS_SCHEDULED = 1190, + MD_ERROR_WIN_SHUTDOWN_USERS_LOGGED_ON = 1191, + MD_ERROR_WIN_BAD_DEVICE = 1200, + MD_ERROR_WIN_CONNECTION_UNAVAIL = 1201, + MD_ERROR_WIN_DEVICE_ALREADY_REMEMBERED = 1202, + MD_ERROR_WIN_NO_NET_OR_BAD_PATH = 1203, + MD_ERROR_WIN_BAD_PROVIDER = 1204, + MD_ERROR_WIN_CANNOT_OPEN_PROFILE = 1205, + MD_ERROR_WIN_BAD_PROFILE = 1206, + MD_ERROR_WIN_NOT_CONTAINER = 1207, + MD_ERROR_WIN_EXTENDED_ERROR = 1208, + MD_ERROR_WIN_INVALID_GROUPNAME = 1209, + MD_ERROR_WIN_INVALID_COMPUTERNAME = 1210, + MD_ERROR_WIN_INVALID_EVENTNAME = 1211, + MD_ERROR_WIN_INVALID_DOMAINNAME = 1212, + MD_ERROR_WIN_INVALID_SERVICENAME = 1213, + MD_ERROR_WIN_INVALID_NETNAME = 1214, + MD_ERROR_WIN_INVALID_SHARENAME = 1215, + MD_ERROR_WIN_INVALID_PASSWORDNAME = 1216, + MD_ERROR_WIN_INVALID_MESSAGENAME = 1217, + MD_ERROR_WIN_INVALID_MESSAGEDEST = 1218, + MD_ERROR_WIN_SESSION_CREDENTIAL_CONFLICT = 1219, + MD_ERROR_WIN_REMOTE_SESSION_LIMIT_EXCEEDED = 1220, + MD_ERROR_WIN_DUP_DOMAINNAME = 1221, + MD_ERROR_WIN_NO_NETWORK = 1222, + MD_ERROR_WIN_CANCELLED = 1223, + MD_ERROR_WIN_USER_MAPPED_FILE = 1224, + MD_ERROR_WIN_CONNECTION_REFUSED = 1225, + MD_ERROR_WIN_GRACEFUL_DISCONNECT = 1226, + MD_ERROR_WIN_ADDRESS_ALREADY_ASSOCIATED = 1227, + MD_ERROR_WIN_ADDRESS_NOT_ASSOCIATED = 1228, + MD_ERROR_WIN_CONNECTION_INVALID = 1229, + MD_ERROR_WIN_CONNECTION_ACTIVE = 1230, + MD_ERROR_WIN_NETWORK_UNREACHABLE = 1231, + MD_ERROR_WIN_HOST_UNREACHABLE = 1232, + MD_ERROR_WIN_PROTOCOL_UNREACHABLE = 1233, + MD_ERROR_WIN_PORT_UNREACHABLE = 1234, + MD_ERROR_WIN_REQUEST_ABORTED = 1235, + MD_ERROR_WIN_CONNECTION_ABORTED = 1236, + MD_ERROR_WIN_RETRY = 1237, + MD_ERROR_WIN_CONNECTION_COUNT_LIMIT = 1238, + MD_ERROR_WIN_LOGIN_TIME_RESTRICTION = 1239, + MD_ERROR_WIN_LOGIN_WKSTA_RESTRICTION = 1240, + MD_ERROR_WIN_INCORRECT_ADDRESS = 1241, + MD_ERROR_WIN_ALREADY_REGISTERED = 1242, + MD_ERROR_WIN_SERVICE_NOT_FOUND = 1243, + MD_ERROR_WIN_NOT_AUTHENTICATED = 1244, + MD_ERROR_WIN_NOT_LOGGED_ON = 1245, + MD_ERROR_WIN_CONTINUE = 1246, + MD_ERROR_WIN_ALREADY_INITIALIZED = 1247, + MD_ERROR_WIN_NO_MORE_DEVICES = 1248, + MD_ERROR_WIN_NO_SUCH_SITE = 1249, + MD_ERROR_WIN_DOMAIN_CONTROLLER_EXISTS = 1250, + MD_ERROR_WIN_ONLY_IF_CONNECTED = 1251, + MD_ERROR_WIN_OVERRIDE_NOCHANGES = 1252, + MD_ERROR_WIN_BAD_USER_PROFILE = 1253, + MD_ERROR_WIN_NOT_SUPPORTED_ON_SBS = 1254, + MD_ERROR_WIN_SERVER_SHUTDOWN_IN_PROGRESS = 1255, + MD_ERROR_WIN_HOST_DOWN = 1256, + MD_ERROR_WIN_NON_ACCOUNT_SID = 1257, + MD_ERROR_WIN_NON_DOMAIN_SID = 1258, + MD_ERROR_WIN_APPHELP_BLOCK = 1259, + MD_ERROR_WIN_ACCESS_DISABLED_BY_POLICY = 1260, + MD_ERROR_WIN_REG_NAT_CONSUMPTION = 1261, + MD_ERROR_WIN_CSCSHARE_OFFLINE = 1262, + MD_ERROR_WIN_PKINIT_FAILURE = 1263, + MD_ERROR_WIN_SMARTCARD_SUBSYSTEM_FAILURE = 1264, + MD_ERROR_WIN_DOWNGRADE_DETECTED = 1265, + MD_ERROR_WIN_MACHINE_LOCKED = 1271, + MD_ERROR_WIN_SMB_GUEST_LOGON_BLOCKED = 1272, + MD_ERROR_WIN_CALLBACK_SUPPLIED_INVALID_DATA = 1273, + MD_ERROR_WIN_SYNC_FOREGROUND_REFRESH_REQUIRED = 1274, + MD_ERROR_WIN_DRIVER_BLOCKED = 1275, + MD_ERROR_WIN_INVALID_IMPORT_OF_NON_DLL = 1276, + MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE = 1277, + MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE_TAMPER = 1278, + MD_ERROR_WIN_RECOVERY_FAILURE = 1279, + MD_ERROR_WIN_ALREADY_FIBER = 1280, + MD_ERROR_WIN_ALREADY_THREAD = 1281, + MD_ERROR_WIN_STACK_BUFFER_OVERRUN = 1282, + MD_ERROR_WIN_PARAMETER_QUOTA_EXCEEDED = 1283, + MD_ERROR_WIN_DEBUGGER_INACTIVE = 1284, + MD_ERROR_WIN_DELAY_LOAD_FAILED = 1285, + MD_ERROR_WIN_VDM_DISALLOWED = 1286, + MD_ERROR_WIN_UNIDENTIFIED_ERROR = 1287, + MD_ERROR_WIN_INVALID_CRUNTIME_PARAMETER = 1288, + MD_ERROR_WIN_BEYOND_VDL = 1289, + MD_ERROR_WIN_INCOMPATIBLE_SERVICE_SID_TYPE = 1290, + MD_ERROR_WIN_DRIVER_PROCESS_TERMINATED = 1291, + MD_ERROR_WIN_IMPLEMENTATION_LIMIT = 1292, + MD_ERROR_WIN_PROCESS_IS_PROTECTED = 1293, + MD_ERROR_WIN_SERVICE_NOTIFY_CLIENT_LAGGING = 1294, + MD_ERROR_WIN_DISK_QUOTA_EXCEEDED = 1295, + MD_ERROR_WIN_CONTENT_BLOCKED = 1296, + MD_ERROR_WIN_INCOMPATIBLE_SERVICE_PRIVILEGE = 1297, + MD_ERROR_WIN_APP_HANG = 1298, + MD_ERROR_WIN_INVALID_LABEL = 1299, + MD_ERROR_WIN_NOT_ALL_ASSIGNED = 1300, + MD_ERROR_WIN_SOME_NOT_MAPPED = 1301, + MD_ERROR_WIN_NO_QUOTAS_FOR_ACCOUNT = 1302, + MD_ERROR_WIN_LOCAL_USER_SESSION_KEY = 1303, + MD_ERROR_WIN_NULL_LM_PASSWORD = 1304, + MD_ERROR_WIN_UNKNOWN_REVISION = 1305, + MD_ERROR_WIN_REVISION_MISMATCH = 1306, + MD_ERROR_WIN_INVALID_OWNER = 1307, + MD_ERROR_WIN_INVALID_PRIMARY_GROUP = 1308, + MD_ERROR_WIN_NO_IMPERSONATION_TOKEN = 1309, + MD_ERROR_WIN_CANT_DISABLE_MANDATORY = 1310, + MD_ERROR_WIN_NO_LOGON_SERVERS = 1311, + MD_ERROR_WIN_NO_SUCH_LOGON_SESSION = 1312, + MD_ERROR_WIN_NO_SUCH_PRIVILEGE = 1313, + MD_ERROR_WIN_PRIVILEGE_NOT_HELD = 1314, + MD_ERROR_WIN_INVALID_ACCOUNT_NAME = 1315, + MD_ERROR_WIN_USER_EXISTS = 1316, + MD_ERROR_WIN_NO_SUCH_USER = 1317, + MD_ERROR_WIN_GROUP_EXISTS = 1318, + MD_ERROR_WIN_NO_SUCH_GROUP = 1319, + MD_ERROR_WIN_MEMBER_IN_GROUP = 1320, + MD_ERROR_WIN_MEMBER_NOT_IN_GROUP = 1321, + MD_ERROR_WIN_LAST_ADMIN = 1322, + MD_ERROR_WIN_WRONG_PASSWORD = 1323, + MD_ERROR_WIN_ILL_FORMED_PASSWORD = 1324, + MD_ERROR_WIN_PASSWORD_RESTRICTION = 1325, + MD_ERROR_WIN_LOGON_FAILURE = 1326, + MD_ERROR_WIN_ACCOUNT_RESTRICTION = 1327, + MD_ERROR_WIN_INVALID_LOGON_HOURS = 1328, + MD_ERROR_WIN_INVALID_WORKSTATION = 1329, + MD_ERROR_WIN_PASSWORD_EXPIRED = 1330, + MD_ERROR_WIN_ACCOUNT_DISABLED = 1331, + MD_ERROR_WIN_NONE_MAPPED = 1332, + MD_ERROR_WIN_TOO_MANY_LUIDS_REQUESTED = 1333, + MD_ERROR_WIN_LUIDS_EXHAUSTED = 1334, + MD_ERROR_WIN_INVALID_SUB_AUTHORITY = 1335, + MD_ERROR_WIN_INVALID_ACL = 1336, + MD_ERROR_WIN_INVALID_SID = 1337, + MD_ERROR_WIN_INVALID_SECURITY_DESCR = 1338, + MD_ERROR_WIN_BAD_INHERITANCE_ACL = 1340, + MD_ERROR_WIN_SERVER_DISABLED = 1341, + MD_ERROR_WIN_SERVER_NOT_DISABLED = 1342, + MD_ERROR_WIN_INVALID_ID_AUTHORITY = 1343, + MD_ERROR_WIN_ALLOTTED_SPACE_EXCEEDED = 1344, + MD_ERROR_WIN_INVALID_GROUP_ATTRIBUTES = 1345, + MD_ERROR_WIN_BAD_IMPERSONATION_LEVEL = 1346, + MD_ERROR_WIN_CANT_OPEN_ANONYMOUS = 1347, + MD_ERROR_WIN_BAD_VALIDATION_CLASS = 1348, + MD_ERROR_WIN_BAD_TOKEN_TYPE = 1349, + MD_ERROR_WIN_NO_SECURITY_ON_OBJECT = 1350, + MD_ERROR_WIN_CANT_ACCESS_DOMAIN_INFO = 1351, + MD_ERROR_WIN_INVALID_SERVER_STATE = 1352, + MD_ERROR_WIN_INVALID_DOMAIN_STATE = 1353, + MD_ERROR_WIN_INVALID_DOMAIN_ROLE = 1354, + MD_ERROR_WIN_NO_SUCH_DOMAIN = 1355, + MD_ERROR_WIN_DOMAIN_EXISTS = 1356, + MD_ERROR_WIN_DOMAIN_LIMIT_EXCEEDED = 1357, + MD_ERROR_WIN_INTERNAL_DB_CORRUPTION = 1358, + MD_ERROR_WIN_INTERNAL_ERROR = 1359, + MD_ERROR_WIN_GENERIC_NOT_MAPPED = 1360, + MD_ERROR_WIN_BAD_DESCRIPTOR_FORMAT = 1361, + MD_ERROR_WIN_NOT_LOGON_PROCESS = 1362, + MD_ERROR_WIN_LOGON_SESSION_EXISTS = 1363, + MD_ERROR_WIN_NO_SUCH_PACKAGE = 1364, + MD_ERROR_WIN_BAD_LOGON_SESSION_STATE = 1365, + MD_ERROR_WIN_LOGON_SESSION_COLLISION = 1366, + MD_ERROR_WIN_INVALID_LOGON_TYPE = 1367, + MD_ERROR_WIN_CANNOT_IMPERSONATE = 1368, + MD_ERROR_WIN_RXACT_INVALID_STATE = 1369, + MD_ERROR_WIN_RXACT_COMMIT_FAILURE = 1370, + MD_ERROR_WIN_SPECIAL_ACCOUNT = 1371, + MD_ERROR_WIN_SPECIAL_GROUP = 1372, + MD_ERROR_WIN_SPECIAL_USER = 1373, + MD_ERROR_WIN_MEMBERS_PRIMARY_GROUP = 1374, + MD_ERROR_WIN_TOKEN_ALREADY_IN_USE = 1375, + MD_ERROR_WIN_NO_SUCH_ALIAS = 1376, + MD_ERROR_WIN_MEMBER_NOT_IN_ALIAS = 1377, + MD_ERROR_WIN_MEMBER_IN_ALIAS = 1378, + MD_ERROR_WIN_ALIAS_EXISTS = 1379, + MD_ERROR_WIN_LOGON_NOT_GRANTED = 1380, + MD_ERROR_WIN_TOO_MANY_SECRETS = 1381, + MD_ERROR_WIN_SECRET_TOO_LONG = 1382, + MD_ERROR_WIN_INTERNAL_DB_ERROR = 1383, + MD_ERROR_WIN_TOO_MANY_CONTEXT_IDS = 1384, + MD_ERROR_WIN_LOGON_TYPE_NOT_GRANTED = 1385, + MD_ERROR_WIN_NT_CROSS_ENCRYPTION_REQUIRED = 1386, + MD_ERROR_WIN_NO_SUCH_MEMBER = 1387, + MD_ERROR_WIN_INVALID_MEMBER = 1388, + MD_ERROR_WIN_TOO_MANY_SIDS = 1389, + MD_ERROR_WIN_LM_CROSS_ENCRYPTION_REQUIRED = 1390, + MD_ERROR_WIN_NO_INHERITANCE = 1391, + MD_ERROR_WIN_FILE_CORRUPT = 1392, + MD_ERROR_WIN_DISK_CORRUPT = 1393, + MD_ERROR_WIN_NO_USER_SESSION_KEY = 1394, + MD_ERROR_WIN_LICENSE_QUOTA_EXCEEDED = 1395, + MD_ERROR_WIN_WRONG_TARGET_NAME = 1396, + MD_ERROR_WIN_MUTUAL_AUTH_FAILED = 1397, + MD_ERROR_WIN_TIME_SKEW = 1398, + MD_ERROR_WIN_CURRENT_DOMAIN_NOT_ALLOWED = 1399, + MD_ERROR_WIN_INVALID_WINDOW_HANDLE = 1400, + MD_ERROR_WIN_INVALID_MENU_HANDLE = 1401, + MD_ERROR_WIN_INVALID_CURSOR_HANDLE = 1402, + MD_ERROR_WIN_INVALID_ACCEL_HANDLE = 1403, + MD_ERROR_WIN_INVALID_HOOK_HANDLE = 1404, + MD_ERROR_WIN_INVALID_DWP_HANDLE = 1405, + MD_ERROR_WIN_TLW_WITH_WSCHILD = 1406, + MD_ERROR_WIN_CANNOT_FIND_WND_CLASS = 1407, + MD_ERROR_WIN_WINDOW_OF_OTHER_THREAD = 1408, + MD_ERROR_WIN_HOTKEY_ALREADY_REGISTERED = 1409, + MD_ERROR_WIN_CLASS_ALREADY_EXISTS = 1410, + MD_ERROR_WIN_CLASS_DOES_NOT_EXIST = 1411, + MD_ERROR_WIN_CLASS_HAS_WINDOWS = 1412, + MD_ERROR_WIN_INVALID_INDEX = 1413, + MD_ERROR_WIN_INVALID_ICON_HANDLE = 1414, + MD_ERROR_WIN_PRIVATE_DIALOG_INDEX = 1415, + MD_ERROR_WIN_LISTBOX_ID_NOT_FOUND = 1416, + MD_ERROR_WIN_NO_WILDCARD_CHARACTERS = 1417, + MD_ERROR_WIN_CLIPBOARD_NOT_OPEN = 1418, + MD_ERROR_WIN_HOTKEY_NOT_REGISTERED = 1419, + MD_ERROR_WIN_WINDOW_NOT_DIALOG = 1420, + MD_ERROR_WIN_CONTROL_ID_NOT_FOUND = 1421, + MD_ERROR_WIN_INVALID_COMBOBOX_MESSAGE = 1422, + MD_ERROR_WIN_WINDOW_NOT_COMBOBOX = 1423, + MD_ERROR_WIN_INVALID_EDIT_HEIGHT = 1424, + MD_ERROR_WIN_DC_NOT_FOUND = 1425, + MD_ERROR_WIN_INVALID_HOOK_FILTER = 1426, + MD_ERROR_WIN_INVALID_FILTER_PROC = 1427, + MD_ERROR_WIN_HOOK_NEEDS_HMOD = 1428, + MD_ERROR_WIN_GLOBAL_ONLY_HOOK = 1429, + MD_ERROR_WIN_JOURNAL_HOOK_SET = 1430, + MD_ERROR_WIN_HOOK_NOT_INSTALLED = 1431, + MD_ERROR_WIN_INVALID_LB_MESSAGE = 1432, + MD_ERROR_WIN_SETCOUNT_ON_BAD_LB = 1433, + MD_ERROR_WIN_LB_WITHOUT_TABSTOPS = 1434, + MD_ERROR_WIN_DESTROY_OBJECT_OF_OTHER_THREAD = 1435, + MD_ERROR_WIN_CHILD_WINDOW_MENU = 1436, + MD_ERROR_WIN_NO_SYSTEM_MENU = 1437, + MD_ERROR_WIN_INVALID_MSGBOX_STYLE = 1438, + MD_ERROR_WIN_INVALID_SPI_VALUE = 1439, + MD_ERROR_WIN_SCREEN_ALREADY_LOCKED = 1440, + MD_ERROR_WIN_HWNDS_HAVE_DIFF_PARENT = 1441, + MD_ERROR_WIN_NOT_CHILD_WINDOW = 1442, + MD_ERROR_WIN_INVALID_GW_COMMAND = 1443, + MD_ERROR_WIN_INVALID_THREAD_ID = 1444, + MD_ERROR_WIN_NON_MDICHILD_WINDOW = 1445, + MD_ERROR_WIN_POPUP_ALREADY_ACTIVE = 1446, + MD_ERROR_WIN_NO_SCROLLBARS = 1447, + MD_ERROR_WIN_INVALID_SCROLLBAR_RANGE = 1448, + MD_ERROR_WIN_INVALID_SHOWWIN_COMMAND = 1449, + MD_ERROR_WIN_NO_SYSTEM_RESOURCES = 1450, + MD_ERROR_WIN_NONPAGED_SYSTEM_RESOURCES = 1451, + MD_ERROR_WIN_PAGED_SYSTEM_RESOURCES = 1452, + MD_ERROR_WIN_WORKING_SET_QUOTA = 1453, + MD_ERROR_WIN_PAGEFILE_QUOTA = 1454, + MD_ERROR_WIN_COMMITMENT_LIMIT = 1455, + MD_ERROR_WIN_MENU_ITEM_NOT_FOUND = 1456, + MD_ERROR_WIN_INVALID_KEYBOARD_HANDLE = 1457, + MD_ERROR_WIN_HOOK_TYPE_NOT_ALLOWED = 1458, + MD_ERROR_WIN_REQUIRES_INTERACTIVE_WINDOWSTATION = 1459, + MD_ERROR_WIN_TIMEOUT = 1460, + MD_ERROR_WIN_INVALID_MONITOR_HANDLE = 1461, + MD_ERROR_WIN_INCORRECT_SIZE = 1462, + MD_ERROR_WIN_SYMLINK_CLASS_DISABLED = 1463, + MD_ERROR_WIN_SYMLINK_NOT_SUPPORTED = 1464, + MD_ERROR_WIN_XML_PARSE_ERROR = 1465, + MD_ERROR_WIN_XMLDSIG_ERROR = 1466, + MD_ERROR_WIN_RESTART_APPLICATION = 1467, + MD_ERROR_WIN_WRONG_COMPARTMENT = 1468, + MD_ERROR_WIN_AUTHIP_FAILURE = 1469, + MD_ERROR_WIN_NO_NVRAM_RESOURCES = 1470, + MD_ERROR_WIN_NOT_GUI_PROCESS = 1471, + MD_ERROR_WIN_EVENTLOG_FILE_CORRUPT = 1500, + MD_ERROR_WIN_EVENTLOG_CANT_START = 1501, + MD_ERROR_WIN_LOG_FILE_FULL = 1502, + MD_ERROR_WIN_EVENTLOG_FILE_CHANGED = 1503, + MD_ERROR_WIN_CONTAINER_ASSIGNED = 1504, + MD_ERROR_WIN_JOB_NO_CONTAINER = 1505, + MD_ERROR_WIN_INVALID_TASK_NAME = 1550, + MD_ERROR_WIN_INVALID_TASK_INDEX = 1551, + MD_ERROR_WIN_THREAD_ALREADY_IN_TASK = 1552, + MD_ERROR_WIN_INSTALL_SERVICE_FAILURE = 1601, + MD_ERROR_WIN_INSTALL_USEREXIT = 1602, + MD_ERROR_WIN_INSTALL_FAILURE = 1603, + MD_ERROR_WIN_INSTALL_SUSPEND = 1604, + MD_ERROR_WIN_UNKNOWN_PRODUCT = 1605, + MD_ERROR_WIN_UNKNOWN_FEATURE = 1606, + MD_ERROR_WIN_UNKNOWN_COMPONENT = 1607, + MD_ERROR_WIN_UNKNOWN_PROPERTY = 1608, + MD_ERROR_WIN_INVALID_HANDLE_STATE = 1609, + MD_ERROR_WIN_BAD_CONFIGURATION = 1610, + MD_ERROR_WIN_INDEX_ABSENT = 1611, + MD_ERROR_WIN_INSTALL_SOURCE_ABSENT = 1612, + MD_ERROR_WIN_INSTALL_PACKAGE_VERSION = 1613, + MD_ERROR_WIN_PRODUCT_UNINSTALLED = 1614, + MD_ERROR_WIN_BAD_QUERY_SYNTAX = 1615, + MD_ERROR_WIN_INVALID_FIELD = 1616, + MD_ERROR_WIN_DEVICE_REMOVED = 1617, + MD_ERROR_WIN_INSTALL_ALREADY_RUNNING = 1618, + MD_ERROR_WIN_INSTALL_PACKAGE_OPEN_FAILED = 1619, + MD_ERROR_WIN_INSTALL_PACKAGE_INVALID = 1620, + MD_ERROR_WIN_INSTALL_UI_FAILURE = 1621, + MD_ERROR_WIN_INSTALL_LOG_FAILURE = 1622, + MD_ERROR_WIN_INSTALL_LANGUAGE_UNSUPPORTED = 1623, + MD_ERROR_WIN_INSTALL_TRANSFORM_FAILURE = 1624, + MD_ERROR_WIN_INSTALL_PACKAGE_REJECTED = 1625, + MD_ERROR_WIN_FUNCTION_NOT_CALLED = 1626, + MD_ERROR_WIN_FUNCTION_FAILED = 1627, + MD_ERROR_WIN_INVALID_TABLE = 1628, + MD_ERROR_WIN_DATATYPE_MISMATCH = 1629, + MD_ERROR_WIN_UNSUPPORTED_TYPE = 1630, + MD_ERROR_WIN_CREATE_FAILED = 1631, + MD_ERROR_WIN_INSTALL_TEMP_UNWRITABLE = 1632, + MD_ERROR_WIN_INSTALL_PLATFORM_UNSUPPORTED = 1633, + MD_ERROR_WIN_INSTALL_NOTUSED = 1634, + MD_ERROR_WIN_PATCH_PACKAGE_OPEN_FAILED = 1635, + MD_ERROR_WIN_PATCH_PACKAGE_INVALID = 1636, + MD_ERROR_WIN_PATCH_PACKAGE_UNSUPPORTED = 1637, + MD_ERROR_WIN_PRODUCT_VERSION = 1638, + MD_ERROR_WIN_INVALID_COMMAND_LINE = 1639, + MD_ERROR_WIN_INSTALL_REMOTE_DISALLOWED = 1640, + MD_ERROR_WIN_SUCCESS_REBOOT_INITIATED = 1641, + MD_ERROR_WIN_PATCH_TARGET_NOT_FOUND = 1642, + MD_ERROR_WIN_PATCH_PACKAGE_REJECTED = 1643, + MD_ERROR_WIN_INSTALL_TRANSFORM_REJECTED = 1644, + MD_ERROR_WIN_INSTALL_REMOTE_PROHIBITED = 1645, + MD_ERROR_WIN_PATCH_REMOVAL_UNSUPPORTED = 1646, + MD_ERROR_WIN_UNKNOWN_PATCH = 1647, + MD_ERROR_WIN_PATCH_NO_SEQUENCE = 1648, + MD_ERROR_WIN_PATCH_REMOVAL_DISALLOWED = 1649, + MD_ERROR_WIN_INVALID_PATCH_XML = 1650, + MD_ERROR_WIN_PATCH_MANAGED_ADVERTISED_PRODUCT = 1651, + MD_ERROR_WIN_INSTALL_SERVICE_SAFEBOOT = 1652, + MD_ERROR_WIN_FAIL_FAST_EXCEPTION = 1653, + MD_ERROR_WIN_INSTALL_REJECTED = 1654, + MD_ERROR_WIN_DYNAMIC_CODE_BLOCKED = 1655, + MD_ERROR_WIN_NOT_SAME_OBJECT = 1656, + MD_ERROR_WIN_STRICT_CFG_VIOLATION = 1657, + MD_ERROR_WIN_SET_CONTEXT_DENIED = 1660, + MD_ERROR_WIN_CROSS_PARTITION_VIOLATION = 1661, + MD_ERROR_WIN_RETURN_ADDRESS_HIJACK_ATTEMPT = 1662, + MD_ERROR_WIN_INVALID_USER_BUFFER = 1784, + MD_ERROR_WIN_UNRECOGNIZED_MEDIA = 1785, + MD_ERROR_WIN_NO_TRUST_LSA_SECRET = 1786, + MD_ERROR_WIN_NO_TRUST_SAM_ACCOUNT = 1787, + MD_ERROR_WIN_TRUSTED_DOMAIN_FAILURE = 1788, + MD_ERROR_WIN_TRUSTED_RELATIONSHIP_FAILURE = 1789, + MD_ERROR_WIN_TRUST_FAILURE = 1790, + MD_ERROR_WIN_NETLOGON_NOT_STARTED = 1792, + MD_ERROR_WIN_ACCOUNT_EXPIRED = 1793, + MD_ERROR_WIN_REDIRECTOR_HAS_OPEN_HANDLES = 1794, + MD_ERROR_WIN_PRINTER_DRIVER_ALREADY_INSTALLED = 1795, + MD_ERROR_WIN_UNKNOWN_PORT = 1796, + MD_ERROR_WIN_UNKNOWN_PRINTER_DRIVER = 1797, + MD_ERROR_WIN_UNKNOWN_PRINTPROCESSOR = 1798, + MD_ERROR_WIN_INVALID_SEPARATOR_FILE = 1799, + MD_ERROR_WIN_INVALID_PRIORITY = 1800, + MD_ERROR_WIN_INVALID_PRINTER_NAME = 1801, + MD_ERROR_WIN_PRINTER_ALREADY_EXISTS = 1802, + MD_ERROR_WIN_INVALID_PRINTER_COMMAND = 1803, + MD_ERROR_WIN_INVALID_DATATYPE = 1804, + MD_ERROR_WIN_INVALID_ENVIRONMENT = 1805, + MD_ERROR_WIN_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 1807, + MD_ERROR_WIN_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 1808, + MD_ERROR_WIN_NOLOGON_SERVER_TRUST_ACCOUNT = 1809, + MD_ERROR_WIN_DOMAIN_TRUST_INCONSISTENT = 1810, + MD_ERROR_WIN_SERVER_HAS_OPEN_HANDLES = 1811, + MD_ERROR_WIN_RESOURCE_DATA_NOT_FOUND = 1812, + MD_ERROR_WIN_RESOURCE_TYPE_NOT_FOUND = 1813, + MD_ERROR_WIN_RESOURCE_NAME_NOT_FOUND = 1814, + MD_ERROR_WIN_RESOURCE_LANG_NOT_FOUND = 1815, + MD_ERROR_WIN_NOT_ENOUGH_QUOTA = 1816, + MD_ERROR_WIN_INVALID_TIME = 1901, + MD_ERROR_WIN_INVALID_FORM_NAME = 1902, + MD_ERROR_WIN_INVALID_FORM_SIZE = 1903, + MD_ERROR_WIN_ALREADY_WAITING = 1904, + MD_ERROR_WIN_PRINTER_DELETED = 1905, + MD_ERROR_WIN_INVALID_PRINTER_STATE = 1906, + MD_ERROR_WIN_PASSWORD_MUST_CHANGE = 1907, + MD_ERROR_WIN_DOMAIN_CONTROLLER_NOT_FOUND = 1908, + MD_ERROR_WIN_ACCOUNT_LOCKED_OUT = 1909, + MD_ERROR_WIN_NO_SITENAME = 1919, + MD_ERROR_WIN_CANT_ACCESS_FILE = 1920, + MD_ERROR_WIN_CANT_RESOLVE_FILENAME = 1921, + MD_ERROR_WIN_KM_DRIVER_BLOCKED = 1930, + MD_ERROR_WIN_CONTEXT_EXPIRED = 1931, + MD_ERROR_WIN_PER_USER_TRUST_QUOTA_EXCEEDED = 1932, + MD_ERROR_WIN_ALL_USER_TRUST_QUOTA_EXCEEDED = 1933, + MD_ERROR_WIN_USER_DELETE_TRUST_QUOTA_EXCEEDED = 1934, + MD_ERROR_WIN_AUTHENTICATION_FIREWALL_FAILED = 1935, + MD_ERROR_WIN_REMOTE_PRINT_CONNECTIONS_BLOCKED = 1936, + MD_ERROR_WIN_NTLM_BLOCKED = 1937, + MD_ERROR_WIN_PASSWORD_CHANGE_REQUIRED = 1938, + MD_ERROR_WIN_LOST_MODE_LOGON_RESTRICTION = 1939, + MD_ERROR_WIN_INVALID_PIXEL_FORMAT = 2000, + MD_ERROR_WIN_BAD_DRIVER = 2001, + MD_ERROR_WIN_INVALID_WINDOW_STYLE = 2002, + MD_ERROR_WIN_METAFILE_NOT_SUPPORTED = 2003, + MD_ERROR_WIN_TRANSFORM_NOT_SUPPORTED = 2004, + MD_ERROR_WIN_CLIPPING_NOT_SUPPORTED = 2005, + MD_ERROR_WIN_INVALID_CMM = 2010, + MD_ERROR_WIN_INVALID_PROFILE = 2011, + MD_ERROR_WIN_TAG_NOT_FOUND = 2012, + MD_ERROR_WIN_TAG_NOT_PRESENT = 2013, + MD_ERROR_WIN_DUPLICATE_TAG = 2014, + MD_ERROR_WIN_PROFILE_NOT_ASSOCIATED_WITH_DEVICE = 2015, + MD_ERROR_WIN_PROFILE_NOT_FOUND = 2016, + MD_ERROR_WIN_INVALID_COLORSPACE = 2017, + MD_ERROR_WIN_ICM_NOT_ENABLED = 2018, + MD_ERROR_WIN_DELETING_ICM_XFORM = 2019, + MD_ERROR_WIN_INVALID_TRANSFORM = 2020, + MD_ERROR_WIN_COLORSPACE_MISMATCH = 2021, + MD_ERROR_WIN_INVALID_COLORINDEX = 2022, + MD_ERROR_WIN_PROFILE_DOES_NOT_MATCH_DEVICE = 2023, + MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD = 2108, + MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD_DEFAULT = 2109, + MD_ERROR_WIN_BAD_USERNAME = 2202, + MD_ERROR_WIN_NOT_CONNECTED = 2250, + MD_ERROR_WIN_OPEN_FILES = 2401, + MD_ERROR_WIN_ACTIVE_CONNECTIONS = 2402, + MD_ERROR_WIN_DEVICE_IN_USE = 2404, + MD_ERROR_WIN_UNKNOWN_PRINT_MONITOR = 3000, + MD_ERROR_WIN_PRINTER_DRIVER_IN_USE = 3001, + MD_ERROR_WIN_SPOOL_FILE_NOT_FOUND = 3002, + MD_ERROR_WIN_SPL_NO_STARTDOC = 3003, + MD_ERROR_WIN_SPL_NO_ADDJOB = 3004, + MD_ERROR_WIN_PRINT_PROCESSOR_ALREADY_INSTALLED = 3005, + MD_ERROR_WIN_PRINT_MONITOR_ALREADY_INSTALLED = 3006, + MD_ERROR_WIN_INVALID_PRINT_MONITOR = 3007, + MD_ERROR_WIN_PRINT_MONITOR_IN_USE = 3008, + MD_ERROR_WIN_PRINTER_HAS_JOBS_QUEUED = 3009, + MD_ERROR_WIN_SUCCESS_REBOOT_REQUIRED = 3010, + MD_ERROR_WIN_SUCCESS_RESTART_REQUIRED = 3011, + MD_ERROR_WIN_PRINTER_NOT_FOUND = 3012, + MD_ERROR_WIN_PRINTER_DRIVER_WARNED = 3013, + MD_ERROR_WIN_PRINTER_DRIVER_BLOCKED = 3014, + MD_ERROR_WIN_PRINTER_DRIVER_PACKAGE_IN_USE = 3015, + MD_ERROR_WIN_CORE_DRIVER_PACKAGE_NOT_FOUND = 3016, + MD_ERROR_WIN_FAIL_REBOOT_REQUIRED = 3017, + MD_ERROR_WIN_FAIL_REBOOT_INITIATED = 3018, + MD_ERROR_WIN_PRINTER_DRIVER_DOWNLOAD_NEEDED = 3019, + MD_ERROR_WIN_PRINT_JOB_RESTART_REQUIRED = 3020, + MD_ERROR_WIN_INVALID_PRINTER_DRIVER_MANIFEST = 3021, + MD_ERROR_WIN_PRINTER_NOT_SHAREABLE = 3022, + MD_ERROR_WIN_REQUEST_PAUSED = 3050, + MD_ERROR_WIN_APPEXEC_CONDITION_NOT_SATISFIED = 3060, + MD_ERROR_WIN_APPEXEC_HANDLE_INVALIDATED = 3061, + MD_ERROR_WIN_APPEXEC_INVALID_HOST_GENERATION = 3062, + MD_ERROR_WIN_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION = 3063, + MD_ERROR_WIN_APPEXEC_INVALID_HOST_STATE = 3064, + MD_ERROR_WIN_APPEXEC_NO_DONOR = 3065, + MD_ERROR_WIN_APPEXEC_HOST_ID_MISMATCH = 3066, + MD_ERROR_WIN_APPEXEC_UNKNOWN_USER = 3067, + MD_ERROR_WIN_IO_REISSUE_AS_CACHED = 3950, + MD_ERROR_WIN_WINS_INTERNAL = 4000, + MD_ERROR_WIN_CAN_NOT_DEL_LOCAL_WINS = 4001, + MD_ERROR_WIN_STATIC_INIT = 4002, + MD_ERROR_WIN_INC_BACKUP = 4003, + MD_ERROR_WIN_FULL_BACKUP = 4004, + MD_ERROR_WIN_REC_NON_EXISTENT = 4005, + MD_ERROR_WIN_RPL_NOT_ALLOWED = 4006, + MD_ERROR_WIN_DHCP_ADDRESS_CONFLICT = 4100, + MD_ERROR_WIN_WMI_GUID_NOT_FOUND = 4200, + MD_ERROR_WIN_WMI_INSTANCE_NOT_FOUND = 4201, + MD_ERROR_WIN_WMI_ITEMID_NOT_FOUND = 4202, + MD_ERROR_WIN_WMI_TRY_AGAIN = 4203, + MD_ERROR_WIN_WMI_DP_NOT_FOUND = 4204, + MD_ERROR_WIN_WMI_UNRESOLVED_INSTANCE_REF = 4205, + MD_ERROR_WIN_WMI_ALREADY_ENABLED = 4206, + MD_ERROR_WIN_WMI_GUID_DISCONNECTED = 4207, + MD_ERROR_WIN_WMI_SERVER_UNAVAILABLE = 4208, + MD_ERROR_WIN_WMI_DP_FAILED = 4209, + MD_ERROR_WIN_WMI_INVALID_MOF = 4210, + MD_ERROR_WIN_WMI_INVALID_REGINFO = 4211, + MD_ERROR_WIN_WMI_ALREADY_DISABLED = 4212, + MD_ERROR_WIN_WMI_READ_ONLY = 4213, + MD_ERROR_WIN_WMI_SET_FAILURE = 4214, + MD_ERROR_WIN_NOT_APPCONTAINER = 4250, + MD_ERROR_WIN_APPCONTAINER_REQUIRED = 4251, + MD_ERROR_WIN_NOT_SUPPORTED_IN_APPCONTAINER = 4252, + MD_ERROR_WIN_INVALID_PACKAGE_SID_LENGTH = 4253, + MD_ERROR_WIN_INVALID_MEDIA = 4300, + MD_ERROR_WIN_INVALID_LIBRARY = 4301, + MD_ERROR_WIN_INVALID_MEDIA_POOL = 4302, + MD_ERROR_WIN_DRIVE_MEDIA_MISMATCH = 4303, + MD_ERROR_WIN_MEDIA_OFFLINE = 4304, + MD_ERROR_WIN_LIBRARY_OFFLINE = 4305, + MD_ERROR_WIN_EMPTY = 4306, + MD_ERROR_WIN_NOT_EMPTY = 4307, + MD_ERROR_WIN_MEDIA_UNAVAILABLE = 4308, + MD_ERROR_WIN_RESOURCE_DISABLED = 4309, + MD_ERROR_WIN_INVALID_CLEANER = 4310, + MD_ERROR_WIN_UNABLE_TO_CLEAN = 4311, + MD_ERROR_WIN_OBJECT_NOT_FOUND = 4312, + MD_ERROR_WIN_DATABASE_FAILURE = 4313, + MD_ERROR_WIN_DATABASE_FULL = 4314, + MD_ERROR_WIN_MEDIA_INCOMPATIBLE = 4315, + MD_ERROR_WIN_RESOURCE_NOT_PRESENT = 4316, + MD_ERROR_WIN_INVALID_OPERATION = 4317, + MD_ERROR_WIN_MEDIA_NOT_AVAILABLE = 4318, + MD_ERROR_WIN_DEVICE_NOT_AVAILABLE = 4319, + MD_ERROR_WIN_REQUEST_REFUSED = 4320, + MD_ERROR_WIN_INVALID_DRIVE_OBJECT = 4321, + MD_ERROR_WIN_LIBRARY_FULL = 4322, + MD_ERROR_WIN_MEDIUM_NOT_ACCESSIBLE = 4323, + MD_ERROR_WIN_UNABLE_TO_LOAD_MEDIUM = 4324, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_DRIVE = 4325, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_SLOT = 4326, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_TRANSPORT = 4327, + MD_ERROR_WIN_TRANSPORT_FULL = 4328, + MD_ERROR_WIN_CONTROLLING_IEPORT = 4329, + MD_ERROR_WIN_UNABLE_TO_EJECT_MOUNTED_MEDIA = 4330, + MD_ERROR_WIN_CLEANER_SLOT_SET = 4331, + MD_ERROR_WIN_CLEANER_SLOT_NOT_SET = 4332, + MD_ERROR_WIN_CLEANER_CARTRIDGE_SPENT = 4333, + MD_ERROR_WIN_UNEXPECTED_OMID = 4334, + MD_ERROR_WIN_CANT_DELETE_LAST_ITEM = 4335, + MD_ERROR_WIN_MESSAGE_EXCEEDS_MAX_SIZE = 4336, + MD_ERROR_WIN_VOLUME_CONTAINS_SYS_FILES = 4337, + MD_ERROR_WIN_INDIGENOUS_TYPE = 4338, + MD_ERROR_WIN_NO_SUPPORTING_DRIVES = 4339, + MD_ERROR_WIN_CLEANER_CARTRIDGE_INSTALLED = 4340, + MD_ERROR_WIN_IEPORT_FULL = 4341, + MD_ERROR_WIN_FILE_OFFLINE = 4350, + MD_ERROR_WIN_REMOTE_STORAGE_NOT_ACTIVE = 4351, + MD_ERROR_WIN_REMOTE_STORAGE_MEDIA_ERROR = 4352, + MD_ERROR_WIN_NOT_A_REPARSE_POINT = 4390, + MD_ERROR_WIN_REPARSE_ATTRIBUTE_CONFLICT = 4391, + MD_ERROR_WIN_INVALID_REPARSE_DATA = 4392, + MD_ERROR_WIN_REPARSE_TAG_INVALID = 4393, + MD_ERROR_WIN_REPARSE_TAG_MISMATCH = 4394, + MD_ERROR_WIN_REPARSE_POINT_ENCOUNTERED = 4395, + MD_ERROR_WIN_APP_DATA_NOT_FOUND = 4400, + MD_ERROR_WIN_APP_DATA_EXPIRED = 4401, + MD_ERROR_WIN_APP_DATA_CORRUPT = 4402, + MD_ERROR_WIN_APP_DATA_LIMIT_EXCEEDED = 4403, + MD_ERROR_WIN_APP_DATA_REBOOT_REQUIRED = 4404, + MD_ERROR_WIN_SECUREBOOT_ROLLBACK_DETECTED = 4420, + MD_ERROR_WIN_SECUREBOOT_POLICY_VIOLATION = 4421, + MD_ERROR_WIN_SECUREBOOT_INVALID_POLICY = 4422, + MD_ERROR_WIN_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 4423, + MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_SIGNED = 4424, + MD_ERROR_WIN_SECUREBOOT_NOT_ENABLED = 4425, + MD_ERROR_WIN_SECUREBOOT_FILE_REPLACED = 4426, + MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_AUTHORIZED = 4427, + MD_ERROR_WIN_SECUREBOOT_POLICY_UNKNOWN = 4428, + MD_ERROR_WIN_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION = 4429, + MD_ERROR_WIN_SECUREBOOT_PLATFORM_ID_MISMATCH = 4430, + MD_ERROR_WIN_SECUREBOOT_POLICY_ROLLBACK_DETECTED = 4431, + MD_ERROR_WIN_SECUREBOOT_POLICY_UPGRADE_MISMATCH = 4432, + MD_ERROR_WIN_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING = 4433, + MD_ERROR_WIN_SECUREBOOT_NOT_BASE_POLICY = 4434, + MD_ERROR_WIN_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY = 4435, + MD_ERROR_WIN_OFFLOAD_READ_FLT_NOT_SUPPORTED = 4440, + MD_ERROR_WIN_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 4441, + MD_ERROR_WIN_OFFLOAD_READ_FILE_NOT_SUPPORTED = 4442, + MD_ERROR_WIN_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 4443, + MD_ERROR_WIN_ALREADY_HAS_STREAM_ID = 4444, + MD_ERROR_WIN_SMR_GARBAGE_COLLECTION_REQUIRED = 4445, + MD_ERROR_WIN_WOF_WIM_HEADER_CORRUPT = 4446, + MD_ERROR_WIN_WOF_WIM_RESOURCE_TABLE_CORRUPT = 4447, + MD_ERROR_WIN_WOF_FILE_RESOURCE_TABLE_CORRUPT = 4448, + MD_ERROR_WIN_VOLUME_NOT_SIS_ENABLED = 4500, + MD_ERROR_WIN_SYSTEM_INTEGRITY_ROLLBACK_DETECTED = 4550, + MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_VIOLATION = 4551, + MD_ERROR_WIN_SYSTEM_INTEGRITY_INVALID_POLICY = 4552, + MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED = 4553, + MD_ERROR_WIN_SYSTEM_INTEGRITY_TOO_MANY_POLICIES = 4554, + MD_ERROR_WIN_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED = 4555, + MD_ERROR_WIN_VSM_NOT_INITIALIZED = 4560, + MD_ERROR_WIN_VSM_DMA_PROTECTION_NOT_IN_USE = 4561, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_AUTHORIZED = 4570, + MD_ERROR_WIN_PLATFORM_MANIFEST_INVALID = 4571, + MD_ERROR_WIN_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED = 4572, + MD_ERROR_WIN_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED = 4573, + MD_ERROR_WIN_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND = 4574, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_ACTIVE = 4575, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_SIGNED = 4576, + MD_ERROR_WIN_DEPENDENT_RESOURCE_EXISTS = 5001, + MD_ERROR_WIN_DEPENDENCY_NOT_FOUND = 5002, + MD_ERROR_WIN_DEPENDENCY_ALREADY_EXISTS = 5003, + MD_ERROR_WIN_RESOURCE_NOT_ONLINE = 5004, + MD_ERROR_WIN_HOST_NODE_NOT_AVAILABLE = 5005, + MD_ERROR_WIN_RESOURCE_NOT_AVAILABLE = 5006, + MD_ERROR_WIN_RESOURCE_NOT_FOUND = 5007, + MD_ERROR_WIN_SHUTDOWN_CLUSTER = 5008, + MD_ERROR_WIN_CANT_EVICT_ACTIVE_NODE = 5009, + MD_ERROR_WIN_OBJECT_ALREADY_EXISTS = 5010, + MD_ERROR_WIN_OBJECT_IN_LIST = 5011, + MD_ERROR_WIN_GROUP_NOT_AVAILABLE = 5012, + MD_ERROR_WIN_GROUP_NOT_FOUND = 5013, + MD_ERROR_WIN_GROUP_NOT_ONLINE = 5014, + MD_ERROR_WIN_HOST_NODE_NOT_RESOURCE_OWNER = 5015, + MD_ERROR_WIN_HOST_NODE_NOT_GROUP_OWNER = 5016, + MD_ERROR_WIN_RESMON_CREATE_FAILED = 5017, + MD_ERROR_WIN_RESMON_ONLINE_FAILED = 5018, + MD_ERROR_WIN_RESOURCE_ONLINE = 5019, + MD_ERROR_WIN_QUORUM_RESOURCE = 5020, + MD_ERROR_WIN_NOT_QUORUM_CAPABLE = 5021, + MD_ERROR_WIN_CLUSTER_SHUTTING_DOWN = 5022, + MD_ERROR_WIN_INVALID_STATE = 5023, + MD_ERROR_WIN_RESOURCE_PROPERTIES_STORED = 5024, + MD_ERROR_WIN_NOT_QUORUM_CLASS = 5025, + MD_ERROR_WIN_CORE_RESOURCE = 5026, + MD_ERROR_WIN_QUORUM_RESOURCE_ONLINE_FAILED = 5027, + MD_ERROR_WIN_QUORUMLOG_OPEN_FAILED = 5028, + MD_ERROR_WIN_CLUSTERLOG_CORRUPT = 5029, + MD_ERROR_WIN_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE = 5030, + MD_ERROR_WIN_CLUSTERLOG_EXCEEDS_MAXSIZE = 5031, + MD_ERROR_WIN_CLUSTERLOG_CHKPOINT_NOT_FOUND = 5032, + MD_ERROR_WIN_CLUSTERLOG_NOT_ENOUGH_SPACE = 5033, + MD_ERROR_WIN_QUORUM_OWNER_ALIVE = 5034, + MD_ERROR_WIN_NETWORK_NOT_AVAILABLE = 5035, + MD_ERROR_WIN_NODE_NOT_AVAILABLE = 5036, + MD_ERROR_WIN_ALL_NODES_NOT_AVAILABLE = 5037, + MD_ERROR_WIN_RESOURCE_FAILED = 5038, + MD_ERROR_WIN_CLUSTER_INVALID_NODE = 5039, + MD_ERROR_WIN_CLUSTER_NODE_EXISTS = 5040, + MD_ERROR_WIN_CLUSTER_JOIN_IN_PROGRESS = 5041, + MD_ERROR_WIN_CLUSTER_NODE_NOT_FOUND = 5042, + MD_ERROR_WIN_CLUSTER_LOCAL_NODE_NOT_FOUND = 5043, + MD_ERROR_WIN_CLUSTER_NETWORK_EXISTS = 5044, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND = 5045, + MD_ERROR_WIN_CLUSTER_NETINTERFACE_EXISTS = 5046, + MD_ERROR_WIN_CLUSTER_NETINTERFACE_NOT_FOUND = 5047, + MD_ERROR_WIN_CLUSTER_INVALID_REQUEST = 5048, + MD_ERROR_WIN_CLUSTER_INVALID_NETWORK_PROVIDER = 5049, + MD_ERROR_WIN_CLUSTER_NODE_DOWN = 5050, + MD_ERROR_WIN_CLUSTER_NODE_UNREACHABLE = 5051, + MD_ERROR_WIN_CLUSTER_NODE_NOT_MEMBER = 5052, + MD_ERROR_WIN_CLUSTER_JOIN_NOT_IN_PROGRESS = 5053, + MD_ERROR_WIN_CLUSTER_INVALID_NETWORK = 5054, + MD_ERROR_WIN_CLUSTER_NODE_UP = 5056, + MD_ERROR_WIN_CLUSTER_IPADDR_IN_USE = 5057, + MD_ERROR_WIN_CLUSTER_NODE_NOT_PAUSED = 5058, + MD_ERROR_WIN_CLUSTER_NO_SECURITY_CONTEXT = 5059, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_INTERNAL = 5060, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_UP = 5061, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_DOWN = 5062, + MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_ONLINE = 5063, + MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_OFFLINE = 5064, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_MEMBER = 5065, + MD_ERROR_WIN_CLUSTER_LAST_INTERNAL_NETWORK = 5066, + MD_ERROR_WIN_CLUSTER_NETWORK_HAS_DEPENDENTS = 5067, + MD_ERROR_WIN_INVALID_OPERATION_ON_QUORUM = 5068, + MD_ERROR_WIN_DEPENDENCY_NOT_ALLOWED = 5069, + MD_ERROR_WIN_CLUSTER_NODE_PAUSED = 5070, + MD_ERROR_WIN_NODE_CANT_HOST_RESOURCE = 5071, + MD_ERROR_WIN_CLUSTER_NODE_NOT_READY = 5072, + MD_ERROR_WIN_CLUSTER_NODE_SHUTTING_DOWN = 5073, + MD_ERROR_WIN_CLUSTER_JOIN_ABORTED = 5074, + MD_ERROR_WIN_CLUSTER_INCOMPATIBLE_VERSIONS = 5075, + MD_ERROR_WIN_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED = 5076, + MD_ERROR_WIN_CLUSTER_SYSTEM_CONFIG_CHANGED = 5077, + MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_NOT_FOUND = 5078, + MD_ERROR_WIN_CLUSTER_RESTYPE_NOT_SUPPORTED = 5079, + MD_ERROR_WIN_CLUSTER_RESNAME_NOT_FOUND = 5080, + MD_ERROR_WIN_CLUSTER_NO_RPC_PACKAGES_REGISTERED = 5081, + MD_ERROR_WIN_CLUSTER_OWNER_NOT_IN_PREFLIST = 5082, + MD_ERROR_WIN_CLUSTER_DATABASE_SEQMISMATCH = 5083, + MD_ERROR_WIN_RESMON_INVALID_STATE = 5084, + MD_ERROR_WIN_CLUSTER_GUM_NOT_LOCKER = 5085, + MD_ERROR_WIN_QUORUM_DISK_NOT_FOUND = 5086, + MD_ERROR_WIN_DATABASE_BACKUP_CORRUPT = 5087, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT = 5088, + MD_ERROR_WIN_RESOURCE_PROPERTY_UNCHANGEABLE = 5089, + MD_ERROR_WIN_NO_ADMIN_ACCESS_POINT = 5090, + MD_ERROR_WIN_CLUSTER_MEMBERSHIP_INVALID_STATE = 5890, + MD_ERROR_WIN_CLUSTER_QUORUMLOG_NOT_FOUND = 5891, + MD_ERROR_WIN_CLUSTER_MEMBERSHIP_HALT = 5892, + MD_ERROR_WIN_CLUSTER_INSTANCE_ID_MISMATCH = 5893, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND_FOR_IP = 5894, + MD_ERROR_WIN_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH = 5895, + MD_ERROR_WIN_CLUSTER_EVICT_WITHOUT_CLEANUP = 5896, + MD_ERROR_WIN_CLUSTER_PARAMETER_MISMATCH = 5897, + MD_ERROR_WIN_NODE_CANNOT_BE_CLUSTERED = 5898, + MD_ERROR_WIN_CLUSTER_WRONG_OS_VERSION = 5899, + MD_ERROR_WIN_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME = 5900, + MD_ERROR_WIN_CLUSCFG_ALREADY_COMMITTED = 5901, + MD_ERROR_WIN_CLUSCFG_ROLLBACK_FAILED = 5902, + MD_ERROR_WIN_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT = 5903, + MD_ERROR_WIN_CLUSTER_OLD_VERSION = 5904, + MD_ERROR_WIN_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME = 5905, + MD_ERROR_WIN_CLUSTER_NO_NET_ADAPTERS = 5906, + MD_ERROR_WIN_CLUSTER_POISONED = 5907, + MD_ERROR_WIN_CLUSTER_GROUP_MOVING = 5908, + MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_BUSY = 5909, + MD_ERROR_WIN_RESOURCE_CALL_TIMED_OUT = 5910, + MD_ERROR_WIN_INVALID_CLUSTER_IPV6_ADDRESS = 5911, + MD_ERROR_WIN_CLUSTER_INTERNAL_INVALID_FUNCTION = 5912, + MD_ERROR_WIN_CLUSTER_PARAMETER_OUT_OF_BOUNDS = 5913, + MD_ERROR_WIN_CLUSTER_PARTIAL_SEND = 5914, + MD_ERROR_WIN_CLUSTER_REGISTRY_INVALID_FUNCTION = 5915, + MD_ERROR_WIN_CLUSTER_INVALID_STRING_TERMINATION = 5916, + MD_ERROR_WIN_CLUSTER_INVALID_STRING_FORMAT = 5917, + MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS = 5918, + MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS = 5919, + MD_ERROR_WIN_CLUSTER_NULL_DATA = 5920, + MD_ERROR_WIN_CLUSTER_PARTIAL_READ = 5921, + MD_ERROR_WIN_CLUSTER_PARTIAL_WRITE = 5922, + MD_ERROR_WIN_CLUSTER_CANT_DESERIALIZE_DATA = 5923, + MD_ERROR_WIN_DEPENDENT_RESOURCE_PROPERTY_CONFLICT = 5924, + MD_ERROR_WIN_CLUSTER_NO_QUORUM = 5925, + MD_ERROR_WIN_CLUSTER_INVALID_IPV6_NETWORK = 5926, + MD_ERROR_WIN_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK = 5927, + MD_ERROR_WIN_QUORUM_NOT_ALLOWED_IN_THIS_GROUP = 5928, + MD_ERROR_WIN_DEPENDENCY_TREE_TOO_COMPLEX = 5929, + MD_ERROR_WIN_EXCEPTION_IN_RESOURCE_CALL = 5930, + MD_ERROR_WIN_CLUSTER_RHS_FAILED_INITIALIZATION = 5931, + MD_ERROR_WIN_CLUSTER_NOT_INSTALLED = 5932, + MD_ERROR_WIN_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE = 5933, + MD_ERROR_WIN_CLUSTER_MAX_NODES_IN_CLUSTER = 5934, + MD_ERROR_WIN_CLUSTER_TOO_MANY_NODES = 5935, + MD_ERROR_WIN_CLUSTER_OBJECT_ALREADY_USED = 5936, + MD_ERROR_WIN_NONCORE_GROUPS_FOUND = 5937, + MD_ERROR_WIN_FILE_SHARE_RESOURCE_CONFLICT = 5938, + MD_ERROR_WIN_CLUSTER_EVICT_INVALID_REQUEST = 5939, + MD_ERROR_WIN_CLUSTER_SINGLETON_RESOURCE = 5940, + MD_ERROR_WIN_CLUSTER_GROUP_SINGLETON_RESOURCE = 5941, + MD_ERROR_WIN_CLUSTER_RESOURCE_PROVIDER_FAILED = 5942, + MD_ERROR_WIN_CLUSTER_RESOURCE_CONFIGURATION_ERROR = 5943, + MD_ERROR_WIN_CLUSTER_GROUP_BUSY = 5944, + MD_ERROR_WIN_CLUSTER_NOT_SHARED_VOLUME = 5945, + MD_ERROR_WIN_CLUSTER_INVALID_SECURITY_DESCRIPTOR = 5946, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUMES_IN_USE = 5947, + MD_ERROR_WIN_CLUSTER_USE_SHARED_VOLUMES_API = 5948, + MD_ERROR_WIN_CLUSTER_BACKUP_IN_PROGRESS = 5949, + MD_ERROR_WIN_NON_CSV_PATH = 5950, + MD_ERROR_WIN_CSV_VOLUME_NOT_LOCAL = 5951, + MD_ERROR_WIN_CLUSTER_WATCHDOG_TERMINATING = 5952, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES = 5953, + MD_ERROR_WIN_CLUSTER_INVALID_NODE_WEIGHT = 5954, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_CALL = 5955, + MD_ERROR_WIN_RESMON_SYSTEM_RESOURCES_LACKING = 5956, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION = 5957, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE = 5958, + MD_ERROR_WIN_CLUSTER_GROUP_QUEUED = 5959, + MD_ERROR_WIN_CLUSTER_RESOURCE_LOCKED_STATUS = 5960, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED = 5961, + MD_ERROR_WIN_CLUSTER_NODE_DRAIN_IN_PROGRESS = 5962, + MD_ERROR_WIN_CLUSTER_DISK_NOT_CONNECTED = 5963, + MD_ERROR_WIN_DISK_NOT_CSV_CAPABLE = 5964, + MD_ERROR_WIN_RESOURCE_NOT_IN_AVAILABLE_STORAGE = 5965, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_REDIRECTED = 5966, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED = 5967, + MD_ERROR_WIN_CLUSTER_CANNOT_RETURN_PROPERTIES = 5968, + MD_ERROR_WIN_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES = 5969, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE = 5970, + MD_ERROR_WIN_CLUSTER_AFFINITY_CONFLICT = 5971, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE = 5972, + MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS = 5973, + MD_ERROR_WIN_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED = 5974, + MD_ERROR_WIN_CLUSTER_UPGRADE_RESTART_REQUIRED = 5975, + MD_ERROR_WIN_CLUSTER_UPGRADE_IN_PROGRESS = 5976, + MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPLETE = 5977, + MD_ERROR_WIN_CLUSTER_NODE_IN_GRACE_PERIOD = 5978, + MD_ERROR_WIN_CLUSTER_CSV_IO_PAUSE_TIMEOUT = 5979, + MD_ERROR_WIN_NODE_NOT_ACTIVE_CLUSTER_MEMBER = 5980, + MD_ERROR_WIN_CLUSTER_RESOURCE_NOT_MONITORED = 5981, + MD_ERROR_WIN_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED = 5982, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICATED = 5983, + MD_ERROR_WIN_CLUSTER_NODE_ISOLATED = 5984, + MD_ERROR_WIN_CLUSTER_NODE_QUARANTINED = 5985, + MD_ERROR_WIN_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED = 5986, + MD_ERROR_WIN_CLUSTER_SPACE_DEGRADED = 5987, + MD_ERROR_WIN_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED = 5988, + MD_ERROR_WIN_CLUSTER_CSV_INVALID_HANDLE = 5989, + MD_ERROR_WIN_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR = 5990, + MD_ERROR_WIN_GROUPSET_NOT_AVAILABLE = 5991, + MD_ERROR_WIN_GROUPSET_NOT_FOUND = 5992, + MD_ERROR_WIN_GROUPSET_CANT_PROVIDE = 5993, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND = 5994, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY = 5995, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION = 5996, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS = 5997, + MD_ERROR_WIN_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME = 5998, + MD_ERROR_WIN_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE = 5999, + MD_ERROR_WIN_ENCRYPTION_FAILED = 6000, + MD_ERROR_WIN_DECRYPTION_FAILED = 6001, + MD_ERROR_WIN_FILE_ENCRYPTED = 6002, + MD_ERROR_WIN_NO_RECOVERY_POLICY = 6003, + MD_ERROR_WIN_NO_EFS = 6004, + MD_ERROR_WIN_WRONG_EFS = 6005, + MD_ERROR_WIN_NO_USER_KEYS = 6006, + MD_ERROR_WIN_FILE_NOT_ENCRYPTED = 6007, + MD_ERROR_WIN_NOT_EXPORT_FORMAT = 6008, + MD_ERROR_WIN_FILE_READ_ONLY = 6009, + MD_ERROR_WIN_DIR_EFS_DISALLOWED = 6010, + MD_ERROR_WIN_EFS_SERVER_NOT_TRUSTED = 6011, + MD_ERROR_WIN_BAD_RECOVERY_POLICY = 6012, + MD_ERROR_WIN_EFS_ALG_BLOB_TOO_BIG = 6013, + MD_ERROR_WIN_VOLUME_NOT_SUPPORT_EFS = 6014, + MD_ERROR_WIN_EFS_DISABLED = 6015, + MD_ERROR_WIN_EFS_VERSION_NOT_SUPPORT = 6016, + MD_ERROR_WIN_CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 6017, + MD_ERROR_WIN_CS_ENCRYPTION_UNSUPPORTED_SERVER = 6018, + MD_ERROR_WIN_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 6019, + MD_ERROR_WIN_CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 6020, + MD_ERROR_WIN_CS_ENCRYPTION_FILE_NOT_CSE = 6021, + MD_ERROR_WIN_ENCRYPTION_POLICY_DENIES_OPERATION = 6022, + MD_ERROR_WIN_WIP_ENCRYPTION_FAILED = 6023, + MD_ERROR_WIN_NO_BROWSER_SERVERS_FOUND = 6118, + MD_ERROR_WIN_CLUSTER_OBJECT_IS_CLUSTER_SET_VM = 6250, + MD_ERROR_WIN_LOG_SECTOR_INVALID = 6600, + MD_ERROR_WIN_LOG_SECTOR_PARITY_INVALID = 6601, + MD_ERROR_WIN_LOG_SECTOR_REMAPPED = 6602, + MD_ERROR_WIN_LOG_BLOCK_INCOMPLETE = 6603, + MD_ERROR_WIN_LOG_INVALID_RANGE = 6604, + MD_ERROR_WIN_LOG_BLOCKS_EXHAUSTED = 6605, + MD_ERROR_WIN_LOG_READ_CONTEXT_INVALID = 6606, + MD_ERROR_WIN_LOG_RESTART_INVALID = 6607, + MD_ERROR_WIN_LOG_BLOCK_VERSION = 6608, + MD_ERROR_WIN_LOG_BLOCK_INVALID = 6609, + MD_ERROR_WIN_LOG_READ_MODE_INVALID = 6610, + MD_ERROR_WIN_LOG_NO_RESTART = 6611, + MD_ERROR_WIN_LOG_METADATA_CORRUPT = 6612, + MD_ERROR_WIN_LOG_METADATA_INVALID = 6613, + MD_ERROR_WIN_LOG_METADATA_INCONSISTENT = 6614, + MD_ERROR_WIN_LOG_RESERVATION_INVALID = 6615, + MD_ERROR_WIN_LOG_CANT_DELETE = 6616, + MD_ERROR_WIN_LOG_CONTAINER_LIMIT_EXCEEDED = 6617, + MD_ERROR_WIN_LOG_START_OF_LOG = 6618, + MD_ERROR_WIN_LOG_POLICY_ALREADY_INSTALLED = 6619, + MD_ERROR_WIN_LOG_POLICY_NOT_INSTALLED = 6620, + MD_ERROR_WIN_LOG_POLICY_INVALID = 6621, + MD_ERROR_WIN_LOG_POLICY_CONFLICT = 6622, + MD_ERROR_WIN_LOG_PINNED_ARCHIVE_TAIL = 6623, + MD_ERROR_WIN_LOG_RECORD_NONEXISTENT = 6624, + MD_ERROR_WIN_LOG_RECORDS_RESERVED_INVALID = 6625, + MD_ERROR_WIN_LOG_SPACE_RESERVED_INVALID = 6626, + MD_ERROR_WIN_LOG_TAIL_INVALID = 6627, + MD_ERROR_WIN_LOG_FULL = 6628, + MD_ERROR_WIN_COULD_NOT_RESIZE_LOG = 6629, + MD_ERROR_WIN_LOG_MULTIPLEXED = 6630, + MD_ERROR_WIN_LOG_DEDICATED = 6631, + MD_ERROR_WIN_LOG_ARCHIVE_NOT_IN_PROGRESS = 6632, + MD_ERROR_WIN_LOG_ARCHIVE_IN_PROGRESS = 6633, + MD_ERROR_WIN_LOG_EPHEMERAL = 6634, + MD_ERROR_WIN_LOG_NOT_ENOUGH_CONTAINERS = 6635, + MD_ERROR_WIN_LOG_CLIENT_ALREADY_REGISTERED = 6636, + MD_ERROR_WIN_LOG_CLIENT_NOT_REGISTERED = 6637, + MD_ERROR_WIN_LOG_FULL_HANDLER_IN_PROGRESS = 6638, + MD_ERROR_WIN_LOG_CONTAINER_READ_FAILED = 6639, + MD_ERROR_WIN_LOG_CONTAINER_WRITE_FAILED = 6640, + MD_ERROR_WIN_LOG_CONTAINER_OPEN_FAILED = 6641, + MD_ERROR_WIN_LOG_CONTAINER_STATE_INVALID = 6642, + MD_ERROR_WIN_LOG_STATE_INVALID = 6643, + MD_ERROR_WIN_LOG_PINNED = 6644, + MD_ERROR_WIN_LOG_METADATA_FLUSH_FAILED = 6645, + MD_ERROR_WIN_LOG_INCONSISTENT_SECURITY = 6646, + MD_ERROR_WIN_LOG_APPENDED_FLUSH_FAILED = 6647, + MD_ERROR_WIN_LOG_PINNED_RESERVATION = 6648, + MD_ERROR_WIN_INVALID_TRANSACTION = 6700, + MD_ERROR_WIN_TRANSACTION_NOT_ACTIVE = 6701, + MD_ERROR_WIN_TRANSACTION_REQUEST_NOT_VALID = 6702, + MD_ERROR_WIN_TRANSACTION_NOT_REQUESTED = 6703, + MD_ERROR_WIN_TRANSACTION_ALREADY_ABORTED = 6704, + MD_ERROR_WIN_TRANSACTION_ALREADY_COMMITTED = 6705, + MD_ERROR_WIN_TM_INITIALIZATION_FAILED = 6706, + MD_ERROR_WIN_RESOURCEMANAGER_READ_ONLY = 6707, + MD_ERROR_WIN_TRANSACTION_NOT_JOINED = 6708, + MD_ERROR_WIN_TRANSACTION_SUPERIOR_EXISTS = 6709, + MD_ERROR_WIN_CRM_PROTOCOL_ALREADY_EXISTS = 6710, + MD_ERROR_WIN_TRANSACTION_PROPAGATION_FAILED = 6711, + MD_ERROR_WIN_CRM_PROTOCOL_NOT_FOUND = 6712, + MD_ERROR_WIN_TRANSACTION_INVALID_MARSHALL_BUFFER = 6713, + MD_ERROR_WIN_CURRENT_TRANSACTION_NOT_VALID = 6714, + MD_ERROR_WIN_TRANSACTION_NOT_FOUND = 6715, + MD_ERROR_WIN_RESOURCEMANAGER_NOT_FOUND = 6716, + MD_ERROR_WIN_ENLISTMENT_NOT_FOUND = 6717, + MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_FOUND = 6718, + MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_ONLINE = 6719, + MD_ERROR_WIN_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 6720, + MD_ERROR_WIN_TRANSACTION_NOT_ROOT = 6721, + MD_ERROR_WIN_TRANSACTION_OBJECT_EXPIRED = 6722, + MD_ERROR_WIN_TRANSACTION_RESPONSE_NOT_ENLISTED = 6723, + MD_ERROR_WIN_TRANSACTION_RECORD_TOO_LONG = 6724, + MD_ERROR_WIN_IMPLICIT_TRANSACTION_NOT_SUPPORTED = 6725, + MD_ERROR_WIN_TRANSACTION_INTEGRITY_VIOLATED = 6726, + MD_ERROR_WIN_TRANSACTIONMANAGER_IDENTITY_MISMATCH = 6727, + MD_ERROR_WIN_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT = 6728, + MD_ERROR_WIN_TRANSACTION_MUST_WRITETHROUGH = 6729, + MD_ERROR_WIN_TRANSACTION_NO_SUPERIOR = 6730, + MD_ERROR_WIN_HEURISTIC_DAMAGE_POSSIBLE = 6731, + MD_ERROR_WIN_TRANSACTIONAL_CONFLICT = 6800, + MD_ERROR_WIN_RM_NOT_ACTIVE = 6801, + MD_ERROR_WIN_RM_METADATA_CORRUPT = 6802, + MD_ERROR_WIN_DIRECTORY_NOT_RM = 6803, + MD_ERROR_WIN_TRANSACTIONS_UNSUPPORTED_REMOTE = 6805, + MD_ERROR_WIN_LOG_RESIZE_INVALID_SIZE = 6806, + MD_ERROR_WIN_OBJECT_NO_LONGER_EXISTS = 6807, + MD_ERROR_WIN_STREAM_MINIVERSION_NOT_FOUND = 6808, + MD_ERROR_WIN_STREAM_MINIVERSION_NOT_VALID = 6809, + MD_ERROR_WIN_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 6810, + MD_ERROR_WIN_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 6811, + MD_ERROR_WIN_CANT_CREATE_MORE_STREAM_MINIVERSIONS = 6812, + MD_ERROR_WIN_REMOTE_FILE_VERSION_MISMATCH = 6814, + MD_ERROR_WIN_HANDLE_NO_LONGER_VALID = 6815, + MD_ERROR_WIN_NO_TXF_METADATA = 6816, + MD_ERROR_WIN_LOG_CORRUPTION_DETECTED = 6817, + MD_ERROR_WIN_CANT_RECOVER_WITH_HANDLE_OPEN = 6818, + MD_ERROR_WIN_RM_DISCONNECTED = 6819, + MD_ERROR_WIN_ENLISTMENT_NOT_SUPERIOR = 6820, + MD_ERROR_WIN_RECOVERY_NOT_NEEDED = 6821, + MD_ERROR_WIN_RM_ALREADY_STARTED = 6822, + MD_ERROR_WIN_FILE_IDENTITY_NOT_PERSISTENT = 6823, + MD_ERROR_WIN_CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 6824, + MD_ERROR_WIN_CANT_CROSS_RM_BOUNDARY = 6825, + MD_ERROR_WIN_TXF_DIR_NOT_EMPTY = 6826, + MD_ERROR_WIN_INDOUBT_TRANSACTIONS_EXIST = 6827, + MD_ERROR_WIN_TM_VOLATILE = 6828, + MD_ERROR_WIN_ROLLBACK_TIMER_EXPIRED = 6829, + MD_ERROR_WIN_TXF_ATTRIBUTE_CORRUPT = 6830, + MD_ERROR_WIN_EFS_NOT_ALLOWED_IN_TRANSACTION = 6831, + MD_ERROR_WIN_TRANSACTIONAL_OPEN_NOT_ALLOWED = 6832, + MD_ERROR_WIN_LOG_GROWTH_FAILED = 6833, + MD_ERROR_WIN_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 6834, + MD_ERROR_WIN_TXF_METADATA_ALREADY_PRESENT = 6835, + MD_ERROR_WIN_TRANSACTION_SCOPE_CALLBACKS_NOT_SET = 6836, + MD_ERROR_WIN_TRANSACTION_REQUIRED_PROMOTION = 6837, + MD_ERROR_WIN_CANNOT_EXECUTE_FILE_IN_TRANSACTION = 6838, + MD_ERROR_WIN_TRANSACTIONS_NOT_FROZEN = 6839, + MD_ERROR_WIN_TRANSACTION_FREEZE_IN_PROGRESS = 6840, + MD_ERROR_WIN_NOT_SNAPSHOT_VOLUME = 6841, + MD_ERROR_WIN_NO_SAVEPOINT_WITH_OPEN_FILES = 6842, + MD_ERROR_WIN_DATA_LOST_REPAIR = 6843, + MD_ERROR_WIN_SPARSE_NOT_ALLOWED_IN_TRANSACTION = 6844, + MD_ERROR_WIN_TM_IDENTITY_MISMATCH = 6845, + MD_ERROR_WIN_FLOATED_SECTION = 6846, + MD_ERROR_WIN_CANNOT_ACCEPT_TRANSACTED_WORK = 6847, + MD_ERROR_WIN_CANNOT_ABORT_TRANSACTIONS = 6848, + MD_ERROR_WIN_BAD_CLUSTERS = 6849, + MD_ERROR_WIN_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 6850, + MD_ERROR_WIN_VOLUME_DIRTY = 6851, + MD_ERROR_WIN_NO_LINK_TRACKING_IN_TRANSACTION = 6852, + MD_ERROR_WIN_OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 6853, + MD_ERROR_WIN_EXPIRED_HANDLE = 6854, + MD_ERROR_WIN_TRANSACTION_NOT_ENLISTED = 6855, + MD_ERROR_WIN_CTX_WINSTATION_NAME_INVALID = 7001, + MD_ERROR_WIN_CTX_INVALID_PD = 7002, + MD_ERROR_WIN_CTX_PD_NOT_FOUND = 7003, + MD_ERROR_WIN_CTX_WD_NOT_FOUND = 7004, + MD_ERROR_WIN_CTX_CANNOT_MAKE_EVENTLOG_ENTRY = 7005, + MD_ERROR_WIN_CTX_SERVICE_NAME_COLLISION = 7006, + MD_ERROR_WIN_CTX_CLOSE_PENDING = 7007, + MD_ERROR_WIN_CTX_NO_OUTBUF = 7008, + MD_ERROR_WIN_CTX_MODEM_INF_NOT_FOUND = 7009, + MD_ERROR_WIN_CTX_INVALID_MODEMNAME = 7010, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_ERROR = 7011, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_TIMEOUT = 7012, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_CARRIER = 7013, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_DIALTONE = 7014, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_BUSY = 7015, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_VOICE = 7016, + MD_ERROR_WIN_CTX_TD_ERROR = 7017, + MD_ERROR_WIN_CTX_WINSTATION_NOT_FOUND = 7022, + MD_ERROR_WIN_CTX_WINSTATION_ALREADY_EXISTS = 7023, + MD_ERROR_WIN_CTX_WINSTATION_BUSY = 7024, + MD_ERROR_WIN_CTX_BAD_VIDEO_MODE = 7025, + MD_ERROR_WIN_CTX_GRAPHICS_INVALID = 7035, + MD_ERROR_WIN_CTX_LOGON_DISABLED = 7037, + MD_ERROR_WIN_CTX_NOT_CONSOLE = 7038, + MD_ERROR_WIN_CTX_CLIENT_QUERY_TIMEOUT = 7040, + MD_ERROR_WIN_CTX_CONSOLE_DISCONNECT = 7041, + MD_ERROR_WIN_CTX_CONSOLE_CONNECT = 7042, + MD_ERROR_WIN_CTX_SHADOW_DENIED = 7044, + MD_ERROR_WIN_CTX_WINSTATION_ACCESS_DENIED = 7045, + MD_ERROR_WIN_CTX_INVALID_WD = 7049, + MD_ERROR_WIN_CTX_SHADOW_INVALID = 7050, + MD_ERROR_WIN_CTX_SHADOW_DISABLED = 7051, + MD_ERROR_WIN_CTX_CLIENT_LICENSE_IN_USE = 7052, + MD_ERROR_WIN_CTX_CLIENT_LICENSE_NOT_SET = 7053, + MD_ERROR_WIN_CTX_LICENSE_NOT_AVAILABLE = 7054, + MD_ERROR_WIN_CTX_LICENSE_CLIENT_INVALID = 7055, + MD_ERROR_WIN_CTX_LICENSE_EXPIRED = 7056, + MD_ERROR_WIN_CTX_SHADOW_NOT_RUNNING = 7057, + MD_ERROR_WIN_CTX_SHADOW_ENDED_BY_MODE_CHANGE = 7058, + MD_ERROR_WIN_ACTIVATION_COUNT_EXCEEDED = 7059, + MD_ERROR_WIN_CTX_WINSTATIONS_DISABLED = 7060, + MD_ERROR_WIN_CTX_ENCRYPTION_LEVEL_REQUIRED = 7061, + MD_ERROR_WIN_CTX_SESSION_IN_USE = 7062, + MD_ERROR_WIN_CTX_NO_FORCE_LOGOFF = 7063, + MD_ERROR_WIN_CTX_ACCOUNT_RESTRICTION = 7064, + MD_ERROR_WIN_RDP_PROTOCOL_ERROR = 7065, + MD_ERROR_WIN_CTX_CDM_CONNECT = 7066, + MD_ERROR_WIN_CTX_CDM_DISCONNECT = 7067, + MD_ERROR_WIN_CTX_SECURITY_LAYER_ERROR = 7068, + MD_ERROR_WIN_TS_INCOMPATIBLE_SESSIONS = 7069, + MD_ERROR_WIN_TS_VIDEO_SUBSYSTEM_ERROR = 7070, + MD_ERROR_WIN_DS_NOT_INSTALLED = 8200, + MD_ERROR_WIN_DS_MEMBERSHIP_EVALUATED_LOCALLY = 8201, + MD_ERROR_WIN_DS_NO_ATTRIBUTE_OR_VALUE = 8202, + MD_ERROR_WIN_DS_INVALID_ATTRIBUTE_SYNTAX = 8203, + MD_ERROR_WIN_DS_ATTRIBUTE_TYPE_UNDEFINED = 8204, + MD_ERROR_WIN_DS_ATTRIBUTE_OR_VALUE_EXISTS = 8205, + MD_ERROR_WIN_DS_BUSY = 8206, + MD_ERROR_WIN_DS_UNAVAILABLE = 8207, + MD_ERROR_WIN_DS_NO_RIDS_ALLOCATED = 8208, + MD_ERROR_WIN_DS_NO_MORE_RIDS = 8209, + MD_ERROR_WIN_DS_INCORRECT_ROLE_OWNER = 8210, + MD_ERROR_WIN_DS_RIDMGR_INIT_ERROR = 8211, + MD_ERROR_WIN_DS_OBJ_CLASS_VIOLATION = 8212, + MD_ERROR_WIN_DS_CANT_ON_NON_LEAF = 8213, + MD_ERROR_WIN_DS_CANT_ON_RDN = 8214, + MD_ERROR_WIN_DS_CANT_MOD_OBJ_CLASS = 8215, + MD_ERROR_WIN_DS_CROSS_DOM_MOVE_ERROR = 8216, + MD_ERROR_WIN_DS_GC_NOT_AVAILABLE = 8217, + MD_ERROR_WIN_SHARED_POLICY = 8218, + MD_ERROR_WIN_POLICY_OBJECT_NOT_FOUND = 8219, + MD_ERROR_WIN_POLICY_ONLY_IN_DS = 8220, + MD_ERROR_WIN_PROMOTION_ACTIVE = 8221, + MD_ERROR_WIN_NO_PROMOTION_ACTIVE = 8222, + MD_ERROR_WIN_DS_OPERATIONS_ERROR = 8224, + MD_ERROR_WIN_DS_PROTOCOL_ERROR = 8225, + MD_ERROR_WIN_DS_TIMELIMIT_EXCEEDED = 8226, + MD_ERROR_WIN_DS_SIZELIMIT_EXCEEDED = 8227, + MD_ERROR_WIN_DS_ADMIN_LIMIT_EXCEEDED = 8228, + MD_ERROR_WIN_DS_COMPARE_FALSE = 8229, + MD_ERROR_WIN_DS_COMPARE_TRUE = 8230, + MD_ERROR_WIN_DS_AUTH_METHOD_NOT_SUPPORTED = 8231, + MD_ERROR_WIN_DS_STRONG_AUTH_REQUIRED = 8232, + MD_ERROR_WIN_DS_INAPPROPRIATE_AUTH = 8233, + MD_ERROR_WIN_DS_AUTH_UNKNOWN = 8234, + MD_ERROR_WIN_DS_REFERRAL = 8235, + MD_ERROR_WIN_DS_UNAVAILABLE_CRIT_EXTENSION = 8236, + MD_ERROR_WIN_DS_CONFIDENTIALITY_REQUIRED = 8237, + MD_ERROR_WIN_DS_INAPPROPRIATE_MATCHING = 8238, + MD_ERROR_WIN_DS_CONSTRAINT_VIOLATION = 8239, + MD_ERROR_WIN_DS_NO_SUCH_OBJECT = 8240, + MD_ERROR_WIN_DS_ALIAS_PROBLEM = 8241, + MD_ERROR_WIN_DS_INVALID_DN_SYNTAX = 8242, + MD_ERROR_WIN_DS_IS_LEAF = 8243, + MD_ERROR_WIN_DS_ALIAS_DEREF_PROBLEM = 8244, + MD_ERROR_WIN_DS_UNWILLING_TO_PERFORM = 8245, + MD_ERROR_WIN_DS_LOOP_DETECT = 8246, + MD_ERROR_WIN_DS_NAMING_VIOLATION = 8247, + MD_ERROR_WIN_DS_OBJECT_RESULTS_TOO_LARGE = 8248, + MD_ERROR_WIN_DS_AFFECTS_MULTIPLE_DSAS = 8249, + MD_ERROR_WIN_DS_SERVER_DOWN = 8250, + MD_ERROR_WIN_DS_LOCAL_ERROR = 8251, + MD_ERROR_WIN_DS_ENCODING_ERROR = 8252, + MD_ERROR_WIN_DS_DECODING_ERROR = 8253, + MD_ERROR_WIN_DS_FILTER_UNKNOWN = 8254, + MD_ERROR_WIN_DS_PARAM_ERROR = 8255, + MD_ERROR_WIN_DS_NOT_SUPPORTED = 8256, + MD_ERROR_WIN_DS_NO_RESULTS_RETURNED = 8257, + MD_ERROR_WIN_DS_CONTROL_NOT_FOUND = 8258, + MD_ERROR_WIN_DS_CLIENT_LOOP = 8259, + MD_ERROR_WIN_DS_REFERRAL_LIMIT_EXCEEDED = 8260, + MD_ERROR_WIN_DS_SORT_CONTROL_MISSING = 8261, + MD_ERROR_WIN_DS_OFFSET_RANGE_ERROR = 8262, + MD_ERROR_WIN_DS_RIDMGR_DISABLED = 8263, + MD_ERROR_WIN_DS_ROOT_MUST_BE_NC = 8301, + MD_ERROR_WIN_DS_ADD_REPLICA_INHIBITED = 8302, + MD_ERROR_WIN_DS_ATT_NOT_DEF_IN_SCHEMA = 8303, + MD_ERROR_WIN_DS_MAX_OBJ_SIZE_EXCEEDED = 8304, + MD_ERROR_WIN_DS_OBJ_STRING_NAME_EXISTS = 8305, + MD_ERROR_WIN_DS_NO_RDN_DEFINED_IN_SCHEMA = 8306, + MD_ERROR_WIN_DS_RDN_DOESNT_MATCH_SCHEMA = 8307, + MD_ERROR_WIN_DS_NO_REQUESTED_ATTS_FOUND = 8308, + MD_ERROR_WIN_DS_USER_BUFFER_TO_SMALL = 8309, + MD_ERROR_WIN_DS_ATT_IS_NOT_ON_OBJ = 8310, + MD_ERROR_WIN_DS_ILLEGAL_MOD_OPERATION = 8311, + MD_ERROR_WIN_DS_OBJ_TOO_LARGE = 8312, + MD_ERROR_WIN_DS_BAD_INSTANCE_TYPE = 8313, + MD_ERROR_WIN_DS_MASTERDSA_REQUIRED = 8314, + MD_ERROR_WIN_DS_OBJECT_CLASS_REQUIRED = 8315, + MD_ERROR_WIN_DS_MISSING_REQUIRED_ATT = 8316, + MD_ERROR_WIN_DS_ATT_NOT_DEF_FOR_CLASS = 8317, + MD_ERROR_WIN_DS_ATT_ALREADY_EXISTS = 8318, + MD_ERROR_WIN_DS_CANT_ADD_ATT_VALUES = 8320, + MD_ERROR_WIN_DS_SINGLE_VALUE_CONSTRAINT = 8321, + MD_ERROR_WIN_DS_RANGE_CONSTRAINT = 8322, + MD_ERROR_WIN_DS_ATT_VAL_ALREADY_EXISTS = 8323, + MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT = 8324, + MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT_VAL = 8325, + MD_ERROR_WIN_DS_ROOT_CANT_BE_SUBREF = 8326, + MD_ERROR_WIN_DS_NO_CHAINING = 8327, + MD_ERROR_WIN_DS_NO_CHAINED_EVAL = 8328, + MD_ERROR_WIN_DS_NO_PARENT_OBJECT = 8329, + MD_ERROR_WIN_DS_PARENT_IS_AN_ALIAS = 8330, + MD_ERROR_WIN_DS_CANT_MIX_MASTER_AND_REPS = 8331, + MD_ERROR_WIN_DS_CHILDREN_EXIST = 8332, + MD_ERROR_WIN_DS_OBJ_NOT_FOUND = 8333, + MD_ERROR_WIN_DS_ALIASED_OBJ_MISSING = 8334, + MD_ERROR_WIN_DS_BAD_NAME_SYNTAX = 8335, + MD_ERROR_WIN_DS_ALIAS_POINTS_TO_ALIAS = 8336, + MD_ERROR_WIN_DS_CANT_DEREF_ALIAS = 8337, + MD_ERROR_WIN_DS_OUT_OF_SCOPE = 8338, + MD_ERROR_WIN_DS_OBJECT_BEING_REMOVED = 8339, + MD_ERROR_WIN_DS_CANT_DELETE_DSA_OBJ = 8340, + MD_ERROR_WIN_DS_GENERIC_ERROR = 8341, + MD_ERROR_WIN_DS_DSA_MUST_BE_INT_MASTER = 8342, + MD_ERROR_WIN_DS_CLASS_NOT_DSA = 8343, + MD_ERROR_WIN_DS_INSUFF_ACCESS_RIGHTS = 8344, + MD_ERROR_WIN_DS_ILLEGAL_SUPERIOR = 8345, + MD_ERROR_WIN_DS_ATTRIBUTE_OWNED_BY_SAM = 8346, + MD_ERROR_WIN_DS_NAME_TOO_MANY_PARTS = 8347, + MD_ERROR_WIN_DS_NAME_TOO_LONG = 8348, + MD_ERROR_WIN_DS_NAME_VALUE_TOO_LONG = 8349, + MD_ERROR_WIN_DS_NAME_UNPARSEABLE = 8350, + MD_ERROR_WIN_DS_NAME_TYPE_UNKNOWN = 8351, + MD_ERROR_WIN_DS_NOT_AN_OBJECT = 8352, + MD_ERROR_WIN_DS_SEC_DESC_TOO_SHORT = 8353, + MD_ERROR_WIN_DS_SEC_DESC_INVALID = 8354, + MD_ERROR_WIN_DS_NO_DELETED_NAME = 8355, + MD_ERROR_WIN_DS_SUBREF_MUST_HAVE_PARENT = 8356, + MD_ERROR_WIN_DS_NCNAME_MUST_BE_NC = 8357, + MD_ERROR_WIN_DS_CANT_ADD_SYSTEM_ONLY = 8358, + MD_ERROR_WIN_DS_CLASS_MUST_BE_CONCRETE = 8359, + MD_ERROR_WIN_DS_INVALID_DMD = 8360, + MD_ERROR_WIN_DS_OBJ_GUID_EXISTS = 8361, + MD_ERROR_WIN_DS_NOT_ON_BACKLINK = 8362, + MD_ERROR_WIN_DS_NO_CROSSREF_FOR_NC = 8363, + MD_ERROR_WIN_DS_SHUTTING_DOWN = 8364, + MD_ERROR_WIN_DS_UNKNOWN_OPERATION = 8365, + MD_ERROR_WIN_DS_INVALID_ROLE_OWNER = 8366, + MD_ERROR_WIN_DS_COULDNT_CONTACT_FSMO = 8367, + MD_ERROR_WIN_DS_CROSS_NC_DN_RENAME = 8368, + MD_ERROR_WIN_DS_CANT_MOD_SYSTEM_ONLY = 8369, + MD_ERROR_WIN_DS_REPLICATOR_ONLY = 8370, + MD_ERROR_WIN_DS_OBJ_CLASS_NOT_DEFINED = 8371, + MD_ERROR_WIN_DS_OBJ_CLASS_NOT_SUBCLASS = 8372, + MD_ERROR_WIN_DS_NAME_REFERENCE_INVALID = 8373, + MD_ERROR_WIN_DS_CROSS_REF_EXISTS = 8374, + MD_ERROR_WIN_DS_CANT_DEL_MASTER_CROSSREF = 8375, + MD_ERROR_WIN_DS_SUBTREE_NOTIFY_NOT_NC_HEAD = 8376, + MD_ERROR_WIN_DS_NOTIFY_FILTER_TOO_COMPLEX = 8377, + MD_ERROR_WIN_DS_DUP_RDN = 8378, + MD_ERROR_WIN_DS_DUP_OID = 8379, + MD_ERROR_WIN_DS_DUP_MAPI_ID = 8380, + MD_ERROR_WIN_DS_DUP_SCHEMA_ID_GUID = 8381, + MD_ERROR_WIN_DS_DUP_LDAP_DISPLAY_NAME = 8382, + MD_ERROR_WIN_DS_SEMANTIC_ATT_TEST = 8383, + MD_ERROR_WIN_DS_SYNTAX_MISMATCH = 8384, + MD_ERROR_WIN_DS_EXISTS_IN_MUST_HAVE = 8385, + MD_ERROR_WIN_DS_EXISTS_IN_MAY_HAVE = 8386, + MD_ERROR_WIN_DS_NONEXISTENT_MAY_HAVE = 8387, + MD_ERROR_WIN_DS_NONEXISTENT_MUST_HAVE = 8388, + MD_ERROR_WIN_DS_AUX_CLS_TEST_FAIL = 8389, + MD_ERROR_WIN_DS_NONEXISTENT_POSS_SUP = 8390, + MD_ERROR_WIN_DS_SUB_CLS_TEST_FAIL = 8391, + MD_ERROR_WIN_DS_BAD_RDN_ATT_ID_SYNTAX = 8392, + MD_ERROR_WIN_DS_EXISTS_IN_AUX_CLS = 8393, + MD_ERROR_WIN_DS_EXISTS_IN_SUB_CLS = 8394, + MD_ERROR_WIN_DS_EXISTS_IN_POSS_SUP = 8395, + MD_ERROR_WIN_DS_RECALCSCHEMA_FAILED = 8396, + MD_ERROR_WIN_DS_TREE_DELETE_NOT_FINISHED = 8397, + MD_ERROR_WIN_DS_CANT_DELETE = 8398, + MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_ID = 8399, + MD_ERROR_WIN_DS_BAD_ATT_SCHEMA_SYNTAX = 8400, + MD_ERROR_WIN_DS_CANT_CACHE_ATT = 8401, + MD_ERROR_WIN_DS_CANT_CACHE_CLASS = 8402, + MD_ERROR_WIN_DS_CANT_REMOVE_ATT_CACHE = 8403, + MD_ERROR_WIN_DS_CANT_REMOVE_CLASS_CACHE = 8404, + MD_ERROR_WIN_DS_CANT_RETRIEVE_DN = 8405, + MD_ERROR_WIN_DS_MISSING_SUPREF = 8406, + MD_ERROR_WIN_DS_CANT_RETRIEVE_INSTANCE = 8407, + MD_ERROR_WIN_DS_CODE_INCONSISTENCY = 8408, + MD_ERROR_WIN_DS_DATABASE_ERROR = 8409, + MD_ERROR_WIN_DS_GOVERNSID_MISSING = 8410, + MD_ERROR_WIN_DS_MISSING_EXPECTED_ATT = 8411, + MD_ERROR_WIN_DS_NCNAME_MISSING_CR_REF = 8412, + MD_ERROR_WIN_DS_SECURITY_CHECKING_ERROR = 8413, + MD_ERROR_WIN_DS_SCHEMA_NOT_LOADED = 8414, + MD_ERROR_WIN_DS_SCHEMA_ALLOC_FAILED = 8415, + MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_SYNTAX = 8416, + MD_ERROR_WIN_DS_GCVERIFY_ERROR = 8417, + MD_ERROR_WIN_DS_DRA_SCHEMA_MISMATCH = 8418, + MD_ERROR_WIN_DS_CANT_FIND_DSA_OBJ = 8419, + MD_ERROR_WIN_DS_CANT_FIND_EXPECTED_NC = 8420, + MD_ERROR_WIN_DS_CANT_FIND_NC_IN_CACHE = 8421, + MD_ERROR_WIN_DS_CANT_RETRIEVE_CHILD = 8422, + MD_ERROR_WIN_DS_SECURITY_ILLEGAL_MODIFY = 8423, + MD_ERROR_WIN_DS_CANT_REPLACE_HIDDEN_REC = 8424, + MD_ERROR_WIN_DS_BAD_HIERARCHY_FILE = 8425, + MD_ERROR_WIN_DS_BUILD_HIERARCHY_TABLE_FAILED = 8426, + MD_ERROR_WIN_DS_CONFIG_PARAM_MISSING = 8427, + MD_ERROR_WIN_DS_COUNTING_AB_INDICES_FAILED = 8428, + MD_ERROR_WIN_DS_HIERARCHY_TABLE_MALLOC_FAILED = 8429, + MD_ERROR_WIN_DS_INTERNAL_FAILURE = 8430, + MD_ERROR_WIN_DS_UNKNOWN_ERROR = 8431, + MD_ERROR_WIN_DS_ROOT_REQUIRES_CLASS_TOP = 8432, + MD_ERROR_WIN_DS_REFUSING_FSMO_ROLES = 8433, + MD_ERROR_WIN_DS_MISSING_FSMO_SETTINGS = 8434, + MD_ERROR_WIN_DS_UNABLE_TO_SURRENDER_ROLES = 8435, + MD_ERROR_WIN_DS_DRA_GENERIC = 8436, + MD_ERROR_WIN_DS_DRA_INVALID_PARAMETER = 8437, + MD_ERROR_WIN_DS_DRA_BUSY = 8438, + MD_ERROR_WIN_DS_DRA_BAD_DN = 8439, + MD_ERROR_WIN_DS_DRA_BAD_NC = 8440, + MD_ERROR_WIN_DS_DRA_DN_EXISTS = 8441, + MD_ERROR_WIN_DS_DRA_INTERNAL_ERROR = 8442, + MD_ERROR_WIN_DS_DRA_INCONSISTENT_DIT = 8443, + MD_ERROR_WIN_DS_DRA_CONNECTION_FAILED = 8444, + MD_ERROR_WIN_DS_DRA_BAD_INSTANCE_TYPE = 8445, + MD_ERROR_WIN_DS_DRA_OUT_OF_MEM = 8446, + MD_ERROR_WIN_DS_DRA_MAIL_PROBLEM = 8447, + MD_ERROR_WIN_DS_DRA_REF_ALREADY_EXISTS = 8448, + MD_ERROR_WIN_DS_DRA_REF_NOT_FOUND = 8449, + MD_ERROR_WIN_DS_DRA_OBJ_IS_REP_SOURCE = 8450, + MD_ERROR_WIN_DS_DRA_DB_ERROR = 8451, + MD_ERROR_WIN_DS_DRA_NO_REPLICA = 8452, + MD_ERROR_WIN_DS_DRA_ACCESS_DENIED = 8453, + MD_ERROR_WIN_DS_DRA_NOT_SUPPORTED = 8454, + MD_ERROR_WIN_DS_DRA_RPC_CANCELLED = 8455, + MD_ERROR_WIN_DS_DRA_SOURCE_DISABLED = 8456, + MD_ERROR_WIN_DS_DRA_SINK_DISABLED = 8457, + MD_ERROR_WIN_DS_DRA_NAME_COLLISION = 8458, + MD_ERROR_WIN_DS_DRA_SOURCE_REINSTALLED = 8459, + MD_ERROR_WIN_DS_DRA_MISSING_PARENT = 8460, + MD_ERROR_WIN_DS_DRA_PREEMPTED = 8461, + MD_ERROR_WIN_DS_DRA_ABANDON_SYNC = 8462, + MD_ERROR_WIN_DS_DRA_SHUTDOWN = 8463, + MD_ERROR_WIN_DS_DRA_INCOMPATIBLE_PARTIAL_SET = 8464, + MD_ERROR_WIN_DS_DRA_SOURCE_IS_PARTIAL_REPLICA = 8465, + MD_ERROR_WIN_DS_DRA_EXTN_CONNECTION_FAILED = 8466, + MD_ERROR_WIN_DS_INSTALL_SCHEMA_MISMATCH = 8467, + MD_ERROR_WIN_DS_DUP_LINK_ID = 8468, + MD_ERROR_WIN_DS_NAME_ERROR_RESOLVING = 8469, + MD_ERROR_WIN_DS_NAME_ERROR_NOT_FOUND = 8470, + MD_ERROR_WIN_DS_NAME_ERROR_NOT_UNIQUE = 8471, + MD_ERROR_WIN_DS_NAME_ERROR_NO_MAPPING = 8472, + MD_ERROR_WIN_DS_NAME_ERROR_DOMAIN_ONLY = 8473, + MD_ERROR_WIN_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING = 8474, + MD_ERROR_WIN_DS_CONSTRUCTED_ATT_MOD = 8475, + MD_ERROR_WIN_DS_WRONG_OM_OBJ_CLASS = 8476, + MD_ERROR_WIN_DS_DRA_REPL_PENDING = 8477, + MD_ERROR_WIN_DS_DS_REQUIRED = 8478, + MD_ERROR_WIN_DS_INVALID_LDAP_DISPLAY_NAME = 8479, + MD_ERROR_WIN_DS_NON_BASE_SEARCH = 8480, + MD_ERROR_WIN_DS_CANT_RETRIEVE_ATTS = 8481, + MD_ERROR_WIN_DS_BACKLINK_WITHOUT_LINK = 8482, + MD_ERROR_WIN_DS_EPOCH_MISMATCH = 8483, + MD_ERROR_WIN_DS_SRC_NAME_MISMATCH = 8484, + MD_ERROR_WIN_DS_SRC_AND_DST_NC_IDENTICAL = 8485, + MD_ERROR_WIN_DS_DST_NC_MISMATCH = 8486, + MD_ERROR_WIN_DS_NOT_AUTHORITIVE_FOR_DST_NC = 8487, + MD_ERROR_WIN_DS_SRC_GUID_MISMATCH = 8488, + MD_ERROR_WIN_DS_CANT_MOVE_DELETED_OBJECT = 8489, + MD_ERROR_WIN_DS_PDC_OPERATION_IN_PROGRESS = 8490, + MD_ERROR_WIN_DS_CROSS_DOMAIN_CLEANUP_REQD = 8491, + MD_ERROR_WIN_DS_ILLEGAL_XDOM_MOVE_OPERATION = 8492, + MD_ERROR_WIN_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS = 8493, + MD_ERROR_WIN_DS_NC_MUST_HAVE_NC_PARENT = 8494, + MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE = 8495, + MD_ERROR_WIN_DS_DST_DOMAIN_NOT_NATIVE = 8496, + MD_ERROR_WIN_DS_MISSING_INFRASTRUCTURE_CONTAINER = 8497, + MD_ERROR_WIN_DS_CANT_MOVE_ACCOUNT_GROUP = 8498, + MD_ERROR_WIN_DS_CANT_MOVE_RESOURCE_GROUP = 8499, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG = 8500, + MD_ERROR_WIN_DS_NO_TREE_DELETE_ABOVE_NC = 8501, + MD_ERROR_WIN_DS_COULDNT_LOCK_TREE_FOR_DELETE = 8502, + MD_ERROR_WIN_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE = 8503, + MD_ERROR_WIN_DS_SAM_INIT_FAILURE = 8504, + MD_ERROR_WIN_DS_SENSITIVE_GROUP_VIOLATION = 8505, + MD_ERROR_WIN_DS_CANT_MOD_PRIMARYGROUPID = 8506, + MD_ERROR_WIN_DS_ILLEGAL_BASE_SCHEMA_MOD = 8507, + MD_ERROR_WIN_DS_NONSAFE_SCHEMA_CHANGE = 8508, + MD_ERROR_WIN_DS_SCHEMA_UPDATE_DISALLOWED = 8509, + MD_ERROR_WIN_DS_CANT_CREATE_UNDER_SCHEMA = 8510, + MD_ERROR_WIN_DS_INSTALL_NO_SRC_SCH_VERSION = 8511, + MD_ERROR_WIN_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE = 8512, + MD_ERROR_WIN_DS_INVALID_GROUP_TYPE = 8513, + MD_ERROR_WIN_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 8514, + MD_ERROR_WIN_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 8515, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 8516, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 8517, + MD_ERROR_WIN_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 8518, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 8519, + MD_ERROR_WIN_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 8520, + MD_ERROR_WIN_DS_HAVE_PRIMARY_MEMBERS = 8521, + MD_ERROR_WIN_DS_STRING_SD_CONVERSION_FAILED = 8522, + MD_ERROR_WIN_DS_NAMING_MASTER_GC = 8523, + MD_ERROR_WIN_DS_DNS_LOOKUP_FAILURE = 8524, + MD_ERROR_WIN_DS_COULDNT_UPDATE_SPNS = 8525, + MD_ERROR_WIN_DS_CANT_RETRIEVE_SD = 8526, + MD_ERROR_WIN_DS_KEY_NOT_UNIQUE = 8527, + MD_ERROR_WIN_DS_WRONG_LINKED_ATT_SYNTAX = 8528, + MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_PASSWORD = 8529, + MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_FLOPPY = 8530, + MD_ERROR_WIN_DS_CANT_START = 8531, + MD_ERROR_WIN_DS_INIT_FAILURE = 8532, + MD_ERROR_WIN_DS_NO_PKT_PRIVACY_ON_CONNECTION = 8533, + MD_ERROR_WIN_DS_SOURCE_DOMAIN_IN_FOREST = 8534, + MD_ERROR_WIN_DS_DESTINATION_DOMAIN_NOT_IN_FOREST = 8535, + MD_ERROR_WIN_DS_DESTINATION_AUDITING_NOT_ENABLED = 8536, + MD_ERROR_WIN_DS_CANT_FIND_DC_FOR_SRC_DOMAIN = 8537, + MD_ERROR_WIN_DS_SRC_OBJ_NOT_GROUP_OR_USER = 8538, + MD_ERROR_WIN_DS_SRC_SID_EXISTS_IN_FOREST = 8539, + MD_ERROR_WIN_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH = 8540, + MD_ERROR_WIN_SAM_INIT_FAILURE = 8541, + MD_ERROR_WIN_DS_DRA_SCHEMA_INFO_SHIP = 8542, + MD_ERROR_WIN_DS_DRA_SCHEMA_CONFLICT = 8543, + MD_ERROR_WIN_DS_DRA_EARLIER_SCHEMA_CONFLICT = 8544, + MD_ERROR_WIN_DS_DRA_OBJ_NC_MISMATCH = 8545, + MD_ERROR_WIN_DS_NC_STILL_HAS_DSAS = 8546, + MD_ERROR_WIN_DS_GC_REQUIRED = 8547, + MD_ERROR_WIN_DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 8548, + MD_ERROR_WIN_DS_NO_FPO_IN_UNIVERSAL_GROUPS = 8549, + MD_ERROR_WIN_DS_CANT_ADD_TO_GC = 8550, + MD_ERROR_WIN_DS_NO_CHECKPOINT_WITH_PDC = 8551, + MD_ERROR_WIN_DS_SOURCE_AUDITING_NOT_ENABLED = 8552, + MD_ERROR_WIN_DS_CANT_CREATE_IN_NONDOMAIN_NC = 8553, + MD_ERROR_WIN_DS_INVALID_NAME_FOR_SPN = 8554, + MD_ERROR_WIN_DS_FILTER_USES_CONTRUCTED_ATTRS = 8555, + MD_ERROR_WIN_DS_UNICODEPWD_NOT_IN_QUOTES = 8556, + MD_ERROR_WIN_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 8557, + MD_ERROR_WIN_DS_MUST_BE_RUN_ON_DST_DC = 8558, + MD_ERROR_WIN_DS_SRC_DC_MUST_BE_SP4_OR_GREATER = 8559, + MD_ERROR_WIN_DS_CANT_TREE_DELETE_CRITICAL_OBJ = 8560, + MD_ERROR_WIN_DS_INIT_FAILURE_CONSOLE = 8561, + MD_ERROR_WIN_DS_SAM_INIT_FAILURE_CONSOLE = 8562, + MD_ERROR_WIN_DS_FOREST_VERSION_TOO_HIGH = 8563, + MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_HIGH = 8564, + MD_ERROR_WIN_DS_FOREST_VERSION_TOO_LOW = 8565, + MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_LOW = 8566, + MD_ERROR_WIN_DS_INCOMPATIBLE_VERSION = 8567, + MD_ERROR_WIN_DS_LOW_DSA_VERSION = 8568, + MD_ERROR_WIN_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN = 8569, + MD_ERROR_WIN_DS_NOT_SUPPORTED_SORT_ORDER = 8570, + MD_ERROR_WIN_DS_NAME_NOT_UNIQUE = 8571, + MD_ERROR_WIN_DS_MACHINE_ACCOUNT_CREATED_PRENT4 = 8572, + MD_ERROR_WIN_DS_OUT_OF_VERSION_STORE = 8573, + MD_ERROR_WIN_DS_INCOMPATIBLE_CONTROLS_USED = 8574, + MD_ERROR_WIN_DS_NO_REF_DOMAIN = 8575, + MD_ERROR_WIN_DS_RESERVED_LINK_ID = 8576, + MD_ERROR_WIN_DS_LINK_ID_NOT_AVAILABLE = 8577, + MD_ERROR_WIN_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 8578, + MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE = 8579, + MD_ERROR_WIN_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC = 8580, + MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_FLAG = 8581, + MD_ERROR_WIN_DS_MODIFYDN_WRONG_GRANDPARENT = 8582, + MD_ERROR_WIN_DS_NAME_ERROR_TRUST_REFERRAL = 8583, + MD_ERROR_WIN_NOT_SUPPORTED_ON_STANDARD_SERVER = 8584, + MD_ERROR_WIN_DS_CANT_ACCESS_REMOTE_PART_OF_AD = 8585, + MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2 = 8586, + MD_ERROR_WIN_DS_THREAD_LIMIT_EXCEEDED = 8587, + MD_ERROR_WIN_DS_NOT_CLOSEST = 8588, + MD_ERROR_WIN_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF = 8589, + MD_ERROR_WIN_DS_SINGLE_USER_MODE_FAILED = 8590, + MD_ERROR_WIN_DS_NTDSCRIPT_SYNTAX_ERROR = 8591, + MD_ERROR_WIN_DS_NTDSCRIPT_PROCESS_ERROR = 8592, + MD_ERROR_WIN_DS_DIFFERENT_REPL_EPOCHS = 8593, + MD_ERROR_WIN_DS_DRS_EXTENSIONS_CHANGED = 8594, + MD_ERROR_WIN_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR = 8595, + MD_ERROR_WIN_DS_NO_MSDS_INTID = 8596, + MD_ERROR_WIN_DS_DUP_MSDS_INTID = 8597, + MD_ERROR_WIN_DS_EXISTS_IN_RDNATTID = 8598, + MD_ERROR_WIN_DS_AUTHORIZATION_FAILED = 8599, + MD_ERROR_WIN_DS_INVALID_SCRIPT = 8600, + MD_ERROR_WIN_DS_REMOTE_CROSSREF_OP_FAILED = 8601, + MD_ERROR_WIN_DS_CROSS_REF_BUSY = 8602, + MD_ERROR_WIN_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN = 8603, + MD_ERROR_WIN_DS_CANT_DEMOTE_WITH_WRITEABLE_NC = 8604, + MD_ERROR_WIN_DS_DUPLICATE_ID_FOUND = 8605, + MD_ERROR_WIN_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT = 8606, + MD_ERROR_WIN_DS_GROUP_CONVERSION_ERROR = 8607, + MD_ERROR_WIN_DS_CANT_MOVE_APP_BASIC_GROUP = 8608, + MD_ERROR_WIN_DS_CANT_MOVE_APP_QUERY_GROUP = 8609, + MD_ERROR_WIN_DS_ROLE_NOT_VERIFIED = 8610, + MD_ERROR_WIN_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL = 8611, + MD_ERROR_WIN_DS_DOMAIN_RENAME_IN_PROGRESS = 8612, + MD_ERROR_WIN_DS_EXISTING_AD_CHILD_NC = 8613, + MD_ERROR_WIN_DS_REPL_LIFETIME_EXCEEDED = 8614, + MD_ERROR_WIN_DS_DISALLOWED_IN_SYSTEM_CONTAINER = 8615, + MD_ERROR_WIN_DS_LDAP_SEND_QUEUE_FULL = 8616, + MD_ERROR_WIN_DS_DRA_OUT_SCHEDULE_WINDOW = 8617, + MD_ERROR_WIN_DS_POLICY_NOT_KNOWN = 8618, + MD_ERROR_WIN_NO_SITE_SETTINGS_OBJECT = 8619, + MD_ERROR_WIN_NO_SECRETS = 8620, + MD_ERROR_WIN_NO_WRITABLE_DC_FOUND = 8621, + MD_ERROR_WIN_DS_NO_SERVER_OBJECT = 8622, + MD_ERROR_WIN_DS_NO_NTDSA_OBJECT = 8623, + MD_ERROR_WIN_DS_NON_ASQ_SEARCH = 8624, + MD_ERROR_WIN_DS_AUDIT_FAILURE = 8625, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_SUBTREE = 8626, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_TUPLE = 8627, + MD_ERROR_WIN_DS_HIERARCHY_TABLE_TOO_DEEP = 8628, + MD_ERROR_WIN_DS_DRA_CORRUPT_UTD_VECTOR = 8629, + MD_ERROR_WIN_DS_DRA_SECRETS_DENIED = 8630, + MD_ERROR_WIN_DS_RESERVED_MAPI_ID = 8631, + MD_ERROR_WIN_DS_MAPI_ID_NOT_AVAILABLE = 8632, + MD_ERROR_WIN_DS_DRA_MISSING_KRBTGT_SECRET = 8633, + MD_ERROR_WIN_DS_DOMAIN_NAME_EXISTS_IN_FOREST = 8634, + MD_ERROR_WIN_DS_FLAT_NAME_EXISTS_IN_FOREST = 8635, + MD_ERROR_WIN_INVALID_USER_PRINCIPAL_NAME = 8636, + MD_ERROR_WIN_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 8637, + MD_ERROR_WIN_DS_OID_NOT_FOUND = 8638, + MD_ERROR_WIN_DS_DRA_RECYCLED_TARGET = 8639, + MD_ERROR_WIN_DS_DISALLOWED_NC_REDIRECT = 8640, + MD_ERROR_WIN_DS_HIGH_ADLDS_FFL = 8641, + MD_ERROR_WIN_DS_HIGH_DSA_VERSION = 8642, + MD_ERROR_WIN_DS_LOW_ADLDS_FFL = 8643, + MD_ERROR_WIN_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION = 8644, + MD_ERROR_WIN_DS_UNDELETE_SAM_VALIDATION_FAILED = 8645, + MD_ERROR_WIN_INCORRECT_ACCOUNT_TYPE = 8646, + MD_ERROR_WIN_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST = 8647, + MD_ERROR_WIN_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST = 8648, + MD_ERROR_WIN_DS_MISSING_FOREST_TRUST = 8649, + MD_ERROR_WIN_DS_VALUE_KEY_NOT_UNIQUE = 8650, + MD_ERROR_WIN_IPSEC_QM_POLICY_EXISTS = 13000, + MD_ERROR_WIN_IPSEC_QM_POLICY_NOT_FOUND = 13001, + MD_ERROR_WIN_IPSEC_QM_POLICY_IN_USE = 13002, + MD_ERROR_WIN_IPSEC_MM_POLICY_EXISTS = 13003, + MD_ERROR_WIN_IPSEC_MM_POLICY_NOT_FOUND = 13004, + MD_ERROR_WIN_IPSEC_MM_POLICY_IN_USE = 13005, + MD_ERROR_WIN_IPSEC_MM_FILTER_EXISTS = 13006, + MD_ERROR_WIN_IPSEC_MM_FILTER_NOT_FOUND = 13007, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_EXISTS = 13008, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_NOT_FOUND = 13009, + MD_ERROR_WIN_IPSEC_MM_AUTH_EXISTS = 13010, + MD_ERROR_WIN_IPSEC_MM_AUTH_NOT_FOUND = 13011, + MD_ERROR_WIN_IPSEC_MM_AUTH_IN_USE = 13012, + MD_ERROR_WIN_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND = 13013, + MD_ERROR_WIN_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND = 13014, + MD_ERROR_WIN_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND = 13015, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_EXISTS = 13016, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_NOT_FOUND = 13017, + MD_ERROR_WIN_IPSEC_MM_FILTER_PENDING_DELETION = 13018, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_PENDING_DELETION = 13019, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_PENDING_DELETION = 13020, + MD_ERROR_WIN_IPSEC_MM_POLICY_PENDING_DELETION = 13021, + MD_ERROR_WIN_IPSEC_MM_AUTH_PENDING_DELETION = 13022, + MD_ERROR_WIN_IPSEC_QM_POLICY_PENDING_DELETION = 13023, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_BEGIN = 13800, + MD_ERROR_WIN_IPSEC_IKE_AUTH_FAIL = 13801, + MD_ERROR_WIN_IPSEC_IKE_ATTRIB_FAIL = 13802, + MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_PENDING = 13803, + MD_ERROR_WIN_IPSEC_IKE_GENERAL_PROCESSING_ERROR = 13804, + MD_ERROR_WIN_IPSEC_IKE_TIMED_OUT = 13805, + MD_ERROR_WIN_IPSEC_IKE_NO_CERT = 13806, + MD_ERROR_WIN_IPSEC_IKE_SA_DELETED = 13807, + MD_ERROR_WIN_IPSEC_IKE_SA_REAPED = 13808, + MD_ERROR_WIN_IPSEC_IKE_MM_ACQUIRE_DROP = 13809, + MD_ERROR_WIN_IPSEC_IKE_QM_ACQUIRE_DROP = 13810, + MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_MM = 13811, + MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_NO_MM = 13812, + MD_ERROR_WIN_IPSEC_IKE_DROP_NO_RESPONSE = 13813, + MD_ERROR_WIN_IPSEC_IKE_MM_DELAY_DROP = 13814, + MD_ERROR_WIN_IPSEC_IKE_QM_DELAY_DROP = 13815, + MD_ERROR_WIN_IPSEC_IKE_ERROR = 13816, + MD_ERROR_WIN_IPSEC_IKE_CRL_FAILED = 13817, + MD_ERROR_WIN_IPSEC_IKE_INVALID_KEY_USAGE = 13818, + MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_TYPE = 13819, + MD_ERROR_WIN_IPSEC_IKE_NO_PRIVATE_KEY = 13820, + MD_ERROR_WIN_IPSEC_IKE_SIMULTANEOUS_REKEY = 13821, + MD_ERROR_WIN_IPSEC_IKE_DH_FAIL = 13822, + MD_ERROR_WIN_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED = 13823, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HEADER = 13824, + MD_ERROR_WIN_IPSEC_IKE_NO_POLICY = 13825, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SIGNATURE = 13826, + MD_ERROR_WIN_IPSEC_IKE_KERBEROS_ERROR = 13827, + MD_ERROR_WIN_IPSEC_IKE_NO_PUBLIC_KEY = 13828, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR = 13829, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SA = 13830, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_PROP = 13831, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_TRANS = 13832, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_KE = 13833, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_ID = 13834, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT = 13835, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT_REQ = 13836, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_HASH = 13837, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SIG = 13838, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NONCE = 13839, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NOTIFY = 13840, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_DELETE = 13841, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_VENDOR = 13842, + MD_ERROR_WIN_IPSEC_IKE_INVALID_PAYLOAD = 13843, + MD_ERROR_WIN_IPSEC_IKE_LOAD_SOFT_SA = 13844, + MD_ERROR_WIN_IPSEC_IKE_SOFT_SA_TORN_DOWN = 13845, + MD_ERROR_WIN_IPSEC_IKE_INVALID_COOKIE = 13846, + MD_ERROR_WIN_IPSEC_IKE_NO_PEER_CERT = 13847, + MD_ERROR_WIN_IPSEC_IKE_PEER_CRL_FAILED = 13848, + MD_ERROR_WIN_IPSEC_IKE_POLICY_CHANGE = 13849, + MD_ERROR_WIN_IPSEC_IKE_NO_MM_POLICY = 13850, + MD_ERROR_WIN_IPSEC_IKE_NOTCBPRIV = 13851, + MD_ERROR_WIN_IPSEC_IKE_SECLOADFAIL = 13852, + MD_ERROR_WIN_IPSEC_IKE_FAILSSPINIT = 13853, + MD_ERROR_WIN_IPSEC_IKE_FAILQUERYSSP = 13854, + MD_ERROR_WIN_IPSEC_IKE_SRVACQFAIL = 13855, + MD_ERROR_WIN_IPSEC_IKE_SRVQUERYCRED = 13856, + MD_ERROR_WIN_IPSEC_IKE_GETSPIFAIL = 13857, + MD_ERROR_WIN_IPSEC_IKE_INVALID_FILTER = 13858, + MD_ERROR_WIN_IPSEC_IKE_OUT_OF_MEMORY = 13859, + MD_ERROR_WIN_IPSEC_IKE_ADD_UPDATE_KEY_FAILED = 13860, + MD_ERROR_WIN_IPSEC_IKE_INVALID_POLICY = 13861, + MD_ERROR_WIN_IPSEC_IKE_UNKNOWN_DOI = 13862, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SITUATION = 13863, + MD_ERROR_WIN_IPSEC_IKE_DH_FAILURE = 13864, + MD_ERROR_WIN_IPSEC_IKE_INVALID_GROUP = 13865, + MD_ERROR_WIN_IPSEC_IKE_ENCRYPT = 13866, + MD_ERROR_WIN_IPSEC_IKE_DECRYPT = 13867, + MD_ERROR_WIN_IPSEC_IKE_POLICY_MATCH = 13868, + MD_ERROR_WIN_IPSEC_IKE_UNSUPPORTED_ID = 13869, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH = 13870, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_ALG = 13871, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_SIZE = 13872, + MD_ERROR_WIN_IPSEC_IKE_INVALID_ENCRYPT_ALG = 13873, + MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_ALG = 13874, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SIG = 13875, + MD_ERROR_WIN_IPSEC_IKE_LOAD_FAILED = 13876, + MD_ERROR_WIN_IPSEC_IKE_RPC_DELETE = 13877, + MD_ERROR_WIN_IPSEC_IKE_BENIGN_REINIT = 13878, + MD_ERROR_WIN_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY = 13879, + MD_ERROR_WIN_IPSEC_IKE_INVALID_MAJOR_VERSION = 13880, + MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_KEYLEN = 13881, + MD_ERROR_WIN_IPSEC_IKE_MM_LIMIT = 13882, + MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_DISABLED = 13883, + MD_ERROR_WIN_IPSEC_IKE_QM_LIMIT = 13884, + MD_ERROR_WIN_IPSEC_IKE_MM_EXPIRED = 13885, + MD_ERROR_WIN_IPSEC_IKE_PEER_MM_ASSUMED_INVALID = 13886, + MD_ERROR_WIN_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH = 13887, + MD_ERROR_WIN_IPSEC_IKE_UNEXPECTED_MESSAGE_ID = 13888, + MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_PAYLOAD = 13889, + MD_ERROR_WIN_IPSEC_IKE_DOS_COOKIE_SENT = 13890, + MD_ERROR_WIN_IPSEC_IKE_SHUTTING_DOWN = 13891, + MD_ERROR_WIN_IPSEC_IKE_CGA_AUTH_FAILED = 13892, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NATOA = 13893, + MD_ERROR_WIN_IPSEC_IKE_INVALID_MM_FOR_QM = 13894, + MD_ERROR_WIN_IPSEC_IKE_QM_EXPIRED = 13895, + MD_ERROR_WIN_IPSEC_IKE_TOO_MANY_FILTERS = 13896, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_END = 13897, + MD_ERROR_WIN_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL = 13898, + MD_ERROR_WIN_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE = 13899, + MD_ERROR_WIN_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING = 13900, + MD_ERROR_WIN_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING = 13901, + MD_ERROR_WIN_IPSEC_IKE_COEXISTENCE_SUPPRESS = 13902, + MD_ERROR_WIN_IPSEC_IKE_RATELIMIT_DROP = 13903, + MD_ERROR_WIN_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE = 13904, + MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE = 13905, + MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE = 13906, + MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY = 13907, + MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE = 13908, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_EXTENDED_END = 13909, + MD_ERROR_WIN_IPSEC_BAD_SPI = 13910, + MD_ERROR_WIN_IPSEC_SA_LIFETIME_EXPIRED = 13911, + MD_ERROR_WIN_IPSEC_WRONG_SA = 13912, + MD_ERROR_WIN_IPSEC_REPLAY_CHECK_FAILED = 13913, + MD_ERROR_WIN_IPSEC_INVALID_PACKET = 13914, + MD_ERROR_WIN_IPSEC_INTEGRITY_CHECK_FAILED = 13915, + MD_ERROR_WIN_IPSEC_CLEAR_TEXT_DROP = 13916, + MD_ERROR_WIN_IPSEC_AUTH_FIREWALL_DROP = 13917, + MD_ERROR_WIN_IPSEC_THROTTLE_DROP = 13918, + MD_ERROR_WIN_IPSEC_DOSP_BLOCK = 13925, + MD_ERROR_WIN_IPSEC_DOSP_RECEIVED_MULTICAST = 13926, + MD_ERROR_WIN_IPSEC_DOSP_INVALID_PACKET = 13927, + MD_ERROR_WIN_IPSEC_DOSP_STATE_LOOKUP_FAILED = 13928, + MD_ERROR_WIN_IPSEC_DOSP_MAX_ENTRIES = 13929, + MD_ERROR_WIN_IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 13930, + MD_ERROR_WIN_IPSEC_DOSP_NOT_INSTALLED = 13931, + MD_ERROR_WIN_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 13932, + MD_ERROR_WIN_SXS_SECTION_NOT_FOUND = 14000, + MD_ERROR_WIN_SXS_CANT_GEN_ACTCTX = 14001, + MD_ERROR_WIN_SXS_INVALID_ACTCTXDATA_FORMAT = 14002, + MD_ERROR_WIN_SXS_ASSEMBLY_NOT_FOUND = 14003, + MD_ERROR_WIN_SXS_MANIFEST_FORMAT_ERROR = 14004, + MD_ERROR_WIN_SXS_MANIFEST_PARSE_ERROR = 14005, + MD_ERROR_WIN_SXS_ACTIVATION_CONTEXT_DISABLED = 14006, + MD_ERROR_WIN_SXS_KEY_NOT_FOUND = 14007, + MD_ERROR_WIN_SXS_VERSION_CONFLICT = 14008, + MD_ERROR_WIN_SXS_WRONG_SECTION_TYPE = 14009, + MD_ERROR_WIN_SXS_THREAD_QUERIES_DISABLED = 14010, + MD_ERROR_WIN_SXS_PROCESS_DEFAULT_ALREADY_SET = 14011, + MD_ERROR_WIN_SXS_UNKNOWN_ENCODING_GROUP = 14012, + MD_ERROR_WIN_SXS_UNKNOWN_ENCODING = 14013, + MD_ERROR_WIN_SXS_INVALID_XML_NAMESPACE_URI = 14014, + MD_ERROR_WIN_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED = 14015, + MD_ERROR_WIN_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED = 14016, + MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE = 14017, + MD_ERROR_WIN_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE = 14018, + MD_ERROR_WIN_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE = 14019, + MD_ERROR_WIN_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT = 14020, + MD_ERROR_WIN_SXS_DUPLICATE_DLL_NAME = 14021, + MD_ERROR_WIN_SXS_DUPLICATE_WINDOWCLASS_NAME = 14022, + MD_ERROR_WIN_SXS_DUPLICATE_CLSID = 14023, + MD_ERROR_WIN_SXS_DUPLICATE_IID = 14024, + MD_ERROR_WIN_SXS_DUPLICATE_TLBID = 14025, + MD_ERROR_WIN_SXS_DUPLICATE_PROGID = 14026, + MD_ERROR_WIN_SXS_DUPLICATE_ASSEMBLY_NAME = 14027, + MD_ERROR_WIN_SXS_FILE_HASH_MISMATCH = 14028, + MD_ERROR_WIN_SXS_POLICY_PARSE_ERROR = 14029, + MD_ERROR_WIN_SXS_XML_E_MISSINGQUOTE = 14030, + MD_ERROR_WIN_SXS_XML_E_COMMENTSYNTAX = 14031, + MD_ERROR_WIN_SXS_XML_E_BADSTARTNAMECHAR = 14032, + MD_ERROR_WIN_SXS_XML_E_BADNAMECHAR = 14033, + MD_ERROR_WIN_SXS_XML_E_BADCHARINSTRING = 14034, + MD_ERROR_WIN_SXS_XML_E_XMLDECLSYNTAX = 14035, + MD_ERROR_WIN_SXS_XML_E_BADCHARDATA = 14036, + MD_ERROR_WIN_SXS_XML_E_MISSINGWHITESPACE = 14037, + MD_ERROR_WIN_SXS_XML_E_EXPECTINGTAGEND = 14038, + MD_ERROR_WIN_SXS_XML_E_MISSINGSEMICOLON = 14039, + MD_ERROR_WIN_SXS_XML_E_UNBALANCEDPAREN = 14040, + MD_ERROR_WIN_SXS_XML_E_INTERNALERROR = 14041, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_WHITESPACE = 14042, + MD_ERROR_WIN_SXS_XML_E_INCOMPLETE_ENCODING = 14043, + MD_ERROR_WIN_SXS_XML_E_MISSING_PAREN = 14044, + MD_ERROR_WIN_SXS_XML_E_EXPECTINGCLOSEQUOTE = 14045, + MD_ERROR_WIN_SXS_XML_E_MULTIPLE_COLONS = 14046, + MD_ERROR_WIN_SXS_XML_E_INVALID_DECIMAL = 14047, + MD_ERROR_WIN_SXS_XML_E_INVALID_HEXIDECIMAL = 14048, + MD_ERROR_WIN_SXS_XML_E_INVALID_UNICODE = 14049, + MD_ERROR_WIN_SXS_XML_E_WHITESPACEORQUESTIONMARK = 14050, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDENDTAG = 14051, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDTAG = 14052, + MD_ERROR_WIN_SXS_XML_E_DUPLICATEATTRIBUTE = 14053, + MD_ERROR_WIN_SXS_XML_E_MULTIPLEROOTS = 14054, + MD_ERROR_WIN_SXS_XML_E_INVALIDATROOTLEVEL = 14055, + MD_ERROR_WIN_SXS_XML_E_BADXMLDECL = 14056, + MD_ERROR_WIN_SXS_XML_E_MISSINGROOT = 14057, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDEOF = 14058, + MD_ERROR_WIN_SXS_XML_E_BADPEREFINSUBSET = 14059, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTARTTAG = 14060, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDENDTAG = 14061, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTRING = 14062, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCOMMENT = 14063, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDDECL = 14064, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCDATA = 14065, + MD_ERROR_WIN_SXS_XML_E_RESERVEDNAMESPACE = 14066, + MD_ERROR_WIN_SXS_XML_E_INVALIDENCODING = 14067, + MD_ERROR_WIN_SXS_XML_E_INVALIDSWITCH = 14068, + MD_ERROR_WIN_SXS_XML_E_BADXMLCASE = 14069, + MD_ERROR_WIN_SXS_XML_E_INVALID_STANDALONE = 14070, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_STANDALONE = 14071, + MD_ERROR_WIN_SXS_XML_E_INVALID_VERSION = 14072, + MD_ERROR_WIN_SXS_XML_E_MISSINGEQUALS = 14073, + MD_ERROR_WIN_SXS_PROTECTION_RECOVERY_FAILED = 14074, + MD_ERROR_WIN_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT = 14075, + MD_ERROR_WIN_SXS_PROTECTION_CATALOG_NOT_VALID = 14076, + MD_ERROR_WIN_SXS_UNTRANSLATABLE_HRESULT = 14077, + MD_ERROR_WIN_SXS_PROTECTION_CATALOG_FILE_MISSING = 14078, + MD_ERROR_WIN_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE = 14079, + MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME = 14080, + MD_ERROR_WIN_SXS_ASSEMBLY_MISSING = 14081, + MD_ERROR_WIN_SXS_CORRUPT_ACTIVATION_STACK = 14082, + MD_ERROR_WIN_SXS_CORRUPTION = 14083, + MD_ERROR_WIN_SXS_EARLY_DEACTIVATION = 14084, + MD_ERROR_WIN_SXS_INVALID_DEACTIVATION = 14085, + MD_ERROR_WIN_SXS_MULTIPLE_DEACTIVATION = 14086, + MD_ERROR_WIN_SXS_PROCESS_TERMINATION_REQUESTED = 14087, + MD_ERROR_WIN_SXS_RELEASE_ACTIVATION_CONTEXT = 14088, + MD_ERROR_WIN_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 14089, + MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 14090, + MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 14091, + MD_ERROR_WIN_SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 14092, + MD_ERROR_WIN_SXS_IDENTITY_PARSE_ERROR = 14093, + MD_ERROR_WIN_MALFORMED_SUBSTITUTION_STRING = 14094, + MD_ERROR_WIN_SXS_INCORRECT_PUBLIC_KEY_TOKEN = 14095, + MD_ERROR_WIN_UNMAPPED_SUBSTITUTION_STRING = 14096, + MD_ERROR_WIN_SXS_ASSEMBLY_NOT_LOCKED = 14097, + MD_ERROR_WIN_SXS_COMPONENT_STORE_CORRUPT = 14098, + MD_ERROR_WIN_ADVANCED_INSTALLER_FAILED = 14099, + MD_ERROR_WIN_XML_ENCODING_MISMATCH = 14100, + MD_ERROR_WIN_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 14101, + MD_ERROR_WIN_SXS_IDENTITIES_DIFFERENT = 14102, + MD_ERROR_WIN_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 14103, + MD_ERROR_WIN_SXS_FILE_NOT_PART_OF_ASSEMBLY = 14104, + MD_ERROR_WIN_SXS_MANIFEST_TOO_BIG = 14105, + MD_ERROR_WIN_SXS_SETTING_NOT_REGISTERED = 14106, + MD_ERROR_WIN_SXS_TRANSACTION_CLOSURE_INCOMPLETE = 14107, + MD_ERROR_WIN_SMI_PRIMITIVE_INSTALLER_FAILED = 14108, + MD_ERROR_WIN_GENERIC_COMMAND_FAILED = 14109, + MD_ERROR_WIN_SXS_FILE_HASH_MISSING = 14110, + MD_ERROR_WIN_SXS_DUPLICATE_ACTIVATABLE_CLASS = 14111, + MD_ERROR_WIN_EVT_INVALID_CHANNEL_PATH = 15000, + MD_ERROR_WIN_EVT_INVALID_QUERY = 15001, + MD_ERROR_WIN_EVT_PUBLISHER_METADATA_NOT_FOUND = 15002, + MD_ERROR_WIN_EVT_EVENT_TEMPLATE_NOT_FOUND = 15003, + MD_ERROR_WIN_EVT_INVALID_PUBLISHER_NAME = 15004, + MD_ERROR_WIN_EVT_INVALID_EVENT_DATA = 15005, + MD_ERROR_WIN_EVT_CHANNEL_NOT_FOUND = 15007, + MD_ERROR_WIN_EVT_MALFORMED_XML_TEXT = 15008, + MD_ERROR_WIN_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL = 15009, + MD_ERROR_WIN_EVT_CONFIGURATION_ERROR = 15010, + MD_ERROR_WIN_EVT_QUERY_RESULT_STALE = 15011, + MD_ERROR_WIN_EVT_QUERY_RESULT_INVALID_POSITION = 15012, + MD_ERROR_WIN_EVT_NON_VALIDATING_MSXML = 15013, + MD_ERROR_WIN_EVT_FILTER_ALREADYSCOPED = 15014, + MD_ERROR_WIN_EVT_FILTER_NOTELTSET = 15015, + MD_ERROR_WIN_EVT_FILTER_INVARG = 15016, + MD_ERROR_WIN_EVT_FILTER_INVTEST = 15017, + MD_ERROR_WIN_EVT_FILTER_INVTYPE = 15018, + MD_ERROR_WIN_EVT_FILTER_PARSEERR = 15019, + MD_ERROR_WIN_EVT_FILTER_UNSUPPORTEDOP = 15020, + MD_ERROR_WIN_EVT_FILTER_UNEXPECTEDTOKEN = 15021, + MD_ERROR_WIN_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL = 15022, + MD_ERROR_WIN_EVT_INVALID_CHANNEL_PROPERTY_VALUE = 15023, + MD_ERROR_WIN_EVT_INVALID_PUBLISHER_PROPERTY_VALUE = 15024, + MD_ERROR_WIN_EVT_CHANNEL_CANNOT_ACTIVATE = 15025, + MD_ERROR_WIN_EVT_FILTER_TOO_COMPLEX = 15026, + MD_ERROR_WIN_EVT_MESSAGE_NOT_FOUND = 15027, + MD_ERROR_WIN_EVT_MESSAGE_ID_NOT_FOUND = 15028, + MD_ERROR_WIN_EVT_UNRESOLVED_VALUE_INSERT = 15029, + MD_ERROR_WIN_EVT_UNRESOLVED_PARAMETER_INSERT = 15030, + MD_ERROR_WIN_EVT_MAX_INSERTS_REACHED = 15031, + MD_ERROR_WIN_EVT_EVENT_DEFINITION_NOT_FOUND = 15032, + MD_ERROR_WIN_EVT_MESSAGE_LOCALE_NOT_FOUND = 15033, + MD_ERROR_WIN_EVT_VERSION_TOO_OLD = 15034, + MD_ERROR_WIN_EVT_VERSION_TOO_NEW = 15035, + MD_ERROR_WIN_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY = 15036, + MD_ERROR_WIN_EVT_PUBLISHER_DISABLED = 15037, + MD_ERROR_WIN_EVT_FILTER_OUT_OF_RANGE = 15038, + MD_ERROR_WIN_EC_SUBSCRIPTION_CANNOT_ACTIVATE = 15080, + MD_ERROR_WIN_EC_LOG_DISABLED = 15081, + MD_ERROR_WIN_EC_CIRCULAR_FORWARDING = 15082, + MD_ERROR_WIN_EC_CREDSTORE_FULL = 15083, + MD_ERROR_WIN_EC_CRED_NOT_FOUND = 15084, + MD_ERROR_WIN_EC_NO_ACTIVE_CHANNEL = 15085, + MD_ERROR_WIN_MUI_FILE_NOT_FOUND = 15100, + MD_ERROR_WIN_MUI_INVALID_FILE = 15101, + MD_ERROR_WIN_MUI_INVALID_RC_CONFIG = 15102, + MD_ERROR_WIN_MUI_INVALID_LOCALE_NAME = 15103, + MD_ERROR_WIN_MUI_INVALID_ULTIMATEFALLBACK_NAME = 15104, + MD_ERROR_WIN_MUI_FILE_NOT_LOADED = 15105, + MD_ERROR_WIN_RESOURCE_ENUM_USER_STOP = 15106, + MD_ERROR_WIN_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED = 15107, + MD_ERROR_WIN_MUI_INTLSETTINGS_INVALID_LOCALE_NAME = 15108, + MD_ERROR_WIN_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE = 15110, + MD_ERROR_WIN_MRM_INVALID_PRICONFIG = 15111, + MD_ERROR_WIN_MRM_INVALID_FILE_TYPE = 15112, + MD_ERROR_WIN_MRM_UNKNOWN_QUALIFIER = 15113, + MD_ERROR_WIN_MRM_INVALID_QUALIFIER_VALUE = 15114, + MD_ERROR_WIN_MRM_NO_CANDIDATE = 15115, + MD_ERROR_WIN_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE = 15116, + MD_ERROR_WIN_MRM_RESOURCE_TYPE_MISMATCH = 15117, + MD_ERROR_WIN_MRM_DUPLICATE_MAP_NAME = 15118, + MD_ERROR_WIN_MRM_DUPLICATE_ENTRY = 15119, + MD_ERROR_WIN_MRM_INVALID_RESOURCE_IDENTIFIER = 15120, + MD_ERROR_WIN_MRM_FILEPATH_TOO_LONG = 15121, + MD_ERROR_WIN_MRM_UNSUPPORTED_DIRECTORY_TYPE = 15122, + MD_ERROR_WIN_MRM_INVALID_PRI_FILE = 15126, + MD_ERROR_WIN_MRM_NAMED_RESOURCE_NOT_FOUND = 15127, + MD_ERROR_WIN_MRM_MAP_NOT_FOUND = 15135, + MD_ERROR_WIN_MRM_UNSUPPORTED_PROFILE_TYPE = 15136, + MD_ERROR_WIN_MRM_INVALID_QUALIFIER_OPERATOR = 15137, + MD_ERROR_WIN_MRM_INDETERMINATE_QUALIFIER_VALUE = 15138, + MD_ERROR_WIN_MRM_AUTOMERGE_ENABLED = 15139, + MD_ERROR_WIN_MRM_TOO_MANY_RESOURCES = 15140, + MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE = 15141, + MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE = 15142, + MD_ERROR_WIN_MRM_NO_CURRENT_VIEW_ON_THREAD = 15143, + MD_ERROR_WIN_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST = 15144, + MD_ERROR_WIN_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT = 15145, + MD_ERROR_WIN_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE = 15146, + MD_ERROR_WIN_MRM_GENERATION_COUNT_MISMATCH = 15147, + MD_ERROR_WIN_PRI_MERGE_VERSION_MISMATCH = 15148, + MD_ERROR_WIN_PRI_MERGE_MISSING_SCHEMA = 15149, + MD_ERROR_WIN_PRI_MERGE_LOAD_FILE_FAILED = 15150, + MD_ERROR_WIN_PRI_MERGE_ADD_FILE_FAILED = 15151, + MD_ERROR_WIN_PRI_MERGE_WRITE_FILE_FAILED = 15152, + MD_ERROR_WIN_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED = 15153, + MD_ERROR_WIN_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED = 15154, + MD_ERROR_WIN_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED = 15155, + MD_ERROR_WIN_PRI_MERGE_MAIN_PACKAGE_REQUIRED = 15156, + MD_ERROR_WIN_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED = 15157, + MD_ERROR_WIN_PRI_MERGE_INVALID_FILE_NAME = 15158, + MD_ERROR_WIN_MRM_PACKAGE_NOT_FOUND = 15159, + MD_ERROR_WIN_MRM_MISSING_DEFAULT_LANGUAGE = 15160, + MD_ERROR_WIN_MCA_INVALID_CAPABILITIES_STRING = 15200, + MD_ERROR_WIN_MCA_INVALID_VCP_VERSION = 15201, + MD_ERROR_WIN_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION = 15202, + MD_ERROR_WIN_MCA_MCCS_VERSION_MISMATCH = 15203, + MD_ERROR_WIN_MCA_UNSUPPORTED_MCCS_VERSION = 15204, + MD_ERROR_WIN_MCA_INTERNAL_ERROR = 15205, + MD_ERROR_WIN_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED = 15206, + MD_ERROR_WIN_MCA_UNSUPPORTED_COLOR_TEMPERATURE = 15207, + MD_ERROR_WIN_AMBIGUOUS_SYSTEM_DEVICE = 15250, + MD_ERROR_WIN_SYSTEM_DEVICE_NOT_FOUND = 15299, + MD_ERROR_WIN_HASH_NOT_SUPPORTED = 15300, + MD_ERROR_WIN_HASH_NOT_PRESENT = 15301, + MD_ERROR_WIN_SECONDARY_IC_PROVIDER_NOT_REGISTERED = 15321, + MD_ERROR_WIN_GPIO_CLIENT_INFORMATION_INVALID = 15322, + MD_ERROR_WIN_GPIO_VERSION_NOT_SUPPORTED = 15323, + MD_ERROR_WIN_GPIO_INVALID_REGISTRATION_PACKET = 15324, + MD_ERROR_WIN_GPIO_OPERATION_DENIED = 15325, + MD_ERROR_WIN_GPIO_INCOMPATIBLE_CONNECT_MODE = 15326, + MD_ERROR_WIN_GPIO_INTERRUPT_ALREADY_UNMASKED = 15327, + MD_ERROR_WIN_CANNOT_SWITCH_RUNLEVEL = 15400, + MD_ERROR_WIN_INVALID_RUNLEVEL_SETTING = 15401, + MD_ERROR_WIN_RUNLEVEL_SWITCH_TIMEOUT = 15402, + MD_ERROR_WIN_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 15403, + MD_ERROR_WIN_RUNLEVEL_SWITCH_IN_PROGRESS = 15404, + MD_ERROR_WIN_SERVICES_FAILED_AUTOSTART = 15405, + MD_ERROR_WIN_COM_TASK_STOP_PENDING = 15501, + MD_ERROR_WIN_INSTALL_OPEN_PACKAGE_FAILED = 15600, + MD_ERROR_WIN_INSTALL_PACKAGE_NOT_FOUND = 15601, + MD_ERROR_WIN_INSTALL_INVALID_PACKAGE = 15602, + MD_ERROR_WIN_INSTALL_RESOLVE_DEPENDENCY_FAILED = 15603, + MD_ERROR_WIN_INSTALL_OUT_OF_DISK_SPACE = 15604, + MD_ERROR_WIN_INSTALL_NETWORK_FAILURE = 15605, + MD_ERROR_WIN_INSTALL_REGISTRATION_FAILURE = 15606, + MD_ERROR_WIN_INSTALL_DEREGISTRATION_FAILURE = 15607, + MD_ERROR_WIN_INSTALL_CANCEL = 15608, + MD_ERROR_WIN_INSTALL_FAILED = 15609, + MD_ERROR_WIN_REMOVE_FAILED = 15610, + MD_ERROR_WIN_PACKAGE_ALREADY_EXISTS = 15611, + MD_ERROR_WIN_NEEDS_REMEDIATION = 15612, + MD_ERROR_WIN_INSTALL_PREREQUISITE_FAILED = 15613, + MD_ERROR_WIN_PACKAGE_REPOSITORY_CORRUPTED = 15614, + MD_ERROR_WIN_INSTALL_POLICY_FAILURE = 15615, + MD_ERROR_WIN_PACKAGE_UPDATING = 15616, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_POLICY = 15617, + MD_ERROR_WIN_PACKAGES_IN_USE = 15618, + MD_ERROR_WIN_RECOVERY_FILE_CORRUPT = 15619, + MD_ERROR_WIN_INVALID_STAGED_SIGNATURE = 15620, + MD_ERROR_WIN_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED = 15621, + MD_ERROR_WIN_INSTALL_PACKAGE_DOWNGRADE = 15622, + MD_ERROR_WIN_SYSTEM_NEEDS_REMEDIATION = 15623, + MD_ERROR_WIN_APPX_INTEGRITY_FAILURE_CLR_NGEN = 15624, + MD_ERROR_WIN_RESILIENCY_FILE_CORRUPT = 15625, + MD_ERROR_WIN_INSTALL_FIREWALL_SERVICE_NOT_RUNNING = 15626, + MD_ERROR_WIN_PACKAGE_MOVE_FAILED = 15627, + MD_ERROR_WIN_INSTALL_VOLUME_NOT_EMPTY = 15628, + MD_ERROR_WIN_INSTALL_VOLUME_OFFLINE = 15629, + MD_ERROR_WIN_INSTALL_VOLUME_CORRUPT = 15630, + MD_ERROR_WIN_NEEDS_REGISTRATION = 15631, + MD_ERROR_WIN_INSTALL_WRONG_PROCESSOR_ARCHITECTURE = 15632, + MD_ERROR_WIN_DEV_SIDELOAD_LIMIT_EXCEEDED = 15633, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE = 15634, + MD_ERROR_WIN_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM = 15635, + MD_ERROR_WIN_PACKAGE_MOVE_BLOCKED_BY_STREAMING = 15636, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE = 15637, + MD_ERROR_WIN_PACKAGE_STAGING_ONHOLD = 15638, + MD_ERROR_WIN_INSTALL_INVALID_RELATED_SET_UPDATE = 15639, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY = 15640, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF = 15641, + MD_ERROR_WIN_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED = 15642, + MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_FAILED = 15643, + MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_TIMEDOUT = 15644, + MD_ERROR_WIN_DEPLOYMENT_OPTION_NOT_SUPPORTED = 15645, + MD_ERROR_WIN_APPINSTALLER_ACTIVATION_BLOCKED = 15646, + MD_ERROR_WIN_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED = 15647, + MD_ERROR_WIN_APPX_RAW_DATA_WRITE_FAILED = 15648, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE = 15649, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE = 15650, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY = 15651, + MD_ERROR_WIN_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY = 15652, + MD_ERROR_WIN_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER = 15653, + MD_ERROR_WIN_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED = 15654, + MD_ERROR_WIN_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE = 15655, + MD_ERROR_WIN_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES = 15656, + MD_ERROR_WIN_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED = 15657, + MD_ERROR_WIN_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST = 15658, + MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_CONTENT = 15659, + MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE = 15660, + MD_ERROR_WIN_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE = 15661, + MD_ERROR_WIN_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED = 15662, + MD_ERROR_WIN_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY = 15663, + MD_ERROR_WIN_STATE_LOAD_STORE_FAILED = 15800, + MD_ERROR_WIN_STATE_GET_VERSION_FAILED = 15801, + MD_ERROR_WIN_STATE_SET_VERSION_FAILED = 15802, + MD_ERROR_WIN_STATE_STRUCTURED_RESET_FAILED = 15803, + MD_ERROR_WIN_STATE_OPEN_CONTAINER_FAILED = 15804, + MD_ERROR_WIN_STATE_CREATE_CONTAINER_FAILED = 15805, + MD_ERROR_WIN_STATE_DELETE_CONTAINER_FAILED = 15806, + MD_ERROR_WIN_STATE_READ_SETTING_FAILED = 15807, + MD_ERROR_WIN_STATE_WRITE_SETTING_FAILED = 15808, + MD_ERROR_WIN_STATE_DELETE_SETTING_FAILED = 15809, + MD_ERROR_WIN_STATE_QUERY_SETTING_FAILED = 15810, + MD_ERROR_WIN_STATE_READ_COMPOSITE_SETTING_FAILED = 15811, + MD_ERROR_WIN_STATE_WRITE_COMPOSITE_SETTING_FAILED = 15812, + MD_ERROR_WIN_STATE_ENUMERATE_CONTAINER_FAILED = 15813, + MD_ERROR_WIN_STATE_ENUMERATE_SETTINGS_FAILED = 15814, + MD_ERROR_WIN_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED = 15815, + MD_ERROR_WIN_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED = 15816, + MD_ERROR_WIN_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED = 15817, + MD_ERROR_WIN_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED = 15818, + MD_ERROR_WIN_API_UNAVAILABLE = 15841, +} MDErrorWin; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_format.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_format.h new file mode 100644 index 0000000000..4155a202dd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_format.h @@ -0,0 +1,1178 @@ +/* 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 + +#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 { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} MDGUID; /* GUID */ + + +/* + * WinNT.h + */ + +/* Non-x86 CPU identifiers found in the high 24 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 */ +/* 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_ALPHA 0x00020000 /* CONTEXT_ALPHA */ + +/* As of Windows 7 SP1, the number of flag bits has increased to + * include 0x40 (CONTEXT_XSTATE): + * http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx */ +#define MD_CONTEXT_CPU_MASK 0xffffff00 + + +/* 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 { + uint32_t context_flags; +} MDRawContextBase; + +#include "minidump_cpu_amd64.h" +#include "minidump_cpu_arm.h" +#include "minidump_cpu_arm64.h" +#include "minidump_cpu_mips.h" +#include "minidump_cpu_ppc.h" +#include "minidump_cpu_ppc64.h" +#include "minidump_cpu_sparc.h" +#include "minidump_cpu_x86.h" + +/* + * WinVer.h + */ + + +typedef struct { + uint32_t signature; + uint32_t struct_version; + uint32_t file_version_hi; + uint32_t file_version_lo; + uint32_t product_version_hi; + uint32_t product_version_lo; + uint32_t file_flags_mask; /* Identifies valid bits in fileFlags */ + uint32_t file_flags; + uint32_t file_os; + uint32_t file_type; + uint32_t file_subtype; + uint32_t file_date_hi; + uint32_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 uint32_t MDRVA; /* RVA */ +typedef uint64_t MDRVA64; /* RVA64 */ + +typedef struct { + uint32_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. */ + uint64_t start_of_memory_range; + + MDLocationDescriptor memory; +} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */ + + +typedef struct { + uint32_t signature; + uint32_t version; + uint32_t stream_count; + MDRVA stream_directory_rva; /* A |stream_count|-sized array of + * MDRawDirectory structures. */ + uint32_t checksum; /* Can be 0. In fact, that's all that's + * been found in minidump files. */ + uint32_t time_date_stamp; /* time_t */ + uint64_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, + MD_WITHOUT_AUXILLIARY_SEGS = 0x00004000, + MD_WITH_FULL_AUXILLIARY_STATE = 0x00008000, + MD_WITH_PRIVATE_WRITE_COPY_MEMORY = 0x00010000, + MD_IGNORE_INACCESSIBLE_MEMORY = 0x00020000, + MD_WITH_TOKEN_INFORMATION = 0x00040000 +} MDType; /* MINIDUMP_TYPE */ + + +typedef struct { + uint32_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_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */ + MD_THREAD_INFO_LIST_STREAM = 17, + MD_HANDLE_OPERATION_LIST_STREAM = 18, + MD_TOKEN_STREAM = 19, + MD_JAVASCRIPT_DATA_STREAM = 20, + MD_SYSTEM_MEMORY_INFO_STREAM = 21, + MD_PROCESS_VM_COUNTERS_STREAM = 22, + MD_IPT_TRACE_STREAM = 23, + MD_THREAD_NAMES_STREAM = 24, + MD_LAST_RESERVED_STREAM = 0x0000ffff, + + /* Breakpad extension types. 0x4767 = "Gg" */ + MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */ + MD_ASSERTION_INFO_STREAM = 0x47670002, /* MDRawAssertionInfo */ + /* These are additional minidump stream values which are specific to + * the linux breakpad implementation. */ + MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */ + MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */ + MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */ + MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */ + MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */ + MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */ + MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */ + MD_LINUX_DSO_DEBUG = 0x4767000A, /* MDRawDebug{32,64} */ + + /* Crashpad extension types. 0x4350 = "CP" + * See Crashpad's minidump/minidump_extensions.h. */ + MD_CRASHPAD_INFO_STREAM = 0x43500001, /* MDRawCrashpadInfo */ + + /* Data from the __DATA,__crash_info section of every module which contains + * one that has useful data. Only available on macOS. 0x4D7A = "Mz". */ + MOZ_MACOS_CRASH_INFO_STREAM = 0x4d7a0001, + + /* The kernel boot args on the machine where the crashed process is + * running. Only available on macOS. 0x4D7A = "Mz". */ + MOZ_MACOS_BOOTARGS_STREAM = 0x4d7a0002, +} MDStreamType; /* MINIDUMP_STREAM_TYPE */ + + +typedef struct { + uint32_t length; /* Length of buffer in bytes (not characters), + * excluding 0-terminator */ + uint16_t buffer[1]; /* UTF-16-encoded, 0-terminated */ +} MDString; /* MINIDUMP_STRING */ + +static const size_t MDString_minsize = offsetof(MDString, buffer[0]); + + +typedef struct { + uint32_t thread_id; + uint32_t suspend_count; + uint32_t priority_class; + uint32_t priority; + uint64_t teb; /* Thread environment block */ + MDMemoryDescriptor stack; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawThread; /* MINIDUMP_THREAD */ + + +typedef struct { + uint32_t number_of_threads; + MDRawThread threads[1]; +} MDRawThreadList; /* MINIDUMP_THREAD_LIST */ + +static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList, + threads[0]); + + +typedef struct { + uint64_t base_of_image; + uint32_t size_of_image; + uint32_t checksum; /* 0 if unknown */ + uint32_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. */ + uint32_t reserved0[2]; + uint32_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 { + uint32_t signature; + uint32_t offset; /* Offset to debug data (expect 0 in minidump) */ +} MDCVHeader; + +typedef struct { + MDCVHeader cv_header; + uint32_t signature; /* time_t debug information created */ + uint32_t age; /* revision of PDB file */ + uint8_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 { + uint32_t cv_signature; + MDGUID signature; /* GUID, identifies PDB file */ + uint32_t age; /* Identifies incremental changes to PDB file */ + uint8_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' */ + +/* + * Modern ELF toolchains insert a "build id" into the ELF headers that + * usually contains a hash of some ELF headers + sections to uniquely + * identify a binary. + * + * https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/compiling-build-id.html + * https://sourceware.org/binutils/docs-2.26/ld/Options.html#index-g_t_002d_002dbuild_002did-292 + */ +typedef struct { + uint32_t cv_signature; + uint8_t build_id[1]; /* Bytes of build id from GNU_BUILD_ID ELF note. + * This is variable-length, but usually 20 bytes + * as the binutils ld default is a SHA-1 hash. */ +} MDCVInfoELF; + +static const size_t MDCVInfoELF_minsize = offsetof(MDCVInfoELF, + build_id[0]); + +#define MD_CVINFOELF_SIGNATURE 0x4270454c /* cvSignature = 'BpEL' */ + +/* 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 { + uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because + * this debug record type is mostly obsolete. */ + uint32_t length; /* Length of entire MDImageDebugMisc structure */ + uint8_t unicode; /* True if data is multibyte */ + uint8_t reserved[3]; + uint8_t data[1]; +} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */ + +static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc, + data[0]); + + +typedef struct { + uint32_t number_of_modules; + MDRawModule modules[1]; +} MDRawModuleList; /* MINIDUMP_MODULE_LIST */ + +static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList, + modules[0]); + + +typedef struct { + uint32_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 { + uint32_t exception_code; /* Windows: MDExceptionCodeWin, + * Mac OS X: MDExceptionMac, + * Linux: MDExceptionCodeLinux. */ + uint32_t exception_flags; /* Windows: 1 if noncontinuable, + Mac OS X: MDExceptionCodeMac. */ + uint64_t exception_record; /* Address (in the minidump-producing host's + * memory) of another MDException, for + * nested exceptions. */ + uint64_t exception_address; /* The address that caused the exception. + * Mac OS X: exception subcode (which is + * typically the address). */ + uint32_t number_parameters; /* Number of valid elements in + * exception_information. */ + uint32_t __align; + uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS]; +} MDException; /* MINIDUMP_EXCEPTION */ + +#include "minidump_exception_fuchsia.h" +#include "minidump_exception_linux.h" +#include "minidump_exception_mac.h" +#include "minidump_exception_ps3.h" +#include "minidump_exception_solaris.h" +#include "minidump_exception_win32.h" + +typedef struct { + uint32_t thread_id; /* Thread in which the exception + * occurred. Corresponds to + * (MDRawThread).thread_id. */ + uint32_t __align; + MDException exception_record; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */ + + +typedef union { + struct { + uint32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ + uint32_t version_information; /* cpuid 1: eax */ + uint32_t feature_information; /* cpuid 1: edx */ + uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ + } x86_cpu_info; + struct { + uint32_t cpuid; + uint32_t elf_hwcaps; /* linux specific, 0 otherwise */ + } arm_cpu_info; + struct { + uint64_t processor_features[2]; + } other_cpu_info; +} MDCPUInformation; /* CPU_INFORMATION */ + +/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps. + * This matches the Linux kernel definitions from */ +typedef enum { + MD_CPU_ARM_ELF_HWCAP_SWP = (1 << 0), + MD_CPU_ARM_ELF_HWCAP_HALF = (1 << 1), + MD_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2), + MD_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3), + MD_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4), + MD_CPU_ARM_ELF_HWCAP_FPA = (1 << 5), + MD_CPU_ARM_ELF_HWCAP_VFP = (1 << 6), + MD_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7), + MD_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8), + MD_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9), + MD_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10), + MD_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11), + MD_CPU_ARM_ELF_HWCAP_NEON = (1 << 12), + MD_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13), + MD_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14), + MD_CPU_ARM_ELF_HWCAP_TLS = (1 << 15), + MD_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16), + MD_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17), + MD_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18), +} MDCPUInformationARMElfHwCaps; + +typedef struct { + /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO + * structure as returned by GetSystemInfo */ + uint16_t processor_architecture; + uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */ + /* ARM: 6 = ARMv6, 7 = ARMv7 ... */ + uint16_t processor_revision; /* x86: 0xMMSS, where MM=model, + * SS=stepping */ + /* ARM: 0 */ + + uint8_t number_of_processors; + uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */ + + /* The next 5 fields are from the OSVERSIONINFO structure as returned + * by GetVersionEx */ + uint32_t major_version; + uint32_t minor_version; + uint32_t build_number; + uint32_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 */ + + uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */ + uint16_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_ARM64 = 12, /* PROCESSOR_ARCHITECTURE_ARM64 */ + MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ + MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ + MD_CPU_ARCHITECTURE_ARM64_OLD = 0x8003, /* Breakpad-defined value for ARM64 */ + MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */ + 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_IOS = 0x8102, /* iOS */ + MD_OS_LINUX = 0x8201, /* Linux */ + MD_OS_SOLARIS = 0x8202, /* Solaris */ + MD_OS_ANDROID = 0x8203, /* Android */ + MD_OS_PS3 = 0x8204, /* PS3 */ + MD_OS_NACL = 0x8205, /* Native Client (NaCl) */ + MD_OS_FUCHSIA = 0x8206 /* Fuchsia */ +} MDOSPlatform; + +typedef struct { + uint64_t base_of_image; + uint32_t size_of_image; + uint32_t checksum; + uint32_t time_date_stamp; + MDRVA module_name_rva; +} MDRawUnloadedModule; + +typedef struct { + uint32_t size_of_header; + uint32_t size_of_entry; + uint32_t number_of_entries; +} MDRawUnloadedModuleList; /* MINIDUMP_UNLOADED_MODULE_LIST */ + +typedef struct { + uint16_t year; + uint16_t month; + uint16_t day_of_week; + uint16_t day; + uint16_t hour; + uint16_t minute; + uint16_t second; + uint16_t milliseconds; +} MDSystemTime; /* SYSTEMTIME */ + +typedef struct { + /* Required field. The bias is the difference, in minutes, between + * Coordinated Universal Time (UTC) and local time. + * Formula: UTC = local time + bias */ + int32_t bias; + /* A description for standard time. For example, "EST" could indicate Eastern + * Standard Time. In practice this contains the full time zone names. This + * string can be empty. */ + uint16_t standard_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from daylight saving time to standard time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero. */ + MDSystemTime standard_date; + /* The bias value to be used during local time translations that occur during + * standard time. */ + int32_t standard_bias; + /* A description for daylight saving time. For example, "PDT" could indicate + * Pacific Daylight Time. In practice this contains the full time zone names. + * This string can be empty. */ + uint16_t daylight_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from standard time to daylight saving time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero.*/ + MDSystemTime daylight_date; + /* The bias value to be used during local time translations that occur during + * daylight saving time. */ + int32_t daylight_bias; +} MDTimeZoneInformation; /* TIME_ZONE_INFORMATION */ + +/* MAX_PATH from windef.h */ +#define MD_MAX_PATH 260 + +/* For MDXStateConfigFeatureMscInfo.features */ +typedef struct { + uint32_t offset; + uint32_t size; +} MDXStateFeature; + +/* For MDXStateConfigFeatureMscInfo.enabled_features from winnt.h */ +typedef enum { + MD_XSTATE_LEGACY_FLOATING_POINT = 0, /* XSTATE_LEGACY_FLOATING_POINT */ + MD_XSTATE_LEGACY_SSE = 1, /* XSTATE_LEGACY_SSE */ + MD_XSTATE_GSSE = 2, /* XSTATE_GSSE */ + MD_XSTATE_AVX = MD_XSTATE_GSSE, /* XSTATE_AVX */ + MD_XSTATE_MPX_BNDREGS = 3, /* XSTATE_MPX_BNDREGS */ + MD_XSTATE_MPX_BNDCSR = 4, /* XSTATE_MPX_BNDCSR */ + MD_XSTATE_AVX512_KMASK = 5, /* XSTATE_AVX512_KMASK */ + MD_XSTATE_AVX512_ZMM_H = 6, /* XSTATE_AVX512_ZMM_H */ + MD_XSTATE_AVX512_ZMM = 7, /* XSTATE_AVX512_ZMM */ + MD_XSTATE_IPT = 8, /* XSTATE_IPT */ + MD_XSTATE_LWP = 62 /* XSTATE_LWP */ +} MDXStateFeatureFlag; + +/* MAXIMUM_XSTATE_FEATURES from winnt.h */ +#define MD_MAXIMUM_XSTATE_FEATURES 64 + +/* For MDRawMiscInfo.xstate_data */ +typedef struct { + uint32_t size_of_info; + uint32_t context_size; + /* An entry in the features array is valid only if the corresponding bit in + * the enabled_features flag is set. */ + uint64_t enabled_features; + MDXStateFeature features[MD_MAXIMUM_XSTATE_FEATURES]; +} MDXStateConfigFeatureMscInfo; + + +/* The miscellaneous information stream contains a variety + * of small pieces of information. A member is valid if + * it's within the available size and its corresponding + * bit is set. */ +typedef struct { + uint32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */ + uint32_t flags1; + + /* The next field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_ID. */ + uint32_t process_id; + + /* The next 3 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_TIMES. */ + uint32_t process_create_time; /* time_t process started */ + uint32_t process_user_time; /* seconds of user CPU time */ + uint32_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 and size_of_info to determine whether these + * values are present. These are only valid when flags1 contains + * MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */ + uint32_t processor_max_mhz; + uint32_t processor_current_mhz; + uint32_t processor_mhz_limit; + uint32_t processor_max_idle_state; + uint32_t processor_current_idle_state; + + /* The following fields are not present in MINIDUMP_MISC_INFO_2 but are + * in MINIDUMP_MISC_INFO_3. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY. */ + uint32_t process_integrity_level; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS. */ + uint32_t process_execute_flags; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROTECTED_PROCESS. */ + uint32_t protected_process; + + /* The following 2 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_TIMEZONE. */ + uint32_t time_zone_id; + MDTimeZoneInformation time_zone; + + /* The following fields are not present in MINIDUMP_MISC_INFO_3 but are + * in MINIDUMP_MISC_INFO_4. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following 2 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_BUILDSTRING. */ + uint16_t build_string[MD_MAX_PATH]; /* UTF-16-encoded, 0-terminated */ + uint16_t dbg_bld_str[40]; /* UTF-16-encoded, 0-terminated */ + + /* The following fields are not present in MINIDUMP_MISC_INFO_4 but are + * in MINIDUMP_MISC_INFO_5. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following field has its own flags for establishing the validity of + * the structure's contents.*/ + MDXStateConfigFeatureMscInfo xstate_data; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_COOKIE. */ + uint32_t process_cookie; +} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO_2, + * MINIDUMP_MISC_INFO_3, MINIDUMP_MISC_INFO_4, + * MINIDUMP_MISC_INFO_5, MINIDUMP_MISC_INFO_N */ + +static const size_t MD_MISCINFO_SIZE = + offsetof(MDRawMiscInfo, processor_max_mhz); +static const size_t MD_MISCINFO2_SIZE = + offsetof(MDRawMiscInfo, process_integrity_level); +static const size_t MD_MISCINFO3_SIZE = + offsetof(MDRawMiscInfo, build_string[0]); +static const size_t MD_MISCINFO4_SIZE = + offsetof(MDRawMiscInfo, xstate_data); +/* Version 5 of the MDRawMiscInfo structure is not a multiple of 8 in size and + * yet it contains some 8-bytes sized fields. This causes many compilers to + * round the structure size up to a multiple of 8 by adding padding at the end. + * The following hack is thus required for matching the proper on-disk size. */ +static const size_t MD_MISCINFO5_SIZE = + offsetof(MDRawMiscInfo, process_cookie) + sizeof(uint32_t); + +/* 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 */ + MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY = 0x00000010, + /* MINIDUMP_MISC3_PROCESS_INTEGRITY */ + MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS = 0x00000020, + /* MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS */ + MD_MISCINFO_FLAGS1_TIMEZONE = 0x00000040, + /* MINIDUMP_MISC3_TIMEZONE */ + MD_MISCINFO_FLAGS1_PROTECTED_PROCESS = 0x00000080, + /* MINIDUMP_MISC3_PROTECTED_PROCESS */ + MD_MISCINFO_FLAGS1_BUILDSTRING = 0x00000100, + /* MINIDUMP_MISC4_BUILDSTRING */ + MD_MISCINFO_FLAGS1_PROCESS_COOKIE = 0x00000200, + /* MINIDUMP_MISC5_PROCESS_COOKIE */ +} MDMiscInfoFlags1; + +/* + * Around DbgHelp version 6.0, the style of new LIST structures changed + * from including an array of length 1 at the end of the struct to + * represent the variable-length data to including explicit + * "size of header", "size of entry" and "number of entries" fields + * in the header, presumably to allow backwards-compatibly-extending + * the structures in the future. The actual list entries follow the + * header data directly in this case. + */ + +typedef struct { + uint32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */ + uint32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */ + uint64_t number_of_entries; +} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */ + +typedef struct { + uint64_t base_address; /* Base address of a region of pages */ + uint64_t allocation_base; /* Base address of a range of pages + * within this region. */ + uint32_t allocation_protection; /* Memory protection when this region + * was originally allocated: + * MDMemoryProtection */ + uint32_t __alignment1; + uint64_t region_size; + uint32_t state; /* MDMemoryState */ + uint32_t protection; /* MDMemoryProtection */ + uint32_t type; /* MDMemoryType */ + uint32_t __alignment2; +} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */ + +/* For (MDRawMemoryInfo).state */ +typedef enum { + MD_MEMORY_STATE_COMMIT = 0x1000, /* physical storage has been allocated */ + MD_MEMORY_STATE_RESERVE = 0x2000, /* reserved, but no physical storage */ + MD_MEMORY_STATE_FREE = 0x10000 /* available to be allocated */ +} MDMemoryState; + +/* For (MDRawMemoryInfo).allocation_protection and .protection */ +typedef enum { + MD_MEMORY_PROTECT_NOACCESS = 0x01, /* PAGE_NOACCESS */ + MD_MEMORY_PROTECT_READONLY = 0x02, /* PAGE_READONLY */ + MD_MEMORY_PROTECT_READWRITE = 0x04, /* PAGE_READWRITE */ + MD_MEMORY_PROTECT_WRITECOPY = 0x08, /* PAGE_WRITECOPY */ + MD_MEMORY_PROTECT_EXECUTE = 0x10, /* PAGE_EXECUTE */ + MD_MEMORY_PROTECT_EXECUTE_READ = 0x20, /* PAGE_EXECUTE_READ */ + MD_MEMORY_PROTECT_EXECUTE_READWRITE = 0x40, /* PAGE_EXECUTE_READWRITE */ + MD_MEMORY_PROTECT_EXECUTE_WRITECOPY = 0x80, /* PAGE_EXECUTE_WRITECOPY */ + /* These options can be combined with the previous flags. */ + MD_MEMORY_PROTECT_GUARD = 0x100, /* PAGE_GUARD */ + MD_MEMORY_PROTECT_NOCACHE = 0x200, /* PAGE_NOCACHE */ + MD_MEMORY_PROTECT_WRITECOMBINE = 0x400, /* PAGE_WRITECOMBINE */ +} MDMemoryProtection; + +/* Used to mask the mutually exclusive options from the combinable flags. */ +const uint32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF; + +/* For (MDRawMemoryInfo).type */ +typedef enum { + MD_MEMORY_TYPE_PRIVATE = 0x20000, /* not shared by other processes */ + MD_MEMORY_TYPE_MAPPED = 0x40000, /* mapped into the view of a section */ + MD_MEMORY_TYPE_IMAGE = 0x1000000 /* mapped into the view of an image */ +} MDMemoryType; + +/* + * Breakpad extension types + */ + + +typedef struct { + /* validity is a bitmask with values from MDBreakpadInfoValidity, indicating + * which of the other fields in the structure are valid. */ + uint32_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. */ + uint32_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. */ + uint32_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. */ + uint16_t expression[128]; /* Assertion that failed... */ + uint16_t function[128]; /* ...within this function... */ + uint16_t file[128]; /* ...in this file... */ + uint32_t line; /* ...at this line. */ + uint32_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; + +/* These structs are used to store the DSO debug data in Linux minidumps, + * which is necessary for converting minidumps to usable coredumps. + * Because of a historical accident, several fields are variably encoded + * according to client word size, so tools potentially need to support both. */ + +typedef struct { + uint32_t addr; + MDRVA name; + uint32_t ld; +} MDRawLinkMap32; + +typedef struct { + uint32_t version; + MDRVA map; /* array of MDRawLinkMap32 */ + uint32_t dso_count; + uint32_t brk; + uint32_t ldbase; + uint32_t dynamic; +} MDRawDebug32; + +typedef struct { + uint64_t addr; + MDRVA name; + uint64_t ld; +} MDRawLinkMap64; + +typedef struct { + uint32_t version; + MDRVA map; /* array of MDRawLinkMap64 */ + uint32_t dso_count; + uint64_t brk; + uint64_t ldbase; + uint64_t dynamic; +} MDRawDebug64; + +/* Crashpad extension types. See Crashpad's minidump/minidump_extensions.h. */ + +typedef struct { + MDRVA key; + MDRVA value; +} MDRawSimpleStringDictionaryEntry; + +typedef struct { + uint32_t count; + MDRawSimpleStringDictionaryEntry entries[0]; +} MDRawSimpleStringDictionary; + +typedef struct { + uint32_t version; + MDLocationDescriptor list_annotations; + MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ +} MDRawModuleCrashpadInfo; + +typedef struct { + uint32_t minidump_module_list_index; + MDLocationDescriptor location; /* MDRawModuleCrashpadInfo */ +} MDRawModuleCrashpadInfoLink; + +typedef struct { + uint32_t count; + MDLocationDescriptor modules[0]; /* MDRawModuleCrashpadInfoLink */ +} MDRawModuleCrashpadInfoList; + +typedef struct { + uint32_t version; + MDGUID report_id; + MDGUID client_id; + MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */ + MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */ +} MDRawCrashpadInfo; + +/* macOS __DATA,__crash_info data */ + +typedef struct { + uint64_t stream_type; /* MOZ_MACOS_CRASH_INFO_STREAM */ + uint64_t version; + uint64_t thread; + uint64_t dialog_mode; + uint64_t abort_cause; /* Only valid when 'version' > 4 */ + /* If/when Apple adds more fields to crashreporter_annotations_t, add + * numerical fields here and change (MDRawMacCrashInfo).record_start_size + * accordingly. Make them all uint64_t, to keep this structure the same size + * on all platforms. 'data' should always be the last field. Add new string + * fields to the end of 'data'. */ + /* 'data' currently contains five null-terminated uint8_t arrays, each + * possibly empty (containing only a single terminal null), stored one after + * the other: + * module_path; + * message; + * signature_string; + * backtrace; + * message2; */ + uint8_t data[0]; +} MDRawMacCrashInfoRecord; + +/* This is the maximum supported size for each string in + * (MDRawMacCrashInfoRecord).data. If we encounter a string in the + * __crash_info section which seems larger than this, that's a sign of data + * corruption. */ +#define MACCRASHINFO_STRING_MAXSIZE 8192 + +/* In principle there should only be one or two non-empty __DATA,__crash_info + * sections per process. But the __crash_info section is almost entirely + * undocumented, so just in case we set a large maximum. */ +#define MAC_CRASH_INFOS_MAX 20 + +typedef struct { + uint32_t stream_type; /* MOZ_MACOS_CRASH_INFO_STREAM */ + uint32_t record_count; + /* The size of the "fixed-size" part of MDRawMacCrashInfoRecord, before the + * 'data' field. This will always be 'sizeof(MDRawMacCrashInfoRecord)'. But + * that value may change if more numerical fields are added to + * MDRawMacCrashInfoRecord in the future. */ + uint32_t record_start_size; + MDLocationDescriptor records[MAC_CRASH_INFOS_MAX]; +} MDRawMacCrashInfo; + +/* macOS kernel boot args */ + +typedef struct __attribute__((packed,aligned(4))) { + uint32_t stream_type; /* MOZ_MACOS_BOOTARGS_STREAM */ + MDRVA64 bootargs; +} MDRawMacBootargs; + +/* Thread names */ + +typedef struct __attribute__((packed,aligned(4))) { + uint32_t thread_id; + MDRVA64 rva_of_thread_name; +} MDRawThreadName; + +typedef struct { + uint32_t number_of_thread_names; + MDRawThreadName thread_names[0]; +} MDRawThreadNamesList; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* _MSC_VER */ + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_size.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_size.h new file mode 100644 index 0000000000..fae57923cc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/common/minidump_size.h @@ -0,0 +1,113 @@ +// 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 + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +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 { + public: + static size_t size() { return MDString_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawThreadList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB20_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB70_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoELF_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDImageDebugMisc_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawModuleList_minsize; } +}; + +template<> +class minidump_size { + 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 { + public: + static size_t size() { return MD_MODULE_SIZE; } +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/basic_source_line_resolver.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/basic_source_line_resolver.h new file mode 100644 index 0000000000..91fb784173 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/basic_source_line_resolver.h @@ -0,0 +1,148 @@ +// Copyright (c) 2010 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_source_line_resolver.h: BasicSourceLineResolver is derived from +// SourceLineResolverBase, and is a concrete implementation of +// SourceLineResolverInterface, using address map files produced by a +// compatible writer, e.g. PDBSourceLineWriter. +// +// see "processor/source_line_resolver_base.h" +// and "source_line_resolver_interface.h" for more documentation. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/source_line_resolver_base.h" + +namespace google_breakpad { + +using std::map; + +class BasicSourceLineResolver : public SourceLineResolverBase { + public: + BasicSourceLineResolver(); + virtual ~BasicSourceLineResolver() { } + + using SourceLineResolverBase::LoadModule; + using SourceLineResolverBase::LoadModuleUsingMapBuffer; + using SourceLineResolverBase::LoadModuleUsingMemoryBuffer; + using SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule; + using SourceLineResolverBase::UnloadModule; + using SourceLineResolverBase::HasModule; + using SourceLineResolverBase::IsModuleCorrupt; + using SourceLineResolverBase::FillSourceLineInfo; + using SourceLineResolverBase::FindWindowsFrameInfo; + using SourceLineResolverBase::FindCFIFrameInfo; + + private: + // friend declarations: + friend class BasicModuleFactory; + friend class ModuleComparer; + friend class ModuleSerializer; + template friend class SimpleSerializer; + + // Function derives from SourceLineResolverBase::Function. + struct Function; + // Module implements SourceLineResolverBase::Module interface. + class Module; + + // Disallow unwanted copy ctor and assignment operator + BasicSourceLineResolver(const BasicSourceLineResolver&); + void operator=(const BasicSourceLineResolver&); +}; + +// Helper class, containing useful methods for parsing of Breakpad symbol files. +class SymbolParseHelper { + public: + // Parses a |file_line| declaration. Returns true on success. + // Format: FILE . + // Notice, that this method modifies the input |file_line| which is why it + // can't be const. On success, , and are stored in |*index|, + // and |*filename|. No allocation is done, |*filename| simply points inside + // |file_line|. + static bool ParseFile(char *file_line, // in + long *index, // out + char **filename); // out + + // Parses a |function_line| declaration. Returns true on success. + // Format: FUNC []
. + // Notice, that this method modifies the input |function_line| which is why it + // can't be const. On success, the presence of ,
, , + // , and are stored in |*is_multiple|, |*address|, + // |*size|, |*stack_param_size|, and |*name|. No allocation is done, |*name| + // simply points inside |function_line|. + static bool ParseFunction(char *function_line, // in + bool *is_multiple, // out + uint64_t *address, // out + uint64_t *size, // out + long *stack_param_size, // out + char **name); // out + + // Parses a |line| declaration. Returns true on success. + // Format:
+ // Notice, that this method modifies the input |function_line| which is why + // it can't be const. On success,
, , , and + // are stored in |*address|, |*size|, |*line_number|, and + // |*source_file|. + static bool ParseLine(char *line_line, // in + uint64_t *address, // out + uint64_t *size, // out + long *line_number, // out + long *source_file); // out + + // Parses a |public_line| declaration. Returns true on success. + // Format: PUBLIC []
+ // Notice, that this method modifies the input |function_line| which is why + // it can't be const. On success, the presence of ,
, + // , are stored in |*is_multiple|, |*address|, + // |*stack_param_size|, and |*name|. No allocation is done, |*name| simply + // points inside |public_line|. + static bool ParsePublicSymbol(char *public_line, // in + bool *is_multiple, // out + uint64_t *address, // out + long *stack_param_size, // out + char **name); // out + + private: + // Used for success checks after strtoull and strtol. + static bool IsValidAfterNumber(char *after_number); + + // Only allow static methods. + SymbolParseHelper(); + SymbolParseHelper(const SymbolParseHelper&); + void operator=(const SymbolParseHelper&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/call_stack.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/call_stack.h new file mode 100644 index 0000000000..bf45e71bd1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/call_stack.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. + +// 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 +#include +#include + +namespace google_breakpad { + +using std::vector; +using std::string; + +struct StackFrame; +template class linked_ptr; + +class CallStack { + public: + CallStack() { Clear(); } + ~CallStack(); + + // Resets the CallStack to its initial empty state + void Clear(); + + const vector* frames() const { return &frames_; } + + // Set the TID associated with this call stack. + void set_tid(uint32_t tid) { tid_ = tid; } + void set_last_error(uint32_t last_error) { last_error_ = last_error; } + void set_name(const string& name) { name_ = name; } + + uint32_t tid() const { return tid_; } + uint32_t last_error() const { return last_error_; } + const string name() const { return name_; } + + private: + // Stackwalker is responsible for building the frames_ vector. + friend class Stackwalker; + + // Storage for pushed frames. + vector frames_; + + // The TID associated with this call stack. Default to 0 if it's not + // available. + uint32_t tid_; + // The last error the OS set for this thread (win32's GetLastError()) + uint32_t last_error_; + // The name of this thread, empty if it's not available + string name_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_module.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_module.h new file mode 100644 index 0000000000..29b8d9c9ab --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_module.h @@ -0,0 +1,104 @@ +// 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 + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +class CodeModule { + public: + virtual ~CodeModule() {} + + // The base address of this code module as it was loaded by the process. + // (uint64_t)-1 on error. + virtual uint64_t base_address() const = 0; + + // The size of the code module. 0 on error. + virtual uint64_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 CodeModule* Copy() const = 0; + + // Getter and setter for shrink_down_delta. This is used when the address + // range for a module is shrunk down due to address range conflicts with + // other modules. The base_address and size fields are not updated and they + // should always reflect the original values (reported in the minidump). + virtual uint64_t shrink_down_delta() const = 0; + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) = 0; + + // Whether the module was unloaded from memory. + virtual bool is_unloaded() const = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_modules.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_modules.h new file mode 100644 index 0000000000..74f113c19c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/code_modules.h @@ -0,0 +1,108 @@ +// 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 + +#include + +#include "google_breakpad/common/breakpad_types.h" +#include "processor/linked_ptr.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(uint64_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; + + // Returns a vector of all modules which address ranges needed to be shrunk + // down due to address range conflicts with other modules. + virtual std::vector > + GetShrunkRangeModules() const = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_context.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_context.h new file mode 100644 index 0000000000..df80bf7ef7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_context.h @@ -0,0 +1,116 @@ +// Copyright (c) 2014 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. + +// dump_context.h: A (mini/micro) dump CPU-specific context. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ + +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/dump_object.h" + +namespace google_breakpad { + +// DumpContext carries a CPU-specific MDRawContext structure, which contains CPU +// context such as register states. +class DumpContext : public DumpObject { + public: + virtual ~DumpContext(); + + // 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. + uint32_t GetContextCPU() const; + + // Return the raw value of |context_flags_| + uint32_t GetContextFlags() 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 MDRawContextAMD64* GetContextAMD64() const; + const MDRawContextARM* GetContextARM() const; + const MDRawContextARM64* GetContextARM64() const; + const MDRawContextMIPS* GetContextMIPS() const; + const MDRawContextPPC* GetContextPPC() const; + const MDRawContextPPC64* GetContextPPC64() const; + const MDRawContextSPARC* GetContextSPARC() const; + const MDRawContextX86* GetContextX86() const; + + // A convenience method to get the instruction pointer out of the + // MDRawContext, since it varies per-CPU architecture. + bool GetInstructionPointer(uint64_t* ip) const; + + // Similar to the GetInstructionPointer method, this method gets the stack + // pointer for all CPU architectures. + bool GetStackPointer(uint64_t* sp) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + DumpContext(); + + // Sets row CPU-specific context data for the names CPU type. + void SetContextFlags(uint32_t context_flags); + void SetContextX86(MDRawContextX86* x86); + void SetContextPPC(MDRawContextPPC* ppc); + void SetContextPPC64(MDRawContextPPC64* ppc64); + void SetContextAMD64(MDRawContextAMD64* amd64); + void SetContextSPARC(MDRawContextSPARC* ctx_sparc); + void SetContextARM(MDRawContextARM* arm); + void SetContextARM64(MDRawContextARM64* arm64); + void SetContextMIPS(MDRawContextMIPS* ctx_mips); + + // Free the CPU-specific context structure. + void FreeContext(); + + private: + // The CPU-specific context structure. + union { + MDRawContextBase* base; + MDRawContextX86* x86; + MDRawContextPPC* ppc; + MDRawContextPPC64* ppc64; + MDRawContextAMD64* amd64; + // on Solaris SPARC, sparc is defined as a numeric constant, + // so variables can NOT be named as sparc + MDRawContextSPARC* ctx_sparc; + MDRawContextARM* arm; + MDRawContextARM64* arm64; + MDRawContextMIPS* ctx_mips; + } context_; + + // Store this separately because of the weirdo AMD64 context + uint32_t context_flags_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_object.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_object.h new file mode 100644 index 0000000000..112f687f4c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/dump_object.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014 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. + +// dump_object.h: A base class for all mini/micro dump object. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ + +namespace google_breakpad { + +// DumpObject is the base of various mini/micro dump's objects. +class DumpObject { + public: + DumpObject(); + + bool valid() const { return valid_; } + + protected: + // DumpObjects 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_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exception_record.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exception_record.h new file mode 100644 index 0000000000..eac6c90ae2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exception_record.h @@ -0,0 +1,124 @@ +// Copyright (c) 2019 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_record.h: A snapshot of an exception record. +// +// Author: Ivan Penkov + +#ifndef THIRD_PARTY_BREAKPAD_SRC_GOOGLE_BREAKPAD_PROCESSOR_EXCEPTION_RECORD_H_ +#define THIRD_PARTY_BREAKPAD_SRC_GOOGLE_BREAKPAD_PROCESSOR_EXCEPTION_RECORD_H_ + +#include + +namespace google_breakpad { + +// Additional argument that describes the exception. +class ExceptionParameter { + public: + ExceptionParameter(uint64_t value, const string& description) + : value_(value), description_(description) {} + // Accessors. See the data declarations below. + uint64_t value() const { return value_; } + void set_value(uint64_t value) { value_ = value; } + const string& description() const { return description_; } + void set_description(const string& description) { + description_ = description; + } + + private: + // Parameter value. + uint64_t value_; + // Human readable description/interpretation of the above value. + string description_; +}; + +// A snapshot of an exception record. Contains exception record details: code, +// flags, address, parameters. +class ExceptionRecord { + public: + // Accessors. See the data declarations below. + uint32_t code() const { return code_; } + const string& code_description() const { return code_description_; } + void set_code(uint32_t code, const string& description) { + code_ = code; + code_description_ = description; + } + + uint32_t flags() const { return flags_; } + const string& flags_description() const { return flags_description_; } + void set_flags(uint32_t flags, const string& description) { + flags_ = flags; + flags_description_ = description; + } + + uint64_t nested_exception_record_address() const { + return nested_exception_record_address_; + } + void set_nested_exception_record_address( + uint64_t nested_exception_record_address) { + nested_exception_record_address_ = nested_exception_record_address; + } + + uint64_t address() const { return address_; } + void set_address(uint64_t address) { address_ = address; } + + const std::vector* parameters() const { + return ¶meters_; + } + void add_parameter(uint64_t value, const string& description) { + parameters_.push_back(ExceptionParameter(value, description)); + } + + private: + // Exception code. + uint32_t code_; + string code_description_; + + // Exception flags. + uint32_t flags_; + string flags_description_; + + // The address of an associated MDException structure. Exception records can + // be chained together to provide additional information when nested + // exceptions occur. + uint64_t nested_exception_record_address_; + + // The memory address that caused the exception. 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. + uint64_t address_; + + // An array of additional arguments that describe the exception. + std::vector parameters_; +}; + +} // namespace google_breakpad + + +#endif // THIRD_PARTY_BREAKPAD_SRC_GOOGLE_BREAKPAD_PROCESSOR_EXCEPTION_RECORD_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exploitability.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exploitability.h new file mode 100644 index 0000000000..014413c944 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/exploitability.h @@ -0,0 +1,82 @@ +// Copyright (c) 2010 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. + +// exploitability_engine.h: Generic exploitability engine. +// +// The Exploitability class is an abstract base class providing common +// generic methods that apply to exploitability engines for specific platforms. +// Specific implementations will extend this class by providing run +// methods to fill in the exploitability_ enumeration of the ProcessState +// for a crash. +// +// Author: Cris Neckar + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/process_state.h" + +namespace google_breakpad { + +class Exploitability { + public: + virtual ~Exploitability() {} + + static Exploitability *ExploitabilityForPlatform(Minidump *dump, + ProcessState *process_state); + + // The boolean parameter signals whether the exploitability engine is + // enabled to call out to objdump for disassembly. This is disabled by + // default. It is used to check the identity of the instruction that + // caused the program to crash. This should not be enabled if there are + // portability concerns. + static Exploitability *ExploitabilityForPlatform(Minidump *dump, + ProcessState *process_state, + bool enable_objdump); + + ExploitabilityRating CheckExploitability(); + bool AddressIsAscii(uint64_t); + + protected: + Exploitability(Minidump *dump, + ProcessState *process_state); + + Minidump *dump_; + ProcessState *process_state_; + SystemInfo *system_info_; + + private: + virtual ExploitabilityRating CheckPlatformExploitability() = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/fast_source_line_resolver.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/fast_source_line_resolver.h new file mode 100644 index 0000000000..fdf9107766 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/fast_source_line_resolver.h @@ -0,0 +1,100 @@ +// Copyright (c) 2010 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. +// +// fast_source_line_resolver.h: FastSourceLineResolver is derived from +// SourceLineResolverBase, and is a concrete implementation of +// SourceLineResolverInterface. +// +// FastSourceLineResolver is a sibling class of BasicSourceLineResolver. The +// difference is FastSourceLineResolver loads a serialized memory chunk of data +// which can be used directly a Module without parsing or copying of underlying +// data. Therefore loading a symbol in FastSourceLineResolver is much faster +// and more memory-efficient than BasicSourceLineResolver. +// +// See "source_line_resolver_base.h" and +// "google_breakpad/source_line_resolver_interface.h" for more reference. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ + +#include +#include + +#include "google_breakpad/processor/source_line_resolver_base.h" + +namespace google_breakpad { + +using std::map; + +class FastSourceLineResolver : public SourceLineResolverBase { + public: + FastSourceLineResolver(); + virtual ~FastSourceLineResolver() { } + + using SourceLineResolverBase::FillSourceLineInfo; + using SourceLineResolverBase::FindCFIFrameInfo; + using SourceLineResolverBase::FindWindowsFrameInfo; + using SourceLineResolverBase::HasModule; + using SourceLineResolverBase::IsModuleCorrupt; + using SourceLineResolverBase::LoadModule; + using SourceLineResolverBase::LoadModuleUsingMapBuffer; + using SourceLineResolverBase::LoadModuleUsingMemoryBuffer; + using SourceLineResolverBase::UnloadModule; + + private: + // Friend declarations. + friend class ModuleComparer; + friend class ModuleSerializer; + friend class FastModuleFactory; + + // Nested types that will derive from corresponding nested types defined in + // SourceLineResolverBase. + struct Line; + struct Function; + struct PublicSymbol; + class Module; + + // Deserialize raw memory data to construct a WindowsFrameInfo object. + static WindowsFrameInfo CopyWFI(const char *raw_memory); + + // FastSourceLineResolver requires the memory buffer stays alive during the + // lifetime of a corresponding module, therefore it needs to redefine this + // virtual method. + virtual bool ShouldDeleteMemoryBufferAfterLoadModule(); + + // Disallow unwanted copy ctor and assignment operator + FastSourceLineResolver(const FastSourceLineResolver&); + void operator=(const FastSourceLineResolver&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/memory_region.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/memory_region.h new file mode 100644 index 0000000000..30f88df490 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/memory_region.h @@ -0,0 +1,79 @@ +// Copyright (c) 2010 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 uint64_t GetBase() const = 0; + + // The size of this memory region. + virtual uint32_t GetSize() const = 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(uint64_t address, uint8_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const = 0; + + // Print a human-readable representation of the object to stdout. + virtual void Print() const = 0; +}; + + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump.h new file mode 100644 index 0000000000..02ebdcd79b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump.h @@ -0,0 +1,135 @@ +// Copyright (c) 2014 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. + +// microdump.h: A microdump reader. Microdump is a minified variant of a +// minidump (see minidump.h for documentation) which contains the minimum +// amount of information required to get a stack trace for the crashing thread. +// The information contained in a microdump is: +// - the crashing thread stack +// - system information (os type / version) +// - cpu context (state of the registers) +// - list of mmaps + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ + +#include +#include + +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/basic_code_modules.h" + +namespace google_breakpad { + +// MicrodumpModuleList contains all of the loaded code modules for a process +// in the form of MicrodumpModules. It maintains a vector of these modules +// and provides access to a code module corresponding to a specific address. +class MicrodumpModules : public BasicCodeModules { + public: + // Takes over ownership of |module|. + void Add(const CodeModule* module); + + // Enables/disables module address range shrink. + void SetEnableModuleShrink(bool is_enabled); +}; + +// MicrodumpContext carries a CPU-specific context. +// See dump_context.h for documentation. +class MicrodumpContext : public DumpContext { + public: + virtual void SetContextARM(MDRawContextARM* arm); + virtual void SetContextARM64(MDRawContextARM64* arm64); + virtual void SetContextX86(MDRawContextX86* x86); + virtual void SetContextMIPS(MDRawContextMIPS* mips32); + virtual void SetContextMIPS64(MDRawContextMIPS* mips64); +}; + +// This class provides access to microdump memory regions. +// See memory_region.h for documentation. +class MicrodumpMemoryRegion : public MemoryRegion { + public: + MicrodumpMemoryRegion(); + virtual ~MicrodumpMemoryRegion() {} + + // Set this region's address and contents. If we have placed an + // instance of this class in a test fixture class, individual tests + // can use this to provide the region's contents. + void Init(uint64_t base_address, const std::vector& contents); + + virtual uint64_t GetBase() const; + virtual uint32_t GetSize() const; + + virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + + // Print a human-readable representation of the object to stdout. + virtual void Print() const; + + private: + // Fetch a little-endian value from ADDRESS in contents_ whose size + // is BYTES, and store it in *VALUE. Returns true on success. + template + bool GetMemoryLittleEndian(uint64_t address, ValueType* value) const; + + uint64_t base_address_; + std::vector contents_; +}; + +// Microdump is the user's interface to a microdump file. It provides access to +// the microdump's context, memory regions and modules. +class Microdump { + public: + explicit Microdump(const string& contents); + virtual ~Microdump() {} + + DumpContext* GetContext() { return context_.get(); } + MicrodumpMemoryRegion* GetMemory() { return stack_region_.get(); } + MicrodumpModules* GetModules() { return modules_.get(); } + SystemInfo* GetSystemInfo() { return system_info_.get(); } + + string GetCrashReason() { return crash_reason_; } + uint64_t GetCrashAddress() { return crash_address_; } + private: + scoped_ptr context_; + scoped_ptr stack_region_; + scoped_ptr modules_; + scoped_ptr system_info_; + string crash_reason_; + uint64_t crash_address_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump_processor.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump_processor.h new file mode 100644 index 0000000000..60d14a541f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/microdump_processor.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014, 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 processor for microdump (a reduced dump containing only the state of the +// crashing thread). See crbug.com/410294 for more info and design docs. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/process_result.h" + +namespace google_breakpad { + +class Microdump; +class ProcessState; +class StackFrameSymbolizer; + +class MicrodumpProcessor { + public: + // Initializes the MicrodumpProcessor with a stack frame symbolizer. + // Does not take ownership of frame_symbolizer, which must NOT be NULL. + explicit MicrodumpProcessor(StackFrameSymbolizer* frame_symbolizer); + + virtual ~MicrodumpProcessor(); + + // Processes the microdump contents and fills process_state with the result. + google_breakpad::ProcessResult Process(Microdump* microdump, + ProcessState* process_state); + private: + StackFrameSymbolizer* frame_symbolizer_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump.h new file mode 100644 index 0000000000..b2eab95d8a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump.h @@ -0,0 +1,1498 @@ +// Copyright (c) 2010 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 + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include +#include + +#include "common/basictypes.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/dump_object.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/proc_maps_linux.h" + + +namespace google_breakpad { + + +using std::map; +using std::vector; + + +class Minidump; +template class RangeMap; + + +// MinidumpObject is the base of all Minidump* objects except for Minidump +// itself. +class MinidumpObject : public DumpObject { + public: + virtual ~MinidumpObject() {} + + 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_; +}; + + +// 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 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(uint32_t expected_size) = 0; + + DISALLOW_COPY_AND_ASSIGN(MinidumpStream); +}; + + +// 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 DumpContext { + public: + virtual ~MinidumpContext(); + + protected: + explicit MinidumpContext(Minidump* minidump); + + private: + friend class MinidumpThread; + friend class MinidumpException; + + bool Read(uint32_t expected_size); + + // 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(uint32_t context_cpu_type); + + // 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_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpContext); +}; + + +// 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(uint32_t max_bytes) { max_bytes_ = max_bytes; } + static uint32_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 uint8_t* GetMemory() const; + + // The address of the base of the memory region. + uint64_t GetBase() const; + + // The size, in bytes, of the memory region. + uint32_t GetSize() const; + + // Frees the cached memory region, if cached. + void FreeMemory(); + + // Obtains the value of memory at the pointer specified by address. + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + + // Print a human-readable representation of the object to stdout. + void Print() const; + void SetPrintMode(bool hexdump, unsigned int width); + + protected: + explicit MinidumpMemoryRegion(Minidump* minidump); + + private: + friend class MinidumpThread; + friend class MinidumpMemoryList; + + // 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 bool GetMemoryAtAddressInternal(uint64_t address, + T* value) const; + + // Knobs for controlling display of memory printing. + bool hexdump_; + unsigned int hexdump_width_; + + // The largest memory region that will be read from a minidump. + static uint32_t max_bytes_; + + // Base address and size of the memory region, and its position in the + // minidump file. + MDMemoryDescriptor* descriptor_; + + // Cached memory. + mutable vector* 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. +// Note that a MinidumpThread may be valid() even if it does not +// contain a memory region or context. +class MinidumpThread : public MinidumpObject { + public: + virtual ~MinidumpThread(); + + const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } + // GetMemory may return NULL even if the MinidumpThread is valid, + // if the thread memory cannot be read. + virtual MinidumpMemoryRegion* GetMemory(); + // Corresponds to win32's GetLastError function, which records the last + // error value set by the OS for this thread. A more useful error message + // can be produced by passing this value to FormatMessage: + // + // https://docs.microsoft.com/windows/win32/debug/retrieving-the-last-error-code + // + // The value may also be looked up in Microsoft's System Error Codes listing: + // + // https://docs.microsoft.com/windows/win32/debug/system-error-codes + virtual uint32_t GetLastError(); + // GetContext may return NULL even if the MinidumpThread is valid. + virtual 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. + virtual bool GetThreadID(uint32_t *thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + // Returns the start address of the thread stack memory region. Returns 0 if + // MinidumpThread is invalid. Note that this method can be called even when + // the thread memory cannot be read and GetMemory returns NULL. + virtual uint64_t GetStartOfStackMemoryRange() const; + + protected: + explicit MinidumpThread(Minidump* minidump); + + private: + // These objects are managed by MinidumpThreadList. + friend class MinidumpThreadList; + + // 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(uint32_t max_threads) { + max_threads_ = max_threads; + } + static uint32_t max_threads() { return max_threads_; } + + virtual unsigned int thread_count() const { + return valid_ ? thread_count_ : 0; + } + + // Sequential access to threads. + virtual MinidumpThread* GetThreadAtIndex(unsigned int index) const; + + // Random access to threads. + MinidumpThread* GetThreadByID(uint32_t thread_id); + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpThreadList(Minidump* aMinidump); + + private: + friend class Minidump; + + typedef map IDToThreadMap; + typedef vector MinidumpThreads; + + static const uint32_t kStreamType = MD_THREAD_LIST_STREAM; + + bool Read(uint32_t aExpectedSize) override; + + // The largest number of threads that will be read from a minidump. The + // default is 256. + static uint32_t max_threads_; + + // Access to threads using the thread ID as the key. + IDToThreadMap id_to_thread_map_; + + // The list of threads. + MinidumpThreads* threads_; + uint32_t thread_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList); +}; + + +// 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(uint32_t max_cv_bytes) { + max_cv_bytes_ = max_cv_bytes; + } + static uint32_t max_cv_bytes() { return max_cv_bytes_; } + + static void set_max_misc_bytes(uint32_t max_misc_bytes) { + max_misc_bytes_ = max_misc_bytes; + } + static uint32_t max_misc_bytes() { return max_misc_bytes_; } + + const MDRawModule* module() const { return valid_ ? &module_ : NULL; } + + // CodeModule implementation + virtual uint64_t base_address() const { + return valid_ ? module_.base_of_image : static_cast(-1); + } + virtual uint64_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 CodeModule* Copy() const; + virtual bool is_unloaded() const { return false; } + + // Getter and setter for shrink_down_delta. This is used when the address + // range for a module is shrunk down due to address range conflicts with + // other modules. The base_address and size fields are not updated and they + // should always reflect the original values (reported in the minidump). + virtual uint64_t shrink_down_delta() const; + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta); + + // The CodeView record, which contains information to locate the module's + // debugging information (pdb). This is returned as uint8_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 uint8_t* GetCVRecord(uint32_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(uint32_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 uint32_t max_cv_bytes_; + static uint32_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 uint8_t + // because the structure contains a variable-sized string and its exact + // size cannot be known until it is processed. + vector* 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. + uint32_t cv_record_signature_; + + // Cached MDImageDebugMisc (usually not present), stored as uint8_t + // because the structure contains a variable-sized string and its exact + // size cannot be known until it is processed. + vector* 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(uint32_t max_modules) { + max_modules_ = max_modules; + } + static uint32_t max_modules() { return max_modules_; } + + // CodeModules implementation. + virtual unsigned int module_count() const { + return valid_ ? module_count_ : 0; + } + virtual const MinidumpModule* GetModuleForAddress(uint64_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; + + // Returns a vector of all modules which address ranges needed to be shrunk + // down due to address range conflicts with other modules. + virtual vector > GetShrunkRangeModules() const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpModuleList(Minidump* minidump); + + private: + friend class Minidump; + + typedef vector MinidumpModules; + + static const uint32_t kStreamType = MD_MODULE_LIST_STREAM; + + bool Read(uint32_t expected_size); + + bool StoreRange(const MinidumpModule& module, + uint64_t base_address, + uint32_t module_index, + uint32_t module_count, + bool is_android); + + // The largest number of modules that will be read from a minidump. The + // default is 1024. + static uint32_t max_modules_; + + // Access to modules using addresses as the key. + RangeMap *range_map_; + + MinidumpModules *modules_; + uint32_t module_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList); +}; + + +// 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(uint32_t max_regions) { + max_regions_ = max_regions; + } + static uint32_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. + virtual MinidumpMemoryRegion* GetMemoryRegionForAddress(uint64_t address); + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + friend class MockMinidumpMemoryList; + + typedef vector MemoryDescriptors; + typedef vector MemoryRegions; + + static const uint32_t kStreamType = MD_MEMORY_LIST_STREAM; + + explicit MinidumpMemoryList(Minidump* minidump); + + bool Read(uint32_t expected_size) override; + + // The largest number of memory regions that will be read from a minidump. + // The default is 256. + static uint32_t max_regions_; + + // Access to memory regions using addresses as the key. + RangeMap *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_; + uint32_t region_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList); +}; + + +// 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(uint32_t *thread_id) const; + + MinidumpContext* GetContext(); + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_EXCEPTION_STREAM; + + explicit MinidumpException(Minidump* minidump); + + bool Read(uint32_t expected_size) override; + + MDRawExceptionStream exception_; + MinidumpContext* context_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpException); +}; + +// MinidumpAssertion wraps MDRawAssertionInfo, which contains information +// about an assertion that caused the minidump to be generated. +class MinidumpAssertion : public MinidumpStream { + public: + virtual ~MinidumpAssertion(); + + const MDRawAssertionInfo* assertion() const { + return valid_ ? &assertion_ : NULL; + } + + string expression() const { + return valid_ ? expression_ : ""; + } + + string function() const { + return valid_ ? function_ : ""; + } + + string file() const { + return valid_ ? file_ : ""; + } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_ASSERTION_INFO_STREAM; + + explicit MinidumpAssertion(Minidump* minidump); + + bool Read(uint32_t expected_size) override; + + MDRawAssertionInfo assertion_; + string expression_; + string function_; + string file_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpAssertion); +}; + + +// 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(); + + protected: + explicit MinidumpSystemInfo(Minidump* minidump); + MDRawSystemInfo system_info_; + + // Textual representation of the OS service pack, for minidumps produced + // by MiniDumpWriteDump on Windows. + const string* csd_version_; + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_SYSTEM_INFO_STREAM; + + bool Read(uint32_t expected_size) override; + + // A string identifying the CPU vendor, if known. + const string* cpu_vendor_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpSystemInfo); +}; + + +// MinidumpUnloadedModule wraps MDRawUnloadedModule +class MinidumpUnloadedModule : public MinidumpObject, + public CodeModule { + public: + ~MinidumpUnloadedModule() override; + + const MDRawUnloadedModule* module() const { + return valid_ ? &unloaded_module_ : NULL; + } + + // CodeModule implementation + uint64_t base_address() const override { + return valid_ ? unloaded_module_.base_of_image : 0; + } + uint64_t size() const override { + return valid_ ? unloaded_module_.size_of_image : 0; + } + string code_file() const override; + string code_identifier() const override; + string debug_file() const override; + string debug_identifier() const override; + string version() const override; + CodeModule* Copy() const override; + bool is_unloaded() const override { return true; } + uint64_t shrink_down_delta() const override; + void SetShrinkDownDelta(uint64_t shrink_down_delta) override; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpUnloadedModule(Minidump* minidump); + + private: + // These objects are managed by MinidumpUnloadedModuleList + friend class MinidumpUnloadedModuleList; + + // This works like MinidumpStream::Read, but is driven by + // MinidumpUnloadedModuleList. + bool Read(uint32_t expected_size); + + // Reads the module name. This is done separately from Read to + // allow contiguous reading of code modules by MinidumpUnloadedModuleList. + bool ReadAuxiliaryData(); + + // 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_; + + MDRawUnloadedModule unloaded_module_; + + // Cached module name + const string* name_; +}; + + +// MinidumpUnloadedModuleList contains all the unloaded code modules for a +// process in the form of MinidumpUnloadedModules. It maintains a map of +// these modules so that it may easily provide a code module corresponding +// to a specific address. If multiple modules in the list have identical +// ranges, only the first module encountered is recorded in the range map. +class MinidumpUnloadedModuleList : public MinidumpStream, + public CodeModules { + public: + ~MinidumpUnloadedModuleList() override; + + static void set_max_modules(uint32_t max_modules) { + max_modules_ = max_modules; + } + static uint32_t max_modules() { return max_modules_; } + + // CodeModules implementation. + unsigned int module_count() const override { + return valid_ ? module_count_ : 0; + } + const MinidumpUnloadedModule* + GetModuleForAddress(uint64_t address) const override; + const MinidumpUnloadedModule* GetMainModule() const override; + const MinidumpUnloadedModule* + GetModuleAtSequence(unsigned int sequence) const override; + const MinidumpUnloadedModule* + GetModuleAtIndex(unsigned int index) const override; + const CodeModules* Copy() const override; + vector> GetShrunkRangeModules() const override; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpUnloadedModuleList(Minidump* minidump_); + + private: + friend class Minidump; + + typedef vector MinidumpUnloadedModules; + + static const uint32_t kStreamType = MD_UNLOADED_MODULE_LIST_STREAM; + + bool Read(uint32_t expected_size_) override; + + // The largest number of modules that will be read from a minidump. The + // default is 1024. + static uint32_t max_modules_; + + // Access to module indices using addresses as the key. + RangeMap *range_map_; + + MinidumpUnloadedModules *unloaded_modules_; + uint32_t module_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList); +}; + + +// 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; + friend class TestMinidumpMiscInfo; + + static const uint32_t kStreamType = MD_MISC_INFO_STREAM; + + explicit MinidumpMiscInfo(Minidump* minidump_); + + bool Read(uint32_t expected_size_) override; + + MDRawMiscInfo misc_info_; + + // Populated by Read. Contains the converted strings from the corresponding + // UTF-16 fields in misc_info_ + string standard_name_; + string daylight_name_; + string build_string_; + string dbg_bld_str_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfo); +}; + + +// 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(uint32_t *thread_id) const; + bool GetRequestingThreadID(uint32_t *thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_BREAKPAD_INFO_STREAM; + + explicit MinidumpBreakpadInfo(Minidump* minidump_); + + bool Read(uint32_t expected_size_) override; + + MDRawBreakpadInfo breakpad_info_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpBreakpadInfo); +}; + +// MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information +// about mapped memory regions in a process, including their ranges +// and protection. +class MinidumpMemoryInfo : public MinidumpObject { + public: + const MDRawMemoryInfo* info() const { return valid_ ? &memory_info_ : NULL; } + + // The address of the base of the memory region. + uint64_t GetBase() const { return valid_ ? memory_info_.base_address : 0; } + + // The size, in bytes, of the memory region. + uint64_t GetSize() const { return valid_ ? memory_info_.region_size : 0; } + + // Return true if the memory protection allows execution. + bool IsExecutable() const; + + // Return true if the memory protection allows writing. + bool IsWritable() const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + // These objects are managed by MinidumpMemoryInfoList. + friend class MinidumpMemoryInfoList; + + explicit MinidumpMemoryInfo(Minidump* minidump_); + + // This works like MinidumpStream::Read, but is driven by + // MinidumpMemoryInfoList. No size checking is done, because + // MinidumpMemoryInfoList handles that directly. + bool Read(); + + MDRawMemoryInfo memory_info_; +}; + +// MinidumpMemoryInfoList contains a list of information about +// mapped memory regions for a process in the form of MDRawMemoryInfo. +// It maintains a map of these structures so that it may easily provide +// info corresponding to a specific address. +class MinidumpMemoryInfoList : public MinidumpStream { + public: + virtual ~MinidumpMemoryInfoList(); + + unsigned int info_count() const { return valid_ ? info_count_ : 0; } + + const MinidumpMemoryInfo* GetMemoryInfoForAddress(uint64_t address) const; + const MinidumpMemoryInfo* GetMemoryInfoAtIndex(unsigned int index) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + typedef vector MinidumpMemoryInfos; + + static const uint32_t kStreamType = MD_MEMORY_INFO_LIST_STREAM; + + explicit MinidumpMemoryInfoList(Minidump* minidump_); + + bool Read(uint32_t expected_size) override; + + // Access to memory info using addresses as the key. + RangeMap *range_map_; + + MinidumpMemoryInfos* infos_; + uint32_t info_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryInfoList); +}; + +// MinidumpLinuxMaps wraps information about a single mapped memory region +// from /proc/self/maps. +class MinidumpLinuxMaps : public MinidumpObject { + public: + // The memory address of the base of the mapped region. + uint64_t GetBase() const { return valid_ ? region_.start : 0; } + // The size of the mapped region. + uint64_t GetSize() const { return valid_ ? region_.end - region_.start : 0; } + + // The permissions of the mapped region. + bool IsReadable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::READ : false; + } + bool IsWriteable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::WRITE : false; + } + bool IsExecutable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::EXECUTE : false; + } + bool IsPrivate() const { + return valid_ ? region_.permissions & MappedMemoryRegion::PRIVATE : false; + } + + // The offset of the mapped region. + uint64_t GetOffset() const { return valid_ ? region_.offset : 0; } + + // The major device number. + uint8_t GetMajorDevice() const { return valid_ ? region_.major_device : 0; } + // The minor device number. + uint8_t GetMinorDevice() const { return valid_ ? region_.minor_device : 0; } + + // The inode of the mapped region. + uint64_t GetInode() const { return valid_ ? region_.inode : 0; } + + // The pathname of the mapped region. + const string GetPathname() const { return valid_ ? region_.path : ""; } + + // Print the contents of this mapping. + void Print() const; + + private: + // These objects are managed by MinidumpLinuxMapsList. + friend class MinidumpLinuxMapsList; + + // This caller owns the pointer. + explicit MinidumpLinuxMaps(Minidump *minidump); + + // The memory region struct that this class wraps. + MappedMemoryRegion region_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMaps); +}; + +// MinidumpLinuxMapsList corresponds to the Linux-exclusive MD_LINUX_MAPS +// stream, which contains the contents of /prod/self/maps, which contains +// the mapped memory regions and their access permissions. +class MinidumpLinuxMapsList : public MinidumpStream { + public: + virtual ~MinidumpLinuxMapsList(); + + // Get number of mappings. + unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } + + // Get mapping at the given memory address. The caller owns the pointer. + const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const; + // Get mapping at the given index. The caller owns the pointer. + const MinidumpLinuxMaps *GetLinuxMapsAtIndex(unsigned int index) const; + + // Print the contents of /proc/self/maps to stdout. + void Print() const; + + private: + friend class Minidump; + + typedef vector MinidumpLinuxMappings; + + static const uint32_t kStreamType = MD_LINUX_MAPS; + + // The caller owns the pointer. + explicit MinidumpLinuxMapsList(Minidump *minidump); + + // Read and load the contents of the process mapping data. + // The stream should have data in the form of /proc/self/maps. + // This method returns whether the stream was read successfully. + bool Read(uint32_t expected_size) override; + + // The list of individual mappings. + MinidumpLinuxMappings *maps_; + // The number of mappings. + uint32_t maps_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList); +}; + +// MinidumpCrashpadInfo wraps MDRawCrashpadInfo, which is an optional stream in +// a minidump that provides additional information about the process state +// at the time the minidump was generated. +class MinidumpCrashpadInfo : public MinidumpStream { + public: + const MDRawCrashpadInfo* crashpad_info() const { + return valid_ ? &crashpad_info_ : NULL; + } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_CRASHPAD_INFO_STREAM; + + explicit MinidumpCrashpadInfo(Minidump* minidump_); + + bool Read(uint32_t expected_size); + + MDRawCrashpadInfo crashpad_info_; + std::vector module_crashpad_info_links_; + std::vector module_crashpad_info_; + std::vector> module_crashpad_info_list_annotations_; + std::vector> + module_crashpad_info_simple_annotations_; + std::map simple_annotations_; +}; + +// MinidumpMacCrashInfo wraps MDRawMacCrashInfo. It's an optional stream +// in a minidump that records information from the __DATA,__crash_info +// section of every module in the crashing process that contains one, and +// which isn't empty of useful information. Only present on macOS. + +// Friendly wrapper for the information in MDRawMacCrashInfoRecord. +typedef struct crash_info_record { + string module_path; + unsigned long version; + string message; + string signature_string; + string backtrace; + string message2; + unsigned long long thread; + unsigned int dialog_mode; + long long abort_cause; // Only valid when 'version' > 4 + crash_info_record() + : version(0), thread(0), dialog_mode(0), abort_cause(0) + {} +} crash_info_record_t; + +class MinidumpMacCrashInfo : public MinidumpStream { + public: + // A human-readable representation of the data from the __DATA,__crash_info + // sections in all of the crashing process's modules that have one, if + // it's not empty of useful data. Suitable for use by "minidump_stackwalk". + string description() const { return description_; } + // A "machine-readable" copy of the same information, suitable for use by + // "minidump_stalkwalk -m". + vector const records() { + return records_; + } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MOZ_MACOS_CRASH_INFO_STREAM; + + explicit MinidumpMacCrashInfo(Minidump* minidump_); + + bool ReadCrashInfoRecord(MDLocationDescriptor location, + uint32_t record_start_size); + bool Read(uint32_t expected_size); + + string description_; + vector records_; +}; + +// MinidumpThreadName wraps MDRawThreadName +class MinidumpThreadName : public MinidumpObject { + public: + ~MinidumpThreadName() override; + + const MDRawThreadName* thread_name() const { + if (valid_) { + return &thread_name_; + } + + return NULL; + } + + uint32_t thread_id() const { + if (valid_) { + return thread_name_.thread_id; + } + + return 0; + } + + string name() const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpThreadName(Minidump* minidump); + + private: + // These objects are managed by MinidumpThreadNameList + friend class MinidumpThreadNamesList; + + // This works like MinidumpStream::Read, but is driven by + // MinidumpThreadNameList. + bool Read(uint32_t expected_size); + + // Reads the thread name. This is done separately from Read to + // allow contiguous reading of thread names by MinidumpThreadNameList. + bool ReadAuxiliaryData(); + + bool valid_; + MDRawThreadName thread_name_; + const string* name_; +}; + + +// MinidumpThreadNamesList contains all the names for threads in a process +// in the form of MinidumpThreadNames. +class MinidumpThreadNamesList : public MinidumpStream { + public: + ~MinidumpThreadNamesList() override; + + unsigned int name_count() const { + return valid_ ? name_count_ : 0; + } + + const string GetNameForThreadId(uint32_t thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpThreadNamesList(Minidump* minidump_); + + private: + friend class Minidump; + + typedef vector MinidumpThreadNames; + + static const uint32_t kStreamType = MD_THREAD_NAMES_STREAM; + + bool Read(uint32_t expected_size_) override; + + MinidumpThreadNames* thread_names_; + uint32_t name_count_; + bool valid_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpThreadNamesList); +}; + +// 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, + bool hexdump=false, + unsigned int hexdump_width=16); + // input is an istream wrapping minidump data. Minidump holds a + // weak pointer to input, and the caller must ensure that the stream + // is valid as long as the Minidump object is. + explicit Minidump(std::istream& input); + + virtual ~Minidump(); + + // path may be empty if the minidump was not opened from a file + virtual string path() const { + return path_; + } + static void set_max_streams(uint32_t max_streams) { + max_streams_ = max_streams; + } + static uint32_t max_streams() { return max_streams_; } + + static void set_max_string_length(uint32_t max_string_length) { + max_string_length_ = max_string_length; + } + static uint32_t max_string_length() { return max_string_length_; } + + virtual const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } + + // Reads the CPU information from the system info stream and generates the + // appropriate CPU flags. The returned context_cpu_flags are the same as + // if the CPU type bits were set in the context_flags of a context record. + // On success, context_cpu_flags will have the flags that identify the CPU. + // If a system info stream is missing, context_cpu_flags will be 0. + // Returns true if the current position in the stream was not changed. + // Returns false when the current location in the stream was changed and the + // attempt to restore the original position failed. + bool GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags); + + // 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. + virtual 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). + virtual MinidumpThreadList* GetThreadList(); + virtual MinidumpModuleList* GetModuleList(); + virtual MinidumpMemoryList* GetMemoryList(); + virtual MinidumpException* GetException(); + virtual MinidumpAssertion* GetAssertion(); + virtual MinidumpSystemInfo* GetSystemInfo(); + virtual MinidumpUnloadedModuleList* GetUnloadedModuleList(); + virtual MinidumpMiscInfo* GetMiscInfo(); + virtual MinidumpBreakpadInfo* GetBreakpadInfo(); + virtual MinidumpMemoryInfoList* GetMemoryInfoList(); + MinidumpCrashpadInfo* GetCrashpadInfo(); + MinidumpMacCrashInfo* GetMacCrashInfo(); + MinidumpThreadNamesList* GetThreadNamesList(); + + // The next method also calls GetStream, but is exclusive for Linux dumps. + virtual MinidumpLinuxMapsList *GetLinuxMapsList(); + + // 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(); + + // 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); + + bool ReadUTF8String(off_t offset, string* string_utf8); + + bool ReadStringList(off_t offset, std::vector* string_list); + + bool ReadSimpleStringDictionary( + off_t offset, + std::map* simple_string_dictionary); + + // 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(uint32_t stream_type, uint32_t* stream_length); + + bool swap() const { return valid_ ? swap_ : false; } + + bool is_big_endian() const { return valid_ ? is_big_endian_ : false; } + + // Print a human-readable representation of the object to stdout. + void Print(); + + // Is the OS Android. + bool IsAndroid(); + + // Determines the platform where the minidump was produced. |platform| is + // valid iff this method returns true. + bool GetPlatform(MDOSPlatform* platform); + + // Get current hexdump display settings. + unsigned int HexdumpMode() const { return hexdump_ ? hexdump_width_ : 0; } + + 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 MinidumpDirectoryEntries; + typedef map MinidumpStreamMap; + + template 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 uint32_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. + // This may be empty if the minidump was opened directly from a stream. + const string path_; + + // The stream for all file I/O. Used by ReadBytes and SeekSet. + // Set based on the path in Open, or directly in the constructor. + std::istream* stream_; + + // 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_; + + // true if the minidump was produced by a big-endian cpu. + bool is_big_endian_; + + // Validity of the Minidump structure, false immediately after + // construction or after a failed Read(); true following a successful + // Read(). + bool valid_; + + // Knobs for controlling display of memory printing. + bool hexdump_; + unsigned int hexdump_width_; + + DISALLOW_COPY_AND_ASSIGN(Minidump); +}; + + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump_processor.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump_processor.h new file mode 100644 index 0000000000..387115ef71 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/minidump_processor.h @@ -0,0 +1,147 @@ +// 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 +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/process_result.h" + +namespace google_breakpad { + +class Minidump; +class ProcessState; +class StackFrameSymbolizer; +class SourceLineResolverInterface; +class SymbolSupplier; +struct SystemInfo; + +class MinidumpProcessor { + public: + // Initializes this MinidumpProcessor. supplier should be an + // implementation of the SymbolSupplier abstract base class. + MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver); + + // Initializes the MinidumpProcessor with the option of + // enabling the exploitability framework to analyze dumps + // for probable security relevance. + MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver, + bool enable_exploitability); + + // Initializes the MinidumpProcessor with source line resolver helper, and + // the option of enabling the exploitability framework to analyze dumps + // for probable security relevance. + // Does not take ownership of resolver_helper, which must NOT be NULL. + MinidumpProcessor(StackFrameSymbolizer* stack_frame_symbolizer, + bool enable_exploitability); + + ~MinidumpProcessor(); + + // Processes the minidump file and fills process_state with the result. + ProcessResult Process(const string &minidump_file, + ProcessState* process_state); + + // Processes the minidump structure and fills process_state with the + // result. + ProcessResult Process(Minidump* minidump, + 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); + + // Populates the |process_create_time| parameter with the create time of the + // crashed process. Returns false if this information is not available in + // the minidump |dump|. + static bool GetProcessCreateTime(Minidump* dump, + uint32_t* process_create_time); + + // 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, uint64_t* address); + + // This function returns true if the passed-in error code is + // something unrecoverable(i.e. retry should not happen). For + // instance, if the minidump is corrupt, then it makes no sense to + // retry as we won't be able to glean additional information. + // However, as an example of the other case, the symbol supplier can + // return an error code indicating it was 'interrupted', which can + // happen of the symbols are fetched from a remote store, and a + // retry might be successful later on. + // You should not call this method with PROCESS_OK! Test for + // that separately before calling this. + static bool IsErrorUnrecoverable(ProcessResult p) { + assert(p != PROCESS_OK); + return (p != PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); + } + + // Returns a textual representation of an assertion included + // in the minidump. Returns an empty string if this information + // does not exist or cannot be determined. + static string GetAssertion(Minidump* dump); + + void set_enable_objdump(bool enabled) { enable_objdump_ = enabled; } + + private: + StackFrameSymbolizer* frame_symbolizer_; + // Indicate whether resolver_helper_ is owned by this instance. + bool own_frame_symbolizer_; + + // This flag enables the exploitability scanner which attempts to + // guess how likely it is that the crash represents an exploitable + // memory corruption issue. + bool enable_exploitability_; + + // This flag permits the exploitability scanner to shell out to objdump + // for purposes of disassembly. + bool enable_objdump_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/proc_maps_linux.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/proc_maps_linux.h new file mode 100644 index 0000000000..3045daa5f6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/proc_maps_linux.h @@ -0,0 +1,60 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_ +#define BASE_DEBUG_PROC_MAPS_LINUX_H_ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// Describes a region of mapped memory and the path of the file mapped. +struct MappedMemoryRegion { + enum Permission { + READ = 1 << 0, + WRITE = 1 << 1, + EXECUTE = 1 << 2, + PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared. + }; + + // The address range [start,end) of mapped memory. + uint64_t start; + uint64_t end; + + // Byte offset into |path| of the range mapped into memory. + uint64_t offset; + + // Bitmask of read/write/execute/private/shared permissions. + uint8_t permissions; + + // Major and minor devices. + uint8_t major_device; + uint8_t minor_device; + + // Value of the inode. + uint64_t inode; + + // Name of the file mapped into memory. + // + // NOTE: path names aren't guaranteed to point at valid files. For example, + // "[heap]" and "[stack]" are used to represent the location of the process' + // heap and stack, respectively. + string path; + + // The line from /proc//maps that this struct represents. + string line; +}; + +// Parses /proc//maps input data and stores in |regions|. Returns true +// and updates |regions| if and only if all of |input| was successfully parsed. +bool ParseProcMaps(const string& input, + std::vector* regions); + +} // namespace google_breakpad + +#endif // BASE_DEBUG_PROC_MAPS_LINUX_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_result.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_result.h new file mode 100644 index 0000000000..15c7213e9b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_result.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014, 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_PROCESS_RESULT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_PROCESS_RESULT_H__ + +namespace google_breakpad { + +// Return type for MinidumpProcessor or MicrodumpProcessor's Process() +enum ProcessResult { + PROCESS_OK, // The dump was processed + // successfully. + + PROCESS_ERROR_MINIDUMP_NOT_FOUND, // The minidump file was not + // found. + + PROCESS_ERROR_NO_MINIDUMP_HEADER, // The minidump file had no + // header. + + PROCESS_ERROR_NO_THREAD_LIST, // The minidump file has no + // thread list. + + PROCESS_ERROR_GETTING_THREAD, // There was an error getting one + // thread's data from th dump. + + PROCESS_ERROR_GETTING_THREAD_ID, // There was an error getting a + // thread id from the thread's + // data. + + PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS, // There was more than one + // requesting thread. + + PROCESS_SYMBOL_SUPPLIER_INTERRUPTED // The dump processing was + // interrupted by the + // SymbolSupplier(not fatal). +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_PROCESS_RESULT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_state.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_state.h new file mode 100644 index 0000000000..37b208ecbe --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/process_state.h @@ -0,0 +1,220 @@ +// 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 +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/exception_record.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/linked_ptr.h" + +namespace google_breakpad { + +using std::vector; + +class CallStack; +class CodeModules; + +enum ExploitabilityRating { + EXPLOITABILITY_HIGH, // The crash likely represents + // a exploitable memory corruption + // vulnerability. + + EXPLOITABILITY_MEDIUM, // The crash appears to corrupt + // memory in a way which may be + // exploitable in some situations. + + EXPLOITABLITY_MEDIUM = EXPLOITABILITY_MEDIUM, // an old misspelling + + EXPLOITABILITY_LOW, // The crash either does not corrupt + // memory directly or control over + // the affected data is limited. The + // issue may still be exploitable + // on certain platforms or situations. + + EXPLOITABILITY_INTERESTING, // The crash does not appear to be + // directly exploitable. However it + // represents a condition which should + // be further analyzed. + + EXPLOITABILITY_NONE, // The crash does not appear to represent + // an exploitable condition. + + EXPLOITABILITY_NOT_ANALYZED, // The crash was not analyzed for + // exploitability because the engine + // was disabled. + + EXPLOITABILITY_ERR_NOENGINE, // The supplied minidump's platform does + // not have a exploitability engine + // associated with it. + + EXPLOITABILITY_ERR_PROCESSING // An error occured within the + // exploitability engine and no rating + // was calculated. +}; + +class ProcessState { + public: + ProcessState() : modules_(NULL), unloaded_modules_(NULL) { Clear(); } + ~ProcessState(); + + // Resets the ProcessState to its default values + void Clear(); + + // Accessors. See the data declarations below. + uint32_t time_date_stamp() const { return time_date_stamp_; } + uint32_t process_create_time() const { return process_create_time_; } + bool crashed() const { return crashed_; } + string crash_reason() const { return crash_reason_; } + uint64_t crash_address() const { return crash_address_; } + string assertion() const { return assertion_; } + int requesting_thread() const { return requesting_thread_; } + const ExceptionRecord* exception_record() const { return &exception_record_; } + const vector* threads() const { return &threads_; } + const vector* thread_memory_regions() const { + return &thread_memory_regions_; + } + const SystemInfo* system_info() const { return &system_info_; } + string mac_crash_info() const { return mac_crash_info_; } + size_t mac_crash_info_records_count() const { + return mac_crash_info_records_.size(); + } + const crash_info_record_t* mac_crash_info_records() const { + return reinterpret_cast( + &mac_crash_info_records_[0]); + } + const CodeModules* modules() const { return modules_; } + const CodeModules* unloaded_modules() const { return unloaded_modules_; } + const vector >* shrunk_range_modules() const { + return &shrunk_range_modules_; + } + const vector* modules_without_symbols() const { + return &modules_without_symbols_; + } + const vector* modules_with_corrupt_symbols() const { + return &modules_with_corrupt_symbols_; + } + ExploitabilityRating exploitability() const { return exploitability_; } + + private: + // MinidumpProcessor and MicrodumpProcessor are responsible for building + // ProcessState objects. + friend class MinidumpProcessor; + friend class MicrodumpProcessor; + + // The time-date stamp of the minidump (time_t format) + uint32_t time_date_stamp_; + + // The time-date stamp when the process was created (time_t format) + uint32_t process_create_time_; + + // 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. + uint64_t crash_address_; + + // If there was an assertion that was hit, a textual representation + // of that assertion, possibly including the file and line at which + // it occurred. + string assertion_; + + // 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_; + + // Exception record details: code, flags, address, parameters. + ExceptionRecord exception_record_; + + // Stacks for each thread (except possibly the exception handler + // thread) at the time of the crash. + vector threads_; + vector thread_memory_regions_; + + // OS and CPU information. + SystemInfo system_info_; + + // Information from __DATA,__crash_info sections. Only present on macOS. + string mac_crash_info_; + vector mac_crash_info_records_; + + // The modules that were loaded into the process represented by the + // ProcessState. + const CodeModules *modules_; + + // The modules that have been unloaded from the process represented by the + // ProcessState. + const CodeModules *unloaded_modules_; + + // The modules which virtual address ranges were shrunk down due to + // virtual address conflicts. + vector > shrunk_range_modules_; + + // The modules that didn't have symbols when the report was processed. + vector modules_without_symbols_; + + // The modules that had corrupt symbols when the report was processed. + vector modules_with_corrupt_symbols_; + + // The exploitability rating as determined by the exploitability + // engine. When the exploitability engine is not enabled this + // defaults to EXPLOITABILITY_NOT_ANALYZED. + ExploitabilityRating exploitability_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_base.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_base.h new file mode 100644 index 0000000000..c720b0c325 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_base.h @@ -0,0 +1,128 @@ +// Copyright (c) 2010 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. +// +// source_line_resolver_base.h: SourceLineResolverBase, an (incomplete) +// implementation of SourceLineResolverInterface. It serves as a common base +// class for concrete implementations: FastSourceLineResolver and +// BasicSourceLineResolver. It is designed for refactoring that removes +// code redundancy in the two concrete source line resolver classes. +// +// See "google_breakpad/processor/source_line_resolver_interface.h" for more +// documentation. + +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ + +#include +#include +#include + +#include "google_breakpad/processor/source_line_resolver_interface.h" + +namespace google_breakpad { + +using std::map; +using std::set; + +// Forward declaration. +// ModuleFactory is a simple factory interface for creating a Module instance +// at run-time. +class ModuleFactory; + +class SourceLineResolverBase : public SourceLineResolverInterface { + public: + // Read the symbol_data from a file with given file_name. + // The part of code was originally in BasicSourceLineResolver::Module's + // LoadMap() method. + // Place dynamically allocated heap buffer in symbol_data. Caller has the + // ownership of the buffer, and should call delete [] to free the buffer. + static bool ReadSymbolFile(const string &file_name, + char **symbol_data, + size_t *symbol_data_size); + + protected: + // Users are not allowed create SourceLineResolverBase instance directly. + SourceLineResolverBase(ModuleFactory *module_factory); + virtual ~SourceLineResolverBase(); + + // Virtual methods inherited from SourceLineResolverInterface. + virtual bool LoadModule(const CodeModule *module, const string &map_file); + virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, + const string &map_buffer); + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, + char *memory_buffer, + size_t memory_buffer_size); + virtual bool ShouldDeleteMemoryBufferAfterLoadModule(); + virtual void UnloadModule(const CodeModule *module); + virtual bool HasModule(const CodeModule *module); + virtual bool IsModuleCorrupt(const CodeModule *module); + virtual void FillSourceLineInfo(StackFrame *frame); + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame); + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame); + + // Nested structs and classes. + struct Line; + struct Function; + struct PublicSymbol; + struct CompareString { + bool operator()(const string &s1, const string &s2) const; + }; + // Module is an interface for an in-memory symbol file. + class Module; + class AutoFileCloser; + + // All of the modules that are loaded. + typedef map ModuleMap; + ModuleMap *modules_; + + // The loaded modules that were detecting to be corrupt during load. + typedef set ModuleSet; + ModuleSet *corrupt_modules_; + + // All of heap-allocated buffers that are owned locally by resolver. + typedef std::map MemoryMap; + MemoryMap *memory_buffers_; + + // Creates a concrete module at run-time. + ModuleFactory *module_factory_; + + private: + // ModuleFactory needs to have access to protected type Module. + friend class ModuleFactory; + + // Disallow unwanted copy ctor and assignment operator + SourceLineResolverBase(const SourceLineResolverBase&); + void operator=(const SourceLineResolverBase&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_interface.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_interface.h new file mode 100644 index 0000000000..a694bf2ea1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/source_line_resolver_interface.h @@ -0,0 +1,117 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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 + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_module.h" + +namespace google_breakpad { + +struct StackFrame; +struct WindowsFrameInfo; +class CFIFrameInfo; + +class SourceLineResolverInterface { + public: + typedef uint64_t MemAddr; + + virtual ~SourceLineResolverInterface() {} + + // Adds a module to this resolver, returning true on success. + // + // module should have at least the code_file, debug_file, + // and debug_identifier members populated. + // + // map_file should contain line/address mappings for this module. + virtual bool LoadModule(const CodeModule *module, + const string &map_file) = 0; + // Same as above, but takes the contents of a pre-read map buffer + virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, + const string &map_buffer) = 0; + + // Add an interface to load symbol using C-String data instead of string. + // This is useful in the optimization design for avoiding unnecessary copying + // of symbol data, in order to improve memory efficiency. + // LoadModuleUsingMemoryBuffer() does NOT take ownership of memory_buffer. + // LoadModuleUsingMemoryBuffer() null terminates the passed in buffer, if + // the last character is not a null terminator. + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, + char *memory_buffer, + size_t memory_buffer_size) = 0; + + // Return true if the memory buffer should be deleted immediately after + // LoadModuleUsingMemoryBuffer(). Return false if the memory buffer has to be + // alive during the lifetime of the corresponding Module. + virtual bool ShouldDeleteMemoryBufferAfterLoadModule() = 0; + + // Request that the specified module be unloaded from this resolver. + // A resolver may choose to ignore such a request. + virtual void UnloadModule(const CodeModule *module) = 0; + + // Returns true if the module has been loaded. + virtual bool HasModule(const CodeModule *module) = 0; + + // Returns true if the module has been loaded and it is corrupt. + virtual bool IsModuleCorrupt(const CodeModule *module) = 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. + virtual void FillSourceLineInfo(StackFrame *frame) = 0; + + // If Windows stack walking information is available covering + // FRAME's instruction address, return a WindowsFrameInfo structure + // describing it. If the information is not available, returns NULL. + // A NULL return value does not indicate an error. The caller takes + // ownership of any returned WindowsFrameInfo object. + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) = 0; + + // If CFI stack walking information is available covering ADDRESS, + // return a CFIFrameInfo structure describing it. If the information + // is not available, return NULL. The caller takes ownership of any + // returned CFIFrameInfo object. + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) = 0; + + protected: + // SourceLineResolverInterface cannot be instantiated except by subclasses + SourceLineResolverInterface() {} +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h new file mode 100644 index 0000000000..1491d78825 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h @@ -0,0 +1,144 @@ +// 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 + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +class CodeModule; + +struct StackFrame { + // Indicates how well the instruction pointer derived during + // stack walking is trusted. Since the stack walker can resort to + // stack scanning, it can wind up with dubious frames. + // In rough order of "trust metric". + enum FrameTrust { + FRAME_TRUST_NONE, // Unknown + FRAME_TRUST_SCAN, // Scanned the stack, found this + FRAME_TRUST_CFI_SCAN, // Found while scanning stack using call frame info + FRAME_TRUST_FP, // Derived from frame pointer + FRAME_TRUST_CFI, // Derived from call frame info + FRAME_TRUST_PREWALKED, // Explicitly provided by some external stack walker. + FRAME_TRUST_CONTEXT // Given as instruction pointer in a context + }; + + StackFrame() + : instruction(), + module(NULL), + function_name(), + function_base(), + source_file_name(), + source_line(), + source_line_base(), + trust(FRAME_TRUST_NONE) {} + virtual ~StackFrame() {} + + // Return a string describing how this stack frame was found + // by the stackwalker. + string trust_description() const { + switch (trust) { + case StackFrame::FRAME_TRUST_CONTEXT: + return "given as instruction pointer in context"; + case StackFrame::FRAME_TRUST_PREWALKED: + return "recovered by external stack walker"; + case StackFrame::FRAME_TRUST_CFI: + return "call frame info"; + case StackFrame::FRAME_TRUST_CFI_SCAN: + return "call frame info with scanning"; + case StackFrame::FRAME_TRUST_FP: + return "previous frame's frame pointer"; + case StackFrame::FRAME_TRUST_SCAN: + return "stack scanning"; + default: + return "unknown"; + } + } + + // Return the actual return address, as saved on the stack or in a + // register. See the comments for 'instruction', below, for details. + virtual uint64_t ReturnAddress() const { return instruction; } + + // 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 address is within the instruction that + // caused execution to branch to this frame's callee (although it may + // not point to the exact beginning of that instruction). This ensures + // that, when we look up the source code location for this frame, we + // get the source location of the call, not of the point at which + // control will resume when the call returns, which may be on the next + // line. (If the compiler knows the callee never returns, it may even + // place the call instruction at the very end of the caller's machine + // code, such that the "return address" (which will never be used) + // immediately after the call instruction is in an entirely different + // function, perhaps even from a different source file.) + // + // On some architectures, the return address as saved on the stack or in + // a register is fine for looking up the point of the call. On others, it + // requires adjustment. ReturnAddress returns the address as saved by the + // machine. + uint64_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. + uint64_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. + uint64_t source_line_base; + + // Amount of trust the stack walker has in the instruction pointer + // of this frame. + FrameTrust trust; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_cpu.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_cpu.h new file mode 100644 index 0000000000..dc5d8ae673 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_cpu.h @@ -0,0 +1,405 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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 WindowsFrameInfo; +class CFIFrameInfo; + +struct StackFrameX86 : public StackFrame { + // ContextValidity has one entry for each relevant hardware pointer + // register (%eip and %esp) and one entry for each general-purpose + // register. It's worthwhile having validity flags for caller-saves + // registers: they are valid in the youngest frame, and such a frame + // might save a callee-saves register in a caller-saves register, but + // SimpleCFIWalker won't touch registers unless they're marked as valid. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_EIP = 1 << 0, + CONTEXT_VALID_ESP = 1 << 1, + CONTEXT_VALID_EBP = 1 << 2, + CONTEXT_VALID_EAX = 1 << 3, + CONTEXT_VALID_EBX = 1 << 4, + CONTEXT_VALID_ECX = 1 << 5, + CONTEXT_VALID_EDX = 1 << 6, + CONTEXT_VALID_ESI = 1 << 7, + CONTEXT_VALID_EDI = 1 << 8, + CONTEXT_VALID_ALL = -1 + }; + + StackFrameX86() + : context(), + context_validity(CONTEXT_VALID_NONE), + windows_frame_info(NULL), + cfi_frame_info(NULL) {} + ~StackFrameX86(); + + // Overriden to return the return address as saved on the stack. + virtual uint64_t ReturnAddress() const; + + // 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; + + // Any stack walking information we found describing this.instruction. + // These may be NULL if there is no such information for that address. + WindowsFrameInfo *windows_frame_info; + CFIFrameInfo *cfi_frame_info; +}; + +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 StackFramePPC64 : 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 + }; + + StackFramePPC64() : 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. + MDRawContextPPC64 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 register that we might be able + // to recover. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_RAX = 1 << 0, + CONTEXT_VALID_RDX = 1 << 1, + CONTEXT_VALID_RCX = 1 << 2, + CONTEXT_VALID_RBX = 1 << 3, + CONTEXT_VALID_RSI = 1 << 4, + CONTEXT_VALID_RDI = 1 << 5, + CONTEXT_VALID_RBP = 1 << 6, + CONTEXT_VALID_RSP = 1 << 7, + CONTEXT_VALID_R8 = 1 << 8, + CONTEXT_VALID_R9 = 1 << 9, + CONTEXT_VALID_R10 = 1 << 10, + CONTEXT_VALID_R11 = 1 << 11, + CONTEXT_VALID_R12 = 1 << 12, + CONTEXT_VALID_R13 = 1 << 13, + CONTEXT_VALID_R14 = 1 << 14, + CONTEXT_VALID_R15 = 1 << 15, + CONTEXT_VALID_RIP = 1 << 16, + CONTEXT_VALID_ALL = -1 + }; + + StackFrameAMD64() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Overriden to return the return address as saved on the stack. + virtual uint64_t ReturnAddress() const; + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information we had available. Refer to context_validity. + MDRawContextAMD64 context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + // + // context_validity's type should actually be ContextValidity, but + // we use int instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + 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; +}; + +struct StackFrameARM : public StackFrame { + // A flag for each register we might know. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_R0 = 1 << 0, + CONTEXT_VALID_R1 = 1 << 1, + CONTEXT_VALID_R2 = 1 << 2, + CONTEXT_VALID_R3 = 1 << 3, + CONTEXT_VALID_R4 = 1 << 4, + CONTEXT_VALID_R5 = 1 << 5, + CONTEXT_VALID_R6 = 1 << 6, + CONTEXT_VALID_R7 = 1 << 7, + CONTEXT_VALID_R8 = 1 << 8, + CONTEXT_VALID_R9 = 1 << 9, + CONTEXT_VALID_R10 = 1 << 10, + CONTEXT_VALID_R11 = 1 << 11, + CONTEXT_VALID_R12 = 1 << 12, + CONTEXT_VALID_R13 = 1 << 13, + CONTEXT_VALID_R14 = 1 << 14, + CONTEXT_VALID_R15 = 1 << 15, + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE, + + // Aliases for registers with dedicated or conventional roles. + CONTEXT_VALID_FP = CONTEXT_VALID_R11, + CONTEXT_VALID_SP = CONTEXT_VALID_R13, + CONTEXT_VALID_LR = CONTEXT_VALID_R14, + CONTEXT_VALID_PC = CONTEXT_VALID_R15 + }; + + StackFrameARM() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Return the ContextValidity flag for register rN. + static ContextValidity RegisterValidFlag(int n) { + return ContextValidity(1 << n); + } + + // 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. + MDRawContextARM context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + // + // context_validity's type should actually be ContextValidity, but + // we use int instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +struct StackFrameARM64 : public StackFrame { + // A flag for each register we might know. Note that we can't use an enum + // here as there are 33 values to represent. + static const uint64_t CONTEXT_VALID_NONE = 0; + static const uint64_t CONTEXT_VALID_X0 = 1ULL << 0; + static const uint64_t CONTEXT_VALID_X1 = 1ULL << 1; + static const uint64_t CONTEXT_VALID_X2 = 1ULL << 2; + static const uint64_t CONTEXT_VALID_X3 = 1ULL << 3; + static const uint64_t CONTEXT_VALID_X4 = 1ULL << 4; + static const uint64_t CONTEXT_VALID_X5 = 1ULL << 5; + static const uint64_t CONTEXT_VALID_X6 = 1ULL << 6; + static const uint64_t CONTEXT_VALID_X7 = 1ULL << 7; + static const uint64_t CONTEXT_VALID_X8 = 1ULL << 8; + static const uint64_t CONTEXT_VALID_X9 = 1ULL << 9; + static const uint64_t CONTEXT_VALID_X10 = 1ULL << 10; + static const uint64_t CONTEXT_VALID_X11 = 1ULL << 11; + static const uint64_t CONTEXT_VALID_X12 = 1ULL << 12; + static const uint64_t CONTEXT_VALID_X13 = 1ULL << 13; + static const uint64_t CONTEXT_VALID_X14 = 1ULL << 14; + static const uint64_t CONTEXT_VALID_X15 = 1ULL << 15; + static const uint64_t CONTEXT_VALID_X16 = 1ULL << 16; + static const uint64_t CONTEXT_VALID_X17 = 1ULL << 17; + static const uint64_t CONTEXT_VALID_X18 = 1ULL << 18; + static const uint64_t CONTEXT_VALID_X19 = 1ULL << 19; + static const uint64_t CONTEXT_VALID_X20 = 1ULL << 20; + static const uint64_t CONTEXT_VALID_X21 = 1ULL << 21; + static const uint64_t CONTEXT_VALID_X22 = 1ULL << 22; + static const uint64_t CONTEXT_VALID_X23 = 1ULL << 23; + static const uint64_t CONTEXT_VALID_X24 = 1ULL << 24; + static const uint64_t CONTEXT_VALID_X25 = 1ULL << 25; + static const uint64_t CONTEXT_VALID_X26 = 1ULL << 26; + static const uint64_t CONTEXT_VALID_X27 = 1ULL << 27; + static const uint64_t CONTEXT_VALID_X28 = 1ULL << 28; + static const uint64_t CONTEXT_VALID_X29 = 1ULL << 29; + static const uint64_t CONTEXT_VALID_X30 = 1ULL << 30; + static const uint64_t CONTEXT_VALID_X31 = 1ULL << 31; + static const uint64_t CONTEXT_VALID_X32 = 1ULL << 32; + static const uint64_t CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE; + + // Aliases for registers with dedicated or conventional roles. + static const uint64_t CONTEXT_VALID_FP = CONTEXT_VALID_X29; + static const uint64_t CONTEXT_VALID_LR = CONTEXT_VALID_X30; + static const uint64_t CONTEXT_VALID_SP = CONTEXT_VALID_X31; + static const uint64_t CONTEXT_VALID_PC = CONTEXT_VALID_X32; + + StackFrameARM64() : context(), + context_validity(CONTEXT_VALID_NONE) {} + + // Return the validity flag for register xN. + static uint64_t RegisterValidFlag(int n) { + return 1ULL << n; + } + + // 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. + MDRawContextARM64 context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + uint64_t context_validity; +}; + +struct StackFrameMIPS : public StackFrame { + // MIPS callee save registers for o32 ABI (32bit registers) are: + // 1. $s0-$s7, + // 2. $sp, $fp + // 3. $f20-$f31 + // + // The register structure is available at + // http://en.wikipedia.org/wiki/MIPS_architecture#Compiler_register_usage + +#define INDEX_MIPS_REG_S0 MD_CONTEXT_MIPS_REG_S0 // 16 +#define INDEX_MIPS_REG_S7 MD_CONTEXT_MIPS_REG_S7 // 23 +#define INDEX_MIPS_REG_GP MD_CONTEXT_MIPS_REG_GP // 28 +#define INDEX_MIPS_REG_RA MD_CONTEXT_MIPS_REG_RA // 31 +#define INDEX_MIPS_REG_PC 34 +#define SHIFT_MIPS_REG_S0 0 +#define SHIFT_MIPS_REG_GP 8 +#define SHIFT_MIPS_REG_PC 12 + + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_S0 = 1 << 0, // $16 + CONTEXT_VALID_S1 = 1 << 1, // $17 + CONTEXT_VALID_S2 = 1 << 2, // $18 + CONTEXT_VALID_S3 = 1 << 3, // $19 + CONTEXT_VALID_S4 = 1 << 4, // $20 + CONTEXT_VALID_S5 = 1 << 5, // $21 + CONTEXT_VALID_S6 = 1 << 6, // $22 + CONTEXT_VALID_S7 = 1 << 7, // $23 + // GP is not calee-save for o32 abi. + CONTEXT_VALID_GP = 1 << 8, // $28 + CONTEXT_VALID_SP = 1 << 9, // $29 + CONTEXT_VALID_FP = 1 << 10, // $30 + CONTEXT_VALID_RA = 1 << 11, // $31 + CONTEXT_VALID_PC = 1 << 12, // $34 + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE + }; + + // Return the ContextValidity flag for register rN. + static ContextValidity RegisterValidFlag(int n) { + if (n >= INDEX_MIPS_REG_S0 && n <= INDEX_MIPS_REG_S7) + return ContextValidity(1 << (n - INDEX_MIPS_REG_S0 + SHIFT_MIPS_REG_S0)); + else if (n >= INDEX_MIPS_REG_GP && n <= INDEX_MIPS_REG_RA) + return ContextValidity(1 << (n - INDEX_MIPS_REG_GP + SHIFT_MIPS_REG_GP)); + else if (n == INDEX_MIPS_REG_PC) + return ContextValidity(1 << SHIFT_MIPS_REG_PC); + + return CONTEXT_VALID_NONE; + } + + StackFrameMIPS() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information were available. Refer to 'context_validity' below. + MDRawContextMIPS context; + + // For each register in context whose value has been recovered, + // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set. + // + // context_validity's type should actually be ContextValidity, but + // type int is used instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_symbolizer.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_symbolizer.h new file mode 100644 index 0000000000..0bbaae0a36 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame_symbolizer.h @@ -0,0 +1,110 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2012 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. + +// Helper class that encapsulates the logic of how symbol supplier interacts +// with source line resolver to fill stack frame information. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_module.h" + +namespace google_breakpad { +class CFIFrameInfo; +class CodeModules; +class SymbolSupplier; +class SourceLineResolverInterface; +struct StackFrame; +struct SystemInfo; +struct WindowsFrameInfo; + +class StackFrameSymbolizer { + public: + enum SymbolizerResult { + // Symbol data was found and successfully loaded in resolver. + // This does NOT guarantee source line info is found within symbol file. + kNoError, + // This indicates non-critical error, such as, no code module found for + // frame's instruction, no symbol file, or resolver failed to load symbol. + kError, + // This indicates error for which stack walk should be interrupted + // and retried in future. + kInterrupt, + // Symbol data was found and loaded in resolver however some corruptions + // were detected. + kWarningCorruptSymbols, + }; + + StackFrameSymbolizer(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver); + + virtual ~StackFrameSymbolizer() { } + + // Encapsulate the step of resolving source line info for a stack frame. + // "frame" must not be NULL. + virtual SymbolizerResult FillSourceLineInfo( + const CodeModules* modules, + const CodeModules* unloaded_modules, + const SystemInfo* system_info, + StackFrame* stack_frame); + + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame); + + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame); + + // Reset internal (locally owned) data as if the helper is re-instantiated. + // A typical case is to call Reset() after processing an individual report + // before start to process next one, in order to reset internal information + // about missing symbols found so far. + virtual void Reset() { no_symbol_modules_.clear(); } + + // Returns true if there is valid implementation for stack symbolization. + virtual bool HasImplementation() { return resolver_ && supplier_; } + + SourceLineResolverInterface* resolver() { return resolver_; } + SymbolSupplier* supplier() { return supplier_; } + + protected: + SymbolSupplier* supplier_; + SourceLineResolverInterface* resolver_; + // A list of modules known to have symbols missing. This helps avoid + // repeated lookups for the missing symbols within one minidump. + std::set no_symbol_modules_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h new file mode 100644 index 0000000000..0c458d500e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stackwalker.h @@ -0,0 +1,257 @@ +// Copyright (c) 2010 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 +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" + +namespace google_breakpad { + +class CallStack; +class DumpContext; +class StackFrameSymbolizer; + +using std::set; +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(). + // Upon return, |modules_without_symbols| will be populated with pointers to + // the code modules (CodeModule*) that DON'T have symbols. + // |modules_with_corrupt_symbols| will be populated with pointers to the + // modules which have corrupt symbols. |modules_without_symbols| and + // |modules_with_corrupt_symbols| DO NOT take ownership of the code modules. + // The lifetime of these code modules is the same as the lifetime of the + // CodeModules passed to the StackWalker constructor (which currently + // happens to be the lifetime of the Breakpad's ProcessingState object). + // There is a check for duplicate modules so no duplicates are expected. + bool Walk(CallStack* stack, + vector* modules_without_symbols, + vector* modules_with_corrupt_symbols); + + // 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, + DumpContext* context, + MemoryRegion* memory, + const CodeModules* modules, + const CodeModules* unloaded_modules, + StackFrameSymbolizer* resolver_helper); + + + static void set_max_frames(uint32_t max_frames) { + max_frames_ = max_frames; + max_frames_set_ = true; + } + static uint32_t max_frames() { return max_frames_; } + + static void set_max_frames_scanned(uint32_t max_frames_scanned) { + max_frames_scanned_ = max_frames_scanned; + } + + 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. frame_symbolizer is a StackFrameSymbolizer object that + // encapsulates the logic of how source line resolver interacts with symbol + // supplier to symbolize stack frame and look up caller frame information + // (see stack_frame_symbolizer.h). + // frame_symbolizer MUST NOT be NULL (asserted). + Stackwalker(const SystemInfo* system_info, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // This can be used to filter out potential return addresses when + // the stack walker resorts to stack scanning. + // Returns true if any of: + // * This address is within a loaded module, but we don't have symbols + // for that module. + // * This address is within a loaded module for which we have symbols, + // and falls inside a function in that module. + // Returns false otherwise. + bool InstructionAddressSeemsValid(uint64_t address) const; + + // Checks whether we should stop the stack trace. + // (either we reached the end-of-stack or we detected a + // broken callstack invariant) + bool TerminateWalk(uint64_t caller_ip, + uint64_t caller_sp, + uint64_t callee_sp, + bool first_unwind) const; + + // The default number of words to search through on the stack + // for a return address. + static const int kRASearchWords; + + template + bool ScanForReturnAddress(InstructionType location_start, + InstructionType* location_found, + InstructionType* ip_found, + bool is_context_frame) { + // When searching for the caller of the context frame, + // allow the scanner to look farther down the stack. + const int search_words = is_context_frame ? + kRASearchWords * 4 : + kRASearchWords; + + return ScanForReturnAddress(location_start, location_found, ip_found, + search_words); + } + + // Scan the stack starting at location_start, looking for an address + // that looks like a valid instruction pointer. Addresses must + // 1) be contained in the current stack memory + // 2) pass the checks in InstructionAddressSeemsValid + // + // Returns true if a valid-looking instruction pointer was found. + // When returning true, sets location_found to the address at which + // the value was found, and ip_found to the value contained at that + // location in memory. + template + bool ScanForReturnAddress(InstructionType location_start, + InstructionType* location_found, + InstructionType* ip_found, + int searchwords) { + for (InstructionType location = location_start; + location <= location_start + searchwords * sizeof(InstructionType); + location += sizeof(InstructionType)) { + InstructionType ip; + if (!memory_->GetMemoryAtAddress(location, &ip)) + break; + + if (modules_ && modules_->GetModuleForAddress(ip) && + InstructionAddressSeemsValid(ip)) { + *ip_found = ip; + *location_found = location; + return true; + } + } + // nothing found + return false; + } + + // 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_; + + // A list of unloaded modules, for populating frames which aren't matched + // to any loaded modules. + // This field is optional and may be NULL. + const CodeModules* unloaded_modules_; + + protected: + // The StackFrameSymbolizer implementation. + StackFrameSymbolizer* frame_symbolizer_; + + 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. |stack_scan_allowed| controls whether stack scanning is + // an allowable frame-recovery method, since it is desirable to be able to + // disable stack scanning in performance-critical use cases. + // + // CONSIDER: a way to differentiate between: + // - full stack traces + // - explicitly truncated traces (max_frames_) + // - stopping after max scanned frames + // - failed stack walk (breaking one of the stack walk invariants) + // + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) = 0; + + // The maximum number of frames Stackwalker will walk through. + // This defaults to 1024 to prevent infinite loops. + static uint32_t max_frames_; + + // Keep track of whether max_frames_ has been set by the user, since + // it affects whether or not an error message is printed in the case + // where an unwind got stopped by the limit. + static bool max_frames_set_; + + // The maximum number of stack-scanned and otherwise untrustworthy + // frames allowed. Stack-scanning can be expensive, so the option to + // disable or limit it is helpful in cases where unwind performance is + // important. This defaults to 1024, the same as max_frames_. + static uint32_t max_frames_scanned_; +}; + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/symbol_supplier.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/symbol_supplier.h new file mode 100644 index 0000000000..a042081f3b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/symbol_supplier.h @@ -0,0 +1,99 @@ +// 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 +#include "common/using_std_string.h" + +namespace google_breakpad { + +class CodeModule; +struct 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; + + // Same as above, except allocates data buffer on heap and then places the + // symbol data into the buffer as C-string. + // SymbolSupplier is responsible for deleting the data buffer. After the call + // to GetCStringSymbolData(), the caller should call FreeSymbolData(const + // Module *module) once the data buffer is no longer needed. + // If symbol_data is not NULL, symbol supplier won't return FOUND unless it + // returns a valid buffer in symbol_data, e.g., returns INTERRUPT on memory + // allocation failure. + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) = 0; + + // Frees the data buffer allocated for the module in GetCStringSymbolData. + virtual void FreeSymbolData(const CodeModule *module) = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/system_info.h b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/system_info.h new file mode 100644 index 0000000000..8d2f60be48 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/system_info.h @@ -0,0 +1,106 @@ +// 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 + +#include "common/using_std_string.h" + +namespace google_breakpad { + +struct SystemInfo { + public: + SystemInfo() : os(), os_short(), os_version(), cpu(), cpu_info(), + cpu_count(0), gl_version(), gl_vendor(), gl_renderer() {} + + // 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; + gl_version.clear(); + gl_vendor.clear(); + gl_renderer.clear(); + } + + // 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 include "windows", + // "mac", "linux" and "nacl". 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; + + // The GPU information. Currently only populated in microdumps. + string gl_version; + string gl_vendor; + string gl_renderer; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/address_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/address_map-inl.h new file mode 100644 index 0000000000..251c44781a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/address_map-inl.h @@ -0,0 +1,93 @@ +// 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 "processor/address_map.h" + +#include + +#include "processor/logging.h" + +namespace google_breakpad { + +template +bool AddressMap::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 +bool AddressMap::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 +void AddressMap::Clear() { + map_.clear(); +} + +} // namespace google_breakpad + +#endif // PROCESSOR_ADDRESS_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/address_map.h b/toolkit/crashreporter/google-breakpad/src/processor/address_map.h new file mode 100644 index 0000000000..2972cbb9f8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/address_map.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. + +// 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 + +namespace google_breakpad { + +// Forward declarations (for later friend declarations). +template class AddressMapSerializer; + +template +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: + friend class AddressMapSerializer; + friend class ModuleComparer; + + // Convenience types. + typedef std::map 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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/address_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/address_map_unittest.cc new file mode 100644 index 0000000000..9b4095b16c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/address_map_unittest.cc @@ -0,0 +1,196 @@ +// 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_unittest.cc: Unit tests for AddressMap. +// +// Author: Mark Mentovai + +#include +#include + +#include "processor/address_map-inl.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + +#define ASSERT_TRUE(condition) \ + if (!(condition)) { \ + fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \ + return false; \ + } + +#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition)) + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) + +namespace { + +using google_breakpad::AddressMap; +using google_breakpad::linked_ptr; + +// A CountedObject holds an int. A global (not thread safe!) count of +// allocated CountedObjects is maintained to help test memory management. +class CountedObject { + public: + explicit CountedObject(int id) : id_(id) { ++count_; } + ~CountedObject() { --count_; } + + static int count() { return count_; } + int id() const { return id_; } + + private: + static int count_; + int id_; +}; + +int CountedObject::count_; + +typedef int AddressType; +typedef AddressMap< AddressType, linked_ptr > TestMap; + +static bool DoAddressMapTest() { + ASSERT_EQ(CountedObject::count(), 0); + + TestMap test_map; + linked_ptr entry; + AddressType address; + + // Check that a new map is truly empty. + ASSERT_FALSE(test_map.Retrieve(0, &entry, &address)); + ASSERT_FALSE(test_map.Retrieve(INT_MIN, &entry, &address)); + ASSERT_FALSE(test_map.Retrieve(INT_MAX, &entry, &address)); + + // Check that Clear clears the map without leaking. + ASSERT_EQ(CountedObject::count(), 0); + ASSERT_TRUE(test_map.Store(1, + linked_ptr(new CountedObject(0)))); + ASSERT_TRUE(test_map.Retrieve(1, &entry, &address)); + ASSERT_EQ(CountedObject::count(), 1); + test_map.Clear(); + ASSERT_EQ(CountedObject::count(), 1); // still holding entry in this scope + + // Check that a cleared map is truly empty. + ASSERT_FALSE(test_map.Retrieve(0, &entry, &address)); + ASSERT_FALSE(test_map.Retrieve(INT_MIN, &entry, &address)); + ASSERT_FALSE(test_map.Retrieve(INT_MAX, &entry, &address)); + + // Check a single-element map. + ASSERT_TRUE(test_map.Store(10, + linked_ptr(new CountedObject(1)))); + ASSERT_FALSE(test_map.Retrieve(9, &entry, &address)); + ASSERT_TRUE(test_map.Retrieve(10, &entry, &address)); + ASSERT_EQ(CountedObject::count(), 1); + ASSERT_EQ(entry->id(), 1); + ASSERT_EQ(address, 10); + ASSERT_TRUE(test_map.Retrieve(11, &entry, &address)); + ASSERT_TRUE(test_map.Retrieve(11, &entry, NULL)); // NULL ok here + + // Add some more elements. + ASSERT_TRUE(test_map.Store(5, + linked_ptr(new CountedObject(2)))); + ASSERT_EQ(CountedObject::count(), 2); + ASSERT_TRUE(test_map.Store(20, + linked_ptr(new CountedObject(3)))); + ASSERT_TRUE(test_map.Store(15, + linked_ptr(new CountedObject(4)))); + ASSERT_FALSE(test_map.Store(10, + linked_ptr(new CountedObject(5)))); // already in map + ASSERT_TRUE(test_map.Store(16, + linked_ptr(new CountedObject(6)))); + ASSERT_TRUE(test_map.Store(14, + linked_ptr(new CountedObject(7)))); + + // Nothing was stored with a key under 5. Don't use ASSERT inside loops + // because it won't show exactly which key/entry/address failed. + for (AddressType key = 0; key < 5; ++key) { + if (test_map.Retrieve(key, &entry, &address)) { + fprintf(stderr, + "FAIL: retrieve %d expected false observed true @ %s:%d\n", + key, __FILE__, __LINE__); + return false; + } + } + + // Check everything that was stored. + const int id_verify[] = { 0, 0, 0, 0, 0, // unused + 2, 2, 2, 2, 2, // 5 - 9 + 1, 1, 1, 1, 7, // 10 - 14 + 4, 6, 6, 6, 6, // 15 - 19 + 3, 3, 3, 3, 3, // 20 - 24 + 3, 3, 3, 3, 3 }; // 25 - 29 + const AddressType address_verify[] = { 0, 0, 0, 0, 0, // unused + 5, 5, 5, 5, 5, // 5 - 9 + 10, 10, 10, 10, 14, // 10 - 14 + 15, 16, 16, 16, 16, // 15 - 19 + 20, 20, 20, 20, 20, // 20 - 24 + 20, 20, 20, 20, 20 }; // 25 - 29 + + for (AddressType key = 5; key < 30; ++key) { + if (!test_map.Retrieve(key, &entry, &address)) { + fprintf(stderr, + "FAIL: retrieve %d expected true observed false @ %s:%d\n", + key, __FILE__, __LINE__); + return false; + } + if (entry->id() != id_verify[key]) { + fprintf(stderr, + "FAIL: retrieve %d expected entry %d observed %d @ %s:%d\n", + key, id_verify[key], entry->id(), __FILE__, __LINE__); + return false; + } + if (address != address_verify[key]) { + fprintf(stderr, + "FAIL: retrieve %d expected address %d observed %d @ %s:%d\n", + key, address_verify[key], address, __FILE__, __LINE__); + return false; + } + } + + // The stored objects should still be in the map. + ASSERT_EQ(CountedObject::count(), 6); + + return true; +} + +static bool RunTests() { + if (!DoAddressMapTest()) + return false; + + // Leak check. + ASSERT_EQ(CountedObject::count(), 0); + + return true; +} + +} // namespace + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_code_module.h b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_module.h new file mode 100644 index 0000000000..35d66a6075 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_module.h @@ -0,0 +1,121 @@ +// 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 + +#include "common/using_std_string.h" +#include "google_breakpad/processor/code_module.h" + +namespace google_breakpad { + +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()), + shrink_down_delta_(that->shrink_down_delta()), + code_file_(that->code_file()), + code_identifier_(that->code_identifier()), + debug_file_(that->debug_file()), + debug_identifier_(that->debug_identifier()), + version_(that->version()), + is_unloaded_(that->is_unloaded()) {} + + BasicCodeModule(uint64_t base_address, uint64_t size, + const string &code_file, + const string &code_identifier, + const string &debug_file, + const string &debug_identifier, + const string &version, + const bool is_unloaded = false) + : base_address_(base_address), + size_(size), + shrink_down_delta_(0), + code_file_(code_file), + code_identifier_(code_identifier), + debug_file_(debug_file), + debug_identifier_(debug_identifier), + version_(version), + is_unloaded_(is_unloaded) + {} + virtual ~BasicCodeModule() {} + + // See code_module.h for descriptions of these methods and the associated + // members. + virtual uint64_t base_address() const { return base_address_; } + virtual uint64_t size() const { return size_; } + virtual uint64_t shrink_down_delta() const { return shrink_down_delta_; } + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) { + shrink_down_delta_ = shrink_down_delta; + } + 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 CodeModule* Copy() const { return new BasicCodeModule(this); } + virtual bool is_unloaded() const { return is_unloaded_; } + + private: + uint64_t base_address_; + uint64_t size_; + uint64_t shrink_down_delta_; + string code_file_; + string code_identifier_; + string debug_file_; + string debug_identifier_; + string version_; + bool is_unloaded_; + + // Disallow copy constructor and assignment operator. + BasicCodeModule(const BasicCodeModule &that); + void operator=(const BasicCodeModule &that); +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_BASIC_CODE_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.cc b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.cc new file mode 100644 index 0000000000..f71aeb7476 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.cc @@ -0,0 +1,152 @@ +// 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.cc: Contains all of the CodeModule objects that +// were loaded into a single process. +// +// See basic_code_modules.h for documentation. +// +// Author: Mark Mentovai + +#include "processor/basic_code_modules.h" + +#include + +#include + +#include "google_breakpad/processor/code_module.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" +#include "processor/range_map-inl.h" + +namespace google_breakpad { + +using std::vector; + +BasicCodeModules::BasicCodeModules(const CodeModules* that, + MergeRangeStrategy strategy) + : main_address_(0), map_() { + BPLOG_IF(ERROR, !that) << "BasicCodeModules::BasicCodeModules requires " + "|that|"; + assert(that); + + map_.SetMergeStrategy(strategy); + + const CodeModule *main_module = that->GetMainModule(); + if (main_module) + main_address_ = main_module->base_address(); + + unsigned int count = that->module_count(); + for (unsigned int i = 0; i < count; ++i) { + // Make a copy of the module and insert it into the map. Use + // GetModuleAtIndex because ordering is unimportant when slurping the + // entire list, and GetModuleAtIndex may be faster than + // GetModuleAtSequence. + linked_ptr module(that->GetModuleAtIndex(i)->Copy()); + if (!map_.StoreRange(module->base_address(), module->size(), module)) { + BPLOG(ERROR) << "Module " << module->code_file() + << " could not be stored"; + } + } + + // Report modules with shrunk ranges. + for (unsigned int i = 0; i < count; ++i) { + linked_ptr module(that->GetModuleAtIndex(i)->Copy()); + uint64_t delta = 0; + if (map_.RetrieveRange(module->base_address() + module->size() - 1, + &module, NULL /* base */, &delta, NULL /* size */) && + delta > 0) { + BPLOG(INFO) << "The range for module " << module->code_file() + << " was shrunk down by " << HexString(delta) << " bytes."; + linked_ptr shrunk_range_module(module->Copy()); + shrunk_range_module->SetShrinkDownDelta(delta); + shrunk_range_modules_.push_back(shrunk_range_module); + } + } + + // TODO(ivanpe): Report modules with conflicting ranges. The list of such + // modules should be copied from |that|. +} + +BasicCodeModules::BasicCodeModules() : main_address_(0), map_() { } + +BasicCodeModules::~BasicCodeModules() { +} + +unsigned int BasicCodeModules::module_count() const { + return map_.GetCount(); +} + +const CodeModule* BasicCodeModules::GetModuleForAddress( + uint64_t address) const { + linked_ptr module; + if (!map_.RetrieveRange(address, &module, NULL /* base */, NULL /* delta */, + NULL /* size */)) { + BPLOG(INFO) << "No module at " << HexString(address); + return NULL; + } + + return module.get(); +} + +const CodeModule* BasicCodeModules::GetMainModule() const { + return GetModuleForAddress(main_address_); +} + +const CodeModule* BasicCodeModules::GetModuleAtSequence( + unsigned int sequence) const { + linked_ptr module; + if (!map_.RetrieveRangeAtIndex(sequence, &module, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + BPLOG(ERROR) << "RetrieveRangeAtIndex failed for sequence " << sequence; + return NULL; + } + + return module.get(); +} + +const CodeModule* BasicCodeModules::GetModuleAtIndex( + unsigned int index) const { + // This class stores everything in a RangeMap, without any more-efficient + // way to walk the list of CodeModule objects. Implement GetModuleAtIndex + // using GetModuleAtSequence, which meets all of the requirements, and + // in addition, guarantees ordering. + return GetModuleAtSequence(index); +} + +const CodeModules* BasicCodeModules::Copy() const { + return new BasicCodeModules(this, map_.GetMergeStrategy()); +} + +vector > +BasicCodeModules::GetShrunkRangeModules() const { + return shrunk_range_modules_; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.h b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.h new file mode 100644 index 0000000000..45ebc53b24 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_code_modules.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. + +// 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 + +#include + +#include "google_breakpad/processor/code_modules.h" +#include "processor/linked_ptr.h" +#include "processor/range_map.h" + +namespace google_breakpad { + +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. + BasicCodeModules(const CodeModules *that, MergeRangeStrategy strategy); + + virtual ~BasicCodeModules(); + + // See code_modules.h for descriptions of these methods. + virtual unsigned int module_count() const; + virtual const CodeModule* GetModuleForAddress(uint64_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; + virtual std::vector > + GetShrunkRangeModules() const; + + protected: + BasicCodeModules(); + + // The base address of the main module. + uint64_t main_address_; + + // The map used to contain each CodeModule, keyed by each CodeModule's + // address range. + RangeMap > map_; + + // A vector of all CodeModules that were shrunk downs due to + // address range conflicts. + std::vector > shrunk_range_modules_; + + private: + // Disallow copy constructor and assignment operator. + BasicCodeModules(const BasicCodeModules &that); + void operator=(const BasicCodeModules &that); +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_BASIC_CODE_MODULES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver.cc b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver.cc new file mode 100644 index 0000000000..c4aa949caa --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver.cc @@ -0,0 +1,657 @@ +// Copyright (c) 2010 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_source_line_resolver.cc: BasicSourceLineResolver implementation. +// +// See basic_source_line_resolver.h and basic_source_line_resolver_types.h +// for documentation. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "processor/basic_source_line_resolver_types.h" +#include "processor/module_factory.h" + +#include "processor/tokenize.h" + +using std::map; +using std::vector; +using std::make_pair; + +namespace google_breakpad { + +#ifdef _WIN32 +#ifdef _MSC_VER +#define strtok_r strtok_s +#endif +#define strtoull _strtoui64 +#endif + +namespace { + +// Utility function to tokenize given the presence of an optional initial +// field. In this case, optional_field is the expected string for the optional +// field, and max_tokens is the maximum number of tokens including the optional +// field. Refer to the documentation for Tokenize for descriptions of the other +// arguments. +bool TokenizeWithOptionalField(char *line, + const char *optional_field, + const char *separators, + int max_tokens, + vector *tokens) { + // First tokenize assuming the optional field is not present. If we then see + // the optional field, additionally tokenize the last token into two tokens. + if (!Tokenize(line, separators, max_tokens - 1, tokens)) { + return false; + } + + if (strcmp(tokens->front(), optional_field) == 0) { + // The optional field is present. Split the last token in two to recover the + // field prior to the last. + vector last_tokens; + if (!Tokenize(tokens->back(), separators, 2, &last_tokens)) { + return false; + } + // Replace the previous last token with the two new tokens. + tokens->pop_back(); + tokens->push_back(last_tokens[0]); + tokens->push_back(last_tokens[1]); + } + + return true; +} + +} // namespace + +static const char *kWhitespace = " \r\n"; +static const int kMaxErrorsPrinted = 5; +static const int kMaxErrorsBeforeBailing = 100; + +BasicSourceLineResolver::BasicSourceLineResolver() : + SourceLineResolverBase(new BasicModuleFactory) { } + +// static +void BasicSourceLineResolver::Module::LogParseError( + const string &message, + int line_number, + int *num_errors) { + if (++(*num_errors) <= kMaxErrorsPrinted) { + if (line_number > 0) { + BPLOG(ERROR) << "Line " << line_number << ": " << message; + } else { + BPLOG(ERROR) << message; + } + } +} + +bool BasicSourceLineResolver::Module::LoadMapFromMemory( + char *memory_buffer, + size_t memory_buffer_size) { + linked_ptr cur_func; + int line_number = 0; + int num_errors = 0; + char *save_ptr; + + // If the length is 0, we can still pretend we have a symbol file. This is + // for scenarios that want to test symbol lookup, but don't necessarily care + // if certain modules do not have any information, like system libraries. + if (memory_buffer_size == 0) { + return true; + } + + // Make sure the last character is null terminator. + size_t last_null_terminator = memory_buffer_size - 1; + if (memory_buffer[last_null_terminator] != '\0') { + memory_buffer[last_null_terminator] = '\0'; + } + + // Skip any null terminators at the end of the memory buffer, and make sure + // there are no other null terminators in the middle of the memory buffer. + bool has_null_terminator_in_the_middle = false; + while (last_null_terminator > 0 && + memory_buffer[last_null_terminator - 1] == '\0') { + last_null_terminator--; + } + for (size_t i = 0; i < last_null_terminator; i++) { + if (memory_buffer[i] == '\0') { + memory_buffer[i] = '_'; + has_null_terminator_in_the_middle = true; + } + } + if (has_null_terminator_in_the_middle) { + LogParseError( + "Null terminator is not expected in the middle of the symbol data", + line_number, + &num_errors); + } + + char *buffer; + buffer = strtok_r(memory_buffer, "\r\n", &save_ptr); + + while (buffer != NULL) { + ++line_number; + + if (strncmp(buffer, "FILE ", 5) == 0) { + if (!ParseFile(buffer)) { + LogParseError("ParseFile on buffer failed", line_number, &num_errors); + } + } else if (strncmp(buffer, "STACK ", 6) == 0) { + if (!ParseStackInfo(buffer)) { + LogParseError("ParseStackInfo failed", line_number, &num_errors); + } + } else if (strncmp(buffer, "FUNC ", 5) == 0) { + cur_func.reset(ParseFunction(buffer)); + if (!cur_func.get()) { + LogParseError("ParseFunction failed", line_number, &num_errors); + } else { + // StoreRange will fail if the function has an invalid address or size. + // We'll silently ignore this, the function and any corresponding lines + // will be destroyed when cur_func is released. + functions_.StoreRange(cur_func->address, cur_func->size, cur_func); + } + } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { + // Clear cur_func: public symbols don't contain line number information. + cur_func.reset(); + + if (!ParsePublicSymbol(buffer)) { + LogParseError("ParsePublicSymbol failed", line_number, &num_errors); + } + } else if (strncmp(buffer, "MODULE ", 7) == 0) { + // Ignore these. They're not of any use to BasicSourceLineResolver, + // which is fed modules by a SymbolSupplier. These lines are present to + // aid other tools in properly placing symbol files so that they can + // be accessed by a SymbolSupplier. + // + // MODULE + } else if (strncmp(buffer, "INFO ", 5) == 0) { + // Ignore these as well, they're similarly just for housekeeping. + // + // INFO CODE_ID + } else { + if (!cur_func.get()) { + LogParseError("Found source line data without a function", + line_number, &num_errors); + } else { + Line *line = ParseLine(buffer); + if (!line) { + LogParseError("ParseLine failed", line_number, &num_errors); + } else { + cur_func->lines.StoreRange(line->address, line->size, + linked_ptr(line)); + } + } + } + if (num_errors > kMaxErrorsBeforeBailing) { + break; + } + buffer = strtok_r(NULL, "\r\n", &save_ptr); + } + is_corrupt_ = num_errors > 0; + return true; +} + +void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + + // First, look for a FUNC record that covers address. Use + // RetrieveNearestRange instead of RetrieveRange so that, if there + // is no such function, we can use the next function to bound the + // extent of the PUBLIC symbol we find, below. This does mean we + // need to check that address indeed falls within the function we + // find; do the range comparison in an overflow-friendly way. + linked_ptr func; + linked_ptr public_symbol; + MemAddr function_base; + MemAddr function_size; + MemAddr public_address; + if (functions_.RetrieveNearestRange(address, &func, &function_base, + NULL /* delta */, &function_size) && + address >= function_base && address - function_base < function_size) { + frame->function_name = func->name; + frame->function_base = frame->module->base_address() + function_base; + + linked_ptr line; + MemAddr line_base; + if (func->lines.RetrieveRange(address, &line, &line_base, NULL /* delta */, + NULL /* size */)) { + FileMap::const_iterator it = files_.find(line->source_file_id); + if (it != files_.end()) { + frame->source_file_name = files_.find(line->source_file_id)->second; + } + frame->source_line = line->line; + frame->source_line_base = frame->module->base_address() + line_base; + } + } else if (public_symbols_.Retrieve(address, + &public_symbol, &public_address) && + (!func.get() || public_address > function_base)) { + frame->function_name = public_symbol->name; + frame->function_base = frame->module->base_address() + public_address; + } +} + +WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo( + const StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + scoped_ptr result(new WindowsFrameInfo()); + + // We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and + // WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order. + // WindowsFrameInfo::STACK_INFO_FRAME_DATA is the newer type that + // includes its own program string. + // WindowsFrameInfo::STACK_INFO_FPO is the older type + // corresponding to the FPO_DATA struct. See stackwalker_x86.cc. + linked_ptr frame_info; + if ((windows_frame_info_[WindowsFrameInfo::STACK_INFO_FRAME_DATA] + .RetrieveRange(address, &frame_info)) + || (windows_frame_info_[WindowsFrameInfo::STACK_INFO_FPO] + .RetrieveRange(address, &frame_info))) { + result->CopyFrom(*frame_info.get()); + return result.release(); + } + + // Even without a relevant STACK line, many functions contain + // information about how much space their parameters consume on the + // stack. Use RetrieveNearestRange instead of RetrieveRange, so that + // we can use the function to bound the extent of the PUBLIC symbol, + // below. However, this does mean we need to check that ADDRESS + // falls within the retrieved function's range; do the range + // comparison in an overflow-friendly way. + linked_ptr function; + MemAddr function_base, function_size; + if (functions_.RetrieveNearestRange(address, &function, &function_base, + NULL /* delta */, &function_size) && + address >= function_base && address - function_base < function_size) { + result->parameter_size = function->parameter_size; + result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; + return result.release(); + } + + // PUBLIC symbols might have a parameter size. Use the function we + // found above to limit the range the public symbol covers. + linked_ptr public_symbol; + MemAddr public_address; + if (public_symbols_.Retrieve(address, &public_symbol, &public_address) && + (!function.get() || public_address > function_base)) { + result->parameter_size = public_symbol->parameter_size; + } + + return NULL; +} + +CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo( + const StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + MemAddr initial_base, initial_size; + string initial_rules; + + // Find the initial rule whose range covers this address. That + // provides an initial set of register recovery rules. Then, walk + // forward from the initial rule's starting address to frame's + // instruction address, applying delta rules. + if (!cfi_initial_rules_.RetrieveRange(address, &initial_rules, &initial_base, + NULL /* delta */, &initial_size)) { + return NULL; + } + + // Create a frame info structure, and populate it with the rules from + // the STACK CFI INIT record. + scoped_ptr rules(new CFIFrameInfo()); + if (!ParseCFIRuleSet(initial_rules, rules.get())) + return NULL; + + // Find the first delta rule that falls within the initial rule's range. + map::const_iterator delta = + cfi_delta_rules_.lower_bound(initial_base); + + // Apply delta rules up to and including the frame's address. + while (delta != cfi_delta_rules_.end() && delta->first <= address) { + ParseCFIRuleSet(delta->second, rules.get()); + delta++; + } + + return rules.release(); +} + +bool BasicSourceLineResolver::Module::ParseFile(char *file_line) { + long index; + char *filename; + if (SymbolParseHelper::ParseFile(file_line, &index, &filename)) { + files_.insert(make_pair(index, string(filename))); + return true; + } + return false; +} + +BasicSourceLineResolver::Function* +BasicSourceLineResolver::Module::ParseFunction(char *function_line) { + bool is_multiple; + uint64_t address; + uint64_t size; + long stack_param_size; + char *name; + if (SymbolParseHelper::ParseFunction(function_line, &is_multiple, &address, + &size, &stack_param_size, &name)) { + return new Function(name, address, size, stack_param_size, is_multiple); + } + return NULL; +} + +BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( + char *line_line) { + uint64_t address; + uint64_t size; + long line_number; + long source_file; + + if (SymbolParseHelper::ParseLine(line_line, &address, &size, &line_number, + &source_file)) { + return new Line(address, size, source_file, line_number); + } + return NULL; +} + +bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) { + bool is_multiple; + uint64_t address; + long stack_param_size; + char *name; + + if (SymbolParseHelper::ParsePublicSymbol(public_line, &is_multiple, &address, + &stack_param_size, &name)) { + // A few public symbols show up with an address of 0. This has been seen + // in the dumped output of ntdll.pdb for symbols such as _CIlog, _CIpow, + // RtlDescribeChunkLZNT1, and RtlReserveChunkLZNT1. They would conflict + // with one another if they were allowed into the public_symbols_ map, + // but since the address is obviously invalid, gracefully accept them + // as input without putting them into the map. + if (address == 0) { + return true; + } + + linked_ptr symbol(new PublicSymbol(name, address, + stack_param_size, + is_multiple)); + return public_symbols_.Store(address, symbol); + } + return false; +} + +bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { + // Skip "STACK " prefix. + stack_info_line += 6; + + // Find the token indicating what sort of stack frame walking + // information this is. + while (*stack_info_line == ' ') + stack_info_line++; + const char *platform = stack_info_line; + while (!strchr(kWhitespace, *stack_info_line)) + stack_info_line++; + *stack_info_line++ = '\0'; + + // MSVC stack frame info. + if (strcmp(platform, "WIN") == 0) { + int type = 0; + uint64_t rva, code_size; + linked_ptr + stack_frame_info(WindowsFrameInfo::ParseFromString(stack_info_line, + type, + rva, + code_size)); + if (stack_frame_info == NULL) + return false; + + // TODO(mmentovai): I wanted to use StoreRange's return value as this + // method's return value, but MSVC infrequently outputs stack info that + // violates the containment rules. This happens with a section of code + // in strncpy_s in test_app.cc (testdata/minidump2). There, problem looks + // like this: + // STACK WIN 4 4242 1a a 0 ... (STACK WIN 4 base size prolog 0 ...) + // STACK WIN 4 4243 2e 9 0 ... + // ContainedRangeMap treats these two blocks as conflicting. In reality, + // when the prolog lengths are taken into account, the actual code of + // these blocks doesn't conflict. However, we can't take the prolog lengths + // into account directly here because we'd wind up with a different set + // of range conflicts when MSVC outputs stack info like this: + // STACK WIN 4 1040 73 33 0 ... + // STACK WIN 4 105a 59 19 0 ... + // because in both of these entries, the beginning of the code after the + // prolog is at 0x1073, and the last byte of contained code is at 0x10b2. + // Perhaps we could get away with storing ranges by rva + prolog_size + // if ContainedRangeMap were modified to allow replacement of + // already-stored values. + + windows_frame_info_[type].StoreRange(rva, code_size, stack_frame_info); + return true; + } else if (strcmp(platform, "CFI") == 0) { + // DWARF CFI stack frame info + return ParseCFIFrameInfo(stack_info_line); + } else { + // Something unrecognized. + return false; + } +} + +bool BasicSourceLineResolver::Module::ParseCFIFrameInfo( + char *stack_info_line) { + char *cursor; + + // Is this an INIT record or a delta record? + char *init_or_address = strtok_r(stack_info_line, " \r\n", &cursor); + if (!init_or_address) + return false; + + if (strcmp(init_or_address, "INIT") == 0) { + // This record has the form "STACK INIT
". + char *address_field = strtok_r(NULL, " \r\n", &cursor); + if (!address_field) return false; + + char *size_field = strtok_r(NULL, " \r\n", &cursor); + if (!size_field) return false; + + char *initial_rules = strtok_r(NULL, "\r\n", &cursor); + if (!initial_rules) return false; + + MemAddr address = strtoul(address_field, NULL, 16); + MemAddr size = strtoul(size_field, NULL, 16); + cfi_initial_rules_.StoreRange(address, size, initial_rules); + return true; + } + + // This record has the form "STACK
". + char *address_field = init_or_address; + char *delta_rules = strtok_r(NULL, "\r\n", &cursor); + if (!delta_rules) return false; + MemAddr address = strtoul(address_field, NULL, 16); + cfi_delta_rules_[address] = delta_rules; + return true; +} + +// static +bool SymbolParseHelper::ParseFile(char *file_line, long *index, + char **filename) { + // FILE + assert(strncmp(file_line, "FILE ", 5) == 0); + file_line += 5; // skip prefix + + vector tokens; + if (!Tokenize(file_line, kWhitespace, 2, &tokens)) { + return false; + } + + char *after_number; + *index = strtol(tokens[0], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *index < 0 || + *index == std::numeric_limits::max()) { + return false; + } + + *filename = tokens[1]; + if (!*filename) { + return false; + } + + return true; +} + +// static +bool SymbolParseHelper::ParseFunction(char *function_line, bool *is_multiple, + uint64_t *address, uint64_t *size, + long *stack_param_size, char **name) { + // FUNC []
+ assert(strncmp(function_line, "FUNC ", 5) == 0); + function_line += 5; // skip prefix + + vector tokens; + if (!TokenizeWithOptionalField(function_line, "m", kWhitespace, 5, &tokens)) { + return false; + } + + *is_multiple = strcmp(tokens[0], "m") == 0; + int next_token = *is_multiple ? 1 : 0; + + char *after_number; + *address = strtoull(tokens[next_token++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *address == std::numeric_limits::max()) { + return false; + } + *size = strtoull(tokens[next_token++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *size == std::numeric_limits::max()) { + return false; + } + *stack_param_size = strtol(tokens[next_token++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *stack_param_size == std::numeric_limits::max() || + *stack_param_size < 0) { + return false; + } + *name = tokens[next_token++]; + + return true; +} + +// static +bool SymbolParseHelper::ParseLine(char *line_line, uint64_t *address, + uint64_t *size, long *line_number, + long *source_file) { + //
+ vector tokens; + if (!Tokenize(line_line, kWhitespace, 4, &tokens)) { + return false; + } + + char *after_number; + *address = strtoull(tokens[0], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *address == std::numeric_limits::max()) { + return false; + } + *size = strtoull(tokens[1], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *size == std::numeric_limits::max()) { + return false; + } + *line_number = strtol(tokens[2], &after_number, 10); + if (!IsValidAfterNumber(after_number) || + *line_number == std::numeric_limits::max()) { + return false; + } + *source_file = strtol(tokens[3], &after_number, 10); + if (!IsValidAfterNumber(after_number) || *source_file < 0 || + *source_file == std::numeric_limits::max()) { + return false; + } + + // Valid line numbers normally start from 1, however there are functions that + // are associated with a source file but not associated with any line number + // (block helper function) and for such functions the symbol file contains 0 + // for the line numbers. Hence, 0 should be treated as a valid line number. + // For more information on block helper functions, please, take a look at: + // http://clang.llvm.org/docs/Block-ABI-Apple.html + if (*line_number < 0) { + return false; + } + + return true; +} + +// static +bool SymbolParseHelper::ParsePublicSymbol(char *public_line, bool *is_multiple, + uint64_t *address, + long *stack_param_size, + char **name) { + // PUBLIC []
+ assert(strncmp(public_line, "PUBLIC ", 7) == 0); + public_line += 7; // skip prefix + + vector tokens; + if (!TokenizeWithOptionalField(public_line, "m", kWhitespace, 4, &tokens)) { + return false; + } + + *is_multiple = strcmp(tokens[0], "m") == 0; + int next_token = *is_multiple ? 1 : 0; + + char *after_number; + *address = strtoull(tokens[next_token++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *address == std::numeric_limits::max()) { + return false; + } + *stack_param_size = strtol(tokens[next_token++], &after_number, 16); + if (!IsValidAfterNumber(after_number) || + *stack_param_size == std::numeric_limits::max() || + *stack_param_size < 0) { + return false; + } + *name = tokens[next_token++]; + + return true; +} + +// static +bool SymbolParseHelper::IsValidAfterNumber(char *after_number) { + if (after_number != NULL && strchr(kWhitespace, *after_number) != NULL) { + return true; + } + return false; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_types.h b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_types.h new file mode 100644 index 0000000000..89eb57e88a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_types.h @@ -0,0 +1,179 @@ +// Copyright (c) 2010 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_source_line_types.h: definition of nested classes/structs in +// BasicSourceLineResolver. It moves the definitions out of +// basic_source_line_resolver.cc, so that other classes could have access +// to these private nested types without including basic_source_line_resolver.cc +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__ +#define PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__ + +#include +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "processor/source_line_resolver_base_types.h" + +#include "processor/address_map-inl.h" +#include "processor/range_map-inl.h" +#include "processor/contained_range_map-inl.h" + +#include "processor/linked_ptr.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/cfi_frame_info.h" +#include "processor/windows_frame_info.h" + +namespace google_breakpad { + +struct +BasicSourceLineResolver::Function : public SourceLineResolverBase::Function { + Function(const string &function_name, + MemAddr function_address, + MemAddr code_size, + int set_parameter_size, + bool is_mutiple) : Base(function_name, + function_address, + code_size, + set_parameter_size, + is_mutiple), + lines() { } + RangeMap< MemAddr, linked_ptr > lines; + private: + typedef SourceLineResolverBase::Function Base; +}; + + +class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module { + public: + explicit Module(const string &name) : name_(name), is_corrupt_(false) { } + virtual ~Module() { } + + // Loads a map from the given buffer in char* type. + // Does NOT have ownership of memory_buffer. + // The passed in |memory buffer| is of size |memory_buffer_size|. If it is + // not null terminated, LoadMapFromMemory() will null terminate it by + // modifying the passed in buffer. + virtual bool LoadMapFromMemory(char *memory_buffer, + size_t memory_buffer_size); + + // Tells whether the loaded symbol data is corrupt. Return value is + // undefined, if the symbol data hasn't been loaded yet. + virtual bool IsCorrupt() const { return is_corrupt_; } + + // Looks up the given relative address, and fills the StackFrame struct + // with the result. + virtual void LookupAddress(StackFrame *frame) const; + + // If Windows stack walking information is available covering ADDRESS, + // return a WindowsFrameInfo structure describing it. If the information + // is not available, returns NULL. A NULL return value does not indicate + // an error. The caller takes ownership of any returned WindowsFrameInfo + // object. + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const; + + // If CFI stack walking information is available covering ADDRESS, + // return a CFIFrameInfo structure describing it. If the information + // is not available, return NULL. The caller takes ownership of any + // returned CFIFrameInfo object. + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const; + + private: + // Friend declarations. + friend class BasicSourceLineResolver; + friend class ModuleComparer; + friend class ModuleSerializer; + + typedef std::map FileMap; + + // Logs parse errors. |*num_errors| is increased every time LogParseError is + // called. + static void LogParseError( + const string &message, + int line_number, + int *num_errors); + + // Parses a file declaration + bool ParseFile(char *file_line); + + // Parses a function declaration, returning a new Function object. + Function* ParseFunction(char *function_line); + + // Parses a line declaration, returning a new Line object. + Line* ParseLine(char *line_line); + + // Parses a PUBLIC symbol declaration, storing it in public_symbols_. + // Returns false if an error occurs. + bool ParsePublicSymbol(char *public_line); + + // Parses a STACK WIN or STACK CFI frame info declaration, storing + // it in the appropriate table. + bool ParseStackInfo(char *stack_info_line); + + // Parses a STACK CFI record, storing it in cfi_frame_info_. + bool ParseCFIFrameInfo(char *stack_info_line); + + string name_; + FileMap files_; + RangeMap< MemAddr, linked_ptr > functions_; + AddressMap< MemAddr, linked_ptr > public_symbols_; + bool is_corrupt_; + + // Each element in the array is a ContainedRangeMap for a type + // listed in WindowsFrameInfoTypes. These are split by type because + // there may be overlaps between maps of different types, but some + // information is only available as certain types. + ContainedRangeMap< MemAddr, linked_ptr > + windows_frame_info_[WindowsFrameInfo::STACK_INFO_LAST]; + + // DWARF CFI stack walking data. The Module stores the initial rule sets + // and rule deltas as strings, just as they appear in the symbol file: + // although the file may contain hundreds of thousands of STACK CFI + // records, walking a stack will only ever use a few of them, so it's + // best to delay parsing a record until it's actually needed. + + // STACK CFI INIT records: for each range, an initial set of register + // recovery rules. The RangeMap's itself gives the starting and ending + // addresses. + RangeMap cfi_initial_rules_; + + // STACK CFI records: at a given address, the changes to the register + // recovery rules that take effect at that address. The map key is the + // starting address; the ending address is the key of the next entry in + // this map, or the end of the range as given by the cfi_initial_rules_ + // entry (which FindCFIFrameInfo looks up first). + std::map cfi_delta_rules_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_unittest.cc new file mode 100644 index 0000000000..90c3417236 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/basic_source_line_resolver_unittest.cc @@ -0,0 +1,744 @@ +// Copyright (c) 2010 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 +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/memory_region.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" +#include "processor/windows_frame_info.h" +#include "processor/cfi_frame_info.h" + +namespace { + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CFIFrameInfo; +using google_breakpad::CodeModule; +using google_breakpad::MemoryRegion; +using google_breakpad::StackFrame; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::linked_ptr; +using google_breakpad::scoped_ptr; +using google_breakpad::SymbolParseHelper; + +class TestCodeModule : public CodeModule { + public: + TestCodeModule(string code_file) : code_file_(code_file) {} + virtual ~TestCodeModule() {} + + virtual uint64_t base_address() const { return 0; } + virtual uint64_t size() const { return 0xb000; } + virtual string code_file() const { return code_file_; } + virtual string code_identifier() const { return ""; } + virtual string debug_file() const { return ""; } + virtual string debug_identifier() const { return ""; } + virtual string version() const { return ""; } + virtual CodeModule* Copy() const { + return new TestCodeModule(code_file_); + } + virtual bool is_unloaded() const { return false; } + virtual uint64_t shrink_down_delta() const { return 0; } + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {} + + private: + string code_file_; +}; + +// A mock memory region object, for use by the STACK CFI tests. +class MockMemoryRegion: public MemoryRegion { + uint64_t GetBase() const { return 0x10000; } + uint32_t GetSize() const { return 0x01000; } + bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + *value = address & 0xff; + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + *value = address & 0xffff; + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + switch (address) { + case 0x10008: *value = 0x98ecadc3; break; // saved %ebx + case 0x1000c: *value = 0x878f7524; break; // saved %esi + case 0x10010: *value = 0x6312f9a5; break; // saved %edi + case 0x10014: *value = 0x10038; break; // caller's %ebp + case 0x10018: *value = 0xf6438648; break; // return address + default: *value = 0xdeadbeef; break; // junk + } + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + *value = address; + return true; + } + void Print() const { + assert(false); + } +}; + +// Verify that, for every association in ACTUAL, EXPECTED has the same +// association. (That is, ACTUAL's associations should be a subset of +// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and +// ".cfa". +static bool VerifyRegisters( + const char *file, int line, + const CFIFrameInfo::RegisterValueMap &expected, + const CFIFrameInfo::RegisterValueMap &actual) { + CFIFrameInfo::RegisterValueMap::const_iterator a; + a = actual.find(".cfa"); + if (a == actual.end()) + return false; + a = actual.find(".ra"); + if (a == actual.end()) + return false; + for (a = actual.begin(); a != actual.end(); a++) { + CFIFrameInfo::RegisterValueMap::const_iterator e = + expected.find(a->first); + if (e == expected.end()) { + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", + file, line, a->first.c_str(), a->second); + return false; + } + if (e->second != a->second) { + fprintf(stderr, + "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n", + file, line, a->first.c_str(), a->second, e->second); + return false; + } + // Don't complain if this doesn't recover all registers. Although + // the DWARF spec says that unmentioned registers are undefined, + // GCC uses omission to mean that they are unchanged. + } + return true; +} + + +static bool VerifyEmpty(const StackFrame &frame) { + if (frame.function_name.empty() && + frame.source_file_name.empty() && + frame.source_line == 0) + return true; + return false; +} + +static void ClearSourceLineInfo(StackFrame *frame) { + frame->function_name.clear(); + frame->module = NULL; + frame->source_file_name.clear(); + frame->source_line = 0; +} + +class TestBasicSourceLineResolver : public ::testing::Test { +public: + void SetUp() { + testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata"; + } + + BasicSourceLineResolver resolver; + string testdata_dir; +}; + +TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve) +{ + TestCodeModule module1("module1"); + ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out")); + ASSERT_TRUE(resolver.HasModule(&module1)); + TestCodeModule module2("module2"); + ASSERT_TRUE(resolver.LoadModule(&module2, testdata_dir + "/module2.out")); + ASSERT_TRUE(resolver.HasModule(&module2)); + + + StackFrame frame; + scoped_ptr windows_frame_info; + scoped_ptr cfi_frame_info; + frame.instruction = 0x1000; + frame.module = NULL; + resolver.FillSourceLineInfo(&frame); + ASSERT_FALSE(frame.module); + ASSERT_TRUE(frame.function_name.empty()); + ASSERT_EQ(frame.function_base, 0U); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + ASSERT_EQ(frame.source_line_base, 0U); + + frame.module = &module1; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_1"); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module1"); + ASSERT_EQ(frame.function_base, 0x1000U); + ASSERT_EQ(frame.source_file_name, "file1_1.cc"); + ASSERT_EQ(frame.source_line, 44); + ASSERT_EQ(frame.source_line_base, 0x1000U); + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_EQ(windows_frame_info->program_string, + "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ ="); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x800; + frame.module = &module1; + resolver.FillSourceLineInfo(&frame); + ASSERT_TRUE(VerifyEmpty(frame)); + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_FALSE(windows_frame_info.get()); + + frame.instruction = 0x1280; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_3"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_TRUE(windows_frame_info->program_string.empty()); + + frame.instruction = 0x1380; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_4"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_FALSE(windows_frame_info->program_string.empty()); + + frame.instruction = 0x2000; + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_FALSE(windows_frame_info.get()); + + // module1 has STACK CFI records covering 3d40..3def; + // module2 has STACK CFI records covering 3df0..3e9f; + // check that FindCFIFrameInfo doesn't claim to find any outside those ranges. + frame.instruction = 0x3d3f; + frame.module = &module1; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + frame.instruction = 0x3e9f; + frame.module = &module1; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + CFIFrameInfo::RegisterValueMap current_registers; + CFIFrameInfo::RegisterValueMap caller_registers; + CFIFrameInfo::RegisterValueMap expected_caller_registers; + MockMemoryRegion memory; + + // Regardless of which instruction evaluation takes place at, it + // should produce the same values for the caller's registers. + expected_caller_registers[".cfa"] = 0x1001c; + expected_caller_registers[".ra"] = 0xf6438648; + expected_caller_registers["$ebp"] = 0x10038; + expected_caller_registers["$ebx"] = 0x98ecadc3; + expected_caller_registers["$esi"] = 0x878f7524; + expected_caller_registers["$edi"] = 0x6312f9a5; + + frame.instruction = 0x3d40; + frame.module = &module1; + current_registers.clear(); + current_registers["$esp"] = 0x10018; + current_registers["$ebp"] = 0x10038; + current_registers["$ebx"] = 0x98ecadc3; + current_registers["$esi"] = 0x878f7524; + current_registers["$edi"] = 0x6312f9a5; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d41; + current_registers["$esp"] = 0x10014; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d43; + current_registers["$ebp"] = 0x10014; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d54; + current_registers["$ebx"] = 0x6864f054U; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d5a; + current_registers["$esi"] = 0x6285f79aU; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d84; + current_registers["$edi"] = 0x64061449U; + cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x2900; + frame.module = &module1; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, string("PublicSymbol")); + + frame.instruction = 0x4000; + frame.module = &module1; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, string("LargeFunction")); + + frame.instruction = 0x2181; + frame.module = &module2; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function2_2"); + ASSERT_EQ(frame.function_base, 0x2170U); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module2"); + ASSERT_EQ(frame.source_file_name, "file2_2.cc"); + ASSERT_EQ(frame.source_line, 21); + ASSERT_EQ(frame.source_line_base, 0x2180U); + windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); + ASSERT_EQ(windows_frame_info->prolog_size, 1U); + + frame.instruction = 0x216f; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_1"); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x219f; + frame.module = &module2; + resolver.FillSourceLineInfo(&frame); + ASSERT_TRUE(frame.function_name.empty()); + + frame.instruction = 0x21a0; + frame.module = &module2; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_2"); +} + +TEST_F(TestBasicSourceLineResolver, TestInvalidLoads) +{ + TestCodeModule module3("module3"); + ASSERT_TRUE(resolver.LoadModule(&module3, + testdata_dir + "/module3_bad.out")); + ASSERT_TRUE(resolver.HasModule(&module3)); + ASSERT_TRUE(resolver.IsModuleCorrupt(&module3)); + TestCodeModule module4("module4"); + ASSERT_TRUE(resolver.LoadModule(&module4, + testdata_dir + "/module4_bad.out")); + ASSERT_TRUE(resolver.HasModule(&module4)); + ASSERT_TRUE(resolver.IsModuleCorrupt(&module4)); + TestCodeModule module5("module5"); + ASSERT_FALSE(resolver.LoadModule(&module5, + testdata_dir + "/invalid-filename")); + ASSERT_FALSE(resolver.HasModule(&module5)); + TestCodeModule invalidmodule("invalid-module"); + ASSERT_FALSE(resolver.HasModule(&invalidmodule)); +} + +TEST_F(TestBasicSourceLineResolver, TestUnload) +{ + TestCodeModule module1("module1"); + ASSERT_FALSE(resolver.HasModule(&module1)); + ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out")); + ASSERT_TRUE(resolver.HasModule(&module1)); + resolver.UnloadModule(&module1); + ASSERT_FALSE(resolver.HasModule(&module1)); + ASSERT_TRUE(resolver.LoadModule(&module1, testdata_dir + "/module1.out")); + ASSERT_TRUE(resolver.HasModule(&module1)); +} + +// Test parsing of valid FILE lines. The format is: +// FILE +TEST(SymbolParseHelper, ParseFileValid) { + long index; + char *filename; + + char kTestLine[] = "FILE 1 file name"; + ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename)); + EXPECT_EQ(1, index); + EXPECT_EQ("file name", string(filename)); + + // 0 is a valid index. + char kTestLine1[] = "FILE 0 file name"; + ASSERT_TRUE(SymbolParseHelper::ParseFile(kTestLine1, &index, &filename)); + EXPECT_EQ(0, index); + EXPECT_EQ("file name", string(filename)); +} + +// Test parsing of invalid FILE lines. The format is: +// FILE +TEST(SymbolParseHelper, ParseFileInvalid) { + long index; + char *filename; + + // Test missing file name. + char kTestLine[] = "FILE 1 "; + ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine, &index, &filename)); + + // Test bad index. + char kTestLine1[] = "FILE x1 file name"; + ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine1, &index, &filename)); + + // Test large index. + char kTestLine2[] = "FILE 123123123123123123123123 file name"; + ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine2, &index, &filename)); + + // Test negative index. + char kTestLine3[] = "FILE -2 file name"; + ASSERT_FALSE(SymbolParseHelper::ParseFile(kTestLine3, &index, &filename)); +} + +// Test parsing of valid FUNC lines. The format is: +// FUNC []
+TEST(SymbolParseHelper, ParseFunctionValid) { + bool multiple; + uint64_t address; + uint64_t size; + long stack_param_size; + char *name; + + char kTestLine[] = "FUNC 1 2 3 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address, + &size, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(1ULL, address); + EXPECT_EQ(2ULL, size); + EXPECT_EQ(3, stack_param_size); + EXPECT_EQ("function name", string(name)); + + // Test hex address, size, and param size. + char kTestLine1[] = "FUNC a1 a2 a3 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine1, &multiple, &address, + &size, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2ULL, size); + EXPECT_EQ(0xa3, stack_param_size); + EXPECT_EQ("function name", string(name)); + + char kTestLine2[] = "FUNC 0 0 0 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine2, &multiple, &address, + &size, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(0ULL, address); + EXPECT_EQ(0ULL, size); + EXPECT_EQ(0, stack_param_size); + EXPECT_EQ("function name", string(name)); + + // Test optional multiple field. + char kTestLine3[] = "FUNC m a1 a2 a3 function name"; + ASSERT_TRUE(SymbolParseHelper::ParseFunction(kTestLine3, &multiple, &address, + &size, &stack_param_size, + &name)); + EXPECT_TRUE(multiple); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2ULL, size); + EXPECT_EQ(0xa3, stack_param_size); + EXPECT_EQ("function name", string(name)); +} + +// Test parsing of invalid FUNC lines. The format is: +// FUNC []
+TEST(SymbolParseHelper, ParseFunctionInvalid) { + bool multiple; + uint64_t address; + uint64_t size; + long stack_param_size; + char *name; + + // Test missing function name. + char kTestLine[] = "FUNC 1 2 3 "; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test bad address. + char kTestLine1[] = "FUNC 1z 2 3 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine1, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test large address. + char kTestLine2[] = "FUNC 123123123123123123123123123 2 3 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine2, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test bad size. + char kTestLine3[] = "FUNC 1 z2 3 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine3, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test large size. + char kTestLine4[] = "FUNC 1 231231231231231231231231232 3 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine4, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test bad param size. + char kTestLine5[] = "FUNC 1 2 3z function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine5, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test large param size. + char kTestLine6[] = "FUNC 1 2 312312312312312312312312323 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine6, &multiple, &address, + &size, &stack_param_size, + &name)); + // Negative param size. + char kTestLine7[] = "FUNC 1 2 -5 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine7, &multiple, &address, + &size, &stack_param_size, + &name)); + // Test invalid optional field. + char kTestLine8[] = "FUNC x 1 2 5 function name"; + ASSERT_FALSE(SymbolParseHelper::ParseFunction(kTestLine8, &multiple, &address, + &size, &stack_param_size, + &name)); +} + +// Test parsing of valid lines. The format is: +//
+TEST(SymbolParseHelper, ParseLineValid) { + uint64_t address; + uint64_t size; + long line_number; + long source_file; + + char kTestLine[] = "1 2 3 4"; + ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine, &address, &size, + &line_number, &source_file)); + EXPECT_EQ(1ULL, address); + EXPECT_EQ(2ULL, size); + EXPECT_EQ(3, line_number); + EXPECT_EQ(4, source_file); + + // Test hex size and address. + char kTestLine1[] = "a1 a2 3 4 // some comment"; + ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine1, &address, &size, + &line_number, &source_file)); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2ULL, size); + EXPECT_EQ(3, line_number); + EXPECT_EQ(4, source_file); + + // 0 is a valid line number. + char kTestLine2[] = "a1 a2 0 4 // some comment"; + ASSERT_TRUE(SymbolParseHelper::ParseLine(kTestLine2, &address, &size, + &line_number, &source_file)); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2ULL, size); + EXPECT_EQ(0, line_number); + EXPECT_EQ(4, source_file); +} + +// Test parsing of invalid lines. The format is: +//
+TEST(SymbolParseHelper, ParseLineInvalid) { + uint64_t address; + uint64_t size; + long line_number; + long source_file; + + // Test missing source file id. + char kTestLine[] = "1 2 3"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine, &address, &size, + &line_number, &source_file)); + // Test bad address. + char kTestLine1[] = "1z 2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine1, &address, &size, + &line_number, &source_file)); + // Test large address. + char kTestLine2[] = "123123123123123123123123 2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine2, &address, &size, + &line_number, &source_file)); + // Test bad size. + char kTestLine3[] = "1 z2 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine3, &address, &size, + &line_number, &source_file)); + // Test large size. + char kTestLine4[] = "1 123123123123123123123123 3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine4, &address, &size, + &line_number, &source_file)); + // Test bad line number. + char kTestLine5[] = "1 2 z3 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine5, &address, &size, + &line_number, &source_file)); + // Test negative line number. + char kTestLine6[] = "1 2 -1 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine6, &address, &size, + &line_number, &source_file)); + // Test large line number. + char kTestLine7[] = "1 2 123123123123123123123 4"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine7, &address, &size, + &line_number, &source_file)); + // Test bad source file id. + char kTestLine8[] = "1 2 3 f"; + ASSERT_FALSE(SymbolParseHelper::ParseLine(kTestLine8, &address, &size, + &line_number, &source_file)); +} + +// Test parsing of valid PUBLIC lines. The format is: +// PUBLIC []
+TEST(SymbolParseHelper, ParsePublicSymbolValid) { + bool multiple; + uint64_t address; + long stack_param_size; + char *name; + + char kTestLine[] = "PUBLIC 1 2 3"; + ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple, + &address, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(1ULL, address); + EXPECT_EQ(2, stack_param_size); + EXPECT_EQ("3", string(name)); + + // Test hex size and address. + char kTestLine1[] = "PUBLIC a1 a2 function name"; + ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine1, &multiple, + &address, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2, stack_param_size); + EXPECT_EQ("function name", string(name)); + + // Test 0 is a valid address. + char kTestLine2[] = "PUBLIC 0 a2 function name"; + ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine2, &multiple, + &address, &stack_param_size, + &name)); + EXPECT_FALSE(multiple); + EXPECT_EQ(0ULL, address); + EXPECT_EQ(0xa2, stack_param_size); + EXPECT_EQ("function name", string(name)); + + // Test optional multiple field. + char kTestLine3[] = "PUBLIC m a1 a2 function name"; + ASSERT_TRUE(SymbolParseHelper::ParsePublicSymbol(kTestLine3, &multiple, + &address, &stack_param_size, + &name)); + EXPECT_TRUE(multiple); + EXPECT_EQ(0xa1ULL, address); + EXPECT_EQ(0xa2, stack_param_size); + EXPECT_EQ("function name", string(name)); +} + +// Test parsing of invalid PUBLIC lines. The format is: +// PUBLIC []
+TEST(SymbolParseHelper, ParsePublicSymbolInvalid) { + bool multiple; + uint64_t address; + long stack_param_size; + char *name; + + // Test missing source function name. + char kTestLine[] = "PUBLIC 1 2 "; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine, &multiple, + &address, &stack_param_size, + &name)); + // Test bad address. + char kTestLine1[] = "PUBLIC 1z 2 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine1, &multiple, + &address, &stack_param_size, + &name)); + // Test large address. + char kTestLine2[] = "PUBLIC 123123123123123123123123 2 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine2, &multiple, + &address, &stack_param_size, + &name)); + // Test bad param stack size. + char kTestLine3[] = "PUBLIC 1 z2 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine3, &multiple, + &address, &stack_param_size, + &name)); + // Test large param stack size. + char kTestLine4[] = "PUBLIC 1 123123123123123123123123123 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine4, &multiple, + &address, &stack_param_size, + &name)); + // Test negative param stack size. + char kTestLine5[] = "PUBLIC 1 -5 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine5, &multiple, + &address, &stack_param_size, + &name)); + // Test invalid optional field. + char kTestLine6[] = "PUBLIC x 1 5 3"; + ASSERT_FALSE(SymbolParseHelper::ParsePublicSymbol(kTestLine6, &multiple, + &address, &stack_param_size, + &name)); +} + +} // namespace + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/call_stack.cc b/toolkit/crashreporter/google-breakpad/src/processor/call_stack.cc new file mode 100644 index 0000000000..16cde0aae8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/call_stack.cc @@ -0,0 +1,56 @@ +// 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.cc: A call stack comprised of stack frames. +// +// See call_stack.h for documentation. +// +// Author: Mark Mentovai + +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/stack_frame.h" + +namespace google_breakpad { + +CallStack::~CallStack() { + Clear(); +} + +void CallStack::Clear() { + for (vector::const_iterator iterator = frames_.begin(); + iterator != frames_.end(); + ++iterator) { + delete *iterator; + } + tid_ = 0; + last_error_ = 0; + name_ = ""; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info-inl.h new file mode 100644 index 0000000000..7e7af0af93 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info-inl.h @@ -0,0 +1,119 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_frame_info-inl.h: Definitions for cfi_frame_info.h inlined functions. + +#ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_ +#define PROCESSOR_CFI_FRAME_INFO_INL_H_ + +#include + +namespace google_breakpad { + +template +bool SimpleCFIWalker::FindCallerRegisters( + const MemoryRegion &memory, + const CFIFrameInfo &cfi_frame_info, + const RawContextType &callee_context, + int callee_validity, + RawContextType *caller_context, + int *caller_validity) const { + typedef CFIFrameInfo::RegisterValueMap ValueMap; + ValueMap callee_registers; + ValueMap caller_registers; + // Just for brevity. + typename ValueMap::const_iterator caller_none = caller_registers.end(); + + // Populate callee_registers with register values from callee_context. + for (size_t i = 0; i < map_size_; i++) { + const RegisterSet &r = register_map_[i]; + if (callee_validity & r.validity_flag) + callee_registers[r.name] = callee_context.*r.context_member; + } + + // Apply the rules, and see what register values they yield. + if (!cfi_frame_info.FindCallerRegs(callee_registers, memory, + &caller_registers)) + return false; + + // Populate *caller_context with the values the rules placed in + // caller_registers. + memset(caller_context, 0xda, sizeof(*caller_context)); + *caller_validity = 0; + for (size_t i = 0; i < map_size_; i++) { + const RegisterSet &r = register_map_[i]; + typename ValueMap::const_iterator caller_entry; + + // Did the rules provide a value for this register by its name? + caller_entry = caller_registers.find(r.name); + if (caller_entry != caller_none) { + caller_context->*r.context_member = caller_entry->second; + *caller_validity |= r.validity_flag; + continue; + } + + // Did the rules provide a value for this register under its + // alternate name? + if (r.alternate_name) { + caller_entry = caller_registers.find(r.alternate_name); + if (caller_entry != caller_none) { + caller_context->*r.context_member = caller_entry->second; + *caller_validity |= r.validity_flag; + continue; + } + } + + // Is this a callee-saves register? The walker assumes that these + // still hold the caller's value if the CFI doesn't mention them. + // + // Note that other frame walkers may fail to recover callee-saves + // registers; for example, the x86 "traditional" strategy only + // recovers %eip, %esp, and %ebp, even though %ebx, %esi, and %edi + // are callee-saves, too. It is not correct to blindly set the + // valid bit for all callee-saves registers, without first + // checking its validity bit in the callee. + if (r.callee_saves && (callee_validity & r.validity_flag) != 0) { + caller_context->*r.context_member = callee_context.*r.context_member; + *caller_validity |= r.validity_flag; + continue; + } + + // Otherwise, the register's value is unknown. + } + + return true; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_CFI_FRAME_INFO_INL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc new file mode 100644 index 0000000000..0c4af7ba84 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_frame_info.cc: Implementation of CFIFrameInfo class. +// See cfi_frame_info.h for details. + +#include "processor/cfi_frame_info.h" + +#include + +#include + +#include "common/scoped_ptr.h" +#include "processor/postfix_evaluator-inl.h" + +namespace google_breakpad { + +#ifdef _MSC_VER +#define strtok_r strtok_s +#endif + +template +bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap ®isters, + const MemoryRegion &memory, + RegisterValueMap *caller_registers) const { + // If there are not rules for both .ra and .cfa in effect at this address, + // don't use this CFI data for stack walking. + if (cfa_rule_.empty() || ra_rule_.empty()) + return false; + + RegisterValueMap working; + PostfixEvaluator evaluator(&working, &memory); + + caller_registers->clear(); + + // First, compute the CFA. + V cfa; + working = registers; + if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) + return false; + + // Then, compute the return address. + V ra; + working = registers; + working[".cfa"] = cfa; + if (!evaluator.EvaluateForValue(ra_rule_, &ra)) + return false; + + // Now, compute values for all the registers register_rules_ mentions. + for (RuleMap::const_iterator it = register_rules_.begin(); + it != register_rules_.end(); it++) { + V value; + working = registers; + working[".cfa"] = cfa; + if (!evaluator.EvaluateForValue(it->second, &value)) + return false; + (*caller_registers)[it->first] = value; + } + + (*caller_registers)[".ra"] = ra; + (*caller_registers)[".cfa"] = cfa; + + return true; +} + +// Explicit instantiations for 32-bit and 64-bit architectures. +template bool CFIFrameInfo::FindCallerRegs( + const RegisterValueMap ®isters, + const MemoryRegion &memory, + RegisterValueMap *caller_registers) const; +template bool CFIFrameInfo::FindCallerRegs( + const RegisterValueMap ®isters, + const MemoryRegion &memory, + RegisterValueMap *caller_registers) const; + +string CFIFrameInfo::Serialize() const { + std::ostringstream stream; + + if (!cfa_rule_.empty()) { + stream << ".cfa: " << cfa_rule_; + } + if (!ra_rule_.empty()) { + if (static_cast(stream.tellp()) != 0) + stream << " "; + stream << ".ra: " << ra_rule_; + } + for (RuleMap::const_iterator iter = register_rules_.begin(); + iter != register_rules_.end(); + ++iter) { + if (static_cast(stream.tellp()) != 0) + stream << " "; + stream << iter->first << ": " << iter->second; + } + + return stream.str(); +} + +bool CFIRuleParser::Parse(const string &rule_set) { + size_t rule_set_len = rule_set.size(); + scoped_array working_copy(new char[rule_set_len + 1]); + memcpy(working_copy.get(), rule_set.data(), rule_set_len); + working_copy[rule_set_len] = '\0'; + + name_.clear(); + expression_.clear(); + + char *cursor; + static const char token_breaks[] = " \t\r\n"; + char *token = strtok_r(working_copy.get(), token_breaks, &cursor); + + for (;;) { + // End of rule set? + if (!token) return Report(); + + // Register/pseudoregister name? + size_t token_len = strlen(token); + if (token_len >= 1 && token[token_len - 1] == ':') { + // Names can't be empty. + if (token_len < 2) return false; + // If there is any pending content, report it. + if (!name_.empty() || !expression_.empty()) { + if (!Report()) return false; + } + name_.assign(token, token_len - 1); + expression_.clear(); + } else { + // Another expression component. + assert(token_len > 0); // strtok_r guarantees this, I think. + if (!expression_.empty()) + expression_ += ' '; + expression_ += token; + } + token = strtok_r(NULL, token_breaks, &cursor); + } +} + +bool CFIRuleParser::Report() { + if (name_.empty() || expression_.empty()) return false; + if (name_ == ".cfa") handler_->CFARule(expression_); + else if (name_ == ".ra") handler_->RARule(expression_); + else handler_->RegisterRule(name_, expression_); + return true; +} + +void CFIFrameInfoParseHandler::CFARule(const string &expression) { + frame_info_->SetCFARule(expression); +} + +void CFIFrameInfoParseHandler::RARule(const string &expression) { + frame_info_->SetRARule(expression); +} + +void CFIFrameInfoParseHandler::RegisterRule(const string &name, + const string &expression) { + frame_info_->SetRegisterRule(name, expression); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.h b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.h new file mode 100644 index 0000000000..90a1b3d74a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info.h @@ -0,0 +1,275 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_frame_info.h: Define the CFIFrameInfo class, which holds the +// set of 'STACK CFI'-derived register recovery rules that apply at a +// given instruction. + +#ifndef PROCESSOR_CFI_FRAME_INFO_H_ +#define PROCESSOR_CFI_FRAME_INFO_H_ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::map; + +class MemoryRegion; + +// A set of rules for recovering the calling frame's registers' +// values, when the PC is at a given address in the current frame's +// function. See the description of 'STACK CFI' records at: +// +// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md +// +// To prepare an instance of CFIFrameInfo for use at a given +// instruction, first populate it with the rules from the 'STACK CFI +// INIT' record that covers that instruction, and then apply the +// changes given by the 'STACK CFI' records up to our instruction's +// address. Then, use the FindCallerRegs member function to apply the +// rules to the callee frame's register values, yielding the caller +// frame's register values. +class CFIFrameInfo { + public: + // A map from register names onto values. + template class RegisterValueMap: + public map { }; + + // Set the expression for computing a call frame address, return + // address, or register's value. At least the CFA rule and the RA + // rule must be set before calling FindCallerRegs. + void SetCFARule(const string &expression) { cfa_rule_ = expression; } + void SetRARule(const string &expression) { ra_rule_ = expression; } + void SetRegisterRule(const string ®ister_name, const string &expression) { + register_rules_[register_name] = expression; + } + + // Compute the values of the calling frame's registers, according to + // this rule set. Use ValueType in expression evaluation; this + // should be uint32_t on machines with 32-bit addresses, or + // uint64_t on machines with 64-bit addresses. + // + // Return true on success, false otherwise. + // + // MEMORY provides access to the contents of the stack. REGISTERS is + // a dictionary mapping the names of registers whose values are + // known in the current frame to their values. CALLER_REGISTERS is + // populated with the values of the recoverable registers in the + // frame that called the current frame. + // + // In addition, CALLER_REGISTERS[".ra"] will be the return address, + // and CALLER_REGISTERS[".cfa"] will be the call frame address. + // These may be helpful in computing the caller's PC and stack + // pointer, if their values are not explicitly specified. + template + bool FindCallerRegs(const RegisterValueMap ®isters, + const MemoryRegion &memory, + RegisterValueMap *caller_registers) const; + + // Serialize the rules in this object into a string in the format + // of STACK CFI records. + string Serialize() const; + + private: + + // A map from register names onto evaluation rules. + typedef map RuleMap; + + // In this type, a "postfix expression" is an expression of the sort + // interpreted by google_breakpad::PostfixEvaluator. + + // A postfix expression for computing the current frame's CFA (call + // frame address). The CFA is a reference address for the frame that + // remains unchanged throughout the frame's lifetime. You should + // evaluate this expression with a dictionary initially populated + // with the values of the current frame's known registers. + string cfa_rule_; + + // The following expressions should be evaluated with a dictionary + // initially populated with the values of the current frame's known + // registers, and with ".cfa" set to the result of evaluating the + // cfa_rule expression, above. + + // A postfix expression for computing the current frame's return + // address. + string ra_rule_; + + // For a register named REG, rules[REG] is a postfix expression + // which leaves the value of REG in the calling frame on the top of + // the stack. You should evaluate this expression + RuleMap register_rules_; +}; + +// A parser for STACK CFI-style rule sets. +// This may seem bureaucratic: there's no legitimate run-time reason +// to use a parser/handler pattern for this, as it's not a likely +// reuse boundary. But doing so makes finer-grained unit testing +// possible. +class CFIRuleParser { + public: + + class Handler { + public: + Handler() { } + virtual ~Handler() { } + + // The input specifies EXPRESSION as the CFA/RA computation rule. + virtual void CFARule(const string &expression) = 0; + virtual void RARule(const string &expression) = 0; + + // The input specifies EXPRESSION as the recovery rule for register NAME. + virtual void RegisterRule(const string &name, const string &expression) = 0; + }; + + // Construct a parser which feeds its results to HANDLER. + CFIRuleParser(Handler *handler) : handler_(handler) { } + + // Parse RULE_SET as a set of CFA computation and RA/register + // recovery rules, as appearing in STACK CFI records. Report the + // results of parsing by making the appropriate calls to handler_. + // Return true if parsing was successful, false otherwise. + bool Parse(const string &rule_set); + + private: + // Report any accumulated rule to handler_ + bool Report(); + + // The handler to which the parser reports its findings. + Handler *handler_; + + // Working data. + string name_, expression_; +}; + +// A handler for rule set parsing that populates a CFIFrameInfo with +// the results. +class CFIFrameInfoParseHandler: public CFIRuleParser::Handler { + public: + // Populate FRAME_INFO with the results of parsing. + CFIFrameInfoParseHandler(CFIFrameInfo *frame_info) + : frame_info_(frame_info) { } + + void CFARule(const string &expression); + void RARule(const string &expression); + void RegisterRule(const string &name, const string &expression); + + private: + CFIFrameInfo *frame_info_; +}; + +// A utility class template for simple 'STACK CFI'-driven stack walkers. +// Given a CFIFrameInfo instance, a table describing the architecture's +// register set, and a context holding the last frame's registers, an +// instance of this class can populate a new context with the caller's +// registers. +// +// This class template doesn't use any internal knowledge of CFIFrameInfo +// or the other stack walking structures; it just uses the public interface +// of CFIFrameInfo to do the usual things. But the logic it handles should +// be common to many different architectures' stack walkers, so wrapping it +// up in a class should allow the walkers to share code. +// +// RegisterType should be the type of this architecture's registers, either +// uint32_t or uint64_t. RawContextType should be the raw context +// structure type for this architecture. +template +class SimpleCFIWalker { + public: + // A structure describing one architecture register. + struct RegisterSet { + // The register name, as it appears in STACK CFI rules. + const char *name; + + // An alternate name that the register's value might be found + // under in a register value dictionary, or NULL. When generating + // names, prefer NAME to this value. It's common to list ".cfa" as + // an alternative name for the stack pointer, and ".ra" as an + // alternative name for the instruction pointer. + const char *alternate_name; + + // True if the callee is expected to preserve the value of this + // register. If this flag is true for some register R, and the STACK + // CFI records provide no rule to recover R, then SimpleCFIWalker + // assumes that the callee has not changed R's value, and the caller's + // value for R is that currently in the callee's context. + bool callee_saves; + + // The ContextValidity flag representing the register's presence. + int validity_flag; + + // A pointer to the RawContextType member that holds the + // register's value. + RegisterType RawContextType::*context_member; + }; + + // Create a simple CFI-based frame walker, given a description of the + // architecture's register set. REGISTER_MAP is an array of + // RegisterSet structures; MAP_SIZE is the number of elements in the + // array. + SimpleCFIWalker(const RegisterSet *register_map, size_t map_size) + : register_map_(register_map), map_size_(map_size) { } + + // Compute the calling frame's raw context given the callee's raw + // context. + // + // Given: + // + // - MEMORY, holding the stack's contents, + // - CFI_FRAME_INFO, describing the called function, + // - CALLEE_CONTEXT, holding the called frame's registers, and + // - CALLEE_VALIDITY, indicating which registers in CALLEE_CONTEXT are valid, + // + // fill in CALLER_CONTEXT with the caller's register values, and set + // CALLER_VALIDITY to indicate which registers are valid in + // CALLER_CONTEXT. Return true on success, or false on failure. + bool FindCallerRegisters(const MemoryRegion &memory, + const CFIFrameInfo &cfi_frame_info, + const RawContextType &callee_context, + int callee_validity, + RawContextType *caller_context, + int *caller_validity) const; + + private: + const RegisterSet *register_map_; + size_t map_size_; +}; + +} // namespace google_breakpad + +#include "cfi_frame_info-inl.h" + +#endif // PROCESSOR_CFI_FRAME_INFO_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info_unittest.cc new file mode 100644 index 0000000000..542b28492e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/cfi_frame_info_unittest.cc @@ -0,0 +1,546 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// cfi_frame_info_unittest.cc: Unit tests for CFIFrameInfo, +// CFIRuleParser, CFIFrameInfoParseHandler, and SimpleCFIWalker. + +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "processor/cfi_frame_info.h" +#include "google_breakpad/processor/memory_region.h" + +using google_breakpad::CFIFrameInfo; +using google_breakpad::CFIFrameInfoParseHandler; +using google_breakpad::CFIRuleParser; +using google_breakpad::MemoryRegion; +using google_breakpad::SimpleCFIWalker; +using testing::_; +using testing::A; +using testing::AtMost; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class MockMemoryRegion: public MemoryRegion { + public: + MOCK_CONST_METHOD0(GetBase, uint64_t()); + MOCK_CONST_METHOD0(GetSize, uint32_t()); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint8_t *)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint16_t *)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint32_t *)); + MOCK_CONST_METHOD2(GetMemoryAtAddress, bool(uint64_t, uint64_t *)); + MOCK_CONST_METHOD0(Print, void()); +}; + +// Handy definitions for all tests. +struct CFIFixture { + + // Set up the mock memory object to expect no references. + void ExpectNoMemoryReferences() { + EXPECT_CALL(memory, GetBase()).Times(0); + EXPECT_CALL(memory, GetSize()).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A())).Times(0); + EXPECT_CALL(memory, GetMemoryAtAddress(_, A())).Times(0); + } + + CFIFrameInfo cfi; + MockMemoryRegion memory; + CFIFrameInfo::RegisterValueMap registers, caller_registers; +}; + +class Simple: public CFIFixture, public Test { }; + +// FindCallerRegs should fail if no .cfa rule is provided. +TEST_F(Simple, NoCFA) { + ExpectNoMemoryReferences(); + + cfi.SetRARule("0"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(".ra: 0", cfi.Serialize()); +} + +// FindCallerRegs should fail if no .ra rule is provided. +TEST_F(Simple, NoRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("0"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(".cfa: 0", cfi.Serialize()); +} + +TEST_F(Simple, SetCFAAndRARule) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("330903416631436410"); + cfi.SetRARule("5870666104170902211"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(330903416631436410ULL, caller_registers[".cfa"]); + ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); + + ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211", + cfi.Serialize()); +} + +TEST_F(Simple, SetManyRules) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -"); + cfi.SetRARule(".cfa 99804755 +"); + cfi.SetRegisterRule("register1", ".cfa 54370437 *"); + cfi.SetRegisterRule("vodkathumbscrewingly", "24076308 .cfa +"); + cfi.SetRegisterRule("pubvexingfjordschmaltzy", ".cfa 29801007 -"); + cfi.SetRegisterRule("uncopyrightables", "92642917 .cfa /"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(6U, caller_registers.size()); + ASSERT_EQ(7664691U, caller_registers[".cfa"]); + ASSERT_EQ(107469446U, caller_registers[".ra"]); + ASSERT_EQ(416732599139967ULL, caller_registers["register1"]); + ASSERT_EQ(31740999U, caller_registers["vodkathumbscrewingly"]); + ASSERT_EQ(-22136316ULL, caller_registers["pubvexingfjordschmaltzy"]); + ASSERT_EQ(12U, caller_registers["uncopyrightables"]); + ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - " + ".ra: .cfa 99804755 + " + "pubvexingfjordschmaltzy: .cfa 29801007 - " + "register1: .cfa 54370437 * " + "uncopyrightables: 92642917 .cfa / " + "vodkathumbscrewingly: 24076308 .cfa +", + cfi.Serialize()); +} + +TEST_F(Simple, RulesOverride) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("330903416631436410"); + cfi.SetRARule("5870666104170902211"); + cfi.SetCFARule("2828089117179001"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(2828089117179001ULL, caller_registers[".cfa"]); + ASSERT_EQ(5870666104170902211ULL, caller_registers[".ra"]); + ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211", + cfi.Serialize()); +} + +class Scope: public CFIFixture, public Test { }; + +// There should be no value for .cfa in scope when evaluating the CFA rule. +TEST_F(Scope, CFALacksCFA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(".cfa"); + cfi.SetRARule("0"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +} + +// There should be no value for .ra in scope when evaluating the CFA rule. +TEST_F(Scope, CFALacksRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule(".ra"); + cfi.SetRARule("0"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +} + +// The current frame's registers should be in scope when evaluating +// the CFA rule. +TEST_F(Scope, CFASeesCurrentRegs) { + ExpectNoMemoryReferences(); + + registers[".baraminology"] = 0x06a7bc63e4f13893ULL; + registers[".ornithorhynchus"] = 0x5e0bf850bafce9d2ULL; + cfi.SetCFARule(".baraminology .ornithorhynchus +"); + cfi.SetRARule("0"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(0x06a7bc63e4f13893ULL + 0x5e0bf850bafce9d2ULL, + caller_registers[".cfa"]); +} + +// .cfa should be in scope in the return address expression. +TEST_F(Scope, RASeesCFA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("48364076"); + cfi.SetRARule(".cfa"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(48364076U, caller_registers[".ra"]); +} + +// There should be no value for .ra in scope when evaluating the CFA rule. +TEST_F(Scope, RALacksRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("0"); + cfi.SetRARule(".ra"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +} + +// The current frame's registers should be in scope in the return +// address expression. +TEST_F(Scope, RASeesCurrentRegs) { + ExpectNoMemoryReferences(); + + registers["noachian"] = 0x54dc4a5d8e5eb503ULL; + cfi.SetCFARule("10359370"); + cfi.SetRARule("noachian"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(2U, caller_registers.size()); + ASSERT_EQ(0x54dc4a5d8e5eb503ULL, caller_registers[".ra"]); +} + +// .cfa should be in scope for register rules. +TEST_F(Scope, RegistersSeeCFA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("6515179"); + cfi.SetRARule(".cfa"); + cfi.SetRegisterRule("rogerian", ".cfa"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(3U, caller_registers.size()); + ASSERT_EQ(6515179U, caller_registers["rogerian"]); +} + +// The return address should not be in scope for register rules. +TEST_F(Scope, RegsLackRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("42740329"); + cfi.SetRARule("27045204"); + cfi.SetRegisterRule("$r1", ".ra"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +} + +// Register rules can see the current frame's register values. +TEST_F(Scope, RegsSeeRegs) { + ExpectNoMemoryReferences(); + + registers["$r1"] = 0x6ed3582c4bedb9adULL; + registers["$r2"] = 0xd27d9e742b8df6d0ULL; + cfi.SetCFARule("88239303"); + cfi.SetRARule("30503835"); + cfi.SetRegisterRule("$r1", "$r1 42175211 = $r2"); + cfi.SetRegisterRule("$r2", "$r2 21357221 = $r1"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(4U, caller_registers.size()); + ASSERT_EQ(0xd27d9e742b8df6d0ULL, caller_registers["$r1"]); + ASSERT_EQ(0x6ed3582c4bedb9adULL, caller_registers["$r2"]); +} + +// Each rule's temporaries are separate. +TEST_F(Scope, SeparateTempsRA) { + ExpectNoMemoryReferences(); + + cfi.SetCFARule("$temp1 76569129 = $temp1"); + cfi.SetRARule("0"); + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + + cfi.SetCFARule("$temp1 76569129 = $temp1"); + cfi.SetRARule("$temp1"); + ASSERT_FALSE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); +} + +class MockCFIRuleParserHandler: public CFIRuleParser::Handler { + public: + MOCK_METHOD1(CFARule, void(const string &)); + MOCK_METHOD1(RARule, void(const string &)); + MOCK_METHOD2(RegisterRule, void(const string &, const string &)); +}; + +// A fixture class for testing CFIRuleParser. +class CFIParserFixture { + public: + CFIParserFixture() : parser(&mock_handler) { + // Expect no parsing results to be reported to mock_handler. Individual + // tests can override this. + EXPECT_CALL(mock_handler, CFARule(_)).Times(0); + EXPECT_CALL(mock_handler, RARule(_)).Times(0); + EXPECT_CALL(mock_handler, RegisterRule(_, _)).Times(0); + } + + MockCFIRuleParserHandler mock_handler; + CFIRuleParser parser; +}; + +class Parser: public CFIParserFixture, public Test { }; + +TEST_F(Parser, Empty) { + EXPECT_FALSE(parser.Parse("")); +} + +TEST_F(Parser, LoneColon) { + EXPECT_FALSE(parser.Parse(":")); +} + +TEST_F(Parser, CFANoExpr) { + EXPECT_FALSE(parser.Parse(".cfa:")); +} + +TEST_F(Parser, CFANoColonNoExpr) { + EXPECT_FALSE(parser.Parse(".cfa")); +} + +TEST_F(Parser, RANoExpr) { + EXPECT_FALSE(parser.Parse(".ra:")); +} + +TEST_F(Parser, RANoColonNoExpr) { + EXPECT_FALSE(parser.Parse(".ra")); +} + +TEST_F(Parser, RegNoExpr) { + EXPECT_FALSE(parser.Parse("reg:")); +} + +TEST_F(Parser, NoName) { + EXPECT_FALSE(parser.Parse("expr")); +} + +TEST_F(Parser, NoNameTwo) { + EXPECT_FALSE(parser.Parse("expr1 expr2")); +} + +TEST_F(Parser, StartsWithExpr) { + EXPECT_FALSE(parser.Parse("expr1 reg: expr2")); +} + +TEST_F(Parser, CFA) { + EXPECT_CALL(mock_handler, CFARule("spleen")).WillOnce(Return()); + EXPECT_TRUE(parser.Parse(".cfa: spleen")); +} + +TEST_F(Parser, RA) { + EXPECT_CALL(mock_handler, RARule("notoriety")).WillOnce(Return()); + EXPECT_TRUE(parser.Parse(".ra: notoriety")); +} + +TEST_F(Parser, Reg) { + EXPECT_CALL(mock_handler, RegisterRule("nemo", "mellifluous")) + .WillOnce(Return()); + EXPECT_TRUE(parser.Parse("nemo: mellifluous")); +} + +TEST_F(Parser, CFARARegs) { + EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return()); + EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return()); + EXPECT_CALL(mock_handler, RegisterRule("galba", "praetorian")) + .WillOnce(Return()); + EXPECT_CALL(mock_handler, RegisterRule("otho", "vitellius")) + .WillOnce(Return()); + EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression " + "galba: praetorian otho: vitellius")); +} + +TEST_F(Parser, Whitespace) { + EXPECT_CALL(mock_handler, RegisterRule("r1", "r1 expression")) + .WillOnce(Return()); + EXPECT_CALL(mock_handler, RegisterRule("r2", "r2 expression")) + .WillOnce(Return()); + EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n " + "expression \n")); +} + +TEST_F(Parser, WhitespaceLoneColon) { + EXPECT_FALSE(parser.Parse(" \n:\t ")); +} + +TEST_F(Parser, EmptyName) { + EXPECT_CALL(mock_handler, RegisterRule("reg", _)) + .Times(AtMost(1)) + .WillRepeatedly(Return()); + EXPECT_FALSE(parser.Parse("reg: expr1 : expr2")); +} + +TEST_F(Parser, RuleLoneColon) { + EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) + .Times(AtMost(1)) + .WillRepeatedly(Return()); + EXPECT_FALSE(parser.Parse(" r1: expr :")); +} + +TEST_F(Parser, RegNoExprRule) { + EXPECT_CALL(mock_handler, RegisterRule("r1", "expr")) + .Times(AtMost(1)) + .WillRepeatedly(Return()); + EXPECT_FALSE(parser.Parse("r0: r1: expr")); +} + +class ParseHandlerFixture: public CFIFixture { + public: + ParseHandlerFixture() : CFIFixture(), handler(&cfi) { } + CFIFrameInfoParseHandler handler; +}; + +class ParseHandler: public ParseHandlerFixture, public Test { }; + +TEST_F(ParseHandler, CFARARule) { + handler.CFARule("reg-for-cfa"); + handler.RARule("reg-for-ra"); + registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; + registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); +} + +TEST_F(ParseHandler, RegisterRules) { + handler.CFARule("reg-for-cfa"); + handler.RARule("reg-for-ra"); + handler.RegisterRule("reg1", "reg-for-reg1"); + handler.RegisterRule("reg2", "reg-for-reg2"); + registers["reg-for-cfa"] = 0x268a9a4a3821a797ULL; + registers["reg-for-ra"] = 0x6301b475b8b91c02ULL; + registers["reg-for-reg1"] = 0x06cde8e2ff062481ULL; + registers["reg-for-reg2"] = 0xff0c4f76403173e2ULL; + ASSERT_TRUE(cfi.FindCallerRegs(registers, memory, + &caller_registers)); + ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers[".cfa"]); + ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers[".ra"]); + ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers["reg1"]); + ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers["reg2"]); +} + +struct SimpleCFIWalkerFixture { + struct RawContext { + uint64_t r0, r1, r2, r3, r4, sp, pc; + }; + enum Validity { + R0_VALID = 0x01, + R1_VALID = 0x02, + R2_VALID = 0x04, + R3_VALID = 0x08, + R4_VALID = 0x10, + SP_VALID = 0x20, + PC_VALID = 0x40 + }; + typedef SimpleCFIWalker CFIWalker; + + SimpleCFIWalkerFixture() + : walker(register_map, + sizeof(register_map) / sizeof(register_map[0])) { } + + static CFIWalker::RegisterSet register_map[7]; + CFIFrameInfo call_frame_info; + CFIWalker walker; + MockMemoryRegion memory; + RawContext callee_context, caller_context; +}; + +SimpleCFIWalkerFixture::CFIWalker::RegisterSet +SimpleCFIWalkerFixture::register_map[7] = { + { "r0", NULL, true, R0_VALID, &RawContext::r0 }, + { "r1", NULL, true, R1_VALID, &RawContext::r1 }, + { "r2", NULL, false, R2_VALID, &RawContext::r2 }, + { "r3", NULL, false, R3_VALID, &RawContext::r3 }, + { "r4", NULL, true, R4_VALID, &RawContext::r4 }, + { "sp", ".cfa", true, SP_VALID, &RawContext::sp }, + { "pc", ".ra", true, PC_VALID, &RawContext::pc }, +}; + +class SimpleWalker: public SimpleCFIWalkerFixture, public Test { }; + +TEST_F(SimpleWalker, Walk) { + // Stack_top is the current stack pointer, pointing to the lowest + // address of a frame that looks like this (all 64-bit words): + // + // sp -> saved r0 + // garbage + // return address + // cfa -> + // + // r0 has been saved on the stack. + // r1 has been saved in r2. + // r2 and r3 are not recoverable. + // r4 is not recoverable, even though it is a callee-saves register. + // Some earlier frame's unwinder must have failed to recover it. + + uint64_t stack_top = 0x83254944b20d5512ULL; + + // Saved r0. + EXPECT_CALL(memory, + GetMemoryAtAddress(stack_top, A())) + .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xdc1975eba8602302ULL), + Return(true))); + // Saved return address. + EXPECT_CALL(memory, + GetMemoryAtAddress(stack_top + 16, A())) + .WillRepeatedly(DoAll(SetArgumentPointee<1>(0xba5ad6d9acce28deULL), + Return(true))); + + call_frame_info.SetCFARule("sp 24 +"); + call_frame_info.SetRARule(".cfa 8 - ^"); + call_frame_info.SetRegisterRule("r0", ".cfa 24 - ^"); + call_frame_info.SetRegisterRule("r1", "r2"); + + callee_context.r0 = 0x94e030ca79edd119ULL; + callee_context.r1 = 0x937b4d7e95ce52d9ULL; + callee_context.r2 = 0x5fe0027416b8b62aULL; // caller's r1 + // callee_context.r3 is not valid in callee. + // callee_context.r4 is not valid in callee. + callee_context.sp = stack_top; + callee_context.pc = 0x25b21b224311d280ULL; + int callee_validity = R0_VALID | R1_VALID | R2_VALID | SP_VALID | PC_VALID; + + memset(&caller_context, 0, sizeof(caller_context)); + + int caller_validity; + EXPECT_TRUE(walker.FindCallerRegisters(memory, call_frame_info, + callee_context, callee_validity, + &caller_context, &caller_validity)); + EXPECT_EQ(R0_VALID | R1_VALID | SP_VALID | PC_VALID, caller_validity); + EXPECT_EQ(0xdc1975eba8602302ULL, caller_context.r0); + EXPECT_EQ(0x5fe0027416b8b62aULL, caller_context.r1); + EXPECT_EQ(stack_top + 24, caller_context.sp); + EXPECT_EQ(0xba5ad6d9acce28deULL, caller_context.pc); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map-inl.h new file mode 100644 index 0000000000..4c0ad41f94 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map-inl.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 "processor/contained_range_map.h" + +#include + +#include "processor/logging.h" + + +namespace google_breakpad { + + +template +ContainedRangeMap::~ContainedRangeMap() { + // Clear frees the children pointed to by the map, and frees the map itself. + Clear(); +} + + +template +bool ContainedRangeMap::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 +bool ContainedRangeMap::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 +void ContainedRangeMap::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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map.h b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map.h new file mode 100644 index 0000000000..1015ae8cfd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map.h @@ -0,0 +1,150 @@ +// 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 + + +namespace google_breakpad { + +// Forward declarations (for later friend declarations of specialized template). +template class ContainedRangeMapSerializer; + +template +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: + friend class ContainedRangeMapSerializer; + friend class ModuleComparer; + + // AddressToRangeMap stores pointers. This makes reparenting simpler in + // StoreRange, because it doesn't need to copy entire objects. + typedef std::map 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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map_unittest.cc new file mode 100644 index 0000000000..e5910da0d5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/contained_range_map_unittest.cc @@ -0,0 +1,263 @@ +// 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_unittest.cc: Unit tests for ContainedRangeMap +// +// Author: Mark Mentovai + +#include + +#include "processor/contained_range_map-inl.h" + +#include "processor/logging.h" + + +#define ASSERT_TRUE(condition) \ + if (!(condition)) { \ + fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \ + return false; \ + } + +#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition)) + + +namespace { + + +using google_breakpad::ContainedRangeMap; + + +static bool RunTests() { + ContainedRangeMap crm; + + // First, do the StoreRange tests. This validates the containment + // rules. + ASSERT_TRUE (crm.StoreRange(10, 10, 1)); + ASSERT_FALSE(crm.StoreRange(10, 10, 2)); // exactly equal to 1 + ASSERT_FALSE(crm.StoreRange(11, 10, 3)); // begins inside 1 and extends up + ASSERT_FALSE(crm.StoreRange( 9, 10, 4)); // begins below 1 and ends inside + ASSERT_TRUE (crm.StoreRange(11, 9, 5)); // contained by existing + ASSERT_TRUE (crm.StoreRange(12, 7, 6)); + ASSERT_TRUE (crm.StoreRange( 9, 12, 7)); // contains existing + ASSERT_TRUE (crm.StoreRange( 9, 13, 8)); + ASSERT_TRUE (crm.StoreRange( 8, 14, 9)); + ASSERT_TRUE (crm.StoreRange(30, 3, 10)); + ASSERT_TRUE (crm.StoreRange(33, 3, 11)); + ASSERT_TRUE (crm.StoreRange(30, 6, 12)); // storable but totally masked + ASSERT_TRUE (crm.StoreRange(40, 8, 13)); // will be totally masked + ASSERT_TRUE (crm.StoreRange(40, 4, 14)); + ASSERT_TRUE (crm.StoreRange(44, 4, 15)); + ASSERT_FALSE(crm.StoreRange(32, 10, 16)); // begins in #10, ends in #14 + ASSERT_FALSE(crm.StoreRange(50, 0, 17)); // zero length + ASSERT_TRUE (crm.StoreRange(50, 10, 18)); + ASSERT_TRUE (crm.StoreRange(50, 1, 19)); + ASSERT_TRUE (crm.StoreRange(59, 1, 20)); + ASSERT_TRUE (crm.StoreRange(60, 1, 21)); + ASSERT_TRUE (crm.StoreRange(69, 1, 22)); + ASSERT_TRUE (crm.StoreRange(60, 10, 23)); + ASSERT_TRUE (crm.StoreRange(68, 1, 24)); + ASSERT_TRUE (crm.StoreRange(61, 1, 25)); + ASSERT_TRUE (crm.StoreRange(61, 8, 26)); + ASSERT_FALSE(crm.StoreRange(59, 9, 27)); + ASSERT_FALSE(crm.StoreRange(59, 10, 28)); + ASSERT_FALSE(crm.StoreRange(59, 11, 29)); + ASSERT_TRUE (crm.StoreRange(70, 10, 30)); + ASSERT_TRUE (crm.StoreRange(74, 2, 31)); + ASSERT_TRUE (crm.StoreRange(77, 2, 32)); + ASSERT_FALSE(crm.StoreRange(72, 6, 33)); + ASSERT_TRUE (crm.StoreRange(80, 3, 34)); + ASSERT_TRUE (crm.StoreRange(81, 1, 35)); + ASSERT_TRUE (crm.StoreRange(82, 1, 36)); + ASSERT_TRUE (crm.StoreRange(83, 3, 37)); + ASSERT_TRUE (crm.StoreRange(84, 1, 38)); + ASSERT_TRUE (crm.StoreRange(83, 1, 39)); + ASSERT_TRUE (crm.StoreRange(86, 5, 40)); + ASSERT_TRUE (crm.StoreRange(88, 1, 41)); + ASSERT_TRUE (crm.StoreRange(90, 1, 42)); + ASSERT_TRUE (crm.StoreRange(86, 1, 43)); + ASSERT_TRUE (crm.StoreRange(87, 1, 44)); + ASSERT_TRUE (crm.StoreRange(89, 1, 45)); + ASSERT_TRUE (crm.StoreRange(87, 4, 46)); + ASSERT_TRUE (crm.StoreRange(87, 3, 47)); + ASSERT_FALSE(crm.StoreRange(86, 2, 48)); + + // Each element in test_data contains the expected result when calling + // RetrieveRange on an address. + const int test_data[] = { + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 9, // 8 + 7, // 9 + 1, // 10 + 5, // 11 + 6, // 12 + 6, // 13 + 6, // 14 + 6, // 15 + 6, // 16 + 6, // 17 + 6, // 18 + 5, // 19 + 7, // 20 + 8, // 21 + 0, // 22 + 0, // 23 + 0, // 24 + 0, // 25 + 0, // 26 + 0, // 27 + 0, // 28 + 0, // 29 + 10, // 30 + 10, // 31 + 10, // 32 + 11, // 33 + 11, // 34 + 11, // 35 + 0, // 36 + 0, // 37 + 0, // 38 + 0, // 39 + 14, // 40 + 14, // 41 + 14, // 42 + 14, // 43 + 15, // 44 + 15, // 45 + 15, // 46 + 15, // 47 + 0, // 48 + 0, // 49 + 19, // 50 + 18, // 51 + 18, // 52 + 18, // 53 + 18, // 54 + 18, // 55 + 18, // 56 + 18, // 57 + 18, // 58 + 20, // 59 + 21, // 60 + 25, // 61 + 26, // 62 + 26, // 63 + 26, // 64 + 26, // 65 + 26, // 66 + 26, // 67 + 24, // 68 + 22, // 69 + 30, // 70 + 30, // 71 + 30, // 72 + 30, // 73 + 31, // 74 + 31, // 75 + 30, // 76 + 32, // 77 + 32, // 78 + 30, // 79 + 34, // 80 + 35, // 81 + 36, // 82 + 39, // 83 + 38, // 84 + 37, // 85 + 43, // 86 + 44, // 87 + 41, // 88 + 45, // 89 + 42, // 90 + 0, // 91 + 0, // 92 + 0, // 93 + 0, // 94 + 0, // 95 + 0, // 96 + 0, // 97 + 0, // 98 + 0 // 99 + }; + unsigned int test_high = sizeof(test_data) / sizeof(int); + + // Now, do the RetrieveRange tests. This further validates that the + // objects were stored properly and that retrieval returns the correct + // object. + // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a + // new test_data array will be printed. Exercise caution when doing this. + // Be sure to verify the results manually! +#ifdef GENERATE_TEST_DATA + printf(" const int test_data[] = {\n"); +#endif // GENERATE_TEST_DATA + + for (unsigned int address = 0; address < test_high; ++address) { + int value; + if (!crm.RetrieveRange(address, &value)) + value = 0; + +#ifndef GENERATE_TEST_DATA + // Don't use ASSERT inside the loop because it won't show the failed + // |address|, and the line number will always be the same. That makes + // it difficult to figure out which test failed. + if (value != test_data[address]) { + fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n", + address, test_data[address], value, __FILE__, __LINE__); + return false; + } +#else // !GENERATE_TEST_DATA + printf(" %d%c%s // %d\n", value, + address == test_high - 1 ? ' ' : ',', + value < 10 ? " " : "", + address); +#endif // !GENERATE_TEST_DATA + } + +#ifdef GENERATE_TEST_DATA + printf(" };\n"); +#endif // GENERATE_TEST_DATA + + return true; +} + + +} // namespace + + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.cc b/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.cc new file mode 100644 index 0000000000..d4b749e7f2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2018, 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 "processor/convert_old_arm64_context.h" + +#include + +namespace google_breakpad { + +void ConvertOldARM64Context(const MDRawContextARM64_Old& old, + MDRawContextARM64* context) { + context->context_flags = MD_CONTEXT_ARM64; + if (old.context_flags & MD_CONTEXT_ARM64_INTEGER_OLD) { + context->context_flags |= + MD_CONTEXT_ARM64_INTEGER | MD_CONTEXT_ARM64_CONTROL; + } + if (old.context_flags & MD_CONTEXT_ARM64_FLOATING_POINT_OLD) { + context->context_flags |= MD_CONTEXT_ARM64_FLOATING_POINT; + } + + context->cpsr = old.cpsr; + + static_assert(sizeof(old.iregs) == sizeof(context->iregs), + "iregs size mismatch"); + memcpy(context->iregs, old.iregs, sizeof(context->iregs)); + + static_assert(sizeof(old.float_save.regs) == sizeof(context->float_save.regs), + "float_save.regs size mismatch"); + memcpy(context->float_save.regs, + old.float_save.regs, + sizeof(context->float_save.regs)); + context->float_save.fpcr = old.float_save.fpcr; + context->float_save.fpsr = old.float_save.fpsr; + + memset(context->bcr, 0, sizeof(context->bcr)); + memset(context->bvr, 0, sizeof(context->bvr)); + memset(context->wcr, 0, sizeof(context->wcr)); + memset(context->wvr, 0, sizeof(context->wvr)); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.h b/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.h new file mode 100644 index 0000000000..8c0dfe900c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/convert_old_arm64_context.h @@ -0,0 +1,42 @@ +// Copyright (c) 2018, 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 PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ +#define PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ + +#include "google_breakpad/common/minidump_cpu_arm64.h" + +namespace google_breakpad { + +void ConvertOldARM64Context(const MDRawContextARM64_Old& old, + MDRawContextARM64* context); + +} // namespace google_breakpad + +#endif // PROCESSOR_CONVERT_OLD_ARM64_CONTEXT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.cc b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.cc new file mode 100644 index 0000000000..559022404f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.cc @@ -0,0 +1,240 @@ +// 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. + +// disassembler_x86.cc: simple x86 disassembler. +// +// Provides single step disassembly of x86 bytecode and flags instructions +// that utilize known bad register values. +// +// Author: Cris Neckar + +#include "processor/disassembler_x86.h" + +#include + +namespace google_breakpad { + +DisassemblerX86::DisassemblerX86(const uint8_t *bytecode, + uint32_t size, + uint32_t virtual_address) : + bytecode_(bytecode), + size_(size), + virtual_address_(virtual_address), + current_byte_offset_(0), + current_inst_offset_(0), + instr_valid_(false), + register_valid_(false), + pushed_bad_value_(false), + end_of_block_(false), + flags_(0) { + libdis::x86_init(libdis::opt_none, NULL, NULL); +} + +DisassemblerX86::~DisassemblerX86() { + if (instr_valid_) + libdis::x86_oplist_free(¤t_instr_); + + libdis::x86_cleanup(); +} + +uint32_t DisassemblerX86::NextInstruction() { + if (instr_valid_) + libdis::x86_oplist_free(¤t_instr_); + + if (current_byte_offset_ >= size_) { + instr_valid_ = false; + return 0; + } + uint32_t instr_size = 0; + instr_size = libdis::x86_disasm((unsigned char *)bytecode_, size_, + virtual_address_, current_byte_offset_, + ¤t_instr_); + if (instr_size == 0) { + instr_valid_ = false; + return 0; + } + + current_byte_offset_ += instr_size; + current_inst_offset_++; + instr_valid_ = libdis::x86_insn_is_valid(¤t_instr_); + if (!instr_valid_) + return 0; + + if (current_instr_.type == libdis::insn_return) + end_of_block_ = true; + libdis::x86_op_t *src = libdis::x86_get_src_operand(¤t_instr_); + libdis::x86_op_t *dest = libdis::x86_get_dest_operand(¤t_instr_); + + if (register_valid_) { + switch (current_instr_.group) { + // Flag branches based off of bad registers and calls that occur + // after pushing bad values. + case libdis::insn_controlflow: + switch (current_instr_.type) { + case libdis::insn_jmp: + case libdis::insn_jcc: + case libdis::insn_call: + case libdis::insn_callcc: + if (dest) { + switch (dest->type) { + case libdis::op_expression: + if (dest->data.expression.base.id == bad_register_.id) + flags_ |= DISX86_BAD_BRANCH_TARGET; + break; + case libdis::op_register: + if (dest->data.reg.id == bad_register_.id) + flags_ |= DISX86_BAD_BRANCH_TARGET; + break; + default: + if (pushed_bad_value_ && + (current_instr_.type == libdis::insn_call || + current_instr_.type == libdis::insn_callcc)) + flags_ |= DISX86_BAD_ARGUMENT_PASSED; + break; + } + } + break; + default: + break; + } + break; + + // Flag block data operations that use bad registers for src or dest. + case libdis::insn_string: + if (dest && dest->type == libdis::op_expression && + dest->data.expression.base.id == bad_register_.id) + flags_ |= DISX86_BAD_BLOCK_WRITE; + if (src && src->type == libdis::op_expression && + src->data.expression.base.id == bad_register_.id) + flags_ |= DISX86_BAD_BLOCK_READ; + break; + + // Flag comparisons based on bad data. + case libdis::insn_comparison: + if ((dest && dest->type == libdis::op_expression && + dest->data.expression.base.id == bad_register_.id) || + (src && src->type == libdis::op_expression && + src->data.expression.base.id == bad_register_.id) || + (dest && dest->type == libdis::op_register && + dest->data.reg.id == bad_register_.id) || + (src && src->type == libdis::op_register && + src->data.reg.id == bad_register_.id)) + flags_ |= DISX86_BAD_COMPARISON; + break; + + // Flag any other instruction which derefs a bad register for + // src or dest. + default: + if (dest && dest->type == libdis::op_expression && + dest->data.expression.base.id == bad_register_.id) + flags_ |= DISX86_BAD_WRITE; + if (src && src->type == libdis::op_expression && + src->data.expression.base.id == bad_register_.id) + flags_ |= DISX86_BAD_READ; + break; + } + } + + // When a register is marked as tainted check if it is pushed. + // TODO(cdn): may also want to check for MOVs into EBP offsets. + if (register_valid_ && dest && current_instr_.type == libdis::insn_push) { + switch (dest->type) { + case libdis::op_expression: + if (dest->data.expression.base.id == bad_register_.id || + dest->data.expression.index.id == bad_register_.id) + pushed_bad_value_ = true; + break; + case libdis::op_register: + if (dest->data.reg.id == bad_register_.id) + pushed_bad_value_ = true; + break; + default: + break; + } + } + + // Check if a tainted register value is clobbered. + // For conditional MOVs and XCHGs assume that + // there is a hit. + if (register_valid_) { + switch (current_instr_.type) { + case libdis::insn_xor: + if (src && src->type == libdis::op_register && + dest && dest->type == libdis::op_register && + src->data.reg.id == bad_register_.id && + src->data.reg.id == dest->data.reg.id) + register_valid_ = false; + break; + case libdis::insn_pop: + case libdis::insn_mov: + case libdis::insn_movcc: + if (dest && dest->type == libdis::op_register && + dest->data.reg.id == bad_register_.id) + register_valid_ = false; + break; + case libdis::insn_popregs: + register_valid_ = false; + break; + case libdis::insn_xchg: + case libdis::insn_xchgcc: + if (dest && dest->type == libdis::op_register && + src && src->type == libdis::op_register) { + if (dest->data.reg.id == bad_register_.id) + memcpy(&bad_register_, &src->data.reg, sizeof(libdis::x86_reg_t)); + else if (src->data.reg.id == bad_register_.id) + memcpy(&bad_register_, &dest->data.reg, sizeof(libdis::x86_reg_t)); + } + break; + default: + break; + } + } + + return instr_size; +} + +bool DisassemblerX86::setBadRead() { + if (!instr_valid_) + return false; + + libdis::x86_op_t *operand = libdis::x86_get_src_operand(¤t_instr_); + if (!operand || operand->type != libdis::op_expression) + return false; + + memcpy(&bad_register_, &operand->data.expression.base, + sizeof(libdis::x86_reg_t)); + register_valid_ = true; + return true; +} + +bool DisassemblerX86::setBadWrite() { + if (!instr_valid_) + return false; + + libdis::x86_op_t *operand = libdis::x86_get_dest_operand(¤t_instr_); + if (!operand || operand->type != libdis::op_expression) + return false; + + memcpy(&bad_register_, &operand->data.expression.base, + sizeof(libdis::x86_reg_t)); + register_valid_ = true; + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.h b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.h new file mode 100644 index 0000000000..7106941072 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86.h @@ -0,0 +1,127 @@ +// 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. + +// disassembler_x86.h: Basic x86 bytecode disassembler +// +// Provides a simple disassembler which wraps libdisasm. This allows simple +// tests to be run against bytecode to test for various properties. +// +// Author: Cris Neckar + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_X86_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_X86_H_ + +#include +#include + +#include "google_breakpad/common/breakpad_types.h" + +namespace libdis { +#include "third_party/libdisasm/libdis.h" +} + +namespace google_breakpad { + +enum { + DISX86_NONE = 0x0, + DISX86_BAD_BRANCH_TARGET = 0x1, + DISX86_BAD_ARGUMENT_PASSED = 0x2, + DISX86_BAD_WRITE = 0x4, + DISX86_BAD_BLOCK_WRITE = 0x8, + DISX86_BAD_READ = 0x10, + DISX86_BAD_BLOCK_READ = 0x20, + DISX86_BAD_COMPARISON = 0x40 +}; + +class DisassemblerX86 { + public: + // TODO(cdn): Modify this class to take a MemoryRegion instead of just + // a raw buffer. This will make it easier to use this on arbitrary + // minidumps without first copying out the code segment. + DisassemblerX86(const uint8_t *bytecode, uint32_t, uint32_t); + ~DisassemblerX86(); + + // This walks to the next instruction in the memory region and + // sets flags based on the type of instruction and previous state + // including any registers marked as bad through setBadRead() + // or setBadWrite(). This method can be called in a loop to + // disassemble until the end of a region. + uint32_t NextInstruction(); + + // Indicates whether the current disassembled instruction was valid. + bool currentInstructionValid() { return instr_valid_; } + + // Returns the current instruction as defined in libdis.h, + // or NULL if the current instruction is not valid. + const libdis::x86_insn_t* currentInstruction() { + return instr_valid_ ? ¤t_instr_ : NULL; + } + + // Returns the type of the current instruction as defined in libdis.h. + libdis::x86_insn_group currentInstructionGroup() { + return current_instr_.group; + } + + // Indicates whether a return instruction has been encountered. + bool endOfBlock() { return end_of_block_; } + + // The flags set so far for the disassembly. + uint16_t flags() { return flags_; } + + // This sets an indicator that the register used to determine + // src or dest for the current instruction is tainted. These can + // be used after examining the current instruction to indicate, + // for example that a bad read or write occurred and the pointer + // stored in the register is currently invalid. + bool setBadRead(); + bool setBadWrite(); + + protected: + const uint8_t *bytecode_; + uint32_t size_; + uint32_t virtual_address_; + uint32_t current_byte_offset_; + uint32_t current_inst_offset_; + + bool instr_valid_; + libdis::x86_insn_t current_instr_; + + // TODO(cdn): Maybe also track an expression's index register. + // ex: mov eax, [ebx + ecx]; ebx is base, ecx is index. + bool register_valid_; + libdis::x86_reg_t bad_register_; + + bool pushed_bad_value_; + bool end_of_block_; + + uint16_t flags_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DISASSEMBLER_X86_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86_unittest.cc new file mode 100644 index 0000000000..352905f20d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/disassembler_x86_unittest.cc @@ -0,0 +1,233 @@ +// Copyright (c) 2010, 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 + +#include "breakpad_googletest_includes.h" +#include "processor/disassembler_x86.h" +#include "third_party/libdisasm/libdis.h" + +namespace { + +using google_breakpad::DisassemblerX86; + +unsigned char just_return[] = "\xc3"; // retn + +unsigned char invalid_instruction[] = "\x00"; // invalid + +unsigned char read_eax_jmp_eax[] = + "\x8b\x18" // mov ebx, [eax]; + "\x33\xc9" // xor ebx, ebx; + "\xff\x20" // jmp eax; + "\xc3"; // retn; + +unsigned char write_eax_arg_to_call[] = + "\x89\xa8\x00\x02\x00\x00" // mov [eax+200], ebp; + "\xc1\xeb\x02" // shr ebx, 2; + "\x50" // push eax; + "\xe8\xd1\x24\x77\x88" // call something; + "\xc3"; // retn; + +unsigned char read_edi_stosb[] = + "\x8b\x07" // mov eax, [edi]; + "\x8b\xc8" // mov ecx, eax; + "\xf3\xaa" // rep stosb; + "\xc3"; // retn; + +unsigned char read_clobber_write[] = + "\x03\x18" // add ebx, [eax]; + "\x8b\xc1" // mov eax, ecx; + "\x89\x10" // mov [eax], edx; + "\xc3"; // retn; + +unsigned char read_xchg_write[] = + "\x03\x18" // add ebx, [eax]; + "\x91" // xchg eax, ecx; + "\x89\x18" // mov [eax], ebx; + "\x89\x11" // mov [ecx], edx; + "\xc3"; // retn; + +unsigned char read_cmp[] = + "\x03\x18" // add ebx, [eax]; + "\x83\xf8\x00" // cmp eax, 0; + "\x74\x04" // je +4; + "\xc3"; // retn; + +TEST(DisassemblerX86Test, SimpleReturnInstruction) { + DisassemblerX86 dis(just_return, sizeof(just_return)-1, 0); + EXPECT_EQ(1U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_TRUE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); + const libdis::x86_insn_t* instruction = dis.currentInstruction(); + EXPECT_EQ(libdis::insn_controlflow, instruction->group); + EXPECT_EQ(libdis::insn_return, instruction->type); + EXPECT_EQ(0U, dis.NextInstruction()); + EXPECT_FALSE(dis.currentInstructionValid()); + EXPECT_EQ(NULL, dis.currentInstruction()); +} + +TEST(DisassemblerX86Test, SimpleInvalidInstruction) { + DisassemblerX86 dis(invalid_instruction, sizeof(invalid_instruction)-1, 0); + EXPECT_EQ(0U, dis.NextInstruction()); + EXPECT_FALSE(dis.currentInstructionValid()); +} + +TEST(DisassemblerX86Test, BadReadLeadsToBranch) { + DisassemblerX86 dis(read_eax_jmp_eax, sizeof(read_eax_jmp_eax)-1, 0); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadRead()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_logic, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_BRANCH_TARGET, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); +} + +TEST(DisassemblerX86Test, BadWriteLeadsToPushedArg) { + DisassemblerX86 dis(write_eax_arg_to_call, + sizeof(write_eax_arg_to_call)-1, 0); + EXPECT_EQ(6U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadWrite()); + EXPECT_EQ(3U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_EQ(1U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(5U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_ARGUMENT_PASSED, dis.flags()); + EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); + EXPECT_FALSE(dis.endOfBlock()); +} + + +TEST(DisassemblerX86Test, BadReadLeadsToBlockWrite) { + DisassemblerX86 dis(read_edi_stosb, sizeof(read_edi_stosb)-1, 0); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadRead()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_BLOCK_WRITE, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_string, dis.currentInstructionGroup()); +} + +TEST(DisassemblerX86Test, BadReadClobberThenWrite) { + DisassemblerX86 dis(read_clobber_write, sizeof(read_clobber_write)-1, 0); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadRead()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); +} + +TEST(DisassemblerX86Test, BadReadXCHGThenWrite) { + DisassemblerX86 dis(read_xchg_write, sizeof(read_xchg_write)-1, 0); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadRead()); + EXPECT_EQ(1U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_WRITE, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_move, dis.currentInstructionGroup()); +} + +TEST(DisassemblerX86Test, BadReadThenCMP) { + DisassemblerX86 dis(read_cmp, sizeof(read_cmp)-1, 0); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(0U, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_arithmetic, dis.currentInstructionGroup()); + EXPECT_TRUE(dis.setBadRead()); + EXPECT_EQ(3U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_comparison, dis.currentInstructionGroup()); + EXPECT_EQ(2U, dis.NextInstruction()); + EXPECT_TRUE(dis.currentInstructionValid()); + EXPECT_EQ(google_breakpad::DISX86_BAD_COMPARISON, dis.flags()); + EXPECT_FALSE(dis.endOfBlock()); + EXPECT_EQ(libdis::insn_controlflow, dis.currentInstructionGroup()); +} +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/dump_context.cc b/toolkit/crashreporter/google-breakpad/src/processor/dump_context.cc new file mode 100644 index 0000000000..da531b74d0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/dump_context.cc @@ -0,0 +1,664 @@ +// Copyright (c) 2010 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. + +// dump_context.cc: A (mini/micro)dump context. +// +// See dump_context.h for documentation. + +#include "google_breakpad/processor/dump_context.h" + +#include + +#ifdef _WIN32 +#include +#else // _WIN32 +#include +#endif // _WIN32 + +#include "common/stdio_wrapper.h" +#include "processor/logging.h" + +namespace google_breakpad { + +DumpContext::DumpContext() : context_(), + context_flags_(0) { } + +DumpContext::~DumpContext() { + FreeContext(); +} + +uint32_t DumpContext::GetContextCPU() const { + if (!valid_) { + // Don't log a message, GetContextCPU can be legitimately called with + // valid_ false by FreeContext, which is called by Read. + return 0; + } + + return context_flags_ & MD_CONTEXT_CPU_MASK; +} + +uint32_t DumpContext::GetContextFlags() const { + return context_flags_; +} + +const MDRawContextX86* DumpContext::GetContextX86() const { + if (GetContextCPU() != MD_CONTEXT_X86) { + BPLOG(ERROR) << "DumpContext cannot get x86 context"; + return NULL; + } + + return context_.x86; +} + +const MDRawContextPPC* DumpContext::GetContextPPC() const { + if (GetContextCPU() != MD_CONTEXT_PPC) { + BPLOG(ERROR) << "DumpContext cannot get ppc context"; + return NULL; + } + + return context_.ppc; +} + +const MDRawContextPPC64* DumpContext::GetContextPPC64() const { + if (GetContextCPU() != MD_CONTEXT_PPC64) { + BPLOG(ERROR) << "DumpContext cannot get ppc64 context"; + return NULL; + } + + return context_.ppc64; +} + +const MDRawContextAMD64* DumpContext::GetContextAMD64() const { + if (GetContextCPU() != MD_CONTEXT_AMD64) { + BPLOG(ERROR) << "DumpContext cannot get amd64 context"; + return NULL; + } + + return context_.amd64; +} + +const MDRawContextSPARC* DumpContext::GetContextSPARC() const { + if (GetContextCPU() != MD_CONTEXT_SPARC) { + BPLOG(ERROR) << "DumpContext cannot get sparc context"; + return NULL; + } + + return context_.ctx_sparc; +} + +const MDRawContextARM* DumpContext::GetContextARM() const { + if (GetContextCPU() != MD_CONTEXT_ARM) { + BPLOG(ERROR) << "DumpContext cannot get arm context"; + return NULL; + } + + return context_.arm; +} + +const MDRawContextARM64* DumpContext::GetContextARM64() const { + if (GetContextCPU() != MD_CONTEXT_ARM64) { + BPLOG(ERROR) << "DumpContext cannot get arm64 context"; + return NULL; + } + + return context_.arm64; +} + +const MDRawContextMIPS* DumpContext::GetContextMIPS() const { + if ((GetContextCPU() != MD_CONTEXT_MIPS) && + (GetContextCPU() != MD_CONTEXT_MIPS64)) { + BPLOG(ERROR) << "DumpContext cannot get MIPS context"; + return NULL; + } + + return context_.ctx_mips; +} + +bool DumpContext::GetInstructionPointer(uint64_t* ip) const { + BPLOG_IF(ERROR, !ip) << "DumpContext::GetInstructionPointer requires |ip|"; + assert(ip); + *ip = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid DumpContext for GetInstructionPointer"; + return false; + } + + switch (GetContextCPU()) { + case MD_CONTEXT_AMD64: + *ip = GetContextAMD64()->rip; + break; + case MD_CONTEXT_ARM: + *ip = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_PC]; + break; + case MD_CONTEXT_ARM64: + *ip = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_PC]; + break; + case MD_CONTEXT_PPC: + *ip = GetContextPPC()->srr0; + break; + case MD_CONTEXT_PPC64: + *ip = GetContextPPC64()->srr0; + break; + case MD_CONTEXT_SPARC: + *ip = GetContextSPARC()->pc; + break; + case MD_CONTEXT_X86: + *ip = GetContextX86()->eip; + break; + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: + *ip = GetContextMIPS()->epc; + break; + default: + // This should never happen. + BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer"; + return false; + } + return true; +} + +bool DumpContext::GetStackPointer(uint64_t* sp) const { + BPLOG_IF(ERROR, !sp) << "DumpContext::GetStackPointer requires |sp|"; + assert(sp); + *sp = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid DumpContext for GetStackPointer"; + return false; + } + + switch (GetContextCPU()) { + case MD_CONTEXT_AMD64: + *sp = GetContextAMD64()->rsp; + break; + case MD_CONTEXT_ARM: + *sp = GetContextARM()->iregs[MD_CONTEXT_ARM_REG_SP]; + break; + case MD_CONTEXT_ARM64: + *sp = GetContextARM64()->iregs[MD_CONTEXT_ARM64_REG_SP]; + break; + case MD_CONTEXT_PPC: + *sp = GetContextPPC()->gpr[MD_CONTEXT_PPC_REG_SP]; + break; + case MD_CONTEXT_PPC64: + *sp = GetContextPPC64()->gpr[MD_CONTEXT_PPC64_REG_SP]; + break; + case MD_CONTEXT_SPARC: + *sp = GetContextSPARC()->g_r[MD_CONTEXT_SPARC_REG_SP]; + break; + case MD_CONTEXT_X86: + *sp = GetContextX86()->esp; + break; + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: + *sp = GetContextMIPS()->iregs[MD_CONTEXT_MIPS_REG_SP]; + break; + default: + // This should never happen. + BPLOG(ERROR) << "Unknown CPU architecture in GetStackPointer"; + return false; + } + return true; +} + +void DumpContext::SetContextFlags(uint32_t context_flags) { + context_flags_ = context_flags; +} + +void DumpContext::SetContextX86(MDRawContextX86* x86) { + context_.x86 = x86; +} + +void DumpContext::SetContextPPC(MDRawContextPPC* ppc) { + context_.ppc = ppc; +} + +void DumpContext::SetContextPPC64(MDRawContextPPC64* ppc64) { + context_.ppc64 = ppc64; +} + +void DumpContext::SetContextAMD64(MDRawContextAMD64* amd64) { + context_.amd64 = amd64; +} + +void DumpContext::SetContextSPARC(MDRawContextSPARC* ctx_sparc) { + context_.ctx_sparc = ctx_sparc; +} + +void DumpContext::SetContextARM(MDRawContextARM* arm) { + context_.arm = arm; +} + +void DumpContext::SetContextARM64(MDRawContextARM64* arm64) { + context_.arm64 = arm64; +} + +void DumpContext::SetContextMIPS(MDRawContextMIPS* ctx_mips) { + context_.ctx_mips = ctx_mips; +} + +void DumpContext::FreeContext() { + switch (GetContextCPU()) { + case MD_CONTEXT_X86: + delete context_.x86; + break; + + case MD_CONTEXT_PPC: + delete context_.ppc; + break; + + case MD_CONTEXT_PPC64: + delete context_.ppc64; + break; + + case MD_CONTEXT_AMD64: + delete context_.amd64; + break; + + case MD_CONTEXT_SPARC: + delete context_.ctx_sparc; + break; + + case MD_CONTEXT_ARM: + delete context_.arm; + break; + + case MD_CONTEXT_ARM64: + delete context_.arm64; + break; + + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: + delete context_.ctx_mips; + break; + + default: + // There is no context record (valid_ is false) or there's a + // context record for an unknown CPU (shouldn't happen, only known + // records are stored by Read). + break; + } + + context_flags_ = 0; + context_.base = NULL; +} + +void DumpContext::Print() { + if (!valid_) { + BPLOG(ERROR) << "DumpContext cannot print invalid data"; + return; + } + + switch (GetContextCPU()) { + case MD_CONTEXT_X86: { + const MDRawContextX86* context_x86 = GetContextX86(); + printf("MDRawContextX86\n"); + printf(" context_flags = 0x%x\n", + context_x86->context_flags); + printf(" dr0 = 0x%x\n", context_x86->dr0); + printf(" dr1 = 0x%x\n", context_x86->dr1); + printf(" dr2 = 0x%x\n", context_x86->dr2); + printf(" dr3 = 0x%x\n", context_x86->dr3); + printf(" dr6 = 0x%x\n", context_x86->dr6); + printf(" dr7 = 0x%x\n", context_x86->dr7); + printf(" float_save.control_word = 0x%x\n", + context_x86->float_save.control_word); + printf(" float_save.status_word = 0x%x\n", + context_x86->float_save.status_word); + printf(" float_save.tag_word = 0x%x\n", + context_x86->float_save.tag_word); + printf(" float_save.error_offset = 0x%x\n", + context_x86->float_save.error_offset); + printf(" float_save.error_selector = 0x%x\n", + context_x86->float_save.error_selector); + printf(" float_save.data_offset = 0x%x\n", + context_x86->float_save.data_offset); + printf(" float_save.data_selector = 0x%x\n", + context_x86->float_save.data_selector); + printf(" float_save.register_area[%2d] = 0x", + MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE); + for (unsigned int register_index = 0; + register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE; + ++register_index) { + printf("%02x", context_x86->float_save.register_area[register_index]); + } + printf("\n"); + printf(" float_save.cr0_npx_state = 0x%x\n", + context_x86->float_save.cr0_npx_state); + printf(" gs = 0x%x\n", context_x86->gs); + printf(" fs = 0x%x\n", context_x86->fs); + printf(" es = 0x%x\n", context_x86->es); + printf(" ds = 0x%x\n", context_x86->ds); + printf(" edi = 0x%x\n", context_x86->edi); + printf(" esi = 0x%x\n", context_x86->esi); + printf(" ebx = 0x%x\n", context_x86->ebx); + printf(" edx = 0x%x\n", context_x86->edx); + printf(" ecx = 0x%x\n", context_x86->ecx); + printf(" eax = 0x%x\n", context_x86->eax); + printf(" ebp = 0x%x\n", context_x86->ebp); + printf(" eip = 0x%x\n", context_x86->eip); + printf(" cs = 0x%x\n", context_x86->cs); + printf(" eflags = 0x%x\n", context_x86->eflags); + printf(" esp = 0x%x\n", context_x86->esp); + printf(" ss = 0x%x\n", context_x86->ss); + printf(" extended_registers[%3d] = 0x", + MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE); + for (unsigned int register_index = 0; + register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE; + ++register_index) { + printf("%02x", context_x86->extended_registers[register_index]); + } + printf("\n\n"); + + break; + } + + case MD_CONTEXT_PPC: { + const MDRawContextPPC* context_ppc = GetContextPPC(); + printf("MDRawContextPPC\n"); + printf(" context_flags = 0x%x\n", + context_ppc->context_flags); + printf(" srr0 = 0x%x\n", context_ppc->srr0); + printf(" srr1 = 0x%x\n", context_ppc->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC_GPR_COUNT; + ++gpr_index) { + printf(" gpr[%2d] = 0x%x\n", + gpr_index, context_ppc->gpr[gpr_index]); + } + printf(" cr = 0x%x\n", context_ppc->cr); + printf(" xer = 0x%x\n", context_ppc->xer); + printf(" lr = 0x%x\n", context_ppc->lr); + printf(" ctr = 0x%x\n", context_ppc->ctr); + printf(" mq = 0x%x\n", context_ppc->mq); + printf(" vrsave = 0x%x\n", context_ppc->vrsave); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; + ++fpr_index) { + printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_ppc->float_save.fpregs[fpr_index]); + } + printf(" float_save.fpscr = 0x%x\n", + context_ppc->float_save.fpscr); + // TODO(mmentovai): print the 128-bit quantities in + // context_ppc->vector_save. This isn't done yet because printf + // doesn't support 128-bit quantities, and printing them using + // PRIx64 as two 64-bit quantities requires knowledge of the CPU's + // byte ordering. + printf(" vector_save.save_vrvalid = 0x%x\n", + context_ppc->vector_save.save_vrvalid); + printf("\n"); + + break; + } + + case MD_CONTEXT_PPC64: { + const MDRawContextPPC64* context_ppc64 = GetContextPPC64(); + printf("MDRawContextPPC64\n"); + printf(" context_flags = 0x%" PRIx64 "\n", + context_ppc64->context_flags); + printf(" srr0 = 0x%" PRIx64 "\n", + context_ppc64->srr0); + printf(" srr1 = 0x%" PRIx64 "\n", + context_ppc64->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC64_GPR_COUNT; + ++gpr_index) { + printf(" gpr[%2d] = 0x%" PRIx64 "\n", + gpr_index, context_ppc64->gpr[gpr_index]); + } + printf(" cr = 0x%" PRIx64 "\n", context_ppc64->cr); + printf(" xer = 0x%" PRIx64 "\n", + context_ppc64->xer); + printf(" lr = 0x%" PRIx64 "\n", context_ppc64->lr); + printf(" ctr = 0x%" PRIx64 "\n", + context_ppc64->ctr); + printf(" vrsave = 0x%" PRIx64 "\n", + context_ppc64->vrsave); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; + ++fpr_index) { + printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_ppc64->float_save.fpregs[fpr_index]); + } + printf(" float_save.fpscr = 0x%x\n", + context_ppc64->float_save.fpscr); + // TODO(mmentovai): print the 128-bit quantities in + // context_ppc64->vector_save. This isn't done yet because printf + // doesn't support 128-bit quantities, and printing them using + // PRIx64 as two 64-bit quantities requires knowledge of the CPU's + // byte ordering. + printf(" vector_save.save_vrvalid = 0x%x\n", + context_ppc64->vector_save.save_vrvalid); + printf("\n"); + + break; + } + + case MD_CONTEXT_AMD64: { + const MDRawContextAMD64* context_amd64 = GetContextAMD64(); + printf("MDRawContextAMD64\n"); + printf(" p1_home = 0x%" PRIx64 "\n", + context_amd64->p1_home); + printf(" p2_home = 0x%" PRIx64 "\n", + context_amd64->p2_home); + printf(" p3_home = 0x%" PRIx64 "\n", + context_amd64->p3_home); + printf(" p4_home = 0x%" PRIx64 "\n", + context_amd64->p4_home); + printf(" p5_home = 0x%" PRIx64 "\n", + context_amd64->p5_home); + printf(" p6_home = 0x%" PRIx64 "\n", + context_amd64->p6_home); + printf(" context_flags = 0x%x\n", + context_amd64->context_flags); + printf(" mx_csr = 0x%x\n", + context_amd64->mx_csr); + printf(" cs = 0x%x\n", context_amd64->cs); + printf(" ds = 0x%x\n", context_amd64->ds); + printf(" es = 0x%x\n", context_amd64->es); + printf(" fs = 0x%x\n", context_amd64->fs); + printf(" gs = 0x%x\n", context_amd64->gs); + printf(" ss = 0x%x\n", context_amd64->ss); + printf(" eflags = 0x%x\n", context_amd64->eflags); + printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0); + printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1); + printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2); + printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3); + printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6); + printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7); + printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax); + printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx); + printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx); + printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx); + printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp); + printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp); + printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi); + printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi); + printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8); + printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9); + printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10); + printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11); + printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12); + printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13); + printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14); + printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15); + printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip); + // TODO: print xmm, vector, debug registers + printf("\n"); + break; + } + + case MD_CONTEXT_SPARC: { + const MDRawContextSPARC* context_sparc = GetContextSPARC(); + printf("MDRawContextSPARC\n"); + printf(" context_flags = 0x%x\n", + context_sparc->context_flags); + for (unsigned int g_r_index = 0; + g_r_index < MD_CONTEXT_SPARC_GPR_COUNT; + ++g_r_index) { + printf(" g_r[%2d] = 0x%" PRIx64 "\n", + g_r_index, context_sparc->g_r[g_r_index]); + } + printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr); + printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc); + printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc); + printf(" y = 0x%" PRIx64 "\n", context_sparc->y); + printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi); + printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs); + + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT; + ++fpr_index) { + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_sparc->float_save.regs[fpr_index]); + } + printf(" float_save.filler = 0x%" PRIx64 "\n", + context_sparc->float_save.filler); + printf(" float_save.fsr = 0x%" PRIx64 "\n", + context_sparc->float_save.fsr); + break; + } + + case MD_CONTEXT_ARM: { + const MDRawContextARM* context_arm = GetContextARM(); + const char * const names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + }; + printf("MDRawContextARM\n"); + printf(" context_flags = 0x%x\n", + context_arm->context_flags); + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; + ++ireg_index) { + printf(" %-3s = 0x%x\n", + names[ireg_index], context_arm->iregs[ireg_index]); + } + printf(" cpsr = 0x%x\n", context_arm->cpsr); + printf(" float_save.fpscr = 0x%" PRIx64 "\n", + context_arm->float_save.fpscr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; + ++fpr_index) { + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_arm->float_save.regs[fpr_index]); + } + for (unsigned int fpe_index = 0; + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; + ++fpe_index) { + printf(" float_save.extra[%2d] = 0x%" PRIx32 "\n", + fpe_index, context_arm->float_save.extra[fpe_index]); + } + + break; + } + + case MD_CONTEXT_ARM64: { + const MDRawContextARM64* context_arm64 = GetContextARM64(); + printf("MDRawContextARM64\n"); + printf(" context_flags = 0x%x\n", + context_arm64->context_flags); + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM64_GPR_COUNT; + ++ireg_index) { + printf(" iregs[%2d] = 0x%" PRIx64 "\n", + ireg_index, context_arm64->iregs[ireg_index]); + } + printf(" cpsr = 0x%x\n", context_arm64->cpsr); + printf(" float_save.fpsr = 0x%x\n", context_arm64->float_save.fpsr); + printf(" float_save.fpcr = 0x%x\n", context_arm64->float_save.fpcr); + + for (unsigned int freg_index = 0; + freg_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT; + ++freg_index) { + uint128_struct fp_value = context_arm64->float_save.regs[freg_index]; + printf(" float_save.regs[%2d] = 0x%" PRIx64 "%" PRIx64 "\n", + freg_index, fp_value.high, fp_value.low); + } + + break; + } + + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: { + const MDRawContextMIPS* context_mips = GetContextMIPS(); + printf("MDRawContextMIPS\n"); + printf(" context_flags = 0x%x\n", + context_mips->context_flags); + for (int ireg_index = 0; + ireg_index < MD_CONTEXT_MIPS_GPR_COUNT; + ++ireg_index) { + printf(" iregs[%2d] = 0x%" PRIx64 "\n", + ireg_index, context_mips->iregs[ireg_index]); + } + printf(" mdhi = 0x%" PRIx64 "\n", + context_mips->mdhi); + printf(" mdlo = 0x%" PRIx64 "\n", + context_mips->mdhi); + for (int dsp_index = 0; + dsp_index < MD_CONTEXT_MIPS_DSP_COUNT; + ++dsp_index) { + printf(" hi[%1d] = 0x%" PRIx32 "\n", + dsp_index, context_mips->hi[dsp_index]); + printf(" lo[%1d] = 0x%" PRIx32 "\n", + dsp_index, context_mips->lo[dsp_index]); + } + printf(" dsp_control = 0x%" PRIx32 "\n", + context_mips->dsp_control); + printf(" epc = 0x%" PRIx64 "\n", + context_mips->epc); + printf(" badvaddr = 0x%" PRIx64 "\n", + context_mips->badvaddr); + printf(" status = 0x%" PRIx32 "\n", + context_mips->status); + printf(" cause = 0x%" PRIx32 "\n", + context_mips->cause); + + for (int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; + ++fpr_index) { + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", + fpr_index, context_mips->float_save.regs[fpr_index]); + } + printf(" float_save.fpcsr = 0x%" PRIx32 "\n", + context_mips->float_save.fpcsr); + printf(" float_save.fir = 0x%" PRIx32 "\n", + context_mips->float_save.fir); + break; + } + + default: { + break; + } + } +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/dump_object.cc b/toolkit/crashreporter/google-breakpad/src/processor/dump_object.cc new file mode 100644 index 0000000000..2c82b200b8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/dump_object.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2010 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. + +// dump_object.cc: A base class for all mini/micro dump object. + +#include "google_breakpad/processor/dump_object.h" + +namespace google_breakpad { + +DumpObject::DumpObject() : valid_(false) { +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability.cc b/toolkit/crashreporter/google-breakpad/src/processor/exploitability.cc new file mode 100644 index 0000000000..5f05b51052 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2010 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. + +// exploitability_engine.cc: Generic exploitability engine. +// +// See exploitable_engine.h for documentation. +// +// Author: Cris Neckar + + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/exploitability.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/process_state.h" +#include "processor/exploitability_linux.h" +#include "processor/exploitability_win.h" +#include "processor/logging.h" + +namespace google_breakpad { + +Exploitability::Exploitability(Minidump *dump, + ProcessState *process_state) + : dump_(dump), + process_state_(process_state) {} + +ExploitabilityRating Exploitability::CheckExploitability() { + return CheckPlatformExploitability(); +} + +Exploitability *Exploitability::ExploitabilityForPlatform( + Minidump *dump, + ProcessState *process_state) { + return ExploitabilityForPlatform(dump, process_state, false); +} + +Exploitability *Exploitability::ExploitabilityForPlatform( + Minidump *dump, + ProcessState *process_state, + bool enable_objdump) { + Exploitability *platform_exploitability = NULL; + MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); + if (!minidump_system_info) + return NULL; + + const MDRawSystemInfo *raw_system_info = + minidump_system_info->system_info(); + if (!raw_system_info) + return NULL; + + switch (raw_system_info->platform_id) { + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: { + platform_exploitability = new ExploitabilityWin(dump, process_state); + break; + } + case MD_OS_LINUX: { + platform_exploitability = new ExploitabilityLinux(dump, + process_state, + enable_objdump); + break; + } + case MD_OS_MAC_OS_X: + case MD_OS_IOS: + case MD_OS_UNIX: + case MD_OS_SOLARIS: + case MD_OS_ANDROID: + case MD_OS_PS3: + case MD_OS_FUCHSIA: + default: { + platform_exploitability = NULL; + break; + } + } + + BPLOG_IF(ERROR, !platform_exploitability) << + "No Exploitability module for platform: " << + process_state->system_info()->os; + return platform_exploitability; +} + +bool Exploitability::AddressIsAscii(uint64_t address) { + for (int i = 0; i < 8; i++) { + uint8_t byte = (address >> (8*i)) & 0xff; + if ((byte >= ' ' && byte <= '~') || byte == 0) + continue; + return false; + } + return true; +} + +} // namespace google_breakpad + diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.cc b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.cc new file mode 100644 index 0000000000..ccc9f1459c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.cc @@ -0,0 +1,626 @@ +// Copyright (c) 2013 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. + +// exploitability_linux.cc: Linux specific exploitability engine. +// +// Provides a guess at the exploitability of the crash for the Linux +// platform given a minidump and process_state. +// +// Author: Matthew Riley + +#include "processor/exploitability_linux.h" + +#ifndef _WIN32 +#include +#include +#include + +#include +#include +#endif // _WIN32 + +#include + +#include "google_breakpad/common/minidump_exception_linux.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/logging.h" + +namespace { + +// Prefixes for memory mapping names. +constexpr char kHeapPrefix[] = "[heap"; +constexpr char kStackPrefix[] = "[stack"; + +// This function in libc is called if the program was compiled with +// -fstack-protector and a function's stack canary changes. +constexpr char kStackCheckFailureFunction[] = "__stack_chk_fail"; + +// This function in libc is called if the program was compiled with +// -D_FORTIFY_SOURCE=2, a function like strcpy() is called, and the runtime +// can determine that the call would overflow the target buffer. +constexpr char kBoundsCheckFailureFunction[] = "__chk_fail"; + +#ifndef _WIN32 +const unsigned int MAX_INSTRUCTION_LEN = 15; +const unsigned int MAX_OBJDUMP_BUFFER_LEN = 4096; +#endif // _WIN32 + +} // namespace + +namespace google_breakpad { + +ExploitabilityLinux::ExploitabilityLinux(Minidump *dump, + ProcessState *process_state) + : Exploitability(dump, process_state), + enable_objdump_(false) { } + +ExploitabilityLinux::ExploitabilityLinux(Minidump *dump, + ProcessState *process_state, + bool enable_objdump) + : Exploitability(dump, process_state), + enable_objdump_(enable_objdump) { } + + +ExploitabilityRating ExploitabilityLinux::CheckPlatformExploitability() { + // Check the crashing thread for functions suggesting a buffer overflow or + // stack smash. + if (process_state_->requesting_thread() != -1) { + CallStack* crashing_thread = + process_state_->threads()->at(process_state_->requesting_thread()); + const vector& crashing_thread_frames = + *crashing_thread->frames(); + for (size_t i = 0; i < crashing_thread_frames.size(); ++i) { + if (crashing_thread_frames[i]->function_name == + kStackCheckFailureFunction) { + return EXPLOITABILITY_HIGH; + } + + if (crashing_thread_frames[i]->function_name == + kBoundsCheckFailureFunction) { + return EXPLOITABILITY_HIGH; + } + } + } + + // Getting exception data. (It should exist for all minidumps.) + MinidumpException *exception = dump_->GetException(); + if (exception == NULL) { + BPLOG(INFO) << "No exception record."; + return EXPLOITABILITY_ERR_PROCESSING; + } + const MDRawExceptionStream *raw_exception_stream = exception->exception(); + if (raw_exception_stream == NULL) { + BPLOG(INFO) << "No raw exception stream."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Checking for benign exceptions that caused the crash. + if (this->BenignCrashTrigger(raw_exception_stream)) { + return EXPLOITABILITY_NONE; + } + + // Check if the instruction pointer is in a valid instruction region + // by finding if it maps to an executable part of memory. + uint64_t instruction_ptr = 0; + uint64_t stack_ptr = 0; + + const MinidumpContext *context = exception->GetContext(); + if (context == NULL) { + BPLOG(INFO) << "No exception context."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Getting the instruction pointer. + if (!context->GetInstructionPointer(&instruction_ptr)) { + BPLOG(INFO) << "Failed to retrieve instruction pointer."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Getting the stack pointer. + if (!context->GetStackPointer(&stack_ptr)) { + BPLOG(INFO) << "Failed to retrieve stack pointer."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Checking for the instruction pointer in a valid instruction region, + // a misplaced stack pointer, and an executable stack or heap. + if (!this->InstructionPointerInCode(instruction_ptr) || + this->StackPointerOffStack(stack_ptr) || + this->ExecutableStackOrHeap()) { + return EXPLOITABILITY_HIGH; + } + + // Check for write to read only memory or invalid memory, shelling out + // to objdump is enabled. + if (enable_objdump_ && this->EndedOnIllegalWrite(instruction_ptr)) { + return EXPLOITABILITY_HIGH; + } + + // There was no strong evidence suggesting exploitability, but the minidump + // does not appear totally benign either. + return EXPLOITABILITY_INTERESTING; +} + +bool ExploitabilityLinux::EndedOnIllegalWrite(uint64_t instruction_ptr) { +#ifdef _WIN32 + BPLOG(INFO) << "MinGW does not support fork and exec. Terminating method."; +#else + // Get memory region containing instruction pointer. + MinidumpMemoryList *memory_list = dump_->GetMemoryList(); + MinidumpMemoryRegion *memory_region = + memory_list ? + memory_list->GetMemoryRegionForAddress(instruction_ptr) : NULL; + if (!memory_region) { + BPLOG(INFO) << "No memory region around instruction pointer."; + return false; + } + + // Get exception data to find architecture. + string architecture = ""; + MinidumpException *exception = dump_->GetException(); + // This should never evaluate to true, since this should not be reachable + // without checking for exception data earlier. + if (!exception) { + BPLOG(INFO) << "No exception data."; + return false; + } + const MDRawExceptionStream *raw_exception_stream = exception->exception(); + const MinidumpContext *context = exception->GetContext(); + // This should not evaluate to true, for the same reason mentioned above. + if (!raw_exception_stream || !context) { + BPLOG(INFO) << "No exception or architecture data."; + return false; + } + // Check architecture and set architecture variable to corresponding flag + // in objdump. + switch (context->GetContextCPU()) { + case MD_CONTEXT_X86: + architecture = "i386"; + break; + case MD_CONTEXT_AMD64: + architecture = "i386:x86-64"; + break; + default: + // Unsupported architecture. Note that ARM architectures are not + // supported because objdump does not support ARM. + return false; + break; + } + + // Get memory region around instruction pointer and the number of bytes + // before and after the instruction pointer in the memory region. + const uint8_t *raw_memory = memory_region->GetMemory(); + const uint64_t base = memory_region->GetBase(); + if (base > instruction_ptr) { + BPLOG(ERROR) << "Memory region base value exceeds instruction pointer."; + return false; + } + const uint64_t offset = instruction_ptr - base; + if (memory_region->GetSize() < MAX_INSTRUCTION_LEN + offset) { + BPLOG(INFO) << "Not enough bytes left to guarantee complete instruction."; + return false; + } + + // Convert bytes into objdump output. + char objdump_output_buffer[MAX_OBJDUMP_BUFFER_LEN] = {0}; + DisassembleBytes(architecture, + raw_memory + offset, + MAX_OBJDUMP_BUFFER_LEN, + objdump_output_buffer); + + string line; + if (!GetObjdumpInstructionLine(objdump_output_buffer, &line)) { + return false; + } + + // Convert objdump instruction line into the operation and operands. + string instruction = ""; + string dest = ""; + string src = ""; + TokenizeObjdumpInstruction(line, &instruction, &dest, &src); + + // Check if the operation is a write to memory. First, the instruction + // must one that can write to memory. Second, the write destination + // must be a spot in memory rather than a register. Since there are no + // symbols from objdump, the destination will be enclosed by brackets. + if (dest.size() > 2 && dest.at(0) == '[' && dest.at(dest.size() - 1) == ']' && + (!instruction.compare("mov") || !instruction.compare("inc") || + !instruction.compare("dec") || !instruction.compare("and") || + !instruction.compare("or") || !instruction.compare("xor") || + !instruction.compare("not") || !instruction.compare("neg") || + !instruction.compare("add") || !instruction.compare("sub") || + !instruction.compare("shl") || !instruction.compare("shr"))) { + // Strip away enclosing brackets from the destination address. + dest = dest.substr(1, dest.size() - 2); + uint64_t write_address = 0; + CalculateAddress(dest, *context, &write_address); + + // If the program crashed as a result of a write, the destination of + // the write must have been an address that did not permit writing. + // However, if the address is under 4k, due to program protections, + // the crash does not suggest exploitability for writes with such a + // low target address. + return write_address > 4096; + } +#endif // _WIN32 + return false; +} + +#ifndef _WIN32 +bool ExploitabilityLinux::CalculateAddress(const string &address_expression, + const DumpContext &context, + uint64_t *write_address) { + // The destination should be the format reg+a or reg-a, where reg + // is a register and a is a hexadecimal constant. Although more complex + // expressions can make valid instructions, objdump's disassembly outputs + // it in this simpler format. + // TODO(liuandrew): Handle more complex formats, should they arise. + + if (!write_address) { + BPLOG(ERROR) << "Null parameter."; + return false; + } + + // Clone parameter into a non-const string. + string expression = address_expression; + + // Parse out the constant that is added to the address (if it exists). + size_t delim = expression.find('+'); + bool positive_add_constant = true; + // Check if constant is subtracted instead of added. + if (delim == string::npos) { + positive_add_constant = false; + delim = expression.find('-'); + } + uint32_t add_constant = 0; + // Save constant and remove it from the expression. + if (delim != string::npos) { + if (!sscanf(expression.substr(delim + 1).c_str(), "%x", &add_constant)) { + BPLOG(ERROR) << "Failed to scan constant."; + return false; + } + expression = expression.substr(0, delim); + } + + // Set the the write address to the corresponding register. + // TODO(liuandrew): Add support for partial registers, such as + // the rax/eax/ax/ah/al chain. + switch (context.GetContextCPU()) { + case MD_CONTEXT_X86: + if (!expression.compare("eax")) { + *write_address = context.GetContextX86()->eax; + } else if (!expression.compare("ebx")) { + *write_address = context.GetContextX86()->ebx; + } else if (!expression.compare("ecx")) { + *write_address = context.GetContextX86()->ecx; + } else if (!expression.compare("edx")) { + *write_address = context.GetContextX86()->edx; + } else if (!expression.compare("edi")) { + *write_address = context.GetContextX86()->edi; + } else if (!expression.compare("esi")) { + *write_address = context.GetContextX86()->esi; + } else if (!expression.compare("ebp")) { + *write_address = context.GetContextX86()->ebp; + } else if (!expression.compare("esp")) { + *write_address = context.GetContextX86()->esp; + } else if (!expression.compare("eip")) { + *write_address = context.GetContextX86()->eip; + } else { + BPLOG(ERROR) << "Unsupported register"; + return false; + } + break; + case MD_CONTEXT_AMD64: + if (!expression.compare("rax")) { + *write_address = context.GetContextAMD64()->rax; + } else if (!expression.compare("rbx")) { + *write_address = context.GetContextAMD64()->rbx; + } else if (!expression.compare("rcx")) { + *write_address = context.GetContextAMD64()->rcx; + } else if (!expression.compare("rdx")) { + *write_address = context.GetContextAMD64()->rdx; + } else if (!expression.compare("rdi")) { + *write_address = context.GetContextAMD64()->rdi; + } else if (!expression.compare("rsi")) { + *write_address = context.GetContextAMD64()->rsi; + } else if (!expression.compare("rbp")) { + *write_address = context.GetContextAMD64()->rbp; + } else if (!expression.compare("rsp")) { + *write_address = context.GetContextAMD64()->rsp; + } else if (!expression.compare("rip")) { + *write_address = context.GetContextAMD64()->rip; + } else if (!expression.compare("r8")) { + *write_address = context.GetContextAMD64()->r8; + } else if (!expression.compare("r9")) { + *write_address = context.GetContextAMD64()->r9; + } else if (!expression.compare("r10")) { + *write_address = context.GetContextAMD64()->r10; + } else if (!expression.compare("r11")) { + *write_address = context.GetContextAMD64()->r11; + } else if (!expression.compare("r12")) { + *write_address = context.GetContextAMD64()->r12; + } else if (!expression.compare("r13")) { + *write_address = context.GetContextAMD64()->r13; + } else if (!expression.compare("r14")) { + *write_address = context.GetContextAMD64()->r14; + } else if (!expression.compare("r15")) { + *write_address = context.GetContextAMD64()->r15; + } else { + BPLOG(ERROR) << "Unsupported register"; + return false; + } + break; + default: + // This should not occur since the same switch condition + // should have terminated this method. + return false; + break; + } + + // Add or subtract constant from write address (if applicable). + *write_address = + positive_add_constant ? + *write_address + add_constant : *write_address - add_constant; + + return true; +} + +// static +bool ExploitabilityLinux::GetObjdumpInstructionLine( + const char *objdump_output_buffer, + string *instruction_line) { + // Put buffer data into stream to output line-by-line. + std::stringstream objdump_stream; + objdump_stream.str(string(objdump_output_buffer)); + + // Pipe each output line into the string until the string contains the first + // instruction from objdump. All lines before the "<.data>:" section are + // skipped. Loop until the line shows the first instruction or there are no + // lines left. + bool data_section_seen = false; + do { + if (!getline(objdump_stream, *instruction_line)) { + BPLOG(INFO) << "Objdump instructions not found"; + return false; + } + if (instruction_line->find("<.data>:") != string::npos) { + data_section_seen = true; + } + } while (!data_section_seen || instruction_line->find("0:") == string::npos); + // This first instruction contains the above substring. + + return true; +} + +bool ExploitabilityLinux::TokenizeObjdumpInstruction(const string &line, + string *operation, + string *dest, + string *src) { + if (!operation || !dest || !src) { + BPLOG(ERROR) << "Null parameters passed."; + return false; + } + + // Set all pointer values to empty strings. + *operation = ""; + *dest = ""; + *src = ""; + + // Tokenize the objdump line. + vector tokens; + std::istringstream line_stream(line); + copy(std::istream_iterator(line_stream), + std::istream_iterator(), + std::back_inserter(tokens)); + + // Regex for the data in hex form. Each byte is two hex digits. + regex_t regex; + regcomp(®ex, "^[[:xdigit:]]{2}$", REG_EXTENDED | REG_NOSUB); + + // Find and set the location of the operator. The operator appears + // directly after the chain of bytes that define the instruction. The + // operands will be the last token, given that the instruction has operands. + // If not, the operator is the last token. The loop skips the first token + // because the first token is the instruction number (namely "0:"). + string operands = ""; + for (size_t i = 1; i < tokens.size(); i++) { + // Check if current token no longer is in byte format. + if (regexec(®ex, tokens[i].c_str(), 0, NULL, 0)) { + // instruction = tokens[i]; + *operation = tokens[i]; + // If the operator is the last token, there are no operands. + if (i != tokens.size() - 1) { + operands = tokens[tokens.size() - 1]; + } + break; + } + } + regfree(®ex); + + if (operation->empty()) { + BPLOG(ERROR) << "Failed to parse out operation from objdump instruction."; + return false; + } + + // Split operands into source and destination (if applicable). + if (!operands.empty()) { + size_t delim = operands.find(','); + if (delim == string::npos) { + *dest = operands; + } else { + *dest = operands.substr(0, delim); + *src = operands.substr(delim + 1); + } + } + return true; +} + +bool ExploitabilityLinux::DisassembleBytes(const string &architecture, + const uint8_t *raw_bytes, + const unsigned int buffer_len, + char *objdump_output_buffer) { + if (!raw_bytes || !objdump_output_buffer) { + BPLOG(ERROR) << "Bad input parameters."; + return false; + } + + // Write raw bytes around instruction pointer to a temporary file to + // pass as an argument to objdump. + char raw_bytes_tmpfile[] = "/tmp/breakpad_mem_region-raw_bytes-XXXXXX"; + int raw_bytes_fd = mkstemp(raw_bytes_tmpfile); + if (raw_bytes_fd < 0) { + BPLOG(ERROR) << "Failed to create tempfile."; + unlink(raw_bytes_tmpfile); + return false; + } + if (write(raw_bytes_fd, raw_bytes, MAX_INSTRUCTION_LEN) + != MAX_INSTRUCTION_LEN) { + BPLOG(ERROR) << "Writing of raw bytes failed."; + unlink(raw_bytes_tmpfile); + return false; + } + + char cmd[1024] = {0}; + snprintf(cmd, + 1024, + "objdump -D -b binary -M intel -m %s %s", + architecture.c_str(), + raw_bytes_tmpfile); + FILE *objdump_fp = popen(cmd, "r"); + if (!objdump_fp) { + fclose(objdump_fp); + unlink(raw_bytes_tmpfile); + BPLOG(ERROR) << "Failed to call objdump."; + return false; + } + if (fread(objdump_output_buffer, 1, buffer_len, objdump_fp) <= 0) { + fclose(objdump_fp); + unlink(raw_bytes_tmpfile); + BPLOG(ERROR) << "Failed to read objdump output."; + return false; + } + fclose(objdump_fp); + unlink(raw_bytes_tmpfile); + return true; +} +#endif // _WIN32 + +bool ExploitabilityLinux::StackPointerOffStack(uint64_t stack_ptr) { + MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + // Inconclusive if there are no mappings available. + if (!linux_maps_list) { + return false; + } + const MinidumpLinuxMaps *linux_maps = + linux_maps_list->GetLinuxMapsForAddress(stack_ptr); + // Checks if the stack pointer maps to a valid mapping and if the mapping + // is not the stack. If the mapping has no name, it is inconclusive whether + // it is off the stack. + return !linux_maps || (linux_maps->GetPathname().compare("") && + linux_maps->GetPathname().compare( + 0, strlen(kStackPrefix), kStackPrefix)); +} + +bool ExploitabilityLinux::ExecutableStackOrHeap() { + MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + if (linux_maps_list) { + for (size_t i = 0; i < linux_maps_list->get_maps_count(); i++) { + const MinidumpLinuxMaps *linux_maps = + linux_maps_list->GetLinuxMapsAtIndex(i); + // Check for executable stack or heap for each mapping. + if (linux_maps && (!linux_maps->GetPathname().compare( + 0, strlen(kStackPrefix), kStackPrefix) || + !linux_maps->GetPathname().compare( + 0, strlen(kHeapPrefix), kHeapPrefix)) && + linux_maps->IsExecutable()) { + return true; + } + } + } + return false; +} + +bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { + // Get Linux memory mapping from /proc/self/maps. Checking whether the + // region the instruction pointer is in has executable permission can tell + // whether it is in a valid code region. If there is no mapping for the + // instruction pointer, it is indicative that the instruction pointer is + // not within a module, which implies that it is outside a valid area. + MinidumpLinuxMapsList *linux_maps_list = dump_->GetLinuxMapsList(); + const MinidumpLinuxMaps *linux_maps = + linux_maps_list ? + linux_maps_list->GetLinuxMapsForAddress(instruction_ptr) : NULL; + return linux_maps ? linux_maps->IsExecutable() : false; +} + +bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream + *raw_exception_stream) { + // Check the cause of crash. + // If the exception of the crash is a benign exception, + // it is probably not exploitable. + switch (raw_exception_stream->exception_record.exception_code) { + case MD_EXCEPTION_CODE_LIN_SIGHUP: + case MD_EXCEPTION_CODE_LIN_SIGINT: + case MD_EXCEPTION_CODE_LIN_SIGQUIT: + case MD_EXCEPTION_CODE_LIN_SIGTRAP: + case MD_EXCEPTION_CODE_LIN_SIGABRT: + case MD_EXCEPTION_CODE_LIN_SIGFPE: + case MD_EXCEPTION_CODE_LIN_SIGKILL: + case MD_EXCEPTION_CODE_LIN_SIGUSR1: + case MD_EXCEPTION_CODE_LIN_SIGUSR2: + case MD_EXCEPTION_CODE_LIN_SIGPIPE: + case MD_EXCEPTION_CODE_LIN_SIGALRM: + case MD_EXCEPTION_CODE_LIN_SIGTERM: + case MD_EXCEPTION_CODE_LIN_SIGCHLD: + case MD_EXCEPTION_CODE_LIN_SIGCONT: + case MD_EXCEPTION_CODE_LIN_SIGSTOP: + case MD_EXCEPTION_CODE_LIN_SIGTSTP: + case MD_EXCEPTION_CODE_LIN_SIGTTIN: + case MD_EXCEPTION_CODE_LIN_SIGTTOU: + case MD_EXCEPTION_CODE_LIN_SIGURG: + case MD_EXCEPTION_CODE_LIN_SIGXCPU: + case MD_EXCEPTION_CODE_LIN_SIGXFSZ: + case MD_EXCEPTION_CODE_LIN_SIGVTALRM: + case MD_EXCEPTION_CODE_LIN_SIGPROF: + case MD_EXCEPTION_CODE_LIN_SIGWINCH: + case MD_EXCEPTION_CODE_LIN_SIGIO: + case MD_EXCEPTION_CODE_LIN_SIGPWR: + case MD_EXCEPTION_CODE_LIN_SIGSYS: + case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: + return true; + break; + default: + return false; + break; + } +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.h b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.h new file mode 100644 index 0000000000..e3ff13b6e0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_linux.h @@ -0,0 +1,129 @@ +// Copyright (c) 2013 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. + +// exploitability_linux.h: Linux specific exploitability engine. +// +// Provides a guess at the exploitability of the crash for the Linux +// platform given a minidump and process_state. +// +// Author: Matthew Riley + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_LINUX_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_LINUX_H_ + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/exploitability.h" + +namespace google_breakpad { + +class ExploitabilityLinux : public Exploitability { + public: + ExploitabilityLinux(Minidump *dump, + ProcessState *process_state); + + // Parameters are the minidump to analyze, the object representing process + // state, and whether to enable objdump disassembly. + // Enabling objdump will allow exploitability analysis to call out to + // objdump for diassembly. It is used to check the identity of the + // instruction that caused the program to crash. If there are any + // portability concerns, this should not be enabled. + ExploitabilityLinux(Minidump *dump, + ProcessState *process_state, + bool enable_objdump); + + virtual ExploitabilityRating CheckPlatformExploitability(); + + private: + friend class ExploitabilityLinuxTest; + + // Takes the address of the instruction pointer and returns + // whether the instruction pointer lies in a valid instruction region. + bool InstructionPointerInCode(uint64_t instruction_ptr); + + // Checks the exception that triggered the creation of the + // minidump and reports whether the exception suggests no exploitability. + bool BenignCrashTrigger(const MDRawExceptionStream *raw_exception_stream); + + // This method checks if the crash occurred during a write to read-only or + // invalid memory. It does so by checking if the instruction at the + // instruction pointer is a write instruction, and if the target of the + // instruction is at a spot in memory that prohibits writes. + bool EndedOnIllegalWrite(uint64_t instruction_ptr); + +#ifndef _WIN32 + // Disassembles raw bytes via objdump and pipes the output into the provided + // buffer, given the desired architecture, the file from which objdump will + // read, and the buffer length. The method returns whether the disassembly + // was a success, and the caller owns all pointers. + static bool DisassembleBytes(const string &architecture, + const uint8_t *raw_bytes, + const unsigned int MAX_OBJDUMP_BUFFER_LEN, + char *objdump_output_buffer); + + // Parses the objdump output given in |objdump_output_buffer| and extracts + // the line of the first instruction into |instruction_line|. Returns true + // when the instruction line is successfully extracted. + static bool GetObjdumpInstructionLine( + const char *objdump_output_buffer, + string *instruction_line); + + // Tokenizes out the operation and operands from a line of instruction + // disassembled by objdump. This method modifies the pointers to match the + // tokens of the instruction, and returns if the tokenizing was a success. + // The caller owns all pointers. + static bool TokenizeObjdumpInstruction(const string &line, + string *operation, + string *dest, + string *src); + + // Calculates the effective address of an expression in the form reg+a or + // reg-a, where 'reg' is a register and 'a' is a constant, and writes the + // result in the pointer. The method returns whether the calculation was + // a success. The caller owns the pointer. + static bool CalculateAddress(const string &address_expression, + const DumpContext &context, + uint64_t *write_address); +#endif // _WIN32 + + // Checks if the stack pointer points to a memory mapping that is not + // labelled as the stack. + bool StackPointerOffStack(uint64_t stack_ptr); + + // Checks if the stack or heap are marked executable according + // to the memory mappings. + bool ExecutableStackOrHeap(); + + // Whether this exploitability engine is permitted to shell out to objdump + // to disassemble raw bytes. + bool enable_objdump_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_LINUX_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_unittest.cc new file mode 100644 index 0000000000..528ee5f213 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_unittest.cc @@ -0,0 +1,306 @@ +// Copyright (c) 2010, 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 +#include + +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#ifndef _WIN32 +#include "processor/exploitability_linux.h" +#endif // _WIN32 +#include "processor/simple_symbol_supplier.h" + +#ifndef _WIN32 +namespace google_breakpad { + +class ExploitabilityLinuxTest : public ExploitabilityLinux { + public: + using ExploitabilityLinux::CalculateAddress; + using ExploitabilityLinux::DisassembleBytes; + using ExploitabilityLinux::GetObjdumpInstructionLine; + using ExploitabilityLinux::TokenizeObjdumpInstruction; +}; + +class ExploitabilityLinuxTestMinidumpContext : public MinidumpContext { + public: + explicit ExploitabilityLinuxTestMinidumpContext( + const MDRawContextAMD64& context) : MinidumpContext(NULL) { + valid_ = true; + SetContextAMD64(new MDRawContextAMD64(context)); + SetContextFlags(MD_CONTEXT_AMD64); + } +}; + +} // namespace google_breakpad +#endif // _WIN32 + +namespace { + +using google_breakpad::BasicSourceLineResolver; +#ifndef _WIN32 +using google_breakpad::ExploitabilityLinuxTest; +using google_breakpad::ExploitabilityLinuxTestMinidumpContext; +#endif // _WIN32 +using google_breakpad::MinidumpProcessor; +using google_breakpad::ProcessState; +using google_breakpad::SimpleSymbolSupplier; + +string TestDataDir() { + return string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata"; +} + +// Find the given dump file in /src/processor/testdata, process it, +// and get the exploitability rating. Returns EXPLOITABILITY_ERR_PROCESSING +// if the crash dump can't be processed. +google_breakpad::ExploitabilityRating +ExploitabilityFor(const string& filename) { + SimpleSymbolSupplier supplier(TestDataDir() + "/symbols"); + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver, true); + processor.set_enable_objdump(true); + ProcessState state; + + string minidump_file = TestDataDir() + "/" + filename; + + if (processor.Process(minidump_file, &state) != + google_breakpad::PROCESS_OK) { + return google_breakpad::EXPLOITABILITY_ERR_PROCESSING; + } + + return state.exploitability(); +} + +TEST(ExploitabilityTest, TestWindowsEngine) { + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av_block_write.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av_clobber_write.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av_conditional.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av_then_jmp.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_read_av_xchg_write.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_write_av.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("ascii_write_av_arg_to_call.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("null_read_av.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("null_write_av.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("stack_exhaustion.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("exec_av_on_stack.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_MEDIUM, + ExploitabilityFor("write_av_non_null.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW, + ExploitabilityFor("read_av_non_null.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW, + ExploitabilityFor("read_av_clobber_write.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_LOW, + ExploitabilityFor("read_av_conditional.dmp")); +} + +TEST(ExploitabilityTest, TestLinuxEngine) { + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_null_read_av.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_overflow.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_stacksmash.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("linux_divide_by_zero.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_null_dereference.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_jmp_to_0.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_outside_module.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NONE, + ExploitabilityFor("linux_raise_sigabrt.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_inside_module_exe_region1.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_inside_module_exe_region2.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_stack_pointer_in_stack.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_stack_pointer_in_stack_alt_name.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_stack_pointer_in_module.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_executable_stack.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_executable_heap.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_jmp_to_module_not_exe_region.dmp")); +#ifndef _WIN32 + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_write_to_nonwritable_module.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_write_to_nonwritable_region_math.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_write_to_outside_module.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_HIGH, + ExploitabilityFor("linux_write_to_outside_module_via_math.dmp")); + ASSERT_EQ(google_breakpad::EXPLOITABILITY_INTERESTING, + ExploitabilityFor("linux_write_to_under_4k.dmp")); +#endif // _WIN32 +} + +#ifndef _WIN32 +TEST(ExploitabilityLinuxUtilsTest, DisassembleBytesTest) { + ASSERT_FALSE(ExploitabilityLinuxTest::DisassembleBytes("", NULL, 5, NULL)); + uint8_t bytes[6] = {0xc7, 0x0, 0x5, 0x0, 0x0, 0x0}; + char buffer[1024] = {0}; + ASSERT_TRUE(ExploitabilityLinuxTest::DisassembleBytes("i386:x86-64", + bytes, + 1024, + buffer)); + std::stringstream objdump_stream; + objdump_stream.str(string(buffer)); + string line = ""; + while (line.find("<.data>") == string::npos) + getline(objdump_stream, line); + getline(objdump_stream, line); + ASSERT_EQ(line, " 0:\tc7 00 05 00 00 00 \tmov DWORD PTR [rax],0x5"); +} + +TEST(ExploitabilityLinuxUtilsTest, GetObjdumpInstructionLine) { + string disassebly = + "\n" + "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n" + "// Trying to confuse the parser 0:\n" + "\n" + "Disassembly of section .data:\n" + "\n" + "0000000000000000 <.data>:\n" + " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n" + " 6:\t5d \tpop rbp\n" + " 7:\tc3 \tret \n" + " 8:\t55 \tpush rbp\n" + " 9:\t48 89 e5 \tmov rbp,rsp\n" + " c:\t53 \tpush rbx\n" + " d:\t48 \trex.W\n" + " e:\t81 \t.byte 0x81\n"; + string line; + EXPECT_TRUE(ExploitabilityLinuxTest::GetObjdumpInstructionLine( + disassebly.c_str(), &line)); + EXPECT_EQ(" 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1", line); + + // There is no "0:" after "<.data>:". Expected to return false. + disassebly = + "\n" + "/tmp/breakpad_mem_region-raw_bytes-tMmMo0: file format binary\n" + "// Trying to confuse the parser 0:\n" + "\n" + "Disassembly of section .data:\n" + "\n" + " 0:\tc7 00 01 00 00 00 \tmov DWORD PTR [rax],0x1\n" + " 6:\t5d \tpop rbp\n" + " 7:\tc3 \tret \n" + " 8:\t55 \tpush rbp\n" + " 9:\t48 89 e5 \tmov rbp,rsp\n" + " d:\t48 \trex.W\n" + "0000000000000000 <.data>:\n" + " c:\t53 \tpush rbx\n"; + EXPECT_FALSE(ExploitabilityLinuxTest::GetObjdumpInstructionLine( + disassebly.c_str(), &line)); +} + +TEST(ExploitabilityLinuxUtilsTest, TokenizeObjdumpInstructionTest) { + ASSERT_FALSE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction("", + NULL, + NULL, + NULL)); + string line = "0: c7 00 05 00 00 00 mov DWORD PTR [rax],0x5"; + string operation = ""; + string dest = ""; + string src = ""; + ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, + &operation, + &dest, + &src)); + ASSERT_EQ(operation, "mov"); + ASSERT_EQ(dest, "[rax]"); + ASSERT_EQ(src, "0x5"); + line = "0: c3 ret"; + ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, + &operation, + &dest, + &src)); + ASSERT_EQ(operation, "ret"); + ASSERT_EQ(dest, ""); + ASSERT_EQ(src, ""); + line = "0: 5f pop rdi"; + ASSERT_TRUE(ExploitabilityLinuxTest::TokenizeObjdumpInstruction(line, + &operation, + &dest, + &src)); + ASSERT_EQ(operation, "pop"); + ASSERT_EQ(dest, "rdi"); + ASSERT_EQ(src, ""); +} + +TEST(ExploitabilityLinuxUtilsTest, CalculateAddressTest) { + MDRawContextAMD64 raw_context; + raw_context.rdx = 12345; + ExploitabilityLinuxTestMinidumpContext context(raw_context); + ASSERT_EQ(context.GetContextAMD64()->rdx, 12345U); + ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("", context, NULL)); + uint64_t write_address = 0; + ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx-0x4D2", + context, + &write_address)); + ASSERT_EQ(write_address, 11111U); + ASSERT_TRUE(ExploitabilityLinuxTest::CalculateAddress("rdx+0x4D2", + context, + &write_address)); + ASSERT_EQ(write_address, 13579U); + ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("rdx+rax", + context, + &write_address)); + ASSERT_FALSE(ExploitabilityLinuxTest::CalculateAddress("0x3482+0x4D2", + context, + &write_address)); +} +#endif // _WIN32 + +} // namespace diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.cc b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.cc new file mode 100644 index 0000000000..515b9727bf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.cc @@ -0,0 +1,283 @@ +// Copyright (c) 2010 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. + +// exploitability_win.cc: Windows specific exploitability engine. +// +// Provides a guess at the exploitability of the crash for the Windows +// platform given a minidump and process_state. +// +// Author: Cris Neckar + +#include + +#include "processor/exploitability_win.h" + +#include "common/scoped_ptr.h" +#include "google_breakpad/common/minidump_exception_win32.h" +#include "google_breakpad/processor/minidump.h" +#include "processor/disassembler_x86.h" +#include "processor/logging.h" + +#include "third_party/libdisasm/libdis.h" + +namespace google_breakpad { + +// The cutoff that we use to judge if and address is likely an offset +// from various interesting addresses. +static const uint64_t kProbableNullOffset = 4096; +static const uint64_t kProbableStackOffset = 8192; + +// The various cutoffs for the different ratings. +static const size_t kHighCutoff = 100; +static const size_t kMediumCutoff = 80; +static const size_t kLowCutoff = 50; +static const size_t kInterestingCutoff = 25; + +// Predefined incremental values for conditional weighting. +static const size_t kTinyBump = 5; +static const size_t kSmallBump = 20; +static const size_t kMediumBump = 50; +static const size_t kLargeBump = 70; +static const size_t kHugeBump = 90; + +// The maximum number of bytes to disassemble past the program counter. +static const size_t kDisassembleBytesBeyondPC = 2048; + +ExploitabilityWin::ExploitabilityWin(Minidump *dump, + ProcessState *process_state) + : Exploitability(dump, process_state) { } + +ExploitabilityRating ExploitabilityWin::CheckPlatformExploitability() { + MinidumpException *exception = dump_->GetException(); + if (!exception) { + BPLOG(INFO) << "Minidump does not have exception record."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + const MDRawExceptionStream *raw_exception = exception->exception(); + if (!raw_exception) { + BPLOG(INFO) << "Could not obtain raw exception info."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + const MinidumpContext *context = exception->GetContext(); + if (!context) { + BPLOG(INFO) << "Could not obtain exception context."; + return EXPLOITABILITY_ERR_PROCESSING; + } + + MinidumpMemoryList *memory_list = dump_->GetMemoryList(); + bool memory_available = true; + if (!memory_list) { + BPLOG(INFO) << "Minidump memory segments not available."; + memory_available = false; + } + uint64_t address = process_state_->crash_address(); + uint32_t exception_code = raw_exception->exception_record.exception_code; + + uint32_t exploitability_weight = 0; + + uint64_t stack_ptr = 0; + uint64_t instruction_ptr = 0; + + // Getting the instruction pointer. + if (!context->GetInstructionPointer(&instruction_ptr)) { + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Getting the stack pointer. + if (!context->GetStackPointer(&stack_ptr)) { + return EXPLOITABILITY_ERR_PROCESSING; + } + + // Check if we are executing on the stack. + if (instruction_ptr <= (stack_ptr + kProbableStackOffset) && + instruction_ptr >= (stack_ptr - kProbableStackOffset)) + exploitability_weight += kHugeBump; + + switch (exception_code) { + // This is almost certainly recursion. + case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: + exploitability_weight += kTinyBump; + break; + + // These exceptions tend to be benign and we can generally ignore them. + case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: + case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: + case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: + case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: + case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: + case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: + case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: + exploitability_weight += kTinyBump; + break; + + // These exceptions will typically mean that we have jumped where we + // shouldn't. + case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: + case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: + case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: + exploitability_weight += kLargeBump; + break; + + // These represent bugs in exception handlers. + case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: + case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: + exploitability_weight += kSmallBump; + break; + + case MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION: + case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: + exploitability_weight += kHugeBump; + break; + + case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: + exploitability_weight += kLargeBump; + break; + + case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: + bool near_null = (address <= kProbableNullOffset); + bool bad_read = false; + bool bad_write = false; + if (raw_exception->exception_record.number_parameters >= 1) { + MDAccessViolationTypeWin av_type = + static_cast + (raw_exception->exception_record.exception_information[0]); + switch (av_type) { + case MD_ACCESS_VIOLATION_WIN_READ: + bad_read = true; + if (near_null) + exploitability_weight += kSmallBump; + else + exploitability_weight += kMediumBump; + break; + case MD_ACCESS_VIOLATION_WIN_WRITE: + bad_write = true; + if (near_null) + exploitability_weight += kSmallBump; + else + exploitability_weight += kHugeBump; + break; + case MD_ACCESS_VIOLATION_WIN_EXEC: + if (near_null) + exploitability_weight += kSmallBump; + else + exploitability_weight += kHugeBump; + break; + default: + BPLOG(INFO) << "Unrecognized access violation type."; + return EXPLOITABILITY_ERR_PROCESSING; + break; + } + MinidumpMemoryRegion *instruction_region = 0; + if (memory_available) { + instruction_region = + memory_list->GetMemoryRegionForAddress(instruction_ptr); + } + if (!near_null && instruction_region && + context->GetContextCPU() == MD_CONTEXT_X86 && + (bad_read || bad_write)) { + // Perform checks related to memory around instruction pointer. + uint32_t memory_offset = + instruction_ptr - instruction_region->GetBase(); + uint32_t available_memory = + instruction_region->GetSize() - memory_offset; + available_memory = available_memory > kDisassembleBytesBeyondPC ? + kDisassembleBytesBeyondPC : available_memory; + if (available_memory) { + const uint8_t *raw_memory = + instruction_region->GetMemory() + memory_offset; + DisassemblerX86 disassembler(raw_memory, + available_memory, + instruction_ptr); + disassembler.NextInstruction(); + if (bad_read) + disassembler.setBadRead(); + else + disassembler.setBadWrite(); + if (disassembler.currentInstructionValid()) { + // Check if the faulting instruction falls into one of + // several interesting groups. + switch (disassembler.currentInstructionGroup()) { + case libdis::insn_controlflow: + exploitability_weight += kLargeBump; + break; + case libdis::insn_string: + exploitability_weight += kHugeBump; + break; + default: + break; + } + // Loop the disassembler through the code and check if it + // IDed any interesting conditions in the near future. + // Multiple flags may be set so treat each equally. + while (disassembler.NextInstruction() && + disassembler.currentInstructionValid() && + !disassembler.endOfBlock()) + continue; + if (disassembler.flags() & DISX86_BAD_BRANCH_TARGET) + exploitability_weight += kLargeBump; + if (disassembler.flags() & DISX86_BAD_ARGUMENT_PASSED) + exploitability_weight += kTinyBump; + if (disassembler.flags() & DISX86_BAD_WRITE) + exploitability_weight += kMediumBump; + if (disassembler.flags() & DISX86_BAD_BLOCK_WRITE) + exploitability_weight += kMediumBump; + if (disassembler.flags() & DISX86_BAD_READ) + exploitability_weight += kTinyBump; + if (disassembler.flags() & DISX86_BAD_BLOCK_READ) + exploitability_weight += kTinyBump; + if (disassembler.flags() & DISX86_BAD_COMPARISON) + exploitability_weight += kTinyBump; + } + } + } + if (!near_null && AddressIsAscii(address)) + exploitability_weight += kMediumBump; + } else { + BPLOG(INFO) << "Access violation type parameter missing."; + return EXPLOITABILITY_ERR_PROCESSING; + } + } + + // Based on the calculated weight we return a simplified classification. + BPLOG(INFO) << "Calculated exploitability weight: " << exploitability_weight; + if (exploitability_weight >= kHighCutoff) + return EXPLOITABILITY_HIGH; + if (exploitability_weight >= kMediumCutoff) + return EXPLOITABLITY_MEDIUM; + if (exploitability_weight >= kLowCutoff) + return EXPLOITABILITY_LOW; + if (exploitability_weight >= kInterestingCutoff) + return EXPLOITABILITY_INTERESTING; + + return EXPLOITABILITY_NONE; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.h b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.h new file mode 100644 index 0000000000..4e08aef030 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/exploitability_win.h @@ -0,0 +1,55 @@ +// Copyright (c) 2010 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. + +// exploitability_win.h: Windows specific exploitability engine. +// +// Provides a guess at the exploitability of the crash for the Windows +// platform given a minidump and process_state. +// +// Author: Cris Neckar + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_WIN_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_WIN_H_ + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/exploitability.h" + +namespace google_breakpad { + +class ExploitabilityWin : public Exploitability { + public: + ExploitabilityWin(Minidump *dump, + ProcessState *process_state); + + virtual ExploitabilityRating CheckPlatformExploitability(); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_WIN_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver.cc b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver.cc new file mode 100644 index 0000000000..4a3d000714 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver.cc @@ -0,0 +1,275 @@ +// Copyright (c) 2010 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. +// +// fast_source_line_resolver.cc: FastSourceLineResolver is a concrete class that +// implements SourceLineResolverInterface. Both FastSourceLineResolver and +// BasicSourceLineResolver inherit from SourceLineResolverBase class to reduce +// code redundancy. +// +// See fast_source_line_resolver.h and fast_source_line_resolver_types.h +// for more documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include "google_breakpad/processor/fast_source_line_resolver.h" +#include "processor/fast_source_line_resolver_types.h" + +#include +#include +#include + +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "processor/module_factory.h" +#include "processor/simple_serializer-inl.h" + +using std::map; +using std::make_pair; + +namespace google_breakpad { + +FastSourceLineResolver::FastSourceLineResolver() + : SourceLineResolverBase(new FastModuleFactory) { } + +bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() { + return false; +} + +void FastSourceLineResolver::Module::LookupAddress(StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + + // First, look for a FUNC record that covers address. Use + // RetrieveNearestRange instead of RetrieveRange so that, if there + // is no such function, we can use the next function to bound the + // extent of the PUBLIC symbol we find, below. This does mean we + // need to check that address indeed falls within the function we + // find; do the range comparison in an overflow-friendly way. + scoped_ptr func(new Function); + const Function* func_ptr = 0; + scoped_ptr public_symbol(new PublicSymbol); + const PublicSymbol* public_symbol_ptr = 0; + MemAddr function_base; + MemAddr function_size; + MemAddr public_address; + + if (functions_.RetrieveNearestRange(address, func_ptr, + &function_base, &function_size) && + address >= function_base && address - function_base < function_size) { + func.get()->CopyFrom(func_ptr); + frame->function_name = func->name; + frame->function_base = frame->module->base_address() + function_base; + + scoped_ptr line(new Line); + const Line* line_ptr = 0; + MemAddr line_base; + if (func->lines.RetrieveRange(address, line_ptr, &line_base, NULL)) { + line.get()->CopyFrom(line_ptr); + FileMap::iterator it = files_.find(line->source_file_id); + if (it != files_.end()) { + frame->source_file_name = + files_.find(line->source_file_id).GetValuePtr(); + } + frame->source_line = line->line; + frame->source_line_base = frame->module->base_address() + line_base; + } + } else if (public_symbols_.Retrieve(address, + public_symbol_ptr, &public_address) && + (!func_ptr || public_address > function_base)) { + public_symbol.get()->CopyFrom(public_symbol_ptr); + frame->function_name = public_symbol->name; + frame->function_base = frame->module->base_address() + public_address; + } +} + +// WFI: WindowsFrameInfo. +// Returns a WFI object reading from a raw memory chunk of data +WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) { + const WindowsFrameInfo::StackInfoTypes type = + static_cast( + *reinterpret_cast(raw)); + + // The first 8 bytes of int data are unused. + // They correspond to "StackInfoTypes type_;" and "int valid;" + // data member of WFI. + const uint32_t *para_uint32 = reinterpret_cast( + raw + 2 * sizeof(int32_t)); + + uint32_t prolog_size = para_uint32[0];; + uint32_t epilog_size = para_uint32[1]; + uint32_t parameter_size = para_uint32[2]; + uint32_t saved_register_size = para_uint32[3]; + uint32_t local_size = para_uint32[4]; + uint32_t max_stack_size = para_uint32[5]; + const char *boolean = reinterpret_cast(para_uint32 + 6); + bool allocates_base_pointer = (*boolean != 0); + string program_string = boolean + 1; + + return WindowsFrameInfo(type, + prolog_size, + epilog_size, + parameter_size, + saved_register_size, + local_size, + max_stack_size, + allocates_base_pointer, + program_string); +} + +// Loads a map from the given buffer in char* type. +// Does NOT take ownership of mem_buffer. +// In addition, treat mem_buffer as const char*. +bool FastSourceLineResolver::Module::LoadMapFromMemory( + char *memory_buffer, + size_t memory_buffer_size) { + if (!memory_buffer) return false; + + // Read the "is_corrupt" flag. + const char *mem_buffer = memory_buffer; + mem_buffer = SimpleSerializer::Read(mem_buffer, &is_corrupt_); + + const uint32_t *map_sizes = reinterpret_cast(mem_buffer); + + unsigned int header_size = kNumberMaps_ * sizeof(unsigned int); + + // offsets[]: an array of offset addresses (with respect to mem_buffer), + // for each "Static***Map" component of Module. + // "Static***Map": static version of std::map or map wrapper, i.e., StaticMap, + // StaticAddressMap, StaticContainedRangeMap, and StaticRangeMap. + unsigned int offsets[kNumberMaps_]; + offsets[0] = header_size; + for (int i = 1; i < kNumberMaps_; ++i) { + offsets[i] = offsets[i - 1] + map_sizes[i - 1]; + } + + // Use pointers to construct Static*Map data members in Module: + int map_id = 0; + files_ = StaticMap(mem_buffer + offsets[map_id++]); + functions_ = + StaticRangeMap(mem_buffer + offsets[map_id++]); + public_symbols_ = + StaticAddressMap(mem_buffer + offsets[map_id++]); + for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) + windows_frame_info_[i] = + StaticContainedRangeMap(mem_buffer + offsets[map_id++]); + + cfi_initial_rules_ = + StaticRangeMap(mem_buffer + offsets[map_id++]); + cfi_delta_rules_ = StaticMap(mem_buffer + offsets[map_id++]); + + return true; +} + +WindowsFrameInfo *FastSourceLineResolver::Module::FindWindowsFrameInfo( + const StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + scoped_ptr result(new WindowsFrameInfo()); + + // We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and + // WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order. + // WindowsFrameInfo::STACK_INFO_FRAME_DATA is the newer type that + // includes its own program string. + // WindowsFrameInfo::STACK_INFO_FPO is the older type + // corresponding to the FPO_DATA struct. See stackwalker_x86.cc. + const char* frame_info_ptr; + if ((windows_frame_info_[WindowsFrameInfo::STACK_INFO_FRAME_DATA] + .RetrieveRange(address, frame_info_ptr)) + || (windows_frame_info_[WindowsFrameInfo::STACK_INFO_FPO] + .RetrieveRange(address, frame_info_ptr))) { + result->CopyFrom(CopyWFI(frame_info_ptr)); + return result.release(); + } + + // Even without a relevant STACK line, many functions contain + // information about how much space their parameters consume on the + // stack. Use RetrieveNearestRange instead of RetrieveRange, so that + // we can use the function to bound the extent of the PUBLIC symbol, + // below. However, this does mean we need to check that ADDRESS + // falls within the retrieved function's range; do the range + // comparison in an overflow-friendly way. + scoped_ptr function(new Function); + const Function* function_ptr = 0; + MemAddr function_base, function_size; + if (functions_.RetrieveNearestRange(address, function_ptr, + &function_base, &function_size) && + address >= function_base && address - function_base < function_size) { + function.get()->CopyFrom(function_ptr); + result->parameter_size = function->parameter_size; + result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE; + return result.release(); + } + + // PUBLIC symbols might have a parameter size. Use the function we + // found above to limit the range the public symbol covers. + scoped_ptr public_symbol(new PublicSymbol); + const PublicSymbol* public_symbol_ptr = 0; + MemAddr public_address; + if (public_symbols_.Retrieve(address, public_symbol_ptr, &public_address) && + (!function_ptr || public_address > function_base)) { + public_symbol.get()->CopyFrom(public_symbol_ptr); + result->parameter_size = public_symbol->parameter_size; + } + + return NULL; +} + +CFIFrameInfo *FastSourceLineResolver::Module::FindCFIFrameInfo( + const StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + MemAddr initial_base, initial_size; + const char* initial_rules = NULL; + + // Find the initial rule whose range covers this address. That + // provides an initial set of register recovery rules. Then, walk + // forward from the initial rule's starting address to frame's + // instruction address, applying delta rules. + if (!cfi_initial_rules_.RetrieveRange(address, initial_rules, + &initial_base, &initial_size)) { + return NULL; + } + + // Create a frame info structure, and populate it with the rules from + // the STACK CFI INIT record. + scoped_ptr rules(new CFIFrameInfo()); + if (!ParseCFIRuleSet(initial_rules, rules.get())) + return NULL; + + // Find the first delta rule that falls within the initial rule's range. + StaticMap::iterator delta = + cfi_delta_rules_.lower_bound(initial_base); + + // Apply delta rules up to and including the frame's address. + while (delta != cfi_delta_rules_.end() && delta.GetKey() <= address) { + ParseCFIRuleSet(delta.GetValuePtr(), rules.get()); + delta++; + } + + return rules.release(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_types.h b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_types.h new file mode 100644 index 0000000000..2c010470f5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_types.h @@ -0,0 +1,185 @@ +// Copyright (c) 2010 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. +// +// fast_source_line_resolver_types.h: definition of nested classes/structs in +// FastSourceLineResolver. It moves the definitions out of +// fast_source_line_resolver.cc, so that other classes could have access +// to these private nested types without including fast_source_line_resolver.cc +// +// Author: lambxsy@google.com (Siyang Xie) + +#ifndef PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__ +#define PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__ + +#include "google_breakpad/processor/fast_source_line_resolver.h" +#include "processor/source_line_resolver_base_types.h" + +#include +#include + +#include "google_breakpad/processor/stack_frame.h" +#include "processor/cfi_frame_info.h" +#include "processor/static_address_map-inl.h" +#include "processor/static_contained_range_map-inl.h" +#include "processor/static_map.h" +#include "processor/static_range_map-inl.h" +#include "processor/windows_frame_info.h" + +namespace google_breakpad { + +struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { + void CopyFrom(const Line *line_ptr) { + const char *raw = reinterpret_cast(line_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a Line. + void CopyFrom(const char *raw) { + address = *(reinterpret_cast(raw)); + size = *(reinterpret_cast(raw + sizeof(address))); + source_file_id = *(reinterpret_cast( + raw + 2 * sizeof(address))); + line = *(reinterpret_cast( + raw + 2 * sizeof(address) + sizeof(source_file_id))); + } +}; + +struct FastSourceLineResolver::Function : +public SourceLineResolverBase::Function { + void CopyFrom(const Function *func_ptr) { + const char *raw = reinterpret_cast(func_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a Function. + void CopyFrom(const char *raw) { + size_t name_size = strlen(raw) + 1; + name = raw; + address = *(reinterpret_cast(raw + name_size)); + size = *(reinterpret_cast( + raw + name_size + sizeof(MemAddr))); + parameter_size = *(reinterpret_cast( + raw + name_size + 2 * sizeof(MemAddr))); + lines = StaticRangeMap( + raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t)); + } + + StaticRangeMap lines; +}; + +struct FastSourceLineResolver::PublicSymbol : +public SourceLineResolverBase::PublicSymbol { + void CopyFrom(const PublicSymbol *public_symbol_ptr) { + const char *raw = reinterpret_cast(public_symbol_ptr); + CopyFrom(raw); + } + + // De-serialize the memory data of a PublicSymbol. + void CopyFrom(const char *raw) { + size_t name_size = strlen(raw) + 1; + name = raw; + address = *(reinterpret_cast(raw + name_size)); + parameter_size = *(reinterpret_cast( + raw + name_size + sizeof(MemAddr))); + } +}; + +class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { + public: + explicit Module(const string &name) : name_(name), is_corrupt_(false) { } + virtual ~Module() { } + + // Looks up the given relative address, and fills the StackFrame struct + // with the result. + virtual void LookupAddress(StackFrame *frame) const; + + // Loads a map from the given buffer in char* type. + virtual bool LoadMapFromMemory(char *memory_buffer, + size_t memory_buffer_size); + + // Tells whether the loaded symbol data is corrupt. Return value is + // undefined, if the symbol data hasn't been loaded yet. + virtual bool IsCorrupt() const { return is_corrupt_; } + + // If Windows stack walking information is available covering ADDRESS, + // return a WindowsFrameInfo structure describing it. If the information + // is not available, returns NULL. A NULL return value does not indicate + // an error. The caller takes ownership of any returned WindowsFrameInfo + // object. + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) const; + + // If CFI stack walking information is available covering ADDRESS, + // return a CFIFrameInfo structure describing it. If the information + // is not available, return NULL. The caller takes ownership of any + // returned CFIFrameInfo object. + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const; + + // Number of serialized map components of Module. + static const int kNumberMaps_ = 5 + WindowsFrameInfo::STACK_INFO_LAST; + + private: + friend class FastSourceLineResolver; + friend class ModuleComparer; + typedef StaticMap FileMap; + + string name_; + StaticMap files_; + StaticRangeMap functions_; + StaticAddressMap public_symbols_; + bool is_corrupt_; + + // Each element in the array is a ContainedRangeMap for a type + // listed in WindowsFrameInfoTypes. These are split by type because + // there may be overlaps between maps of different types, but some + // information is only available as certain types. + StaticContainedRangeMap + windows_frame_info_[WindowsFrameInfo::STACK_INFO_LAST]; + + // DWARF CFI stack walking data. The Module stores the initial rule sets + // and rule deltas as strings, just as they appear in the symbol file: + // although the file may contain hundreds of thousands of STACK CFI + // records, walking a stack will only ever use a few of them, so it's + // best to delay parsing a record until it's actually needed. + // + // STACK CFI INIT records: for each range, an initial set of register + // recovery rules. The RangeMap's itself gives the starting and ending + // addresses. + StaticRangeMap cfi_initial_rules_; + + // STACK CFI records: at a given address, the changes to the register + // recovery rules that take effect at that address. The map key is the + // starting address; the ending address is the key of the next entry in + // this map, or the end of the range as given by the cfi_initial_rules_ + // entry (which FindCFIFrameInfo looks up first). + StaticMap cfi_delta_rules_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_unittest.cc new file mode 100644 index 0000000000..87b13c522e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/fast_source_line_resolver_unittest.cc @@ -0,0 +1,492 @@ +// Copyright (c) 2010 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. +// +// fast_source_line_resolver_unittest.cc: Unit tests for FastSourceLineResolver. +// Two different approaches for testing fast source line resolver: +// First, use the same unit test data for basic source line resolver. +// Second, read data from symbol files, load them as basic modules, and then +// serialize them and load the serialized data as fast modules. Then compare +// modules to assure the fast module contains exactly the same data as +// basic module. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include +#include + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/memory_region.h" +#include "processor/logging.h" +#include "processor/module_serializer.h" +#include "processor/module_comparer.h" + +namespace { + +using google_breakpad::SourceLineResolverBase; +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::FastSourceLineResolver; +using google_breakpad::ModuleSerializer; +using google_breakpad::ModuleComparer; +using google_breakpad::CFIFrameInfo; +using google_breakpad::CodeModule; +using google_breakpad::MemoryRegion; +using google_breakpad::StackFrame; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::linked_ptr; +using google_breakpad::scoped_ptr; + +class TestCodeModule : public CodeModule { + public: + explicit TestCodeModule(string code_file) : code_file_(code_file) {} + virtual ~TestCodeModule() {} + + virtual uint64_t base_address() const { return 0; } + virtual uint64_t size() const { return 0xb000; } + virtual string code_file() const { return code_file_; } + virtual string code_identifier() const { return ""; } + virtual string debug_file() const { return ""; } + virtual string debug_identifier() const { return ""; } + virtual string version() const { return ""; } + virtual CodeModule* Copy() const { + return new TestCodeModule(code_file_); + } + virtual bool is_unloaded() const { return false; } + virtual uint64_t shrink_down_delta() const { return 0; } + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {} + + private: + string code_file_; +}; + +// A mock memory region object, for use by the STACK CFI tests. +class MockMemoryRegion: public MemoryRegion { + uint64_t GetBase() const { return 0x10000; } + uint32_t GetSize() const { return 0x01000; } + bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + *value = address & 0xff; + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + *value = address & 0xffff; + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + switch (address) { + case 0x10008: *value = 0x98ecadc3; break; // saved %ebx + case 0x1000c: *value = 0x878f7524; break; // saved %esi + case 0x10010: *value = 0x6312f9a5; break; // saved %edi + case 0x10014: *value = 0x10038; break; // caller's %ebp + case 0x10018: *value = 0xf6438648; break; // return address + default: *value = 0xdeadbeef; break; // junk + } + return true; + } + bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + *value = address; + return true; + } + void Print() const { + assert(false); + } +}; + +// Verify that, for every association in ACTUAL, EXPECTED has the same +// association. (That is, ACTUAL's associations should be a subset of +// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and +// ".cfa". +static bool VerifyRegisters( + const char *file, int line, + const CFIFrameInfo::RegisterValueMap &expected, + const CFIFrameInfo::RegisterValueMap &actual) { + CFIFrameInfo::RegisterValueMap::const_iterator a; + a = actual.find(".cfa"); + if (a == actual.end()) + return false; + a = actual.find(".ra"); + if (a == actual.end()) + return false; + for (a = actual.begin(); a != actual.end(); a++) { + CFIFrameInfo::RegisterValueMap::const_iterator e = + expected.find(a->first); + if (e == expected.end()) { + fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n", + file, line, a->first.c_str(), a->second); + return false; + } + if (e->second != a->second) { + fprintf(stderr, + "%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n", + file, line, a->first.c_str(), a->second, e->second); + return false; + } + // Don't complain if this doesn't recover all registers. Although + // the DWARF spec says that unmentioned registers are undefined, + // GCC uses omission to mean that they are unchanged. + } + return true; +} + +static bool VerifyEmpty(const StackFrame &frame) { + if (frame.function_name.empty() && + frame.source_file_name.empty() && + frame.source_line == 0) + return true; + return false; +} + +static void ClearSourceLineInfo(StackFrame *frame) { + frame->function_name.clear(); + frame->module = NULL; + frame->source_file_name.clear(); + frame->source_line = 0; +} + +class TestFastSourceLineResolver : public ::testing::Test { + public: + void SetUp() { + testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata"; + } + + string symbol_file(int file_index) { + std::stringstream ss; + ss << testdata_dir << "/module" << file_index << ".out"; + return ss.str(); + } + + ModuleSerializer serializer; + BasicSourceLineResolver basic_resolver; + FastSourceLineResolver fast_resolver; + ModuleComparer module_comparer; + + string testdata_dir; +}; + +// Test adapted from basic_source_line_resolver_unittest. +TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { + TestCodeModule module1("module1"); + ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1))); + ASSERT_TRUE(basic_resolver.HasModule(&module1)); + // Convert module1 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule( + module1.code_file(), &basic_resolver, &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module1)); + + TestCodeModule module2("module2"); + ASSERT_TRUE(basic_resolver.LoadModule(&module2, symbol_file(2))); + ASSERT_TRUE(basic_resolver.HasModule(&module2)); + // Convert module2 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule( + module2.code_file(), &basic_resolver, &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module2)); + + StackFrame frame; + scoped_ptr windows_frame_info; + scoped_ptr cfi_frame_info; + frame.instruction = 0x1000; + frame.module = NULL; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_FALSE(frame.module); + ASSERT_TRUE(frame.function_name.empty()); + ASSERT_EQ(frame.function_base, 0U); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + ASSERT_EQ(frame.source_line_base, 0U); + + frame.module = &module1; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_1"); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module1"); + ASSERT_EQ(frame.function_base, 0x1000U); + ASSERT_EQ(frame.source_file_name, "file1_1.cc"); + ASSERT_EQ(frame.source_line, 44); + ASSERT_EQ(frame.source_line_base, 0x1000U); + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_EQ(windows_frame_info->program_string, + "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ ="); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x800; + frame.module = &module1; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_TRUE(VerifyEmpty(frame)); + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_FALSE(windows_frame_info.get()); + + frame.instruction = 0x1280; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_3"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_UNKNOWN); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_TRUE(windows_frame_info->program_string.empty()); + + frame.instruction = 0x1380; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function1_4"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); + ASSERT_FALSE(windows_frame_info->allocates_base_pointer); + ASSERT_FALSE(windows_frame_info->program_string.empty()); + + frame.instruction = 0x2000; + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_FALSE(windows_frame_info.get()); + + // module1 has STACK CFI records covering 3d40..3def; + // module2 has STACK CFI records covering 3df0..3e9f; + // check that FindCFIFrameInfo doesn't claim to find any outside those ranges. + frame.instruction = 0x3d3f; + frame.module = &module1; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + frame.instruction = 0x3e9f; + frame.module = &module1; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_FALSE(cfi_frame_info.get()); + + CFIFrameInfo::RegisterValueMap current_registers; + CFIFrameInfo::RegisterValueMap caller_registers; + CFIFrameInfo::RegisterValueMap expected_caller_registers; + MockMemoryRegion memory; + + // Regardless of which instruction evaluation takes place at, it + // should produce the same values for the caller's registers. + expected_caller_registers[".cfa"] = 0x1001c; + expected_caller_registers[".ra"] = 0xf6438648; + expected_caller_registers["$ebp"] = 0x10038; + expected_caller_registers["$ebx"] = 0x98ecadc3; + expected_caller_registers["$esi"] = 0x878f7524; + expected_caller_registers["$edi"] = 0x6312f9a5; + + frame.instruction = 0x3d40; + frame.module = &module1; + current_registers.clear(); + current_registers["$esp"] = 0x10018; + current_registers["$ebp"] = 0x10038; + current_registers["$ebx"] = 0x98ecadc3; + current_registers["$esi"] = 0x878f7524; + current_registers["$edi"] = 0x6312f9a5; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d41; + current_registers["$esp"] = 0x10014; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers)); + + frame.instruction = 0x3d43; + current_registers["$ebp"] = 0x10014; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d54; + current_registers["$ebx"] = 0x6864f054U; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d5a; + current_registers["$esi"] = 0x6285f79aU; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x3d84; + current_registers["$edi"] = 0x64061449U; + cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame)); + ASSERT_TRUE(cfi_frame_info.get()); + ASSERT_TRUE(cfi_frame_info.get() + ->FindCallerRegs(current_registers, memory, + &caller_registers)); + VerifyRegisters(__FILE__, __LINE__, + expected_caller_registers, caller_registers); + + frame.instruction = 0x2900; + frame.module = &module1; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, string("PublicSymbol")); + + frame.instruction = 0x4000; + frame.module = &module1; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, string("LargeFunction")); + + frame.instruction = 0x2181; + frame.module = &module2; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Function2_2"); + ASSERT_EQ(frame.function_base, 0x2170U); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module2"); + ASSERT_EQ(frame.source_file_name, "file2_2.cc"); + ASSERT_EQ(frame.source_line, 21); + ASSERT_EQ(frame.source_line_base, 0x2180U); + windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame)); + ASSERT_TRUE(windows_frame_info.get()); + ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA); + ASSERT_EQ(windows_frame_info->prolog_size, 1U); + + frame.instruction = 0x216f; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_1"); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x219f; + frame.module = &module2; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_TRUE(frame.function_name.empty()); + + frame.instruction = 0x21a0; + frame.module = &module2; + fast_resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_2"); +} + +TEST_F(TestFastSourceLineResolver, TestInvalidLoads) { + TestCodeModule module3("module3"); + ASSERT_TRUE(basic_resolver.LoadModule(&module3, + testdata_dir + "/module3_bad.out")); + ASSERT_TRUE(basic_resolver.HasModule(&module3)); + ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module3)); + // Convert module3 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule(module3.code_file(), + &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module3)); + ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module3)); + + TestCodeModule module4("module4"); + ASSERT_TRUE(basic_resolver.LoadModule(&module4, + testdata_dir + "/module4_bad.out")); + ASSERT_TRUE(basic_resolver.HasModule(&module4)); + ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module4)); + // Convert module4 to fast_module: + ASSERT_TRUE(serializer.ConvertOneModule(module4.code_file(), + &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module4)); + ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module4)); + + TestCodeModule module5("module5"); + ASSERT_FALSE(fast_resolver.LoadModule(&module5, + testdata_dir + "/invalid-filename")); + ASSERT_FALSE(fast_resolver.HasModule(&module5)); + + TestCodeModule invalidmodule("invalid-module"); + ASSERT_FALSE(fast_resolver.HasModule(&invalidmodule)); +} + +TEST_F(TestFastSourceLineResolver, TestUnload) { + TestCodeModule module1("module1"); + ASSERT_FALSE(basic_resolver.HasModule(&module1)); + + ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1))); + ASSERT_TRUE(basic_resolver.HasModule(&module1)); + // Convert module1 to fast_module. + ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(), + &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module1)); + basic_resolver.UnloadModule(&module1); + fast_resolver.UnloadModule(&module1); + ASSERT_FALSE(fast_resolver.HasModule(&module1)); + + ASSERT_TRUE(basic_resolver.LoadModule(&module1, symbol_file(1))); + ASSERT_TRUE(basic_resolver.HasModule(&module1)); + // Convert module1 to fast_module. + ASSERT_TRUE(serializer.ConvertOneModule(module1.code_file(), + &basic_resolver, + &fast_resolver)); + ASSERT_TRUE(fast_resolver.HasModule(&module1)); +} + +TEST_F(TestFastSourceLineResolver, CompareModule) { + char *symbol_data; + size_t symbol_data_size; + string symbol_data_string; + string filename; + + for (int module_index = 0; module_index < 3; ++module_index) { + std::stringstream ss; + ss << testdata_dir << "/module" << module_index << ".out"; + filename = ss.str(); + ASSERT_TRUE(SourceLineResolverBase::ReadSymbolFile( + symbol_file(module_index), &symbol_data, &symbol_data_size)); + symbol_data_string.assign(symbol_data, symbol_data_size); + delete [] symbol_data; + ASSERT_TRUE(module_comparer.Compare(symbol_data_string)); + } +} + +} // namespace + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/linked_ptr.h b/toolkit/crashreporter/google-breakpad/src/processor/linked_ptr.h new file mode 100644 index 0000000000..72fbba84a9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/linked_ptr.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(obj) vs linked_ptr(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. +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 +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 linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr 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() { + 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 + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + 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 void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace google_breakpad + +#endif // PROCESSOR_LINKED_PTR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/logging.cc b/toolkit/crashreporter/google-breakpad/src/processor/logging.cc new file mode 100644 index 0000000000..d59175a735 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/logging.cc @@ -0,0 +1,114 @@ +// 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.cc: Breakpad logging +// +// See logging.h for documentation. +// +// Author: Mark Mentovai + +#include +#include +#include +#include + +#include + +#include "common/stdio_wrapper.h" +#include "common/using_std_string.h" +#include "processor/logging.h" +#include "processor/pathname_stripper.h" + +namespace google_breakpad { + +LogStream::LogStream(std::ostream &stream, Severity severity, + const char *file, int line) + : stream_(stream) { + time_t clock; + time(&clock); + struct tm tm_struct; +#ifdef _WIN32 + localtime_s(&tm_struct, &clock); +#else + localtime_r(&clock, &tm_struct); +#endif + char time_string[20]; + strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", &tm_struct); + + const char *severity_string = "UNKNOWN_SEVERITY"; + switch (severity) { + case SEVERITY_INFO: + severity_string = "INFO"; + break; + case SEVERITY_ERROR: + severity_string = "ERROR"; + break; + case SEVERITY_CRITICAL: + severity_string = "CRITICAL"; + break; + } + + stream_ << time_string << ": " << PathnameStripper::File(file) << ":" << + line << ": " << severity_string << ": "; +} + +LogStream::~LogStream() { + stream_ << std::endl; +} + +string HexString(uint32_t number) { + char buffer[11]; + snprintf(buffer, sizeof(buffer), "0x%x", number); + return string(buffer); +} + +string HexString(uint64_t number) { + char buffer[19]; + snprintf(buffer, sizeof(buffer), "0x%" PRIx64, number); + return string(buffer); +} + +string HexString(int number) { + char buffer[19]; + snprintf(buffer, sizeof(buffer), "0x%x", number); + return string(buffer); +} + +int ErrnoString(string *error_string) { + assert(error_string); + + // strerror isn't necessarily thread-safe. strerror_r would be preferrable, + // but GNU libc uses a nonstandard strerror_r by default, which returns a + // char* (rather than an int success indicator) and doesn't necessarily + // use the supplied buffer. + error_string->assign(strerror(errno)); + return errno; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/logging.h b/toolkit/crashreporter/google-breakpad/src/processor/logging.h new file mode 100644 index 0000000000..43f3cfc951 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/logging.h @@ -0,0 +1,188 @@ +// 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 +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +#ifdef BP_LOGGING_INCLUDE +#include BP_LOGGING_INCLUDE +#endif // BP_LOGGING_INCLUDE + +namespace google_breakpad { + +// These are defined in Microsoft headers. +#ifdef SEVERITY_ERROR +#undef SEVERITY_ERROR +#endif + +#ifdef ERROR +#undef ERROR +#endif + +class LogStream { + public: + enum Severity { + SEVERITY_INFO, + SEVERITY_ERROR, + SEVERITY_CRITICAL + }; + + // 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 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". +string HexString(uint32_t number); +string HexString(uint64_t number); +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(string *error_string); + +} // namespace google_breakpad + +#ifndef BPLOG_INIT +#define BPLOG_INIT(pargc, pargv) +#endif // BPLOG_INIT + +#ifndef BPLOG_LAZY_STREAM +#define BPLOG_LAZY_STREAM(stream, condition) \ + !(condition) ? (void) 0 : \ + google_breakpad::LogMessageVoidify() & (BPLOG_ ## stream) +#endif + +#ifndef BPLOG_MINIMUM_SEVERITY +#define BPLOG_MINIMUM_SEVERITY SEVERITY_INFO +#endif + +#define BPLOG_LOG_IS_ON(severity) \ + ((google_breakpad::LogStream::SEVERITY_ ## severity) >= \ + (google_breakpad::LogStream::BPLOG_MINIMUM_SEVERITY)) + +#ifndef BPLOG +#define BPLOG(severity) BPLOG_LAZY_STREAM(severity, BPLOG_LOG_IS_ON(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 + +#ifndef BPLOG_CRITICAL +#ifndef BPLOG_CRITICAL_STREAM +#define BPLOG_CRITICAL_STREAM std::cerr +#endif // BPLOG_CRITICAL_STREAM +#define BPLOG_CRITICAL google_breakpad::LogStream(BPLOG_CRITICAL_STREAM, \ + google_breakpad::LogStream::SEVERITY_CRITICAL, \ + __FILE__, __LINE__) +#endif // BPLOG_CRITICAL + +#ifndef BPLOG_IF +#define BPLOG_IF(severity, condition) \ + BPLOG_LAZY_STREAM(severity, ((condition) && BPLOG_LOG_IS_ON(severity))) +#endif // BPLOG_IF + +#endif // PROCESSOR_LOGGING_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/map_serializers-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers-inl.h new file mode 100644 index 0000000000..61c7bbd7c8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers-inl.h @@ -0,0 +1,266 @@ +// Copyright (c) 2010, 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. +// +// map_serializers_inl.h: implementation for serializing std::map and its +// wrapper classes. +// +// See map_serializers.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_MAP_SERIALIZERS_INL_H__ +#define PROCESSOR_MAP_SERIALIZERS_INL_H__ + +#include +#include + +#include "processor/map_serializers.h" +#include "processor/simple_serializer.h" + +#include "processor/address_map-inl.h" +#include "processor/range_map-inl.h" +#include "processor/contained_range_map-inl.h" + +#include "processor/logging.h" + +namespace google_breakpad { + +template +size_t StdMapSerializer::SizeOf( + const std::map &m) const { + size_t size = 0; + size_t header_size = (1 + m.size()) * sizeof(uint32_t); + size += header_size; + + typename std::map::const_iterator iter; + for (iter = m.begin(); iter != m.end(); ++iter) { + size += key_serializer_.SizeOf(iter->first); + size += value_serializer_.SizeOf(iter->second); + } + return size; +} + +template +char *StdMapSerializer::Write(const std::map &m, + char *dest) const { + if (!dest) { + BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; + return NULL; + } + char *start_address = dest; + + // Write header: + // Number of nodes. + dest = SimpleSerializer::Write(m.size(), dest); + // Nodes offsets. + uint32_t *offsets = reinterpret_cast(dest); + dest += sizeof(uint32_t) * m.size(); + + char *key_address = dest; + dest += sizeof(Key) * m.size(); + + // Traverse map. + typename std::map::const_iterator iter; + int index = 0; + for (iter = m.begin(); iter != m.end(); ++iter, ++index) { + offsets[index] = static_cast(dest - start_address); + key_address = key_serializer_.Write(iter->first, key_address); + dest = value_serializer_.Write(iter->second, dest); + } + return dest; +} + +template +char *StdMapSerializer::Serialize( + const std::map &m, unsigned int *size) const { + // Compute size of memory to be allocated. + unsigned int size_to_alloc = SizeOf(m); + // Allocate memory. + char *serialized_data = new char[size_to_alloc]; + if (!serialized_data) { + BPLOG(INFO) << "StdMapSerializer memory allocation failed."; + if (size) *size = 0; + return NULL; + } + // Write serialized data into memory. + Write(m, serialized_data); + + if (size) *size = size_to_alloc; + return serialized_data; +} + +template +size_t RangeMapSerializer::SizeOf( + const RangeMap &m) const { + size_t size = 0; + size_t header_size = (1 + m.map_.size()) * sizeof(uint32_t); + size += header_size; + + typename std::map::const_iterator iter; + for (iter = m.map_.begin(); iter != m.map_.end(); ++iter) { + // Size of key (high address). + size += address_serializer_.SizeOf(iter->first); + // Size of base (low address). + size += address_serializer_.SizeOf(iter->second.base()); + // Size of entry. + size += entry_serializer_.SizeOf(iter->second.entry()); + } + return size; +} + +template +char *RangeMapSerializer::Write( + const RangeMap &m, char *dest) const { + if (!dest) { + BPLOG(ERROR) << "RangeMapSerializer failed: write to NULL address."; + return NULL; + } + char *start_address = dest; + + // Write header: + // Number of nodes. + dest = SimpleSerializer::Write(m.map_.size(), dest); + // Nodes offsets. + uint32_t *offsets = reinterpret_cast(dest); + dest += sizeof(uint32_t) * m.map_.size(); + + char *key_address = dest; + dest += sizeof(Address) * m.map_.size(); + + // Traverse map. + typename std::map::const_iterator iter; + int index = 0; + for (iter = m.map_.begin(); iter != m.map_.end(); ++iter, ++index) { + offsets[index] = static_cast(dest - start_address); + key_address = address_serializer_.Write(iter->first, key_address); + dest = address_serializer_.Write(iter->second.base(), dest); + dest = entry_serializer_.Write(iter->second.entry(), dest); + } + return dest; +} + +template +char *RangeMapSerializer::Serialize( + const RangeMap &m, unsigned int *size) const { + // Compute size of memory to be allocated. + unsigned int size_to_alloc = SizeOf(m); + // Allocate memory. + char *serialized_data = new char[size_to_alloc]; + if (!serialized_data) { + BPLOG(INFO) << "RangeMapSerializer memory allocation failed."; + if (size) *size = 0; + return NULL; + } + + // Write serialized data into memory. + Write(m, serialized_data); + + if (size) *size = size_to_alloc; + return serialized_data; +} + + +template +size_t ContainedRangeMapSerializer::SizeOf( + const ContainedRangeMap *m) const { + size_t size = 0; + size_t header_size = addr_serializer_.SizeOf(m->base_) + + entry_serializer_.SizeOf(m->entry_) + + sizeof(uint32_t); + size += header_size; + // In case m.map_ == NULL, we treat it as an empty map: + size += sizeof(uint32_t); + if (m->map_) { + size += m->map_->size() * sizeof(uint32_t); + typename Map::const_iterator iter; + for (iter = m->map_->begin(); iter != m->map_->end(); ++iter) { + size += addr_serializer_.SizeOf(iter->first); + // Recursive calculation of size: + size += SizeOf(iter->second); + } + } + return size; +} + +template +char *ContainedRangeMapSerializer::Write( + const ContainedRangeMap *m, char *dest) const { + if (!dest) { + BPLOG(ERROR) << "StdMapSerializer failed: write to NULL address."; + return NULL; + } + dest = addr_serializer_.Write(m->base_, dest); + dest = SimpleSerializer::Write(entry_serializer_.SizeOf(m->entry_), + dest); + dest = entry_serializer_.Write(m->entry_, dest); + + // Write map<: + char *map_address = dest; + if (m->map_ == NULL) { + dest = SimpleSerializer::Write(0, dest); + } else { + dest = SimpleSerializer::Write(m->map_->size(), dest); + uint32_t *offsets = reinterpret_cast(dest); + dest += sizeof(uint32_t) * m->map_->size(); + + char *key_address = dest; + dest += sizeof(AddrType) * m->map_->size(); + + // Traverse map. + typename Map::const_iterator iter; + int index = 0; + for (iter = m->map_->begin(); iter != m->map_->end(); ++iter, ++index) { + offsets[index] = static_cast(dest - map_address); + key_address = addr_serializer_.Write(iter->first, key_address); + // Recursively write. + dest = Write(iter->second, dest); + } + } + return dest; +} + +template +char *ContainedRangeMapSerializer::Serialize( + const ContainedRangeMap *m, unsigned int *size) const { + unsigned int size_to_alloc = SizeOf(m); + // Allocating memory. + char *serialized_data = new char[size_to_alloc]; + if (!serialized_data) { + BPLOG(INFO) << "ContainedRangeMapSerializer memory allocation failed."; + if (size) *size = 0; + return NULL; + } + Write(m, serialized_data); + if (size) *size = size_to_alloc; + return serialized_data; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_MAP_SERIALIZERS_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/map_serializers.h b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers.h new file mode 100644 index 0000000000..a0b9d3fd67 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers.h @@ -0,0 +1,168 @@ +// Copyright (c) 2010, 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. +// +// map_serializers.h: defines templates for serializing std::map and its +// wrappers: AddressMap, RangeMap, and ContainedRangeMap. +// +// Author: Siyang Xie (lambxsy@google.com) + + +#ifndef PROCESSOR_MAP_SERIALIZERS_H__ +#define PROCESSOR_MAP_SERIALIZERS_H__ + +#include +#include + +#include "processor/simple_serializer.h" + +#include "processor/address_map-inl.h" +#include "processor/range_map-inl.h" +#include "processor/contained_range_map-inl.h" + +namespace google_breakpad { + +// StdMapSerializer allocates memory and serializes an std::map instance into a +// chunk of memory data. +template +class StdMapSerializer { + public: + // Calculate the memory size of serialized data. + size_t SizeOf(const std::map &m) const; + + // Writes the serialized data to memory with start address = dest, + // and returns the "end" of data, i.e., return the address follow the final + // byte of data. + // NOTE: caller has to allocate enough memory before invoke Write() method. + char* Write(const std::map &m, char* dest) const; + + // Serializes a std::map object into a chunk of memory data with format + // described in "StaticMap.h" comment. + // Returns a pointer to the serialized data. If size != NULL, *size is set + // to the size of serialized data, i.e., SizeOf(m). + // Caller has the ownership of memory allocated as "new char[]". + char* Serialize(const std::map &m, unsigned int *size) const; + + private: + SimpleSerializer key_serializer_; + SimpleSerializer value_serializer_; +}; + +// AddressMapSerializer allocates memory and serializes an AddressMap into a +// chunk of memory data. +template +class AddressMapSerializer { + public: + // Calculate the memory size of serialized data. + size_t SizeOf(const AddressMap &m) const { + return std_map_serializer_.SizeOf(m.map_); + } + + // Write the serialized data to specified memory location. Return the "end" + // of data, i.e., return the address after the final byte of data. + // NOTE: caller has to allocate enough memory before invoke Write() method. + char* Write(const AddressMap &m, char *dest) const { + return std_map_serializer_.Write(m.map_, dest); + } + + // Serializes an AddressMap object into a chunk of memory data. + // Returns a pointer to the serialized data. If size != NULL, *size is set + // to the size of serialized data, i.e., SizeOf(m). + // Caller has the ownership of memory allocated as "new char[]". + char* Serialize(const AddressMap &m, unsigned int *size) const { + return std_map_serializer_.Serialize(m.map_, size); + } + + private: + // AddressMapSerializer is a simple wrapper of StdMapSerializer, just as + // AddressMap is a simple wrapper of std::map. + StdMapSerializer std_map_serializer_; +}; + +// RangeMapSerializer allocates memory and serializes a RangeMap instance into a +// chunk of memory data. +template +class RangeMapSerializer { + public: + // Calculate the memory size of serialized data. + size_t SizeOf(const RangeMap &m) const; + + // Write the serialized data to specified memory location. Return the "end" + // of data, i.e., return the address after the final byte of data. + // NOTE: caller has to allocate enough memory before invoke Write() method. + char* Write(const RangeMap &m, char* dest) const; + + // Serializes a RangeMap object into a chunk of memory data. + // Returns a pointer to the serialized data. If size != NULL, *size is set + // to the size of serialized data, i.e., SizeOf(m). + // Caller has the ownership of memory allocated as "new char[]". + char* Serialize(const RangeMap &m, unsigned int *size) const; + + private: + // Convenient type name for Range. + typedef typename RangeMap::Range Range; + + // Serializer for RangeMap's key and Range::base_. + SimpleSerializer
address_serializer_; + // Serializer for RangeMap::Range::entry_. + SimpleSerializer entry_serializer_; +}; + +// ContainedRangeMapSerializer allocates memory and serializes a +// ContainedRangeMap instance into a chunk of memory data. +template +class ContainedRangeMapSerializer { + public: + // Calculate the memory size of serialized data. + size_t SizeOf(const ContainedRangeMap *m) const; + + // Write the serialized data to specified memory location. Return the "end" + // of data, i.e., return the address after the final byte of data. + // NOTE: caller has to allocate enough memory before invoke Write() method. + char* Write(const ContainedRangeMap *m, + char* dest) const; + + // Serializes a ContainedRangeMap object into a chunk of memory data. + // Returns a pointer to the serialized data. If size != NULL, *size is set + // to the size of serialized data, i.e., SizeOf(m). + // Caller has the ownership of memory allocated as "new char[]". + char* Serialize(const ContainedRangeMap *m, + unsigned int *size) const; + + private: + // Convenient type name for the underlying map type. + typedef std::map*> Map; + + // Serializer for addresses and entries stored in ContainedRangeMap. + SimpleSerializer addr_serializer_; + SimpleSerializer entry_serializer_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_MAP_SERIALIZERS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/map_serializers_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers_unittest.cc new file mode 100644 index 0000000000..0d872ec2e2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/map_serializers_unittest.cc @@ -0,0 +1,386 @@ +// Copyright (c) 2010, 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. + +// map_serializers_unittest.cc: Unit tests for std::map serializer and +// std::map wrapper serializers. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "map_serializers-inl.h" + +#include "processor/address_map-inl.h" +#include "processor/range_map-inl.h" +#include "processor/contained_range_map-inl.h" + +typedef int32_t AddrType; +typedef int32_t EntryType; + +class TestStdMapSerializer : public ::testing::Test { + protected: + void SetUp() { + serialized_size_ = 0; + serialized_data_ = NULL; + } + + void TearDown() { + delete [] serialized_data_; + } + + std::map std_map_; + google_breakpad::StdMapSerializer serializer_; + uint32_t serialized_size_; + char *serialized_data_; +}; + +TEST_F(TestStdMapSerializer, EmptyMapTestCase) { + const int32_t correct_data[] = { 0 }; + uint32_t correct_size = sizeof(correct_data); + + // std_map_ is empty. + serialized_data_ = serializer_.Serialize(std_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestStdMapSerializer, MapWithTwoElementsTestCase) { + const int32_t correct_data[] = { + // # of nodes + 2, + // Offsets + 20, 24, + // Keys + 1, 3, + // Values + 2, 6 + }; + uint32_t correct_size = sizeof(correct_data); + + std_map_.insert(std::make_pair(1, 2)); + std_map_.insert(std::make_pair(3, 6)); + + serialized_data_ = serializer_.Serialize(std_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestStdMapSerializer, MapWithFiveElementsTestCase) { + const int32_t correct_data[] = { + // # of nodes + 5, + // Offsets + 44, 48, 52, 56, 60, + // Keys + 1, 2, 3, 4, 5, + // Values + 11, 12, 13, 14, 15 + }; + uint32_t correct_size = sizeof(correct_data); + + for (int i = 1; i < 6; ++i) + std_map_.insert(std::make_pair(i, 10 + i)); + + serialized_data_ = serializer_.Serialize(std_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +class TestAddressMapSerializer : public ::testing::Test { + protected: + void SetUp() { + serialized_size_ = 0; + serialized_data_ = 0; + } + + void TearDown() { + delete [] serialized_data_; + } + + google_breakpad::AddressMap address_map_; + google_breakpad::AddressMapSerializer serializer_; + uint32_t serialized_size_; + char *serialized_data_; +}; + +TEST_F(TestAddressMapSerializer, EmptyMapTestCase) { + const int32_t correct_data[] = { 0 }; + uint32_t correct_size = sizeof(correct_data); + + // std_map_ is empty. + serialized_data_ = serializer_.Serialize(address_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestAddressMapSerializer, MapWithTwoElementsTestCase) { + const int32_t correct_data[] = { + // # of nodes + 2, + // Offsets + 20, 24, + // Keys + 1, 3, + // Values + 2, 6 + }; + uint32_t correct_size = sizeof(correct_data); + + address_map_.Store(1, 2); + address_map_.Store(3, 6); + + serialized_data_ = serializer_.Serialize(address_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestAddressMapSerializer, MapWithFourElementsTestCase) { + const int32_t correct_data[] = { + // # of nodes + 4, + // Offsets + 36, 40, 44, 48, + // Keys + -6, -4, 8, 123, + // Values + 2, 3, 5, 8 + }; + uint32_t correct_size = sizeof(correct_data); + + address_map_.Store(-6, 2); + address_map_.Store(-4, 3); + address_map_.Store(8, 5); + address_map_.Store(123, 8); + + serialized_data_ = serializer_.Serialize(address_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + + +class TestRangeMapSerializer : public ::testing::Test { + protected: + void SetUp() { + serialized_size_ = 0; + serialized_data_ = 0; + } + + void TearDown() { + delete [] serialized_data_; + } + + google_breakpad::RangeMap range_map_; + google_breakpad::RangeMapSerializer serializer_; + uint32_t serialized_size_; + char *serialized_data_; +}; + +TEST_F(TestRangeMapSerializer, EmptyMapTestCase) { + const int32_t correct_data[] = { 0 }; + uint32_t correct_size = sizeof(correct_data); + + // range_map_ is empty. + serialized_data_ = serializer_.Serialize(range_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestRangeMapSerializer, MapWithOneRangeTestCase) { + const int32_t correct_data[] = { + // # of nodes + 1, + // Offsets + 12, + // Keys: high address + 10, + // Values: (low address, entry) pairs + 1, 6 + }; + uint32_t correct_size = sizeof(correct_data); + + range_map_.StoreRange(1, 10, 6); + + serialized_data_ = serializer_.Serialize(range_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestRangeMapSerializer, MapWithThreeRangesTestCase) { + const int32_t correct_data[] = { + // # of nodes + 3, + // Offsets + 28, 36, 44, + // Keys: high address + 5, 9, 20, + // Values: (low address, entry) pairs + 2, 1, 6, 2, 10, 3 + }; + uint32_t correct_size = sizeof(correct_data); + + ASSERT_TRUE(range_map_.StoreRange(2, 4, 1)); + ASSERT_TRUE(range_map_.StoreRange(6, 4, 2)); + ASSERT_TRUE(range_map_.StoreRange(10, 11, 3)); + + serialized_data_ = serializer_.Serialize(range_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + + +class TestContainedRangeMapSerializer : public ::testing::Test { + protected: + void SetUp() { + serialized_size_ = 0; + serialized_data_ = 0; + } + + void TearDown() { + delete [] serialized_data_; + } + + google_breakpad::ContainedRangeMap crm_map_; + google_breakpad::ContainedRangeMapSerializer serializer_; + uint32_t serialized_size_; + char *serialized_data_; +}; + +TEST_F(TestContainedRangeMapSerializer, EmptyMapTestCase) { + const int32_t correct_data[] = { + 0, // base address of root + 4, // size of entry + 0, // entry stored at root + 0 // empty map stored at root + }; + uint32_t correct_size = sizeof(correct_data); + + // crm_map_ is empty. + serialized_data_ = serializer_.Serialize(&crm_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestContainedRangeMapSerializer, MapWithOneRangeTestCase) { + const int32_t correct_data[] = { + 0, // base address of root + 4, // size of entry + 0, // entry stored at root + // Map stored at root node: + 1, // # of nodes + 12, // offset + 9, // key + // value: a child ContainedRangeMap + 3, // base address of child CRM + 4, // size of entry + -1, // entry stored in child CRM + 0 // empty sub-map stored in child CRM + }; + uint32_t correct_size = sizeof(correct_data); + + crm_map_.StoreRange(3, 7, -1); + + serialized_data_ = serializer_.Serialize(&crm_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + +TEST_F(TestContainedRangeMapSerializer, MapWithTwoLevelsTestCase) { + // Tree structure of ranges: + // root level 0 + // | + // map + // / \ level 1: child1, child2 + // 2~8 10~20 + // | | + // map map + // / \ | + // 3~4 6~7 16-20 level 2: grandchild1, grandchild2, grandchild3 + + const int32_t correct_data[] = { + // root: base, entry_size, entry + 0, 4, 0, + // root's map: # of nodes, offset1, offset2, key1, key2 + 2, 20, 84, 8, 20, + // child1: base, entry_size, entry: + 2, 4, -1, + // child1's map: # of nodes, offset1, offset2, key1, key2 + 2, 20, 36, 4, 7, + // grandchild1: base, entry_size, entry, empty_map + 3, 4, -1, 0, + // grandchild2: base, entry_size, entry, empty_map + 6, 4, -1, 0, + // child2: base, entry_size, entry: + 10, 4, -1, + // child2's map: # of nodes, offset1, key1 + 1, 12, 20, + // grandchild3: base, entry_size, entry, empty_map + 16, 4, -1, 0 + }; + uint32_t correct_size = sizeof(correct_data); + + // Store child1. + ASSERT_TRUE(crm_map_.StoreRange(2, 7, -1)); + // Store child2. + ASSERT_TRUE(crm_map_.StoreRange(10, 11, -1)); + // Store grandchild1. + ASSERT_TRUE(crm_map_.StoreRange(3, 2, -1)); + // Store grandchild2. + ASSERT_TRUE(crm_map_.StoreRange(6, 2, -1)); + // Store grandchild3. + ASSERT_TRUE(crm_map_.StoreRange(16, 5, -1)); + + serialized_data_ = serializer_.Serialize(&crm_map_, &serialized_size_); + + EXPECT_EQ(correct_size, serialized_size_); + EXPECT_EQ(memcmp(correct_data, serialized_data_, correct_size), 0); +} + + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump.cc b/toolkit/crashreporter/google-breakpad/src/processor/microdump.cc new file mode 100644 index 0000000000..d8141a2a8f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump.cc @@ -0,0 +1,405 @@ +// Copyright (c) 2014 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. + +// microdump.cc: A microdump reader. +// +// See microdump.h for documentation. + +#include "google_breakpad/processor/microdump.h" + +#include +#include + +#include +#include +#include +#include + +#include "google_breakpad/common/minidump_cpu_arm.h" +#include "google_breakpad/processor/code_module.h" +#include "processor/basic_code_module.h" +#include "processor/convert_old_arm64_context.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" +#include "processor/range_map-inl.h" + +namespace { +static const char kGoogleBreakpadKey[] = "google-breakpad"; +static const char kMicrodumpBegin[] = "-----BEGIN BREAKPAD MICRODUMP-----"; +static const char kMicrodumpEnd[] = "-----END BREAKPAD MICRODUMP-----"; +static const char kOsKey[] = ": O "; +static const char kCpuKey[] = ": C "; +static const char kCrashReasonKey[] = ": R "; +static const char kGpuKey[] = ": G "; +static const char kMmapKey[] = ": M "; +static const char kStackKey[] = ": S "; +static const char kStackFirstLineKey[] = ": S 0 "; +static const char kArmArchitecture[] = "arm"; +static const char kArm64Architecture[] = "arm64"; +static const char kX86Architecture[] = "x86"; +static const char kMipsArchitecture[] = "mips"; +static const char kMips64Architecture[] = "mips64"; +static const char kGpuUnknown[] = "UNKNOWN"; + +template +T HexStrToL(const string& str) { + uint64_t res = 0; + std::istringstream ss(str); + ss >> std::hex >> res; + return static_cast(res); +} + +std::vector ParseHexBuf(const string& str) { + std::vector buf; + for (size_t i = 0; i < str.length(); i += 2) { + buf.push_back(HexStrToL(str.substr(i, 2))); + } + return buf; +} + +bool GetLine(std::istringstream* istream, string* str) { + if (std::getline(*istream, *str)) { + // Trim any trailing newline from the end of the line. Allows us + // to seamlessly handle both Windows/DOS and Unix formatted input. The + // adb tool generally writes logcat dumps in Windows/DOS format. + if (!str->empty() && str->at(str->size() - 1) == '\r') { + str->erase(str->size() - 1); + } + return true; + } + return false; +} + +} // namespace + +namespace google_breakpad { + +// +// MicrodumpModules +// + +void MicrodumpModules::Add(const CodeModule* module) { + linked_ptr module_ptr(module); + if (!map_.StoreRange(module->base_address(), module->size(), module_ptr)) { + BPLOG(ERROR) << "Module " << module->code_file() << + " could not be stored"; + } +} + +void MicrodumpModules::SetEnableModuleShrink(bool is_enabled) { + map_.SetMergeStrategy(is_enabled ? MergeRangeStrategy::kTruncateUpper + : MergeRangeStrategy::kExclusiveRanges); +} + +// +// MicrodumpContext +// + +void MicrodumpContext::SetContextARM(MDRawContextARM* arm) { + DumpContext::SetContextFlags(MD_CONTEXT_ARM); + DumpContext::SetContextARM(arm); + valid_ = true; +} + +void MicrodumpContext::SetContextARM64(MDRawContextARM64* arm64) { + DumpContext::SetContextFlags(MD_CONTEXT_ARM64); + DumpContext::SetContextARM64(arm64); + valid_ = true; +} + +void MicrodumpContext::SetContextX86(MDRawContextX86* x86) { + DumpContext::SetContextFlags(MD_CONTEXT_X86); + DumpContext::SetContextX86(x86); + valid_ = true; +} + +void MicrodumpContext::SetContextMIPS(MDRawContextMIPS* mips32) { + DumpContext::SetContextFlags(MD_CONTEXT_MIPS); + DumpContext::SetContextMIPS(mips32); + valid_ = true; +} + +void MicrodumpContext::SetContextMIPS64(MDRawContextMIPS* mips64) { + DumpContext::SetContextFlags(MD_CONTEXT_MIPS64); + DumpContext::SetContextMIPS(mips64); + valid_ = true; +} + + +// +// MicrodumpMemoryRegion +// + +MicrodumpMemoryRegion::MicrodumpMemoryRegion() : base_address_(0) { } + +void MicrodumpMemoryRegion::Init(uint64_t base_address, + const std::vector& contents) { + base_address_ = base_address; + contents_ = contents; +} + +uint64_t MicrodumpMemoryRegion::GetBase() const { return base_address_; } + +uint32_t MicrodumpMemoryRegion::GetSize() const { return contents_.size(); } + +bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint8_t* value) const { + return GetMemoryLittleEndian(address, value); +} + +bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint16_t* value) const { + return GetMemoryLittleEndian(address, value); +} + +bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint32_t* value) const { + return GetMemoryLittleEndian(address, value); +} + +bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint64_t* value) const { + return GetMemoryLittleEndian(address, value); +} + +template +bool MicrodumpMemoryRegion::GetMemoryLittleEndian(uint64_t address, + ValueType* value) const { + if (address < base_address_ || + address - base_address_ + sizeof(ValueType) > contents_.size()) + return false; + ValueType v = 0; + uint64_t start = address - base_address_; + // The loop condition is odd, but it's correct for size_t. + for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--) + v = (v << 8) | static_cast(contents_[start + i]); + *value = v; + return true; +} + +void MicrodumpMemoryRegion::Print() const { + // Not reached, just needed to honor the base class contract. + assert(false); +} + +// +// Microdump +// +Microdump::Microdump(const string& contents) + : context_(new MicrodumpContext()), + stack_region_(new MicrodumpMemoryRegion()), + modules_(new MicrodumpModules()), + system_info_(new SystemInfo()), + crash_reason_(), + crash_address_(0u) { + assert(!contents.empty()); + + bool in_microdump = false; + string line; + uint64_t stack_start = 0; + std::vector stack_content; + string arch; + + std::istringstream stream(contents); + while (GetLine(&stream, &line)) { + if (line.find(kGoogleBreakpadKey) == string::npos) { + continue; + } + if (line.find(kMicrodumpBegin) != string::npos) { + in_microdump = true; + continue; + } + if (!in_microdump) { + continue; + } + if (line.find(kMicrodumpEnd) != string::npos) { + break; + } + + size_t pos; + if ((pos = line.find(kOsKey)) != string::npos) { + string os_str(line, pos + strlen(kOsKey)); + std::istringstream os_tokens(os_str); + string os_id; + string num_cpus; + string os_version; + // This reflect the actual HW arch and might not match the arch emulated + // for the execution (e.g., running a 32-bit binary on a 64-bit cpu). + string hw_arch; + + os_tokens >> os_id; + os_tokens >> arch; + os_tokens >> num_cpus; + os_tokens >> hw_arch; + GetLine(&os_tokens, &os_version); + os_version.erase(0, 1); // remove leading space. + + system_info_->cpu = arch; + system_info_->cpu_count = HexStrToL(num_cpus); + system_info_->os_version = os_version; + + if (os_id == "L") { + system_info_->os = "Linux"; + system_info_->os_short = "linux"; + } else if (os_id == "A") { + system_info_->os = "Android"; + system_info_->os_short = "android"; + modules_->SetEnableModuleShrink(true); + } + + // OS line also contains release and version for future use. + } else if ((pos = line.find(kStackKey)) != string::npos) { + if (line.find(kStackFirstLineKey) != string::npos) { + // The first line of the stack (S 0 stack header) provides the value of + // the stack pointer, the start address of the stack being dumped and + // the length of the stack. We could use it in future to double check + // that we received all the stack as expected. + continue; + } + string stack_str(line, pos + strlen(kStackKey)); + std::istringstream stack_tokens(stack_str); + string start_addr_str; + string raw_content; + stack_tokens >> start_addr_str; + stack_tokens >> raw_content; + uint64_t start_addr = HexStrToL(start_addr_str); + + if (stack_start != 0) { + // Verify that the stack chunks in the microdump are contiguous. + assert(start_addr == stack_start + stack_content.size()); + } else { + stack_start = start_addr; + } + std::vector chunk = ParseHexBuf(raw_content); + stack_content.insert(stack_content.end(), chunk.begin(), chunk.end()); + + } else if ((pos = line.find(kCpuKey)) != string::npos) { + string cpu_state_str(line, pos + strlen(kCpuKey)); + std::vector cpu_state_raw = ParseHexBuf(cpu_state_str); + if (strcmp(arch.c_str(), kArmArchitecture) == 0) { + if (cpu_state_raw.size() != sizeof(MDRawContextARM)) { + std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() + << " bytes instead of " << sizeof(MDRawContextARM) + << std::endl; + continue; + } + MDRawContextARM* arm = new MDRawContextARM(); + memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextARM(arm); + } else if (strcmp(arch.c_str(), kArm64Architecture) == 0) { + if (cpu_state_raw.size() == sizeof(MDRawContextARM64)) { + MDRawContextARM64* arm = new MDRawContextARM64(); + memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextARM64(arm); + } else if (cpu_state_raw.size() == sizeof(MDRawContextARM64_Old)) { + MDRawContextARM64_Old old_arm; + memcpy(&old_arm, &cpu_state_raw[0], cpu_state_raw.size()); + MDRawContextARM64* new_arm = new MDRawContextARM64(); + ConvertOldARM64Context(old_arm, new_arm); + context_->SetContextARM64(new_arm); + } else { + std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() + << " bytes instead of " << sizeof(MDRawContextARM64) + << std::endl; + continue; + } + } else if (strcmp(arch.c_str(), kX86Architecture) == 0) { + if (cpu_state_raw.size() != sizeof(MDRawContextX86)) { + std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() + << " bytes instead of " << sizeof(MDRawContextX86) + << std::endl; + continue; + } + MDRawContextX86* x86 = new MDRawContextX86(); + memcpy(x86, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextX86(x86); + } else if (strcmp(arch.c_str(), kMipsArchitecture) == 0) { + if (cpu_state_raw.size() != sizeof(MDRawContextMIPS)) { + std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() + << " bytes instead of " << sizeof(MDRawContextMIPS) + << std::endl; + continue; + } + MDRawContextMIPS* mips32 = new MDRawContextMIPS(); + memcpy(mips32, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextMIPS(mips32); + } else if (strcmp(arch.c_str(), kMips64Architecture) == 0) { + if (cpu_state_raw.size() != sizeof(MDRawContextMIPS)) { + std::cerr << "Malformed CPU context. Got " << cpu_state_raw.size() + << " bytes instead of " << sizeof(MDRawContextMIPS) + << std::endl; + continue; + } + MDRawContextMIPS* mips64 = new MDRawContextMIPS(); + memcpy(mips64, &cpu_state_raw[0], cpu_state_raw.size()); + context_->SetContextMIPS64(mips64); + } else { + std::cerr << "Unsupported architecture: " << arch << std::endl; + } + } else if ((pos = line.find(kCrashReasonKey)) != string::npos) { + string crash_reason_str(line, pos + strlen(kCrashReasonKey)); + std::istringstream crash_reason_tokens(crash_reason_str); + string signal; + string address; + crash_reason_tokens >> signal; + crash_reason_tokens >> crash_reason_; + crash_reason_tokens >> address; + crash_address_ = HexStrToL(address); + } else if ((pos = line.find(kGpuKey)) != string::npos) { + string gpu_str(line, pos + strlen(kGpuKey)); + if (strcmp(gpu_str.c_str(), kGpuUnknown) != 0) { + std::istringstream gpu_tokens(gpu_str); + std::getline(gpu_tokens, system_info_->gl_version, '|'); + std::getline(gpu_tokens, system_info_->gl_vendor, '|'); + std::getline(gpu_tokens, system_info_->gl_renderer, '|'); + } + } else if ((pos = line.find(kMmapKey)) != string::npos) { + string mmap_line(line, pos + strlen(kMmapKey)); + std::istringstream mmap_tokens(mmap_line); + string addr, offset, size, identifier, filename; + mmap_tokens >> addr; + mmap_tokens >> offset; + mmap_tokens >> size; + mmap_tokens >> identifier; + mmap_tokens >> filename; + + modules_->Add(new BasicCodeModule( + HexStrToL(addr), // base_address + HexStrToL(size), // size + filename, // code_file + identifier, // code_identifier + filename, // debug_file + identifier, // debug_identifier + "")); // version + } + } + stack_region_->Init(stack_start, stack_content); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor.cc b/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor.cc new file mode 100644 index 0000000000..2d3a9558a6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2014, 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. + +// microdump_processor.cc: A microdump processor. +// +// See microdump_processor.h for documentation. + +#include "google_breakpad/processor/microdump_processor.h" + +#include + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/microdump.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stackwalker.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "processor/logging.h" + +namespace google_breakpad { + +MicrodumpProcessor::MicrodumpProcessor(StackFrameSymbolizer* frame_symbolizer) + : frame_symbolizer_(frame_symbolizer) { + assert(frame_symbolizer); +} + +MicrodumpProcessor::~MicrodumpProcessor() {} + +ProcessResult MicrodumpProcessor::Process(Microdump *microdump, + ProcessState* process_state) { + assert(process_state); + + process_state->Clear(); + + process_state->modules_ = microdump->GetModules()->Copy(); + scoped_ptr stackwalker( + Stackwalker::StackwalkerForCPU( + &process_state->system_info_, + microdump->GetContext(), + microdump->GetMemory(), + process_state->modules_, + /* unloaded_modules= */ NULL, + frame_symbolizer_)); + + scoped_ptr stack(new CallStack()); + if (stackwalker.get()) { + if (!stackwalker->Walk(stack.get(), + &process_state->modules_without_symbols_, + &process_state->modules_with_corrupt_symbols_)) { + BPLOG(INFO) << "Processing was interrupted."; + return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; + } + } else { + BPLOG(ERROR) << "No stackwalker found for microdump."; + return PROCESS_ERROR_NO_THREAD_LIST; + } + + process_state->threads_.push_back(stack.release()); + process_state->thread_memory_regions_.push_back(microdump->GetMemory()); + process_state->crashed_ = true; + process_state->requesting_thread_ = 0; + process_state->system_info_ = *microdump->GetSystemInfo(); + process_state->crash_reason_ = microdump->GetCrashReason(); + process_state->crash_address_ = microdump->GetCrashAddress(); + + return PROCESS_OK; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor_unittest.cc new file mode 100644 index 0000000000..83bdef9524 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_processor_unittest.cc @@ -0,0 +1,285 @@ +// Copyright (c) 2014, 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. + +// Unit test for MicrodumpProcessor. + +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/microdump.h" +#include "google_breakpad/processor/microdump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "processor/simple_symbol_supplier.h" +#include "processor/stackwalker_unittest_utils.h" + +namespace { + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::Microdump; +using google_breakpad::MicrodumpProcessor; +using google_breakpad::ProcessState; +using google_breakpad::SimpleSymbolSupplier; +using google_breakpad::StackFrameSymbolizer; + +class MicrodumpProcessorTest : public ::testing::Test { + public: + MicrodumpProcessorTest() + : files_path_(string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata/") { + } + + void ReadFile(const string& file_name, string* file_contents) { + assert(file_contents); + std::ifstream file_stream(file_name.c_str(), std::ios::in); + ASSERT_TRUE(file_stream.good()); + std::vector bytes; + file_stream.seekg(0, std::ios_base::end); + ASSERT_TRUE(file_stream.good()); + bytes.resize(file_stream.tellg()); + file_stream.seekg(0, std::ios_base::beg); + ASSERT_TRUE(file_stream.good()); + file_stream.read(&bytes[0], bytes.size()); + ASSERT_TRUE(file_stream.good()); + *file_contents = string(&bytes[0], bytes.size()); + } + + google_breakpad::ProcessResult ProcessMicrodump( + const string& symbols_file, + const string& microdump_contents, + ProcessState* state) { + SimpleSymbolSupplier supplier(symbols_file); + BasicSourceLineResolver resolver; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + MicrodumpProcessor processor(&frame_symbolizer); + + Microdump microdump(microdump_contents); + return processor.Process(µdump, state); + } + + void AnalyzeDump(const string& microdump_file_name, bool omit_symbols, + int expected_cpu_count, ProcessState* state) { + string symbols_file = omit_symbols ? "" : files_path_ + "symbols/microdump"; + string microdump_file_path = files_path_ + microdump_file_name; + string microdump_contents; + ReadFile(microdump_file_path, µdump_contents); + + google_breakpad::ProcessResult result = + ProcessMicrodump(symbols_file, microdump_contents, state); + + ASSERT_EQ(google_breakpad::PROCESS_OK, result); + ASSERT_TRUE(state->crashed()); + ASSERT_EQ(0, state->requesting_thread()); + ASSERT_EQ(1U, state->threads()->size()); + + ASSERT_EQ(expected_cpu_count, state->system_info()->cpu_count); + ASSERT_EQ("android", state->system_info()->os_short); + ASSERT_EQ("Android", state->system_info()->os); + } + + string files_path_; +}; + +TEST_F(MicrodumpProcessorTest, TestProcess_Invalid) { + ProcessState state; + google_breakpad::ProcessResult result = + ProcessMicrodump("", "This is not a valid microdump", &state); + ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result); +} + +TEST_F(MicrodumpProcessorTest, TestProcess_WithoutCrashReason) { + ProcessState state; + AnalyzeDump("microdump-arm64.dmp", true /* omit_symbols */, + 2 /* expected_cpu_count */, &state); + ASSERT_EQ(state.crash_reason(), ""); + ASSERT_EQ(state.crash_address(), 0x0u); +} + +TEST_F(MicrodumpProcessorTest, TestProcess_WithCrashReason) { + ProcessState state; + AnalyzeDump("microdump-withcrashreason.dmp", true /* omit_symbols */, + 8 /* expected_cpu_count */, &state); + ASSERT_EQ(state.crash_reason(), "SIGTRAP"); + ASSERT_EQ(state.crash_address(), 0x4A7CB000u); +} + +TEST_F(MicrodumpProcessorTest, TestProcess_MissingSymbols) { + ProcessState state; + AnalyzeDump("microdump-arm64.dmp", true /* omit_symbols */, + 2 /* expected_cpu_count */, &state); + + ASSERT_EQ(8U, state.modules()->module_count()); + ASSERT_EQ("arm64", state.system_info()->cpu); + ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version); + ASSERT_EQ(1U, state.threads()->size()); + ASSERT_EQ(11U, state.threads()->at(0)->frames()->size()); + + ASSERT_EQ("", + state.threads()->at(0)->frames()->at(0)->function_name); + ASSERT_EQ("", + state.threads()->at(0)->frames()->at(3)->function_name); +} + +TEST_F(MicrodumpProcessorTest, TestProcess_UnsupportedArch) { + string microdump_contents = + "W/google-breakpad(26491): -----BEGIN BREAKPAD MICRODUMP-----\n" + "W/google-breakpad(26491): O A \"unsupported-arch\"\n" + "W/google-breakpad(26491): S 0 A48BD840 A48BD000 00002000\n"; + + ProcessState state; + + google_breakpad::ProcessResult result = + ProcessMicrodump("", microdump_contents, &state); + + ASSERT_EQ(google_breakpad::PROCESS_ERROR_NO_THREAD_LIST, result); +} + +TEST_F(MicrodumpProcessorTest, TestProcessArm) { + ProcessState state; + AnalyzeDump("microdump-arm.dmp", false /* omit_symbols */, + 2 /* expected_cpu_count*/, &state); + + ASSERT_EQ(6U, state.modules()->module_count()); + ASSERT_EQ("arm", state.system_info()->cpu); + ASSERT_EQ("OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)", + state.system_info()->gl_version); + ASSERT_EQ("Qualcomm", state.system_info()->gl_vendor); + ASSERT_EQ("Adreno (TM) 330", state.system_info()->gl_renderer); + ASSERT_EQ("OS VERSION INFO", state.system_info()->os_version); + ASSERT_EQ(8U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody", + state.threads()->at(0)->frames()->at(0)->function_name); + ASSERT_EQ("testing::Test::Run", + state.threads()->at(0)->frames()->at(1)->function_name); + ASSERT_EQ("main", + state.threads()->at(0)->frames()->at(6)->function_name); + ASSERT_EQ("breakpad_unittests", + state.threads()->at(0)->frames()->at(6)->module->code_file()); +} + +TEST_F(MicrodumpProcessorTest, TestProcessArm64) { + ProcessState state; + AnalyzeDump("microdump-arm64.dmp", false /* omit_symbols */, + 2 /* expected_cpu_count*/, &state); + + ASSERT_EQ(8U, state.modules()->module_count()); + ASSERT_EQ("arm64", state.system_info()->cpu); + ASSERT_EQ("OS 64 VERSION INFO", state.system_info()->os_version); + ASSERT_EQ(9U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ("MicrodumpWriterTest_Setup_Test::TestBody", + state.threads()->at(0)->frames()->at(0)->function_name); + ASSERT_EQ("testing::Test::Run", + state.threads()->at(0)->frames()->at(2)->function_name); + ASSERT_EQ("main", + state.threads()->at(0)->frames()->at(7)->function_name); + ASSERT_EQ("breakpad_unittests", + state.threads()->at(0)->frames()->at(7)->module->code_file()); +} + +TEST_F(MicrodumpProcessorTest, TestProcessX86) { + ProcessState state; + AnalyzeDump("microdump-x86.dmp", false /* omit_symbols */, + 4 /* expected_cpu_count */, &state); + + ASSERT_EQ(124U, state.modules()->module_count()); + ASSERT_EQ("x86", state.system_info()->cpu); + ASSERT_EQ("asus/WW_Z00A/Z00A:5.0/LRX21V/2.19.40.22_20150627_5104_user:user/" + "release-keys", state.system_info()->os_version); + ASSERT_EQ(17U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ("libc.so", + state.threads()->at(0)->frames()->at(0)->module->debug_file()); + // TODO(mmandlis): Get symbols for the test X86 microdump and test function + // names. +} + +TEST_F(MicrodumpProcessorTest, TestProcessMultiple) { + ProcessState state; + AnalyzeDump("microdump-multiple.dmp", false /* omit_symbols */, + 6 /* expected_cpu_count */, &state); + ASSERT_EQ(156U, state.modules()->module_count()); + ASSERT_EQ("arm", state.system_info()->cpu); + ASSERT_EQ("lge/p1_tmo_us/p1:6.0/MRA58K/1603210524c8d:user/release-keys", + state.system_info()->os_version); + ASSERT_EQ(5U, state.threads()->at(0)->frames()->size()); +} + +TEST_F(MicrodumpProcessorTest, TestProcessMips) { + ProcessState state; + AnalyzeDump("microdump-mips32.dmp", false /* omit_symbols */, + 2 /* expected_cpu_count */, &state); + + ASSERT_EQ(7U, state.modules()->module_count()); + ASSERT_EQ("mips", state.system_info()->cpu); + ASSERT_EQ("3.0.8-g893bf16 #7 SMP PREEMPT Fri Jul 10 15:20:59 PDT 2015", + state.system_info()->os_version); + ASSERT_EQ(4U, state.threads()->at(0)->frames()->size()); + + ASSERT_EQ("blaTest", + state.threads()->at(0)->frames()->at(0)->function_name); + ASSERT_EQ("Crash", + state.threads()->at(0)->frames()->at(1)->function_name); + ASSERT_EQ("main", + state.threads()->at(0)->frames()->at(2)->function_name); + ASSERT_EQ("crash_example", + state.threads()->at(0)->frames()->at(0)->module->debug_file()); +} + +TEST_F(MicrodumpProcessorTest, TestProcessMips64) { + ProcessState state; + AnalyzeDump("microdump-mips64.dmp", false /* omit_symbols */, + 1 /* expected_cpu_count */, &state); + + ASSERT_EQ(8U, state.modules()->module_count()); + ASSERT_EQ("mips64", state.system_info()->cpu); + ASSERT_EQ("3.10.0-gf185e20 #112 PREEMPT Mon Oct 5 11:12:49 PDT 2015", + state.system_info()->os_version); + ASSERT_EQ(4U, state.threads()->at(0)->frames()->size()); + + ASSERT_EQ("blaTest", + state.threads()->at(0)->frames()->at(0)->function_name); + ASSERT_EQ("Crash", + state.threads()->at(0)->frames()->at(1)->function_name); + ASSERT_EQ("main", + state.threads()->at(0)->frames()->at(2)->function_name); + ASSERT_EQ("crash_example", + state.threads()->at(0)->frames()->at(0)->module->debug_file()); +} + +} // namespace + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk.cc b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk.cc new file mode 100644 index 0000000000..220396ed93 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk.cc @@ -0,0 +1,181 @@ +// Copyright (c) 2014 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. + +// microdump_stackwalk.cc: Process a microdump with MicrodumpProcessor, printing +// the results, including stack traces. + +#include +#include +#include + +#include +#include +#include + +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/microdump.h" +#include "google_breakpad/processor/microdump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "processor/logging.h" +#include "processor/simple_symbol_supplier.h" +#include "processor/stackwalk_common.h" + + +namespace { + +struct Options { + bool machine_readable; + bool output_stack_contents; + + string microdump_file; + std::vector symbol_paths; +}; + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::Microdump; +using google_breakpad::MicrodumpProcessor; +using google_breakpad::ProcessResult; +using google_breakpad::ProcessState; +using google_breakpad::scoped_ptr; +using google_breakpad::SimpleSymbolSupplier; +using google_breakpad::StackFrameSymbolizer; + +// Processes |options.microdump_file| using +// MicrodumpProcessor. |options.symbol_path|, if non-empty, is the +// base directory of a symbol storage area, laid out in the format +// required by SimpleSymbolSupplier. If such a storage area is +// specified, it is made available for use by the MicrodumpProcessor. +// +// Returns the value of MicrodumpProcessor::Process. If processing succeeds, +// prints identifying OS and CPU information from the microdump, crash +// information and call stacks for the crashing thread. +// All information is printed to stdout. +int PrintMicrodumpProcess(const Options& options) { + std::ifstream file_stream(options.microdump_file); + std::vector bytes; + file_stream.seekg(0, std::ios_base::end); + bytes.resize(file_stream.tellg()); + if (bytes.empty()) { + BPLOG(ERROR) << "Microdump is empty."; + return 1; + } + file_stream.seekg(0, std::ios_base::beg); + file_stream.read(&bytes[0], bytes.size()); + string microdump_content(&bytes[0], bytes.size()); + + scoped_ptr symbol_supplier; + if (!options.symbol_paths.empty()) { + symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths)); + } + + BasicSourceLineResolver resolver; + StackFrameSymbolizer frame_symbolizer(symbol_supplier.get(), &resolver); + ProcessState process_state; + MicrodumpProcessor microdump_processor(&frame_symbolizer); + Microdump microdump(microdump_content); + ProcessResult res = microdump_processor.Process(µdump, + &process_state); + + if (res == google_breakpad::PROCESS_OK) { + if (options.machine_readable) { + PrintProcessStateMachineReadable(process_state); + } else { + PrintProcessState(process_state, options.output_stack_contents, &resolver); + } + return 0; + } + + BPLOG(ERROR) << "MicrodumpProcessor::Process failed (code = " << res << ")"; + return 1; +} + +} // namespace + +static void Usage(int argc, const char *argv[], bool error) { + fprintf(error ? stderr : stdout, + "Usage: %s [options] [symbol-path ...]\n" + "\n" + "Output a stack trace for the provided microdump\n" + "\n" + "Options:\n" + "\n" + " -m Output in machine-readable format\n" + " -s Output stack contents\n", + google_breakpad::BaseName(argv[0]).c_str()); +} + +static void SetupOptions(int argc, const char *argv[], Options* options) { + int ch; + + options->machine_readable = false; + options->output_stack_contents = false; + + while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) { + switch (ch) { + case 'h': + Usage(argc, argv, false); + exit(0); + break; + + case 'm': + options->machine_readable = true; + break; + case 's': + options->output_stack_contents = true; + break; + + case '?': + Usage(argc, argv, true); + exit(1); + break; + } + } + + if ((argc - optind) == 0) { + fprintf(stderr, "%s: Missing microdump file\n", argv[0]); + Usage(argc, argv, true); + exit(1); + } + + options->microdump_file = argv[optind]; + + for (int argi = optind + 1; argi < argc; ++argi) + options->symbol_paths.push_back(argv[argi]); +} + +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + + return PrintMicrodumpProcess(options); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_machine_readable_test b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_machine_readable_test new file mode 100755 index 0000000000..f5614e20f2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_machine_readable_test @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2014, 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. + +. "${0%/*}/microdump_stackwalk_test_vars" || exit 1 # for MICRODUMP_SUPPORTED_ARCHS. +testdata_dir=$srcdir/src/processor/testdata + +set -e # Bail out with an error if any of the commands below fails. +for ARCH in $MICRODUMP_SUPPORTED_ARCHS; do + echo "Testing microdump_stackwalk -m for arch $ARCH" + ./src/processor/microdump_stackwalk -m $testdata_dir/microdump-${ARCH}.dmp \ + $testdata_dir/symbols/microdump | \ + tr -d '\015' | \ + diff -u $testdata_dir/microdump.stackwalk.machine_readable-${ARCH}.out - +done +exit 0 diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test new file mode 100755 index 0000000000..e189765660 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2014, 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. + +. "${0%/*}/microdump_stackwalk_test_vars" || exit 1 # for MICRODUMP_SUPPORTED_ARCHS. +testdata_dir=$srcdir/src/processor/testdata + +set -e # Bail out with an error if any of the commands below fails. +for ARCH in $MICRODUMP_SUPPORTED_ARCHS; do + echo "Testing microdump_stackwalk for arch $ARCH" + ./src/processor/microdump_stackwalk $testdata_dir/microdump-${ARCH}.dmp \ + $testdata_dir/symbols/microdump | \ + tr -d '\015' | \ + diff -u $testdata_dir/microdump.stackwalk-${ARCH}.out - +done +exit 0 diff --git a/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test_vars b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test_vars new file mode 100644 index 0000000000..a8b0e0df5a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/microdump_stackwalk_test_vars @@ -0,0 +1 @@ +MICRODUMP_SUPPORTED_ARCHS="arm arm64" diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump.cc new file mode 100644 index 0000000000..3ba2437af3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump.cc @@ -0,0 +1,6445 @@ +// Copyright (c) 2010 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.cc: A minidump reader. +// +// See minidump.h for documentation. +// +// Author: Mark Mentovai + +#include "google_breakpad/processor/minidump.h" + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else // _WIN32 +#include +#endif // _WIN32 + +#include +#include +#include +#include + +#include "processor/range_map-inl.h" + +#include "common/macros.h" +#include "common/scoped_ptr.h" +#include "common/stdio_wrapper.h" +#include "google_breakpad/processor/dump_context.h" +#include "processor/basic_code_module.h" +#include "processor/basic_code_modules.h" +#include "processor/convert_old_arm64_context.h" +#include "processor/logging.h" + +namespace google_breakpad { + +using std::istream; +using std::ifstream; +using std::numeric_limits; +using std::vector; + +namespace { + +// Returns true iff |context_size| matches exactly one of the sizes of the +// various MDRawContext* types. +// TODO(blundell): This function can be removed once +// https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 is fixed. +bool IsContextSizeUnique(uint32_t context_size) { + int num_matching_contexts = 0; + if (context_size == sizeof(MDRawContextX86)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextPPC)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextPPC64)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextAMD64)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextSPARC)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextARM)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextARM64)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextARM64_Old)) + num_matching_contexts++; + if (context_size == sizeof(MDRawContextMIPS)) + num_matching_contexts++; + return num_matching_contexts == 1; +} + +// +// Swapping routines +// +// Inlining these doesn't increase code size significantly, and it saves +// a whole lot of unnecessary jumping back and forth. +// + + +// Swapping an 8-bit quantity is a no-op. This function is only provided +// to account for certain templatized operations that require swapping for +// wider types but handle uint8_t too +// (MinidumpMemoryRegion::GetMemoryAtAddressInternal). +inline void Swap(uint8_t* value) {} + +// Optimization: don't need to AND the furthest right shift, because we're +// shifting an unsigned quantity. The standard requires zero-filling in this +// case. If the quantities were signed, a bitmask whould be needed for this +// right shift to avoid an arithmetic shift (which retains the sign bit). +// The furthest left shift never needs to be ANDed bitmask. + +inline void Swap(uint16_t* value) { + *value = (*value >> 8) | (*value << 8); +} + +inline void Swap(uint32_t* value) { + *value = (*value >> 24) | + ((*value >> 8) & 0x0000ff00) | + ((*value << 8) & 0x00ff0000) | + (*value << 24); +} + +inline void Swap(uint64_t* value) { + uint32_t* value32 = reinterpret_cast(value); + Swap(&value32[0]); + Swap(&value32[1]); + uint32_t temp = value32[0]; + value32[0] = value32[1]; + value32[1] = temp; +} + + +// Given a pointer to a 128-bit int in the minidump data, set the "low" +// and "high" fields appropriately. +void Normalize128(uint128_struct* value, bool is_big_endian) { + // The struct format is [high, low], so if the format is big-endian, + // the most significant bytes will already be in the high field. + if (!is_big_endian) { + uint64_t temp = value->low; + value->low = value->high; + value->high = temp; + } +} + +// This just swaps each int64 half of the 128-bit value. +// The value should also be normalized by calling Normalize128(). +void Swap(uint128_struct* value) { + Swap(&value->low); + Swap(&value->high); +} + +// Swapping signed integers +inline void Swap(int32_t* value) { + Swap(reinterpret_cast(value)); +} + +inline void Swap(MDLocationDescriptor* location_descriptor) { + Swap(&location_descriptor->data_size); + Swap(&location_descriptor->rva); +} + +inline void Swap(MDMemoryDescriptor* memory_descriptor) { + Swap(&memory_descriptor->start_of_memory_range); + Swap(&memory_descriptor->memory); +} + +inline void Swap(MDGUID* guid) { + Swap(&guid->data1); + Swap(&guid->data2); + Swap(&guid->data3); + // Don't swap guid->data4[] because it contains 8-bit quantities. +} + +inline void Swap(MDSystemTime* system_time) { + Swap(&system_time->year); + Swap(&system_time->month); + Swap(&system_time->day_of_week); + Swap(&system_time->day); + Swap(&system_time->hour); + Swap(&system_time->minute); + Swap(&system_time->second); + Swap(&system_time->milliseconds); +} + +inline void Swap(MDXStateFeature* xstate_feature) { + Swap(&xstate_feature->offset); + Swap(&xstate_feature->size); +} + +inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) { + Swap(&xstate_feature_info->size_of_info); + Swap(&xstate_feature_info->context_size); + Swap(&xstate_feature_info->enabled_features); + + for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) { + Swap(&xstate_feature_info->features[i]); + } +} + +inline void Swap(MDRawSimpleStringDictionaryEntry* entry) { + Swap(&entry->key); + Swap(&entry->value); +} + +inline void Swap(uint16_t* data, size_t size_in_bytes) { + size_t data_length = size_in_bytes / sizeof(data[0]); + for (size_t i = 0; i < data_length; i++) { + Swap(&data[i]); + } +} + +// +// Character conversion routines +// + + +// Standard wide-character conversion routines depend on the system's own +// idea of what width a wide character should be: some use 16 bits, and +// some use 32 bits. For the purposes of a minidump, wide strings are +// always represented with 16-bit UTF-16 chracters. iconv isn't available +// everywhere, and its interface varies where it is available. iconv also +// deals purely with char* pointers, so in addition to considering the swap +// parameter, a converter that uses iconv would also need to take the host +// CPU's endianness into consideration. It doesn't seems worth the trouble +// of making it a dependency when we don't care about anything but UTF-16. +string* UTF16ToUTF8(const vector& in, bool swap) { + scoped_ptr out(new string()); + + // Set the string's initial capacity to the number of UTF-16 characters, + // because the UTF-8 representation will always be at least this long. + // If the UTF-8 representation is longer, the string will grow dynamically. + out->reserve(in.size()); + + for (vector::const_iterator iterator = in.begin(); + iterator != in.end(); + ++iterator) { + // Get a 16-bit value from the input + uint16_t in_word = *iterator; + if (swap) + Swap(&in_word); + + // Convert the input value (in_word) into a Unicode code point (unichar). + uint32_t unichar; + if (in_word >= 0xdc00 && in_word <= 0xdcff) { + BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " << + HexString(in_word) << " without high"; + return NULL; + } else if (in_word >= 0xd800 && in_word <= 0xdbff) { + // High surrogate. + unichar = (in_word - 0xd7c0) << 10; + if (++iterator == in.end()) { + BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << + HexString(in_word) << " at end of string"; + return NULL; + } + uint32_t high_word = in_word; + in_word = *iterator; + if (in_word < 0xdc00 || in_word > 0xdcff) { + BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << + HexString(high_word) << " without low " << + HexString(in_word); + return NULL; + } + unichar |= in_word & 0x03ff; + } else { + // The ordinary case, a single non-surrogate Unicode character encoded + // as a single 16-bit value. + unichar = in_word; + } + + // Convert the Unicode code point (unichar) into its UTF-8 representation, + // appending it to the out string. + if (unichar < 0x80) { + (*out) += static_cast(unichar); + } else if (unichar < 0x800) { + (*out) += 0xc0 | static_cast(unichar >> 6); + (*out) += 0x80 | static_cast(unichar & 0x3f); + } else if (unichar < 0x10000) { + (*out) += 0xe0 | static_cast(unichar >> 12); + (*out) += 0x80 | static_cast((unichar >> 6) & 0x3f); + (*out) += 0x80 | static_cast(unichar & 0x3f); + } else if (unichar < 0x200000) { + (*out) += 0xf0 | static_cast(unichar >> 18); + (*out) += 0x80 | static_cast((unichar >> 12) & 0x3f); + (*out) += 0x80 | static_cast((unichar >> 6) & 0x3f); + (*out) += 0x80 | static_cast(unichar & 0x3f); + } else { + BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " << + HexString(unichar) << " in UTF-8"; + return NULL; + } + } + + return out.release(); +} + +// Return the smaller of the number of code units in the UTF-16 string, +// not including the terminating null word, or maxlen. +size_t UTF16codeunits(const uint16_t* string, size_t maxlen) { + size_t count = 0; + while (count < maxlen && string[count] != 0) + count++; + return count; +} + +inline void Swap(MDTimeZoneInformation* time_zone) { + Swap(&time_zone->bias); + // Skip time_zone->standard_name. No need to swap UTF-16 fields. + // The swap will be done as part of the conversion to UTF-8. + Swap(&time_zone->standard_date); + Swap(&time_zone->standard_bias); + // Skip time_zone->daylight_name. No need to swap UTF-16 fields. + // The swap will be done as part of the conversion to UTF-8. + Swap(&time_zone->daylight_date); + Swap(&time_zone->daylight_bias); +} + +void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data, + size_t max_length_in_bytes, + string* utf8_result, + bool swap) { + // Since there is no explicit byte length for each string, use + // UTF16codeunits to calculate word length, then derive byte + // length from that. + size_t max_word_length = max_length_in_bytes / sizeof(utf16_data[0]); + size_t word_length = UTF16codeunits(utf16_data, max_word_length); + if (word_length > 0) { + size_t byte_length = word_length * sizeof(utf16_data[0]); + vector utf16_vector(word_length); + memcpy(&utf16_vector[0], &utf16_data[0], byte_length); + scoped_ptr temp(UTF16ToUTF8(utf16_vector, swap)); + if (temp.get()) { + utf8_result->assign(*temp); + } + } else { + utf8_result->clear(); + } +} + + +// For fields that may or may not be valid, PrintValueOrInvalid will print the +// string "(invalid)" if the field is not valid, and will print the value if +// the field is valid. The value is printed as hexadecimal or decimal. + +enum NumberFormat { + kNumberFormatDecimal, + kNumberFormatHexadecimal, +}; + +void PrintValueOrInvalid(bool valid, + NumberFormat number_format, + uint32_t value) { + if (!valid) { + printf("(invalid)\n"); + } else if (number_format == kNumberFormatDecimal) { + printf("%d\n", value); + } else { + printf("0x%x\n", value); + } +} + +// Converts a time_t to a string showing the time in UTC. +string TimeTToUTCString(time_t tt) { + struct tm timestruct; +#ifdef _WIN32 + gmtime_s(×truct, &tt); +#else + gmtime_r(&tt, ×truct); +#endif + + char timestr[20]; + size_t rv = strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); + if (rv == 0) { + return string(); + } + + return string(timestr); +} + +string MDGUIDToString(const MDGUID& uuid) { + char buf[37]; + snprintf(buf, sizeof(buf), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.data1, + uuid.data2, + uuid.data3, + uuid.data4[0], + uuid.data4[1], + uuid.data4[2], + uuid.data4[3], + uuid.data4[4], + uuid.data4[5], + uuid.data4[6], + uuid.data4[7]); + return std::string(buf); +} + +bool IsDevAshmem(const string& filename) { + const string kDevAshmem("/dev/ashmem/"); + return filename.compare(0, kDevAshmem.length(), kDevAshmem) == 0; +} + +} // namespace + +// +// MinidumpObject +// + + +MinidumpObject::MinidumpObject(Minidump* minidump) + : DumpObject(), + minidump_(minidump) { +} + + +// +// MinidumpStream +// + + +MinidumpStream::MinidumpStream(Minidump* minidump) + : MinidumpObject(minidump) { +} + + +// +// MinidumpContext +// + + +MinidumpContext::MinidumpContext(Minidump* minidump) + : DumpContext(), + minidump_(minidump) { +} + +MinidumpContext::~MinidumpContext() { +} + +bool MinidumpContext::Read(uint32_t expected_size) { + valid_ = false; + + // Certain raw context types are currently assumed to have unique sizes. + if (!IsContextSizeUnique(sizeof(MDRawContextPPC64))) { + BPLOG(ERROR) << "sizeof(MDRawContextPPC64) cannot match the size of any " + << "other raw context"; + return false; + } + if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) { + BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any " + << "other raw context"; + return false; + } + + FreeContext(); + + if (expected_size == sizeof(MDRawContextPPC64)) { + // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext + // in the else case have 32 bits |context_flags|, so special case it here. + uint64_t context_flags; + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; + } + if (minidump_->swap()) + Swap(&context_flags); + + uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; + scoped_ptr context_ppc64(new MDRawContextPPC64()); + + if (cpu_type == 0) { + if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { + context_ppc64->context_flags |= cpu_type; + } else { + BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } + } + + if (cpu_type != MD_CONTEXT_PPC64) { + // TODO: Fall through to switch below. + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 + BPLOG(ERROR) << "MinidumpContext not actually ppc64 context"; + return false; + } + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_ppc64->context_flags = context_flags; + + size_t flags_size = sizeof(context_ppc64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_ppc64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextPPC64) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read ppc64 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext ppc64 does not match system info"; + return false; + } + if (minidump_->swap()) { + // context_ppc64->context_flags was already swapped. + Swap(&context_ppc64->srr0); + Swap(&context_ppc64->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC64_GPR_COUNT; + ++gpr_index) { + Swap(&context_ppc64->gpr[gpr_index]); + } + Swap(&context_ppc64->cr); + Swap(&context_ppc64->xer); + Swap(&context_ppc64->lr); + Swap(&context_ppc64->ctr); + Swap(&context_ppc64->vrsave); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; + ++fpr_index) { + Swap(&context_ppc64->float_save.fpregs[fpr_index]); + } + // Don't swap context_ppc64->float_save.fpscr_pad because it is only + // used for padding. + Swap(&context_ppc64->float_save.fpscr); + for (unsigned int vr_index = 0; + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; + ++vr_index) { + Normalize128(&context_ppc64->vector_save.save_vr[vr_index], true); + Swap(&context_ppc64->vector_save.save_vr[vr_index]); + } + Swap(&context_ppc64->vector_save.save_vscr); + // Don't swap the padding fields in vector_save. + Swap(&context_ppc64->vector_save.save_vrvalid); + } + + SetContextFlags(static_cast(context_ppc64->context_flags)); + + // Check for data loss when converting context flags from uint64_t into + // uint32_t + if (static_cast(GetContextFlags()) != + context_ppc64->context_flags) { + BPLOG(ERROR) << "Data loss detected when converting PPC64 context_flags"; + return false; + } + + SetContextPPC64(context_ppc64.release()); + } else if (expected_size == sizeof(MDRawContextARM64_Old)) { + // |context_flags| of MDRawContextARM64_Old is 64 bits, but other MDRawContext + // in the else case have 32 bits |context_flags|, so special case it here. + uint64_t context_flags; + + BPLOG(INFO) << "MinidumpContext: looks like ARM64 context"; + + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; + } + if (minidump_->swap()) + Swap(&context_flags); + + scoped_ptr context_arm64(new MDRawContextARM64_Old()); + + uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; + if (cpu_type == 0) { + if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { + context_arm64->context_flags |= cpu_type; + } else { + BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } + } + + if (cpu_type != MD_CONTEXT_ARM64_OLD) { + // TODO: Fall through to switch below. + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 + BPLOG(ERROR) << "MinidumpContext not actually arm64 context"; + return false; + } + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_arm64->context_flags = context_flags; + + size_t flags_size = sizeof(context_arm64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_arm64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextARM64_Old) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read arm64 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext arm64 does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_arm64->context_flags was already swapped. + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM64_GPR_COUNT; + ++ireg_index) { + Swap(&context_arm64->iregs[ireg_index]); + } + Swap(&context_arm64->cpsr); + Swap(&context_arm64->float_save.fpsr); + Swap(&context_arm64->float_save.fpcr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT; + ++fpr_index) { + Normalize128(&context_arm64->float_save.regs[fpr_index], + minidump_->is_big_endian()); + Swap(&context_arm64->float_save.regs[fpr_index]); + } + } + + scoped_ptr new_context(new MDRawContextARM64()); + ConvertOldARM64Context(*context_arm64.get(), new_context.get()); + SetContextFlags(new_context->context_flags); + SetContextARM64(new_context.release()); + } else { + uint32_t cpu_type = 0; + if (!minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { + BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } + + uint32_t context_flags = 0; + if ((cpu_type == 0) || cpu_type != MD_CONTEXT_AMD64) { + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; + } + + if (minidump_->swap()) + Swap(&context_flags); + + if ((context_flags & MD_CONTEXT_CPU_MASK) == 0) { + // Unfortunately the flag for MD_CONTEXT_ARM that was taken + // from a Windows CE SDK header conflicts in practice with + // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, + // but handle dumps with the legacy value gracefully here. + if (context_flags & MD_CONTEXT_ARM_OLD) { + context_flags |= MD_CONTEXT_ARM; + context_flags &= ~MD_CONTEXT_ARM_OLD; + cpu_type = MD_CONTEXT_ARM; + } else { + context_flags |= cpu_type; + } + } else { + cpu_type = context_flags & MD_CONTEXT_CPU_MASK; + } + } + + // Allocate the context structure for the correct CPU and fill it. The + // casts are slightly unorthodox, but it seems better to do that than to + // maintain a separate pointer for each type of CPU context structure + // when only one of them will be used. + switch (cpu_type) { + case MD_CONTEXT_AMD64: { + if (expected_size != sizeof(MDRawContextAMD64)) { + BPLOG(INFO) << "MinidumpContext AMD64 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextAMD64); + } + BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; + + scoped_ptr context_amd64(new MDRawContextAMD64()); + if (!minidump_->ReadBytes(context_amd64.get(), + sizeof(MDRawContextAMD64))) { + BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; + return false; + } + + if (minidump_->swap()) + Swap(&context_amd64->context_flags); + + // Update context_flags since we haven't done it yet + context_flags = context_amd64->context_flags; + + if (cpu_type != (context_flags & MD_CONTEXT_CPU_MASK)) { + BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; + return false; + } + + // Normalize the 128-bit types in the dump. + // Since this is AMD64, by definition, the values are little-endian. + for (unsigned int vr_index = 0; + vr_index < MD_CONTEXT_AMD64_VR_COUNT; + ++vr_index) + Normalize128(&context_amd64->vector_register[vr_index], false); + + if (minidump_->swap()) { + Swap(&context_amd64->p1_home); + Swap(&context_amd64->p2_home); + Swap(&context_amd64->p3_home); + Swap(&context_amd64->p4_home); + Swap(&context_amd64->p5_home); + Swap(&context_amd64->p6_home); + // context_flags is already swapped + Swap(&context_amd64->mx_csr); + Swap(&context_amd64->cs); + Swap(&context_amd64->ds); + Swap(&context_amd64->es); + Swap(&context_amd64->fs); + Swap(&context_amd64->ss); + Swap(&context_amd64->eflags); + Swap(&context_amd64->dr0); + Swap(&context_amd64->dr1); + Swap(&context_amd64->dr2); + Swap(&context_amd64->dr3); + Swap(&context_amd64->dr6); + Swap(&context_amd64->dr7); + Swap(&context_amd64->rax); + Swap(&context_amd64->rcx); + Swap(&context_amd64->rdx); + Swap(&context_amd64->rbx); + Swap(&context_amd64->rsp); + Swap(&context_amd64->rbp); + Swap(&context_amd64->rsi); + Swap(&context_amd64->rdi); + Swap(&context_amd64->r8); + Swap(&context_amd64->r9); + Swap(&context_amd64->r10); + Swap(&context_amd64->r11); + Swap(&context_amd64->r12); + Swap(&context_amd64->r13); + Swap(&context_amd64->r14); + Swap(&context_amd64->r15); + Swap(&context_amd64->rip); + // FIXME: I'm not sure what actually determines + // which member of the union {flt_save, sse_registers} + // is valid. We're not currently using either, + // but it would be good to have them swapped properly. + + for (unsigned int vr_index = 0; + vr_index < MD_CONTEXT_AMD64_VR_COUNT; + ++vr_index) + Swap(&context_amd64->vector_register[vr_index]); + Swap(&context_amd64->vector_control); + Swap(&context_amd64->debug_control); + Swap(&context_amd64->last_branch_to_rip); + Swap(&context_amd64->last_branch_from_rip); + Swap(&context_amd64->last_exception_to_rip); + Swap(&context_amd64->last_exception_from_rip); + } + + SetContextFlags(context_amd64->context_flags); + + SetContextAMD64(context_amd64.release()); + minidump_->SeekSet( + (minidump_->Tell() - sizeof(MDRawContextAMD64)) + expected_size); + break; + } + case MD_CONTEXT_X86: { + if (expected_size != sizeof(MDRawContextX86)) { + BPLOG(INFO) << "MinidumpContext x86 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextX86); + } + + scoped_ptr context_x86(new MDRawContextX86()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_x86->context_flags = context_flags; + + size_t flags_size = sizeof(context_x86->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_x86.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextX86) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read x86 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext x86 does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_x86->context_flags was already swapped. + Swap(&context_x86->dr0); + Swap(&context_x86->dr1); + Swap(&context_x86->dr2); + Swap(&context_x86->dr3); + Swap(&context_x86->dr6); + Swap(&context_x86->dr7); + Swap(&context_x86->float_save.control_word); + Swap(&context_x86->float_save.status_word); + Swap(&context_x86->float_save.tag_word); + Swap(&context_x86->float_save.error_offset); + Swap(&context_x86->float_save.error_selector); + Swap(&context_x86->float_save.data_offset); + Swap(&context_x86->float_save.data_selector); + // context_x86->float_save.register_area[] contains 8-bit quantities + // and does not need to be swapped. + Swap(&context_x86->float_save.cr0_npx_state); + Swap(&context_x86->gs); + Swap(&context_x86->fs); + Swap(&context_x86->es); + Swap(&context_x86->ds); + Swap(&context_x86->edi); + Swap(&context_x86->esi); + Swap(&context_x86->ebx); + Swap(&context_x86->edx); + Swap(&context_x86->ecx); + Swap(&context_x86->eax); + Swap(&context_x86->ebp); + Swap(&context_x86->eip); + Swap(&context_x86->cs); + Swap(&context_x86->eflags); + Swap(&context_x86->esp); + Swap(&context_x86->ss); + // context_x86->extended_registers[] contains 8-bit quantities and + // does not need to be swapped. + } + + SetContextX86(context_x86.release()); + minidump_->SeekSet( + (minidump_->Tell() - sizeof(MDRawContextX86)) + expected_size); + + break; + } + + case MD_CONTEXT_PPC: { + if (expected_size != sizeof(MDRawContextPPC)) { + BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " << + expected_size << " != " << sizeof(MDRawContextPPC); + return false; + } + + scoped_ptr context_ppc(new MDRawContextPPC()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_ppc->context_flags = context_flags; + + size_t flags_size = sizeof(context_ppc->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_ppc.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextPPC) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read ppc context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext ppc does not match system info"; + return false; + } + + // Normalize the 128-bit types in the dump. + // Since this is PowerPC, by definition, the values are big-endian. + for (unsigned int vr_index = 0; + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; + ++vr_index) { + Normalize128(&context_ppc->vector_save.save_vr[vr_index], true); + } + + if (minidump_->swap()) { + // context_ppc->context_flags was already swapped. + Swap(&context_ppc->srr0); + Swap(&context_ppc->srr1); + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_PPC_GPR_COUNT; + ++gpr_index) { + Swap(&context_ppc->gpr[gpr_index]); + } + Swap(&context_ppc->cr); + Swap(&context_ppc->xer); + Swap(&context_ppc->lr); + Swap(&context_ppc->ctr); + Swap(&context_ppc->mq); + Swap(&context_ppc->vrsave); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; + ++fpr_index) { + Swap(&context_ppc->float_save.fpregs[fpr_index]); + } + // Don't swap context_ppc->float_save.fpscr_pad because it is only + // used for padding. + Swap(&context_ppc->float_save.fpscr); + for (unsigned int vr_index = 0; + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; + ++vr_index) { + Swap(&context_ppc->vector_save.save_vr[vr_index]); + } + Swap(&context_ppc->vector_save.save_vscr); + // Don't swap the padding fields in vector_save. + Swap(&context_ppc->vector_save.save_vrvalid); + } + + SetContextPPC(context_ppc.release()); + + break; + } + + case MD_CONTEXT_SPARC: { + if (expected_size != sizeof(MDRawContextSPARC)) { + BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " << + expected_size << " != " << sizeof(MDRawContextSPARC); + return false; + } + + scoped_ptr context_sparc(new MDRawContextSPARC()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_sparc->context_flags = context_flags; + + size_t flags_size = sizeof(context_sparc->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_sparc.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextSPARC) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read sparc context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext sparc does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_sparc->context_flags was already swapped. + for (unsigned int gpr_index = 0; + gpr_index < MD_CONTEXT_SPARC_GPR_COUNT; + ++gpr_index) { + Swap(&context_sparc->g_r[gpr_index]); + } + Swap(&context_sparc->ccr); + Swap(&context_sparc->pc); + Swap(&context_sparc->npc); + Swap(&context_sparc->y); + Swap(&context_sparc->asi); + Swap(&context_sparc->fprs); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT; + ++fpr_index) { + Swap(&context_sparc->float_save.regs[fpr_index]); + } + Swap(&context_sparc->float_save.filler); + Swap(&context_sparc->float_save.fsr); + } + SetContextSPARC(context_sparc.release()); + + break; + } + + case MD_CONTEXT_ARM: { + if (expected_size != sizeof(MDRawContextARM)) { + BPLOG(ERROR) << "MinidumpContext arm size mismatch, " << + expected_size << " != " << sizeof(MDRawContextARM); + return false; + } + + scoped_ptr context_arm(new MDRawContextARM()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_arm->context_flags = context_flags; + + size_t flags_size = sizeof(context_arm->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_arm.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextARM) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read arm context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext arm does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_arm->context_flags was already swapped. + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; + ++ireg_index) { + Swap(&context_arm->iregs[ireg_index]); + } + Swap(&context_arm->cpsr); + Swap(&context_arm->float_save.fpscr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; + ++fpr_index) { + Swap(&context_arm->float_save.regs[fpr_index]); + } + for (unsigned int fpe_index = 0; + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; + ++fpe_index) { + Swap(&context_arm->float_save.extra[fpe_index]); + } + } + SetContextARM(context_arm.release()); + + break; + } + + case MD_CONTEXT_ARM64: { + if (expected_size != sizeof(MDRawContextARM64)) { + BPLOG(ERROR) << "MinidumpContext arm64 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextARM64); + return false; + } + + scoped_ptr context_arm64(new MDRawContextARM64()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_arm64->context_flags = context_flags; + + size_t flags_size = sizeof(context_arm64->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_arm64.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(*context_arm64) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read arm64 context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext arm does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_arm64->context_flags was already swapped. + for (unsigned int ireg_index = 0; + ireg_index < MD_CONTEXT_ARM64_GPR_COUNT; + ++ireg_index) { + Swap(&context_arm64->iregs[ireg_index]); + } + Swap(&context_arm64->cpsr); + Swap(&context_arm64->float_save.fpsr); + Swap(&context_arm64->float_save.fpcr); + for (unsigned int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT; + ++fpr_index) { + Normalize128(&context_arm64->float_save.regs[fpr_index], + minidump_->is_big_endian()); + Swap(&context_arm64->float_save.regs[fpr_index]); + } + } + SetContextARM64(context_arm64.release()); + break; + } + + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: { + if (expected_size != sizeof(MDRawContextMIPS)) { + BPLOG(ERROR) << "MinidumpContext MIPS size mismatch, " + << expected_size + << " != " + << sizeof(MDRawContextMIPS); + return false; + } + + scoped_ptr context_mips(new MDRawContextMIPS()); + + // Set the context_flags member, which has already been read, and + // read the rest of the structure beginning with the first member + // after context_flags. + context_mips->context_flags = context_flags; + + size_t flags_size = sizeof(context_mips->context_flags); + uint8_t* context_after_flags = + reinterpret_cast(context_mips.get()) + flags_size; + if (!minidump_->ReadBytes(context_after_flags, + sizeof(MDRawContextMIPS) - flags_size)) { + BPLOG(ERROR) << "MinidumpContext could not read MIPS context"; + return false; + } + + // Do this after reading the entire MDRawContext structure because + // GetSystemInfo may seek minidump to a new position. + if (!CheckAgainstSystemInfo(cpu_type)) { + BPLOG(ERROR) << "MinidumpContext MIPS does not match system info"; + return false; + } + + if (minidump_->swap()) { + // context_mips->context_flags was already swapped. + for (int ireg_index = 0; + ireg_index < MD_CONTEXT_MIPS_GPR_COUNT; + ++ireg_index) { + Swap(&context_mips->iregs[ireg_index]); + } + Swap(&context_mips->mdhi); + Swap(&context_mips->mdlo); + for (int dsp_index = 0; + dsp_index < MD_CONTEXT_MIPS_DSP_COUNT; + ++dsp_index) { + Swap(&context_mips->hi[dsp_index]); + Swap(&context_mips->lo[dsp_index]); + } + Swap(&context_mips->dsp_control); + Swap(&context_mips->epc); + Swap(&context_mips->badvaddr); + Swap(&context_mips->status); + Swap(&context_mips->cause); + for (int fpr_index = 0; + fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; + ++fpr_index) { + Swap(&context_mips->float_save.regs[fpr_index]); + } + Swap(&context_mips->float_save.fpcsr); + Swap(&context_mips->float_save.fir); + } + SetContextMIPS(context_mips.release()); + + break; + } + + default: { + // Unknown context type - Don't log as an error yet. Let the + // caller work that out. + BPLOG(INFO) << "MinidumpContext unknown context type " << + HexString(cpu_type); + return false; + break; + } + } + SetContextFlags(context_flags); + } + + valid_ = true; + return true; +} + +bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) { + // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM, + // as this function just implements a sanity check. + MinidumpSystemInfo* system_info = minidump_->GetSystemInfo(); + if (!system_info) { + BPLOG(INFO) << "MinidumpContext could not be compared against " + "MinidumpSystemInfo"; + return true; + } + + // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info. + const MDRawSystemInfo* raw_system_info = system_info->system_info(); + if (!raw_system_info) { + BPLOG(INFO) << "MinidumpContext could not be compared against " + "MDRawSystemInfo"; + return false; + } + + MDCPUArchitecture system_info_cpu_type = static_cast( + raw_system_info->processor_architecture); + + // Compare the CPU type of the context record to the CPU type in the + // minidump's system info stream. + bool return_value = false; + switch (context_cpu_type) { + case MD_CONTEXT_X86: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 || + system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 || + system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) { + return_value = true; + } + break; + + case MD_CONTEXT_PPC: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC) + return_value = true; + break; + + case MD_CONTEXT_PPC64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC64) + return_value = true; + break; + + case MD_CONTEXT_AMD64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) + return_value = true; + break; + + case MD_CONTEXT_SPARC: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC) + return_value = true; + break; + + case MD_CONTEXT_ARM: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM) + return_value = true; + break; + + case MD_CONTEXT_ARM64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64) + return_value = true; + break; + + case MD_CONTEXT_ARM64_OLD: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64_OLD) + return_value = true; + break; + + case MD_CONTEXT_MIPS: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS) + return_value = true; + break; + + case MD_CONTEXT_MIPS64: + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS64) + return_value = true; + break; + } + + BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " << + HexString(context_cpu_type) << + " wrong for MinidumpSystemInfo CPU " << + HexString(system_info_cpu_type); + + return return_value; +} + + +// +// MinidumpMemoryRegion +// + + +uint32_t MinidumpMemoryRegion::max_bytes_ = 64 * 1024 * 1024; // 64MB + + +MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump) + : MinidumpObject(minidump), + descriptor_(NULL), + memory_(NULL) { + hexdump_width_ = minidump_ ? minidump_->HexdumpMode() : 0; + hexdump_ = hexdump_width_ != 0; +} + + +MinidumpMemoryRegion::~MinidumpMemoryRegion() { + delete memory_; +} + + +void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) { + descriptor_ = descriptor; + valid_ = descriptor && + descriptor_->memory.data_size <= + numeric_limits::max() - + descriptor_->start_of_memory_range; +} + + +const uint8_t* MinidumpMemoryRegion::GetMemory() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory"; + return NULL; + } + + if (!memory_) { + if (descriptor_->memory.data_size == 0) { + BPLOG(ERROR) << "MinidumpMemoryRegion is empty"; + return NULL; + } + + if (!minidump_->SeekSet(descriptor_->memory.rva)) { + BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region"; + return NULL; + } + + if (descriptor_->memory.data_size > max_bytes_) { + BPLOG(ERROR) << "MinidumpMemoryRegion size " << + descriptor_->memory.data_size << " exceeds maximum " << + max_bytes_; + return NULL; + } + + scoped_ptr< vector > memory( + new vector(descriptor_->memory.data_size)); + + if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) { + BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region"; + return NULL; + } + + memory_ = memory.release(); + } + + return &(*memory_)[0]; +} + + +uint64_t MinidumpMemoryRegion::GetBase() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase"; + return static_cast(-1); + } + + return descriptor_->start_of_memory_range; +} + + +uint32_t MinidumpMemoryRegion::GetSize() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize"; + return 0; + } + + return descriptor_->memory.data_size; +} + + +void MinidumpMemoryRegion::FreeMemory() { + delete memory_; + memory_ = NULL; +} + + +template +bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address, + T* value) const { + BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal " + "requires |value|"; + assert(value); + *value = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for " + "GetMemoryAtAddressInternal"; + return false; + } + + // Common failure case + if (address < descriptor_->start_of_memory_range || + sizeof(T) > numeric_limits::max() - address || + address + sizeof(T) > descriptor_->start_of_memory_range + + descriptor_->memory.data_size) { + BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " << + HexString(address) << "+" << sizeof(T) << "/" << + HexString(descriptor_->start_of_memory_range) << "+" << + HexString(descriptor_->memory.data_size); + return false; + } + + const uint8_t* memory = GetMemory(); + if (!memory) { + // GetMemory already logged a perfectly good message. + return false; + } + + // If the CPU requires memory accesses to be aligned, this can crash. + // x86 and ppc are able to cope, though. + *value = *reinterpret_cast( + &memory[address - descriptor_->start_of_memory_range]); + + if (minidump_->swap()) + Swap(value); + + return true; +} + + +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint8_t* value) const { + return GetMemoryAtAddressInternal(address, value); +} + + +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint16_t* value) const { + return GetMemoryAtAddressInternal(address, value); +} + + +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint32_t* value) const { + return GetMemoryAtAddressInternal(address, value); +} + + +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, + uint64_t* value) const { + return GetMemoryAtAddressInternal(address, value); +} + + +void MinidumpMemoryRegion::Print() const { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data"; + return; + } + + const uint8_t* memory = GetMemory(); + if (memory) { + if (hexdump_) { + // Pretty hexdump view. + for (unsigned int byte_index = 0; + byte_index < descriptor_->memory.data_size; + byte_index += hexdump_width_) { + // In case the memory won't fill a whole line. + unsigned int num_bytes = std::min( + descriptor_->memory.data_size - byte_index, hexdump_width_); + + // Display the leading address. + printf("%08x ", byte_index); + + // Show the bytes in hex. + for (unsigned int i = 0; i < hexdump_width_; ++i) { + if (i < num_bytes) { + // Show the single byte of memory in hex. + printf("%02x ", memory[byte_index + i]); + } else { + // If this line doesn't fill up, pad it out. + printf(" "); + } + + // Insert a space every 8 bytes to make it more readable. + if (((i + 1) % 8) == 0) { + printf(" "); + } + } + + // Decode the line as ASCII. + printf("|"); + for (unsigned int i = 0; i < hexdump_width_; ++i) { + if (i < num_bytes) { + uint8_t byte = memory[byte_index + i]; + printf("%c", isprint(byte) ? byte : '.'); + } else { + // If this line doesn't fill up, pad it out. + printf(" "); + } + } + printf("|\n"); + } + } else { + // Ugly raw string view. + printf("0x"); + for (unsigned int i = 0; + i < descriptor_->memory.data_size; + i++) { + printf("%02x", memory[i]); + } + printf("\n"); + } + } else { + printf("No memory\n"); + } +} + + +void MinidumpMemoryRegion::SetPrintMode(bool hexdump, + unsigned int hexdump_width) { + // Require the width to be a multiple of 8 bytes. + if (hexdump_width == 0 || (hexdump_width % 8) != 0) { + BPLOG(ERROR) << "MinidumpMemoryRegion print hexdump_width must be " + "multiple of 8, not " << hexdump_width; + return; + } + + hexdump_ = hexdump; + hexdump_width_ = hexdump_width; +} + + +// +// MinidumpThread +// + + +MinidumpThread::MinidumpThread(Minidump* minidump) + : MinidumpObject(minidump), + thread_(), + memory_(NULL), + context_(NULL) { +} + + +MinidumpThread::~MinidumpThread() { + delete memory_; + delete context_; +} + + +bool MinidumpThread::Read() { + // Invalidate cached data. + delete memory_; + memory_ = NULL; + delete context_; + context_ = NULL; + + valid_ = false; + + if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) { + BPLOG(ERROR) << "MinidumpThread cannot read thread"; + return false; + } + + if (minidump_->swap()) { + Swap(&thread_.thread_id); + Swap(&thread_.suspend_count); + Swap(&thread_.priority_class); + Swap(&thread_.priority); + Swap(&thread_.teb); + Swap(&thread_.stack); + Swap(&thread_.thread_context); + } + + // Check for base + size overflow or undersize. + if (thread_.stack.memory.rva == 0 || + thread_.stack.memory.data_size == 0 || + thread_.stack.memory.data_size > numeric_limits::max() - + thread_.stack.start_of_memory_range) { + // This is ok, but log an error anyway. + BPLOG(ERROR) << "MinidumpThread has a memory region problem, " << + HexString(thread_.stack.start_of_memory_range) << "+" << + HexString(thread_.stack.memory.data_size) << + ", RVA 0x" << HexString(thread_.stack.memory.rva); + } else { + memory_ = new MinidumpMemoryRegion(minidump_); + memory_->SetDescriptor(&thread_.stack); + } + + valid_ = true; + return true; +} + +uint64_t MinidumpThread::GetStartOfStackMemoryRange() const { + if (!valid_) { + BPLOG(ERROR) << "GetStartOfStackMemoryRange: Invalid MinidumpThread"; + return 0; + } + + return thread_.stack.start_of_memory_range; +} + +MinidumpMemoryRegion* MinidumpThread::GetMemory() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory"; + return NULL; + } + + return memory_; +} + +uint32_t MinidumpThread::GetLastError() { + if (!valid_) { + BPLOG(ERROR) << "Cannot retrieve GetLastError() from an invalid thread"; + return 0; + } + + if (!thread_.teb) { + BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid TEB pointer"; + return 0; + } + + auto memory = minidump_->GetMemoryList(); + if (!memory) { + BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid memory list"; + return 0; + } + + auto context = GetContext(); + if (!context) { + BPLOG(ERROR) << "Cannot retrieve GetLastError()'s without a valid context"; + return 0; + } + + uint64_t pointer_width = 0; + switch (context_->GetContextCPU()) { + case MD_CONTEXT_X86: + pointer_width = 4; + break; + case MD_CONTEXT_AMD64: + case MD_CONTEXT_ARM64: + pointer_width = 8; + break; + default: + BPLOG(ERROR) << "GetLastError() isn't implemented for this CPU type yet"; + return 0; + } + + auto region = memory->GetMemoryRegionForAddress(thread_.teb); + if (!region) { + BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump"; + return 0; + } + + // The TEB is opaque but we know the value we want lives at this offset + // from reverse engineering. + uint64_t offset = pointer_width * 13; + uint32_t error = 0; + if (!region->GetMemoryAtAddress(thread_.teb + offset, &error)) { + BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump"; + return 0; + } + + if (minidump_->swap()) { + Swap(&error); + } + + return error; +} + + + +MinidumpContext* MinidumpThread::GetContext() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThread for GetContext"; + return NULL; + } + + if (!context_) { + if (!minidump_->SeekSet(thread_.thread_context.rva)) { + BPLOG(ERROR) << "MinidumpThread cannot seek to context"; + return NULL; + } + + scoped_ptr context(new MinidumpContext(minidump_)); + + if (!context->Read(thread_.thread_context.data_size)) { + BPLOG(ERROR) << "MinidumpThread cannot read context"; + return NULL; + } + + context_ = context.release(); + } + + return context_; +} + + +bool MinidumpThread::GetThreadID(uint32_t *thread_id) const { + BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires " + "|thread_id|"; + assert(thread_id); + *thread_id = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID"; + return false; + } + + *thread_id = thread_.thread_id; + return true; +} + + +void MinidumpThread::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThread cannot print invalid data"; + return; + } + + printf("MDRawThread\n"); + printf(" thread_id = 0x%x\n", thread_.thread_id); + printf(" suspend_count = %d\n", thread_.suspend_count); + printf(" priority_class = 0x%x\n", thread_.priority_class); + printf(" priority = 0x%x\n", thread_.priority); + printf(" teb = 0x%" PRIx64 "\n", thread_.teb); + printf(" stack.start_of_memory_range = 0x%" PRIx64 "\n", + thread_.stack.start_of_memory_range); + printf(" stack.memory.data_size = 0x%x\n", + thread_.stack.memory.data_size); + printf(" stack.memory.rva = 0x%x\n", thread_.stack.memory.rva); + printf(" thread_context.data_size = 0x%x\n", + thread_.thread_context.data_size); + printf(" thread_context.rva = 0x%x\n", + thread_.thread_context.rva); + + MinidumpContext* context = GetContext(); + if (context) { + printf("\n"); + context->Print(); + } else { + printf(" (no context)\n"); + printf("\n"); + } + + MinidumpMemoryRegion* memory = GetMemory(); + if (memory) { + printf("Stack\n"); + memory->Print(); + } else { + printf("No stack\n"); + } + printf("\n"); +} + + +// +// MinidumpThreadList +// + + +uint32_t MinidumpThreadList::max_threads_ = 4096; + + +MinidumpThreadList::MinidumpThreadList(Minidump* minidump) + : MinidumpStream(minidump), + id_to_thread_map_(), + threads_(NULL), + thread_count_(0) { +} + + +MinidumpThreadList::~MinidumpThreadList() { + delete threads_; +} + + +bool MinidumpThreadList::Read(uint32_t expected_size) { + // Invalidate cached data. + id_to_thread_map_.clear(); + delete threads_; + threads_ = NULL; + thread_count_ = 0; + + valid_ = false; + + uint32_t thread_count; + if (expected_size < sizeof(thread_count)) { + BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " << + expected_size << " < " << sizeof(thread_count); + return false; + } + if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) { + BPLOG(ERROR) << "MinidumpThreadList cannot read thread count"; + return false; + } + + if (minidump_->swap()) + Swap(&thread_count); + + if (thread_count > numeric_limits::max() / sizeof(MDRawThread)) { + BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count << + " would cause multiplication overflow"; + return false; + } + + if (expected_size != sizeof(thread_count) + + thread_count * sizeof(MDRawThread)) { + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(thread_count) + 4 + + thread_count * sizeof(MDRawThread)) { + uint32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded " + "bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size << + " != " << sizeof(thread_count) + + thread_count * sizeof(MDRawThread); + return false; + } + } + + + if (thread_count > max_threads_) { + BPLOG(ERROR) << "MinidumpThreadList count " << thread_count << + " exceeds maximum " << max_threads_; + return false; + } + + if (thread_count != 0) { + scoped_ptr threads( + new MinidumpThreads(thread_count, MinidumpThread(minidump_))); + + for (unsigned int thread_index = 0; + thread_index < thread_count; + ++thread_index) { + MinidumpThread* thread = &(*threads)[thread_index]; + + // Assume that the file offset is correct after the last read. + if (!thread->Read()) { + BPLOG(ERROR) << "MinidumpThreadList cannot read thread " << + thread_index << "/" << thread_count; + return false; + } + + uint32_t thread_id; + if (!thread->GetThreadID(&thread_id)) { + BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " << + thread_index << "/" << thread_count; + return false; + } + + if (GetThreadByID(thread_id)) { + // Another thread with this ID is already in the list. Data error. + BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " << + HexString(thread_id) << " at thread " << + thread_index << "/" << thread_count; + return false; + } + id_to_thread_map_[thread_id] = thread; + } + + threads_ = threads.release(); + } + + thread_count_ = thread_count; + + valid_ = true; + return true; +} + + +MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index) + const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex"; + return NULL; + } + + if (index >= thread_count_) { + BPLOG(ERROR) << "MinidumpThreadList index out of range: " << + index << "/" << thread_count_; + return NULL; + } + + return &(*threads_)[index]; +} + + +MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) { + // Don't check valid_. Read calls this method before everything is + // validated. It is safe to not check valid_ here. + return id_to_thread_map_[thread_id]; +} + + +void MinidumpThreadList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data"; + return; + } + + printf("MinidumpThreadList\n"); + printf(" thread_count = %d\n", thread_count_); + printf("\n"); + + for (unsigned int thread_index = 0; + thread_index < thread_count_; + ++thread_index) { + printf("thread[%d]\n", thread_index); + + (*threads_)[thread_index].Print(); + } +} + + +// +// MinidumpModule +// + + +uint32_t MinidumpModule::max_cv_bytes_ = 32768; +uint32_t MinidumpModule::max_misc_bytes_ = 32768; + + +MinidumpModule::MinidumpModule(Minidump* minidump) + : MinidumpObject(minidump), + module_valid_(false), + has_debug_info_(false), + module_(), + name_(NULL), + cv_record_(NULL), + cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE), + misc_record_(NULL) { +} + + +MinidumpModule::~MinidumpModule() { + delete name_; + delete cv_record_; + delete misc_record_; +} + + +bool MinidumpModule::Read() { + // Invalidate cached data. + delete name_; + name_ = NULL; + delete cv_record_; + cv_record_ = NULL; + cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE; + delete misc_record_; + misc_record_ = NULL; + + module_valid_ = false; + has_debug_info_ = false; + valid_ = false; + + if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) { + BPLOG(ERROR) << "MinidumpModule cannot read module"; + return false; + } + + if (minidump_->swap()) { + Swap(&module_.base_of_image); + Swap(&module_.size_of_image); + Swap(&module_.checksum); + Swap(&module_.time_date_stamp); + Swap(&module_.module_name_rva); + Swap(&module_.version_info.signature); + Swap(&module_.version_info.struct_version); + Swap(&module_.version_info.file_version_hi); + Swap(&module_.version_info.file_version_lo); + Swap(&module_.version_info.product_version_hi); + Swap(&module_.version_info.product_version_lo); + Swap(&module_.version_info.file_flags_mask); + Swap(&module_.version_info.file_flags); + Swap(&module_.version_info.file_os); + Swap(&module_.version_info.file_type); + Swap(&module_.version_info.file_subtype); + Swap(&module_.version_info.file_date_hi); + Swap(&module_.version_info.file_date_lo); + Swap(&module_.cv_record); + Swap(&module_.misc_record); + // Don't swap reserved fields because their contents are unknown (as + // are their proper widths). + } + + // Check for base + size overflow or undersize. + if (module_.size_of_image == 0 || + module_.size_of_image > + numeric_limits::max() - module_.base_of_image) { + BPLOG(ERROR) << "MinidumpModule has a module problem, " << + HexString(module_.base_of_image) << "+" << + HexString(module_.size_of_image); + return false; + } + + module_valid_ = true; + return true; +} + + +bool MinidumpModule::ReadAuxiliaryData() { + if (!module_valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData"; + return false; + } + + // Each module must have a name. + name_ = minidump_->ReadString(module_.module_name_rva); + if (!name_) { + BPLOG(ERROR) << "MinidumpModule could not read name"; + return false; + } + + // At this point, we have enough info for the module to be valid. + valid_ = true; + + // CodeView and miscellaneous debug records are only required if the + // module indicates that they exist. + if (module_.cv_record.data_size && !GetCVRecord(NULL)) { + BPLOG(ERROR) << "MinidumpModule has no CodeView record, " + "but one was expected"; + return false; + } + + if (module_.misc_record.data_size && !GetMiscRecord(NULL)) { + BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, " + "but one was expected"; + return false; + } + + has_debug_info_ = true; + return true; +} + + +string MinidumpModule::code_file() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for code_file"; + return ""; + } + + return *name_; +} + + +string MinidumpModule::code_identifier() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier"; + return ""; + } + + if (!has_debug_info_) + return ""; + + MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo(); + if (!minidump_system_info) { + BPLOG(ERROR) << "MinidumpModule code_identifier requires " + "MinidumpSystemInfo"; + return ""; + } + + const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); + if (!raw_system_info) { + BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo"; + return ""; + } + + string identifier; + + switch (raw_system_info->platform_id) { + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: { + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + char identifier_string[17]; + snprintf(identifier_string, sizeof(identifier_string), "%08X%x", + module_.time_date_stamp, module_.size_of_image); + identifier = identifier_string; + break; + } + + case MD_OS_ANDROID: + case MD_OS_FUCHSIA: + case MD_OS_LINUX: { + // If ELF CodeView data is present, return the debug id. + if (cv_record_ && cv_record_signature_ == MD_CVINFOELF_SIGNATURE) { + const MDCVInfoELF* cv_record_elf = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE); + + for (unsigned int build_id_index = 0; + build_id_index < (cv_record_->size() - MDCVInfoELF_minsize); + ++build_id_index) { + char hexbyte[3]; + snprintf(hexbyte, sizeof(hexbyte), "%02x", + cv_record_elf->build_id[build_id_index]); + identifier += hexbyte; + } + break; + } + // Otherwise fall through to the case below. + BP_FALLTHROUGH; + } + + case MD_OS_MAC_OS_X: + case MD_OS_IOS: + case MD_OS_SOLARIS: + case MD_OS_NACL: + case MD_OS_PS3: { + // TODO(mmentovai): support uuid extension if present, otherwise fall + // back to version (from LC_ID_DYLIB?), otherwise fall back to something + // else. + identifier = "id"; + break; + } + + default: { + // Without knowing what OS generated the dump, we can't generate a good + // identifier. Return an empty string, signalling failure. + BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, " + "found " << HexString(raw_system_info->platform_id); + break; + } + } + + return identifier; +} + + +string MinidumpModule::debug_file() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for debug_file"; + return ""; + } + + if (!has_debug_info_) + return ""; + + string file; + // Prefer the CodeView record if present. + if (cv_record_) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + // It's actually an MDCVInfoPDB70 structure. + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + + // GetCVRecord guarantees pdb_file_name is null-terminated. + file = reinterpret_cast(cv_record_70->pdb_file_name); + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { + // It's actually an MDCVInfoPDB20 structure. + const MDCVInfoPDB20* cv_record_20 = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); + + // GetCVRecord guarantees pdb_file_name is null-terminated. + file = reinterpret_cast(cv_record_20->pdb_file_name); + } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) { + // It's actually an MDCVInfoELF structure. + assert(reinterpret_cast(&(*cv_record_)[0])-> + cv_signature == MD_CVINFOELF_SIGNATURE); + + // For MDCVInfoELF, the debug file is the code file. + file = *name_; + } + + // If there's a CodeView record but it doesn't match a known signature, + // try the miscellaneous record. + } + + if (file.empty()) { + // No usable CodeView record. Try the miscellaneous debug record. + if (misc_record_) { + const MDImageDebugMisc* misc_record = + reinterpret_cast(&(*misc_record_)[0]); + if (!misc_record->unicode) { + // If it's not Unicode, just stuff it into the string. It's unclear + // if misc_record->data is 0-terminated, so use an explicit size. + file = string( + reinterpret_cast(misc_record->data), + module_.misc_record.data_size - MDImageDebugMisc_minsize); + } else { + // There's a misc_record but it encodes the debug filename in UTF-16. + // (Actually, because miscellaneous records are so old, it's probably + // UCS-2.) Convert it to UTF-8 for congruity with the other strings + // that this method (and all other methods in the Minidump family) + // return. + + size_t bytes = + module_.misc_record.data_size - MDImageDebugMisc_minsize; + if (bytes % 2 == 0) { + size_t utf16_words = bytes / 2; + + // UTF16ToUTF8 expects a vector, so create a temporary one + // and copy the UTF-16 data into it. + vector string_utf16(utf16_words); + if (utf16_words) + memcpy(&string_utf16[0], &misc_record->data, bytes); + + // GetMiscRecord already byte-swapped the data[] field if it contains + // UTF-16, so pass false as the swap argument. + scoped_ptr new_file(UTF16ToUTF8(string_utf16, false)); + if (new_file.get() != nullptr) { + file = *new_file; + } + } + } + } + } + + // Relatively common case + BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine " + "debug_file for " << *name_; + + return file; +} + +static string guid_and_age_to_debug_id(const MDGUID& guid, + uint32_t age) { + char identifier_string[41]; + snprintf(identifier_string, sizeof(identifier_string), + "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", + guid.data1, + guid.data2, + guid.data3, + guid.data4[0], + guid.data4[1], + guid.data4[2], + guid.data4[3], + guid.data4[4], + guid.data4[5], + guid.data4[6], + guid.data4[7], + age); + return identifier_string; +} + +string MinidumpModule::debug_identifier() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier"; + return ""; + } + + if (!has_debug_info_) + return ""; + + string identifier; + + // Use the CodeView record if present. + if (cv_record_) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + // It's actually an MDCVInfoPDB70 structure. + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + identifier = guid_and_age_to_debug_id(cv_record_70->signature, + cv_record_70->age); + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { + // It's actually an MDCVInfoPDB20 structure. + const MDCVInfoPDB20* cv_record_20 = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); + + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + char identifier_string[17]; + snprintf(identifier_string, sizeof(identifier_string), + "%08X%x", cv_record_20->signature, cv_record_20->age); + identifier = identifier_string; + } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) { + // It's actually an MDCVInfoELF structure. + const MDCVInfoELF* cv_record_elf = + reinterpret_cast(&(*cv_record_)[0]); + assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE); + + // For backwards-compatibility, stuff as many bytes as will fit into + // a MDGUID and use the MS symbol server format as MDCVInfoPDB70 does + // with age = 0. Historically Breakpad would do this during dump + // writing to fit the build id data into a MDCVInfoPDB70 struct. + // The full build id is available by calling code_identifier. + MDGUID guid = {0}; + memcpy(&guid, &cv_record_elf->build_id, + std::min(cv_record_->size() - MDCVInfoELF_minsize, + sizeof(MDGUID))); + identifier = guid_and_age_to_debug_id(guid, 0); + } + } + + // TODO(mmentovai): if there's no usable CodeView record, there might be a + // miscellaneous debug record. It only carries a filename, though, and no + // identifier. I'm not sure what the right thing to do for the identifier + // is in that case, but I don't expect to find many modules without a + // CodeView record (or some other Breakpad extension structure in place of + // a CodeView record). Treat it as an error (empty identifier) for now. + + // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier(). + + // Relatively common case + BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine " + "debug_identifier for " << *name_; + + return identifier; +} + + +string MinidumpModule::version() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for version"; + return ""; + } + + string version; + + if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE && + module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) { + char version_string[24]; + snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u", + module_.version_info.file_version_hi >> 16, + module_.version_info.file_version_hi & 0xffff, + module_.version_info.file_version_lo >> 16, + module_.version_info.file_version_lo & 0xffff); + version = version_string; + } + + // TODO(mmentovai): possibly support other struct types in place of + // the one used with MD_VSFIXEDFILEINFO_SIGNATURE. We can possibly use + // a different structure that better represents versioning facilities on + // Mac OS X and Linux, instead of forcing them to adhere to the dotted + // quad of 16-bit ints that Windows uses. + + BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine " + "version for " << *name_; + + return version; +} + + +CodeModule* MinidumpModule::Copy() const { + return new BasicCodeModule(this); +} + + +uint64_t MinidumpModule::shrink_down_delta() const { + return 0; +} + +void MinidumpModule::SetShrinkDownDelta(uint64_t shrink_down_delta) { + // Not implemented + assert(false); +} + + +const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { + if (!module_valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord"; + return NULL; + } + + if (!cv_record_) { + // This just guards against 0-sized CodeView records; more specific checks + // are used when the signature is checked against various structure types. + if (module_.cv_record.data_size == 0) { + return NULL; + } + + if (!minidump_->SeekSet(module_.cv_record.rva)) { + BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record"; + return NULL; + } + + if (module_.cv_record.data_size > max_cv_bytes_) { + BPLOG(ERROR) << "MinidumpModule CodeView record size " << + module_.cv_record.data_size << " exceeds maximum " << + max_cv_bytes_; + return NULL; + } + + // Allocating something that will be accessed as MDCVInfoPDB70 or + // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment + // problems. x86 and ppc are able to cope, though. This allocation + // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are + // variable-sized due to their pdb_file_name fields; these structures + // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating + // them as such would result in incomplete structures or overruns. + scoped_ptr< vector > cv_record( + new vector(module_.cv_record.data_size)); + + if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) { + BPLOG(ERROR) << "MinidumpModule could not read CodeView record"; + return NULL; + } + + uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE; + if (module_.cv_record.data_size > sizeof(signature)) { + MDCVInfoPDB70* cv_record_signature = + reinterpret_cast(&(*cv_record)[0]); + signature = cv_record_signature->cv_signature; + if (minidump_->swap()) + Swap(&signature); + } + + if (signature == MD_CVINFOPDB70_SIGNATURE) { + // Now that the structure type is known, recheck the size, + // ensuring at least one byte for the null terminator. + if (MDCVInfoPDB70_minsize + 1 > module_.cv_record.data_size) { + BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " << + MDCVInfoPDB70_minsize << " > " << + module_.cv_record.data_size; + return NULL; + } + + if (minidump_->swap()) { + MDCVInfoPDB70* cv_record_70 = + reinterpret_cast(&(*cv_record)[0]); + Swap(&cv_record_70->cv_signature); + Swap(&cv_record_70->signature); + Swap(&cv_record_70->age); + // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit + // quantities. (It's a path, is it UTF-8?) + } + + // The last field of either structure is null-terminated 8-bit character + // data. Ensure that it's null-terminated. + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { + BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not " + "0-terminated"; + return NULL; + } + } else if (signature == MD_CVINFOPDB20_SIGNATURE) { + // Now that the structure type is known, recheck the size, + // ensuring at least one byte for the null terminator. + if (MDCVInfoPDB20_minsize + 1 > module_.cv_record.data_size) { + BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " << + MDCVInfoPDB20_minsize << " > " << + module_.cv_record.data_size; + return NULL; + } + if (minidump_->swap()) { + MDCVInfoPDB20* cv_record_20 = + reinterpret_cast(&(*cv_record)[0]); + Swap(&cv_record_20->cv_header.signature); + Swap(&cv_record_20->cv_header.offset); + Swap(&cv_record_20->signature); + Swap(&cv_record_20->age); + // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit + // quantities. (It's a path, is it UTF-8?) + } + + // The last field of either structure is null-terminated 8-bit character + // data. Ensure that it's null-terminated. + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { + BPLOG(ERROR) << "MindumpModule CodeView2 record string is not " + "0-terminated"; + return NULL; + } + } else if (signature == MD_CVINFOELF_SIGNATURE) { + // Now that the structure type is known, recheck the size. + if (MDCVInfoELF_minsize > module_.cv_record.data_size) { + BPLOG(ERROR) << "MinidumpModule CodeViewELF record size mismatch, " << + MDCVInfoELF_minsize << " > " << + module_.cv_record.data_size; + return NULL; + } + if (minidump_->swap()) { + MDCVInfoELF* cv_record_elf = + reinterpret_cast(&(*cv_record)[0]); + Swap(&cv_record_elf->cv_signature); + } + } + + // If the signature doesn't match something above, it's not something + // that Breakpad can presently handle directly. Because some modules in + // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE, + // don't bail out here - allow the data to be returned to the user, + // although byte-swapping can't be done. + + // Store the vector type because that's how storage was allocated, but + // return it casted to uint8_t*. + cv_record_ = cv_record.release(); + cv_record_signature_ = signature; + } + + if (size) + *size = module_.cv_record.data_size; + + return &(*cv_record_)[0]; +} + + +const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { + if (!module_valid_) { + BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord"; + return NULL; + } + + if (!misc_record_) { + if (module_.misc_record.data_size == 0) { + return NULL; + } + + if (MDImageDebugMisc_minsize > module_.misc_record.data_size) { + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record " + "size mismatch, " << MDImageDebugMisc_minsize << " > " << + module_.misc_record.data_size; + return NULL; + } + + if (!minidump_->SeekSet(module_.misc_record.rva)) { + BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous " + "debugging record"; + return NULL; + } + + if (module_.misc_record.data_size > max_misc_bytes_) { + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " << + module_.misc_record.data_size << " exceeds maximum " << + max_misc_bytes_; + return NULL; + } + + // Allocating something that will be accessed as MDImageDebugMisc but + // is allocated as uint8_t[] can cause alignment problems. x86 and + // ppc are able to cope, though. This allocation style is needed + // because the MDImageDebugMisc is variable-sized due to its data field; + // this structure is not MDImageDebugMisc_minsize and treating it as such + // would result in an incomplete structure or an overrun. + scoped_ptr< vector > misc_record_mem( + new vector(module_.misc_record.data_size)); + MDImageDebugMisc* misc_record = + reinterpret_cast(&(*misc_record_mem)[0]); + + if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) { + BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging " + "record"; + return NULL; + } + + if (minidump_->swap()) { + Swap(&misc_record->data_type); + Swap(&misc_record->length); + // Don't swap misc_record.unicode because it's an 8-bit quantity. + // Don't swap the reserved fields for the same reason, and because + // they don't contain any valid data. + if (misc_record->unicode) { + // There is a potential alignment problem, but shouldn't be a problem + // in practice due to the layout of MDImageDebugMisc. + uint16_t* data16 = reinterpret_cast(&(misc_record->data)); + size_t dataBytes = module_.misc_record.data_size - + MDImageDebugMisc_minsize; + Swap(data16, dataBytes); + } + } + + if (module_.misc_record.data_size != misc_record->length) { + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data " + "size mismatch, " << module_.misc_record.data_size << + " != " << misc_record->length; + return NULL; + } + + // Store the vector type because that's how storage was allocated, but + // return it casted to MDImageDebugMisc*. + misc_record_ = misc_record_mem.release(); + } + + if (size) + *size = module_.misc_record.data_size; + + return reinterpret_cast(&(*misc_record_)[0]); +} + + +void MinidumpModule::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpModule cannot print invalid data"; + return; + } + + printf("MDRawModule\n"); + printf(" base_of_image = 0x%" PRIx64 "\n", + module_.base_of_image); + printf(" size_of_image = 0x%x\n", + module_.size_of_image); + printf(" checksum = 0x%x\n", + module_.checksum); + printf(" time_date_stamp = 0x%x %s\n", + module_.time_date_stamp, + TimeTToUTCString(module_.time_date_stamp).c_str()); + printf(" module_name_rva = 0x%x\n", + module_.module_name_rva); + printf(" version_info.signature = 0x%x\n", + module_.version_info.signature); + printf(" version_info.struct_version = 0x%x\n", + module_.version_info.struct_version); + printf(" version_info.file_version = 0x%x:0x%x\n", + module_.version_info.file_version_hi, + module_.version_info.file_version_lo); + printf(" version_info.product_version = 0x%x:0x%x\n", + module_.version_info.product_version_hi, + module_.version_info.product_version_lo); + printf(" version_info.file_flags_mask = 0x%x\n", + module_.version_info.file_flags_mask); + printf(" version_info.file_flags = 0x%x\n", + module_.version_info.file_flags); + printf(" version_info.file_os = 0x%x\n", + module_.version_info.file_os); + printf(" version_info.file_type = 0x%x\n", + module_.version_info.file_type); + printf(" version_info.file_subtype = 0x%x\n", + module_.version_info.file_subtype); + printf(" version_info.file_date = 0x%x:0x%x\n", + module_.version_info.file_date_hi, + module_.version_info.file_date_lo); + printf(" cv_record.data_size = %d\n", + module_.cv_record.data_size); + printf(" cv_record.rva = 0x%x\n", + module_.cv_record.rva); + printf(" misc_record.data_size = %d\n", + module_.misc_record.data_size); + printf(" misc_record.rva = 0x%x\n", + module_.misc_record.rva); + + printf(" (code_file) = \"%s\"\n", code_file().c_str()); + printf(" (code_identifier) = \"%s\"\n", + code_identifier().c_str()); + + uint32_t cv_record_size; + const uint8_t *cv_record = GetCVRecord(&cv_record_size); + if (cv_record) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast(cv_record); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + + printf(" (cv_record).cv_signature = 0x%x\n", + cv_record_70->cv_signature); + printf(" (cv_record).signature = %s\n", + MDGUIDToString(cv_record_70->signature).c_str()); + printf(" (cv_record).age = %d\n", + cv_record_70->age); + printf(" (cv_record).pdb_file_name = \"%s\"\n", + cv_record_70->pdb_file_name); + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { + const MDCVInfoPDB20* cv_record_20 = + reinterpret_cast(cv_record); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); + + printf(" (cv_record).cv_header.signature = 0x%x\n", + cv_record_20->cv_header.signature); + printf(" (cv_record).cv_header.offset = 0x%x\n", + cv_record_20->cv_header.offset); + printf(" (cv_record).signature = 0x%x %s\n", + cv_record_20->signature, + TimeTToUTCString(cv_record_20->signature).c_str()); + printf(" (cv_record).age = %d\n", + cv_record_20->age); + printf(" (cv_record).pdb_file_name = \"%s\"\n", + cv_record_20->pdb_file_name); + } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) { + const MDCVInfoELF* cv_record_elf = + reinterpret_cast(cv_record); + assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE); + + printf(" (cv_record).cv_signature = 0x%x\n", + cv_record_elf->cv_signature); + printf(" (cv_record).build_id = "); + for (unsigned int build_id_index = 0; + build_id_index < (cv_record_size - MDCVInfoELF_minsize); + ++build_id_index) { + printf("%02x", cv_record_elf->build_id[build_id_index]); + } + printf("\n"); + } else { + printf(" (cv_record) = "); + for (unsigned int cv_byte_index = 0; + cv_byte_index < cv_record_size; + ++cv_byte_index) { + printf("%02x", cv_record[cv_byte_index]); + } + printf("\n"); + } + } else { + printf(" (cv_record) = (null)\n"); + } + + const MDImageDebugMisc* misc_record = GetMiscRecord(NULL); + if (misc_record) { + printf(" (misc_record).data_type = 0x%x\n", + misc_record->data_type); + printf(" (misc_record).length = 0x%x\n", + misc_record->length); + printf(" (misc_record).unicode = %d\n", + misc_record->unicode); + if (misc_record->unicode) { + string misc_record_data_utf8; + ConvertUTF16BufferToUTF8String( + reinterpret_cast(misc_record->data), + misc_record->length - offsetof(MDImageDebugMisc, data), + &misc_record_data_utf8, + false); // already swapped + printf(" (misc_record).data = \"%s\"\n", + misc_record_data_utf8.c_str()); + } else { + printf(" (misc_record).data = \"%s\"\n", + misc_record->data); + } + } else { + printf(" (misc_record) = (null)\n"); + } + + printf(" (debug_file) = \"%s\"\n", debug_file().c_str()); + printf(" (debug_identifier) = \"%s\"\n", + debug_identifier().c_str()); + printf(" (version) = \"%s\"\n", version().c_str()); + printf("\n"); +} + + +// +// MinidumpModuleList +// + + +uint32_t MinidumpModuleList::max_modules_ = 2048; + + +MinidumpModuleList::MinidumpModuleList(Minidump* minidump) + : MinidumpStream(minidump), + range_map_(new RangeMap()), + modules_(NULL), + module_count_(0) { + MDOSPlatform platform; + if (minidump_->GetPlatform(&platform) && + (platform == MD_OS_ANDROID || platform == MD_OS_LINUX)) { + range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + } +} + + +MinidumpModuleList::~MinidumpModuleList() { + delete range_map_; + delete modules_; +} + + +bool MinidumpModuleList::Read(uint32_t expected_size) { + // Invalidate cached data. + range_map_->Clear(); + delete modules_; + modules_ = NULL; + module_count_ = 0; + + valid_ = false; + + uint32_t module_count; + if (expected_size < sizeof(module_count)) { + BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " << + expected_size << " < " << sizeof(module_count); + return false; + } + if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) { + BPLOG(ERROR) << "MinidumpModuleList could not read module count"; + return false; + } + + if (minidump_->swap()) + Swap(&module_count); + + if (module_count > numeric_limits::max() / MD_MODULE_SIZE) { + BPLOG(ERROR) << "MinidumpModuleList module count " << module_count << + " would cause multiplication overflow"; + return false; + } + + if (expected_size != sizeof(module_count) + + module_count * MD_MODULE_SIZE) { + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(module_count) + 4 + + module_count * MD_MODULE_SIZE) { + uint32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded " + "bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size << + " != " << sizeof(module_count) + + module_count * MD_MODULE_SIZE; + return false; + } + } + + if (module_count > max_modules_) { + BPLOG(ERROR) << "MinidumpModuleList count " << module_count << + " exceeds maximum " << max_modules_; + return false; + } + + if (module_count != 0) { + scoped_ptr modules( + new MinidumpModules(module_count, MinidumpModule(minidump_))); + + for (uint32_t module_index = 0; module_index < module_count; + ++module_index) { + MinidumpModule* module = &(*modules)[module_index]; + + // Assume that the file offset is correct after the last read. + if (!module->Read()) { + BPLOG(ERROR) << "MinidumpModuleList could not read module " << + module_index << "/" << module_count; + return false; + } + } + + // Loop through the module list once more to read additional data and + // build the range map. This is done in a second pass because + // MinidumpModule::ReadAuxiliaryData seeks around, and if it were + // included in the loop above, additional seeks would be needed where + // none are now to read contiguous data. + uint64_t last_end_address = 0; + for (uint32_t module_index = 0; module_index < module_count; + ++module_index) { + MinidumpModule& module = (*modules)[module_index]; + + // ReadAuxiliaryData fails if any data that the module indicates should + // exist is missing, but we treat some such cases as valid anyway. See + // issue #222: if a debugging record is of a format that's too large to + // handle, it shouldn't render the entire dump invalid. Check module + // validity before giving up. + if (!module.ReadAuxiliaryData() && !module.valid()) { + BPLOG(ERROR) << "MinidumpModuleList could not read required module " + "auxiliary data for module " << + module_index << "/" << module_count; + return false; + } + + // It is safe to use module->code_file() after successfully calling + // module->ReadAuxiliaryData or noting that the module is valid. + + uint64_t base_address = module.base_address(); + uint64_t module_size = module.size(); + if (base_address == static_cast(-1)) { + BPLOG(ERROR) << "MinidumpModuleList found bad base address for module " + << module_index << "/" << module_count << ", " + << module.code_file(); + return false; + } + + // Some minidumps have additional modules in the list that are duplicates. + // Ignore them. See https://crbug.com/838322 + uint32_t existing_module_index; + if (range_map_->RetrieveRange(base_address, &existing_module_index, + nullptr, nullptr, nullptr) && + existing_module_index < module_count) { + const MinidumpModule& existing_module = + (*modules)[existing_module_index]; + if (existing_module.base_address() == module.base_address() && + existing_module.size() == module.size() && + existing_module.code_file() == module.code_file() && + existing_module.code_identifier() == module.code_identifier()) { + continue; + } + } + + const bool is_android = minidump_->IsAndroid(); + if (!StoreRange(module, base_address, module_index, module_count, + is_android)) { + if (!is_android || base_address >= last_end_address) { + BPLOG(ERROR) << "MinidumpModuleList could not store module " + << module_index << "/" << module_count << ", " + << module.code_file() << ", " << HexString(base_address) + << "+" << HexString(module_size); + return false; + } + + // If failed due to apparent range overlap the cause may be the client + // correction applied for Android packed relocations. If this is the + // case, back out the client correction and retry. + assert(is_android); + module_size -= last_end_address - base_address; + base_address = last_end_address; + if (!range_map_->StoreRange(base_address, module_size, module_index)) { + BPLOG(ERROR) << "MinidumpModuleList could not store module " + << module_index << "/" << module_count << ", " + << module.code_file() << ", " << HexString(base_address) + << "+" << HexString(module_size) << ", after adjusting"; + return false; + } + } + last_end_address = base_address + module_size; + } + + modules_ = modules.release(); + } + + module_count_ = module_count; + + valid_ = true; + return true; +} + +bool MinidumpModuleList::StoreRange(const MinidumpModule& module, + uint64_t base_address, + uint32_t module_index, + uint32_t module_count, + bool is_android) { + if (range_map_->StoreRange(base_address, module.size(), module_index)) + return true; + + // Android's shared memory implementation /dev/ashmem can contain duplicate + // entries for JITted code, so ignore these. + // TODO(wfh): Remove this code when Android is fixed. + // See https://crbug.com/439531 + if (is_android && IsDevAshmem(module.code_file())) { + BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module " + << module_index << "/" << module_count << ", " + << module.code_file() << ", " << HexString(base_address) << "+" + << HexString(module.size()); + return true; + } + + return false; +} + +const MinidumpModule* MinidumpModuleList::GetModuleForAddress( + uint64_t address) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress"; + return NULL; + } + + unsigned int module_index; + if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + BPLOG(INFO) << "MinidumpModuleList has no module at " << + HexString(address); + return NULL; + } + + return GetModuleAtIndex(module_index); +} + + +const MinidumpModule* MinidumpModuleList::GetMainModule() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule"; + return NULL; + } + + // The main code module is the first one present in a minidump file's + // MDRawModuleList. + return GetModuleAtIndex(0); +} + + +const MinidumpModule* MinidumpModuleList::GetModuleAtSequence( + unsigned int sequence) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence"; + return NULL; + } + + if (sequence >= module_count_) { + BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " << + sequence << "/" << module_count_; + return NULL; + } + + unsigned int module_index; + if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, + NULL /* base */, NULL /* delta */, + NULL /* size */)) { + BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence; + return NULL; + } + + return GetModuleAtIndex(module_index); +} + + +const MinidumpModule* MinidumpModuleList::GetModuleAtIndex( + unsigned int index) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex"; + return NULL; + } + + if (index >= module_count_) { + BPLOG(ERROR) << "MinidumpModuleList index out of range: " << + index << "/" << module_count_; + return NULL; + } + + return &(*modules_)[index]; +} + + +const CodeModules* MinidumpModuleList::Copy() const { + return new BasicCodeModules(this, range_map_->GetMergeStrategy()); +} + +vector > +MinidumpModuleList::GetShrunkRangeModules() const { + return vector >(); +} + +void MinidumpModuleList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data"; + return; + } + + printf("MinidumpModuleList\n"); + printf(" module_count = %d\n", module_count_); + printf("\n"); + + for (unsigned int module_index = 0; + module_index < module_count_; + ++module_index) { + printf("module[%d]\n", module_index); + + (*modules_)[module_index].Print(); + } +} + + +// +// MinidumpMemoryList +// + + +uint32_t MinidumpMemoryList::max_regions_ = 4096; + + +MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump) + : MinidumpStream(minidump), + range_map_(new RangeMap()), + descriptors_(NULL), + regions_(NULL), + region_count_(0) { +} + + +MinidumpMemoryList::~MinidumpMemoryList() { + delete range_map_; + delete descriptors_; + delete regions_; +} + + +bool MinidumpMemoryList::Read(uint32_t expected_size) { + // Invalidate cached data. + delete descriptors_; + descriptors_ = NULL; + delete regions_; + regions_ = NULL; + range_map_->Clear(); + region_count_ = 0; + + valid_ = false; + + uint32_t region_count; + if (expected_size < sizeof(region_count)) { + BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " << + expected_size << " < " << sizeof(region_count); + return false; + } + if (!minidump_->ReadBytes(®ion_count, sizeof(region_count))) { + BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count"; + return false; + } + + if (minidump_->swap()) + Swap(®ion_count); + + if (region_count > + numeric_limits::max() / sizeof(MDMemoryDescriptor)) { + BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count << + " would cause multiplication overflow"; + return false; + } + + if (expected_size != sizeof(region_count) + + region_count * sizeof(MDMemoryDescriptor)) { + // may be padded with 4 bytes on 64bit ABIs for alignment + if (expected_size == sizeof(region_count) + 4 + + region_count * sizeof(MDMemoryDescriptor)) { + uint32_t useless; + if (!minidump_->ReadBytes(&useless, 4)) { + BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded " + "bytes"; + return false; + } + } else { + BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size << + " != " << sizeof(region_count) + + region_count * sizeof(MDMemoryDescriptor); + return false; + } + } + + if (region_count > max_regions_) { + BPLOG(ERROR) << "MinidumpMemoryList count " << region_count << + " exceeds maximum " << max_regions_; + return false; + } + + if (region_count != 0) { + scoped_ptr descriptors( + new MemoryDescriptors(region_count)); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!minidump_->ReadBytes(&(*descriptors)[0], + sizeof(MDMemoryDescriptor) * region_count)) { + BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list"; + return false; + } + + scoped_ptr regions( + new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_))); + + for (unsigned int region_index = 0; + region_index < region_count; + ++region_index) { + MDMemoryDescriptor* descriptor = &(*descriptors)[region_index]; + + if (minidump_->swap()) + Swap(descriptor); + + uint64_t base_address = descriptor->start_of_memory_range; + uint32_t region_size = descriptor->memory.data_size; + + // Check for base + size overflow or undersize. + if (region_size == 0 || + region_size > numeric_limits::max() - base_address) { + BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " << + " region " << region_index << "/" << region_count << + ", " << HexString(base_address) << "+" << + HexString(region_size); + return false; + } + + if (!range_map_->StoreRange(base_address, region_size, region_index)) { + BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " << + region_index << "/" << region_count << ", " << + HexString(base_address) << "+" << + HexString(region_size); + return false; + } + + (*regions)[region_index].SetDescriptor(descriptor); + } + + descriptors_ = descriptors.release(); + regions_ = regions.release(); + } + + region_count_ = region_count; + + valid_ = true; + return true; +} + + +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex( + unsigned int index) { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex"; + return NULL; + } + + if (index >= region_count_) { + BPLOG(ERROR) << "MinidumpMemoryList index out of range: " << + index << "/" << region_count_; + return NULL; + } + + return &(*regions_)[index]; +} + + +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress( + uint64_t address) { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress"; + return NULL; + } + + unsigned int region_index; + if (!range_map_->RetrieveRange(address, ®ion_index, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + BPLOG(INFO) << "MinidumpMemoryList has no memory region at " << + HexString(address); + return NULL; + } + + return GetMemoryRegionAtIndex(region_index); +} + + +void MinidumpMemoryList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data"; + return; + } + + printf("MinidumpMemoryList\n"); + printf(" region_count = %d\n", region_count_); + printf("\n"); + + for (unsigned int region_index = 0; + region_index < region_count_; + ++region_index) { + MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index]; + printf("region[%d]\n", region_index); + printf("MDMemoryDescriptor\n"); + printf(" start_of_memory_range = 0x%" PRIx64 "\n", + descriptor->start_of_memory_range); + printf(" memory.data_size = 0x%x\n", descriptor->memory.data_size); + printf(" memory.rva = 0x%x\n", descriptor->memory.rva); + MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index); + if (region) { + printf("Memory\n"); + region->Print(); + } else { + printf("No memory\n"); + } + printf("\n"); + } +} + + +// +// MinidumpException +// + + +MinidumpException::MinidumpException(Minidump* minidump) + : MinidumpStream(minidump), + exception_(), + context_(NULL) { +} + + +MinidumpException::~MinidumpException() { + delete context_; +} + + +bool MinidumpException::Read(uint32_t expected_size) { + // Invalidate cached data. + delete context_; + context_ = NULL; + + valid_ = false; + + if (expected_size != sizeof(exception_)) { + BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size << + " != " << sizeof(exception_); + return false; + } + + if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) { + BPLOG(ERROR) << "MinidumpException cannot read exception"; + return false; + } + + if (minidump_->swap()) { + Swap(&exception_.thread_id); + // exception_.__align is for alignment only and does not need to be + // swapped. + Swap(&exception_.exception_record.exception_code); + Swap(&exception_.exception_record.exception_flags); + Swap(&exception_.exception_record.exception_record); + Swap(&exception_.exception_record.exception_address); + Swap(&exception_.exception_record.number_parameters); + // exception_.exception_record.__align is for alignment only and does not + // need to be swapped. + for (unsigned int parameter_index = 0; + parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS; + ++parameter_index) { + Swap(&exception_.exception_record.exception_information[parameter_index]); + } + Swap(&exception_.thread_context); + } + + valid_ = true; + return true; +} + + +bool MinidumpException::GetThreadID(uint32_t *thread_id) const { + BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires " + "|thread_id|"; + assert(thread_id); + *thread_id = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID"; + return false; + } + + *thread_id = exception_.thread_id; + return true; +} + + +MinidumpContext* MinidumpException::GetContext() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpException for GetContext"; + return NULL; + } + + if (!context_) { + if (!minidump_->SeekSet(exception_.thread_context.rva)) { + BPLOG(ERROR) << "MinidumpException cannot seek to context"; + return NULL; + } + + scoped_ptr context(new MinidumpContext(minidump_)); + + // Don't log as an error if we can still fall back on the thread's context + // (which must be possible if we got this far.) + if (!context->Read(exception_.thread_context.data_size)) { + BPLOG(INFO) << "MinidumpException cannot read context"; + return NULL; + } + + context_ = context.release(); + } + + return context_; +} + + +void MinidumpException::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpException cannot print invalid data"; + return; + } + + printf("MDException\n"); + printf(" thread_id = 0x%x\n", + exception_.thread_id); + printf(" exception_record.exception_code = 0x%x\n", + exception_.exception_record.exception_code); + printf(" exception_record.exception_flags = 0x%x\n", + exception_.exception_record.exception_flags); + printf(" exception_record.exception_record = 0x%" PRIx64 "\n", + exception_.exception_record.exception_record); + printf(" exception_record.exception_address = 0x%" PRIx64 "\n", + exception_.exception_record.exception_address); + printf(" exception_record.number_parameters = %d\n", + exception_.exception_record.number_parameters); + for (unsigned int parameterIndex = 0; + parameterIndex < exception_.exception_record.number_parameters; + ++parameterIndex) { + printf(" exception_record.exception_information[%2d] = 0x%" PRIx64 "\n", + parameterIndex, + exception_.exception_record.exception_information[parameterIndex]); + } + printf(" thread_context.data_size = %d\n", + exception_.thread_context.data_size); + printf(" thread_context.rva = 0x%x\n", + exception_.thread_context.rva); + MinidumpContext* context = GetContext(); + if (context) { + printf("\n"); + context->Print(); + } else { + printf(" (no context)\n"); + printf("\n"); + } +} + +// +// MinidumpAssertion +// + + +MinidumpAssertion::MinidumpAssertion(Minidump* minidump) + : MinidumpStream(minidump), + assertion_(), + expression_(), + function_(), + file_() { +} + + +MinidumpAssertion::~MinidumpAssertion() { +} + + +bool MinidumpAssertion::Read(uint32_t expected_size) { + // Invalidate cached data. + valid_ = false; + + if (expected_size != sizeof(assertion_)) { + BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size << + " != " << sizeof(assertion_); + return false; + } + + if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) { + BPLOG(ERROR) << "MinidumpAssertion cannot read assertion"; + return false; + } + + // Each of {expression, function, file} is a UTF-16 string, + // we'll convert them to UTF-8 for ease of use. + ConvertUTF16BufferToUTF8String(assertion_.expression, + sizeof(assertion_.expression), &expression_, + minidump_->swap()); + ConvertUTF16BufferToUTF8String(assertion_.function, + sizeof(assertion_.function), &function_, + minidump_->swap()); + ConvertUTF16BufferToUTF8String(assertion_.file, sizeof(assertion_.file), + &file_, minidump_->swap()); + + if (minidump_->swap()) { + Swap(&assertion_.line); + Swap(&assertion_.type); + } + + valid_ = true; + return true; +} + +void MinidumpAssertion::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data"; + return; + } + + printf("MDAssertion\n"); + printf(" expression = %s\n", + expression_.c_str()); + printf(" function = %s\n", + function_.c_str()); + printf(" file = %s\n", + file_.c_str()); + printf(" line = %u\n", + assertion_.line); + printf(" type = %u\n", + assertion_.type); + printf("\n"); +} + +// +// MinidumpSystemInfo +// + + +MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump) + : MinidumpStream(minidump), + system_info_(), + csd_version_(NULL), + cpu_vendor_(NULL) { +} + + +MinidumpSystemInfo::~MinidumpSystemInfo() { + delete csd_version_; + delete cpu_vendor_; +} + + +bool MinidumpSystemInfo::Read(uint32_t expected_size) { + // Invalidate cached data. + delete csd_version_; + csd_version_ = NULL; + delete cpu_vendor_; + cpu_vendor_ = NULL; + + valid_ = false; + + if (expected_size != sizeof(system_info_)) { + BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size << + " != " << sizeof(system_info_); + return false; + } + + if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) { + BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info"; + return false; + } + + if (minidump_->swap()) { + Swap(&system_info_.processor_architecture); + Swap(&system_info_.processor_level); + Swap(&system_info_.processor_revision); + // number_of_processors and product_type are 8-bit quantities and need no + // swapping. + Swap(&system_info_.major_version); + Swap(&system_info_.minor_version); + Swap(&system_info_.build_number); + Swap(&system_info_.platform_id); + Swap(&system_info_.csd_version_rva); + Swap(&system_info_.suite_mask); + // Don't swap the reserved2 field because its contents are unknown. + + if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 || + system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) { + for (unsigned int i = 0; i < 3; ++i) + Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]); + Swap(&system_info_.cpu.x86_cpu_info.version_information); + Swap(&system_info_.cpu.x86_cpu_info.feature_information); + Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features); + } else { + for (unsigned int i = 0; i < 2; ++i) + Swap(&system_info_.cpu.other_cpu_info.processor_features[i]); + } + } + + valid_ = true; + return true; +} + + +string MinidumpSystemInfo::GetOS() { + string os; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS"; + return os; + } + + switch (system_info_.platform_id) { + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: + os = "windows"; + break; + + case MD_OS_MAC_OS_X: + os = "mac"; + break; + + case MD_OS_IOS: + os = "ios"; + break; + + case MD_OS_LINUX: + os = "linux"; + break; + + case MD_OS_SOLARIS: + os = "solaris"; + break; + + case MD_OS_ANDROID: + os = "android"; + break; + + case MD_OS_PS3: + os = "ps3"; + break; + + case MD_OS_NACL: + os = "nacl"; + break; + + case MD_OS_FUCHSIA: + os = "fuchsia"; + break; + + default: + BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " << + HexString(system_info_.platform_id); + break; + } + + return os; +} + + +string MinidumpSystemInfo::GetCPU() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU"; + return ""; + } + + string cpu; + + switch (system_info_.processor_architecture) { + case MD_CPU_ARCHITECTURE_X86: + case MD_CPU_ARCHITECTURE_X86_WIN64: + cpu = "x86"; + break; + + case MD_CPU_ARCHITECTURE_AMD64: + cpu = "x86-64"; + break; + + case MD_CPU_ARCHITECTURE_PPC: + cpu = "ppc"; + break; + + case MD_CPU_ARCHITECTURE_PPC64: + cpu = "ppc64"; + break; + + case MD_CPU_ARCHITECTURE_SPARC: + cpu = "sparc"; + break; + + case MD_CPU_ARCHITECTURE_ARM: + cpu = "arm"; + break; + + case MD_CPU_ARCHITECTURE_ARM64: + case MD_CPU_ARCHITECTURE_ARM64_OLD: + cpu = "arm64"; + break; + + default: + BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " << + HexString(system_info_.processor_architecture); + break; + } + + return cpu; +} + + +const string* MinidumpSystemInfo::GetCSDVersion() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion"; + return NULL; + } + + if (!csd_version_) + csd_version_ = minidump_->ReadString(system_info_.csd_version_rva); + + BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read " + "CSD version"; + + return csd_version_; +} + + +const string* MinidumpSystemInfo::GetCPUVendor() { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor"; + return NULL; + } + + // CPU vendor information can only be determined from x86 minidumps. + if (!cpu_vendor_ && + (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 || + system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) { + char cpu_vendor_string[13]; + snprintf(cpu_vendor_string, sizeof(cpu_vendor_string), + "%c%c%c%c%c%c%c%c%c%c%c%c", + system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff, + system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff, + system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff, + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff); + cpu_vendor_ = new string(cpu_vendor_string); + } + + return cpu_vendor_; +} + + +void MinidumpSystemInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data"; + return; + } + + printf("MDRawSystemInfo\n"); + printf(" processor_architecture = 0x%x\n", + system_info_.processor_architecture); + printf(" processor_level = %d\n", + system_info_.processor_level); + printf(" processor_revision = 0x%x\n", + system_info_.processor_revision); + printf(" number_of_processors = %d\n", + system_info_.number_of_processors); + printf(" product_type = %d\n", + system_info_.product_type); + printf(" major_version = %d\n", + system_info_.major_version); + printf(" minor_version = %d\n", + system_info_.minor_version); + printf(" build_number = %d\n", + system_info_.build_number); + printf(" platform_id = 0x%x\n", + system_info_.platform_id); + printf(" csd_version_rva = 0x%x\n", + system_info_.csd_version_rva); + printf(" suite_mask = 0x%x\n", + system_info_.suite_mask); + if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 || + system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) { + printf(" cpu.x86_cpu_info (valid):\n"); + } else { + printf(" cpu.x86_cpu_info (invalid):\n"); + } + for (unsigned int i = 0; i < 3; ++i) { + printf(" cpu.x86_cpu_info.vendor_id[%d] = 0x%x\n", + i, system_info_.cpu.x86_cpu_info.vendor_id[i]); + } + printf(" cpu.x86_cpu_info.version_information = 0x%x\n", + system_info_.cpu.x86_cpu_info.version_information); + printf(" cpu.x86_cpu_info.feature_information = 0x%x\n", + system_info_.cpu.x86_cpu_info.feature_information); + printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n", + system_info_.cpu.x86_cpu_info.amd_extended_cpu_features); + if (system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86 && + system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86_WIN64) { + printf(" cpu.other_cpu_info (valid):\n"); + for (unsigned int i = 0; i < 2; ++i) { + printf(" cpu.other_cpu_info.processor_features[%d] = 0x%" PRIx64 "\n", + i, system_info_.cpu.other_cpu_info.processor_features[i]); + } + } + const string* csd_version = GetCSDVersion(); + if (csd_version) { + printf(" (csd_version) = \"%s\"\n", + csd_version->c_str()); + } else { + printf(" (csd_version) = (null)\n"); + } + const string* cpu_vendor = GetCPUVendor(); + if (cpu_vendor) { + printf(" (cpu_vendor) = \"%s\"\n", + cpu_vendor->c_str()); + } else { + printf(" (cpu_vendor) = (null)\n"); + } + printf("\n"); +} + + +// +// MinidumpUnloadedModule +// + + +MinidumpUnloadedModule::MinidumpUnloadedModule(Minidump* minidump) + : MinidumpObject(minidump), + module_valid_(false), + unloaded_module_(), + name_(NULL) { + +} + +MinidumpUnloadedModule::~MinidumpUnloadedModule() { + delete name_; +} + +void MinidumpUnloadedModule::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpUnloadedModule cannot print invalid data"; + return; + } + + printf("MDRawUnloadedModule\n"); + printf(" base_of_image = 0x%" PRIx64 "\n", + unloaded_module_.base_of_image); + printf(" size_of_image = 0x%x\n", + unloaded_module_.size_of_image); + printf(" checksum = 0x%x\n", + unloaded_module_.checksum); + printf(" time_date_stamp = 0x%x %s\n", + unloaded_module_.time_date_stamp, + TimeTToUTCString(unloaded_module_.time_date_stamp).c_str()); + printf(" module_name_rva = 0x%x\n", + unloaded_module_.module_name_rva); + + printf(" (code_file) = \"%s\"\n", code_file().c_str()); + printf(" (code_identifier) = \"%s\"\n", + code_identifier().c_str()); + + printf(" (debug_file) = \"%s\"\n", debug_file().c_str()); + printf(" (debug_identifier) = \"%s\"\n", + debug_identifier().c_str()); + printf(" (version) = \"%s\"\n", version().c_str()); + printf("\n"); +} + +string MinidumpUnloadedModule::code_file() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file"; + return ""; + } + + return *name_; +} + +string MinidumpUnloadedModule::code_identifier() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_identifier"; + return ""; + } + + MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo(); + if (!minidump_system_info) { + BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires " + "MinidumpSystemInfo"; + return ""; + } + + const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); + if (!raw_system_info) { + BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires " + << "MDRawSystemInfo"; + return ""; + } + + string identifier; + + switch (raw_system_info->platform_id) { + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: { + // Use the same format that the MS symbol server uses in filesystem + // hierarchies. + char identifier_string[17]; + snprintf(identifier_string, sizeof(identifier_string), "%08X%x", + unloaded_module_.time_date_stamp, + unloaded_module_.size_of_image); + identifier = identifier_string; + break; + } + + case MD_OS_ANDROID: + case MD_OS_LINUX: + case MD_OS_MAC_OS_X: + case MD_OS_IOS: + case MD_OS_SOLARIS: + case MD_OS_NACL: + case MD_OS_PS3: { + // TODO(mmentovai): support uuid extension if present, otherwise fall + // back to version (from LC_ID_DYLIB?), otherwise fall back to something + // else. + identifier = "id"; + break; + } + + default: { + // Without knowing what OS generated the dump, we can't generate a good + // identifier. Return an empty string, signalling failure. + BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires known " + << "platform, found " + << HexString(raw_system_info->platform_id); + break; + } + } + + return identifier; +} + +string MinidumpUnloadedModule::debug_file() const { + return ""; // No debug info provided with unloaded modules +} + +string MinidumpUnloadedModule::debug_identifier() const { + return ""; // No debug info provided with unloaded modules +} + +string MinidumpUnloadedModule::version() const { + return ""; // No version info provided with unloaded modules +} + +CodeModule* MinidumpUnloadedModule::Copy() const { + return new BasicCodeModule(this); +} + +uint64_t MinidumpUnloadedModule::shrink_down_delta() const { + return 0; +} + +void MinidumpUnloadedModule::SetShrinkDownDelta(uint64_t shrink_down_delta) { + // Not implemented + assert(false); +} + +bool MinidumpUnloadedModule::Read(uint32_t expected_size) { + + delete name_; + valid_ = false; + + if (expected_size < sizeof(unloaded_module_)) { + BPLOG(ERROR) << "MinidumpUnloadedModule expected size is less than size " + << "of struct " << expected_size << " < " + << sizeof(unloaded_module_); + return false; + } + + if (!minidump_->ReadBytes(&unloaded_module_, sizeof(unloaded_module_))) { + BPLOG(ERROR) << "MinidumpUnloadedModule cannot read module"; + return false; + } + + if (expected_size > sizeof(unloaded_module_)) { + uint32_t module_bytes_remaining = expected_size - sizeof(unloaded_module_); + off_t pos = minidump_->Tell(); + if (!minidump_->SeekSet(pos + module_bytes_remaining)) { + BPLOG(ERROR) << "MinidumpUnloadedModule unable to seek to end of module"; + return false; + } + } + + if (minidump_->swap()) { + Swap(&unloaded_module_.base_of_image); + Swap(&unloaded_module_.size_of_image); + Swap(&unloaded_module_.checksum); + Swap(&unloaded_module_.time_date_stamp); + Swap(&unloaded_module_.module_name_rva); + } + + // Check for base + size overflow or undersize. + if (unloaded_module_.size_of_image == 0 || + unloaded_module_.size_of_image > + numeric_limits::max() - unloaded_module_.base_of_image) { + BPLOG(ERROR) << "MinidumpUnloadedModule has a module problem, " << + HexString(unloaded_module_.base_of_image) << "+" << + HexString(unloaded_module_.size_of_image); + return false; + } + + + module_valid_ = true; + return true; +} + +bool MinidumpUnloadedModule::ReadAuxiliaryData() { + if (!module_valid_) { + BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for ReadAuxiliaryData"; + return false; + } + + // Each module must have a name. + name_ = minidump_->ReadString(unloaded_module_.module_name_rva); + if (!name_) { + BPLOG(ERROR) << "MinidumpUnloadedModule could not read name"; + return false; + } + + // At this point, we have enough info for the module to be valid. + valid_ = true; + return true; +} + +// +// MinidumpUnloadedModuleList +// + + +uint32_t MinidumpUnloadedModuleList::max_modules_ = 2048; + + +MinidumpUnloadedModuleList::MinidumpUnloadedModuleList(Minidump* minidump) + : MinidumpStream(minidump), + range_map_(new RangeMap()), + unloaded_modules_(NULL), + module_count_(0) { + range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower); +} + +MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() { + delete range_map_; + delete unloaded_modules_; +} + +void MinidumpUnloadedModuleList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList cannot print invalid data"; + return; + } + + printf("MinidumpUnloadedModuleList\n"); + printf(" module_count = %d\n", module_count_); + printf("\n"); + + for (unsigned int module_index = 0; + module_index < module_count_; + ++module_index) { + printf("module[%d]\n", module_index); + + (*unloaded_modules_)[module_index].Print(); + } +} + +bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) { + range_map_->Clear(); + delete unloaded_modules_; + unloaded_modules_ = NULL; + module_count_ = 0; + + valid_ = false; + + uint32_t size_of_header; + if (!minidump_->ReadBytes(&size_of_header, sizeof(size_of_header))) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header size"; + return false; + } + + uint32_t size_of_entry; + if (!minidump_->ReadBytes(&size_of_entry, sizeof(size_of_entry))) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read entry size"; + return false; + } + + uint32_t number_of_entries; + if (!minidump_->ReadBytes(&number_of_entries, sizeof(number_of_entries))) { + BPLOG(ERROR) << + "MinidumpUnloadedModuleList could not read number of entries"; + return false; + } + + if (minidump_->swap()) { + Swap(&size_of_header); + Swap(&size_of_entry); + Swap(&number_of_entries); + } + + uint32_t header_bytes_remaining = size_of_header - sizeof(size_of_header) - + sizeof(size_of_entry) - sizeof(number_of_entries); + if (header_bytes_remaining) { + off_t pos = minidump_->Tell(); + if (!minidump_->SeekSet(pos + header_bytes_remaining)) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header sized " + << size_of_header; + return false; + } + } + + if (expected_size != size_of_header + (size_of_entry * number_of_entries)) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList expected_size mismatch " << + expected_size << " != " << size_of_header << " + (" << + size_of_entry << " * " << number_of_entries << ")"; + return false; + } + + if (number_of_entries > max_modules_) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList count " << + number_of_entries << " exceeds maximum " << max_modules_; + return false; + } + + if (number_of_entries != 0) { + scoped_ptr modules( + new MinidumpUnloadedModules(number_of_entries, + MinidumpUnloadedModule(minidump_))); + + for (unsigned int module_index = 0; + module_index < number_of_entries; + ++module_index) { + MinidumpUnloadedModule* module = &(*modules)[module_index]; + + if (!module->Read(size_of_entry)) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read module " << + module_index << "/" << number_of_entries; + return false; + } + } + + for (unsigned int module_index = 0; + module_index < number_of_entries; + ++module_index) { + MinidumpUnloadedModule* module = &(*modules)[module_index]; + + if (!module->ReadAuxiliaryData()) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read required " + "module auxiliary data for module " << + module_index << "/" << number_of_entries; + return false; + } + + uint64_t base_address = module->base_address(); + uint64_t module_size = module->size(); + + // Ignore any failures for conflicting address ranges + range_map_->StoreRange(base_address, module_size, module_index); + + } + unloaded_modules_ = modules.release(); + } + + module_count_ = number_of_entries; + valid_ = true; + return true; +} + +const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress( + uint64_t address) const { + if (!valid_) { + BPLOG(ERROR) + << "Invalid MinidumpUnloadedModuleList for GetModuleForAddress"; + return NULL; + } + + unsigned int module_index; + if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + BPLOG(INFO) << "MinidumpUnloadedModuleList has no module at " + << HexString(address); + return NULL; + } + + return GetModuleAtIndex(module_index); +} + +const MinidumpUnloadedModule* +MinidumpUnloadedModuleList::GetMainModule() const { + return NULL; +} + +const MinidumpUnloadedModule* +MinidumpUnloadedModuleList::GetModuleAtSequence(unsigned int sequence) const { + if (!valid_) { + BPLOG(ERROR) + << "Invalid MinidumpUnloadedModuleList for GetModuleAtSequence"; + return NULL; + } + + if (sequence >= module_count_) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList sequence out of range: " + << sequence << "/" << module_count_; + return NULL; + } + + unsigned int module_index; + if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, + NULL /* base */, NULL /* delta */, + NULL /* size */)) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList has no module at sequence " + << sequence; + return NULL; + } + + return GetModuleAtIndex(module_index); +} + +const MinidumpUnloadedModule* +MinidumpUnloadedModuleList::GetModuleAtIndex( + unsigned int index) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtIndex"; + return NULL; + } + + if (index >= module_count_) { + BPLOG(ERROR) << "MinidumpUnloadedModuleList index out of range: " + << index << "/" << module_count_; + return NULL; + } + + return &(*unloaded_modules_)[index]; +} + +const CodeModules* MinidumpUnloadedModuleList::Copy() const { + return new BasicCodeModules(this, range_map_->GetMergeStrategy()); +} + +vector> +MinidumpUnloadedModuleList::GetShrunkRangeModules() const { + return vector >(); +} + + +// +// MinidumpMiscInfo +// + + +MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump) + : MinidumpStream(minidump), + misc_info_() { +} + + +bool MinidumpMiscInfo::Read(uint32_t expected_size) { + valid_ = false; + + size_t padding = 0; + if (expected_size != MD_MISCINFO_SIZE && + expected_size != MD_MISCINFO2_SIZE && + expected_size != MD_MISCINFO3_SIZE && + expected_size != MD_MISCINFO4_SIZE && + expected_size != MD_MISCINFO5_SIZE) { + if (expected_size > MD_MISCINFO5_SIZE) { + // Only read the part of the misc info structure we know how to handle + BPLOG(INFO) << "MinidumpMiscInfo size larger than expected " + << expected_size << ", skipping over the unknown part"; + padding = expected_size - MD_MISCINFO5_SIZE; + expected_size = MD_MISCINFO5_SIZE; + } else { + BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size + << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE + << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE + << ", " << MD_MISCINFO5_SIZE << ")"; + return false; + } + } + + if (!minidump_->ReadBytes(&misc_info_, expected_size)) { + BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info"; + return false; + } + + if (padding != 0) { + off_t saved_position = minidump_->Tell(); + if (saved_position == -1) { + BPLOG(ERROR) << "MinidumpMiscInfo could not tell the current position"; + return false; + } + + if (!minidump_->SeekSet(saved_position + static_cast(padding))) { + BPLOG(ERROR) << "MinidumpMiscInfo could not seek past the miscellaneous " + << "info structure"; + return false; + } + } + + if (minidump_->swap()) { + // Swap version 1 fields + Swap(&misc_info_.size_of_info); + Swap(&misc_info_.flags1); + Swap(&misc_info_.process_id); + Swap(&misc_info_.process_create_time); + Swap(&misc_info_.process_user_time); + Swap(&misc_info_.process_kernel_time); + if (misc_info_.size_of_info > MD_MISCINFO_SIZE) { + // Swap version 2 fields + Swap(&misc_info_.processor_max_mhz); + Swap(&misc_info_.processor_current_mhz); + Swap(&misc_info_.processor_mhz_limit); + Swap(&misc_info_.processor_max_idle_state); + Swap(&misc_info_.processor_current_idle_state); + } + if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) { + // Swap version 3 fields + Swap(&misc_info_.process_integrity_level); + Swap(&misc_info_.process_execute_flags); + Swap(&misc_info_.protected_process); + Swap(&misc_info_.time_zone_id); + Swap(&misc_info_.time_zone); + } + if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) { + // Swap version 4 fields. + // Do not swap UTF-16 strings. The swap is done as part of the + // conversion to UTF-8 (code follows below). + } + if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) { + // Swap version 5 fields + Swap(&misc_info_.xstate_data); + Swap(&misc_info_.process_cookie); + } + } + + if (expected_size + padding != misc_info_.size_of_info) { + BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << + expected_size << " != " << misc_info_.size_of_info; + return false; + } + + // Convert UTF-16 strings + if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) { + // Convert UTF-16 strings in version 3 fields + ConvertUTF16BufferToUTF8String(misc_info_.time_zone.standard_name, + sizeof(misc_info_.time_zone.standard_name), + &standard_name_, minidump_->swap()); + ConvertUTF16BufferToUTF8String(misc_info_.time_zone.daylight_name, + sizeof(misc_info_.time_zone.daylight_name), + &daylight_name_, minidump_->swap()); + } + if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) { + // Convert UTF-16 strings in version 4 fields + ConvertUTF16BufferToUTF8String(misc_info_.build_string, + sizeof(misc_info_.build_string), + &build_string_, minidump_->swap()); + ConvertUTF16BufferToUTF8String(misc_info_.dbg_bld_str, + sizeof(misc_info_.dbg_bld_str), + &dbg_bld_str_, minidump_->swap()); + } + + valid_ = true; + return true; +} + + +void MinidumpMiscInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data"; + return; + } + + printf("MDRawMiscInfo\n"); + // Print version 1 fields + printf(" size_of_info = %d\n", misc_info_.size_of_info); + printf(" flags1 = 0x%x\n", misc_info_.flags1); + printf(" process_id = "); + PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_ID, + kNumberFormatDecimal, misc_info_.process_id); + if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES) { + printf(" process_create_time = 0x%x %s\n", + misc_info_.process_create_time, + TimeTToUTCString(misc_info_.process_create_time).c_str()); + } else { + printf(" process_create_time = (invalid)\n"); + } + printf(" process_user_time = "); + PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES, + kNumberFormatDecimal, misc_info_.process_user_time); + printf(" process_kernel_time = "); + PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES, + kNumberFormatDecimal, misc_info_.process_kernel_time); + if (misc_info_.size_of_info > MD_MISCINFO_SIZE) { + // Print version 2 fields + printf(" processor_max_mhz = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO, + kNumberFormatDecimal, misc_info_.processor_max_mhz); + printf(" processor_current_mhz = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO, + kNumberFormatDecimal, misc_info_.processor_current_mhz); + printf(" processor_mhz_limit = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO, + kNumberFormatDecimal, misc_info_.processor_mhz_limit); + printf(" processor_max_idle_state = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO, + kNumberFormatDecimal, + misc_info_.processor_max_idle_state); + printf(" processor_current_idle_state = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO, + kNumberFormatDecimal, + misc_info_.processor_current_idle_state); + } + if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) { + // Print version 3 fields + printf(" process_integrity_level = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY, + kNumberFormatHexadecimal, + misc_info_.process_integrity_level); + printf(" process_execute_flags = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS, + kNumberFormatHexadecimal, + misc_info_.process_execute_flags); + printf(" protected_process = "); + PrintValueOrInvalid(misc_info_.flags1 & + MD_MISCINFO_FLAGS1_PROTECTED_PROCESS, + kNumberFormatDecimal, misc_info_.protected_process); + printf(" time_zone_id = "); + PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE, + kNumberFormatDecimal, misc_info_.time_zone_id); + if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE) { + printf(" time_zone.bias = %d\n", + misc_info_.time_zone.bias); + printf(" time_zone.standard_name = %s\n", standard_name_.c_str()); + printf(" time_zone.standard_date = " + "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n", + misc_info_.time_zone.standard_date.year, + misc_info_.time_zone.standard_date.month, + misc_info_.time_zone.standard_date.day, + misc_info_.time_zone.standard_date.day_of_week, + misc_info_.time_zone.standard_date.hour, + misc_info_.time_zone.standard_date.minute, + misc_info_.time_zone.standard_date.second, + misc_info_.time_zone.standard_date.milliseconds); + printf(" time_zone.standard_bias = %d\n", + misc_info_.time_zone.standard_bias); + printf(" time_zone.daylight_name = %s\n", daylight_name_.c_str()); + printf(" time_zone.daylight_date = " + "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n", + misc_info_.time_zone.daylight_date.year, + misc_info_.time_zone.daylight_date.month, + misc_info_.time_zone.daylight_date.day, + misc_info_.time_zone.daylight_date.day_of_week, + misc_info_.time_zone.daylight_date.hour, + misc_info_.time_zone.daylight_date.minute, + misc_info_.time_zone.daylight_date.second, + misc_info_.time_zone.daylight_date.milliseconds); + printf(" time_zone.daylight_bias = %d\n", + misc_info_.time_zone.daylight_bias); + } else { + printf(" time_zone.bias = (invalid)\n"); + printf(" time_zone.standard_name = (invalid)\n"); + printf(" time_zone.standard_date = (invalid)\n"); + printf(" time_zone.standard_bias = (invalid)\n"); + printf(" time_zone.daylight_name = (invalid)\n"); + printf(" time_zone.daylight_date = (invalid)\n"); + printf(" time_zone.daylight_bias = (invalid)\n"); + } + } + if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) { + // Print version 4 fields + if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_BUILDSTRING) { + printf(" build_string = %s\n", build_string_.c_str()); + printf(" dbg_bld_str = %s\n", dbg_bld_str_.c_str()); + } else { + printf(" build_string = (invalid)\n"); + printf(" dbg_bld_str = (invalid)\n"); + } + } + if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) { + // Print version 5 fields + if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_COOKIE) { + printf(" xstate_data.size_of_info = %d\n", + misc_info_.xstate_data.size_of_info); + printf(" xstate_data.context_size = %d\n", + misc_info_.xstate_data.context_size); + printf(" xstate_data.enabled_features = 0x%" PRIx64 "\n", + misc_info_.xstate_data.enabled_features); + for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) { + if ((misc_info_.xstate_data.enabled_features >> i) & 1) { + printf(" xstate_data.features[%02zu] = { %d, %d }\n", i, + misc_info_.xstate_data.features[i].offset, + misc_info_.xstate_data.features[i].size); + } + } + if (misc_info_.xstate_data.enabled_features == 0) { + printf(" xstate_data.features[] = (empty)\n"); + } + printf(" process_cookie = %d\n", + misc_info_.process_cookie); + } else { + printf(" xstate_data.size_of_info = (invalid)\n"); + printf(" xstate_data.context_size = (invalid)\n"); + printf(" xstate_data.enabled_features = (invalid)\n"); + printf(" xstate_data.features[] = (invalid)\n"); + printf(" process_cookie = (invalid)\n"); + } + } + printf("\n"); +} + + +// +// MinidumpBreakpadInfo +// + + +MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump) + : MinidumpStream(minidump), + breakpad_info_() { +} + + +bool MinidumpBreakpadInfo::Read(uint32_t expected_size) { + valid_ = false; + + if (expected_size != sizeof(breakpad_info_)) { + BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size << + " != " << sizeof(breakpad_info_); + return false; + } + + if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) { + BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info"; + return false; + } + + if (minidump_->swap()) { + Swap(&breakpad_info_.validity); + Swap(&breakpad_info_.dump_thread_id); + Swap(&breakpad_info_.requesting_thread_id); + } + + valid_ = true; + return true; +} + + +bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const { + BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID " + "requires |thread_id|"; + assert(thread_id); + *thread_id = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID"; + return false; + } + + if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) { + BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread"; + return false; + } + + *thread_id = breakpad_info_.dump_thread_id; + return true; +} + + +bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id) + const { + BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID " + "requires |thread_id|"; + assert(thread_id); + *thread_id = 0; + + if (!thread_id || !valid_) { + BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID"; + return false; + } + + if (!(breakpad_info_.validity & + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) { + BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread"; + return false; + } + + *thread_id = breakpad_info_.requesting_thread_id; + return true; +} + + +void MinidumpBreakpadInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data"; + return; + } + + printf("MDRawBreakpadInfo\n"); + printf(" validity = 0x%x\n", breakpad_info_.validity); + printf(" dump_thread_id = "); + PrintValueOrInvalid(breakpad_info_.validity & + MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID, + kNumberFormatHexadecimal, breakpad_info_.dump_thread_id); + printf(" requesting_thread_id = "); + PrintValueOrInvalid(breakpad_info_.validity & + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID, + kNumberFormatHexadecimal, + breakpad_info_.requesting_thread_id); + + printf("\n"); +} + + +// +// MinidumpMemoryInfo +// + + +MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump) + : MinidumpObject(minidump), + memory_info_() { +} + + +bool MinidumpMemoryInfo::IsExecutable() const { + uint32_t protection = + memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK; + return protection == MD_MEMORY_PROTECT_EXECUTE || + protection == MD_MEMORY_PROTECT_EXECUTE_READ || + protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE; +} + + +bool MinidumpMemoryInfo::IsWritable() const { + uint32_t protection = + memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK; + return protection == MD_MEMORY_PROTECT_READWRITE || + protection == MD_MEMORY_PROTECT_WRITECOPY || + protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE || + protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY; +} + + +bool MinidumpMemoryInfo::Read() { + valid_ = false; + + if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) { + BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info"; + return false; + } + + if (minidump_->swap()) { + Swap(&memory_info_.base_address); + Swap(&memory_info_.allocation_base); + Swap(&memory_info_.allocation_protection); + Swap(&memory_info_.region_size); + Swap(&memory_info_.state); + Swap(&memory_info_.protection); + Swap(&memory_info_.type); + } + + // Check for base + size overflow or undersize. + if (memory_info_.region_size == 0 || + memory_info_.region_size > numeric_limits::max() - + memory_info_.base_address) { + BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " << + HexString(memory_info_.base_address) << "+" << + HexString(memory_info_.region_size); + return false; + } + + valid_ = true; + return true; +} + + +void MinidumpMemoryInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data"; + return; + } + + printf("MDRawMemoryInfo\n"); + printf(" base_address = 0x%" PRIx64 "\n", + memory_info_.base_address); + printf(" allocation_base = 0x%" PRIx64 "\n", + memory_info_.allocation_base); + printf(" allocation_protection = 0x%x\n", + memory_info_.allocation_protection); + printf(" region_size = 0x%" PRIx64 "\n", memory_info_.region_size); + printf(" state = 0x%x\n", memory_info_.state); + printf(" protection = 0x%x\n", memory_info_.protection); + printf(" type = 0x%x\n", memory_info_.type); +} + + +// +// MinidumpMemoryInfoList +// + + +MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump) + : MinidumpStream(minidump), + range_map_(new RangeMap()), + infos_(NULL), + info_count_(0) { +} + + +MinidumpMemoryInfoList::~MinidumpMemoryInfoList() { + delete range_map_; + delete infos_; +} + + +bool MinidumpMemoryInfoList::Read(uint32_t expected_size) { + // Invalidate cached data. + delete infos_; + infos_ = NULL; + range_map_->Clear(); + info_count_ = 0; + + valid_ = false; + + MDRawMemoryInfoList header; + if (expected_size < sizeof(MDRawMemoryInfoList)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " << + expected_size << " < " << sizeof(MDRawMemoryInfoList); + return false; + } + if (!minidump_->ReadBytes(&header, sizeof(header))) { + BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header"; + return false; + } + + if (minidump_->swap()) { + Swap(&header.size_of_header); + Swap(&header.size_of_entry); + Swap(&header.number_of_entries); + } + + // Sanity check that the header is the expected size. + // TODO(ted): could possibly handle this more gracefully, assuming + // that future versions of the structs would be backwards-compatible. + if (header.size_of_header != sizeof(MDRawMemoryInfoList)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " << + header.size_of_header << " != " << + sizeof(MDRawMemoryInfoList); + return false; + } + + // Sanity check that the entries are the expected size. + if (header.size_of_entry != sizeof(MDRawMemoryInfo)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " << + header.size_of_entry << " != " << + sizeof(MDRawMemoryInfo); + return false; + } + + if (header.number_of_entries > + numeric_limits::max() / sizeof(MDRawMemoryInfo)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList info count " << + header.number_of_entries << + " would cause multiplication overflow"; + return false; + } + + if (expected_size != sizeof(MDRawMemoryInfoList) + + header.number_of_entries * sizeof(MDRawMemoryInfo)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size << + " != " << sizeof(MDRawMemoryInfoList) + + header.number_of_entries * sizeof(MDRawMemoryInfo); + return false; + } + + // Check for data loss when converting header.number_of_entries from + // uint64_t into MinidumpMemoryInfos::size_type (uint32_t) + MinidumpMemoryInfos::size_type header_number_of_entries = + static_cast(header.number_of_entries); + if (static_cast(header_number_of_entries) != + header.number_of_entries) { + BPLOG(ERROR) << "Data loss detected when converting " + "the header's number_of_entries"; + return false; + } + + if (header.number_of_entries != 0) { + scoped_ptr infos( + new MinidumpMemoryInfos(header_number_of_entries, + MinidumpMemoryInfo(minidump_))); + + for (unsigned int index = 0; + index < header.number_of_entries; + ++index) { + MinidumpMemoryInfo* info = &(*infos)[index]; + + // Assume that the file offset is correct after the last read. + if (!info->Read()) { + BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " << + index << "/" << header.number_of_entries; + return false; + } + + uint64_t base_address = info->GetBase(); + uint64_t region_size = info->GetSize(); + + if (!range_map_->StoreRange(base_address, region_size, index)) { + BPLOG(ERROR) << "MinidumpMemoryInfoList could not store" + " memory region " << + index << "/" << header.number_of_entries << ", " << + HexString(base_address) << "+" << + HexString(region_size); + return false; + } + } + + infos_ = infos.release(); + } + + info_count_ = static_cast(header_number_of_entries); + + valid_ = true; + return true; +} + + +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex( + unsigned int index) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex"; + return NULL; + } + + if (index >= info_count_) { + BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " << + index << "/" << info_count_; + return NULL; + } + + return &(*infos_)[index]; +} + + +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress( + uint64_t address) const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for" + " GetMemoryInfoForAddress"; + return NULL; + } + + unsigned int info_index; + if (!range_map_->RetrieveRange(address, &info_index, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " << + HexString(address); + return NULL; + } + + return GetMemoryInfoAtIndex(info_index); +} + + +void MinidumpMemoryInfoList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data"; + return; + } + + printf("MinidumpMemoryInfoList\n"); + printf(" info_count = %d\n", info_count_); + printf("\n"); + + for (unsigned int info_index = 0; + info_index < info_count_; + ++info_index) { + printf("info[%d]\n", info_index); + (*infos_)[info_index].Print(); + printf("\n"); + } +} + +// +// MinidumpLinuxMaps +// + +MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump *minidump) + : MinidumpObject(minidump) { +} + +void MinidumpLinuxMaps::Print() const { + if (!valid_) { + BPLOG(ERROR) << "MinidumpLinuxMaps cannot print invalid data"; + return; + } + std::cout << region_.line << std::endl; +} + +// +// MinidumpLinuxMapsList +// + +MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump *minidump) + : MinidumpStream(minidump), + maps_(NULL), + maps_count_(0) { +} + +MinidumpLinuxMapsList::~MinidumpLinuxMapsList() { + if (maps_) { + for (unsigned int i = 0; i < maps_->size(); i++) { + delete (*maps_)[i]; + } + delete maps_; + } +} + +const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress( + uint64_t address) const { + if (!valid_ || (maps_ == NULL)) { + BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress"; + return NULL; + } + + // Search every memory mapping. + for (unsigned int index = 0; index < maps_count_; index++) { + // Check if address is within bounds of the current memory region. + if ((*maps_)[index]->GetBase() <= address && + (*maps_)[index]->GetBase() + (*maps_)[index]->GetSize() > address) { + return (*maps_)[index]; + } + } + + // No mapping encloses the memory address. + BPLOG(ERROR) << "MinidumpLinuxMapsList has no mapping at " + << HexString(address); + return NULL; +} + +const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsAtIndex( + unsigned int index) const { + if (!valid_ || (maps_ == NULL)) { + BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex"; + return NULL; + } + + // Index out of bounds. + if (index >= maps_count_ || (maps_ == NULL)) { + BPLOG(ERROR) << "MinidumpLinuxMapsList index of out range: " + << index + << "/" + << maps_count_; + return NULL; + } + return (*maps_)[index]; +} + +bool MinidumpLinuxMapsList::Read(uint32_t expected_size) { + // Invalidate cached data. + if (maps_) { + for (unsigned int i = 0; i < maps_->size(); i++) { + delete (*maps_)[i]; + } + delete maps_; + } + maps_ = NULL; + maps_count_ = 0; + + valid_ = false; + + // Load and check expected stream length. + uint32_t length = 0; + if (!minidump_->SeekToStreamType(MD_LINUX_MAPS, &length)) { + BPLOG(ERROR) << "MinidumpLinuxMapsList stream type not found"; + return false; + } + if (expected_size != length) { + BPLOG(ERROR) << "MinidumpLinuxMapsList size mismatch: " + << expected_size + << " != " + << length; + return false; + } + + // Create a vector to read stream data. The vector needs to have + // at least enough capacity to read all the data. + vector mapping_bytes(length); + if (!minidump_->ReadBytes(&mapping_bytes[0], length)) { + BPLOG(ERROR) << "MinidumpLinuxMapsList failed to read bytes"; + return false; + } + string map_string(mapping_bytes.begin(), mapping_bytes.end()); + vector all_regions; + + // Parse string into mapping data. + if (!ParseProcMaps(map_string, &all_regions)) { + return false; + } + + scoped_ptr maps(new MinidumpLinuxMappings()); + + // Push mapping data into wrapper classes. + for (size_t i = 0; i < all_regions.size(); i++) { + scoped_ptr ele(new MinidumpLinuxMaps(minidump_)); + ele->region_ = all_regions[i]; + ele->valid_ = true; + maps->push_back(ele.release()); + } + + // Set instance variables. + maps_ = maps.release(); + maps_count_ = static_cast(maps_->size()); + valid_ = true; + return true; +} + +void MinidumpLinuxMapsList::Print() const { + if (!valid_ || (maps_ == NULL)) { + BPLOG(ERROR) << "MinidumpLinuxMapsList cannot print valid data"; + return; + } + for (size_t i = 0; i < maps_->size(); i++) { + (*maps_)[i]->Print(); + } +} + +// +// MinidumpCrashpadInfo +// + + +MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump) + : MinidumpStream(minidump), + crashpad_info_(), + module_crashpad_info_links_(), + module_crashpad_info_(), + module_crashpad_info_list_annotations_(), + module_crashpad_info_simple_annotations_(), + simple_annotations_() { +} + + +bool MinidumpCrashpadInfo::Read(uint32_t expected_size) { + valid_ = false; + + if (expected_size != sizeof(crashpad_info_)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size << + " != " << sizeof(crashpad_info_); + return false; + } + + if (!minidump_->ReadBytes(&crashpad_info_, sizeof(crashpad_info_))) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info"; + return false; + } + + if (minidump_->swap()) { + Swap(&crashpad_info_.version); + Swap(&crashpad_info_.report_id); + Swap(&crashpad_info_.client_id); + Swap(&crashpad_info_.simple_annotations); + Swap(&crashpad_info_.module_list); + } + + if (crashpad_info_.simple_annotations.data_size) { + if (!minidump_->ReadSimpleStringDictionary( + crashpad_info_.simple_annotations.rva, + &simple_annotations_)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read simple_annotations"; + return false; + } + } + + if (crashpad_info_.module_list.data_size) { + if (!minidump_->SeekSet(crashpad_info_.module_list.rva)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot seek to module_list"; + return false; + } + + uint32_t count; + if (!minidump_->ReadBytes(&count, sizeof(count))) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read module_list count"; + return false; + } + + if (minidump_->swap()) { + Swap(&count); + } + + scoped_array module_crashpad_info_links( + new MDRawModuleCrashpadInfoLink[count]); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!minidump_->ReadBytes( + &module_crashpad_info_links[0], + sizeof(MDRawModuleCrashpadInfoLink) * count)) { + BPLOG(ERROR) + << "MinidumpCrashpadInfo could not read Crashpad module links"; + return false; + } + + for (uint32_t index = 0; index < count; ++index) { + if (minidump_->swap()) { + Swap(&module_crashpad_info_links[index].minidump_module_list_index); + Swap(&module_crashpad_info_links[index].location); + } + + if (!minidump_->SeekSet(module_crashpad_info_links[index].location.rva)) { + BPLOG(ERROR) + << "MinidumpCrashpadInfo cannot seek to Crashpad module info"; + return false; + } + + MDRawModuleCrashpadInfo module_crashpad_info; + if (!minidump_->ReadBytes(&module_crashpad_info, + sizeof(module_crashpad_info))) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module info"; + return false; + } + + if (minidump_->swap()) { + Swap(&module_crashpad_info.version); + Swap(&module_crashpad_info.list_annotations); + Swap(&module_crashpad_info.simple_annotations); + } + + std::vector list_annotations; + if (module_crashpad_info.list_annotations.data_size) { + if (!minidump_->ReadStringList( + module_crashpad_info.list_annotations.rva, + &list_annotations)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module " + "info list annotations"; + return false; + } + } + + std::map simple_annotations; + if (module_crashpad_info.simple_annotations.data_size) { + if (!minidump_->ReadSimpleStringDictionary( + module_crashpad_info.simple_annotations.rva, + &simple_annotations)) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module " + "info simple annotations"; + return false; + } + } + + module_crashpad_info_links_.push_back( + module_crashpad_info_links[index].minidump_module_list_index); + module_crashpad_info_.push_back(module_crashpad_info); + module_crashpad_info_list_annotations_.push_back(list_annotations); + module_crashpad_info_simple_annotations_.push_back(simple_annotations); + } + } + + valid_ = true; + return true; +} + + +void MinidumpCrashpadInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpCrashpadInfo cannot print invalid data"; + return; + } + + printf("MDRawCrashpadInfo\n"); + printf(" version = %d\n", crashpad_info_.version); + printf(" report_id = %s\n", + MDGUIDToString(crashpad_info_.report_id).c_str()); + printf(" client_id = %s\n", + MDGUIDToString(crashpad_info_.client_id).c_str()); + for (std::map::const_iterator iterator = + simple_annotations_.begin(); + iterator != simple_annotations_.end(); + ++iterator) { + printf(" simple_annotations[\"%s\"] = %s\n", + iterator->first.c_str(), iterator->second.c_str()); + } + for (uint32_t module_index = 0; + module_index < module_crashpad_info_links_.size(); + ++module_index) { + printf(" module_list[%d].minidump_module_list_index = %d\n", + module_index, module_crashpad_info_links_[module_index]); + printf(" module_list[%d].version = %d\n", + module_index, module_crashpad_info_[module_index].version); + for (uint32_t annotation_index = 0; + annotation_index < + module_crashpad_info_list_annotations_[module_index].size(); + ++annotation_index) { + printf(" module_list[%d].list_annotations[%d] = %s\n", + module_index, + annotation_index, + module_crashpad_info_list_annotations_ + [module_index][annotation_index].c_str()); + } + for (std::map::const_iterator iterator = + module_crashpad_info_simple_annotations_[module_index].begin(); + iterator != + module_crashpad_info_simple_annotations_[module_index].end(); + ++iterator) { + printf(" module_list[%d].simple_annotations[\"%s\"] = %s\n", + module_index, iterator->first.c_str(), iterator->second.c_str()); + } + } + + printf("\n"); +} + +// +// MinidumpMacCrashInfo +// + +MinidumpMacCrashInfo::MinidumpMacCrashInfo(Minidump* minidump) + : MinidumpStream(minidump), + description_(), + records_() { +} + +bool MinidumpMacCrashInfo::ReadCrashInfoRecord(MDLocationDescriptor location, + uint32_t record_start_size) { + if (!minidump_->SeekSet(location.rva)) { + BPLOG(ERROR) << "ReadCrashInfoRecord could not seek to record"; + return false; + } + + // We may be reading a minidump 1) created by (newer) code that defines more + // fields than we do in the fixed-size part of MDRawMacCrashInfoRecord + // (before 'data'), or 2) created by (older) code that defines fewer fields. + // In the first case we read in the newer fields but ignore them. In the + // second case we read in only the older fields, and leave the newer fields + // (in 'raw_record_start') set to zero. + uint32_t raw_record_size = sizeof(MDRawMacCrashInfoRecord); + if (record_start_size > raw_record_size) { + raw_record_size = record_start_size; + } + scoped_ptr< vector > raw_record( + new vector(raw_record_size)); + if (!minidump_->ReadBytes(&(*raw_record)[0], record_start_size)) { + BPLOG(ERROR) << "ReadCrashInfoRecord could not read " << + record_start_size << " bytes of record"; + return false; + } + MDRawMacCrashInfoRecord* raw_record_start = + (MDRawMacCrashInfoRecord*) &(*raw_record)[0]; + + if (minidump_->swap()) { + Swap(&raw_record_start->stream_type); + Swap(&raw_record_start->version); + Swap(&raw_record_start->thread); + Swap(&raw_record_start->dialog_mode); + Swap(&raw_record_start->abort_cause); + } + + if (raw_record_start->stream_type != MOZ_MACOS_CRASH_INFO_STREAM) { + BPLOG(ERROR) << "ReadCrashInfoRecord stream type mismatch, " << + raw_record_start->stream_type << " != " << + MOZ_MACOS_CRASH_INFO_STREAM; + return false; + } + + uint32_t string_data_size = location.data_size - record_start_size; + scoped_ptr< vector > data(new vector(string_data_size)); + if (!minidump_->ReadBytes(&(*data)[0], string_data_size)) { + BPLOG(ERROR) << "ReadCrashInfoRecord could not read " << + string_data_size << " bytes of record data"; + return false; + } + + crash_info_record_t record; + + record.version = (unsigned long) raw_record_start->version; + record.thread = (unsigned long long) raw_record_start->thread; + record.dialog_mode = (unsigned int) raw_record_start->dialog_mode; + record.abort_cause = (long long) raw_record_start->abort_cause; + + // Once again, we may be reading a minidump created by newer code that + // stores more strings than we expect in (MDRawMacCrashInfoRecord).data, + // or one created by older code that contains fewer strings than we + // expect. In the first case we ignore the "extra" strings. To deal with + // the second case we bail when 'offset >= string_data_size'. + const char* string_data = (const char*) &(*data)[0]; + size_t offset = 0; + for (int i = 1; i <= 5; ++i) { + switch (i) { + case 1: + record.module_path.append(string_data); + break; + case 2: + record.message.append(string_data); + break; + case 3: + record.signature_string.append(string_data); + break; + case 4: + record.backtrace.append(string_data); + break; + case 5: + record.message2.append(string_data); + break; + } + size_t char_array_size = strlen(string_data) + 1; + offset += char_array_size; + if (offset >= string_data_size) { + break; + } + string_data += char_array_size; + } + + records_.push_back(record); + + description_.append(" Module \""); + description_.append(record.module_path); + description_.append("\":\n"); + + int num_fields = 6; + if (record.version > 4) { + num_fields = 7; + } + for (int i = 1; i <= num_fields; ++i) { + switch (i) { + case 1: + if (!record.message.empty()) { + description_.append(" message: \""); + description_.append(record.message); + description_.append("\"\n"); + } + break; + case 2: + if (!record.signature_string.empty()) { + description_.append(" signature_string: \""); + description_.append(record.signature_string); + description_.append("\"\n"); + } + break; + case 3: + if (!record.backtrace.empty()) { + description_.append(" backtrace: \""); + description_.append(record.backtrace); + description_.append("\"\n"); + } + break; + case 4: + if (!record.message2.empty()) { + description_.append(" message2: \""); + description_.append(record.message2); + description_.append("\"\n"); + } + break; + case 5: + if (record.thread) { + char thread[128]; + snprintf(thread, sizeof(thread), " thread: 0x%llx\n", + record.thread); + description_.append(thread); + } + break; + case 6: + if (record.dialog_mode) { + char dialog_mode[128]; + snprintf(dialog_mode, sizeof(dialog_mode), " dialog_mode: 0x%x\n", + record.dialog_mode); + description_.append(dialog_mode); + } + break; + case 7: + if (record.abort_cause) { + char abort_cause[128]; + snprintf(abort_cause, sizeof(abort_cause), " abort_cause: %lld\n", + record.abort_cause); + description_.append(abort_cause); + } + break; + default: + break; + } + } + + return true; +} + +bool MinidumpMacCrashInfo::Read(uint32_t expected_size) { + description_.clear(); + records_.clear(); + valid_ = false; + + MDRawMacCrashInfo crash_info; + if (expected_size != sizeof(crash_info)) { + BPLOG(ERROR) << "MinidumpMacCrashInfo size mismatch, " << + expected_size << " != " << sizeof(crash_info); + return false; + } + if (!minidump_->ReadBytes(&crash_info, sizeof(crash_info))) { + BPLOG(ERROR) << "MinidumpMacCrashInfo could not read " << + sizeof(crash_info) << " bytes"; + return false; + } + if (minidump_->swap()) { + Swap(&crash_info.stream_type); + Swap(&crash_info.record_count); + Swap(&crash_info.record_start_size); + for (uint32_t i = 0; i < crash_info.record_count; ++i) { + Swap(&crash_info.records[i].data_size); + Swap(&crash_info.records[i].rva); + } + } + if (crash_info.stream_type != MOZ_MACOS_CRASH_INFO_STREAM) { + BPLOG(ERROR) << "MinidumpMacCrashInfo stream type mismatch, " << + crash_info.stream_type << " != " << + MOZ_MACOS_CRASH_INFO_STREAM; + return false; + } + + for (uint32_t i = 0; i < crash_info.record_count; ++i) { + if (!ReadCrashInfoRecord(crash_info.records[i], + crash_info.record_start_size)) { + return false; + } + } + + valid_ = true; + return true; +} + +void MinidumpMacCrashInfo::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpMacCrashInfo cannot print invalid data"; + return; + } + + printf("MinidumpMacCrashInfo:\n\n"); + printf("%s", description_.c_str()); +} + +// +// Minidump +// + + +uint32_t Minidump::max_streams_ = 128; +unsigned int Minidump::max_string_length_ = 1024; + + +Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width) + : header_(), + directory_(NULL), + stream_map_(new MinidumpStreamMap()), + path_(path), + stream_(NULL), + swap_(false), + is_big_endian_(false), + valid_(false), + hexdump_(hexdump), + hexdump_width_(hexdump_width) { +} + +Minidump::Minidump(istream& stream) + : header_(), + directory_(NULL), + stream_map_(new MinidumpStreamMap()), + path_(), + stream_(&stream), + swap_(false), + is_big_endian_(false), + valid_(false), + hexdump_(false), + hexdump_width_(0) { +} + +Minidump::~Minidump() { + if (stream_) { + BPLOG(INFO) << "Minidump closing minidump"; + } + if (!path_.empty()) { + delete stream_; + } + delete directory_; + delete stream_map_; +} + + +bool Minidump::Open() { + if (stream_ != NULL) { + BPLOG(INFO) << "Minidump reopening minidump " << path_; + + // The file is already open. Seek to the beginning, which is the position + // the file would be at if it were opened anew. + return SeekSet(0); + } + + stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary); + if (!stream_ || !stream_->good()) { + string error_string; + int error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "Minidump could not open minidump " << path_ << + ", error " << error_code << ": " << error_string; + return false; + } + + BPLOG(INFO) << "Minidump opened minidump " << path_; + return true; +} + +bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { + // Initialize output parameters + *context_cpu_flags = 0; + + // Save the current stream position + off_t saved_position = Tell(); + if (saved_position == -1) { + // Failed to save the current stream position. + // Returns true because the current position of the stream is preserved. + return true; + } + + const MDRawSystemInfo* system_info = + GetSystemInfo() ? GetSystemInfo()->system_info() : NULL; + + if (system_info != NULL) { + switch (system_info->processor_architecture) { + case MD_CPU_ARCHITECTURE_X86: + *context_cpu_flags = MD_CONTEXT_X86; + break; + case MD_CPU_ARCHITECTURE_MIPS: + *context_cpu_flags = MD_CONTEXT_MIPS; + break; + case MD_CPU_ARCHITECTURE_MIPS64: + *context_cpu_flags = MD_CONTEXT_MIPS64; + break; + case MD_CPU_ARCHITECTURE_ALPHA: + *context_cpu_flags = MD_CONTEXT_ALPHA; + break; + case MD_CPU_ARCHITECTURE_PPC: + *context_cpu_flags = MD_CONTEXT_PPC; + break; + case MD_CPU_ARCHITECTURE_PPC64: + *context_cpu_flags = MD_CONTEXT_PPC64; + break; + case MD_CPU_ARCHITECTURE_SHX: + *context_cpu_flags = MD_CONTEXT_SHX; + break; + case MD_CPU_ARCHITECTURE_ARM: + *context_cpu_flags = MD_CONTEXT_ARM; + break; + case MD_CPU_ARCHITECTURE_ARM64: + *context_cpu_flags = MD_CONTEXT_ARM64; + break; + case MD_CPU_ARCHITECTURE_ARM64_OLD: + *context_cpu_flags = MD_CONTEXT_ARM64_OLD; + break; + case MD_CPU_ARCHITECTURE_IA64: + *context_cpu_flags = MD_CONTEXT_IA64; + break; + case MD_CPU_ARCHITECTURE_ALPHA64: + *context_cpu_flags = 0; + break; + case MD_CPU_ARCHITECTURE_MSIL: + *context_cpu_flags = 0; + break; + case MD_CPU_ARCHITECTURE_AMD64: + *context_cpu_flags = MD_CONTEXT_AMD64; + break; + case MD_CPU_ARCHITECTURE_X86_WIN64: + *context_cpu_flags = 0; + break; + case MD_CPU_ARCHITECTURE_SPARC: + *context_cpu_flags = MD_CONTEXT_SPARC; + break; + case MD_CPU_ARCHITECTURE_UNKNOWN: + *context_cpu_flags = 0; + break; + default: + *context_cpu_flags = 0; + break; + } + } + + // Restore position and return + return SeekSet(saved_position); +} + + +bool Minidump::Read() { + // Invalidate cached data. + delete directory_; + directory_ = NULL; + stream_map_->clear(); + + valid_ = false; + + if (!Open()) { + BPLOG(ERROR) << "Minidump cannot open minidump"; + return false; + } + + if (!ReadBytes(&header_, sizeof(MDRawHeader))) { + BPLOG(ERROR) << "Minidump cannot read header"; + return false; + } + + if (header_.signature != MD_HEADER_SIGNATURE) { + // The file may be byte-swapped. Under the present architecture, these + // classes don't know or need to know what CPU (or endianness) the + // minidump was produced on in order to parse it. Use the signature as + // a byte order marker. + uint32_t signature_swapped = header_.signature; + Swap(&signature_swapped); + if (signature_swapped != MD_HEADER_SIGNATURE) { + // This isn't a minidump or a byte-swapped minidump. + BPLOG(ERROR) << "Minidump header signature mismatch: (" << + HexString(header_.signature) << ", " << + HexString(signature_swapped) << ") != " << + HexString(MD_HEADER_SIGNATURE); + return false; + } + swap_ = true; + } else { + // The file is not byte-swapped. Set swap_ false (it may have been true + // if the object is being reused?) + swap_ = false; + } + +#if defined(__BIG_ENDIAN__) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + is_big_endian_ = !swap_; +#else + is_big_endian_ = swap_; +#endif + + BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") << + "byte-swapping minidump"; + + if (swap_) { + Swap(&header_.signature); + Swap(&header_.version); + Swap(&header_.stream_count); + Swap(&header_.stream_directory_rva); + Swap(&header_.checksum); + Swap(&header_.time_date_stamp); + Swap(&header_.flags); + } + + // Version check. The high 16 bits of header_.version contain something + // else "implementation specific." + if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) { + BPLOG(ERROR) << "Minidump version mismatch: " << + HexString(header_.version & 0x0000ffff) << " != " << + HexString(MD_HEADER_VERSION); + return false; + } + + if (!SeekSet(header_.stream_directory_rva)) { + BPLOG(ERROR) << "Minidump cannot seek to stream directory"; + return false; + } + + if (header_.stream_count > max_streams_) { + BPLOG(ERROR) << "Minidump stream count " << header_.stream_count << + " exceeds maximum " << max_streams_; + return false; + } + + if (header_.stream_count != 0) { + scoped_ptr directory( + new MinidumpDirectoryEntries(header_.stream_count)); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!ReadBytes(&(*directory)[0], + sizeof(MDRawDirectory) * header_.stream_count)) { + BPLOG(ERROR) << "Minidump cannot read stream directory"; + return false; + } + + for (unsigned int stream_index = 0; + stream_index < header_.stream_count; + ++stream_index) { + MDRawDirectory* directory_entry = &(*directory)[stream_index]; + + if (swap_) { + Swap(&directory_entry->stream_type); + Swap(&directory_entry->location); + } + + // Initialize the stream_map_ map, which speeds locating a stream by + // type. + unsigned int stream_type = directory_entry->stream_type; + switch (stream_type) { + case MD_THREAD_LIST_STREAM: + case MD_MODULE_LIST_STREAM: + case MD_MEMORY_LIST_STREAM: + case MD_EXCEPTION_STREAM: + case MD_SYSTEM_INFO_STREAM: + case MD_MISC_INFO_STREAM: + case MD_BREAKPAD_INFO_STREAM: + case MD_CRASHPAD_INFO_STREAM: + case MOZ_MACOS_CRASH_INFO_STREAM: { + if (stream_map_->find(stream_type) != stream_map_->end()) { + // Another stream with this type was already found. A minidump + // file should contain at most one of each of these stream types. + BPLOG(ERROR) << "Minidump found multiple streams of type " << + stream_type << ", but can only deal with one"; + return false; + } + BP_FALLTHROUGH; + } + + default: { + // Overwrites for stream types other than those above, but it's + // expected to be the user's burden in that case. + (*stream_map_)[stream_type].stream_index = stream_index; + } + } + } + + directory_ = directory.release(); + } + + valid_ = true; + return true; +} + + +MinidumpThreadList* Minidump::GetThreadList() { + MinidumpThreadList* thread_list; + return GetStream(&thread_list); +} + + +MinidumpModuleList* Minidump::GetModuleList() { + MinidumpModuleList* module_list; + return GetStream(&module_list); +} + + +MinidumpMemoryList* Minidump::GetMemoryList() { + MinidumpMemoryList* memory_list; + return GetStream(&memory_list); +} + + +MinidumpException* Minidump::GetException() { + MinidumpException* exception; + return GetStream(&exception); +} + +MinidumpAssertion* Minidump::GetAssertion() { + MinidumpAssertion* assertion; + return GetStream(&assertion); +} + + +MinidumpSystemInfo* Minidump::GetSystemInfo() { + MinidumpSystemInfo* system_info; + return GetStream(&system_info); +} + + +MinidumpUnloadedModuleList* Minidump::GetUnloadedModuleList() { + MinidumpUnloadedModuleList* unloaded_module_list; + return GetStream(&unloaded_module_list); +} + + +MinidumpMiscInfo* Minidump::GetMiscInfo() { + MinidumpMiscInfo* misc_info; + return GetStream(&misc_info); +} + + +MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() { + MinidumpBreakpadInfo* breakpad_info; + return GetStream(&breakpad_info); +} + +MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() { + MinidumpMemoryInfoList* memory_info_list; + return GetStream(&memory_info_list); +} + +MinidumpLinuxMapsList *Minidump::GetLinuxMapsList() { + MinidumpLinuxMapsList *linux_maps_list; + return GetStream(&linux_maps_list); +} + +bool Minidump::IsAndroid() { + MDOSPlatform platform; + return GetPlatform(&platform) && platform == MD_OS_ANDROID; +} + +bool Minidump::GetPlatform(MDOSPlatform* platform) { + // Save the current stream position + off_t saved_position = Tell(); + if (saved_position == -1) { + return false; + } + const MDRawSystemInfo* system_info = + GetSystemInfo() ? GetSystemInfo()->system_info() : NULL; + + // Restore position and return + if (!SeekSet(saved_position)) { + BPLOG(ERROR) << "Couldn't seek back to saved position"; + return false; + } + + if (!system_info) { + return false; + } + *platform = static_cast(system_info->platform_id); + return true; +} + +MinidumpCrashpadInfo* Minidump::GetCrashpadInfo() { + MinidumpCrashpadInfo* crashpad_info; + return GetStream(&crashpad_info); +} + +MinidumpMacCrashInfo* Minidump::GetMacCrashInfo() { + MinidumpMacCrashInfo* mac_crash_info; + return GetStream(&mac_crash_info); +} + +MinidumpThreadNamesList* Minidump::GetThreadNamesList() { + MinidumpThreadNamesList* thread_names_list; + return GetStream(&thread_names_list); +} + +// +// MinidumpThreadName +// + + +MinidumpThreadName::MinidumpThreadName(Minidump* minidump) + : MinidumpObject(minidump), + valid_(false), + thread_name_(), + name_(NULL) { + +} + +MinidumpThreadName::~MinidumpThreadName() { + ; +} + +void MinidumpThreadName::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data"; + return; + } + + printf("MDRawThreadName\n"); + printf(" thread_id = 0x%x\n", + thread_name_.thread_id); + printf(" rva_of_thread_name = 0x%" PRIx64 "\n", + thread_name_.rva_of_thread_name); + + printf(" (name) = \"%s\"\n", name().c_str()); + printf("\n"); +} + +string MinidumpThreadName::name() const { + if (!valid_) { + BPLOG(ERROR) << "Invalid MinidumpThreadName for name"; + return ""; + } + + return *name_; +} + +bool MinidumpThreadName::Read(uint32_t expected_size) { + + delete name_; + + if (expected_size < sizeof(thread_name_)) { + BPLOG(ERROR) << "MinidumpThreadName expected size is less than size " + << "of struct " << expected_size << " < " + << sizeof(thread_name_); + return false; + } + + if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) { + BPLOG(ERROR) << "MinidumpThreadName cannot read name"; + return false; + } + + if (expected_size > sizeof(thread_name_)) { + uint32_t thread_name_bytes_remaining = expected_size - sizeof(thread_name_); + off_t pos = minidump_->Tell(); + if (!minidump_->SeekSet(pos + thread_name_bytes_remaining)) { + BPLOG(ERROR) << "MinidumpThreadName unable to seek to end of name"; + return false; + } + } + + if (minidump_->swap()) { + Swap(&thread_name_.thread_id); + uint64_t rva_of_thread_name; + memcpy(&rva_of_thread_name, &thread_name_.rva_of_thread_name, sizeof(uint64_t)); + Swap(&rva_of_thread_name); + memcpy(&thread_name_.rva_of_thread_name, &rva_of_thread_name, sizeof(uint64_t)); + } + + return true; +} + +bool MinidumpThreadName::ReadAuxiliaryData() { + // Each thread must have a name string. + name_ = minidump_->ReadString(thread_name_.rva_of_thread_name); + if (!name_) { + BPLOG(ERROR) << "MinidumpThreadName could not read name"; + valid_ = false; + return false; + } + + // At this point, we have enough info for the name to be valid. + valid_ = true; + return true; +} + +// +// MinidumpThreadNamesList +// + + +MinidumpThreadNamesList::MinidumpThreadNamesList(Minidump* minidump) + : MinidumpStream(minidump), + thread_names_(NULL), + name_count_(0), + valid_(false) { + ; +} + +MinidumpThreadNamesList::~MinidumpThreadNamesList() { + delete thread_names_; +} + +const string MinidumpThreadNamesList::GetNameForThreadId(uint32_t thread_id) const { + if (valid_) { + for (unsigned int name_index = 0; + name_index < name_count_; + ++name_index) { + const MinidumpThreadName& thread_name = (*thread_names_)[name_index]; + if (thread_name.thread_id() == thread_id) { + return thread_name.name(); + } + } + } + + return ""; +} + +void MinidumpThreadNamesList::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpThreadNamesList cannot print invalid data"; + return; + } + + printf("MinidumpThreadNamesList\n"); + printf(" name_count = %d\n", name_count_); + printf("\n"); + + for (unsigned int name_index = 0; + name_index < name_count_; + ++name_index) { + printf("thread_name[%d]\n", name_index); + + (*thread_names_)[name_index].Print(); + } +} + +bool MinidumpThreadNamesList::Read(uint32_t expected_size) { + delete thread_names_; + thread_names_ = NULL; + name_count_ = 0; + + valid_ = false; + + uint32_t number_of_thread_names; + if (!minidump_->ReadBytes(&number_of_thread_names, sizeof(number_of_thread_names))) { + BPLOG(ERROR) << "MinidumpThreadNamesList could not read the number of thread names"; + return false; + } + + if (minidump_->swap()) { + Swap(&number_of_thread_names); + } + + if (expected_size != + sizeof(number_of_thread_names) + (sizeof(MDRawThreadName) * number_of_thread_names)) { + BPLOG(ERROR) << "MinidumpThreadNamesList expected_size mismatch " << + expected_size << " != " << sizeof(number_of_thread_names) << " + (" << + sizeof(MDRawThreadName) << " * " << number_of_thread_names << ")"; + return false; + } + + if (number_of_thread_names != 0) { + scoped_ptr thread_names( + new MinidumpThreadNames(number_of_thread_names, + MinidumpThreadName(minidump_))); + + for (unsigned int name_index = 0; + name_index < number_of_thread_names; + ++name_index) { + MinidumpThreadName* thread_name = &(*thread_names)[name_index]; + + if (!thread_name->Read(sizeof(MDRawThreadName))) { + BPLOG(ERROR) << "MinidumpThreadNamesList could not read name " << + name_index << "/" << number_of_thread_names; + return false; + } + } + + for (unsigned int name_index = 0; + name_index < number_of_thread_names; + ++name_index) { + MinidumpThreadName* thread_name = &(*thread_names)[name_index]; + + if (!thread_name->ReadAuxiliaryData()) { + BPLOG(ERROR) << "MinidumpThreadNamesList could not read required " + "auxiliary data for thread name " << + name_index << "/" << number_of_thread_names; + return false; + } + } + thread_names_ = thread_names.release(); + } + + name_count_ = number_of_thread_names; + valid_ = true; + return true; +} + +static const char* get_stream_name(uint32_t stream_type) { + switch (stream_type) { + case MD_UNUSED_STREAM: + return "MD_UNUSED_STREAM"; + case MD_RESERVED_STREAM_0: + return "MD_RESERVED_STREAM_0"; + case MD_RESERVED_STREAM_1: + return "MD_RESERVED_STREAM_1"; + case MD_THREAD_LIST_STREAM: + return "MD_THREAD_LIST_STREAM"; + case MD_MODULE_LIST_STREAM: + return "MD_MODULE_LIST_STREAM"; + case MD_MEMORY_LIST_STREAM: + return "MD_MEMORY_LIST_STREAM"; + case MD_EXCEPTION_STREAM: + return "MD_EXCEPTION_STREAM"; + case MD_SYSTEM_INFO_STREAM: + return "MD_SYSTEM_INFO_STREAM"; + case MD_THREAD_EX_LIST_STREAM: + return "MD_THREAD_EX_LIST_STREAM"; + case MD_MEMORY_64_LIST_STREAM: + return "MD_MEMORY_64_LIST_STREAM"; + case MD_COMMENT_STREAM_A: + return "MD_COMMENT_STREAM_A"; + case MD_COMMENT_STREAM_W: + return "MD_COMMENT_STREAM_W"; + case MD_HANDLE_DATA_STREAM: + return "MD_HANDLE_DATA_STREAM"; + case MD_FUNCTION_TABLE_STREAM: + return "MD_FUNCTION_TABLE_STREAM"; + case MD_UNLOADED_MODULE_LIST_STREAM: + return "MD_UNLOADED_MODULE_LIST_STREAM"; + case MD_MISC_INFO_STREAM: + return "MD_MISC_INFO_STREAM"; + case MD_MEMORY_INFO_LIST_STREAM: + return "MD_MEMORY_INFO_LIST_STREAM"; + case MD_THREAD_INFO_LIST_STREAM: + return "MD_THREAD_INFO_LIST_STREAM"; + case MD_HANDLE_OPERATION_LIST_STREAM: + return "MD_HANDLE_OPERATION_LIST_STREAM"; + case MD_TOKEN_STREAM: + return "MD_TOKEN_STREAM"; + case MD_JAVASCRIPT_DATA_STREAM: + return "MD_JAVASCRIPT_DATA_STREAM"; + case MD_SYSTEM_MEMORY_INFO_STREAM: + return "MD_SYSTEM_MEMORY_INFO_STREAM"; + case MD_PROCESS_VM_COUNTERS_STREAM: + return "MD_PROCESS_VM_COUNTERS_STREAM"; + case MD_IPT_TRACE_STREAM: + return "MD_IPT_TRACE_STREAM"; + case MD_THREAD_NAMES_STREAM: + return "MD_THREAD_NAMES_STREAM"; + case MD_LAST_RESERVED_STREAM: + return "MD_LAST_RESERVED_STREAM"; + case MD_BREAKPAD_INFO_STREAM: + return "MD_BREAKPAD_INFO_STREAM"; + case MD_ASSERTION_INFO_STREAM: + return "MD_ASSERTION_INFO_STREAM"; + case MD_LINUX_CPU_INFO: + return "MD_LINUX_CPU_INFO"; + case MD_LINUX_PROC_STATUS: + return "MD_LINUX_PROC_STATUS"; + case MD_LINUX_LSB_RELEASE: + return "MD_LINUX_LSB_RELEASE"; + case MD_LINUX_CMD_LINE: + return "MD_LINUX_CMD_LINE"; + case MD_LINUX_ENVIRON: + return "MD_LINUX_ENVIRON"; + case MD_LINUX_AUXV: + return "MD_LINUX_AUXV"; + case MD_LINUX_MAPS: + return "MD_LINUX_MAPS"; + case MD_LINUX_DSO_DEBUG: + return "MD_LINUX_DSO_DEBUG"; + case MD_CRASHPAD_INFO_STREAM: + return "MD_CRASHPAD_INFO_STREAM"; + case MOZ_MACOS_CRASH_INFO_STREAM: + return "MOZ_MACOS_CRASH_INFO_STREAM"; + default: + return "unknown"; + } +} + +void Minidump::Print() { + if (!valid_) { + BPLOG(ERROR) << "Minidump cannot print invalid data"; + return; + } + + printf("MDRawHeader\n"); + printf(" signature = 0x%x\n", header_.signature); + printf(" version = 0x%x\n", header_.version); + printf(" stream_count = %d\n", header_.stream_count); + printf(" stream_directory_rva = 0x%x\n", header_.stream_directory_rva); + printf(" checksum = 0x%x\n", header_.checksum); + printf(" time_date_stamp = 0x%x %s\n", + header_.time_date_stamp, + TimeTToUTCString(header_.time_date_stamp).c_str()); + printf(" flags = 0x%" PRIx64 "\n", header_.flags); + printf("\n"); + + for (unsigned int stream_index = 0; + stream_index < header_.stream_count; + ++stream_index) { + MDRawDirectory* directory_entry = &(*directory_)[stream_index]; + + printf("mDirectory[%d]\n", stream_index); + printf("MDRawDirectory\n"); + printf(" stream_type = 0x%x (%s)\n", directory_entry->stream_type, + get_stream_name(directory_entry->stream_type)); + printf(" location.data_size = %d\n", + directory_entry->location.data_size); + printf(" location.rva = 0x%x\n", directory_entry->location.rva); + printf("\n"); + } + + printf("Streams:\n"); + for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin(); + iterator != stream_map_->end(); + ++iterator) { + uint32_t stream_type = iterator->first; + const MinidumpStreamInfo& info = iterator->second; + printf(" stream type 0x%x (%s) at index %d\n", stream_type, + get_stream_name(stream_type), + info.stream_index); + } + printf("\n"); +} + + +const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index) + const { + if (!valid_) { + BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex"; + return NULL; + } + + if (index >= header_.stream_count) { + BPLOG(ERROR) << "Minidump stream directory index out of range: " << + index << "/" << header_.stream_count; + return NULL; + } + + return &(*directory_)[index]; +} + + +bool Minidump::ReadBytes(void* bytes, size_t count) { + // Can't check valid_ because Read needs to call this method before + // validity can be determined. + if (!stream_) { + return false; + } + stream_->read(static_cast(bytes), count); + std::streamsize bytes_read = stream_->gcount(); + if (bytes_read == -1) { + string error_string; + int error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string; + return false; + } + + // Convert to size_t and check for data loss + size_t bytes_read_converted = static_cast(bytes_read); + if (static_cast(bytes_read_converted) != bytes_read) { + BPLOG(ERROR) << "ReadBytes: conversion data loss detected when converting " + << bytes_read << " to " << bytes_read_converted; + return false; + } + + if (bytes_read_converted != count) { + BPLOG(ERROR) << "ReadBytes: read " << bytes_read_converted << "/" << count; + return false; + } + + return true; +} + + +bool Minidump::SeekSet(off_t offset) { + // Can't check valid_ because Read needs to call this method before + // validity can be determined. + if (!stream_) { + return false; + } + stream_->seekg(offset, std::ios_base::beg); + if (!stream_->good()) { + string error_string; + int error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string; + return false; + } + return true; +} + +off_t Minidump::Tell() { + if (!valid_ || !stream_) { + return (off_t)-1; + } + + // Check for conversion data loss + std::streamoff std_streamoff = stream_->tellg(); + off_t rv = static_cast(std_streamoff); + if (static_cast(rv) == std_streamoff) { + return rv; + } else { + BPLOG(ERROR) << "Data loss detected"; + return (off_t)-1; + } +} + + +string* Minidump::ReadString(off_t offset) { + if (!valid_) { + BPLOG(ERROR) << "Invalid Minidump for ReadString"; + return NULL; + } + if (!SeekSet(offset)) { + BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset; + return NULL; + } + + uint32_t bytes; + if (!ReadBytes(&bytes, sizeof(bytes))) { + BPLOG(ERROR) << "ReadString could not read string size at offset " << + offset; + return NULL; + } + if (swap_) + Swap(&bytes); + + if (bytes % 2 != 0) { + BPLOG(ERROR) << "ReadString found odd-sized " << bytes << + "-byte string at offset " << offset; + return NULL; + } + unsigned int utf16_words = bytes / 2; + + if (utf16_words > max_string_length_) { + BPLOG(ERROR) << "ReadString string length " << utf16_words << + " exceeds maximum " << max_string_length_ << + " at offset " << offset; + return NULL; + } + + vector string_utf16(utf16_words); + + if (utf16_words) { + if (!ReadBytes(&string_utf16[0], bytes)) { + BPLOG(ERROR) << "ReadString could not read " << bytes << + "-byte string at offset " << offset; + return NULL; + } + } + + return UTF16ToUTF8(string_utf16, swap_); +} + + +bool Minidump::ReadUTF8String(off_t offset, string* string_utf8) { + if (!valid_) { + BPLOG(ERROR) << "Invalid Minidump for ReadString"; + return false; + } + if (!SeekSet(offset)) { + BPLOG(ERROR) << "ReadUTF8String could not seek to string at offset " + << offset; + return false; + } + + uint32_t bytes; + if (!ReadBytes(&bytes, sizeof(bytes))) { + BPLOG(ERROR) << "ReadUTF8String could not read string size at offset " << + offset; + return false; + } + + if (swap_) { + Swap(&bytes); + } + + if (bytes > max_string_length_) { + BPLOG(ERROR) << "ReadUTF8String string length " << bytes << + " exceeds maximum " << max_string_length_ << + " at offset " << offset; + return false; + } + + string_utf8->resize(bytes); + + if (!ReadBytes(&(*string_utf8)[0], bytes)) { + BPLOG(ERROR) << "ReadUTF8String could not read " << bytes << + "-byte string at offset " << offset; + return false; + } + + return true; +} + + +bool Minidump::ReadStringList( + off_t offset, + std::vector* string_list) { + string_list->clear(); + + if (!SeekSet(offset)) { + BPLOG(ERROR) << "Minidump cannot seek to string_list"; + return false; + } + + uint32_t count; + if (!ReadBytes(&count, sizeof(count))) { + BPLOG(ERROR) << "Minidump cannot read string_list count"; + return false; + } + + if (swap_) { + Swap(&count); + } + + scoped_array rvas(new MDRVA[count]); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!ReadBytes(&rvas[0], sizeof(MDRVA) * count)) { + BPLOG(ERROR) << "Minidump could not read string_list"; + return false; + } + + for (uint32_t index = 0; index < count; ++index) { + if (swap()) { + Swap(&rvas[index]); + } + + string entry; + if (!ReadUTF8String(rvas[index], &entry)) { + BPLOG(ERROR) << "Minidump could not read string_list entry"; + return false; + } + + string_list->push_back(entry); + } + + return true; +} + + +bool Minidump::ReadSimpleStringDictionary( + off_t offset, + std::map* simple_string_dictionary) { + simple_string_dictionary->clear(); + + if (!SeekSet(offset)) { + BPLOG(ERROR) << "Minidump cannot seek to simple_string_dictionary"; + return false; + } + + uint32_t count; + if (!ReadBytes(&count, sizeof(count))) { + BPLOG(ERROR) + << "Minidump cannot read simple_string_dictionary count"; + return false; + } + + if (swap()) { + Swap(&count); + } + + scoped_array entries( + new MDRawSimpleStringDictionaryEntry[count]); + + // Read the entire array in one fell swoop, instead of reading one entry + // at a time in the loop. + if (!ReadBytes( + &entries[0], + sizeof(MDRawSimpleStringDictionaryEntry) * count)) { + BPLOG(ERROR) << "Minidump could not read simple_string_dictionary"; + return false; + } + + for (uint32_t index = 0; index < count; ++index) { + if (swap()) { + Swap(&entries[index]); + } + + string key; + if (!ReadUTF8String(entries[index].key, &key)) { + BPLOG(ERROR) << "Minidump could not read simple_string_dictionary key"; + return false; + } + + string value; + if (!ReadUTF8String(entries[index].value, &value)) { + BPLOG(ERROR) << "Minidump could not read simple_string_dictionary value"; + return false; + } + + if (simple_string_dictionary->find(key) != + simple_string_dictionary->end()) { + BPLOG(ERROR) + << "Minidump: discarding duplicate simple_string_dictionary value " + << value << " for key " << key; + } else { + simple_string_dictionary->insert(std::make_pair(key, value)); + } + } + + return true; +} + + +bool Minidump::SeekToStreamType(uint32_t stream_type, + uint32_t* stream_length) { + BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires " + "|stream_length|"; + assert(stream_length); + *stream_length = 0; + + if (!valid_) { + BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType"; + return false; + } + + MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type); + if (iterator == stream_map_->end()) { + // This stream type didn't exist in the directory. + BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present"; + return false; + } + + const MinidumpStreamInfo& info = iterator->second; + if (info.stream_index >= header_.stream_count) { + BPLOG(ERROR) << "SeekToStreamType: type " << stream_type << + " out of range: " << + info.stream_index << "/" << header_.stream_count; + return false; + } + + MDRawDirectory* directory_entry = &(*directory_)[info.stream_index]; + if (!SeekSet(directory_entry->location.rva)) { + BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " << + stream_type; + return false; + } + + *stream_length = directory_entry->location.data_size; + + return true; +} + + +template +T* Minidump::GetStream(T** stream) { + // stream is a garbage parameter that's present only to account for C++'s + // inability to overload a method based solely on its return type. + + const uint32_t stream_type = T::kStreamType; + + BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type << + " requires |stream|"; + assert(stream); + *stream = NULL; + + if (!valid_) { + BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type; + return NULL; + } + + MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type); + if (iterator == stream_map_->end()) { + // This stream type didn't exist in the directory. + BPLOG(INFO) << "GetStream: type " << stream_type << " not present"; + return NULL; + } + + // Get a pointer so that the stored stream field can be altered. + MinidumpStreamInfo* info = &iterator->second; + + if (info->stream) { + // This cast is safe because info.stream is only populated by this + // method, and there is a direct correlation between T and stream_type. + *stream = static_cast(info->stream); + return *stream; + } + + uint32_t stream_length; + if (!SeekToStreamType(stream_type, &stream_length)) { + BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type; + return NULL; + } + + scoped_ptr new_stream(new T(this)); + + if (!new_stream->Read(stream_length)) { + BPLOG(ERROR) << "GetStream could not read stream type " << stream_type; + return NULL; + } + + *stream = new_stream.release(); + info->stream = *stream; + return *stream; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump.cc new file mode 100644 index 0000000000..63f25f3800 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump.cc @@ -0,0 +1,291 @@ +// 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_dump.cc: Print the contents of a minidump file in somewhat +// readable text. +// +// Author: Mark Mentovai + +#include +#include +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/minidump.h" +#include "processor/logging.h" + +namespace { + +using google_breakpad::Minidump; +using google_breakpad::MinidumpThreadList; +using google_breakpad::MinidumpModuleList; +using google_breakpad::MinidumpUnloadedModuleList; +using google_breakpad::MinidumpMemoryInfoList; +using google_breakpad::MinidumpMemoryList; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpAssertion; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpMiscInfo; +using google_breakpad::MinidumpBreakpadInfo; +using google_breakpad::MinidumpCrashpadInfo; +using google_breakpad::MinidumpThreadNamesList; + +struct Options { + Options() + : minidumpPath(), hexdump(false), hexdump_width(16) {} + + string minidumpPath; + bool hexdump; + unsigned int hexdump_width; +}; + +static void DumpRawStream(Minidump *minidump, + uint32_t stream_type, + const char *stream_name, + int *errors) { + uint32_t length = 0; + if (!minidump->SeekToStreamType(stream_type, &length)) { + return; + } + + printf("Stream %s:\n", stream_name); + + if (length == 0) { + printf("\n"); + return; + } + std::vector contents(length); + if (!minidump->ReadBytes(&contents[0], length)) { + ++*errors; + BPLOG(ERROR) << "minidump.ReadBytes failed"; + return; + } + size_t current_offset = 0; + while (current_offset < length) { + size_t remaining = length - current_offset; + // Printf requires an int and direct casting from size_t results + // in compatibility warnings. + uint32_t int_remaining = remaining; + printf("%.*s", int_remaining, &contents[current_offset]); + char *next_null = reinterpret_cast( + memchr(&contents[current_offset], 0, remaining)); + if (next_null == NULL) + break; + printf("\\0\n"); + size_t null_offset = next_null - &contents[0]; + current_offset = null_offset + 1; + } + printf("\n\n"); +} + +static bool PrintMinidumpDump(const Options& options) { + Minidump minidump(options.minidumpPath, + options.hexdump); + if (!minidump.Read()) { + BPLOG(ERROR) << "minidump.Read() failed"; + return false; + } + minidump.Print(); + + int errors = 0; + + MinidumpThreadList *thread_list = minidump.GetThreadList(); + if (!thread_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetThreadList() failed"; + } else { + thread_list->Print(); + } + + // It's useful to be able to see the full list of modules here even if it + // would cause minidump_stackwalk to fail. + MinidumpModuleList::set_max_modules(UINT32_MAX); + MinidumpModuleList *module_list = minidump.GetModuleList(); + if (!module_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetModuleList() failed"; + } else { + module_list->Print(); + } + + MinidumpUnloadedModuleList::set_max_modules(UINT32_MAX); + MinidumpUnloadedModuleList *unloaded_module_list = minidump.GetUnloadedModuleList(); + if (!unloaded_module_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetUnloadedModuleList() failed"; + } else { + unloaded_module_list->Print(); + } + + MinidumpMemoryList *memory_list = minidump.GetMemoryList(); + if (!memory_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetMemoryList() failed"; + } else { + memory_list->Print(); + } + + MinidumpException *exception = minidump.GetException(); + if (!exception) { + BPLOG(INFO) << "minidump.GetException() failed"; + } else { + exception->Print(); + } + + MinidumpAssertion *assertion = minidump.GetAssertion(); + if (!assertion) { + BPLOG(INFO) << "minidump.GetAssertion() failed"; + } else { + assertion->Print(); + } + + MinidumpSystemInfo *system_info = minidump.GetSystemInfo(); + if (!system_info) { + ++errors; + BPLOG(ERROR) << "minidump.GetSystemInfo() failed"; + } else { + system_info->Print(); + } + + MinidumpMiscInfo *misc_info = minidump.GetMiscInfo(); + if (!misc_info) { + ++errors; + BPLOG(ERROR) << "minidump.GetMiscInfo() failed"; + } else { + misc_info->Print(); + } + + MinidumpBreakpadInfo *breakpad_info = minidump.GetBreakpadInfo(); + if (!breakpad_info) { + // Breakpad info is optional, so don't treat this as an error. + BPLOG(INFO) << "minidump.GetBreakpadInfo() failed"; + } else { + breakpad_info->Print(); + } + + MinidumpMemoryInfoList *memory_info_list = minidump.GetMemoryInfoList(); + if (!memory_info_list) { + ++errors; + BPLOG(ERROR) << "minidump.GetMemoryInfoList() failed"; + } else { + memory_info_list->Print(); + } + + MinidumpCrashpadInfo *crashpad_info = minidump.GetCrashpadInfo(); + if (crashpad_info) { + // Crashpad info is optional, so don't treat absence as an error. + crashpad_info->Print(); + } + + MinidumpThreadNamesList *thread_names_list = minidump.GetThreadNamesList(); + if (thread_names_list) { + thread_names_list->Print(); + } + + DumpRawStream(&minidump, + MD_LINUX_CMD_LINE, + "MD_LINUX_CMD_LINE", + &errors); + DumpRawStream(&minidump, + MD_LINUX_ENVIRON, + "MD_LINUX_ENVIRON", + &errors); + DumpRawStream(&minidump, + MD_LINUX_LSB_RELEASE, + "MD_LINUX_LSB_RELEASE", + &errors); + DumpRawStream(&minidump, + MD_LINUX_PROC_STATUS, + "MD_LINUX_PROC_STATUS", + &errors); + DumpRawStream(&minidump, + MD_LINUX_CPU_INFO, + "MD_LINUX_CPU_INFO", + &errors); + DumpRawStream(&minidump, + MD_LINUX_MAPS, + "MD_LINUX_MAPS", + &errors); + + return errors == 0; +} + +//============================================================================= +static void +Usage(int argc, char *argv[], bool error) { + FILE *fp = error ? stderr : stdout; + + fprintf(fp, + "Usage: %s [options...] \n" + "Dump data in a minidump.\n" + "\n" + "Options:\n" + " should be a minidump.\n" + " -x:\t Display memory in a hexdump like format\n" + " -h:\t Usage\n", + argv[0]); +} + +//============================================================================= +static void +SetupOptions(int argc, char *argv[], Options *options) { + int ch; + + while ((ch = getopt(argc, (char * const *)argv, "xh")) != -1) { + switch (ch) { + case 'x': + options->hexdump = true; + break; + case 'h': + Usage(argc, argv, false); + exit(0); + + default: + Usage(argc, argv, true); + exit(1); + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + exit(1); + } + + options->minidumpPath = argv[optind]; +} + +} // namespace + +int main(int argc, char *argv[]) { + Options options; + BPLOG_INIT(&argc, &argv); + SetupOptions(argc, argv, &options); + return PrintMinidumpDump(options) ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump_test b/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump_test new file mode 100755 index 0000000000..fb62ace735 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_dump_test @@ -0,0 +1,36 @@ +#!/bin/sh + +# 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. + +testdata_dir=$srcdir/src/processor/testdata +./src/processor/minidump_dump $testdata_dir/minidump2.dmp | \ + tr -d '\015' | \ + diff -u $testdata_dir/minidump2.dump.out - +exit $? diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor.cc new file mode 100644 index 0000000000..bebac3ea48 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor.cc @@ -0,0 +1,2146 @@ +// 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 "google_breakpad/processor/minidump_processor.h" + +#include + +#include + +#include "common/scoped_ptr.h" +#include "common/stdio_wrapper.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/exploitability.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "processor/logging.h" +#include "processor/stackwalker_x86.h" +#include "processor/symbolic_constants_win.h" + +namespace google_breakpad { + +MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), + own_frame_symbolizer_(true), + enable_exploitability_(false), + enable_objdump_(false) { +} + +MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, + SourceLineResolverInterface *resolver, + bool enable_exploitability) + : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), + own_frame_symbolizer_(true), + enable_exploitability_(enable_exploitability), + enable_objdump_(false) { +} + +MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer, + bool enable_exploitability) + : frame_symbolizer_(frame_symbolizer), + own_frame_symbolizer_(false), + enable_exploitability_(enable_exploitability), + enable_objdump_(false) { + assert(frame_symbolizer_); +} + +MinidumpProcessor::~MinidumpProcessor() { + if (own_frame_symbolizer_) delete frame_symbolizer_; +} + +ProcessResult MinidumpProcessor::Process( + Minidump *dump, ProcessState *process_state) { + assert(dump); + assert(process_state); + + process_state->Clear(); + + const MDRawHeader *header = dump->header(); + if (!header) { + BPLOG(ERROR) << "Minidump " << dump->path() << " has no header"; + return PROCESS_ERROR_NO_MINIDUMP_HEADER; + } + process_state->time_date_stamp_ = header->time_date_stamp; + + bool has_process_create_time = + GetProcessCreateTime(dump, &process_state->process_create_time_); + + bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_); + bool has_os_info = GetOSInfo(dump, &process_state->system_info_); + + uint32_t dump_thread_id = 0; + bool has_dump_thread = false; + uint32_t requesting_thread_id = 0; + bool has_requesting_thread = false; + + MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo(); + if (breakpad_info) { + has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id); + has_requesting_thread = + breakpad_info->GetRequestingThreadID(&requesting_thread_id); + } + + MinidumpException *exception = dump->GetException(); + if (exception) { + process_state->crashed_ = true; + has_requesting_thread = exception->GetThreadID(&requesting_thread_id); + + process_state->crash_reason_ = GetCrashReason( + dump, &process_state->crash_address_); + + process_state->exception_record_.set_code( + exception->exception()->exception_record.exception_code, + // TODO(ivanpe): Populate description. + /* description = */ ""); + process_state->exception_record_.set_flags( + exception->exception()->exception_record.exception_flags, + // TODO(ivanpe): Populate description. + /* description = */ ""); + process_state->exception_record_.set_nested_exception_record_address( + exception->exception()->exception_record.exception_record); + process_state->exception_record_.set_address(process_state->crash_address_); + for (uint32_t i = 0; + i < exception->exception()->exception_record.number_parameters; i++) { + process_state->exception_record_.add_parameter( + exception->exception()->exception_record.exception_information[i], + // TODO(ivanpe): Populate description. + /* description = */ ""); + } + } + + MinidumpMacCrashInfo *crash_info = dump->GetMacCrashInfo(); + if (crash_info) { + process_state->mac_crash_info_ = crash_info->description(); + process_state->mac_crash_info_records_ = crash_info->records(); + } + + // This will just return an empty string if it doesn't exist. + process_state->assertion_ = GetAssertion(dump); + + MinidumpModuleList *module_list = dump->GetModuleList(); + + // Put a copy of the module list into ProcessState object. This is not + // necessarily a MinidumpModuleList, but it adheres to the CodeModules + // interface, which is all that ProcessState needs to expose. + if (module_list) { + process_state->modules_ = module_list->Copy(); + process_state->shrunk_range_modules_ = + process_state->modules_->GetShrunkRangeModules(); + for (unsigned int i = 0; + i < process_state->shrunk_range_modules_.size(); + i++) { + linked_ptr module = + process_state->shrunk_range_modules_[i]; + BPLOG(INFO) << "The range for module " << module->code_file() + << " was shrunk down by " << HexString( + module->shrink_down_delta()) << " bytes. "; + } + } + + MinidumpUnloadedModuleList *unloaded_module_list = + dump->GetUnloadedModuleList(); + if (unloaded_module_list) { + process_state->unloaded_modules_ = unloaded_module_list->Copy(); + } + + MinidumpMemoryList *memory_list = dump->GetMemoryList(); + if (memory_list) { + BPLOG(INFO) << "Found " << memory_list->region_count() + << " memory regions."; + } + + MinidumpThreadNamesList* thread_names_list = dump->GetThreadNamesList(); + if (thread_names_list) { + BPLOG(INFO) << "Found " << thread_names_list->name_count() + << " thread names."; + } + + MinidumpThreadList *threads = dump->GetThreadList(); + if (!threads) { + BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list"; + return PROCESS_ERROR_NO_THREAD_LIST; + } + + BPLOG(INFO) << "Minidump " << dump->path() << " has " << + (has_cpu_info ? "" : "no ") << "CPU info, " << + (has_os_info ? "" : "no ") << "OS info, " << + (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << + (exception != NULL ? "" : "no ") << "exception, " << + (module_list != NULL ? "" : "no ") << "module list, " << + (threads != NULL ? "" : "no ") << "thread list, " << + (has_dump_thread ? "" : "no ") << "dump thread, " << + (has_requesting_thread ? "" : "no ") << "requesting thread, and " << + (has_process_create_time ? "" : "no ") << "process create time"; + + bool interrupted = false; + bool found_requesting_thread = false; + unsigned int thread_count = threads->thread_count(); + + // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. + frame_symbolizer_->Reset(); + + for (unsigned int thread_index = 0; + thread_index < thread_count; + ++thread_index) { + char thread_string_buffer[64]; + snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d", + thread_index, thread_count); + string thread_string = dump->path() + ":" + thread_string_buffer; + + MinidumpThread *thread = threads->GetThreadAtIndex(thread_index); + if (!thread) { + BPLOG(ERROR) << "Could not get thread for " << thread_string; + return PROCESS_ERROR_GETTING_THREAD; + } + + uint32_t thread_id; + if (!thread->GetThreadID(&thread_id)) { + BPLOG(ERROR) << "Could not get thread ID for " << thread_string; + return PROCESS_ERROR_GETTING_THREAD_ID; + } + + thread_string += " id " + HexString(thread_id); + BPLOG(INFO) << "Looking at thread " << thread_string; + + // If this thread is the thread that produced the minidump, don't process + // it. Because of the problems associated with a thread producing a + // dump of itself (when both its context and its stack are in flux), + // processing that stack wouldn't provide much useful data. + if (has_dump_thread && thread_id == dump_thread_id) { + continue; + } + + MinidumpContext *context = thread->GetContext(); + + if (has_requesting_thread && thread_id == requesting_thread_id) { + if (found_requesting_thread) { + // There can't be more than one requesting thread. + BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string; + return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS; + } + + // Use processed_state->threads_.size() instead of thread_index. + // thread_index points to the thread index in the minidump, which + // might be greater than the thread index in the threads vector if + // any of the minidump's threads are skipped and not placed into the + // processed threads vector. The thread vector's current size will + // be the index of the current thread when it's pushed into the + // vector. + process_state->requesting_thread_ = process_state->threads_.size(); + + found_requesting_thread = true; + + if (process_state->crashed_) { + // Use the exception record's context for the crashed thread, instead + // of the thread's own context. For the crashed thread, the thread's + // own context is the state inside the exception handler. Using it + // would not result in the expected stack trace from the time of the + // crash. If the exception context is invalid, however, we fall back + // on the thread context. + MinidumpContext *ctx = exception->GetContext(); + context = ctx ? ctx : thread->GetContext(); + } + } + + // If the memory region for the stack cannot be read using the RVA stored + // in the memory descriptor inside MINIDUMP_THREAD, try to locate and use + // a memory region (containing the stack) from the minidump memory list. + MinidumpMemoryRegion *thread_memory = thread->GetMemory(); + if (!thread_memory && memory_list) { + uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange(); + if (start_stack_memory_range) { + thread_memory = memory_list->GetMemoryRegionForAddress( + start_stack_memory_range); + } + } + if (!thread_memory) { + BPLOG(ERROR) << "No memory region for " << thread_string; + } + + // Use process_state->modules_ instead of module_list, because the + // |modules| argument will be used to populate the |module| fields in + // the returned StackFrame objects, which will be placed into the + // returned ProcessState object. module_list's lifetime is only as + // long as the Minidump object: it will be deleted when this function + // returns. process_state->modules_ is owned by the ProcessState object + // (just like the StackFrame objects), and is much more suitable for this + // task. + scoped_ptr stackwalker( + Stackwalker::StackwalkerForCPU(process_state->system_info(), + context, + thread_memory, + process_state->modules_, + process_state->unloaded_modules_, + frame_symbolizer_)); + + scoped_ptr stack(new CallStack()); + if (stackwalker.get()) { + if (!stackwalker->Walk(stack.get(), + &process_state->modules_without_symbols_, + &process_state->modules_with_corrupt_symbols_)) { + BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " + << thread_string; + interrupted = true; + } + } else { + // Threads with missing CPU contexts will hit this, but + // don't abort processing the rest of the dump just for + // one bad thread. + BPLOG(ERROR) << "No stackwalker for " << thread_string; + } + stack->set_tid(thread_id); + stack->set_last_error(thread->GetLastError()); + if (thread_names_list) { + stack->set_name(thread_names_list->GetNameForThreadId(thread_id)); + } + process_state->threads_.push_back(stack.release()); + process_state->thread_memory_regions_.push_back(thread_memory); + } + + if (interrupted) { + BPLOG(INFO) << "Processing interrupted for " << dump->path(); + return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; + } + + // If a requesting thread was indicated, it must be present. + if (has_requesting_thread && !found_requesting_thread) { + // Don't mark as an error, but invalidate the requesting thread + BPLOG(ERROR) << "Minidump indicated requesting thread " << + HexString(requesting_thread_id) << ", not found in " << + dump->path(); + process_state->requesting_thread_ = -1; + } + + // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED + process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED; + + // If an exploitability run was requested we perform the platform specific + // rating. + if (enable_exploitability_) { + scoped_ptr exploitability( + Exploitability::ExploitabilityForPlatform(dump, + process_state, + enable_objdump_)); + // The engine will be null if the platform is not supported + if (exploitability != NULL) { + process_state->exploitability_ = exploitability->CheckExploitability(); + } else { + process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE; + } + } + + BPLOG(INFO) << "Processed " << dump->path(); + return PROCESS_OK; +} + +ProcessResult MinidumpProcessor::Process( + const string &minidump_file, ProcessState *process_state) { + BPLOG(INFO) << "Processing minidump in file " << minidump_file; + + Minidump dump(minidump_file); + if (!dump.Read()) { + BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read"; + return PROCESS_ERROR_MINIDUMP_NOT_FOUND; + } + + return Process(&dump, process_state); +} + +// Returns the MDRawSystemInfo from a minidump, or NULL if system info is +// not available from the minidump. If system_info is non-NULL, it is used +// to pass back the MinidumpSystemInfo object. +static const MDRawSystemInfo* GetSystemInfo(Minidump *dump, + MinidumpSystemInfo **system_info) { + MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); + if (!minidump_system_info) + return NULL; + + if (system_info) + *system_info = minidump_system_info; + + return minidump_system_info->system_info(); +} + +static uint64_t GetAddressForArchitecture(const MDCPUArchitecture architecture, + size_t raw_address) +{ + switch (architecture) { + case MD_CPU_ARCHITECTURE_X86: + case MD_CPU_ARCHITECTURE_MIPS: + case MD_CPU_ARCHITECTURE_PPC: + case MD_CPU_ARCHITECTURE_SHX: + case MD_CPU_ARCHITECTURE_ARM: + case MD_CPU_ARCHITECTURE_X86_WIN64: + // 32-bit architectures, mask the upper bits. + return raw_address & 0xffffffffULL; + + default: + // All other architectures either have 64-bit pointers or it's impossible + // to tell from the minidump (e.g. MSIL or SPARC) so use 64-bits anyway. + return raw_address; + } +} + +// Extract CPU info string from ARM-specific MDRawSystemInfo structure. +// raw_info: pointer to source MDRawSystemInfo. +// cpu_info: address of target string, cpu info text will be appended to it. +static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, + string* cpu_info) { + assert(raw_info != NULL && cpu_info != NULL); + + // Write ARM architecture version. + char cpu_string[32]; + snprintf(cpu_string, sizeof(cpu_string), "ARMv%d", + raw_info->processor_level); + cpu_info->append(cpu_string); + + // There is no good list of implementer id values, but the following + // pages provide some help: + // http://comments.gmane.org/gmane.linux.linaro.devel/6903 + // http://forum.xda-developers.com/archive/index.php/t-480226.html + const struct { + uint32_t id; + const char* name; + } vendors[] = { + { 0x41, "ARM" }, + { 0x51, "Qualcomm" }, + { 0x56, "Marvell" }, + { 0x69, "Intel/Marvell" }, + }; + const struct { + uint32_t id; + const char* name; + } parts[] = { + { 0x4100c050, "Cortex-A5" }, + { 0x4100c080, "Cortex-A8" }, + { 0x4100c090, "Cortex-A9" }, + { 0x4100c0f0, "Cortex-A15" }, + { 0x4100c140, "Cortex-R4" }, + { 0x4100c150, "Cortex-R5" }, + { 0x4100b360, "ARM1136" }, + { 0x4100b560, "ARM1156" }, + { 0x4100b760, "ARM1176" }, + { 0x4100b020, "ARM11-MPCore" }, + { 0x41009260, "ARM926" }, + { 0x41009460, "ARM946" }, + { 0x41009660, "ARM966" }, + { 0x510006f0, "Krait" }, + { 0x510000f0, "Scorpion" }, + }; + + const struct { + uint32_t hwcap; + const char* name; + } features[] = { + { MD_CPU_ARM_ELF_HWCAP_SWP, "swp" }, + { MD_CPU_ARM_ELF_HWCAP_HALF, "half" }, + { MD_CPU_ARM_ELF_HWCAP_THUMB, "thumb" }, + { MD_CPU_ARM_ELF_HWCAP_26BIT, "26bit" }, + { MD_CPU_ARM_ELF_HWCAP_FAST_MULT, "fastmult" }, + { MD_CPU_ARM_ELF_HWCAP_FPA, "fpa" }, + { MD_CPU_ARM_ELF_HWCAP_VFP, "vfpv2" }, + { MD_CPU_ARM_ELF_HWCAP_EDSP, "edsp" }, + { MD_CPU_ARM_ELF_HWCAP_JAVA, "java" }, + { MD_CPU_ARM_ELF_HWCAP_IWMMXT, "iwmmxt" }, + { MD_CPU_ARM_ELF_HWCAP_CRUNCH, "crunch" }, + { MD_CPU_ARM_ELF_HWCAP_THUMBEE, "thumbee" }, + { MD_CPU_ARM_ELF_HWCAP_NEON, "neon" }, + { MD_CPU_ARM_ELF_HWCAP_VFPv3, "vfpv3" }, + { MD_CPU_ARM_ELF_HWCAP_VFPv3D16, "vfpv3d16" }, + { MD_CPU_ARM_ELF_HWCAP_TLS, "tls" }, + { MD_CPU_ARM_ELF_HWCAP_VFPv4, "vfpv4" }, + { MD_CPU_ARM_ELF_HWCAP_IDIVA, "idiva" }, + { MD_CPU_ARM_ELF_HWCAP_IDIVT, "idivt" }, + }; + + uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid; + if (cpuid != 0) { + // Extract vendor name from CPUID + const char* vendor = NULL; + uint32_t vendor_id = (cpuid >> 24) & 0xff; + for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) { + if (vendors[i].id == vendor_id) { + vendor = vendors[i].name; + break; + } + } + cpu_info->append(" "); + if (vendor) { + cpu_info->append(vendor); + } else { + snprintf(cpu_string, sizeof(cpu_string), "vendor(0x%x)", vendor_id); + cpu_info->append(cpu_string); + } + + // Extract part name from CPUID + uint32_t part_id = (cpuid & 0xff00fff0); + const char* part = NULL; + for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) { + if (parts[i].id == part_id) { + part = parts[i].name; + break; + } + } + cpu_info->append(" "); + if (part != NULL) { + cpu_info->append(part); + } else { + snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)", part_id); + cpu_info->append(cpu_string); + } + } + uint32_t elf_hwcaps = raw_info->cpu.arm_cpu_info.elf_hwcaps; + if (elf_hwcaps != 0) { + cpu_info->append(" features: "); + const char* comma = ""; + for (size_t i = 0; i < sizeof(features)/sizeof(features[0]); ++i) { + if (elf_hwcaps & features[i].hwcap) { + cpu_info->append(comma); + cpu_info->append(features[i].name); + comma = ","; + } + } + } +} + +// static +bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { + assert(dump); + assert(info); + + info->cpu.clear(); + info->cpu_info.clear(); + + MinidumpSystemInfo *system_info; + const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); + if (!raw_system_info) + return false; + + switch (raw_system_info->processor_architecture) { + case MD_CPU_ARCHITECTURE_X86: + case MD_CPU_ARCHITECTURE_AMD64: { + if (raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_X86) + info->cpu = "x86"; + else + info->cpu = "amd64"; + + const string *cpu_vendor = system_info->GetCPUVendor(); + if (cpu_vendor) { + info->cpu_info = *cpu_vendor; + info->cpu_info.append(" "); + } + + char x86_info[36]; + snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u", + raw_system_info->processor_level, + raw_system_info->processor_revision >> 8, + raw_system_info->processor_revision & 0xff); + info->cpu_info.append(x86_info); + break; + } + + case MD_CPU_ARCHITECTURE_PPC: { + info->cpu = "ppc"; + break; + } + + case MD_CPU_ARCHITECTURE_PPC64: { + info->cpu = "ppc64"; + break; + } + + case MD_CPU_ARCHITECTURE_SPARC: { + info->cpu = "sparc"; + break; + } + + case MD_CPU_ARCHITECTURE_ARM: { + info->cpu = "arm"; + GetARMCpuInfo(raw_system_info, &info->cpu_info); + break; + } + + case MD_CPU_ARCHITECTURE_ARM64: + case MD_CPU_ARCHITECTURE_ARM64_OLD: { + info->cpu = "arm64"; + break; + } + + case MD_CPU_ARCHITECTURE_MIPS: { + info->cpu = "mips"; + break; + } + case MD_CPU_ARCHITECTURE_MIPS64: { + info->cpu = "mips64"; + break; + } + + default: { + // Assign the numeric architecture ID into the CPU string. + char cpu_string[7]; + snprintf(cpu_string, sizeof(cpu_string), "0x%04x", + raw_system_info->processor_architecture); + info->cpu = cpu_string; + break; + } + } + + info->cpu_count = raw_system_info->number_of_processors; + + return true; +} + +// static +bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { + assert(dump); + assert(info); + + info->os.clear(); + info->os_short.clear(); + info->os_version.clear(); + + MinidumpSystemInfo *system_info; + const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); + if (!raw_system_info) + return false; + + info->os_short = system_info->GetOS(); + + switch (raw_system_info->platform_id) { + case MD_OS_WIN32_NT: { + info->os = "Windows NT"; + break; + } + + case MD_OS_WIN32_WINDOWS: { + info->os = "Windows"; + break; + } + + case MD_OS_MAC_OS_X: { + info->os = "Mac OS X"; + break; + } + + case MD_OS_IOS: { + info->os = "iOS"; + break; + } + + case MD_OS_LINUX: { + info->os = "Linux"; + break; + } + + case MD_OS_SOLARIS: { + info->os = "Solaris"; + break; + } + + case MD_OS_ANDROID: { + info->os = "Android"; + break; + } + + case MD_OS_PS3: { + info->os = "PS3"; + break; + } + + case MD_OS_NACL: { + info->os = "NaCl"; + break; + } + + case MD_OS_FUCHSIA: { + info->os = "Fuchsia"; + break; + } + + default: { + // Assign the numeric platform ID into the OS string. + char os_string[11]; + snprintf(os_string, sizeof(os_string), "0x%08x", + raw_system_info->platform_id); + info->os = os_string; + break; + } + } + + char os_version_string[33]; + snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u", + raw_system_info->major_version, + raw_system_info->minor_version, + raw_system_info->build_number); + info->os_version = os_version_string; + + const string *csd_version = system_info->GetCSDVersion(); + if (csd_version) { + info->os_version.append(" "); + info->os_version.append(*csd_version); + } + + return true; +} + +// static +bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump, + uint32_t* process_create_time) { + assert(dump); + assert(process_create_time); + + *process_create_time = 0; + + MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo(); + if (!minidump_misc_info) { + return false; + } + + const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info(); + if (!md_raw_misc_info) { + return false; + } + + if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) { + return false; + } + + *process_create_time = md_raw_misc_info->process_create_time; + return true; +} + +// static +string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { + MinidumpException *exception = dump->GetException(); + if (!exception) + return ""; + + const MDRawExceptionStream *raw_exception = exception->exception(); + if (!raw_exception) + return ""; + + if (address) + *address = raw_exception->exception_record.exception_address; + + // The reason value is OS-specific and possibly CPU-specific. Set up + // sensible numeric defaults for the reason string in case we can't + // map the codes to a string (because there's no system info, or because + // it's an unrecognized platform, or because it's an unrecognized code.) + char reason_string[24]; + char flags_string[11]; + uint32_t exception_code = raw_exception->exception_record.exception_code; + uint32_t exception_flags = raw_exception->exception_record.exception_flags; + snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags); + snprintf(reason_string, sizeof(reason_string), "0x%08x / %s", exception_code, + flags_string); + string reason = reason_string; + + const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL); + if (!raw_system_info) + return reason; + + switch (raw_system_info->platform_id) { + case MD_OS_FUCHSIA: { + switch (exception_code) { + case MD_EXCEPTION_CODE_FUCHSIA_GENERAL: + reason = "GENERAL / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_FATAL_PAGE_FAULT: + reason = "FATAL_PAGE_FAULT / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_UNDEFINED_INSTRUCTION: + reason = "UNDEFINED_INSTRUCTION / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_SW_BREAKPOINT: + reason = "SW_BREAKPOINT / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_HW_BREAKPOINT: + reason = "HW_BREAKPOINT / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_UNALIGNED_ACCESS: + reason = "UNALIGNED_ACCESS / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_THREAD_STARTING: + reason = "THREAD_STARTING / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_THREAD_EXITING: + reason = "THREAD_EXITING / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_POLICY_ERROR: + reason = "POLICY_ERROR / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_CODE_FUCHSIA_PROCESS_STARTING: + reason = "PROCESS_STARTING / "; + reason.append(flags_string); + break; + default: + BPLOG(INFO) << "Unknown exception reason " << reason; + } + break; + } + + case MD_OS_MAC_OS_X: + case MD_OS_IOS: { + switch (exception_code) { + case MD_EXCEPTION_MAC_BAD_ACCESS: + reason = "EXC_BAD_ACCESS / "; + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS: + reason.append("KERN_INVALID_ADDRESS"); + break; + case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE: + reason.append("KERN_PROTECTION_FAILURE"); + break; + case MD_EXCEPTION_CODE_MAC_NO_ACCESS: + reason.append("KERN_NO_ACCESS"); + break; + case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE: + reason.append("KERN_MEMORY_FAILURE"); + break; + case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR: + reason.append("KERN_MEMORY_ERROR"); + break; + case MD_EXCEPTION_CODE_MAC_CODESIGN_ERROR: + reason.append("KERN_CODESIGN_ERROR"); + break; + default: + // arm and ppc overlap + if (raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_ARM || + raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_ARM64_OLD) { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: + reason.append("EXC_ARM_DA_ALIGN"); + break; + case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: + reason.append("EXC_ARM_DA_DEBUG"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + } else if (raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_PPC) { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ: + reason.append("EXC_PPC_VM_PROT_READ"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE: + reason.append("EXC_PPC_BADSPACE"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED: + reason.append("EXC_PPC_UNALIGNED"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + } else if (raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_X86 || + raw_system_info->processor_architecture == + MD_CPU_ARCHITECTURE_AMD64) { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: + reason.append("EXC_I386_GPFLT"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + } else { + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + } + break; + } + break; + case MD_EXCEPTION_MAC_BAD_INSTRUCTION: + reason = "EXC_BAD_INSTRUCTION / "; + switch (raw_system_info->processor_architecture) { + case MD_CPU_ARCHITECTURE_ARM: + case MD_CPU_ARCHITECTURE_ARM64_OLD: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED: + reason.append("EXC_ARM_UNDEFINED"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + case MD_CPU_ARCHITECTURE_PPC: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL: + reason.append("EXC_PPC_INVALID_SYSCALL"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION: + reason.append("EXC_PPC_UNIPL_INST"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION: + reason.append("EXC_PPC_PRIVINST"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER: + reason.append("EXC_PPC_PRIVREG"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_TRACE: + reason.append("EXC_PPC_TRACE"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR: + reason.append("EXC_PPC_PERFMON"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + case MD_CPU_ARCHITECTURE_AMD64: + case MD_CPU_ARCHITECTURE_X86: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION: + reason.append("EXC_I386_INVOP"); + break; + case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT: + reason.append("EXC_I386_INVTSSFLT"); + break; + case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT: + reason.append("EXC_I386_SEGNPFLT"); + break; + case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT: + reason.append("EXC_I386_STKFLT"); + break; + case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: + reason.append("EXC_I386_GPFLT"); + break; + case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT: + reason.append("EXC_I386_ALIGNFLT"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_MAC_ARITHMETIC: + reason = "EXC_ARITHMETIC / "; + switch (raw_system_info->processor_architecture) { + case MD_CPU_ARCHITECTURE_PPC: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW: + reason.append("EXC_PPC_OVERFLOW"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE: + reason.append("EXC_PPC_ZERO_DIVIDE"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT: + reason.append("EXC_FLT_INEXACT"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE: + reason.append("EXC_PPC_FLT_ZERO_DIVIDE"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW: + reason.append("EXC_PPC_FLT_UNDERFLOW"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW: + reason.append("EXC_PPC_FLT_OVERFLOW"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER: + reason.append("EXC_PPC_FLT_NOT_A_NUMBER"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION: + reason.append("EXC_PPC_NOEMULATION"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST: + reason.append("EXC_PPC_ALTIVECASSIST"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + case MD_CPU_ARCHITECTURE_AMD64: + case MD_CPU_ARCHITECTURE_X86: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_X86_DIV: + reason.append("EXC_I386_DIV"); + break; + case MD_EXCEPTION_CODE_MAC_X86_INTO: + reason.append("EXC_I386_INTO"); + break; + case MD_EXCEPTION_CODE_MAC_X86_NOEXT: + reason.append("EXC_I386_NOEXT"); + break; + case MD_EXCEPTION_CODE_MAC_X86_EXTOVR: + reason.append("EXC_I386_EXTOVR"); + break; + case MD_EXCEPTION_CODE_MAC_X86_EXTERR: + reason.append("EXC_I386_EXTERR"); + break; + case MD_EXCEPTION_CODE_MAC_X86_EMERR: + reason.append("EXC_I386_EMERR"); + break; + case MD_EXCEPTION_CODE_MAC_X86_BOUND: + reason.append("EXC_I386_BOUND"); + break; + case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR: + reason.append("EXC_I386_SSEEXTERR"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_MAC_EMULATION: + reason = "EXC_EMULATION / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_SOFTWARE: + reason = "EXC_SOFTWARE / "; + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_ABORT: + reason.append("SIGABRT"); + break; + case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION: + reason.append("UNCAUGHT_NS_EXCEPTION"); + break; + // These are ppc only but shouldn't be a problem as they're + // unused on x86 + case MD_EXCEPTION_CODE_MAC_PPC_TRAP: + reason.append("EXC_PPC_TRAP"); + break; + case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE: + reason.append("EXC_PPC_MIGRATE"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_MAC_BREAKPOINT: + reason = "EXC_BREAKPOINT / "; + switch (raw_system_info->processor_architecture) { + case MD_CPU_ARCHITECTURE_ARM: + case MD_CPU_ARCHITECTURE_ARM64_OLD: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: + reason.append("EXC_ARM_DA_ALIGN"); + break; + case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: + reason.append("EXC_ARM_DA_DEBUG"); + break; + case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT: + reason.append("EXC_ARM_BREAKPOINT"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + case MD_CPU_ARCHITECTURE_PPC: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT: + reason.append("EXC_PPC_BREAKPOINT"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + case MD_CPU_ARCHITECTURE_AMD64: + case MD_CPU_ARCHITECTURE_X86: { + switch (exception_flags) { + case MD_EXCEPTION_CODE_MAC_X86_SGL: + reason.append("EXC_I386_SGL"); + break; + case MD_EXCEPTION_CODE_MAC_X86_BPT: + reason.append("EXC_I386_BPT"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_MAC_SYSCALL: + reason = "EXC_SYSCALL / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_MACH_SYSCALL: + reason = "EXC_MACH_SYSCALL / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_RPC_ALERT: + reason = "EXC_RPC_ALERT / "; + reason.append(flags_string); + break; + case MD_EXCEPTION_MAC_RESOURCE: + reason = "EXC_RESOURCE / "; + { + uint32_t type = (exception_flags >> 29) & 0x7ULL; + uint32_t flavor = (exception_flags >> 26) & 0x7ULL; + char flavor_string[6] = {}; + switch (type) { + case MD_MAC_EXC_RESOURCE_TYPE_CPU: + reason.append("RESOURCE_TYPE_CPU / "); + switch (flavor) { + case MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR: + reason.append("FLAVOR_CPU_MONITOR"); + break; + case MD_MAC_EXC_RESOURCE_FLAVOR_CPU_MONITOR_FATAL: + reason.append("FLAVOR_CPU_MONITOR_FATAL"); + break; + default: + snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); + reason.append(flavor_string); + break; + } + break; + case MD_MAC_EXC_RESOURCE_TYPE_WAKEUPS: + reason.append("RESOURCE_TYPE_WAKEUPS / "); + if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_WAKEUPS_MONITOR) { + reason.append("FLAVOR_WAKEUPS_MONITOR"); + } else { + snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); + reason.append(flavor_string); + } + break; + case MD_MAC_EXC_RESOURCE_TYPE_MEMORY: + reason.append("RESOURCE_TYPE_MEMORY / "); + if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_HIGH_WATERMARK) { + reason.append("FLAVOR_HIGH_WATERMARK"); + } else { + snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); + reason.append(flavor_string); + } + break; + case MD_MAC_EXC_RESOURCE_TYPE_IO: + reason.append("EXC_RESOURCE_TYPE_IO / "); + switch (flavor) { + case MD_MAC_EXC_RESOURCE_FLAVOR_IO_PHYSICAL_WRITES: + reason.append("FLAVOR_IO_PHYSICAL_WRITES"); + break; + case MD_MAC_EXC_RESOURCE_FLAVOR_IO_LOGICAL_WRITES: + reason.append("FLAVOR_IO_LOGICAL_WRITES"); + break; + default: + snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); + reason.append(flavor_string); + break; + } + break; + case MD_MAC_EXC_RESOURCE_TYPE_THREADS: + reason.append("EXC_RESOURCE_TYPE_THREADS / "); + if (flavor == MD_MAC_EXC_RESOURCE_FLAVOR_THREADS_HIGH_WATERMARK) { + reason.append("FLAVOR_THREADS_HIGH_WATERMARK"); + } else { + snprintf(flavor_string, sizeof(flavor_string), "%#3x", flavor); + reason.append(flavor_string); + } + break; + default: + reason.append(flags_string); + break; + } + } + break; + case MD_EXCEPTION_MAC_GUARD: + reason = "EXC_GUARD / "; + { + uint32_t type = (exception_flags >> 29) & 0x7ULL; + uint32_t flavor = exception_flags & 0x1FFFFFFFULL; + switch (type) { + case MD_MAC_EXC_GUARD_TYPE_NONE: + reason.append("GUARD_TYPE_NONE"); + break; + case MD_MAC_EXC_GUARD_TYPE_MACH_PORT: + reason.append("GUARD_TYPE_MACH_PORT"); + + if (flavor) { + std::vector flavors; + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_DESTROY) { + flavors.push_back("GUARD_EXC_DESTROY"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS) { + flavors.push_back("GUARD_EXC_MOD_REFS"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT) { + flavors.push_back("GUARD_EXC_SET_CONTEXT"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SET_CONTEXT) { + flavors.push_back("GUARD_EXC_SET_CONTEXT"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_UNGUARDED) { + flavors.push_back("GUARD_EXC_UNGUARDED"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INCORRECT_GUARD) { + flavors.push_back("GUARD_EXC_INCORRECT_GUARD"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE) { + flavors.push_back("GUARD_EXC_IMMOVABLE"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_STRICT_REPLY) { + flavors.push_back("GUARD_EXC_STRICT_REPLY"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MSG_FILTERED) { + flavors.push_back("GUARD_EXC_MSG_FILTERED"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_RIGHT) { + flavors.push_back("GUARD_EXC_INVALID_RIGHT"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_NAME) { + flavors.push_back("GUARD_EXC_INVALID_NAME"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_VALUE) { + flavors.push_back("GUARD_EXC_INVALID_VALUE"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_INVALID_ARGUMENT) { + flavors.push_back("GUARD_EXC_INVALID_ARGUMENT"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RIGHT_EXISTS) { + flavors.push_back("GUARD_EXC_RIGHT_EXISTS"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_NO_SPACE) { + flavors.push_back("GUARD_EXC_KERN_NO_SPACE"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_FAILURE) { + flavors.push_back("GUARD_EXC_KERN_FAILURE"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_KERN_RESOURCE) { + flavors.push_back("GUARD_EXC_KERN_RESOURCE"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_REPLY) { + flavors.push_back("GUARD_EXC_SEND_INVALID_REPLY"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_VOUCHER) { + flavors.push_back("GUARD_EXC_SEND_INVALID_VOUCHER"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_SEND_INVALID_RIGHT) { + flavors.push_back("GUARD_EXC_SEND_INVALID_RIGHT"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_INVALID_NAME) { + flavors.push_back("GUARD_EXC_RCV_INVALID_NAME"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_RCV_GUARDED_DESC) { + flavors.push_back("GUARD_EXC_RCV_GUARDED_DESC"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_MOD_REFS_NON_FATAL) { + flavors.push_back("GUARD_EXC_MOD_REFS_NON_FATAL"); + } + + if (flavor & MD_MAC_EXC_GUARD_MACH_PORT_FLAVOR_GUARD_EXC_IMMOVABLE_NON_FATAL) { + flavors.push_back("GUARD_EXC_IMMOVABLE_NON_FATAL"); + } + + reason.append(" / "); + for (size_t i = 0; i < flavors.size(); i++) { + if (i > 0) { + reason.append(" | "); + } + + reason.append(flavors[i]); + } + } + + break; + case MD_MAC_EXC_GUARD_TYPE_FD: + reason.append("GUARD_TYPE_FD"); + + if (flavor) { + std::vector flavors; + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_CLOSE) { + flavors.push_back("GUARD_EXC_CLOSE"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_DUP) { + flavors.push_back("GUARD_EXC_DUP"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_NOCLOEXEC) { + flavors.push_back("GUARD_EXC_NOCLOEXEC"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_SOCKET_IPC) { + flavors.push_back("GUARD_EXC_SOCKET_IPC"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_FILEPORT) { + flavors.push_back("GUARD_EXC_FILEPORT"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_MISMATCH) { + flavors.push_back("GUARD_EXC_MISMATCH"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE) { + flavors.push_back("GUARD_EXC_WRITE"); + } + + reason.append(" / "); + for (size_t i = 0; i < flavors.size(); i++) { + if (i > 0) { + reason.append(" | "); + } + + reason.append(flavors[i]); + } + } + + break; + case MD_MAC_EXC_GUARD_TYPE_USER: + reason.append("GUARD_TYPE_USER"); + break; + case MD_MAC_EXC_GUARD_TYPE_VN: + reason.append("GUARD_TYPE_VN"); + + if (flavor) { + std::vector flavors; + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_TO) { + flavors.push_back("GUARD_EXC_RENAME_TO"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_RENAME_FROM) { + flavors.push_back("GUARD_EXC_RENAME_FROM"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_UNLINK) { + flavors.push_back("GUARD_EXC_UNLINK"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_WRITE_OTHER) { + flavors.push_back("GUARD_EXC_WRITE_OTHER"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_TRUNC_OTHER) { + flavors.push_back("GUARD_EXC_TRUNC_OTHER"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_LINK) { + flavors.push_back("GUARD_EXC_LINK"); + } + + if (flavor & MD_MAC_EXC_GUARD_FD_FLAVOR_GUARD_EXC_EXCHDATA) { + flavors.push_back("GUARD_EXC_EXCHDATA"); + } + + reason.append(" / "); + for (size_t i = 0; i < flavors.size(); i++) { + if (i > 0) { + reason.append(" | "); + } + + reason.append(flavors[i]); + } + } + + break; + case MD_MAC_EXC_GUARD_TYPE_VIRT_MEMORY: + reason.append("GUARD_TYPE_VIRT_MEMORY"); + + if (flavor & MD_MAC_EXC_GUARD_VIRT_MEMORY_FLAVOR_GUARD_EXC_DEALLOC_GAP) { + reason.append(" / GUARD_EXC_DEALLOC_GAP"); + } + + break; + default: + reason.append(flags_string); + break; + } + } + break; + case MD_EXCEPTION_MAC_SIMULATED: + reason = "Simulated Exception"; + break; + } + break; + } + + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: { + switch (exception_code) { + case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: + reason = "EXCEPTION_GUARD_PAGE"; + break; + case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT: + reason = "EXCEPTION_DATATYPE_MISALIGNMENT"; + break; + case MD_EXCEPTION_CODE_WIN_BREAKPOINT: + reason = "EXCEPTION_BREAKPOINT"; + break; + case MD_EXCEPTION_CODE_WIN_SINGLE_STEP: + reason = "EXCEPTION_SINGLE_STEP"; + break; + case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: + // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that + // caused the fault in exception_information[1]. + // exception_information[0] is 0 if the violation was caused by + // an attempt to read data, 1 if it was an attempt to write data, + // and 8 if this was a data execution violation. + // This information is useful in addition to the code address, which + // will be present in the crash thread's instruction field anyway. + if (raw_exception->exception_record.number_parameters >= 1) { + MDAccessViolationTypeWin av_type = + static_cast + (raw_exception->exception_record.exception_information[0]); + switch (av_type) { + case MD_ACCESS_VIOLATION_WIN_READ: + reason = "EXCEPTION_ACCESS_VIOLATION_READ"; + break; + case MD_ACCESS_VIOLATION_WIN_WRITE: + reason = "EXCEPTION_ACCESS_VIOLATION_WRITE"; + break; + case MD_ACCESS_VIOLATION_WIN_EXEC: + reason = "EXCEPTION_ACCESS_VIOLATION_EXEC"; + break; + default: + reason = "EXCEPTION_ACCESS_VIOLATION"; + break; + } + } else { + reason = "EXCEPTION_ACCESS_VIOLATION"; + } + if (address && + raw_exception->exception_record.number_parameters >= 2) { + *address = + raw_exception->exception_record.exception_information[1]; + } + break; + case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: + // For EXCEPTION_IN_PAGE_ERROR, Windows puts the address that + // caused the fault in exception_information[1]. + // exception_information[0] is 0 if the violation was caused by + // an attempt to read data, 1 if it was an attempt to write data, + // and 8 if this was a data execution violation. + // exception_information[2] contains the underlying NTSTATUS code, + // which is the explanation for why this error occured. + // This information is useful in addition to the code address, which + // will be present in the crash thread's instruction field anyway. + if (raw_exception->exception_record.number_parameters >= 1) { + MDInPageErrorTypeWin av_type = + static_cast + (raw_exception->exception_record.exception_information[0]); + switch (av_type) { + case MD_IN_PAGE_ERROR_WIN_READ: + reason = "EXCEPTION_IN_PAGE_ERROR_READ"; + break; + case MD_IN_PAGE_ERROR_WIN_WRITE: + reason = "EXCEPTION_IN_PAGE_ERROR_WRITE"; + break; + case MD_IN_PAGE_ERROR_WIN_EXEC: + reason = "EXCEPTION_IN_PAGE_ERROR_EXEC"; + break; + default: + reason = "EXCEPTION_IN_PAGE_ERROR"; + break; + } + } else { + reason = "EXCEPTION_IN_PAGE_ERROR"; + } + if (address && + raw_exception->exception_record.number_parameters >= 2) { + *address = + raw_exception->exception_record.exception_information[1]; + } + if (raw_exception->exception_record.number_parameters >= 3) { + uint32_t ntstatus = + static_cast + (raw_exception->exception_record.exception_information[2]); + reason.append(" / "); + const char* ntstatus_str = NTStatusToString(ntstatus); + if (ntstatus_str) { + reason.append(ntstatus_str); + } else { + snprintf(reason_string, sizeof(reason_string), "%#010x", ntstatus); + reason.append(reason_string); + } + } + break; + case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE: + reason = "EXCEPTION_INVALID_HANDLE"; + break; + case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: + reason = "EXCEPTION_ILLEGAL_INSTRUCTION"; + break; + case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: + reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + break; + case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: + reason = "EXCEPTION_INVALID_DISPOSITION"; + break; + case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED: + reason = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND: + reason = "EXCEPTION_FLT_DENORMAL_OPERAND"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: + reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: + reason = "EXCEPTION_FLT_INEXACT_RESULT"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: + reason = "EXCEPTION_FLT_INVALID_OPERATION"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: + reason = "EXCEPTION_FLT_OVERFLOW"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK: + reason = "EXCEPTION_FLT_STACK_CHECK"; + break; + case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: + reason = "EXCEPTION_FLT_UNDERFLOW"; + break; + case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: + reason = "EXCEPTION_INT_DIVIDE_BY_ZERO"; + break; + case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: + reason = "EXCEPTION_INT_OVERFLOW"; + break; + case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: + reason = "EXCEPTION_PRIV_INSTRUCTION"; + break; + case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: + reason = "EXCEPTION_STACK_OVERFLOW"; + break; + case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE: + reason = "EXCEPTION_BAD_FUNCTION_TABLE"; + break; + case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: + reason = "EXCEPTION_POSSIBLE_DEADLOCK"; + break; + case MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN: + reason = "STATUS_STACK_BUFFER_OVERRUN"; + if (raw_exception->exception_record.number_parameters > 0) { + uint32_t fast_fail_code = + static_cast + (raw_exception->exception_record.exception_information[0]); + char fast_fail_buff[13] = {}; + const char* fast_fail_string = FastFailToString(fast_fail_code); + if (!fast_fail_string) { + snprintf(fast_fail_buff, sizeof(fast_fail_buff), "%#010x", + fast_fail_code); + fast_fail_string = fast_fail_buff; + } + + reason.append(" / "); + reason.append(fast_fail_string); + } + + break; + case MD_EXCEPTION_OUT_OF_MEMORY: + reason = "Out of Memory"; + break; + case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: + reason = "Unhandled C++ Exception"; + break; + case MD_EXCEPTION_CODE_WIN_SIMULATED: + reason = "Simulated Exception"; + break; + default: + fprintf(stderr, "exception_code = %u\n", exception_code); + const char* exception_str = NTStatusToString(exception_code); + fprintf(stderr, "exception_str = %s\n", exception_str); + if (exception_str == nullptr) { + exception_str = WinErrorToString(exception_code); + } + if (exception_str != nullptr) { + reason = exception_str; + } + break; + } + break; + } + + case MD_OS_ANDROID: + case MD_OS_LINUX: { + switch (exception_code) { + case MD_EXCEPTION_CODE_LIN_SIGHUP: + reason = "SIGHUP"; + break; + case MD_EXCEPTION_CODE_LIN_SIGINT: + reason = "SIGINT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGQUIT: + reason = "SIGQUIT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGILL: + reason = "SIGILL / "; + switch (exception_flags) { + case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC: + reason.append("ILL_ILLOPC"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN: + reason.append("ILL_ILLOPN"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_ILLADR: + reason.append("ILL_ILLADR"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP: + reason.append("ILL_ILLTRP"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC: + reason.append("ILL_PRVOPC"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_PRVREG: + reason.append("ILL_PRVREG"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_COPROC: + reason.append("ILL_COPROC"); + break; + case MD_EXCEPTION_FLAG_LIN_ILL_BADSTK: + reason.append("ILL_BADSTK"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_CODE_LIN_SIGTRAP: + reason = "SIGTRAP"; + break; + case MD_EXCEPTION_CODE_LIN_SIGABRT: + reason = "SIGABRT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGBUS: + reason = "SIGBUS / "; + switch (exception_flags) { + case MD_EXCEPTION_FLAG_LIN_SI_USER: + reason.append("SI_USER"); + break; + case MD_EXCEPTION_FLAG_LIN_SI_KERNEL: + reason.append("SI_KERNEL"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_ADRALN: + reason.append("BUS_ADRALN"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_ADRERR: + reason.append("BUS_ADRERR"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_OBJERR: + reason.append("BUS_OBJERR"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AR: + reason.append("BUS_MCEERR_AR"); + break; + case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO: + reason.append("BUS_MCEERR_AO"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_CODE_LIN_SIGFPE: + reason = "SIGFPE / "; + switch (exception_flags) { + case MD_EXCEPTION_FLAG_LIN_FPE_INTDIV: + reason.append("FPE_INTDIV"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_INTOVF: + reason.append("FPE_INTOVF"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTDIV: + reason.append("FPE_FLTDIV"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTOVF: + reason.append("FPE_FLTOVF"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTUND: + reason.append("FPE_FLTUND"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTRES: + reason.append("FPE_FLTRES"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTINV: + reason.append("FPE_FLTINV"); + break; + case MD_EXCEPTION_FLAG_LIN_FPE_FLTSUB: + reason.append("FPE_FLTSUB"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_CODE_LIN_SIGKILL: + reason = "SIGKILL"; + break; + case MD_EXCEPTION_CODE_LIN_SIGUSR1: + reason = "SIGUSR1"; + break; + case MD_EXCEPTION_CODE_LIN_SIGSEGV: + reason = "SIGSEGV / "; + switch (exception_flags) { + case MD_EXCEPTION_FLAG_LIN_SI_USER: + reason.append("SI_USER"); + break; + case MD_EXCEPTION_FLAG_LIN_SI_KERNEL: + reason.append("SI_KERNEL"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR: + reason.append("SEGV_MAPERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR: + reason.append("SEGV_ACCERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR: + reason.append("SEGV_BNDERR"); + break; + case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR: + reason.append("SEGV_PKUERR"); + break; + default: + reason.append(flags_string); + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + case MD_EXCEPTION_CODE_LIN_SIGUSR2: + reason = "SIGUSR2"; + break; + case MD_EXCEPTION_CODE_LIN_SIGPIPE: + reason = "SIGPIPE"; + break; + case MD_EXCEPTION_CODE_LIN_SIGALRM: + reason = "SIGALRM"; + break; + case MD_EXCEPTION_CODE_LIN_SIGTERM: + reason = "SIGTERM"; + break; + case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: + reason = "SIGSTKFLT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGCHLD: + reason = "SIGCHLD"; + break; + case MD_EXCEPTION_CODE_LIN_SIGCONT: + reason = "SIGCONT"; + break; + case MD_EXCEPTION_CODE_LIN_SIGSTOP: + reason = "SIGSTOP"; + break; + case MD_EXCEPTION_CODE_LIN_SIGTSTP: + reason = "SIGTSTP"; + break; + case MD_EXCEPTION_CODE_LIN_SIGTTIN: + reason = "SIGTTIN"; + break; + case MD_EXCEPTION_CODE_LIN_SIGTTOU: + reason = "SIGTTOU"; + break; + case MD_EXCEPTION_CODE_LIN_SIGURG: + reason = "SIGURG"; + break; + case MD_EXCEPTION_CODE_LIN_SIGXCPU: + reason = "SIGXCPU"; + break; + case MD_EXCEPTION_CODE_LIN_SIGXFSZ: + reason = "SIGXFSZ"; + break; + case MD_EXCEPTION_CODE_LIN_SIGVTALRM: + reason = "SIGVTALRM"; + break; + case MD_EXCEPTION_CODE_LIN_SIGPROF: + reason = "SIGPROF"; + break; + case MD_EXCEPTION_CODE_LIN_SIGWINCH: + reason = "SIGWINCH"; + break; + case MD_EXCEPTION_CODE_LIN_SIGIO: + reason = "SIGIO"; + break; + case MD_EXCEPTION_CODE_LIN_SIGPWR: + reason = "SIGPWR"; + break; + case MD_EXCEPTION_CODE_LIN_SIGSYS: + reason = "SIGSYS"; + break; + case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: + reason = "DUMP_REQUESTED"; + break; + default: + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + + case MD_OS_SOLARIS: { + switch (exception_code) { + case MD_EXCEPTION_CODE_SOL_SIGHUP: + reason = "SIGHUP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGINT: + reason = "SIGINT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGQUIT: + reason = "SIGQUIT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGILL: + reason = "SIGILL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTRAP: + reason = "SIGTRAP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGIOT: + reason = "SIGIOT | SIGABRT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGEMT: + reason = "SIGEMT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGFPE: + reason = "SIGFPE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGKILL: + reason = "SIGKILL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGBUS: + reason = "SIGBUS"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSEGV: + reason = "SIGSEGV"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSYS: + reason = "SIGSYS"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPIPE: + reason = "SIGPIPE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGALRM: + reason = "SIGALRM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTERM: + reason = "SIGTERM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGUSR1: + reason = "SIGUSR1"; + break; + case MD_EXCEPTION_CODE_SOL_SIGUSR2: + reason = "SIGUSR2"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCLD: + reason = "SIGCLD | SIGCHLD"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPWR: + reason = "SIGPWR"; + break; + case MD_EXCEPTION_CODE_SOL_SIGWINCH: + reason = "SIGWINCH"; + break; + case MD_EXCEPTION_CODE_SOL_SIGURG: + reason = "SIGURG"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPOLL: + reason = "SIGPOLL | SIGIO"; + break; + case MD_EXCEPTION_CODE_SOL_SIGSTOP: + reason = "SIGSTOP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTSTP: + reason = "SIGTSTP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCONT: + reason = "SIGCONT"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTTIN: + reason = "SIGTTIN"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTTOU: + reason = "SIGTTOU"; + break; + case MD_EXCEPTION_CODE_SOL_SIGVTALRM: + reason = "SIGVTALRM"; + break; + case MD_EXCEPTION_CODE_SOL_SIGPROF: + reason = "SIGPROF"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXCPU: + reason = "SIGXCPU"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXFSZ: + reason = "SIGXFSZ"; + break; + case MD_EXCEPTION_CODE_SOL_SIGWAITING: + reason = "SIGWAITING"; + break; + case MD_EXCEPTION_CODE_SOL_SIGLWP: + reason = "SIGLWP"; + break; + case MD_EXCEPTION_CODE_SOL_SIGFREEZE: + reason = "SIGFREEZE"; + break; + case MD_EXCEPTION_CODE_SOL_SIGTHAW: + reason = "SIGTHAW"; + break; + case MD_EXCEPTION_CODE_SOL_SIGCANCEL: + reason = "SIGCANCEL"; + break; + case MD_EXCEPTION_CODE_SOL_SIGLOST: + reason = "SIGLOST"; + break; + case MD_EXCEPTION_CODE_SOL_SIGXRES: + reason = "SIGXRES"; + break; + case MD_EXCEPTION_CODE_SOL_SIGJVM1: + reason = "SIGJVM1"; + break; + case MD_EXCEPTION_CODE_SOL_SIGJVM2: + reason = "SIGJVM2"; + break; + default: + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + break; + } + + case MD_OS_PS3: { + switch (exception_code) { + case MD_EXCEPTION_CODE_PS3_UNKNOWN: + reason = "UNKNOWN"; + break; + case MD_EXCEPTION_CODE_PS3_TRAP_EXCEP: + reason = "TRAP_EXCEP"; + break; + case MD_EXCEPTION_CODE_PS3_PRIV_INSTR: + reason = "PRIV_INSTR"; + break; + case MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR: + reason = "ILLEGAL_INSTR"; + break; + case MD_EXCEPTION_CODE_PS3_INSTR_STORAGE: + reason = "INSTR_STORAGE"; + break; + case MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT: + reason = "INSTR_SEGMENT"; + break; + case MD_EXCEPTION_CODE_PS3_DATA_STORAGE: + reason = "DATA_STORAGE"; + break; + case MD_EXCEPTION_CODE_PS3_DATA_SEGMENT: + reason = "DATA_SEGMENT"; + break; + case MD_EXCEPTION_CODE_PS3_FLOAT_POINT: + reason = "FLOAT_POINT"; + break; + case MD_EXCEPTION_CODE_PS3_DABR_MATCH: + reason = "DABR_MATCH"; + break; + case MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP: + reason = "ALIGN_EXCEP"; + break; + case MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS: + reason = "MEMORY_ACCESS"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_ALIGN: + reason = "COPRO_ALIGN"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM: + reason = "COPRO_INVALID_COM"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_ERR: + reason = "COPRO_ERR"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_FIR: + reason = "COPRO_FIR"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT: + reason = "COPRO_DATA_SEGMENT"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE: + reason = "COPRO_DATA_STORAGE"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR: + reason = "COPRO_STOP_INSTR"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR: + reason = "COPRO_HALT_INSTR"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN: + reason = "COPRO_HALTINSTR_UNKNOWN"; + break; + case MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS: + reason = "COPRO_MEMORY_ACCESS"; + break; + case MD_EXCEPTION_CODE_PS3_GRAPHIC: + reason = "GRAPHIC"; + break; + default: + BPLOG(INFO) << "Unknown exception reason "<< reason; + break; + } + break; + } + + default: { + BPLOG(INFO) << "Unknown exception reason " << reason; + break; + } + } + + if (address) { + *address = GetAddressForArchitecture( + static_cast(raw_system_info->processor_architecture), + *address); + } + + return reason; +} + +// static +string MinidumpProcessor::GetAssertion(Minidump *dump) { + MinidumpAssertion *assertion = dump->GetAssertion(); + if (!assertion) + return ""; + + const MDRawAssertionInfo *raw_assertion = assertion->assertion(); + if (!raw_assertion) + return ""; + + string assertion_string; + switch (raw_assertion->type) { + case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER: + assertion_string = "Invalid parameter passed to library function"; + break; + case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL: + assertion_string = "Pure virtual function called"; + break; + default: { + char assertion_type[32]; + snprintf(assertion_type, sizeof(assertion_type), + "0x%08x", raw_assertion->type); + assertion_string = "Unknown assertion type "; + assertion_string += assertion_type; + break; + } + } + + string expression = assertion->expression(); + if (!expression.empty()) { + assertion_string.append(" " + expression); + } + + string function = assertion->function(); + if (!function.empty()) { + assertion_string.append(" in function " + function); + } + + string file = assertion->file(); + if (!file.empty()) { + assertion_string.append(", in file " + file); + } + + if (raw_assertion->line != 0) { + char assertion_line[32]; + snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line); + assertion_string.append(" at line "); + assertion_string.append(assertion_line); + } + + return assertion_string; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor_unittest.cc new file mode 100644 index 0000000000..a4ac3685ac --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_processor_unittest.cc @@ -0,0 +1,769 @@ +// 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. + +// Unit test for MinidumpProcessor. Uses a pre-generated minidump and +// corresponding symbol file, and checks the stack frames for correctness. + +#include + +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/symbol_supplier.h" +#include "processor/logging.h" +#include "processor/stackwalker_unittest_utils.h" + +using std::map; + +namespace google_breakpad { +class MockMinidump : public Minidump { + public: + MockMinidump() : Minidump("") { + } + + MOCK_METHOD0(Read, bool()); + MOCK_CONST_METHOD0(path, string()); + MOCK_CONST_METHOD0(header, const MDRawHeader*()); + MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); + MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*()); + MOCK_METHOD0(GetMiscInfo, MinidumpMiscInfo*()); + MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*()); + MOCK_METHOD0(GetException, MinidumpException*()); + MOCK_METHOD0(GetAssertion, MinidumpAssertion*()); + MOCK_METHOD0(GetModuleList, MinidumpModuleList*()); + MOCK_METHOD0(GetUnloadedModuleList, MinidumpUnloadedModuleList*()); + MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*()); +}; + +class MockMinidumpUnloadedModule : public MinidumpUnloadedModule { + public: + MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {} +}; + +class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList { + public: + MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {} + + ~MockMinidumpUnloadedModuleList() {} + MOCK_CONST_METHOD0(Copy, CodeModules*()); + MOCK_CONST_METHOD1(GetModuleForAddress, + const MinidumpUnloadedModule*(uint64_t)); +}; + +class MockMinidumpThreadList : public MinidumpThreadList { + public: + MockMinidumpThreadList() : MinidumpThreadList(NULL) {} + + MOCK_CONST_METHOD0(thread_count, unsigned int()); + MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int)); +}; + +class MockMinidumpMemoryList : public MinidumpMemoryList { + public: + MockMinidumpMemoryList() : MinidumpMemoryList(NULL) {} + + MOCK_METHOD1(GetMemoryRegionForAddress, MinidumpMemoryRegion*(uint64_t)); +}; + +class MockMinidumpThread : public MinidumpThread { + public: + MockMinidumpThread() : MinidumpThread(NULL) {} + + MOCK_CONST_METHOD1(GetThreadID, bool(uint32_t*)); + MOCK_METHOD0(GetContext, MinidumpContext*()); + MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*()); + MOCK_CONST_METHOD0(GetStartOfStackMemoryRange, uint64_t()); +}; + +// This is crappy, but MinidumpProcessor really does want a +// MinidumpMemoryRegion. +class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { + public: + MockMinidumpMemoryRegion(uint64_t base, const string& contents) : + MinidumpMemoryRegion(NULL) { + region_.Init(base, contents); + } + + uint64_t GetBase() const { return region_.GetBase(); } + uint32_t GetSize() const { return region_.GetSize(); } + + bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + + MockMemoryRegion region_; +}; + +// A test miscelaneous info stream, just returns values from the +// MDRawMiscInfo fed to it. +class TestMinidumpMiscInfo : public MinidumpMiscInfo { + public: + explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) : + MinidumpMiscInfo(NULL) { + valid_ = true; + misc_info_ = misc_info; + } +}; + +} // namespace google_breakpad + +namespace { + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpMemoryRegion; +using google_breakpad::MinidumpMiscInfo; +using google_breakpad::MinidumpProcessor; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpThreadList; +using google_breakpad::MinidumpThread; +using google_breakpad::MockMinidump; +using google_breakpad::MockMinidumpMemoryList; +using google_breakpad::MockMinidumpMemoryRegion; +using google_breakpad::MockMinidumpThread; +using google_breakpad::MockMinidumpThreadList; +using google_breakpad::MockMinidumpUnloadedModule; +using google_breakpad::MockMinidumpUnloadedModuleList; +using google_breakpad::ProcessState; +using google_breakpad::scoped_ptr; +using google_breakpad::SymbolSupplier; +using google_breakpad::SystemInfo; +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::DoAll; +using ::testing::Mock; +using ::testing::Ne; +using ::testing::Property; +using ::testing::Return; +using ::testing::SetArgumentPointee; + +static const char *kSystemInfoOS = "Windows NT"; +static const char *kSystemInfoOSShort = "windows"; +static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; +static const char *kSystemInfoCPU = "x86"; +static const char *kSystemInfoCPUInfo = + "GenuineIntel family 6 model 13 stepping 8"; + +#define ASSERT_TRUE_ABORT(cond) \ + if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + abort(); \ + } + +#define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2)) + +static string GetTestDataPath() { + char *srcdir = getenv("srcdir"); + + return string(srcdir ? srcdir : ".") + "/src/processor/testdata/"; +} + +class TestSymbolSupplier : public SymbolSupplier { + public: + TestSymbolSupplier() : interrupt_(false) {} + + 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); + + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size); + + virtual void FreeSymbolData(const CodeModule *module); + + // When set to true, causes the SymbolSupplier to return INTERRUPT + void set_interrupt(bool interrupt) { interrupt_ = interrupt; } + + private: + bool interrupt_; + map memory_buffers_; +}; + +SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) { + ASSERT_TRUE_ABORT(module); + ASSERT_TRUE_ABORT(system_info); + ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU); + ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo); + ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS); + ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort); + ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion); + + if (interrupt_) { + return INTERRUPT; + } + + if (module && module->code_file() == "c:\\test_app.exe") { + *symbol_file = GetTestDataPath() + "symbols/test_app.pdb/" + + module->debug_identifier() + "/test_app.sym"; + return FOUND; + } + + return NOT_FOUND; +} + +SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) { + SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, + symbol_file); + if (s == FOUND) { + std::ifstream in(symbol_file->c_str()); + std::getline(in, *symbol_data, string::traits_type::to_char_type( + string::traits_type::eof())); + in.close(); + } + + return s; +} + +SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData( + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) { + string symbol_data_string; + SymbolSupplier::SymbolResult s = GetSymbolFile(module, + system_info, + symbol_file, + &symbol_data_string); + if (s == FOUND) { + *symbol_data_size = symbol_data_string.size() + 1; + *symbol_data = new char[*symbol_data_size]; + if (*symbol_data == NULL) { + BPLOG(ERROR) << "Memory allocation failed for module: " + << module->code_file() << " size: " << *symbol_data_size; + return INTERRUPT; + } + memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); + (*symbol_data)[symbol_data_string.size()] = '\0'; + memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); + } + + return s; +} + +void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) { + map::iterator it = memory_buffers_.find(module->code_file()); + if (it != memory_buffers_.end()) { + delete [] it->second; + memory_buffers_.erase(it); + } +} + +// A test system info stream, just returns values from the +// MDRawSystemInfo fed to it. +class TestMinidumpSystemInfo : public MinidumpSystemInfo { + public: + explicit TestMinidumpSystemInfo(MDRawSystemInfo info) : + MinidumpSystemInfo(NULL) { + valid_ = true; + system_info_ = info; + csd_version_ = new string(""); + } +}; + +// A test minidump context, just returns the MDRawContextX86 +// fed to it. +class TestMinidumpContext : public MinidumpContext { + public: + explicit TestMinidumpContext(const MDRawContextX86& context) : + MinidumpContext(NULL) { + valid_ = true; + SetContextX86(new MDRawContextX86(context)); + SetContextFlags(MD_CONTEXT_X86); + } +}; + +class MinidumpProcessorTest : public ::testing::Test { +}; + +TEST_F(MinidumpProcessorTest, TestUnloadedModules) { + MockMinidump dump; + + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fake_header; + fake_header.time_date_stamp = 0; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + MDRawSystemInfo raw_system_info; + memset(&raw_system_info, 0, sizeof(raw_system_info)); + raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; + raw_system_info.platform_id = MD_OS_WIN32_NT; + TestMinidumpSystemInfo dump_system_info(raw_system_info); + + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(&dump_system_info)); + + // No loaded modules + + MockMinidumpUnloadedModuleList unloaded_module_list; + EXPECT_CALL(dump, GetUnloadedModuleList()). + WillOnce(Return(&unloaded_module_list)); + + MockMinidumpMemoryList memory_list; + EXPECT_CALL(dump, GetMemoryList()). + WillOnce(Return(&memory_list)); + + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(&thread_list)); + + EXPECT_CALL(thread_list, thread_count()). + WillRepeatedly(Return(1)); + + MockMinidumpThread thread; + EXPECT_CALL(thread_list, GetThreadAtIndex(0)). + WillOnce(Return(&thread)); + + EXPECT_CALL(thread, GetThreadID(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(1), + Return(true))); + + MDRawContextX86 thread_raw_context; + memset(&thread_raw_context, 0, + sizeof(thread_raw_context)); + thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; + const uint32_t kExpectedEIP = 0xabcd1234; + thread_raw_context.eip = kExpectedEIP; + TestMinidumpContext thread_context(thread_raw_context); + EXPECT_CALL(thread, GetContext()). + WillRepeatedly(Return(&thread_context)); + + // The memory contents don't really matter here, since it won't be used. + MockMinidumpMemoryRegion thread_memory(0x1234, "xxx"); + EXPECT_CALL(thread, GetMemory()). + WillRepeatedly(Return(&thread_memory)); + EXPECT_CALL(thread, GetStartOfStackMemoryRange()). + Times(0); + EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)). + Times(0); + + MockMinidumpUnloadedModuleList* unloaded_module_list_copy = + new MockMinidumpUnloadedModuleList(); + EXPECT_CALL(unloaded_module_list, Copy()). + WillOnce(Return(unloaded_module_list_copy)); + + MockMinidumpUnloadedModule unloaded_module; + EXPECT_CALL(*unloaded_module_list_copy, GetModuleForAddress(kExpectedEIP)). + WillOnce(Return(&unloaded_module)); + + MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + ProcessState state; + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_OK); + + // The single frame should be populated with the unloaded module. + ASSERT_EQ(1U, state.threads()->size()); + ASSERT_EQ(1U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); + ASSERT_EQ(&unloaded_module, state.threads()->at(0)->frames()->at(0)->module); +} + +TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { + MockMinidump dump; + TestSymbolSupplier supplier; + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver); + ProcessState state; + + EXPECT_EQ(processor.Process("nonexistent minidump", &state), + google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND); + + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fakeHeader; + fakeHeader.time_date_stamp = 0; + EXPECT_CALL(dump, header()). + WillOnce(Return(reinterpret_cast(NULL))). + WillRepeatedly(Return(&fakeHeader)); + + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); + + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(reinterpret_cast(NULL))); + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(reinterpret_cast(NULL))); + + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); +} + +// This test case verifies that the symbol supplier is only consulted +// once per minidump per module. +TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) { + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver); + + string minidump_file = GetTestDataPath() + "minidump2.dmp"; + ProcessState state; + EXPECT_CALL(supplier, GetCStringSymbolData( + Property(&google_breakpad::CodeModule::code_file, + "c:\\test_app.exe"), + _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND)); + EXPECT_CALL(supplier, GetCStringSymbolData( + Property(&google_breakpad::CodeModule::code_file, + Ne("c:\\test_app.exe")), + _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND)); + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + + ASSERT_TRUE(Mock::VerifyAndClearExpectations(&supplier)); + + // We need to verify that across minidumps, the processor will refetch + // symbol files, even with the same symbol supplier. + EXPECT_CALL(supplier, GetCStringSymbolData( + Property(&google_breakpad::CodeModule::code_file, + "c:\\test_app.exe"), + _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND)); + EXPECT_CALL(supplier, GetCStringSymbolData( + Property(&google_breakpad::CodeModule::code_file, + Ne("c:\\test_app.exe")), + _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND)); + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); +} + +TEST_F(MinidumpProcessorTest, TestBasicProcessing) { + TestSymbolSupplier supplier; + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver); + + string minidump_file = GetTestDataPath() + "minidump2.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_EQ(state.system_info()->os, kSystemInfoOS); + ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort); + ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); + ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU); + ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); + ASSERT_TRUE(state.crashed()); + ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE"); + ASSERT_EQ(state.crash_address(), 0x45U); + ASSERT_EQ(state.threads()->size(), size_t(1)); + EXPECT_EQ((*state.threads())[0]->tid(), 3060U); + ASSERT_EQ(state.requesting_thread(), 0); + EXPECT_EQ(1171480435U, state.time_date_stamp()); + EXPECT_EQ(1171480435U, state.process_create_time()); + + CallStack *stack = state.threads()->at(0); + ASSERT_TRUE(stack); + ASSERT_EQ(stack->frames()->size(), 4U); + + ASSERT_TRUE(stack->frames()->at(0)->module); + ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000U); + ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe"); + ASSERT_EQ(stack->frames()->at(0)->function_name, + "`anonymous namespace'::CrashFunction"); + ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc"); + ASSERT_EQ(stack->frames()->at(0)->source_line, 58); + + ASSERT_TRUE(stack->frames()->at(1)->module); + ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000U); + ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe"); + ASSERT_EQ(stack->frames()->at(1)->function_name, "main"); + ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc"); + ASSERT_EQ(stack->frames()->at(1)->source_line, 65); + + // This comes from the CRT + ASSERT_TRUE(stack->frames()->at(2)->module); + ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000U); + ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe"); + ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup"); + ASSERT_EQ(stack->frames()->at(2)->source_file_name, + "f:\\sp\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c"); + ASSERT_EQ(stack->frames()->at(2)->source_line, 327); + + // No debug info available for kernel32.dll + ASSERT_TRUE(stack->frames()->at(3)->module); + ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000U); + ASSERT_EQ(stack->frames()->at(3)->module->code_file(), + "C:\\WINDOWS\\system32\\kernel32.dll"); + ASSERT_TRUE(stack->frames()->at(3)->function_name.empty()); + ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty()); + ASSERT_EQ(stack->frames()->at(3)->source_line, 0); + + ASSERT_EQ(state.modules()->module_count(), 13U); + ASSERT_TRUE(state.modules()->GetMainModule()); + ASSERT_EQ(state.modules()->GetMainModule()->code_file(), "c:\\test_app.exe"); + ASSERT_FALSE(state.modules()->GetModuleForAddress(0)); + ASSERT_EQ(state.modules()->GetMainModule(), + state.modules()->GetModuleForAddress(0x400000)); + ASSERT_EQ(state.modules()->GetModuleForAddress(0x7c801234)->debug_file(), + "kernel32.pdb"); + ASSERT_EQ(state.modules()->GetModuleForAddress(0x77d43210)->version(), + "5.1.2600.2622"); + + // Test that disabled exploitability engine defaults to + // EXPLOITABILITY_NOT_ANALYZED. + ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED, + state.exploitability()); + + // Test that the symbol supplier can interrupt processing + state.Clear(); + supplier.set_interrupt(true); + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); +} + +TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fake_header; + fake_header.time_date_stamp = 0; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + MDRawSystemInfo raw_system_info; + memset(&raw_system_info, 0, sizeof(raw_system_info)); + raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; + raw_system_info.platform_id = MD_OS_WIN32_NT; + TestMinidumpSystemInfo dump_system_info(raw_system_info); + + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(&dump_system_info)); + + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(&thread_list)); + + MockMinidumpMemoryList memory_list; + EXPECT_CALL(dump, GetMemoryList()). + WillOnce(Return(&memory_list)); + + // Return a thread missing stack memory. + MockMinidumpThread no_memory_thread; + EXPECT_CALL(no_memory_thread, GetThreadID(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(1), + Return(true))); + EXPECT_CALL(no_memory_thread, GetMemory()). + WillRepeatedly(Return(reinterpret_cast(NULL))); + + const uint64_t kTestStartOfMemoryRange = 0x1234; + EXPECT_CALL(no_memory_thread, GetStartOfStackMemoryRange()). + WillRepeatedly(Return(kTestStartOfMemoryRange)); + EXPECT_CALL(memory_list, GetMemoryRegionForAddress(kTestStartOfMemoryRange)). + WillRepeatedly(Return(reinterpret_cast(NULL))); + + MDRawContextX86 no_memory_thread_raw_context; + memset(&no_memory_thread_raw_context, 0, + sizeof(no_memory_thread_raw_context)); + no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; + const uint32_t kExpectedEIP = 0xabcd1234; + no_memory_thread_raw_context.eip = kExpectedEIP; + TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context); + EXPECT_CALL(no_memory_thread, GetContext()). + WillRepeatedly(Return(&no_memory_thread_context)); + + EXPECT_CALL(thread_list, thread_count()). + WillRepeatedly(Return(1)); + EXPECT_CALL(thread_list, GetThreadAtIndex(0)). + WillOnce(Return(&no_memory_thread)); + + MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + ProcessState state; + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_OK); + + // Should have a single thread with a single frame in it. + ASSERT_EQ(1U, state.threads()->size()); + ASSERT_EQ(1U, state.threads()->at(0)->frames()->size()); + ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); +} + +TEST_F(MinidumpProcessorTest, GetProcessCreateTime) { + const uint32_t kProcessCreateTime = 2000; + const uint32_t kTimeDateStamp = 5000; + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + // Set time of crash. + MDRawHeader fake_header; + fake_header.time_date_stamp = kTimeDateStamp; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + // Set process create time. + MDRawMiscInfo raw_misc_info; + memset(&raw_misc_info, 0, sizeof(raw_misc_info)); + raw_misc_info.process_create_time = kProcessCreateTime; + raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES; + google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info); + EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info)); + + // No threads + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list)); + EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0)); + + MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + ProcessState state; + EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state)); + + // Verify the time stamps. + ASSERT_EQ(kTimeDateStamp, state.time_date_stamp()); + ASSERT_EQ(kProcessCreateTime, state.process_create_time()); +} + +TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fake_header; + fake_header.time_date_stamp = 0; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + MDRawSystemInfo raw_system_info; + memset(&raw_system_info, 0, sizeof(raw_system_info)); + raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; + raw_system_info.platform_id = MD_OS_WIN32_NT; + TestMinidumpSystemInfo dump_system_info(raw_system_info); + + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(&dump_system_info)); + + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(&thread_list)); + + MockMinidumpMemoryList memory_list; + EXPECT_CALL(dump, GetMemoryList()). + WillOnce(Return(&memory_list)); + + // Return a thread missing a thread context. + MockMinidumpThread no_context_thread; + EXPECT_CALL(no_context_thread, GetThreadID(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(1), + Return(true))); + EXPECT_CALL(no_context_thread, GetContext()). + WillRepeatedly(Return(reinterpret_cast(NULL))); + + // The memory contents don't really matter here, since it won't be used. + MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx"); + EXPECT_CALL(no_context_thread, GetMemory()). + WillRepeatedly(Return(&no_context_thread_memory)); + EXPECT_CALL(no_context_thread, GetStartOfStackMemoryRange()). + Times(0); + EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)). + Times(0); + + EXPECT_CALL(thread_list, thread_count()). + WillRepeatedly(Return(1)); + EXPECT_CALL(thread_list, GetThreadAtIndex(0)). + WillOnce(Return(&no_context_thread)); + + MinidumpProcessor processor(reinterpret_cast(NULL), NULL); + ProcessState state; + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_OK); + + // Should have a single thread with zero frames. + ASSERT_EQ(1U, state.threads()->size()); + ASSERT_EQ(0U, state.threads()->at(0)->frames()->size()); +} + +TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) { + TestSymbolSupplier supplier; + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver); + + string minidump_file = GetTestDataPath() + "minidump_32bit_crash_addr.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_EQ(state.system_info()->os, kSystemInfoOS); + ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort); + ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); + ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU); + ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); + ASSERT_TRUE(state.crashed()); + ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION_WRITE"); + ASSERT_EQ(state.crash_address(), 0x45U); +} + +} // namespace + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk.cc new file mode 100644 index 0000000000..acf80972da --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2010 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_stackwalk.cc: Process a minidump with MinidumpProcessor, printing +// the results, including stack traces. +// +// Author: Mark Mentovai + +#include +#include +#include + +#include +#include +#include + +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "processor/logging.h" +#include "processor/simple_symbol_supplier.h" +#include "processor/stackwalk_common.h" + + +namespace { + +struct Options { + bool machine_readable; + bool output_stack_contents; + + string minidump_file; + std::vector symbol_paths; +}; + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::Minidump; +using google_breakpad::MinidumpMemoryList; +using google_breakpad::MinidumpThreadList; +using google_breakpad::MinidumpProcessor; +using google_breakpad::ProcessState; +using google_breakpad::SimpleSymbolSupplier; +using google_breakpad::scoped_ptr; + +// Processes |options.minidump_file| using MinidumpProcessor. +// |options.symbol_path|, if non-empty, is the base directory of a +// symbol storage area, laid out in the format required by +// SimpleSymbolSupplier. If such a storage area is specified, it is +// made available for use by the MinidumpProcessor. +// +// Returns the value of MinidumpProcessor::Process. If processing succeeds, +// prints identifying OS and CPU information from the minidump, crash +// information if the minidump was produced as a result of a crash, and +// call stacks for each thread contained in the minidump. All information +// is printed to stdout. +bool PrintMinidumpProcess(const Options& options) { + scoped_ptr symbol_supplier; + if (!options.symbol_paths.empty()) { + // TODO(mmentovai): check existence of symbol_path if specified? + symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths)); + } + + BasicSourceLineResolver resolver; + MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver); + + // Increase the maximum number of threads and regions. + MinidumpThreadList::set_max_threads(std::numeric_limits::max()); + MinidumpMemoryList::set_max_regions(std::numeric_limits::max()); + // Process the minidump. + Minidump dump(options.minidump_file); + if (!dump.Read()) { + BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read"; + return false; + } + ProcessState process_state; + if (minidump_processor.Process(&dump, &process_state) != + google_breakpad::PROCESS_OK) { + BPLOG(ERROR) << "MinidumpProcessor::Process failed"; + return false; + } + + if (options.machine_readable) { + PrintProcessStateMachineReadable(process_state); + } else { + PrintProcessState(process_state, options.output_stack_contents, &resolver); + } + + return true; +} + +} // namespace + +static void Usage(int argc, const char *argv[], bool error) { + fprintf(error ? stderr : stdout, + "Usage: %s [options] [symbol-path ...]\n" + "\n" + "Output a stack trace for the provided minidump\n" + "\n" + "Options:\n" + "\n" + " -m Output in machine-readable format\n" + " -s Output stack contents\n", + google_breakpad::BaseName(argv[0]).c_str()); +} + +static void SetupOptions(int argc, const char *argv[], Options* options) { + int ch; + + options->machine_readable = false; + options->output_stack_contents = false; + + while ((ch = getopt(argc, (char * const *)argv, "hms")) != -1) { + switch (ch) { + case 'h': + Usage(argc, argv, false); + exit(0); + break; + + case 'm': + options->machine_readable = true; + break; + case 's': + options->output_stack_contents = true; + break; + + case '?': + Usage(argc, argv, true); + exit(1); + break; + } + } + + if ((argc - optind) == 0) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + Usage(argc, argv, true); + exit(1); + } + + options->minidump_file = argv[optind]; + + for (int argi = optind + 1; argi < argc; ++argi) + options->symbol_paths.push_back(argv[argi]); +} + +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + + return PrintMinidumpProcess(options) ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_machine_readable_test b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_machine_readable_test new file mode 100755 index 0000000000..2aadb2412f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_machine_readable_test @@ -0,0 +1,37 @@ +#!/bin/sh + +# 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. + +testdata_dir=$srcdir/src/processor/testdata +./src/processor/minidump_stackwalk -m $testdata_dir/minidump2.dmp \ + $testdata_dir/symbols | \ + tr -d '\015' | \ + diff -u $testdata_dir/minidump2.stackwalk.machine_readable.out - +exit $? diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_test b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_test new file mode 100755 index 0000000000..f97902791e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk_test @@ -0,0 +1,37 @@ +#!/bin/sh + +# 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. + +testdata_dir=$srcdir/src/processor/testdata +./src/processor/minidump_stackwalk $testdata_dir/minidump2.dmp \ + $testdata_dir/symbols | \ + tr -d '\015' | \ + diff -u $testdata_dir/minidump2.stackwalk.out - +exit $? diff --git a/toolkit/crashreporter/google-breakpad/src/processor/minidump_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/minidump_unittest.cc new file mode 100644 index 0000000000..036d03f116 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump_unittest.cc @@ -0,0 +1,1628 @@ +// Copyright (c) 2010, 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. + +// Unit test for Minidump. Uses a pre-generated minidump and +// verifies that certain streams are correct. + +#include +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/minidump.h" +#include "processor/logging.h" +#include "processor/synth_minidump.h" + +namespace { + +using google_breakpad::Minidump; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpException; +using google_breakpad::MinidumpMemoryInfo; +using google_breakpad::MinidumpMemoryInfoList; +using google_breakpad::MinidumpMemoryList; +using google_breakpad::MinidumpMemoryRegion; +using google_breakpad::MinidumpModule; +using google_breakpad::MinidumpModuleList; +using google_breakpad::MinidumpSystemInfo; +using google_breakpad::MinidumpUnloadedModule; +using google_breakpad::MinidumpUnloadedModuleList; +using google_breakpad::MinidumpThread; +using google_breakpad::MinidumpThreadList; +using google_breakpad::SynthMinidump::Context; +using google_breakpad::SynthMinidump::Dump; +using google_breakpad::SynthMinidump::Exception; +using google_breakpad::SynthMinidump::Memory; +using google_breakpad::SynthMinidump::Module; +using google_breakpad::SynthMinidump::UnloadedModule; +using google_breakpad::SynthMinidump::Section; +using google_breakpad::SynthMinidump::Stream; +using google_breakpad::SynthMinidump::String; +using google_breakpad::SynthMinidump::SystemInfo; +using google_breakpad::SynthMinidump::Thread; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using std::ifstream; +using std::istringstream; +using std::vector; +using ::testing::Return; + +class MinidumpTest : public ::testing::Test { +public: + void SetUp() { + minidump_file_ = string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata/minidump2.dmp"; + } + string minidump_file_; +}; + +TEST_F(MinidumpTest, TestMinidumpFromFile) { + Minidump minidump(minidump_file_); + ASSERT_EQ(minidump.path(), minidump_file_); + ASSERT_TRUE(minidump.Read()); + const MDRawHeader* header = minidump.header(); + ASSERT_NE(header, (MDRawHeader*)NULL); + ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); + + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_module != NULL); + ASSERT_EQ("c:\\test_app.exe", md_module->code_file()); + ASSERT_EQ("c:\\test_app.pdb", md_module->debug_file()); + ASSERT_EQ("45D35F6C2d000", md_module->code_identifier()); + ASSERT_EQ("5A9832E5287241C1838ED98914E9B7FF1", md_module->debug_identifier()); +} + +TEST_F(MinidumpTest, TestMinidumpFromStream) { + // read minidump contents into memory, construct a stringstream around them + ifstream file_stream(minidump_file_.c_str(), std::ios::in); + ASSERT_TRUE(file_stream.good()); + vector bytes; + file_stream.seekg(0, std::ios_base::end); + ASSERT_TRUE(file_stream.good()); + bytes.resize(file_stream.tellg()); + file_stream.seekg(0, std::ios_base::beg); + ASSERT_TRUE(file_stream.good()); + file_stream.read(&bytes[0], bytes.size()); + ASSERT_TRUE(file_stream.good()); + string str(&bytes[0], bytes.size()); + istringstream stream(str); + ASSERT_TRUE(stream.good()); + + // now read minidump from stringstream + Minidump minidump(stream); + ASSERT_EQ(minidump.path(), ""); + ASSERT_TRUE(minidump.Read()); + const MDRawHeader* header = minidump.header(); + ASSERT_NE(header, (MDRawHeader*)NULL); + ASSERT_EQ(header->signature, uint32_t(MD_HEADER_SIGNATURE)); + //TODO: add more checks here +} + +TEST(Dump, ReadBackEmpty) { + Dump dump(0); + dump.Finish(); + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream stream(contents); + Minidump minidump(stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); +} + +TEST(Dump, ReadBackEmptyBigEndian) { + Dump big_minidump(0, kBigEndian); + big_minidump.Finish(); + string contents; + ASSERT_TRUE(big_minidump.GetContents(&contents)); + istringstream stream(contents); + Minidump minidump(stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(0U, minidump.GetDirectoryEntryCount()); +} + +TEST(Dump, OneStream) { + Dump dump(0, kBigEndian); + Stream stream(dump, 0xfbb7fa2bU); + stream.Append("stream contents"); + dump.Add(&stream); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ(0xfbb7fa2bU, dir->stream_type); + + uint32_t stream_length; + ASSERT_TRUE(minidump.SeekToStreamType(0xfbb7fa2bU, &stream_length)); + ASSERT_EQ(15U, stream_length); + char stream_contents[15]; + ASSERT_TRUE(minidump.ReadBytes(stream_contents, sizeof(stream_contents))); + EXPECT_EQ(string("stream contents"), + string(stream_contents, sizeof(stream_contents))); + + EXPECT_FALSE(minidump.GetThreadList()); + EXPECT_FALSE(minidump.GetModuleList()); + EXPECT_FALSE(minidump.GetMemoryList()); + EXPECT_FALSE(minidump.GetException()); + EXPECT_FALSE(minidump.GetAssertion()); + EXPECT_FALSE(minidump.GetSystemInfo()); + EXPECT_FALSE(minidump.GetMiscInfo()); + EXPECT_FALSE(minidump.GetBreakpadInfo()); +} + +TEST(Dump, OneMemory) { + Dump dump(0, kBigEndian); + Memory memory(dump, 0x309d68010bd21b2cULL); + memory.Append("memory contents"); + dump.Add(&memory); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ((uint32_t) MD_MEMORY_LIST_STREAM, dir->stream_type); + + MinidumpMemoryList *memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(memory_list != NULL); + ASSERT_EQ(1U, memory_list->region_count()); + + MinidumpMemoryRegion *region1 = memory_list->GetMemoryRegionAtIndex(0); + ASSERT_EQ(0x309d68010bd21b2cULL, region1->GetBase()); + ASSERT_EQ(15U, region1->GetSize()); + const uint8_t *region1_bytes = region1->GetMemory(); + ASSERT_TRUE(memcmp("memory contents", region1_bytes, 15) == 0); +} + +// One thread --- and its requisite entourage. +TEST(Dump, OneThread) { + Dump dump(0, kLittleEndian); + Memory stack(dump, 0x2326a0fa); + stack.Append("stack for thread"); + + MDRawContextX86 raw_context; + const uint32_t kExpectedEIP = 0x6913f540; + raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; + raw_context.edi = 0x3ecba80d; + raw_context.esi = 0x382583b9; + raw_context.ebx = 0x7fccc03f; + raw_context.edx = 0xf62f8ec2; + raw_context.ecx = 0x46a6a6a8; + raw_context.eax = 0x6a5025e2; + raw_context.ebp = 0xd9fabb4a; + raw_context.eip = kExpectedEIP; + raw_context.cs = 0xbffe6eda; + raw_context.eflags = 0xb2ce1e2d; + raw_context.esp = 0x659caaa4; + raw_context.ss = 0x2e951ef7; + Context context(dump, raw_context); + + Thread thread(dump, 0xa898f11b, stack, context, + 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); + + dump.Add(&stack); + dump.Add(&context); + dump.Add(&thread); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + MinidumpMemoryList *md_memory_list = minidump.GetMemoryList(); + ASSERT_TRUE(md_memory_list != NULL); + ASSERT_EQ(1U, md_memory_list->region_count()); + + MinidumpMemoryRegion *md_region = md_memory_list->GetMemoryRegionAtIndex(0); + ASSERT_EQ(0x2326a0faU, md_region->GetBase()); + ASSERT_EQ(16U, md_region->GetSize()); + const uint8_t *region_bytes = md_region->GetMemory(); + ASSERT_TRUE(memcmp("stack for thread", region_bytes, 16) == 0); + + MinidumpThreadList *thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list != NULL); + ASSERT_EQ(1U, thread_list->thread_count()); + + MinidumpThread *md_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(md_thread != NULL); + uint32_t thread_id; + ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); + ASSERT_EQ(0xa898f11bU, thread_id); + MinidumpMemoryRegion *md_stack = md_thread->GetMemory(); + ASSERT_TRUE(md_stack != NULL); + ASSERT_EQ(0x2326a0faU, md_stack->GetBase()); + ASSERT_EQ(16U, md_stack->GetSize()); + const uint8_t *md_stack_bytes = md_stack->GetMemory(); + ASSERT_TRUE(memcmp("stack for thread", md_stack_bytes, 16) == 0); + + MinidumpContext *md_context = md_thread->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); + + uint64_t eip; + ASSERT_TRUE(md_context->GetInstructionPointer(&eip)); + EXPECT_EQ(kExpectedEIP, eip); + + const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), + (md_raw_context->context_flags + & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); + EXPECT_EQ(0x3ecba80dU, raw_context.edi); + EXPECT_EQ(0x382583b9U, raw_context.esi); + EXPECT_EQ(0x7fccc03fU, raw_context.ebx); + EXPECT_EQ(0xf62f8ec2U, raw_context.edx); + EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); + EXPECT_EQ(0x6a5025e2U, raw_context.eax); + EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); + EXPECT_EQ(kExpectedEIP, raw_context.eip); + EXPECT_EQ(0xbffe6edaU, raw_context.cs); + EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); + EXPECT_EQ(0x659caaa4U, raw_context.esp); + EXPECT_EQ(0x2e951ef7U, raw_context.ss); +} + +TEST(Dump, ThreadMissingMemory) { + Dump dump(0, kLittleEndian); + Memory stack(dump, 0x2326a0fa); + // Stack has no contents. + + MDRawContextX86 raw_context; + memset(&raw_context, 0, sizeof(raw_context)); + raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; + Context context(dump, raw_context); + + Thread thread(dump, 0xa898f11b, stack, context, + 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); + + dump.Add(&stack); + dump.Add(&context); + dump.Add(&thread); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + // This should succeed even though the thread has no stack memory. + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list != NULL); + ASSERT_EQ(1U, thread_list->thread_count()); + + MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(md_thread != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); + ASSERT_EQ(0xa898f11bU, thread_id); + + MinidumpContext* md_context = md_thread->GetContext(); + ASSERT_NE(reinterpret_cast(NULL), md_context); + + MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); + ASSERT_EQ(reinterpret_cast(NULL), md_stack); +} + +TEST(Dump, ThreadMissingContext) { + Dump dump(0, kLittleEndian); + Memory stack(dump, 0x2326a0fa); + stack.Append("stack for thread"); + + // Context is empty. + Context context(dump); + + Thread thread(dump, 0xa898f11b, stack, context, + 0x9e39439f, 0x4abfc15f, 0xe499898a, 0x0d43e939dcfd0372ULL); + + dump.Add(&stack); + dump.Add(&context); + dump.Add(&thread); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + // This should succeed even though the thread has no stack memory. + MinidumpThreadList* thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list != NULL); + ASSERT_EQ(1U, thread_list->thread_count()); + + MinidumpThread* md_thread = thread_list->GetThreadAtIndex(0); + ASSERT_TRUE(md_thread != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_thread->GetThreadID(&thread_id)); + ASSERT_EQ(0xa898f11bU, thread_id); + MinidumpMemoryRegion* md_stack = md_thread->GetMemory(); + ASSERT_NE(reinterpret_cast(NULL), md_stack); + + MinidumpContext* md_context = md_thread->GetContext(); + ASSERT_EQ(reinterpret_cast(NULL), md_context); +} + +TEST(Dump, OneUnloadedModule) { + Dump dump(0, kBigEndian); + String module_name(dump, "unloaded module"); + + String csd_version(dump, "Windows 9000"); + SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); + + UnloadedModule unloaded_module( + dump, + 0xa90206ca83eb2852ULL, + 0xada542bd, + module_name, + 0x34571371, + 0xb1054d2a); + + dump.Add(&unloaded_module); + dump.Add(&module_name); + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ((uint32_t) MD_UNLOADED_MODULE_LIST_STREAM, dir->stream_type); + + MinidumpUnloadedModuleList *md_unloaded_module_list = + minidump.GetUnloadedModuleList(); + ASSERT_TRUE(md_unloaded_module_list != NULL); + ASSERT_EQ(1U, md_unloaded_module_list->module_count()); + + const MinidumpUnloadedModule *md_unloaded_module = + md_unloaded_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_unloaded_module != NULL); + ASSERT_EQ(0xa90206ca83eb2852ULL, md_unloaded_module->base_address()); + ASSERT_EQ(0xada542bd, md_unloaded_module->size()); + ASSERT_EQ("unloaded module", md_unloaded_module->code_file()); + ASSERT_EQ("", md_unloaded_module->debug_file()); + // time_date_stamp and size_of_image concatenated + ASSERT_EQ("B1054D2Aada542bd", md_unloaded_module->code_identifier()); + ASSERT_EQ("", md_unloaded_module->debug_identifier()); + + const MDRawUnloadedModule *md_raw_unloaded_module = + md_unloaded_module->module(); + ASSERT_TRUE(md_raw_unloaded_module != NULL); + ASSERT_EQ(0xb1054d2aU, md_raw_unloaded_module->time_date_stamp); + ASSERT_EQ(0x34571371U, md_raw_unloaded_module->checksum); +} + +static const MDVSFixedFileInfo fixed_file_info = { + 0xb2fba33a, // signature + 0x33d7a728, // struct_version + 0x31afcb20, // file_version_hi + 0xe51cdab1, // file_version_lo + 0xd1ea6907, // product_version_hi + 0x03032857, // product_version_lo + 0x11bf71d7, // file_flags_mask + 0x5fb8cdbf, // file_flags + 0xe45d0d5d, // file_os + 0x107d9562, // file_type + 0x5a8844d4, // file_subtype + 0xa8d30b20, // file_date_hi + 0x651c3e4e // file_date_lo +}; + +TEST(Dump, OneModule) { + Dump dump(0, kBigEndian); + String module_name(dump, "single module"); + Section cv_info(dump); + cv_info + .D32(MD_CVINFOPDB70_SIGNATURE) // signature + // signature, a MDGUID + .D32(0xabcd1234) + .D16(0xf00d) + .D16(0xbeef) + .Append("\x01\x02\x03\x04\x05\x06\x07\x08") + .D32(1) // age + .AppendCString("c:\\foo\\file.pdb"); // pdb_file_name + + String csd_version(dump, "Windows 9000"); + SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); + + Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, + module_name, + 0xb1054d2a, + 0x34571371, + fixed_file_info, // from synth_minidump_unittest_data.h + &cv_info, nullptr); + + dump.Add(&module); + dump.Add(&module_name); + dump.Add(&cv_info); + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(1); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ((uint32_t) MD_MODULE_LIST_STREAM, dir->stream_type); + + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + ASSERT_EQ(1U, md_module_list->module_count()); + + const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_module != NULL); + ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); + ASSERT_EQ(0xada542bd, md_module->size()); + ASSERT_EQ("single module", md_module->code_file()); + ASSERT_EQ("c:\\foo\\file.pdb", md_module->debug_file()); + // time_date_stamp and size_of_image concatenated + ASSERT_EQ("B1054D2Aada542bd", md_module->code_identifier()); + ASSERT_EQ("ABCD1234F00DBEEF01020304050607081", md_module->debug_identifier()); + + const MDRawModule *md_raw_module = md_module->module(); + ASSERT_TRUE(md_raw_module != NULL); + ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); + ASSERT_EQ(0x34571371U, md_raw_module->checksum); + ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, + sizeof(fixed_file_info)) == 0); +} + +// Test that a module with a MDCVInfoELF CV record is handled properly. +TEST(Dump, OneModuleCVELF) { + Dump dump(0, kLittleEndian); + String module_name(dump, "elf module"); + Section cv_info(dump); + cv_info + .D32(MD_CVINFOELF_SIGNATURE) // signature + // build_id + .Append("\x5f\xa9\xcd\xb4\x10\x53\xdf\x1b\x86\xfa\xb7\x33\xb4\xdf" + "\x37\x38\xce\xa3\x4a\x87"); + + const MDRawSystemInfo linux_x86 = { + MD_CPU_ARCHITECTURE_X86, // processor_architecture + 6, // processor_level + 0xd08, // processor_revision + 1, // number_of_processors + 0, // product_type + 0, // major_version + 0, // minor_version + 0, // build_number + MD_OS_LINUX, // platform_id + 0xdeadbeef, // csd_version_rva + 0x100, // suite_mask + 0, // reserved2 + { // cpu + { // x86_cpu_info + { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id + 0x6d8, // version_information + 0xafe9fbff, // feature_information + 0xffffffff // amd_extended_cpu_features + } + } + }; + String csd_version(dump, "Literally Linux"); + SystemInfo system_info(dump, linux_x86, csd_version); + + Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, + module_name, + 0xb1054d2a, + 0x34571371, + fixed_file_info, // from synth_minidump_unittest_data.h + &cv_info, nullptr); + + dump.Add(&module); + dump.Add(&module_name); + dump.Add(&cv_info); + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + ASSERT_EQ(1U, md_module_list->module_count()); + + const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_module != NULL); + ASSERT_EQ(0xa90206ca83eb2852ULL, md_module->base_address()); + ASSERT_EQ(0xada542bd, md_module->size()); + ASSERT_EQ("elf module", md_module->code_file()); + // debug_file == code_file + ASSERT_EQ("elf module", md_module->debug_file()); + // just the build_id, directly + ASSERT_EQ("5fa9cdb41053df1b86fab733b4df3738cea34a87", + md_module->code_identifier()); + // build_id truncted to GUID length and treated as such, with zero + // age appended + ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); + + const MDRawModule *md_raw_module = md_module->module(); + ASSERT_TRUE(md_raw_module != NULL); + ASSERT_EQ(0xb1054d2aU, md_raw_module->time_date_stamp); + ASSERT_EQ(0x34571371U, md_raw_module->checksum); + ASSERT_TRUE(memcmp(&md_raw_module->version_info, &fixed_file_info, + sizeof(fixed_file_info)) == 0); +} + +// Test that a build_id that's shorter than a GUID is handled properly. +TEST(Dump, CVELFShort) { + Dump dump(0, kLittleEndian); + String module_name(dump, "elf module"); + Section cv_info(dump); + cv_info + .D32(MD_CVINFOELF_SIGNATURE) // signature + // build_id, shorter than a GUID + .Append("\x5f\xa9\xcd\xb4"); + + const MDRawSystemInfo linux_x86 = { + MD_CPU_ARCHITECTURE_X86, // processor_architecture + 6, // processor_level + 0xd08, // processor_revision + 1, // number_of_processors + 0, // product_type + 0, // major_version + 0, // minor_version + 0, // build_number + MD_OS_LINUX, // platform_id + 0xdeadbeef, // csd_version_rva + 0x100, // suite_mask + 0, // reserved2 + { // cpu + { // x86_cpu_info + { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id + 0x6d8, // version_information + 0xafe9fbff, // feature_information + 0xffffffff // amd_extended_cpu_features + } + } + }; + String csd_version(dump, "Literally Linux"); + SystemInfo system_info(dump, linux_x86, csd_version); + + Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, + module_name, + 0xb1054d2a, + 0x34571371, + fixed_file_info, // from synth_minidump_unittest_data.h + &cv_info, nullptr); + + dump.Add(&module); + dump.Add(&module_name); + dump.Add(&cv_info); + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + ASSERT_EQ(1U, md_module_list->module_count()); + + const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_module != NULL); + // just the build_id, directly + ASSERT_EQ("5fa9cdb4", md_module->code_identifier()); + // build_id expanded to GUID length and treated as such, with zero + // age appended + ASSERT_EQ("B4CDA95F0000000000000000000000000", md_module->debug_identifier()); +} + +// Test that a build_id that's very long is handled properly. +TEST(Dump, CVELFLong) { + Dump dump(0, kLittleEndian); + String module_name(dump, "elf module"); + Section cv_info(dump); + cv_info + .D32(MD_CVINFOELF_SIGNATURE) // signature + // build_id, lots of bytes + .Append("\x5f\xa9\xcd\xb4\x10\x53\xdf\x1b\x86\xfa\xb7\x33\xb4\xdf" + "\x37\x38\xce\xa3\x4a\x87\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f"); + + + const MDRawSystemInfo linux_x86 = { + MD_CPU_ARCHITECTURE_X86, // processor_architecture + 6, // processor_level + 0xd08, // processor_revision + 1, // number_of_processors + 0, // product_type + 0, // major_version + 0, // minor_version + 0, // build_number + MD_OS_LINUX, // platform_id + 0xdeadbeef, // csd_version_rva + 0x100, // suite_mask + 0, // reserved2 + { // cpu + { // x86_cpu_info + { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id + 0x6d8, // version_information + 0xafe9fbff, // feature_information + 0xffffffff // amd_extended_cpu_features + } + } + }; + String csd_version(dump, "Literally Linux"); + SystemInfo system_info(dump, linux_x86, csd_version); + + Module module(dump, 0xa90206ca83eb2852ULL, 0xada542bd, + module_name, + 0xb1054d2a, + 0x34571371, + fixed_file_info, // from synth_minidump_unittest_data.h + &cv_info, nullptr); + + dump.Add(&module); + dump.Add(&module_name); + dump.Add(&cv_info); + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + ASSERT_EQ(1U, md_module_list->module_count()); + + const MinidumpModule *md_module = md_module_list->GetModuleAtIndex(0); + ASSERT_TRUE(md_module != NULL); + // just the build_id, directly + ASSERT_EQ( + "5fa9cdb41053df1b86fab733b4df3738cea34a870102030405060708090a0b0c0d0e0f", + md_module->code_identifier()); + // build_id truncated to GUID length and treated as such, with zero + // age appended. + ASSERT_EQ("B4CDA95F53101BDF86FAB733B4DF37380", md_module->debug_identifier()); +} + +TEST(Dump, OneSystemInfo) { + Dump dump(0, kLittleEndian); + String csd_version(dump, "Petulant Pierogi"); + SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); + + dump.Add(&system_info); + dump.Add(&csd_version); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ((uint32_t) MD_SYSTEM_INFO_STREAM, dir->stream_type); + + MinidumpSystemInfo *md_system_info = minidump.GetSystemInfo(); + ASSERT_TRUE(md_system_info != NULL); + ASSERT_EQ("windows", md_system_info->GetOS()); + ASSERT_EQ("x86", md_system_info->GetCPU()); + ASSERT_EQ("Petulant Pierogi", *md_system_info->GetCSDVersion()); + ASSERT_EQ("GenuineIntel", *md_system_info->GetCPUVendor()); +} + +TEST(Dump, BigDump) { + Dump dump(0, kLittleEndian); + + // A SystemInfo stream. + String csd_version(dump, "Munificent Macaque"); + SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); + dump.Add(&csd_version); + dump.Add(&system_info); + + // Five threads! + Memory stack0(dump, 0x70b9ebfc); + stack0.Append("stack for thread zero"); + MDRawContextX86 raw_context0; + raw_context0.context_flags = MD_CONTEXT_X86_INTEGER; + raw_context0.eip = 0xaf0709e4; + Context context0(dump, raw_context0); + Thread thread0(dump, 0xbbef4432, stack0, context0, + 0xd0377e7b, 0xdb8eb0cf, 0xd73bc314, 0x09d357bac7f9a163ULL); + dump.Add(&stack0); + dump.Add(&context0); + dump.Add(&thread0); + + Memory stack1(dump, 0xf988cc45); + stack1.Append("stack for thread one"); + MDRawContextX86 raw_context1; + raw_context1.context_flags = MD_CONTEXT_X86_INTEGER; + raw_context1.eip = 0xe4f56f81; + Context context1(dump, raw_context1); + Thread thread1(dump, 0x657c3f58, stack1, context1, + 0xa68fa182, 0x6f3cf8dd, 0xe3a78ccf, 0x78cc84775e4534bbULL); + dump.Add(&stack1); + dump.Add(&context1); + dump.Add(&thread1); + + Memory stack2(dump, 0xc8a92e7c); + stack2.Append("stack for thread two"); + MDRawContextX86 raw_context2; + raw_context2.context_flags = MD_CONTEXT_X86_INTEGER; + raw_context2.eip = 0xb336a438; + Context context2(dump, raw_context2); + Thread thread2(dump, 0xdf4b8a71, stack2, context2, + 0x674c26b6, 0x445d7120, 0x7e700c56, 0xd89bf778e7793e17ULL); + dump.Add(&stack2); + dump.Add(&context2); + dump.Add(&thread2); + + Memory stack3(dump, 0x36d08e08); + stack3.Append("stack for thread three"); + MDRawContextX86 raw_context3; + raw_context3.context_flags = MD_CONTEXT_X86_INTEGER; + raw_context3.eip = 0xdf99a60c; + Context context3(dump, raw_context3); + Thread thread3(dump, 0x86e6c341, stack3, context3, + 0x32dc5c55, 0x17a2aba8, 0xe0cc75e7, 0xa46393994dae83aeULL); + dump.Add(&stack3); + dump.Add(&context3); + dump.Add(&thread3); + + Memory stack4(dump, 0x1e0ab4fa); + stack4.Append("stack for thread four"); + MDRawContextX86 raw_context4; + raw_context4.context_flags = MD_CONTEXT_X86_INTEGER; + raw_context4.eip = 0xaa646267; + Context context4(dump, raw_context4); + Thread thread4(dump, 0x261a28d4, stack4, context4, + 0x6ebd389e, 0xa0cd4759, 0x30168846, 0x164f650a0cf39d35ULL); + dump.Add(&stack4); + dump.Add(&context4); + dump.Add(&thread4); + + // Three modules! + String module1_name(dump, "module one"); + Module module1(dump, 0xeb77da57b5d4cbdaULL, 0x83cd5a37, module1_name); + dump.Add(&module1_name); + dump.Add(&module1); + + String module2_name(dump, "module two"); + Module module2(dump, 0x8675884adfe5ac90ULL, 0xb11e4ea3, module2_name); + dump.Add(&module2_name); + dump.Add(&module2); + + String module3_name(dump, "module three"); + Module module3(dump, 0x95fc1544da321b6cULL, 0x7c2bf081, module3_name); + dump.Add(&module3_name); + dump.Add(&module3); + + // Unloaded modules! + uint64_t umodule1_base = 0xeb77da57b5d4cbdaULL; + uint32_t umodule1_size = 0x83cd5a37; + String umodule1_name(dump, "unloaded module one"); + UnloadedModule unloaded_module1(dump, umodule1_base, umodule1_size, + umodule1_name); + dump.Add(&umodule1_name); + dump.Add(&unloaded_module1); + + uint64_t umodule2_base = 0xeb77da57b5d4cbdaULL; + uint32_t umodule2_size = 0x83cd5a37; + String umodule2_name(dump, "unloaded module two"); + UnloadedModule unloaded_module2(dump, umodule2_base, umodule2_size, + umodule2_name); + dump.Add(&umodule2_name); + dump.Add(&unloaded_module2); + + uint64_t umodule3_base = 0xeb77da5839a20000ULL; + uint32_t umodule3_size = 0x83cd5a37; + String umodule3_name(dump, "unloaded module three"); + UnloadedModule unloaded_module3(dump, umodule3_base, umodule3_size, + umodule3_name); + dump.Add(&umodule3_name); + dump.Add(&unloaded_module3); + + + // Add one more memory region, on top of the five stacks. + Memory memory5(dump, 0x61979e828040e564ULL); + memory5.Append("contents of memory 5"); + dump.Add(&memory5); + + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(5U, minidump.GetDirectoryEntryCount()); + + // Check the threads. + MinidumpThreadList *thread_list = minidump.GetThreadList(); + ASSERT_TRUE(thread_list != NULL); + ASSERT_EQ(5U, thread_list->thread_count()); + uint32_t thread_id; + ASSERT_TRUE(thread_list->GetThreadAtIndex(0)->GetThreadID(&thread_id)); + ASSERT_EQ(0xbbef4432U, thread_id); + ASSERT_EQ(0x70b9ebfcU, + thread_list->GetThreadAtIndex(0)->GetMemory()->GetBase()); + ASSERT_EQ(0xaf0709e4U, + thread_list->GetThreadAtIndex(0)->GetContext()->GetContextX86() + ->eip); + + ASSERT_TRUE(thread_list->GetThreadAtIndex(1)->GetThreadID(&thread_id)); + ASSERT_EQ(0x657c3f58U, thread_id); + ASSERT_EQ(0xf988cc45U, + thread_list->GetThreadAtIndex(1)->GetMemory()->GetBase()); + ASSERT_EQ(0xe4f56f81U, + thread_list->GetThreadAtIndex(1)->GetContext()->GetContextX86() + ->eip); + + ASSERT_TRUE(thread_list->GetThreadAtIndex(2)->GetThreadID(&thread_id)); + ASSERT_EQ(0xdf4b8a71U, thread_id); + ASSERT_EQ(0xc8a92e7cU, + thread_list->GetThreadAtIndex(2)->GetMemory()->GetBase()); + ASSERT_EQ(0xb336a438U, + thread_list->GetThreadAtIndex(2)->GetContext()->GetContextX86() + ->eip); + + ASSERT_TRUE(thread_list->GetThreadAtIndex(3)->GetThreadID(&thread_id)); + ASSERT_EQ(0x86e6c341U, thread_id); + ASSERT_EQ(0x36d08e08U, + thread_list->GetThreadAtIndex(3)->GetMemory()->GetBase()); + ASSERT_EQ(0xdf99a60cU, + thread_list->GetThreadAtIndex(3)->GetContext()->GetContextX86() + ->eip); + + ASSERT_TRUE(thread_list->GetThreadAtIndex(4)->GetThreadID(&thread_id)); + ASSERT_EQ(0x261a28d4U, thread_id); + ASSERT_EQ(0x1e0ab4faU, + thread_list->GetThreadAtIndex(4)->GetMemory()->GetBase()); + ASSERT_EQ(0xaa646267U, + thread_list->GetThreadAtIndex(4)->GetContext()->GetContextX86() + ->eip); + + // Check the modules. + MinidumpModuleList *md_module_list = minidump.GetModuleList(); + ASSERT_TRUE(md_module_list != NULL); + ASSERT_EQ(3U, md_module_list->module_count()); + EXPECT_EQ(0xeb77da57b5d4cbdaULL, + md_module_list->GetModuleAtIndex(0)->base_address()); + EXPECT_EQ(0x8675884adfe5ac90ULL, + md_module_list->GetModuleAtIndex(1)->base_address()); + EXPECT_EQ(0x95fc1544da321b6cULL, + md_module_list->GetModuleAtIndex(2)->base_address()); + + // Check unloaded modules + MinidumpUnloadedModuleList *md_unloaded_module_list = + minidump.GetUnloadedModuleList(); + ASSERT_TRUE(md_unloaded_module_list != NULL); + ASSERT_EQ(3U, md_unloaded_module_list->module_count()); + EXPECT_EQ(umodule1_base, + md_unloaded_module_list->GetModuleAtIndex(0)->base_address()); + EXPECT_EQ(umodule2_base, + md_unloaded_module_list->GetModuleAtIndex(1)->base_address()); + EXPECT_EQ(umodule3_base, + md_unloaded_module_list->GetModuleAtIndex(2)->base_address()); + + const MinidumpUnloadedModule *umodule = + md_unloaded_module_list->GetModuleForAddress( + umodule1_base + umodule1_size / 2); + EXPECT_EQ(umodule1_base, umodule->base_address()); + + umodule = md_unloaded_module_list->GetModuleAtSequence(0); + EXPECT_EQ(umodule1_base, umodule->base_address()); + + EXPECT_EQ(NULL, md_unloaded_module_list->GetMainModule()); + +} + +TEST(Dump, OneMemoryInfo) { + Dump dump(0, kBigEndian); + Stream stream(dump, MD_MEMORY_INFO_LIST_STREAM); + + // Add the MDRawMemoryInfoList header. + const uint64_t kNumberOfEntries = 1; + stream.D32(sizeof(MDRawMemoryInfoList)) // size_of_header + .D32(sizeof(MDRawMemoryInfo)) // size_of_entry + .D64(kNumberOfEntries); // number_of_entries + + + // Now add a MDRawMemoryInfo entry. + const uint64_t kBaseAddress = 0x1000; + const uint64_t kRegionSize = 0x2000; + stream.D64(kBaseAddress) // base_address + .D64(kBaseAddress) // allocation_base + .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // allocation_protection + .D32(0) // __alignment1 + .D64(kRegionSize) // region_size + .D32(MD_MEMORY_STATE_COMMIT) // state + .D32(MD_MEMORY_PROTECT_EXECUTE_READWRITE) // protection + .D32(MD_MEMORY_TYPE_PRIVATE) // type + .D32(0); // __alignment2 + + dump.Add(&stream); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + const MDRawDirectory *dir = minidump.GetDirectoryEntryAtIndex(0); + ASSERT_TRUE(dir != NULL); + EXPECT_EQ((uint32_t) MD_MEMORY_INFO_LIST_STREAM, dir->stream_type); + + MinidumpMemoryInfoList *info_list = minidump.GetMemoryInfoList(); + ASSERT_TRUE(info_list != NULL); + ASSERT_EQ(1U, info_list->info_count()); + + const MinidumpMemoryInfo *info1 = info_list->GetMemoryInfoAtIndex(0); + ASSERT_EQ(kBaseAddress, info1->GetBase()); + ASSERT_EQ(kRegionSize, info1->GetSize()); + ASSERT_TRUE(info1->IsExecutable()); + ASSERT_TRUE(info1->IsWritable()); + + // Should get back the same memory region here. + const MinidumpMemoryInfo *info2 = + info_list->GetMemoryInfoForAddress(kBaseAddress + kRegionSize / 2); + ASSERT_EQ(kBaseAddress, info2->GetBase()); + ASSERT_EQ(kRegionSize, info2->GetSize()); +} + +TEST(Dump, OneExceptionX86) { + Dump dump(0, kLittleEndian); + + MDRawContextX86 raw_context; + raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL; + raw_context.edi = 0x3ecba80d; + raw_context.esi = 0x382583b9; + raw_context.ebx = 0x7fccc03f; + raw_context.edx = 0xf62f8ec2; + raw_context.ecx = 0x46a6a6a8; + raw_context.eax = 0x6a5025e2; + raw_context.ebp = 0xd9fabb4a; + raw_context.eip = 0x6913f540; + raw_context.cs = 0xbffe6eda; + raw_context.eflags = 0xb2ce1e2d; + raw_context.esp = 0x659caaa4; + raw_context.ss = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); + const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), + (md_raw_context->context_flags + & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); + EXPECT_EQ(0x3ecba80dU, raw_context.edi); + EXPECT_EQ(0x382583b9U, raw_context.esi); + EXPECT_EQ(0x7fccc03fU, raw_context.ebx); + EXPECT_EQ(0xf62f8ec2U, raw_context.edx); + EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); + EXPECT_EQ(0x6a5025e2U, raw_context.eax); + EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); + EXPECT_EQ(0x6913f540U, raw_context.eip); + EXPECT_EQ(0xbffe6edaU, raw_context.cs); + EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); + EXPECT_EQ(0x659caaa4U, raw_context.esp); + EXPECT_EQ(0x2e951ef7U, raw_context.ss); +} + +TEST(Dump, OneExceptionX86XState) { + Dump dump(0, kLittleEndian); + + MDRawContextX86 raw_context; + raw_context.context_flags = MD_CONTEXT_X86_INTEGER | + MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE; + raw_context.edi = 0x3ecba80d; + raw_context.esi = 0x382583b9; + raw_context.ebx = 0x7fccc03f; + raw_context.edx = 0xf62f8ec2; + raw_context.ecx = 0x46a6a6a8; + raw_context.eax = 0x6a5025e2; + raw_context.ebp = 0xd9fabb4a; + raw_context.eip = 0x6913f540; + raw_context.cs = 0xbffe6eda; + raw_context.eflags = 0xb2ce1e2d; + raw_context.esp = 0x659caaa4; + raw_context.ss = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); + const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL), + (md_raw_context->context_flags + & (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL))); + EXPECT_EQ(0x3ecba80dU, raw_context.edi); + EXPECT_EQ(0x382583b9U, raw_context.esi); + EXPECT_EQ(0x7fccc03fU, raw_context.ebx); + EXPECT_EQ(0xf62f8ec2U, raw_context.edx); + EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); + EXPECT_EQ(0x6a5025e2U, raw_context.eax); + EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); + EXPECT_EQ(0x6913f540U, raw_context.eip); + EXPECT_EQ(0xbffe6edaU, raw_context.cs); + EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); + EXPECT_EQ(0x659caaa4U, raw_context.esp); + EXPECT_EQ(0x2e951ef7U, raw_context.ss); +} + +// Testing that the CPU type can be loaded from a system info stream when +// the CPU flags are missing from the context_flags of an exception record +TEST(Dump, OneExceptionX86NoCPUFlags) { + Dump dump(0, kLittleEndian); + + MDRawContextX86 raw_context; + // Intentionally not setting CPU type in the context_flags + raw_context.context_flags = 0; + raw_context.edi = 0x3ecba80d; + raw_context.esi = 0x382583b9; + raw_context.ebx = 0x7fccc03f; + raw_context.edx = 0xf62f8ec2; + raw_context.ecx = 0x46a6a6a8; + raw_context.eax = 0x6a5025e2; + raw_context.ebp = 0xd9fabb4a; + raw_context.eip = 0x6913f540; + raw_context.cs = 0xbffe6eda; + raw_context.eflags = 0xb2ce1e2d; + raw_context.esp = 0x659caaa4; + raw_context.ss = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + + // Add system info. This is needed as an alternative source for CPU type + // information. Note, that the CPU flags were intentionally skipped from + // the context_flags and this alternative source is required. + String csd_version(dump, "Service Pack 2"); + SystemInfo system_info(dump, SystemInfo::windows_x86, csd_version); + dump.Add(&system_info); + dump.Add(&csd_version); + + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(2U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + + ASSERT_EQ((uint32_t) MD_CONTEXT_X86, md_context->GetContextCPU()); + const MDRawContextX86 *md_raw_context = md_context->GetContextX86(); + ASSERT_TRUE(md_raw_context != NULL); + + // Even though the CPU flags were missing from the context_flags, the + // GetContext call above is expected to load the missing CPU flags from the + // system info stream and set the CPU type bits in context_flags. + ASSERT_EQ((uint32_t) (MD_CONTEXT_X86), md_raw_context->context_flags); + + EXPECT_EQ(0x3ecba80dU, raw_context.edi); + EXPECT_EQ(0x382583b9U, raw_context.esi); + EXPECT_EQ(0x7fccc03fU, raw_context.ebx); + EXPECT_EQ(0xf62f8ec2U, raw_context.edx); + EXPECT_EQ(0x46a6a6a8U, raw_context.ecx); + EXPECT_EQ(0x6a5025e2U, raw_context.eax); + EXPECT_EQ(0xd9fabb4aU, raw_context.ebp); + EXPECT_EQ(0x6913f540U, raw_context.eip); + EXPECT_EQ(0xbffe6edaU, raw_context.cs); + EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags); + EXPECT_EQ(0x659caaa4U, raw_context.esp); + EXPECT_EQ(0x2e951ef7U, raw_context.ss); +} + +// This test covers a scenario where a dump contains an exception but the +// context record of the exception is missing the CPU type information in its +// context_flags. The dump has no system info stream so it is imposible to +// deduce the CPU type, hence the context record is unusable. +TEST(Dump, OneExceptionX86NoCPUFlagsNoSystemInfo) { + Dump dump(0, kLittleEndian); + + MDRawContextX86 raw_context; + // Intentionally not setting CPU type in the context_flags + raw_context.context_flags = 0; + raw_context.edi = 0x3ecba80d; + raw_context.esi = 0x382583b9; + raw_context.ebx = 0x7fccc03f; + raw_context.edx = 0xf62f8ec2; + raw_context.ecx = 0x46a6a6a8; + raw_context.eax = 0x6a5025e2; + raw_context.ebp = 0xd9fabb4a; + raw_context.eip = 0x6913f540; + raw_context.cs = 0xbffe6eda; + raw_context.eflags = 0xb2ce1e2d; + raw_context.esp = 0x659caaa4; + raw_context.ss = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + // The context record of the exception is unusable because the context_flags + // don't have CPU type information and at the same time the minidump lacks + // system info stream so it is impossible to deduce the CPU type. + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_EQ(NULL, md_context); +} + +TEST(Dump, OneExceptionARM) { + Dump dump(0, kLittleEndian); + + MDRawContextARM raw_context; + raw_context.context_flags = MD_CONTEXT_ARM_INTEGER; + raw_context.iregs[0] = 0x3ecba80d; + raw_context.iregs[1] = 0x382583b9; + raw_context.iregs[2] = 0x7fccc03f; + raw_context.iregs[3] = 0xf62f8ec2; + raw_context.iregs[4] = 0x46a6a6a8; + raw_context.iregs[5] = 0x6a5025e2; + raw_context.iregs[6] = 0xd9fabb4a; + raw_context.iregs[7] = 0x6913f540; + raw_context.iregs[8] = 0xbffe6eda; + raw_context.iregs[9] = 0xb2ce1e2d; + raw_context.iregs[10] = 0x659caaa4; + raw_context.iregs[11] = 0xf0e0d0c0; + raw_context.iregs[12] = 0xa9b8c7d6; + raw_context.iregs[13] = 0x12345678; + raw_context.iregs[14] = 0xabcd1234; + raw_context.iregs[15] = 0x10203040; + raw_context.cpsr = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); + const MDRawContextARM *md_raw_context = md_context->GetContextARM(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, + (md_raw_context->context_flags + & MD_CONTEXT_ARM_INTEGER)); + EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); + EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); + EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); + EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); + EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); + EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); + EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); + EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); + EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); + EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); + EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); + EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); + EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); + EXPECT_EQ(0x12345678U, raw_context.iregs[13]); + EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); + EXPECT_EQ(0x10203040U, raw_context.iregs[15]); + EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); +} + +TEST(Dump, OneExceptionARMOldFlags) { + Dump dump(0, kLittleEndian); + + MDRawContextARM raw_context; + // MD_CONTEXT_ARM_INTEGER, but with _OLD + raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002; + raw_context.iregs[0] = 0x3ecba80d; + raw_context.iregs[1] = 0x382583b9; + raw_context.iregs[2] = 0x7fccc03f; + raw_context.iregs[3] = 0xf62f8ec2; + raw_context.iregs[4] = 0x46a6a6a8; + raw_context.iregs[5] = 0x6a5025e2; + raw_context.iregs[6] = 0xd9fabb4a; + raw_context.iregs[7] = 0x6913f540; + raw_context.iregs[8] = 0xbffe6eda; + raw_context.iregs[9] = 0xb2ce1e2d; + raw_context.iregs[10] = 0x659caaa4; + raw_context.iregs[11] = 0xf0e0d0c0; + raw_context.iregs[12] = 0xa9b8c7d6; + raw_context.iregs[13] = 0x12345678; + raw_context.iregs[14] = 0xabcd1234; + raw_context.iregs[15] = 0x10203040; + raw_context.cpsr = 0x2e951ef7; + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9c9d9e9f9ULL, + raw_exception->exception_record.exception_address); + + MinidumpContext *md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_ARM, md_context->GetContextCPU()); + const MDRawContextARM *md_raw_context = md_context->GetContextARM(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_ARM_INTEGER, + (md_raw_context->context_flags + & MD_CONTEXT_ARM_INTEGER)); + EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); + EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); + EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); + EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); + EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); + EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); + EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); + EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); + EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); + EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); + EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); + EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); + EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); + EXPECT_EQ(0x12345678U, raw_context.iregs[13]); + EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); + EXPECT_EQ(0x10203040U, raw_context.iregs[15]); + EXPECT_EQ(0x2e951ef7U, raw_context.cpsr); +} + +TEST(Dump, OneExceptionMIPS) { + Dump dump(0, kLittleEndian); + + MDRawContextMIPS raw_context; + raw_context.context_flags = MD_CONTEXT_MIPS_INTEGER; + raw_context.iregs[0] = 0x3ecba80d; + raw_context.iregs[1] = 0x382583b9; + raw_context.iregs[2] = 0x7fccc03f; + raw_context.iregs[3] = 0xf62f8ec2; + raw_context.iregs[4] = 0x46a6a6a8; + raw_context.iregs[5] = 0x6a5025e2; + raw_context.iregs[6] = 0xd9fabb4a; + raw_context.iregs[7] = 0x6913f540; + raw_context.iregs[8] = 0xbffe6eda; + raw_context.iregs[9] = 0xb2ce1e2d; + raw_context.iregs[10] = 0x659caaa4; + raw_context.iregs[11] = 0xf0e0d0c0; + raw_context.iregs[12] = 0xa9b8c7d6; + raw_context.iregs[13] = 0x12345678; + raw_context.iregs[14] = 0xabcd1234; + raw_context.iregs[15] = 0x10203040; + raw_context.iregs[16] = 0xa80d3ecb; + raw_context.iregs[17] = 0x83b93825; + raw_context.iregs[18] = 0xc03f7fcc; + raw_context.iregs[19] = 0x8ec2f62f; + raw_context.iregs[20] = 0xa6a846a6; + raw_context.iregs[21] = 0x25e26a50; + raw_context.iregs[22] = 0xbb4ad9fa; + raw_context.iregs[23] = 0xf5406913; + raw_context.iregs[24] = 0x6edabffe; + raw_context.iregs[25] = 0x1e2db2ce; + raw_context.iregs[26] = 0xaaa4659c; + raw_context.iregs[27] = 0xd0c0f0e0; + raw_context.iregs[28] = 0xc7d6a9b8; + raw_context.iregs[29] = 0x56781234; + raw_context.iregs[30] = 0x1234abcd; + raw_context.iregs[31] = 0x30401020; + + Context context(dump, raw_context); + + Exception exception(dump, context, + 0x1234abcd, // Thread id. + 0xdcba4321, // Exception code. + 0xf0e0d0c0, // Exception flags. + 0x0919a9b9); // Exception address. + + dump.Add(&context); + dump.Add(&exception); + dump.Finish(); + + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + + istringstream minidump_stream(contents); + Minidump minidump(minidump_stream); + ASSERT_TRUE(minidump.Read()); + ASSERT_EQ(1U, minidump.GetDirectoryEntryCount()); + + MinidumpException *md_exception = minidump.GetException(); + ASSERT_TRUE(md_exception != NULL); + + uint32_t thread_id; + ASSERT_TRUE(md_exception->GetThreadID(&thread_id)); + ASSERT_EQ(0x1234abcdU, thread_id); + + const MDRawExceptionStream* raw_exception = md_exception->exception(); + ASSERT_TRUE(raw_exception != NULL); + EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code); + EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags); + EXPECT_EQ(0x0919a9b9U, + raw_exception->exception_record.exception_address); + + MinidumpContext* md_context = md_exception->GetContext(); + ASSERT_TRUE(md_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS, md_context->GetContextCPU()); + const MDRawContextMIPS* md_raw_context = md_context->GetContextMIPS(); + ASSERT_TRUE(md_raw_context != NULL); + ASSERT_EQ((uint32_t) MD_CONTEXT_MIPS_INTEGER, + (md_raw_context->context_flags & MD_CONTEXT_MIPS_INTEGER)); + EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]); + EXPECT_EQ(0x382583b9U, raw_context.iregs[1]); + EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]); + EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]); + EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]); + EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]); + EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]); + EXPECT_EQ(0x6913f540U, raw_context.iregs[7]); + EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]); + EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]); + EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]); + EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]); + EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]); + EXPECT_EQ(0x12345678U, raw_context.iregs[13]); + EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]); + EXPECT_EQ(0x10203040U, raw_context.iregs[15]); + EXPECT_EQ(0xa80d3ecbU, raw_context.iregs[16]); + EXPECT_EQ(0x83b93825U, raw_context.iregs[17]); + EXPECT_EQ(0xc03f7fccU, raw_context.iregs[18]); + EXPECT_EQ(0x8ec2f62fU, raw_context.iregs[19]); + EXPECT_EQ(0xa6a846a6U, raw_context.iregs[20]); + EXPECT_EQ(0x25e26a50U, raw_context.iregs[21]); + EXPECT_EQ(0xbb4ad9faU, raw_context.iregs[22]); + EXPECT_EQ(0xf5406913U, raw_context.iregs[23]); + EXPECT_EQ(0x6edabffeU, raw_context.iregs[24]); + EXPECT_EQ(0x1e2db2ceU, raw_context.iregs[25]); + EXPECT_EQ(0xaaa4659cU, raw_context.iregs[26]); + EXPECT_EQ(0xd0c0f0e0U, raw_context.iregs[27]); + EXPECT_EQ(0xc7d6a9b8U, raw_context.iregs[28]); + EXPECT_EQ(0x56781234U, raw_context.iregs[29]); + EXPECT_EQ(0x1234abcdU, raw_context.iregs[30]); + EXPECT_EQ(0x30401020U, raw_context.iregs[31]); +} + +} // namespace diff --git a/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.cc b/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.cc new file mode 100644 index 0000000000..025ab883a3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.cc @@ -0,0 +1,302 @@ +// Copyright (c) 2010, 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. +// +// module_comparer.cc: ModuleComparer implementation. +// See module_comparer.h for documentation. +// +// Author: lambxsy@google.com (Siyang Xie) + +#include "processor/module_comparer.h" + +#include +#include + +#include "common/scoped_ptr.h" +#include "processor/basic_code_module.h" +#include "processor/logging.h" + +#define ASSERT_TRUE(condition) \ + if (!(condition)) { \ + BPLOG(ERROR) << "FAIL: " << #condition << " @ " \ + << __FILE__ << ":" << __LINE__; \ + return false; \ + } + +#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition)) + +namespace google_breakpad { + +bool ModuleComparer::Compare(const string &symbol_data) { + scoped_ptr basic_module(new BasicModule("test_module")); + scoped_ptr fast_module(new FastModule("test_module")); + + // Load symbol data into basic_module + scoped_array buffer(new char[symbol_data.size() + 1]); + memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size()); + buffer.get()[symbol_data.size()] = '\0'; + ASSERT_TRUE(basic_module->LoadMapFromMemory(buffer.get(), + symbol_data.size() + 1)); + buffer.reset(); + + // Serialize BasicSourceLineResolver::Module. + unsigned int serialized_size = 0; + scoped_array serialized_data( + serializer_.Serialize(*(basic_module.get()), &serialized_size)); + ASSERT_TRUE(serialized_data.get()); + BPLOG(INFO) << "Serialized size = " << serialized_size << " Bytes"; + + // Load FastSourceLineResolver::Module using serialized data. + ASSERT_TRUE(fast_module->LoadMapFromMemory(serialized_data.get(), + serialized_size)); + ASSERT_TRUE(fast_module->IsCorrupt() == basic_module->IsCorrupt()); + + // Compare FastSourceLineResolver::Module with + // BasicSourceLineResolver::Module. + ASSERT_TRUE(CompareModule(basic_module.get(), fast_module.get())); + + return true; +} + +// Traversal the content of module and do comparison +bool ModuleComparer::CompareModule(const BasicModule *basic_module, + const FastModule *fast_module) const { + // Compare name_. + ASSERT_TRUE(basic_module->name_ == fast_module->name_); + + // Compare files_: + { + BasicModule::FileMap::const_iterator iter1 = basic_module->files_.begin(); + FastModule::FileMap::iterator iter2 = fast_module->files_.begin(); + while (iter1 != basic_module->files_.end() + && iter2 != fast_module->files_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + string tmp(iter2.GetValuePtr()); + ASSERT_TRUE(iter1->second == tmp); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_module->files_.end()); + ASSERT_TRUE(iter2 == fast_module->files_.end()); + } + + // Compare functions_: + { + RangeMap >::MapConstIterator iter1; + StaticRangeMap::MapConstIterator iter2; + iter1 = basic_module->functions_.map_.begin(); + iter2 = fast_module->functions_.map_.begin(); + while (iter1 != basic_module->functions_.map_.end() + && iter2 != fast_module->functions_.map_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base()); + ASSERT_TRUE(CompareFunction( + iter1->second.entry().get(), iter2.GetValuePtr()->entryptr())); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_module->functions_.map_.end()); + ASSERT_TRUE(iter2 == fast_module->functions_.map_.end()); + } + + // Compare public_symbols_: + { + AddressMap >::MapConstIterator iter1; + StaticAddressMap::MapConstIterator iter2; + iter1 = basic_module->public_symbols_.map_.begin(); + iter2 = fast_module->public_symbols_.map_.begin(); + while (iter1 != basic_module->public_symbols_.map_.end() + && iter2 != fast_module->public_symbols_.map_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + ASSERT_TRUE(ComparePubSymbol( + iter1->second.get(), iter2.GetValuePtr())); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_module->public_symbols_.map_.end()); + ASSERT_TRUE(iter2 == fast_module->public_symbols_.map_.end()); + } + + // Compare windows_frame_info_[]: + for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) { + ASSERT_TRUE(CompareCRM(&(basic_module->windows_frame_info_[i]), + &(fast_module->windows_frame_info_[i]))); + } + + // Compare cfi_initial_rules_: + { + RangeMap::MapConstIterator iter1; + StaticRangeMap::MapConstIterator iter2; + iter1 = basic_module->cfi_initial_rules_.map_.begin(); + iter2 = fast_module->cfi_initial_rules_.map_.begin(); + while (iter1 != basic_module->cfi_initial_rules_.map_.end() + && iter2 != fast_module->cfi_initial_rules_.map_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base()); + string tmp(iter2.GetValuePtr()->entryptr()); + ASSERT_TRUE(iter1->second.entry() == tmp); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_module->cfi_initial_rules_.map_.end()); + ASSERT_TRUE(iter2 == fast_module->cfi_initial_rules_.map_.end()); + } + + // Compare cfi_delta_rules_: + { + map::const_iterator iter1; + StaticMap::iterator iter2; + iter1 = basic_module->cfi_delta_rules_.begin(); + iter2 = fast_module->cfi_delta_rules_.begin(); + while (iter1 != basic_module->cfi_delta_rules_.end() + && iter2 != fast_module->cfi_delta_rules_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + string tmp(iter2.GetValuePtr()); + ASSERT_TRUE(iter1->second == tmp); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_module->cfi_delta_rules_.end()); + ASSERT_TRUE(iter2 == fast_module->cfi_delta_rules_.end()); + } + + return true; +} + +bool ModuleComparer::CompareFunction(const BasicFunc *basic_func, + const FastFunc *fast_func_raw) const { + FastFunc* fast_func = new FastFunc(); + fast_func->CopyFrom(fast_func_raw); + ASSERT_TRUE(basic_func->name == fast_func->name); + ASSERT_TRUE(basic_func->address == fast_func->address); + ASSERT_TRUE(basic_func->size == fast_func->size); + + // compare range map of lines: + RangeMap >::MapConstIterator iter1; + StaticRangeMap::MapConstIterator iter2; + iter1 = basic_func->lines.map_.begin(); + iter2 = fast_func->lines.map_.begin(); + while (iter1 != basic_func->lines.map_.end() + && iter2 != fast_func->lines.map_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + ASSERT_TRUE(iter1->second.base() == iter2.GetValuePtr()->base()); + ASSERT_TRUE(CompareLine(iter1->second.entry().get(), + iter2.GetValuePtr()->entryptr())); + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_func->lines.map_.end()); + ASSERT_TRUE(iter2 == fast_func->lines.map_.end()); + + delete fast_func; + return true; +} + +bool ModuleComparer::CompareLine(const BasicLine *basic_line, + const FastLine *fast_line_raw) const { + FastLine *fast_line = new FastLine; + fast_line->CopyFrom(fast_line_raw); + + ASSERT_TRUE(basic_line->address == fast_line->address); + ASSERT_TRUE(basic_line->size == fast_line->size); + ASSERT_TRUE(basic_line->source_file_id == fast_line->source_file_id); + ASSERT_TRUE(basic_line->line == fast_line->line); + + delete fast_line; + return true; +} + +bool ModuleComparer::ComparePubSymbol(const BasicPubSymbol* basic_ps, + const FastPubSymbol* fastps_raw) const { + FastPubSymbol *fast_ps = new FastPubSymbol; + fast_ps->CopyFrom(fastps_raw); + ASSERT_TRUE(basic_ps->name == fast_ps->name); + ASSERT_TRUE(basic_ps->address == fast_ps->address); + ASSERT_TRUE(basic_ps->parameter_size == fast_ps->parameter_size); + delete fast_ps; + return true; +} + +bool ModuleComparer::CompareWFI(const WindowsFrameInfo& wfi1, + const WindowsFrameInfo& wfi2) const { + ASSERT_TRUE(wfi1.type_ == wfi2.type_); + ASSERT_TRUE(wfi1.valid == wfi2.valid); + ASSERT_TRUE(wfi1.prolog_size == wfi2.prolog_size); + ASSERT_TRUE(wfi1.epilog_size == wfi2.epilog_size); + ASSERT_TRUE(wfi1.parameter_size == wfi2.parameter_size); + ASSERT_TRUE(wfi1.saved_register_size == wfi2.saved_register_size); + ASSERT_TRUE(wfi1.local_size == wfi2.local_size); + ASSERT_TRUE(wfi1.max_stack_size == wfi2.max_stack_size); + ASSERT_TRUE(wfi1.allocates_base_pointer == wfi2.allocates_base_pointer); + ASSERT_TRUE(wfi1.program_string == wfi2.program_string); + return true; +} + +// Compare ContainedRangeMap +bool ModuleComparer::CompareCRM( + const ContainedRangeMap >* basic_crm, + const StaticContainedRangeMap* fast_crm) const { + ASSERT_TRUE(basic_crm->base_ == fast_crm->base_); + + if (!basic_crm->entry_.get() || !fast_crm->entry_ptr_) { + // empty entry: + ASSERT_TRUE(!basic_crm->entry_.get() && !fast_crm->entry_ptr_); + } else { + WFI newwfi; + newwfi.CopyFrom(fast_resolver_->CopyWFI(fast_crm->entry_ptr_)); + ASSERT_TRUE(CompareWFI(*(basic_crm->entry_.get()), newwfi)); + } + + if ((!basic_crm->map_ || basic_crm->map_->empty()) + || fast_crm->map_.empty()) { + ASSERT_TRUE((!basic_crm->map_ || basic_crm->map_->empty()) + && fast_crm->map_.empty()); + } else { + ContainedRangeMap >::MapConstIterator iter1; + StaticContainedRangeMap::MapConstIterator iter2; + iter1 = basic_crm->map_->begin(); + iter2 = fast_crm->map_.begin(); + while (iter1 != basic_crm->map_->end() + && iter2 != fast_crm->map_.end()) { + ASSERT_TRUE(iter1->first == iter2.GetKey()); + StaticContainedRangeMap *child = + new StaticContainedRangeMap( + reinterpret_cast(iter2.GetValuePtr())); + ASSERT_TRUE(CompareCRM(iter1->second, child)); + delete child; + ++iter1; + ++iter2; + } + ASSERT_TRUE(iter1 == basic_crm->map_->end()); + ASSERT_TRUE(iter2 == fast_crm->map_.end()); + } + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.h b/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.h new file mode 100644 index 0000000000..fcbd51775f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/module_comparer.h @@ -0,0 +1,98 @@ +// Copyright (c) 2010, 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. +// +// module_comparer.h: ModuleComparer reads a string format of symbol file, and +// loads the symbol into both BasicSourceLineResolver::Module and +// FastSourceLineResolve::Module. It then traverses both Modules and compare +// the content of data to verify the correctness of new fast module. +// ModuleCompare class is a tool to verify correctness of a loaded +// FastSourceLineResolver::Module instance, i.e., in-memory representation of +// parsed symbol. ModuleComparer class should be used for testing purpose only, +// e.g., in fast_source_line_resolver_unittest. +// +// Author: lambxsy@google.com (Siyang Xie) + +#ifndef PROCESSOR_MODULE_COMPARER_H__ +#define PROCESSOR_MODULE_COMPARER_H__ + +#include + +#include "processor/basic_source_line_resolver_types.h" +#include "processor/fast_source_line_resolver_types.h" +#include "processor/module_serializer.h" +#include "processor/windows_frame_info.h" + +namespace google_breakpad { + +class ModuleComparer { + public: + ModuleComparer(): fast_resolver_(new FastSourceLineResolver), + basic_resolver_(new BasicSourceLineResolver) { } + ~ModuleComparer() { + delete fast_resolver_; + delete basic_resolver_; + } + + // BasicSourceLineResolver loads its module using the symbol data, + // ModuleSerializer serialize the loaded module into a memory chunk, + // FastSourceLineResolver loads its module using the serialized memory chunk, + // Then, traverse both modules together and compare underlying data + // return true if both modules contain exactly same data. + bool Compare(const string &symbol_data); + + private: + typedef BasicSourceLineResolver::Module BasicModule; + typedef FastSourceLineResolver::Module FastModule; + typedef BasicSourceLineResolver::Function BasicFunc; + typedef FastSourceLineResolver::Function FastFunc; + typedef BasicSourceLineResolver::Line BasicLine; + typedef FastSourceLineResolver::Line FastLine; + typedef BasicSourceLineResolver::PublicSymbol BasicPubSymbol; + typedef FastSourceLineResolver::PublicSymbol FastPubSymbol; + typedef WindowsFrameInfo WFI; + + bool CompareModule(const BasicModule *oldmodule, + const FastModule *newmodule) const; + bool CompareFunction(const BasicFunc *oldfunc, const FastFunc *newfunc) const; + bool CompareLine(const BasicLine *oldline, const FastLine *newline) const; + bool ComparePubSymbol(const BasicPubSymbol*, const FastPubSymbol*) const; + bool CompareWFI(const WindowsFrameInfo&, const WindowsFrameInfo&) const; + + // Compare ContainedRangeMap + bool CompareCRM(const ContainedRangeMap >*, + const StaticContainedRangeMap*) const; + + FastSourceLineResolver *fast_resolver_; + BasicSourceLineResolver *basic_resolver_; + ModuleSerializer serializer_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_MODULE_COMPARER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/module_factory.h b/toolkit/crashreporter/google-breakpad/src/processor/module_factory.h new file mode 100644 index 0000000000..7aa7caa59d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/module_factory.h @@ -0,0 +1,72 @@ +// Copyright (c) 2010 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. +// +// module_factory.h: ModuleFactory a factory that provides +// an interface for creating a Module and deferring instantiation to subclasses +// BasicModuleFactory and FastModuleFactory. + +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_MODULE_FACTORY_H__ +#define PROCESSOR_MODULE_FACTORY_H__ + +#include "processor/basic_source_line_resolver_types.h" +#include "processor/fast_source_line_resolver_types.h" +#include "processor/source_line_resolver_base_types.h" + +namespace google_breakpad { + +class ModuleFactory { + public: + virtual ~ModuleFactory() { }; + virtual SourceLineResolverBase::Module* CreateModule( + const string &name) const = 0; +}; + +class BasicModuleFactory : public ModuleFactory { + public: + virtual ~BasicModuleFactory() { } + virtual BasicSourceLineResolver::Module* CreateModule( + const string &name) const { + return new BasicSourceLineResolver::Module(name); + } +}; + +class FastModuleFactory : public ModuleFactory { + public: + virtual ~FastModuleFactory() { } + virtual FastSourceLineResolver::Module* CreateModule( + const string &name) const { + return new FastSourceLineResolver::Module(name); + } +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_MODULE_FACTORY_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.cc b/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.cc new file mode 100644 index 0000000000..6ac60c1fcf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.cc @@ -0,0 +1,207 @@ +// Copyright (c) 2010, 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. +// +// module_serializer.cc: ModuleSerializer implementation. +// +// See module_serializer.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include "processor/module_serializer.h" + +#include +#include + +#include "processor/basic_code_module.h" +#include "processor/logging.h" + +namespace google_breakpad { + +// Definition of static member variable in SimplerSerializer, which +// is declared in file "simple_serializer-inl.h" +RangeMapSerializer< MemAddr, linked_ptr > +SimpleSerializer::range_map_serializer_; + +size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) { + size_t total_size_alloc_ = 0; + + // Size of the "is_corrupt" flag. + total_size_alloc_ += SimpleSerializer::SizeOf(module.is_corrupt_); + + // Compute memory size for each map component in Module class. + int map_index = 0; + map_sizes_[map_index++] = files_serializer_.SizeOf(module.files_); + map_sizes_[map_index++] = functions_serializer_.SizeOf(module.functions_); + map_sizes_[map_index++] = pubsym_serializer_.SizeOf(module.public_symbols_); + for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) + map_sizes_[map_index++] = + wfi_serializer_.SizeOf(&(module.windows_frame_info_[i])); + map_sizes_[map_index++] = cfi_init_rules_serializer_.SizeOf( + module.cfi_initial_rules_); + map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf( + module.cfi_delta_rules_); + + // Header size. + total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t); + + for (int i = 0; i < kNumberMaps_; ++i) { + total_size_alloc_ += map_sizes_[i]; + } + + // Extra one byte for null terminator for C-string copy safety. + total_size_alloc_ += SimpleSerializer::SizeOf(0); + + return total_size_alloc_; +} + +char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module, + char *dest) { + // Write the is_corrupt flag. + dest = SimpleSerializer::Write(module.is_corrupt_, dest); + // Write header. + memcpy(dest, map_sizes_, kNumberMaps_ * sizeof(uint32_t)); + dest += kNumberMaps_ * sizeof(uint32_t); + // Write each map. + dest = files_serializer_.Write(module.files_, dest); + dest = functions_serializer_.Write(module.functions_, dest); + dest = pubsym_serializer_.Write(module.public_symbols_, dest); + for (int i = 0; i < WindowsFrameInfo::STACK_INFO_LAST; ++i) + dest = wfi_serializer_.Write(&(module.windows_frame_info_[i]), dest); + dest = cfi_init_rules_serializer_.Write(module.cfi_initial_rules_, dest); + dest = cfi_delta_rules_serializer_.Write(module.cfi_delta_rules_, dest); + // Write a null terminator. + dest = SimpleSerializer::Write(0, dest); + return dest; +} + +char* ModuleSerializer::Serialize( + const BasicSourceLineResolver::Module &module, unsigned int *size) { + // Compute size of memory to allocate. + unsigned int size_to_alloc = SizeOf(module); + + // Allocate memory for serialized data. + char *serialized_data = new char[size_to_alloc]; + if (!serialized_data) { + BPLOG(ERROR) << "ModuleSerializer: memory allocation failed, " + << "size to alloc: " << size_to_alloc; + if (size) *size = 0; + return NULL; + } + + // Write serialized data to allocated memory chunk. + char *end_address = Write(module, serialized_data); + // Verify the allocated memory size is equal to the size of data been written. + unsigned int size_written = + static_cast(end_address - serialized_data); + if (size_to_alloc != size_written) { + BPLOG(ERROR) << "size_to_alloc differs from size_written: " + << size_to_alloc << " vs " << size_written; + } + + // Set size and return the start address of memory chunk. + if (size) + *size = size_to_alloc; + return serialized_data; +} + +bool ModuleSerializer::SerializeModuleAndLoadIntoFastResolver( + const BasicSourceLineResolver::ModuleMap::const_iterator &iter, + FastSourceLineResolver *fast_resolver) { + BPLOG(INFO) << "Converting symbol " << iter->first.c_str(); + + // Cast SourceLineResolverBase::Module* to BasicSourceLineResolver::Module*. + BasicSourceLineResolver::Module* basic_module = + dynamic_cast(iter->second); + + unsigned int size = 0; + scoped_array symbol_data(Serialize(*basic_module, &size)); + if (!symbol_data.get()) { + BPLOG(ERROR) << "Serialization failed for module: " << basic_module->name_; + return false; + } + BPLOG(INFO) << "Serialized Symbol Size " << size; + + // Copy the data into string. + // Must pass string to LoadModuleUsingMapBuffer(), instead of passing char* to + // LoadModuleUsingMemoryBuffer(), becaused of data ownership/lifetime issue. + string symbol_data_string(symbol_data.get(), size); + symbol_data.reset(); + + scoped_ptr code_module( + new BasicCodeModule(0, 0, iter->first, "", "", "", "")); + + return fast_resolver->LoadModuleUsingMapBuffer(code_module.get(), + symbol_data_string); +} + +void ModuleSerializer::ConvertAllModules( + const BasicSourceLineResolver *basic_resolver, + FastSourceLineResolver *fast_resolver) { + // Check for NULL pointer. + if (!basic_resolver || !fast_resolver) + return; + + // Traverse module list in basic resolver. + BasicSourceLineResolver::ModuleMap::const_iterator iter; + iter = basic_resolver->modules_->begin(); + for (; iter != basic_resolver->modules_->end(); ++iter) + SerializeModuleAndLoadIntoFastResolver(iter, fast_resolver); +} + +bool ModuleSerializer::ConvertOneModule( + const string &moduleid, + const BasicSourceLineResolver *basic_resolver, + FastSourceLineResolver *fast_resolver) { + // Check for NULL pointer. + if (!basic_resolver || !fast_resolver) + return false; + + BasicSourceLineResolver::ModuleMap::const_iterator iter; + iter = basic_resolver->modules_->find(moduleid); + if (iter == basic_resolver->modules_->end()) + return false; + + return SerializeModuleAndLoadIntoFastResolver(iter, fast_resolver); +} + +char* ModuleSerializer::SerializeSymbolFileData( + const string &symbol_data, unsigned int *size) { + scoped_ptr module( + new BasicSourceLineResolver::Module("no name")); + scoped_array buffer(new char[symbol_data.size() + 1]); + memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size()); + buffer.get()[symbol_data.size()] = '\0'; + if (!module->LoadMapFromMemory(buffer.get(), symbol_data.size() + 1)) { + return NULL; + } + buffer.reset(NULL); + return Serialize(*(module.get()), size); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.h b/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.h new file mode 100644 index 0000000000..effb009162 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/module_serializer.h @@ -0,0 +1,127 @@ +// Copyright (c) 2010, 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. +// +// module_serializer.h: ModuleSerializer serializes a loaded symbol, +// i.e., a loaded BasicSouceLineResolver::Module instance, into a memory +// chunk of data. The serialized data can be read and loaded by +// FastSourceLineResolver without CPU & memory-intensive parsing. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_MODULE_SERIALIZER_H__ +#define PROCESSOR_MODULE_SERIALIZER_H__ + +#include +#include + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/fast_source_line_resolver.h" +#include "processor/basic_source_line_resolver_types.h" +#include "processor/fast_source_line_resolver_types.h" +#include "processor/linked_ptr.h" +#include "processor/map_serializers-inl.h" +#include "processor/simple_serializer-inl.h" +#include "processor/windows_frame_info.h" + +namespace google_breakpad { + +// ModuleSerializer serializes a loaded BasicSourceLineResolver::Module into a +// chunk of memory data. ModuleSerializer also provides interface to compute +// memory size of the serialized data, write serialized data directly into +// memory, convert ASCII format symbol data into serialized binary data, and +// convert loaded BasicSourceLineResolver::Module into +// FastSourceLineResolver::Module. +class ModuleSerializer { + public: + // Compute the size of memory required to serialize a module. Return the + // total size needed for serialization. + size_t SizeOf(const BasicSourceLineResolver::Module &module); + + // Write a module into an allocated memory chunk with required size. + // Return the "end" of data, i.e., the address after the final byte of data. + char* Write(const BasicSourceLineResolver::Module &module, char *dest); + + // Serializes a loaded Module object into a chunk of memory data and returns + // the address of memory chunk. If size != NULL, *size is set to the memory + // size allocated for the serialized data. + // Caller takes the ownership of the memory chunk (allocated on heap), and + // owner should call delete [] to free the memory after use. + char* Serialize(const BasicSourceLineResolver::Module &module, + unsigned int *size = NULL); + + // Given the string format symbol_data, produces a chunk of serialized data. + // Caller takes ownership of the serialized data (on heap), and owner should + // call delete [] to free the memory after use. + char* SerializeSymbolFileData(const string &symbol_data, + unsigned int *size = NULL); + + // Serializes one loaded module with given moduleid in the basic source line + // resolver, and loads the serialized data into the fast source line resolver. + // Return false if the basic source line doesn't have a module with the given + // moduleid. + bool ConvertOneModule(const string &moduleid, + const BasicSourceLineResolver *basic_resolver, + FastSourceLineResolver *fast_resolver); + + // Serializes all the loaded modules in a basic source line resolver, and + // loads the serialized data into a fast source line resolver. + void ConvertAllModules(const BasicSourceLineResolver *basic_resolver, + FastSourceLineResolver *fast_resolver); + + private: + // Convenient type names. + typedef BasicSourceLineResolver::Line Line; + typedef BasicSourceLineResolver::Function Function; + typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; + + // Internal implementation for ConvertOneModule and ConvertAllModules methods. + bool SerializeModuleAndLoadIntoFastResolver( + const BasicSourceLineResolver::ModuleMap::const_iterator &iter, + FastSourceLineResolver *fast_resolver); + + // Number of Maps that Module class contains. + static const int32_t kNumberMaps_ = + FastSourceLineResolver::Module::kNumberMaps_; + + // Memory sizes required to serialize map components in Module. + uint32_t map_sizes_[kNumberMaps_]; + + // Serializers for each individual map component in Module class. + StdMapSerializer files_serializer_; + RangeMapSerializer > functions_serializer_; + AddressMapSerializer > pubsym_serializer_; + ContainedRangeMapSerializer > wfi_serializer_; + RangeMapSerializer cfi_init_rules_serializer_; + StdMapSerializer cfi_delta_rules_serializer_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_MODULE_SERIALIZER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/moz.build b/toolkit/crashreporter/google-breakpad/src/processor/moz.build new file mode 100644 index 0000000000..697cbea5f7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/moz.build @@ -0,0 +1,76 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + '../third_party/libdisasm/ia32_invariant.c', + '../third_party/libdisasm/ia32_reg.c', + 'disassembler_x86.cc', + 'exploitability_win.cc', +] + +# clang -Wtautological-constant-in-range-compare implicitly enables +# -Wtautological-value-range-compare, but we need to disable it to avoid +# Breakpad bug https://bugs.chromium.org/p/google-breakpad/issues/detail?id=859 +if CONFIG["WARNINGS_CFLAGS"] and "-Wtautological-constant-in-range-compare" in CONFIG["WARNINGS_CFLAGS"]: + SOURCES['../third_party/libdisasm/ia32_invariant.c'].flags += ["-Wno-tautological-value-range-compare"] + +if CONFIG["CC_TYPE"] == "gcc" and int(CONFIG["CC_VERSION"].split(".")[0]) >= 8: + SOURCES['../third_party/libdisasm/ia32_reg.c'].flags += ["-Wno-stringop-truncation"] + +UNIFIED_SOURCES += [ + '../third_party/libdisasm/ia32_implicit.c', + '../third_party/libdisasm/ia32_insn.c', + '../third_party/libdisasm/ia32_modrm.c', + '../third_party/libdisasm/ia32_opcode_tables.c', + '../third_party/libdisasm/ia32_operand.c', + '../third_party/libdisasm/ia32_settings.c', + '../third_party/libdisasm/x86_disasm.c', + '../third_party/libdisasm/x86_imm.c', + '../third_party/libdisasm/x86_insn.c', + '../third_party/libdisasm/x86_misc.c', + '../third_party/libdisasm/x86_operand_list.c', + 'basic_code_modules.cc', + 'basic_source_line_resolver.cc', + 'call_stack.cc', + 'cfi_frame_info.cc', + 'convert_old_arm64_context.cc', + 'dump_context.cc', + 'dump_object.cc', + 'exploitability.cc', + 'exploitability_linux.cc', + 'logging.cc', + 'minidump.cc', + 'minidump_processor.cc', + 'pathname_stripper.cc', + 'proc_maps_linux.cc', + 'process_state.cc', + 'source_line_resolver_base.cc', + 'stack_frame_symbolizer.cc', + 'stackwalk_common.cc', + 'stackwalker.cc', + 'stackwalker_amd64.cc', + 'stackwalker_arm.cc', + 'stackwalker_arm64.cc', + 'stackwalker_mips.cc', + 'stackwalker_ppc.cc', + 'stackwalker_ppc64.cc', + 'stackwalker_sparc.cc', + 'stackwalker_x86.cc', + 'symbolic_constants_win.cc', + 'tokenize.cc', +] + +DEFINES['BPLOG_MINIMUM_SEVERITY'] = 'SEVERITY_CRITICAL' + +Library('breakpad_processor') + +# Don't use the STL wrappers in the crashreporter clients +DisableStlWrapping() + +include('/toolkit/crashreporter/crashreporter.mozbuild') + +if CONFIG['CC_TYPE'] == 'clang-cl': + AllowCompilerWarnings() # workaround for bug 1090497 diff --git a/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc new file mode 100644 index 0000000000..839287bdba --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.cc @@ -0,0 +1,56 @@ +// 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.cc: Manipulates pathnames into their component parts. +// +// See pathname_stripper.h for documentation. +// +// Author: Mark Mentovai + +#include "processor/pathname_stripper.h" + +namespace google_breakpad { + +// static +string PathnameStripper::File(const string &path) { + string::size_type slash = path.rfind('/'); + string::size_type backslash = path.rfind('\\'); + + string::size_type file_start = 0; + if (slash != string::npos && + (backslash == string::npos || slash > backslash)) { + file_start = slash + 1; + } else if (backslash != string::npos) { + file_start = backslash + 1; + } + + return path.substr(file_start); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.h b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.h new file mode 100644 index 0000000000..423ca0d05a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper.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 + +#include "common/using_std_string.h" + +namespace google_breakpad { + +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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper_unittest.cc new file mode 100644 index 0000000000..1bff4cb017 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/pathname_stripper_unittest.cc @@ -0,0 +1,87 @@ +// 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 + +#include "processor/pathname_stripper.h" +#include "processor/logging.h" + +#define ASSERT_TRUE(condition) \ + if (!(condition)) { \ + fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \ + return false; \ + } + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) + +namespace { + +using google_breakpad::PathnameStripper; + +static bool RunTests() { + ASSERT_EQ(PathnameStripper::File("/dir/file"), "file"); + ASSERT_EQ(PathnameStripper::File("\\dir\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("/dir\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("\\dir/file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir/file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir/\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir\\/file"), "file"); + ASSERT_EQ(PathnameStripper::File("file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir/"), ""); + ASSERT_EQ(PathnameStripper::File("dir\\"), ""); + ASSERT_EQ(PathnameStripper::File("dir/dir/"), ""); + ASSERT_EQ(PathnameStripper::File("dir\\dir\\"), ""); + ASSERT_EQ(PathnameStripper::File("dir1/dir2/file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir1\\dir2\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir1/dir2\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir1\\dir2/file"), "file"); + ASSERT_EQ(PathnameStripper::File(""), ""); + ASSERT_EQ(PathnameStripper::File("1"), "1"); + ASSERT_EQ(PathnameStripper::File("1/2"), "2"); + ASSERT_EQ(PathnameStripper::File("1\\2"), "2"); + ASSERT_EQ(PathnameStripper::File("/1/2"), "2"); + ASSERT_EQ(PathnameStripper::File("\\1\\2"), "2"); + ASSERT_EQ(PathnameStripper::File("dir//file"), "file"); + ASSERT_EQ(PathnameStripper::File("dir\\\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("/dir//file"), "file"); + ASSERT_EQ(PathnameStripper::File("\\dir\\\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("c:\\dir\\file"), "file"); + ASSERT_EQ(PathnameStripper::File("c:\\dir\\file.ext"), "file.ext"); + + return true; +} + +} // namespace + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator-inl.h new file mode 100644 index 0000000000..d7dbeac205 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator-inl.h @@ -0,0 +1,363 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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 "processor/postfix_evaluator.h" + +#include + +#include + +#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 *stack) : stack_(stack) {} + ~AutoStackClearer() { stack_->clear(); } + + private: + vector *stack_; +}; + + +template +bool PostfixEvaluator::EvaluateToken( + const string &token, + const string &expression, + DictionaryValidityType *assigned) { + // 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, + BINARY_OP_ALIGN + }; + + 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; + else if (token == "@") + operation = BINARY_OP_ALIGN; + + if (operation != BINARY_OP_NONE) { + // Get the operands. + ValueType operand1 = ValueType(); + ValueType operand2 = ValueType(); + 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_ALIGN: + result = + operand1 & (static_cast(-1) ^ (operand2 - 1)); + 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(INFO) << "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); + } + return true; +} + +template +bool PostfixEvaluator::EvaluateInternal( + const string &expression, + DictionaryValidityType *assigned) { + // Tokenize, splitting on whitespace. + istringstream stream(expression); + string token; + while (stream >> token) { + // Normally, tokens are whitespace-separated, but occasionally, the + // assignment operator is smashed up against the next token, i.e. + // $T0 $ebp 128 + =$eip $T0 4 + ^ =$ebp $T0 ^ = + // This has been observed in program strings produced by MSVS 2010 in LTO + // mode. + if (token.size() > 1 && token[0] == '=') { + if (!EvaluateToken("=", expression, assigned)) { + return false; + } + + if (!EvaluateToken(token.substr(1), expression, assigned)) { + return false; + } + } else if (!EvaluateToken(token, expression, assigned)) { + return false; + } + } + + return true; +} + +template +bool PostfixEvaluator::Evaluate(const string &expression, + DictionaryValidityType *assigned) { + // Ensure that the stack is cleared before returning. + AutoStackClearer clearer(&stack_); + + if (!EvaluateInternal(expression, assigned)) + return false; + + // 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. + if (stack_.empty()) + return true; + + BPLOG(ERROR) << "Incomplete execution: " << expression; + return false; +} + +template +bool PostfixEvaluator::EvaluateForValue(const string &expression, + ValueType *result) { + // Ensure that the stack is cleared before returning. + AutoStackClearer clearer(&stack_); + + if (!EvaluateInternal(expression, NULL)) + return false; + + // A successful execution should leave exactly one value on the stack. + if (stack_.size() != 1) { + BPLOG(ERROR) << "Expression yielded bad number of results: " + << "'" << expression << "'"; + return false; + } + + return PopValue(result); +} + +template +typename PostfixEvaluator::PopResult +PostfixEvaluator::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. Literals may have leading + // '-' sign, and the entire remaining string must be parseable as + // ValueType. If this isn't possible, it can't be a literal, so treat it + // as an identifier instead. + // + // Some versions of the libstdc++, the GNU standard C++ library, have + // stream extractors for unsigned integer values that permit a leading + // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we + // handle it explicitly here. + istringstream token_stream(token); + ValueType literal = ValueType(); + bool negative; + if (token_stream.peek() == '-') { + negative = true; + token_stream.get(); + } else { + negative = false; + } + if (token_stream >> literal && token_stream.peek() == EOF) { + if (value) { + *value = literal; + } + if (negative) + *value = -*value; + return POP_RESULT_VALUE; + } else { + if (identifier) { + *identifier = token; + } + return POP_RESULT_IDENTIFIER; + } +} + + +template +bool PostfixEvaluator::PopValue(ValueType *value) { + ValueType literal = ValueType(); + 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(INFO) << "Identifier " << token << " not in dictionary"; + return false; + } + + *value = iterator->second; + } + + return true; +} + + +template +bool PostfixEvaluator::PopValues(ValueType *value1, + ValueType *value2) { + return PopValue(value2) && PopValue(value1); +} + + +template +void PostfixEvaluator::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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator.h b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator.h new file mode 100644 index 0000000000..94b66190d5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator.h @@ -0,0 +1,179 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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), +// % (modulus of division), and @ (data alignment). The alignment operator (@) +// accepts a value and an alignment size, and produces a result that is a +// multiple of the alignment size by truncating the input value. +// 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 +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::map; +using std::vector; + +class MemoryRegion; + +template +class PostfixEvaluator { + public: + typedef map DictionaryType; + typedef map 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, const MemoryRegion *memory) + : dictionary_(dictionary), memory_(memory), stack_() {} + + // Evaluate the expression, starting with an empty stack. The results of + // execution will be stored in one (or more) variables in the dictionary. + // Returns false if any failures occur 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); + + // Like Evaluate, but provides the value left on the stack to the + // caller. If evaluation succeeds and leaves exactly one value on + // the stack, pop that value, store it in *result, and return true. + // Otherwise, return false. + bool EvaluateForValue(const string &expression, ValueType *result); + + 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); + + // Evaluate expression, updating *assigned if it is non-zero. Return + // true if evaluation completes successfully. Do not clear the stack + // upon successful evaluation. + bool EvaluateInternal(const string &expression, + DictionaryValidityType *assigned); + + bool EvaluateToken(const string &token, + const string &expression, + DictionaryValidityType *assigned); + + // 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. + const 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 stack_; +}; + +} // namespace google_breakpad + + +#endif // PROCESSOR_POSTFIX_EVALUATOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator_unittest.cc new file mode 100644 index 0000000000..f118982849 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/postfix_evaluator_unittest.cc @@ -0,0 +1,403 @@ +// Copyright (c) 2010 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_unittest.cc: Unit tests for PostfixEvaluator. +// +// Author: Mark Mentovai + +#include +#include + +#include +#include + +#include "processor/postfix_evaluator-inl.h" + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/memory_region.h" +#include "processor/logging.h" + + +namespace { + + +using std::map; +using google_breakpad::MemoryRegion; +using google_breakpad::PostfixEvaluator; + + +// FakeMemoryRegion is used to test PostfixEvaluator's dereference (^) +// operator. The result of dereferencing a value is one greater than +// the value. +class FakeMemoryRegion : public MemoryRegion { + public: + virtual uint64_t GetBase() const { return 0; } + virtual uint32_t GetSize() const { return 0; } + virtual bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + *value = address + 1; + return true; + } + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + *value = address + 1; + return true; + } + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + *value = address + 1; + return true; + } + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + *value = address + 1; + return true; + } + virtual void Print() const { + assert(false); + } +}; + + +struct EvaluateTest { + // Expression passed to PostfixEvaluator::Evaluate. + const string expression; + + // True if the expression is expected to be evaluable, false if evaluation + // is expected to fail. + bool evaluable; +}; + + +struct EvaluateTestSet { + // The dictionary used for all tests in the set. + PostfixEvaluator::DictionaryType *dictionary; + + // The list of tests. + const EvaluateTest *evaluate_tests; + + // The number of tests. + unsigned int evaluate_test_count; + + // Identifiers and their expected values upon completion of the Evaluate + // tests in the set. + map *validate_data; +}; + + +struct EvaluateForValueTest { + // Expression passed to PostfixEvaluator::Evaluate. + const string expression; + + // True if the expression is expected to be evaluable, false if evaluation + // is expected to fail. + bool evaluable; + + // If evaluable, the value we expect it to yield. + unsigned int value; +}; + +static bool RunTests() { + // The first test set checks the basic operations and failure modes. + PostfixEvaluator::DictionaryType dictionary_0; + const EvaluateTest evaluate_tests_0[] = { + { "$rAdd 2 2 + =", true }, // $rAdd = 2 + 2 = 4 + { "$rAdd $rAdd 2 + =", true }, // $rAdd = $rAdd + 2 = 6 + { "$rAdd 2 $rAdd + =", true }, // $rAdd = 2 + $rAdd = 8 + { "99", false }, // put some junk on the stack... + { "$rAdd2 2 2 + =", true }, // ...and make sure things still work + { "$rAdd2\t2\n2 + =", true }, // same but with different whitespace + { "$rAdd2 2 2 + = ", true }, // trailing whitespace + { " $rAdd2 2 2 + =", true }, // leading whitespace + { "$rAdd2 2 2 + =", true }, // extra whitespace + { "$T0 2 = +", false }, // too few operands for add + { "2 + =", false }, // too few operands for add + { "2 +", false }, // too few operands for add + { "+", false }, // too few operands for add + { "^", false }, // too few operands for dereference + { "=", false }, // too few operands for assignment + { "2 =", false }, // too few operands for assignment + { "2 2 + =", false }, // too few operands for assignment + { "2 2 =", false }, // can't assign into a literal + { "k 2 =", false }, // can't assign into a constant + { "2", false }, // leftover data on stack + { "2 2 +", false }, // leftover data on stack + { "$rAdd", false }, // leftover data on stack + { "0 $T1 0 0 + =", false }, // leftover data on stack + { "$T2 $T2 2 + =", false }, // can't operate on an undefined value + { "$rMul 9 6 * =", true }, // $rMul = 9 * 6 = 54 + { "$rSub 9 6 - =", true }, // $rSub = 9 - 6 = 3 + { "$rDivQ 9 6 / =", true }, // $rDivQ = 9 / 6 = 1 + { "$rDivM 9 6 % =", true }, // $rDivM = 9 % 6 = 3 + { "$rDeref 9 ^ =", true }, // $rDeref = ^9 = 10 (FakeMemoryRegion) + { "$rAlign 36 8 @ =", true }, // $rAlign = 36 @ 8 + { "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization + }; + map validate_data_0; + validate_data_0["$rAdd"] = 8; + validate_data_0["$rAdd2"] = 4; + validate_data_0["$rSub"] = 3; + validate_data_0["$rMul"] = 54; + validate_data_0["$rDivQ"] = 1; + validate_data_0["$rDivM"] = 3; + validate_data_0["$rDeref"] = 10; + validate_data_0["$rAlign"] = 32; + validate_data_0["$rAdd3"] = 4; + validate_data_0["$rMul2"] = 54; + + // The second test set simulates a couple of MSVC program strings. + // The data is fudged a little bit because the tests use FakeMemoryRegion + // instead of a real stack snapshot, but the program strings are real and + // the implementation doesn't know or care that the data is not real. + PostfixEvaluator::DictionaryType dictionary_1; + dictionary_1["$ebp"] = 0xbfff0010; + dictionary_1["$eip"] = 0x10000000; + dictionary_1["$esp"] = 0xbfff0000; + dictionary_1[".cbSavedRegs"] = 4; + dictionary_1[".cbParams"] = 4; + dictionary_1[".raSearchStart"] = 0xbfff0020; + const EvaluateTest evaluate_tests_1[] = { + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true }, + // Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015, + // $ebp = 0xbfff0011, $esp = 0xbfff0018, + // $L = 0xbfff000c, $P = 0xbfff001c + { "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = " + "$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =", + true }, + // Intermediate state: $T0 = 0xbfff0011, $eip = 0xbfff0016, + // $ebp = 0xbfff0012, $esp = 0xbfff0019, + // $L = 0xbfff000d, $P = 0xbfff001d, + // $ebx = 0xbffefff6 + { "$T0 $ebp = $T2 $esp = $T1 .raSearchStart = $eip $T1 ^ = $ebp $T0 = " + "$esp $T1 4 + = $L $T0 .cbSavedRegs - = $P $T1 4 + .cbParams + = " + "$ebx $T0 28 - ^ =", + true } + }; + map validate_data_1; + validate_data_1["$T0"] = 0xbfff0012; + validate_data_1["$T1"] = 0xbfff0020; + validate_data_1["$T2"] = 0xbfff0019; + validate_data_1["$eip"] = 0xbfff0021; + validate_data_1["$ebp"] = 0xbfff0012; + validate_data_1["$esp"] = 0xbfff0024; + validate_data_1["$L"] = 0xbfff000e; + validate_data_1["$P"] = 0xbfff0028; + validate_data_1["$ebx"] = 0xbffefff7; + validate_data_1[".cbSavedRegs"] = 4; + validate_data_1[".cbParams"] = 4; + + EvaluateTestSet evaluate_test_sets[] = { + { &dictionary_0, evaluate_tests_0, + sizeof(evaluate_tests_0) / sizeof(EvaluateTest), &validate_data_0 }, + { &dictionary_1, evaluate_tests_1, + sizeof(evaluate_tests_1) / sizeof(EvaluateTest), &validate_data_1 }, + }; + + unsigned int evaluate_test_set_count = sizeof(evaluate_test_sets) / + sizeof(EvaluateTestSet); + + FakeMemoryRegion fake_memory; + PostfixEvaluator postfix_evaluator = + PostfixEvaluator(NULL, &fake_memory); + + for (unsigned int evaluate_test_set_index = 0; + evaluate_test_set_index < evaluate_test_set_count; + ++evaluate_test_set_index) { + EvaluateTestSet *evaluate_test_set = + &evaluate_test_sets[evaluate_test_set_index]; + const EvaluateTest *evaluate_tests = evaluate_test_set->evaluate_tests; + unsigned int evaluate_test_count = evaluate_test_set->evaluate_test_count; + + // The same dictionary will be used for each test in the set. Earlier + // tests can affect the state of the dictionary for later tests. + postfix_evaluator.set_dictionary(evaluate_test_set->dictionary); + + // Use a new validity dictionary for each test set. + PostfixEvaluator::DictionaryValidityType assigned; + + for (unsigned int evaluate_test_index = 0; + evaluate_test_index < evaluate_test_count; + ++evaluate_test_index) { + const EvaluateTest *evaluate_test = &evaluate_tests[evaluate_test_index]; + + // Do the test. + bool result = postfix_evaluator.Evaluate(evaluate_test->expression, + &assigned); + if (result != evaluate_test->evaluable) { + fprintf(stderr, "FAIL: evaluate set %d/%d, test %d/%d, " + "expression \"%s\", expected %s, observed %s\n", + evaluate_test_set_index, evaluate_test_set_count, + evaluate_test_index, evaluate_test_count, + evaluate_test->expression.c_str(), + evaluate_test->evaluable ? "evaluable" : "not evaluable", + result ? "evaluted" : "not evaluated"); + return false; + } + } + + // Validate the results. + for (map::const_iterator validate_iterator = + evaluate_test_set->validate_data->begin(); + validate_iterator != evaluate_test_set->validate_data->end(); + ++validate_iterator) { + const string identifier = validate_iterator->first; + unsigned int expected_value = validate_iterator->second; + + map::const_iterator dictionary_iterator = + evaluate_test_set->dictionary->find(identifier); + + // The identifier must exist in the dictionary. + if (dictionary_iterator == evaluate_test_set->dictionary->end()) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate identifier \"%s\", " + "expected %d, observed not found\n", + evaluate_test_set_index, evaluate_test_set_count, + identifier.c_str(), expected_value); + return false; + } + + // The value in the dictionary must be the same as the expected value. + unsigned int observed_value = dictionary_iterator->second; + if (expected_value != observed_value) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate identifier \"%s\", " + "expected %d, observed %d\n", + evaluate_test_set_index, evaluate_test_set_count, + identifier.c_str(), expected_value, observed_value); + return false; + } + + // The value must be set in the "assigned" dictionary if it was a + // variable. It must not have been assigned if it was a constant. + bool expected_assigned = identifier[0] == '$'; + bool observed_assigned = false; + PostfixEvaluator::DictionaryValidityType::const_iterator + iterator_assigned = assigned.find(identifier); + if (iterator_assigned != assigned.end()) { + observed_assigned = iterator_assigned->second; + } + if (expected_assigned != observed_assigned) { + fprintf(stderr, "FAIL: evaluate test set %d/%d, " + "validate assignment of \"%s\", " + "expected %d, observed %d\n", + evaluate_test_set_index, evaluate_test_set_count, + identifier.c_str(), expected_assigned, observed_assigned); + return false; + } + } + } + + // EvaluateForValue tests. + PostfixEvaluator::DictionaryType dictionary_2; + dictionary_2["$ebp"] = 0xbfff0010; + dictionary_2["$eip"] = 0x10000000; + dictionary_2["$esp"] = 0xbfff0000; + dictionary_2[".cbSavedRegs"] = 4; + dictionary_2[".cbParams"] = 4; + dictionary_2[".raSearchStart"] = 0xbfff0020; + const EvaluateForValueTest evaluate_for_value_tests_2[] = { + { "28907223", true, 28907223 }, // simple constant + { "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic + { "-870245 8769343 +", true, 7899098 }, // negative constants + { "$ebp $esp - $eip +", true, 0x10000010 }, // variable references + { "18929794 34015074", false, 0 }, // too many values + { "$ebp $ebp 4 - =", false, 0 }, // too few values + { "$new $eip = $new", true, 0x10000000 }, // make new variable + { "$new 4 +", true, 0x10000004 }, // see prior assignments + { ".cfa 42 = 10", false, 0 } // can't set constants + }; + const int evaluate_for_value_tests_2_size + = (sizeof (evaluate_for_value_tests_2) + / sizeof (evaluate_for_value_tests_2[0])); + map validate_data_2; + validate_data_2["$eip"] = 0x10000000; + validate_data_2["$ebp"] = 0xbfff000c; + validate_data_2["$esp"] = 0xbfff0000; + validate_data_2["$new"] = 0x10000000; + validate_data_2[".cbSavedRegs"] = 4; + validate_data_2[".cbParams"] = 4; + validate_data_2[".raSearchStart"] = 0xbfff0020; + + postfix_evaluator.set_dictionary(&dictionary_2); + for (int i = 0; i < evaluate_for_value_tests_2_size; i++) { + const EvaluateForValueTest *test = &evaluate_for_value_tests_2[i]; + unsigned int result; + if (postfix_evaluator.EvaluateForValue(test->expression, &result) + != test->evaluable) { + fprintf(stderr, "FAIL: evaluate for value test %d, " + "expected evaluation to %s, but it %s\n", + i, test->evaluable ? "succeed" : "fail", + test->evaluable ? "failed" : "succeeded"); + return false; + } + if (test->evaluable && result != test->value) { + fprintf(stderr, "FAIL: evaluate for value test %d, " + "expected value to be 0x%x, but it was 0x%x\n", + i, test->value, result); + return false; + } + } + + for (map::iterator v = validate_data_2.begin(); + v != validate_data_2.end(); v++) { + map::iterator a = dictionary_2.find(v->first); + if (a == dictionary_2.end()) { + fprintf(stderr, "FAIL: evaluate for value dictionary check: " + "expected dict[\"%s\"] to be 0x%x, but it was unset\n", + v->first.c_str(), v->second); + return false; + } else if (a->second != v->second) { + fprintf(stderr, "FAIL: evaluate for value dictionary check: " + "expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n", + v->first.c_str(), v->second, a->second); + return false; + } + dictionary_2.erase(a); + } + + map::iterator remaining = dictionary_2.begin(); + if (remaining != dictionary_2.end()) { + fprintf(stderr, "FAIL: evaluation of test expressions put unexpected " + "values in dictionary:\n"); + for (; remaining != dictionary_2.end(); remaining++) + fprintf(stderr, " dict[\"%s\"] == 0x%x\n", + remaining->first.c_str(), remaining->second); + return false; + } + + return true; +} + + +} // namespace + + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux.cc b/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux.cc new file mode 100644 index 0000000000..a6f8953bc3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "google_breakpad/processor/proc_maps_linux.h" + +#include +#include +#include + +#include "common/using_std_string.h" +#include "processor/logging.h" + +#if defined(ANDROID) && !defined(__LP64__) +// In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an +// unsigned long int, which is incompatible with Bionic's stdint.h +// defining uintptr_t as an unsigned int: +// https://code.google.com/p/android/issues/detail?id=57218 +#undef SCNxPTR +#define SCNxPTR "x" +#endif + +namespace google_breakpad { + +bool ParseProcMaps(const string& input, + std::vector* regions_out) { + std::vector regions; + + // This isn't async safe nor terribly efficient, but it doesn't need to be at + // this point in time. + + // Split the string by newlines. + std::vector lines; + string l = ""; + for (size_t i = 0; i < input.size(); i++) { + if (input[i] != '\n' && input[i] != '\r') { + l.push_back(input[i]); + } else if (l.size() > 0) { + lines.push_back(l); + l.clear(); + } + } + if (l.size() > 0) { + BPLOG(ERROR) << "Input doesn't end in newline"; + return false; + } + + for (size_t i = 0; i < lines.size(); ++i) { + MappedMemoryRegion region; + const char* line = lines[i].c_str(); + char permissions[5] = {'\0'}; // Ensure NUL-terminated string. + int path_index = 0; + + // Sample format from man 5 proc: + // + // address perms offset dev inode pathname + // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm + // + // The final %n term captures the offset in the input string, which is used + // to determine the path name. It *does not* increment the return value. + // Refer to man 3 sscanf for details. + if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4c %" SCNx64" %hhx:%hhx %" + SCNd64 " %n", ®ion.start, ®ion.end, permissions, + ®ion.offset, ®ion.major_device, ®ion.minor_device, + ®ion.inode, &path_index) < 7) { + BPLOG(ERROR) << "sscanf failed for line: " << line; + return false; + } + + region.permissions = 0; + + if (permissions[0] == 'r') + region.permissions |= MappedMemoryRegion::READ; + else if (permissions[0] != '-') + return false; + + if (permissions[1] == 'w') + region.permissions |= MappedMemoryRegion::WRITE; + else if (permissions[1] != '-') + return false; + + if (permissions[2] == 'x') + region.permissions |= MappedMemoryRegion::EXECUTE; + else if (permissions[2] != '-') + return false; + + if (permissions[3] == 'p') + region.permissions |= MappedMemoryRegion::PRIVATE; + else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory. + return false; + + // Pushing then assigning saves us a string copy. + regions.push_back(region); + regions.back().path.assign(line + path_index); + regions.back().line.assign(line); + } + + regions_out->swap(regions); + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux_unittest.cc new file mode 100644 index 0000000000..466f23455e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/proc_maps_linux_unittest.cc @@ -0,0 +1,251 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/proc_maps_linux.h" + +namespace { + +TEST(ProcMapsTest, Empty) { + std::vector regions; + EXPECT_TRUE(ParseProcMaps("", ®ions)); + EXPECT_EQ(0u, regions.size()); +} + +TEST(ProcMapsTest, NoSpaces) { + static const char kNoSpaces[] = + "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kNoSpaces, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0x00400000u, regions[0].start); + EXPECT_EQ(0x0040b000u, regions[0].end); + EXPECT_EQ(0x00002200u, regions[0].offset); + EXPECT_EQ("/bin/cat", regions[0].path); +} + +TEST(ProcMapsTest, Spaces) { + static const char kSpaces[] = + "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kSpaces, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0x00400000u, regions[0].start); + EXPECT_EQ(0x0040b000u, regions[0].end); + EXPECT_EQ(0x00002200u, regions[0].offset); + EXPECT_EQ("/bin/space cat", regions[0].path); +} + +TEST(ProcMapsTest, NoNewline) { + static const char kNoSpaces[] = + "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat"; + + std::vector regions; + ASSERT_FALSE(ParseProcMaps(kNoSpaces, ®ions)); +} + +TEST(ProcMapsTest, NoPath) { + static const char kNoPath[] = + "00400000-0040b000 rw-p 00000000 00:00 0 \n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kNoPath, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0x00400000u, regions[0].start); + EXPECT_EQ(0x0040b000u, regions[0].end); + EXPECT_EQ(0x00000000u, regions[0].offset); + EXPECT_EQ("", regions[0].path); +} + +TEST(ProcMapsTest, Heap) { + static const char kHeap[] = + "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kHeap, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0x022ac000u, regions[0].start); + EXPECT_EQ(0x022cd000u, regions[0].end); + EXPECT_EQ(0x00000000u, regions[0].offset); + EXPECT_EQ("[heap]", regions[0].path); +} + +#if defined(ARCH_CPU_32_BITS) +TEST(ProcMapsTest, Stack32) { + static const char kStack[] = + "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0xbeb04000u, regions[0].start); + EXPECT_EQ(0xbeb25000u, regions[0].end); + EXPECT_EQ(0x00000000u, regions[0].offset); + EXPECT_EQ("[stack]", regions[0].path); +} +#elif defined(ARCH_CPU_64_BITS) +TEST(ProcMapsTest, Stack64) { + static const char kStack[] = + "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); + ASSERT_EQ(1u, regions.size()); + + EXPECT_EQ(0x7fff69c5b000u, regions[0].start); + EXPECT_EQ(0x7fff69c7d000u, regions[0].end); + EXPECT_EQ(0x00000000u, regions[0].offset); + EXPECT_EQ("[stack]", regions[0].path); +} +#endif + +TEST(ProcMapsTest, Multiple) { + static const char kMultiple[] = + "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n" + "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n" + "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n"; + + std::vector regions; + ASSERT_TRUE(ParseProcMaps(kMultiple, ®ions)); + ASSERT_EQ(3u, regions.size()); + + EXPECT_EQ(0x00400000u, regions[0].start); + EXPECT_EQ(0x0040b000u, regions[0].end); + EXPECT_EQ(0x00000000u, regions[0].offset); + EXPECT_EQ("/bin/cat", regions[0].path); + + EXPECT_EQ(0x0060a000u, regions[1].start); + EXPECT_EQ(0x0060b000u, regions[1].end); + EXPECT_EQ(0x0000a000u, regions[1].offset); + EXPECT_EQ("/bin/cat", regions[1].path); + + EXPECT_EQ(0x0060b000u, regions[2].start); + EXPECT_EQ(0x0060c000u, regions[2].end); + EXPECT_EQ(0x0000b000u, regions[2].offset); + EXPECT_EQ("/bin/cat", regions[2].path); +} + +TEST(ProcMapsTest, Permissions) { + static struct { + const char* input; + uint8_t permissions; + } kTestCases[] = { + {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0}, + {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0}, + {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::READ}, + {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::WRITE}, + {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::EXECUTE}, + {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::READ + | google_breakpad::MappedMemoryRegion::WRITE + | google_breakpad::MappedMemoryRegion::EXECUTE}, + {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::PRIVATE}, + {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::READ + | google_breakpad::MappedMemoryRegion::PRIVATE}, + {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::WRITE + | google_breakpad::MappedMemoryRegion::PRIVATE}, + {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::EXECUTE + | google_breakpad::MappedMemoryRegion::PRIVATE}, + {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", + google_breakpad::MappedMemoryRegion::READ + | google_breakpad::MappedMemoryRegion::WRITE + | google_breakpad::MappedMemoryRegion::EXECUTE + | google_breakpad::MappedMemoryRegion::PRIVATE}, + }; + + for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) { + std::vector regions; + EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, ®ions)); + EXPECT_EQ(1u, regions.size()); + if (regions.empty()) + continue; + EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions); + } +} + +TEST(ProcMapsTest, MissingFields) { + static const char* kTestCases[] = { + "00400000\n", // Missing end + beyond. + "00400000-0040b000\n", // Missing perms + beyond. + "00400000-0040b000 r-xp\n", // Missing offset + beyond. + "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond. + "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond. + "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms. + "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset. + "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode. + "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end. + "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start. + "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device. + }; + + for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) { + std::vector regions; + EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); + } +} + +TEST(ProcMapsTest, InvalidInput) { + static const char* kTestCases[] = { + "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", + "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n", + "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n", + "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n", + "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n", + "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n", + }; + + for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) { + std::vector regions; + EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); + } +} + +TEST(ProcMapsTest, ParseProcMapsEmptyString) { + std::vector regions; + EXPECT_TRUE(ParseProcMaps("", ®ions)); + EXPECT_EQ(0ULL, regions.size()); +} + +// Testing a couple of remotely possible weird things in the input: +// - Line ending with \r\n or \n\r. +// - File name contains quotes. +// - File name has whitespaces. +TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) { + std::vector regions; + const string kContents = + "00400000-0040b000 r-xp 00000000 fc:00 2106562 " + " /bin/cat\r\n" + "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 " + " /lib/x86_64-linux-gnu/libc-2.15.so\n\r" + "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 " + " /lib/x86_64-linux-gnu/ld-2.15.so\n" + "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 " + " \"vd so\"\n" + "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 " + " [vsys call]\n"; + EXPECT_TRUE(ParseProcMaps(kContents, ®ions)); + EXPECT_EQ(5ULL, regions.size()); + EXPECT_EQ("/bin/cat", regions[0].path); + EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path); + EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path); + EXPECT_EQ("\"vd so\"", regions[3].path); + EXPECT_EQ("[vsys call]", regions[4].path); +} + +} // namespace diff --git a/toolkit/crashreporter/google-breakpad/src/processor/process_state.cc b/toolkit/crashreporter/google-breakpad/src/processor/process_state.cc new file mode 100644 index 0000000000..43c4a4b8b0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/process_state.cc @@ -0,0 +1,71 @@ +// 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.cc: A snapshot of a process, in a fully-digested state. +// +// See process_state.h for documentation. +// +// Author: Mark Mentovai + +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_modules.h" + +namespace google_breakpad { + +ProcessState::~ProcessState() { + Clear(); +} + +void ProcessState::Clear() { + time_date_stamp_ = 0; + process_create_time_ = 0; + crashed_ = false; + crash_reason_.clear(); + crash_address_ = 0; + assertion_.clear(); + requesting_thread_ = -1; + for (vector::const_iterator iterator = threads_.begin(); + iterator != threads_.end(); + ++iterator) { + delete *iterator; + } + threads_.clear(); + system_info_.Clear(); + // modules_without_symbols_ and modules_with_corrupt_symbols_ DO NOT own + // the underlying CodeModule pointers. Just clear the vectors. + modules_without_symbols_.clear(); + modules_with_corrupt_symbols_.clear(); + delete modules_; + modules_ = NULL; + delete unloaded_modules_; + unloaded_modules_ = NULL; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/processor.gyp b/toolkit/crashreporter/google-breakpad/src/processor/processor.gyp new file mode 100644 index 0000000000..93896c0e98 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/processor.gyp @@ -0,0 +1,187 @@ +# Copyright 2014 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. + +{ + 'includes': [ + '../build/common.gypi', + 'processor_tools.gypi', + ], + 'targets': [ + { + 'target_name': 'processor', + 'type': 'static_library', + 'sources': [ + 'address_map-inl.h', + 'address_map.h', + 'basic_code_module.h', + 'basic_code_modules.cc', + 'basic_code_modules.h', + 'basic_source_line_resolver.cc', + 'basic_source_line_resolver_types.h', + 'call_stack.cc', + 'cfi_frame_info-inl.h', + 'cfi_frame_info.cc', + 'cfi_frame_info.h', + 'contained_range_map-inl.h', + 'contained_range_map.h', + 'convert_old_arm64_context.cc', + 'convert_old_arm64_context.h', + 'disassembler_x86.cc', + 'disassembler_x86.h', + 'dump_context.cc', + 'dump_object.cc', + 'exploitability.cc', + 'exploitability_linux.cc', + 'exploitability_linux.h', + 'exploitability_win.cc', + 'exploitability_win.h', + 'fast_source_line_resolver.cc', + 'fast_source_line_resolver_types.h', + 'linked_ptr.h', + 'logging.cc', + 'logging.h', + 'map_serializers-inl.h', + 'map_serializers.h', + 'microdump_processor.cc', + 'minidump.cc', + 'minidump_processor.cc', + 'module_comparer.cc', + 'module_comparer.h', + 'module_factory.h', + 'module_serializer.cc', + 'module_serializer.h', + 'pathname_stripper.cc', + 'pathname_stripper.h', + 'postfix_evaluator-inl.h', + 'postfix_evaluator.h', + 'proc_maps_linux.cc', + 'process_state.cc', + 'range_map-inl.h', + 'range_map.h', + 'simple_serializer-inl.h', + 'simple_serializer.h', + 'simple_symbol_supplier.cc', + 'simple_symbol_supplier.h', + 'source_line_resolver_base.cc', + 'source_line_resolver_base_types.h', + 'stack_frame_cpu.cc', + 'stack_frame_symbolizer.cc', + 'stackwalk_common.cc', + 'stackwalk_common.h', + 'stackwalker.cc', + 'stackwalker_address_list.cc', + 'stackwalker_address_list.h', + 'stackwalker_amd64.cc', + 'stackwalker_amd64.h', + 'stackwalker_arm.cc', + 'stackwalker_arm.h', + 'stackwalker_arm64.cc', + 'stackwalker_arm64.h', + 'stackwalker_mips.cc', + 'stackwalker_mips.h', + 'stackwalker_ppc.cc', + 'stackwalker_ppc.h', + 'stackwalker_ppc64.cc', + 'stackwalker_ppc64.h', + 'stackwalker_selftest.cc', + 'stackwalker_sparc.cc', + 'stackwalker_sparc.h', + 'stackwalker_x86.cc', + 'stackwalker_x86.h', + 'static_address_map-inl.h', + 'static_address_map.h', + 'static_contained_range_map-inl.h', + 'static_contained_range_map.h', + 'static_map-inl.h', + 'static_map.h', + 'static_map_iterator-inl.h', + 'static_map_iterator.h', + 'static_range_map-inl.h', + 'static_range_map.h', + 'symbolic_constants_win.cc', + 'symbolic_constants_win.h', + 'synth_minidump.cc', + 'synth_minidump.h', + 'tokenize.cc', + 'tokenize.h', + 'windows_frame_info.h', + ], + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../common/common.gyp:common', + '../third_party/libdisasm/libdisasm.gyp:libdisasm', + ], + }, + { + 'target_name': 'processor_unittests', + 'type': 'executable', + 'sources': [ + 'address_map_unittest.cc', + 'basic_source_line_resolver_unittest.cc', + 'cfi_frame_info_unittest.cc', + 'contained_range_map_unittest.cc', + 'disassembler_x86_unittest.cc', + 'exploitability_unittest.cc', + 'fast_source_line_resolver_unittest.cc', + 'map_serializers_unittest.cc', + 'microdump_processor_unittest.cc', + 'minidump_processor_unittest.cc', + 'minidump_unittest.cc', + 'pathname_stripper_unittest.cc', + 'postfix_evaluator_unittest.cc', + 'range_map_truncate_lower_unittest.cc', + 'range_map_truncate_upper_unittest.cc', + 'range_map_unittest.cc', + 'stackwalker_address_list_unittest.cc', + 'stackwalker_amd64_unittest.cc', + 'stackwalker_arm64_unittest.cc', + 'stackwalker_arm_unittest.cc', + 'stackwalker_mips_unittest.cc', + 'stackwalker_mips64_unittest.cc', + 'stackwalker_unittest_utils.h', + 'stackwalker_x86_unittest.cc', + 'static_address_map_unittest.cc', + 'static_contained_range_map_unittest.cc', + 'static_map_unittest.cc', + 'static_range_map_unittest.cc', + 'synth_minidump_unittest.cc', + 'synth_minidump_unittest_data.h', + ], + 'include_dirs': [ + '..', + ], + 'dependencies': [ + 'processor', + '../build/testing.gyp:gmock', + '../build/testing.gyp:gtest', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/processor_tools.gypi b/toolkit/crashreporter/google-breakpad/src/processor/processor_tools.gypi new file mode 100644 index 0000000000..ecb450d602 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/processor_tools.gypi @@ -0,0 +1,57 @@ +# Copyright 2014 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. + +{ + 'target_defaults': { + 'include_dirs': [ + '..', + ], + }, + 'targets': [ + { + 'target_name': 'minidump_dump', + 'type': 'executable', + 'sources': [ + 'minidump_dump.cc', + ], + 'dependencies': [ + 'processor', + ], + }, + { + 'target_name': 'minidump_stackwalk', + 'type': 'executable', + 'sources': [ + 'minidump_stackwalk.cc', + ], + 'dependencies': [ + 'processor', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/proto/README b/toolkit/crashreporter/google-breakpad/src/processor/proto/README new file mode 100644 index 0000000000..f9e5a4d301 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/proto/README @@ -0,0 +1,20 @@ +If you wish to use these protobufs, you must generate their source files +using protoc from the protobuf project (https://github.com/google/protobuf). + +----- +Troubleshooting for Protobuf: + +Install: +If you are getting permission errors install, make sure you are not trying to +install from an NFS. + + +Running protoc: +protoc: error while loading shared libraries: libprotobuf.so.0: cannot open +shared object file: No such file or directory + +The issue is that Ubuntu 8.04 doesn't include /usr/local/lib in +library paths. + +To fix it for your current terminal session, just type in +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib diff --git a/toolkit/crashreporter/google-breakpad/src/processor/proto/process_state.proto b/toolkit/crashreporter/google-breakpad/src/processor/proto/process_state.proto new file mode 100644 index 0000000000..d3e02dc3f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/proto/process_state.proto @@ -0,0 +1,210 @@ +// Copyright (c) 2010, 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_proto.proto: A client proto representation of a process, +// in a fully-digested state. +// +// Derived from earlier struct and class based models of a client-side +// processed minidump found under src/google_breakpad/processor. The +// file process_state.h holds the top level representation of this model, +// supported by additional classes. We've added a proto representation +// to ease serialization and parsing for server-side storage of crash +// reports processed on the client. +// +// Author: Jess Gray + +syntax = "proto2"; + +package google_breakpad; + +// A proto representation of a process, in a fully-digested state. +// See src/google_breakpad/processor/process_state.h +message ProcessStateProto { + // Next value: 14 + + // The time-date stamp of the original minidump (time_t format) + optional int64 time_date_stamp = 1; + + // The time-date stamp when the process was created (time_t format) + optional int64 process_create_time = 13; + + message Crash { + // 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). + required string reason = 1; + + // 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. + required int64 address = 2; + } + optional Crash crash = 2; + + + // If there was an assertion that was hit, a textual representation + // of that assertion, possibly including the file and line at which + // it occurred. + optional string assertion = 3; + + // 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. + optional int32 requesting_thread = 4; + + message Thread { + // Stack for the given thread + repeated StackFrame frames = 1; + } + + // Stacks for each thread (except possibly the exception handler + // thread) at the time of the crash. + repeated Thread threads = 5; + + // The modules that were loaded into the process represented by the + // ProcessState. + repeated CodeModule modules = 6; + + // System Info: OS and CPU + + // 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. + optional string os = 7; + + // 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. + optional string os_short = 8; + + // 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. + optional string os_version = 9; + + // 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. + optional string cpu = 10; + + // 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. + optional string cpu_info = 11; + + // The number of processors in the system. Will be greater than one for + // multi-core systems. + optional int32 cpu_count = 12; + + // Leave the ability to add the raw minidump to this representation +} + + +// Represents a single frame in a stack +// See src/google_breakpad/processor/code_module.h +message StackFrame { + // Next value: 8 + + // 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. + required int64 instruction = 1; + + // The module in which the instruction resides. + optional CodeModule module = 2; + + // The function name, may be omitted if debug symbols are not available. + optional string function_name = 3; + + // The start address of the function, may be omitted if debug symbols + // are not available. + optional int64 function_base = 4; + + // The source file name, may be omitted if debug symbols are not available. + optional string source_file_name = 5; + + // The (1-based) source line number, may be omitted if debug symbols are + // not available. + optional int32 source_line = 6; + + // The start address of the source line, may be omitted if debug symbols + // are not available. + optional int64 source_line_base = 7; +} + + +// Carries information about code modules that are loaded into a process. +// See src/google_breakpad/processor/code_module.h +message CodeModule { + // Next value: 8 + + // The base address of this code module as it was loaded by the process. + optional int64 base_address = 1; + + // The size of the code module. + optional int64 size = 2; + + // The path or file name that the code module was loaded from. + optional string code_file = 3; + + // 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. + optional string code_identifier = 4; + + // 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. + optional string debug_file = 5; + + // 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. + optional string debug_identifier = 6; + + // A human-readable representation of the code module's version. + optional string version = 7; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/range_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/range_map-inl.h new file mode 100644 index 0000000000..4d3b0eb96f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/range_map-inl.h @@ -0,0 +1,291 @@ +// Copyright (c) 2010 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 + +#include "processor/range_map.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + + +namespace google_breakpad { + +template +bool RangeMap::StoreRange(const AddressType &base, + const AddressType &size, + const EntryType &entry) { + return StoreRangeInternal(base, 0 /* delta */, size, entry); +} + +template +bool RangeMap::StoreRangeInternal( + const AddressType &base, const AddressType &delta, + 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) << "StoreRangeInternal failed, " + << HexString(base) << "+" << HexString(size) + << ", " << HexString(high) + << ", delta: " << HexString(delta); + 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 ends in the space used by this range. It may be + // contained within the space used by this range, or it may extend lower. + if (merge_strategy_ == MergeRangeStrategy::kTruncateLower) { + // kTruncate the range with the lower base address. + AddressType other_base = iterator_base->second.base(); + if (base < other_base) { + return StoreRangeInternal(base, delta, other_base - base, entry); + } else if (other_base < base) { + EntryType other_entry; + AddressType other_high, other_size, other_delta; + other_high = iterator_base->first; + RetrieveRange(other_high, &other_entry, &other_base, &other_delta, + &other_size); + map_.erase(iterator_base); + map_.insert( + MapValue(base - 1, Range(other_base, other_delta, other_entry))); + return StoreRangeInternal(base, delta, size, entry); + } else { + return false; + } + } else if (merge_strategy_ == MergeRangeStrategy::kTruncateUpper) { + // Truncate the lower portion of this range. + AddressType additional_delta = iterator_base->first - base + 1; + return StoreRangeInternal(base + additional_delta, + delta + additional_delta, + size - additional_delta, entry); + } else { + // The processor hits this case too frequently with common symbol files. + // This is most appropriate for a DEBUG channel, but since none exists + // now simply comment out this logging. + // AddressType other_base = iterator_base->second.base(); + // AddressType other_size = iterator_base->first - other_base + 1; + // BPLOG(INFO) << "StoreRangeInternal failed, an existing range is " + // << "overlapping with the new range: new " + // << HexString(base) << "+" << HexString(size) + // << ", existing " << HexString(other_base) << "+" + // << HexString(other_size); + return false; + } + } + + if (iterator_high != map_.end() && 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. + if (merge_strategy_ == MergeRangeStrategy::kTruncateLower) { + AddressType other_base = iterator_high->second.base(); + if (base < other_base) { + return StoreRangeInternal(base, delta, other_base - base, entry); + } else if (other_base < base) { + EntryType other_entry; + AddressType other_high, other_size, other_delta; + other_high = iterator_high->first; + RetrieveRange(other_high, &other_entry, &other_base, &other_delta, + &other_size); + map_.erase(iterator_high); + map_.insert( + MapValue(base - 1, Range(other_base, other_delta, other_entry))); + return StoreRangeInternal(base, delta, size, entry); + } else { + return false; + } + } else if (merge_strategy_ == MergeRangeStrategy::kTruncateUpper && + iterator_high->first > high) { + // Shrink the other range down. + AddressType other_high = iterator_high->first; + AddressType additional_delta = high - iterator_high->second.base() + 1; + EntryType other_entry; + AddressType other_base = AddressType(); + AddressType other_size = AddressType(); + AddressType other_delta = AddressType(); + RetrieveRange(other_high, &other_entry, &other_base, &other_delta, + &other_size); + map_.erase(iterator_high); + map_.insert(MapValue(other_high, + Range(other_base + additional_delta, + other_delta + additional_delta, other_entry))); + // Retry to store this range. + return StoreRangeInternal(base, delta, size, entry); + } else { + // The processor hits this case too frequently with common symbol files. + // This is most appropriate for a DEBUG channel, but since none exists + // now simply comment out this logging. + // + // AddressType other_base = iterator_high->second.base(); + // AddressType other_size = iterator_high->first - other_base + 1; + // BPLOG(INFO) << "StoreRangeInternal 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, delta, entry))); + return true; +} + + +template +bool RangeMap::RetrieveRange( + const AddressType &address, EntryType *entry, AddressType *entry_base, + AddressType *entry_delta, 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_delta) + *entry_delta = iterator->second.delta(); + if (entry_size) + *entry_size = iterator->first - iterator->second.base() + 1; + + return true; +} + + +template +bool RangeMap::RetrieveNearestRange( + const AddressType &address, EntryType *entry, AddressType *entry_base, + AddressType *entry_delta, 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_delta, 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->second.base(); + if (entry_delta) + *entry_delta = iterator->second.delta(); + if (entry_size) + *entry_size = iterator->first - iterator->second.base() + 1; + + return true; +} + + +template +bool RangeMap::RetrieveRangeAtIndex( + int index, EntryType *entry, AddressType *entry_base, + AddressType *entry_delta, 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->second.base(); + if (entry_delta) + *entry_delta = iterator->second.delta(); + if (entry_size) + *entry_size = iterator->first - iterator->second.base() + 1; + + return true; +} + + +template +int RangeMap::GetCount() const { + return static_cast(map_.size()); +} + + +template +void RangeMap::Clear() { + map_.clear(); +} + + +} // namespace google_breakpad + + +#endif // PROCESSOR_RANGE_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/range_map.h b/toolkit/crashreporter/google-breakpad/src/processor/range_map.h new file mode 100644 index 0000000000..33f3297349 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/range_map.h @@ -0,0 +1,171 @@ +// 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 + + +namespace google_breakpad { + +// Forward declarations (for later friend declarations of specialized template). +template class RangeMapSerializer; + +// Determines what happens when two ranges overlap. +enum class MergeRangeStrategy { + // When two ranges overlap, the new range fails to be inserted. The default + // strategy. + kExclusiveRanges, + + // The range with the lower base address will be truncated such that it's + // high address is one less than the range above it. + kTruncateLower, + + // The range with the greater high address has its range truncated such that + // its base address is one higher than the range below it. + kTruncateUpper +}; + +template +class RangeMap { + public: + RangeMap() : merge_strategy_(MergeRangeStrategy::kExclusiveRanges), map_() {} + + void SetMergeStrategy(MergeRangeStrategy strat) { merge_strategy_ = strat; } + + MergeRangeStrategy GetMergeStrategy() const { return merge_strategy_; } + + // 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. If enable_shrink_down is true and there is an overlap + // between the current range and some other range (already in the map), + // shrink down the range which ends at a higher address. + 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, entry_delta, and entry_size, if + // non-NULL, are set to the base, delta, and size of the entry's range. + // A positive entry delta (> 0) indicates that there was an overlap and the + // entry was shrunk down (original start address was increased by delta). + bool RetrieveRange(const AddressType &address, EntryType *entry, + AddressType *entry_base, AddressType *entry_delta, + 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, entry_delta, and entry_size, + // if non-NULL, are set to the base, delta, and size of the entry's range. + // A positive entry delta (> 0) indicates that there was an overlap and the + // entry was shrunk down (original start address was increased by delta). + bool RetrieveNearestRange(const AddressType &address, EntryType *entry, + AddressType *entry_base, AddressType *entry_delta, + 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, + // entry_delta, and entry_size, if non-NULL, are set to the base, delta, and + // size of the entry's range. + // A positive entry delta (> 0) indicates that there was an overlap and the + // entry was shrunk down (original start address was increased by delta). + // + // RetrieveRangeAtIndex is not optimized for speedy operation. + bool RetrieveRangeAtIndex(int index, EntryType *entry, + AddressType *entry_base, AddressType *entry_delta, + 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: + // Friend declarations. + friend class ModuleComparer; + friend class RangeMapSerializer; + + // Same a StoreRange() with the only exception that the |delta| can be + // passed in. + bool StoreRangeInternal(const AddressType &base, const AddressType &delta, + const AddressType &size, const EntryType &entry); + + class Range { + public: + Range(const AddressType &base, const AddressType &delta, + const EntryType &entry) + : base_(base), delta_(delta), entry_(entry) {} + + AddressType base() const { return base_; } + AddressType delta() const { return delta_; } + 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 delta when the range is shrunk down. + const AddressType delta_; + + // The entry corresponding to a range. + const EntryType entry_; + }; + + // Convenience types. + typedef std::map AddressToRangeMap; + typedef typename AddressToRangeMap::const_iterator MapConstIterator; + typedef typename AddressToRangeMap::value_type MapValue; + + MergeRangeStrategy merge_strategy_; + + // Maps the high address of each range to a EntryType. + AddressToRangeMap map_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_RANGE_MAP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_lower_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_lower_unittest.cc new file mode 100644 index 0000000000..a933c956f5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_lower_unittest.cc @@ -0,0 +1,346 @@ +// Copyright (c) 2019, 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 +#include + +#include "processor/range_map-inl.h" + +#include "breakpad_googletest_includes.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + +namespace { + +using google_breakpad::linked_ptr; +using google_breakpad::MergeRangeStrategy; +using google_breakpad::RangeMap; + +// A CountedObject holds an int. A global (not thread safe!) count of +// allocated CountedObjects is maintained to help test memory management. +class CountedObject { + public: + explicit CountedObject(int id) : id_(id) { ++count_; } + ~CountedObject() { --count_; } + + static int count() { return count_; } + int id() const { return id_; } + + private: + static int count_; + int id_; +}; + +int CountedObject::count_; + +typedef int AddressType; +typedef RangeMap> TestMap; + +// Same range cannot be stored wice. +TEST(RangeMapTruncateLower, SameRange) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_1)); + + // Same range cannot be stored wice. + linked_ptr object_2(new CountedObject(2)); + EXPECT_FALSE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_2)); +} + +// If a range is completely contained by another range, then the larger range +// should be truncated. +TEST(RangeMapTruncateLower, CompletelyContained) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + // Larger range is added first. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_1)); + // Smaller (contained) range is added second. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(10 /* base address */, 80 /* size */, object_2)); + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range contains the second, so the first range should have been + // shrunk to [0, 10]. Range [90, 99] should be free. + EXPECT_FALSE(range_map.RetrieveRange(90, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_FALSE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(10, retrieved_size); + // Validate the properties of the smaller range (should be untouched). + EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(80, retrieved_size); +} + +// Same as the previous test, however the larger range is added second. +TEST(RangeMapTruncateLower, CompletelyContained_LargerAddedSecond) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + // Smaller (contained) range is added first. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(10 /* base address */, 80 /* size */, object_1)); + // Larger range is added second. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_2)); + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The second range contains the first, so the second range should have been + // truncated to [0, 9]. Range [90, 99] should be free. + EXPECT_FALSE(range_map.RetrieveRange(90, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_FALSE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(10, retrieved_size); + // Validate the properties of the smaller range (should be untouched). + EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(80, retrieved_size); +} + +TEST(RangeMapTruncateLower, PartialOverlap_AtBeginning) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_1)); + + // Partial overlap at the beginning of the new range. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(90 /* base address */, 110 /* size */, object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be truncated, so 99 should address the second range. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(90, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(110, retrieved_size); + // Validate the properties of the truncated range. + EXPECT_TRUE(range_map.RetrieveRange(89, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); +} + +TEST(RangeMapTruncateLower, PartialOverlap_AtEnd) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(50 /* base address */, 50 /* size */, object_1)); + + // Partial overlap at the end of the new range. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 70 /* size */, object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The second range should be truncated so 69 addresses the first range. + EXPECT_TRUE(range_map.RetrieveRange(69, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(50, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(50, retrieved_size); + // Validate the properties of the truncated range. + EXPECT_TRUE(range_map.RetrieveRange(49, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(50, retrieved_size); +} + +// A new range is overlapped at both ends. The new range and the range +// that overlaps at the beginning should be truncated. The range that overlaps +// at the end should be left untouched. +TEST(RangeMapTruncateLower, OverlapAtBothEnds) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + // This should overlap object_3 at the beginning. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 100 /* size */, object_1)); + + // This should overlap object_3 at the end. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(100 /* base address */, 100 /* size */, object_2)); + + // This should be overlapped on both ends by object_1 and object_2. + linked_ptr object_3(new CountedObject(3)); + EXPECT_TRUE( + range_map.StoreRange(50 /* base address */, 100 /* size */, object_3)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be truncated. + EXPECT_TRUE(range_map.RetrieveRange(0, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(50, retrieved_size); + // The second range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(150, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(100, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(100, retrieved_size); + // The third range (in the middle) should be truncated. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(3, object->id()); + EXPECT_EQ(50, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(50, retrieved_size); +} + +TEST(RangeMapTruncateLower, MultipleConflicts) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + // This should overlap with object_3. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(10 /* base address */, 90 /* size */, object_1)); + + // This should also overlap with object_3 but after object_1. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(100 /* base address */, 100 /* size */, object_2)); + + // This should be overlapped on both object_1 and object_2. + linked_ptr object_3(new CountedObject(3)); + EXPECT_TRUE( + range_map.StoreRange(0 /* base address */, 300 /* size */, object_3)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); + // The second range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(100, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(100, retrieved_size); + // The third range should be truncated. + EXPECT_TRUE(range_map.RetrieveRange(9, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(3, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(10, retrieved_size); +} + +// Adding two ranges without overlap should succeed and the ranges should +// be left intact. +TEST(RangeMapTruncateLower, NoConflicts) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateLower); + // Adding range 1. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE( + range_map.StoreRange(10 /* base address */, 90 /* size */, object_1)); + + // Adding range 2 - no overlap with range 1. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE( + range_map.StoreRange(110 /* base address */, 90 /* size */, object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); + // The second range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(110, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); +} + +} // namespace diff --git a/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_upper_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_upper_unittest.cc new file mode 100644 index 0000000000..7e3034f2fc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/range_map_truncate_upper_unittest.cc @@ -0,0 +1,354 @@ +// Copyright (c) 2016, 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_shrink_down_unittest.cc: Unit tests for RangeMap that specifically +// test shrink down when ranges overlap. +// +// Author: Ivan Penkov + +#include +#include + +#include "processor/range_map-inl.h" + +#include "breakpad_googletest_includes.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + +namespace { + +using google_breakpad::linked_ptr; +using google_breakpad::MergeRangeStrategy; +using google_breakpad::RangeMap; + +// A CountedObject holds an int. A global (not thread safe!) count of +// allocated CountedObjects is maintained to help test memory management. +class CountedObject { + public: + explicit CountedObject(int id) : id_(id) { ++count_; } + ~CountedObject() { --count_; } + + static int count() { return count_; } + int id() const { return id_; } + + private: + static int count_; + int id_; +}; + +int CountedObject::count_; + +typedef int AddressType; +typedef RangeMap> TestMap; + +// Same range cannot be stored wice. +TEST(RangeMapTruncateUpper, SameRange) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_1)); + + // Same range cannot be stored wice. + linked_ptr object_2(new CountedObject(2)); + EXPECT_FALSE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_2)); +} + +// If a range is completely contained by another range, then the larger range +// should be shrinked down. +TEST(RangeMapTruncateUpper, CompletelyContained) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + // Larger range is added first. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_1)); + // Smaller (contained) range is added second. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 80 /* size */, + object_2)); + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range contains the second, so the first range should have been + // shrunk to [90, 99]. Range [0, 9] should be free. + EXPECT_FALSE(range_map.RetrieveRange(0, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_FALSE(range_map.RetrieveRange(9, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_TRUE(range_map.RetrieveRange(90, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(90, retrieved_base); + EXPECT_EQ(90, retrieved_delta); + EXPECT_EQ(10, retrieved_size); + // Validate the properties of the smaller range (should be untouched). + EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(80, retrieved_size); +} + +// Same as the previous test, however the larger range is added second. +TEST(RangeMapTruncateUpper, CompletelyContained_LargerAddedSecond) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + // Smaller (contained) range is added first. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 80 /* size */, + object_1)); + // Larger range is added second. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_2)); + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The second range contains the first, so the second range should have been + // shrunk to [90, 99]. Range [0, 9] should be free. + EXPECT_FALSE(range_map.RetrieveRange(0, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_FALSE(range_map.RetrieveRange(9, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_TRUE(range_map.RetrieveRange(90, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(90, retrieved_base); + EXPECT_EQ(90, retrieved_delta); + EXPECT_EQ(10, retrieved_size); + // Validate the properties of the smaller range (should be untouched). + EXPECT_TRUE(range_map.RetrieveRange(10, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(80, retrieved_size); +} + +TEST(RangeMapTruncateUpper, PartialOverlap_AtBeginning) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_1)); + + // Partial overlap at the beginning of the new range. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(90 /* base address */, 110 /* size */, + object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The second range is supposed to be shrunk down so the following address + // should resize in the first range. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(100, retrieved_size); + // Validate the properties of the shrunk down range. + EXPECT_TRUE(range_map.RetrieveRange(100, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(100, retrieved_base); + EXPECT_EQ(10, retrieved_delta); + EXPECT_EQ(100, retrieved_size); +} + +TEST(RangeMapTruncateUpper, PartialOverlap_AtEnd) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(50 /* base address */, 50 /* size */, + object_1)); + + // Partial overlap at the end of the new range. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 70 /* size */, + object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range is supposed to be shrunk down so the following address + // should resize in the first range. + EXPECT_TRUE(range_map.RetrieveRange(69, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(70, retrieved_size); + // Validate the properties of the shrunk down range. + EXPECT_TRUE(range_map.RetrieveRange(70, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(70, retrieved_base); + EXPECT_EQ(20, retrieved_delta); + EXPECT_EQ(30, retrieved_size); +} + +// A new range is overlapped at both ends. The new range and the range +// that overlaps at the end should be shrink. The range that overlaps at the +// beginning should be left untouched. +TEST(RangeMapTruncateUpper, OverlapAtBothEnds) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + // This should overlap object_3 at the beginning. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 100 /* size */, + object_1)); + + // This should overlap object_3 at the end. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(100 /* base address */, 100 /* size */, + object_2)); + + // This should be overlapped on both ends by object_1 and object_2. + linked_ptr object_3(new CountedObject(3)); + EXPECT_TRUE(range_map.StoreRange(50 /* base address */, 100 /* size */, + object_3)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(0, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(0, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(100, retrieved_size); + // The second range should be shrunk down by 50. + EXPECT_TRUE(range_map.RetrieveRange(150, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(150, retrieved_base); + EXPECT_EQ(50, retrieved_delta); + EXPECT_EQ(50, retrieved_size); + // The third range (in the middle) should be shrunk down by 50. + EXPECT_TRUE(range_map.RetrieveRange(100, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(3, object->id()); + EXPECT_EQ(100, retrieved_base); + EXPECT_EQ(50, retrieved_delta); + EXPECT_EQ(50, retrieved_size); +} + +TEST(RangeMapTruncateUpper, MultipleConflicts) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + // This should overlap with object_3. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 90 /* size */, + object_1)); + + // This should also overlap with object_3 but after object_1. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(100 /* base address */, 100 /* size */, + object_2)); + + // This should be overlapped on both object_1 and object_2. Since + // object_3 ends with the higher address it must be shrunk. + linked_ptr object_3(new CountedObject(3)); + EXPECT_TRUE(range_map.StoreRange(0 /* base address */, 300 /* size */, + object_3)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); + // The second range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(100, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(100, retrieved_size); + // The third range should be shrunk down by 200. + EXPECT_TRUE(range_map.RetrieveRange(299, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(3, object->id()); + EXPECT_EQ(200, retrieved_base); + EXPECT_EQ(200, retrieved_delta); + EXPECT_EQ(100, retrieved_size); +} + +// Adding two ranges without overlap should succeed and the ranges should +// be left intact. +TEST(RangeMapTruncateUpper, NoConflicts) { + TestMap range_map; + range_map.SetMergeStrategy(MergeRangeStrategy::kTruncateUpper); + // Adding range 1. + linked_ptr object_1(new CountedObject(1)); + EXPECT_TRUE(range_map.StoreRange(10 /* base address */, 90 /* size */, + object_1)); + + // Adding range 2 - no overlap with range 1. + linked_ptr object_2(new CountedObject(2)); + EXPECT_TRUE(range_map.StoreRange(110 /* base address */, 90 /* size */, + object_2)); + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_delta = AddressType(); + AddressType retrieved_size = AddressType(); + // The first range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(99, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(1, object->id()); + EXPECT_EQ(10, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); + // The second range should be intact. + EXPECT_TRUE(range_map.RetrieveRange(199, &object, &retrieved_base, + &retrieved_delta, &retrieved_size)); + EXPECT_EQ(2, object->id()); + EXPECT_EQ(110, retrieved_base); + EXPECT_EQ(0, retrieved_delta); + EXPECT_EQ(90, retrieved_size); +} + +} // namespace diff --git a/toolkit/crashreporter/google-breakpad/src/processor/range_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/range_map_unittest.cc new file mode 100644 index 0000000000..31b89e5de3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/range_map_unittest.cc @@ -0,0 +1,559 @@ +// Copyright (c) 2010 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_unittest.cc: Unit tests for RangeMap +// +// Author: Mark Mentovai + + +#include +#include + +#include "processor/range_map-inl.h" + +#include "common/scoped_ptr.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + +namespace { + + +using google_breakpad::linked_ptr; +using google_breakpad::scoped_ptr; +using google_breakpad::RangeMap; + + +// A CountedObject holds an int. A global (not thread safe!) count of +// allocated CountedObjects is maintained to help test memory management. +class CountedObject { + public: + explicit CountedObject(int id) : id_(id) { ++count_; } + ~CountedObject() { --count_; } + + static int count() { return count_; } + int id() const { return id_; } + + private: + static int count_; + int id_; +}; + +int CountedObject::count_; + + +typedef int AddressType; +typedef RangeMap< AddressType, linked_ptr > TestMap; + + +// RangeTest contains data to use for store and retrieve tests. See +// RunTests for descriptions of the tests. +struct RangeTest { + // Base address to use for test + AddressType address; + + // Size of range to use for test + AddressType size; + + // Unique ID of range - unstorable ranges must have unique IDs too + int id; + + // Whether this range is expected to be stored successfully or not + bool expect_storable; +}; + + +// A RangeTestSet encompasses multiple RangeTests, which are run in +// sequence on the same RangeMap. +struct RangeTestSet { + // An array of RangeTests + const RangeTest *range_tests; + + // The number of tests in the set + unsigned int range_test_count; +}; + + +// StoreTest uses the data in a RangeTest and calls StoreRange on the +// test RangeMap. It returns true if the expected result occurred, and +// false if something else happened. +static bool StoreTest(TestMap *range_map, const RangeTest *range_test) { + linked_ptr object(new CountedObject(range_test->id)); + bool stored = range_map->StoreRange(range_test->address, + range_test->size, + object); + + if (stored != range_test->expect_storable) { + fprintf(stderr, "FAILED: " + "StoreRange id %d, expected %s, observed %s\n", + range_test->id, + range_test->expect_storable ? "storable" : "not storable", + stored ? "stored" : "not stored"); + return false; + } + + return true; +} + + +// RetrieveTest uses the data in RangeTest and calls RetrieveRange on the +// test RangeMap. If it retrieves the expected value (which can be no +// map entry at the specified range,) it returns true, otherwise, it returns +// false. RetrieveTest will check the values around the base address and +// the high address of a range to guard against off-by-one errors. +static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) { + for (unsigned int side = 0; side <= 1; ++side) { + // When side == 0, check the low side (base address) of each range. + // When side == 1, check the high side (base + size) of each range. + + // Check one-less and one-greater than the target address in addition + // to the target address itself. + + // If the size of the range is only 1, don't check one greater than + // the base or one less than the high - for a successfully stored + // range, these tests would erroneously fail because the range is too + // small. + AddressType low_offset = -1; + AddressType high_offset = 1; + if (range_test->size == 1) { + if (!side) // When checking the low side, + high_offset = 0; // don't check one over the target. + else // When checking the high side, + low_offset = 0; // don't check one under the target. + } + + for (AddressType offset = low_offset; offset <= high_offset; ++offset) { + AddressType address = + offset + + (!side ? range_test->address : + range_test->address + range_test->size - 1); + + bool expected_result = false; // This is correct for tests not stored. + if (range_test->expect_storable) { + if (offset == 0) // When checking the target address, + expected_result = true; // test should always succeed. + else if (offset == -1) // When checking one below the target, + expected_result = side; // should fail low and succeed high. + else // When checking one above the target, + expected_result = !side; // should succeed low and fail high. + } + + linked_ptr object; + AddressType retrieved_base = AddressType(); + AddressType retrieved_size = AddressType(); + AddressType retrieved_delta = AddressType(); + bool retrieved = range_map->RetrieveRange(address, &object, + &retrieved_base, + &retrieved_delta, + &retrieved_size); + + bool observed_result = retrieved && object->id() == range_test->id; + + if (observed_result != expected_result) { + fprintf(stderr, "FAILED: " + "RetrieveRange id %d, side %d, offset %d, " + "expected %s, observed %s\n", + range_test->id, + side, + offset, + expected_result ? "true" : "false", + observed_result ? "true" : "false"); + return false; + } + + // If a range was successfully retrieved, check that the returned + // bounds match the range as stored. + if (observed_result == true && + (retrieved_base != range_test->address || + retrieved_size != range_test->size)) { + fprintf(stderr, "FAILED: " + "RetrieveRange id %d, side %d, offset %d, " + "expected base/size %d/%d, observed %d/%d\n", + range_test->id, + side, + offset, + range_test->address, range_test->size, + retrieved_base, retrieved_size); + return false; + } + + // Now, check RetrieveNearestRange. The nearest range is always + // expected to be different from the test range when checking one + // less than the low side. + bool expected_nearest = range_test->expect_storable; + if (!side && offset < 0) + expected_nearest = false; + + linked_ptr nearest_object; + AddressType nearest_base = AddressType(); + AddressType nearest_delta = AddressType(); + AddressType nearest_size = AddressType(); + bool retrieved_nearest = range_map->RetrieveNearestRange(address, + &nearest_object, + &nearest_base, + &nearest_delta, + &nearest_size); + + // When checking one greater than the high side, RetrieveNearestRange + // should usually return the test range. When a different range begins + // at that address, though, then RetrieveNearestRange should return the + // range at the address instead of the test range. + if (side && offset > 0 && nearest_base == address) { + expected_nearest = false; + } + + bool observed_nearest = retrieved_nearest && + nearest_object->id() == range_test->id; + + if (observed_nearest != expected_nearest) { + fprintf(stderr, "FAILED: " + "RetrieveNearestRange id %d, side %d, offset %d, " + "expected %s, observed %s\n", + range_test->id, + side, + offset, + expected_nearest ? "true" : "false", + observed_nearest ? "true" : "false"); + return false; + } + + // If a range was successfully retrieved, check that the returned + // bounds match the range as stored. + if (expected_nearest && + (nearest_base != range_test->address || + nearest_size != range_test->size)) { + fprintf(stderr, "FAILED: " + "RetrieveNearestRange id %d, side %d, offset %d, " + "expected base/size %d/%d, observed %d/%d\n", + range_test->id, + side, + offset, + range_test->address, range_test->size, + nearest_base, nearest_size); + return false; + } + } + } + + return true; +} + + +// Test RetrieveRangeAtIndex, which is supposed to return objects in order +// according to their addresses. This test is performed by looping through +// the map, calling RetrieveRangeAtIndex for all possible indices in sequence, +// and verifying that each call returns a different object than the previous +// call, and that ranges are returned with increasing base addresses. Returns +// false if the test fails. +static bool RetrieveIndexTest(TestMap *range_map, int set) { + linked_ptr object; + CountedObject *last_object = NULL; + AddressType last_base = 0; + + int object_count = range_map->GetCount(); + for (int object_index = 0; object_index < object_count; ++object_index) { + AddressType base; + if (!range_map->RetrieveRangeAtIndex(object_index, &object, &base, + NULL /* delta */, NULL /* size */)) { + fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " + "expected success, observed failure\n", + set, object_index); + return false; + } + + if (!object.get()) { + fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " + "expected object, observed NULL\n", + set, object_index); + return false; + } + + // It's impossible to do these comparisons unless there's a previous + // object to compare against. + if (last_object) { + // The object must be different from the last one. + if (object->id() == last_object->id()) { + fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " + "expected different objects, observed same objects (%d)\n", + set, object_index, object->id()); + return false; + } + + // Each object must have a base greater than the previous object's base. + if (base <= last_base) { + fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, " + "expected different bases, observed same bases (%d)\n", + set, object_index, base); + return false; + } + } + + last_object = object.get(); + last_base = base; + } + + // Make sure that RetrieveRangeAtIndex doesn't allow lookups at indices that + // are too high. + if (range_map->RetrieveRangeAtIndex(object_count, &object, NULL /* base */, + NULL /* delta */, NULL /* size */)) { + fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d (too large), " + "expected failure, observed success\n", + set, object_count); + return false; + } + + return true; +} + +// Additional RetriveAtIndex test to expose the bug in RetrieveRangeAtIndex(). +// Bug info: RetrieveRangeAtIndex() previously retrieves the high address of +// entry, however, it is supposed to retrieve the base address of entry as +// stated in the comment in range_map.h. +static bool RetriveAtIndexTest2() { + scoped_ptr range_map(new TestMap()); + + // Store ranges with base address = 2 * object_id: + const int range_size = 2; + for (int object_id = 0; object_id < 100; ++object_id) { + linked_ptr object(new CountedObject(object_id)); + int base_address = 2 * object_id; + range_map->StoreRange(base_address, range_size, object); + } + + linked_ptr object; + int object_count = range_map->GetCount(); + for (int object_index = 0; object_index < object_count; ++object_index) { + AddressType base; + if (!range_map->RetrieveRangeAtIndex(object_index, &object, &base, + NULL /* delta */, NULL /* size */)) { + fprintf(stderr, "FAILED: RetrieveAtIndexTest2 index %d, " + "expected success, observed failure\n", object_index); + return false; + } + + int expected_base = 2 * object->id(); + if (base != expected_base) { + fprintf(stderr, "FAILED: RetriveAtIndexTest2 index %d, " + "expected base %d, observed base %d", + object_index, expected_base, base); + return false; + } + } + + return true; +} + + +// RunTests runs a series of test sets. +static bool RunTests() { + // These tests will be run sequentially. The first set of tests exercises + // most functions of RangeTest, and verifies all of the bounds-checking. + const RangeTest range_tests_0[] = { + { INT_MIN, 16, 1, true }, // lowest possible range + { -2, 5, 2, true }, // a range through zero + { INT_MAX - 9, 11, 3, false }, // tests anti-overflow + { INT_MAX - 9, 10, 4, true }, // highest possible range + { 5, 0, 5, false }, // tests anti-zero-size + { 5, 1, 6, true }, // smallest possible range + { -20, 15, 7, true }, // entirely negative + + { 10, 10, 10, true }, // causes the following tests to fail + { 9, 10, 11, false }, // one-less base, one-less high + { 9, 11, 12, false }, // one-less base, identical high + { 9, 12, 13, false }, // completely contains existing + { 10, 9, 14, false }, // identical base, one-less high + { 10, 10, 15, false }, // exactly identical to existing range + { 10, 11, 16, false }, // identical base, one-greater high + { 11, 8, 17, false }, // contained completely within + { 11, 9, 18, false }, // one-greater base, identical high + { 11, 10, 19, false }, // one-greater base, one-greater high + { 9, 2, 20, false }, // overlaps bottom by one + { 10, 1, 21, false }, // overlaps bottom by one, contained + { 19, 1, 22, false }, // overlaps top by one, contained + { 19, 2, 23, false }, // overlaps top by one + + { 9, 1, 24, true }, // directly below without overlap + { 20, 1, 25, true }, // directly above without overlap + + { 6, 3, 26, true }, // exactly between two ranges, gapless + { 7, 3, 27, false }, // tries to span two ranges + { 7, 5, 28, false }, // tries to span three ranges + { 4, 20, 29, false }, // tries to contain several ranges + + { 30, 50, 30, true }, + { 90, 25, 31, true }, + { 35, 65, 32, false }, // tries to span two noncontiguous + { 120, 10000, 33, true }, // > 8-bit + { 20000, 20000, 34, true }, // > 8-bit + { 0x10001, 0x10001, 35, true }, // > 16-bit + + { 27, -1, 36, false } // tests high < base + }; + + // Attempt to fill the entire space. The entire space must be filled with + // three stores because AddressType is signed for these tests, so RangeMap + // treats the size as signed and rejects sizes that appear to be negative. + // Even if these tests were run as unsigned, two stores would be needed + // to fill the space because the entire size of the space could only be + // described by using one more bit than would be present in AddressType. + const RangeTest range_tests_1[] = { + { INT_MIN, INT_MAX, 50, true }, // From INT_MIN to -2, inclusive + { -1, 2, 51, true }, // From -1 to 0, inclusive + { 1, INT_MAX, 52, true }, // From 1 to INT_MAX, inclusive + { INT_MIN, INT_MAX, 53, false }, // Can't fill the space twice + { -1, 2, 54, false }, + { 1, INT_MAX, 55, false }, + { -3, 6, 56, false }, // -3 to 2, inclusive - spans 3 ranges + }; + + // A light round of testing to verify that RetrieveRange does the right + // the right thing at the extremities of the range when nothing is stored + // there. Checks are forced without storing anything at the extremities + // by setting size = 0. + const RangeTest range_tests_2[] = { + { INT_MIN, 0, 100, false }, // makes RetrieveRange check low end + { -1, 3, 101, true }, + { INT_MAX, 0, 102, false }, // makes RetrieveRange check high end + }; + + // Similar to the previous test set, but with a couple of ranges closer + // to the extremities. + const RangeTest range_tests_3[] = { + { INT_MIN + 1, 1, 110, true }, + { INT_MAX - 1, 1, 111, true }, + { INT_MIN, 0, 112, false }, // makes RetrieveRange check low end + { INT_MAX, 0, 113, false } // makes RetrieveRange check high end + }; + + // The range map is cleared between sets of tests listed here. + const RangeTestSet range_test_sets[] = { + { range_tests_0, sizeof(range_tests_0) / sizeof(RangeTest) }, + { range_tests_1, sizeof(range_tests_1) / sizeof(RangeTest) }, + { range_tests_2, sizeof(range_tests_2) / sizeof(RangeTest) }, + { range_tests_3, sizeof(range_tests_3) / sizeof(RangeTest) }, + { range_tests_0, sizeof(range_tests_0) / sizeof(RangeTest) } // Run again + }; + + // Maintain the range map in a pointer so that deletion can be meaningfully + // tested. + scoped_ptr range_map(new TestMap()); + + // Run all of the test sets in sequence. + unsigned int range_test_set_count = sizeof(range_test_sets) / + sizeof(RangeTestSet); + for (unsigned int range_test_set_index = 0; + range_test_set_index < range_test_set_count; + ++range_test_set_index) { + const RangeTest *range_tests = + range_test_sets[range_test_set_index].range_tests; + unsigned int range_test_count = + range_test_sets[range_test_set_index].range_test_count; + + // Run the StoreRange test, which validates StoreRange and initializes + // the RangeMap with data for the RetrieveRange test. + int stored_count = 0; // The number of ranges successfully stored + for (unsigned int range_test_index = 0; + range_test_index < range_test_count; + ++range_test_index) { + const RangeTest *range_test = &range_tests[range_test_index]; + if (!StoreTest(range_map.get(), range_test)) + return false; + + if (range_test->expect_storable) + ++stored_count; + } + + // There should be exactly one CountedObject for everything successfully + // stored in the RangeMap. + if (CountedObject::count() != stored_count) { + fprintf(stderr, "FAILED: " + "stored object counts don't match, expected %d, observed %d\n", + stored_count, + CountedObject::count()); + + return false; + } + + // The RangeMap's own count of objects should also match. + if (range_map->GetCount() != stored_count) { + fprintf(stderr, "FAILED: stored object count doesn't match GetCount, " + "expected %d, observed %d\n", + stored_count, range_map->GetCount()); + + return false; + } + + // Run the RetrieveRange test + for (unsigned int range_test_index = 0; + range_test_index < range_test_count; + ++range_test_index) { + const RangeTest *range_test = &range_tests[range_test_index]; + if (!RetrieveTest(range_map.get(), range_test)) + return false; + } + + if (!RetrieveIndexTest(range_map.get(), range_test_set_index)) + return false; + + // Clear the map between test sets. If this is the final test set, + // delete the map instead to test destruction. + if (range_test_set_index < range_test_set_count - 1) + range_map->Clear(); + else + range_map.reset(); + + // Test that all stored objects are freed when the RangeMap is cleared + // or deleted. + if (CountedObject::count() != 0) { + fprintf(stderr, "FAILED: " + "did not free all objects after %s, %d still allocated\n", + range_test_set_index < range_test_set_count - 1 ? "clear" + : "delete", + CountedObject::count()); + + return false; + } + } + + if (!RetriveAtIndexTest2()) { + fprintf(stderr, "FAILED: did not pass RetrieveAtIndexTest2()\n"); + return false; + } + + return true; +} + + +} // namespace + + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + return RunTests() ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer-inl.h new file mode 100644 index 0000000000..606bb3cead --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer-inl.h @@ -0,0 +1,260 @@ +// Copyright (c) 2010, 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_serializer-inl.h: template specializations for following types: +// bool, const char *(C-string), string, +// Line, Function, PublicSymbol, WindowsFrameInfo and their linked pointers. +// +// See simple_serializer.h for moredocumentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_SIMPLE_SERIALIZER_INL_H__ +#define PROCESSOR_SIMPLE_SERIALIZER_INL_H__ + +#include + +#include "processor/simple_serializer.h" +#include "map_serializers-inl.h" + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "processor/basic_source_line_resolver_types.h" +#include "processor/linked_ptr.h" +#include "processor/windows_frame_info.h" + +namespace google_breakpad { + +// Specializations of SimpleSerializer: bool +template<> +class SimpleSerializer { + public: + static size_t SizeOf(bool boolean) { return 1; } + + static char *Write(bool boolean, char *dest) { + *dest = static_cast(boolean? 255 : 0); + return ++dest; + } + + static const char *Read(const char *source, bool *value) { + *value = ((*source) == 0 ? false : true); + return ++source; + } +}; + +// Specializations of SimpleSerializer: string +template<> +class SimpleSerializer { + public: + static size_t SizeOf(const string &str) { return str.size() + 1; } + + static char *Write(const string &str, char *dest) { + strcpy(dest, str.c_str()); + return dest + SizeOf(str); + } +}; + +// Specializations of SimpleSerializer: C-string +template<> +class SimpleSerializer { + public: + static size_t SizeOf(const char *cstring) { + return strlen(cstring) + 1; + } + + static char *Write(const char *cstring, char *dest) { + strcpy(dest, cstring); + return dest + SizeOf(cstring); + } +}; + +// Specializations of SimpleSerializer: Line +template<> +class SimpleSerializer { + typedef BasicSourceLineResolver::Line Line; + public: + static size_t SizeOf(const Line &line) { + return SimpleSerializer::SizeOf(line.address) + + SimpleSerializer::SizeOf(line.size) + + SimpleSerializer::SizeOf(line.source_file_id) + + SimpleSerializer::SizeOf(line.line); + } + static char *Write(const Line &line, char *dest) { + dest = SimpleSerializer::Write(line.address, dest); + dest = SimpleSerializer::Write(line.size, dest); + dest = SimpleSerializer::Write(line.source_file_id, dest); + dest = SimpleSerializer::Write(line.line, dest); + return dest; + } +}; + +// Specializations of SimpleSerializer: PublicSymbol +template<> +class SimpleSerializer { + typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; + public: + static size_t SizeOf(const PublicSymbol &pubsymbol) { + return SimpleSerializer::SizeOf(pubsymbol.name) + + SimpleSerializer::SizeOf(pubsymbol.address) + + SimpleSerializer::SizeOf(pubsymbol.parameter_size); + } + static char *Write(const PublicSymbol &pubsymbol, char *dest) { + dest = SimpleSerializer::Write(pubsymbol.name, dest); + dest = SimpleSerializer::Write(pubsymbol.address, dest); + dest = SimpleSerializer::Write(pubsymbol.parameter_size, dest); + return dest; + } +}; + +// Specializations of SimpleSerializer: WindowsFrameInfo +template<> +class SimpleSerializer { + public: + static size_t SizeOf(const WindowsFrameInfo &wfi) { + unsigned int size = 0; + size += sizeof(int32_t); // wfi.type_ + size += SimpleSerializer::SizeOf(wfi.valid); + size += SimpleSerializer::SizeOf(wfi.prolog_size); + size += SimpleSerializer::SizeOf(wfi.epilog_size); + size += SimpleSerializer::SizeOf(wfi.parameter_size); + size += SimpleSerializer::SizeOf(wfi.saved_register_size); + size += SimpleSerializer::SizeOf(wfi.local_size); + size += SimpleSerializer::SizeOf(wfi.max_stack_size); + size += SimpleSerializer::SizeOf(wfi.allocates_base_pointer); + size += SimpleSerializer::SizeOf(wfi.program_string); + return size; + } + static char *Write(const WindowsFrameInfo &wfi, char *dest) { + dest = SimpleSerializer::Write( + static_cast(wfi.type_), dest); + dest = SimpleSerializer::Write(wfi.valid, dest); + dest = SimpleSerializer::Write(wfi.prolog_size, dest); + dest = SimpleSerializer::Write(wfi.epilog_size, dest); + dest = SimpleSerializer::Write(wfi.parameter_size, dest); + dest = SimpleSerializer::Write(wfi.saved_register_size, dest); + dest = SimpleSerializer::Write(wfi.local_size, dest); + dest = SimpleSerializer::Write(wfi.max_stack_size, dest); + dest = SimpleSerializer::Write(wfi.allocates_base_pointer, dest); + return SimpleSerializer::Write(wfi.program_string, dest); + } +}; + +// Specializations of SimpleSerializer: Linked_ptr version of +// Line, Function, PublicSymbol, WindowsFrameInfo. +template<> +class SimpleSerializer< linked_ptr > { + typedef BasicSourceLineResolver::Line Line; + public: + static size_t SizeOf(const linked_ptr &lineptr) { + if (lineptr.get() == NULL) return 0; + return SimpleSerializer::SizeOf(*(lineptr.get())); + } + static char *Write(const linked_ptr &lineptr, char *dest) { + if (lineptr.get()) + dest = SimpleSerializer::Write(*(lineptr.get()), dest); + return dest; + } +}; + +template<> +class SimpleSerializer { + // Convenient type names. + typedef BasicSourceLineResolver::Function Function; + typedef BasicSourceLineResolver::Line Line; + public: + static size_t SizeOf(const Function &func) { + unsigned int size = 0; + size += SimpleSerializer::SizeOf(func.name); + size += SimpleSerializer::SizeOf(func.address); + size += SimpleSerializer::SizeOf(func.size); + size += SimpleSerializer::SizeOf(func.parameter_size); + size += range_map_serializer_.SizeOf(func.lines); + return size; + } + + static char *Write(const Function &func, char *dest) { + dest = SimpleSerializer::Write(func.name, dest); + dest = SimpleSerializer::Write(func.address, dest); + dest = SimpleSerializer::Write(func.size, dest); + dest = SimpleSerializer::Write(func.parameter_size, dest); + dest = range_map_serializer_.Write(func.lines, dest); + return dest; + } + private: + // This static member is defined in module_serializer.cc. + static RangeMapSerializer< MemAddr, linked_ptr > range_map_serializer_; +}; + +template<> +class SimpleSerializer< linked_ptr > { + typedef BasicSourceLineResolver::Function Function; + public: + static size_t SizeOf(const linked_ptr &func) { + if (!func.get()) return 0; + return SimpleSerializer::SizeOf(*(func.get())); + } + + static char *Write(const linked_ptr &func, char *dest) { + if (func.get()) + dest = SimpleSerializer::Write(*(func.get()), dest); + return dest; + } +}; + +template<> +class SimpleSerializer< linked_ptr > { + typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; + public: + static size_t SizeOf(const linked_ptr &pubsymbol) { + if (pubsymbol.get() == NULL) return 0; + return SimpleSerializer::SizeOf(*(pubsymbol.get())); + } + static char *Write(const linked_ptr &pubsymbol, char *dest) { + if (pubsymbol.get()) + dest = SimpleSerializer::Write(*(pubsymbol.get()), dest); + return dest; + } +}; + +template<> +class SimpleSerializer< linked_ptr > { + public: + static size_t SizeOf(const linked_ptr &wfi) { + if (wfi.get() == NULL) return 0; + return SimpleSerializer::SizeOf(*(wfi.get())); + } + static char *Write(const linked_ptr &wfi, char *dest) { + if (wfi.get()) + dest = SimpleSerializer::Write(*(wfi.get()), dest); + return dest; + } +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_SIMPLE_SERIALIZER_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer.h b/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer.h new file mode 100644 index 0000000000..275f51ce36 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/simple_serializer.h @@ -0,0 +1,63 @@ +// Copyright (c) 2010, 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_serializer.h: SimpleSerializer is a template for calculating size and +// writing to specific memory location for objects of primitive types, C-style +// string, string, breakpad types/structs etc. +// All specializations of SimpleSerializer template are defined in the +// "simple_serializer-inl.h" file. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_SIMPLE_SERIALIZER_H__ +#define PROCESSOR_SIMPLE_SERIALIZER_H__ + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +typedef uint64_t MemAddr; + +// Default implementation of SimpleSerializer template. +// Specializations are defined in "simple_serializer-inl.h". +template class SimpleSerializer { + public: + // Calculate and return the size of the 'item'. + static size_t SizeOf(const Type &item) { return sizeof(item); } + // Write 'item' to memory location 'dest', and return to the "end" address of + // data written, i.e., the address after the final byte written. + static char *Write(const Type &item, char *dest) { + new (dest) Type(item); + return dest + SizeOf(item); + } +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_SIMPLE_SERIALIZER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.cc b/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.cc new file mode 100644 index 0000000000..bc5ebb687b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.cc @@ -0,0 +1,204 @@ +// 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.cc: A simple SymbolSupplier implementation +// +// See simple_symbol_supplier.h for documentation. +// +// Author: Mark Mentovai + +#include "processor/simple_symbol_supplier.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/logging.h" +#include "processor/pathname_stripper.h" + +namespace google_breakpad { + +static bool file_exists(const string &file_name) { + struct stat sb; + return stat(file_name.c_str(), &sb) == 0; +} + +SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( + const CodeModule *module, const SystemInfo *system_info, + string *symbol_file) { + BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFile " + "requires |symbol_file|"; + assert(symbol_file); + symbol_file->clear(); + + for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) { + SymbolResult result; + if ((result = GetSymbolFileAtPathFromRoot(module, system_info, + paths_[path_index], + symbol_file)) != NOT_FOUND) { + return result; + } + } + return NOT_FOUND; +} + +SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile( + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) { + assert(symbol_data); + symbol_data->clear(); + + SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, + symbol_file); + if (s == FOUND) { + std::ifstream in(symbol_file->c_str()); + std::getline(in, *symbol_data, string::traits_type::to_char_type( + string::traits_type::eof())); + in.close(); + } + return s; +} + +SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData( + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) { + assert(symbol_data); + assert(symbol_data_size); + + string symbol_data_string; + SymbolSupplier::SymbolResult s = + GetSymbolFile(module, system_info, symbol_file, &symbol_data_string); + + if (s == FOUND) { + *symbol_data_size = symbol_data_string.size() + 1; + *symbol_data = new char[*symbol_data_size]; + if (*symbol_data == NULL) { + BPLOG(ERROR) << "Memory allocation for size " << *symbol_data_size + << " failed"; + return INTERRUPT; + } + memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); + (*symbol_data)[symbol_data_string.size()] = '\0'; + memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); + } + return s; +} + +void SimpleSymbolSupplier::FreeSymbolData(const CodeModule *module) { + if (!module) { + BPLOG(INFO) << "Cannot free symbol data buffer for NULL module"; + return; + } + + map::iterator it = memory_buffers_.find(module->code_file()); + if (it == memory_buffers_.end()) { + BPLOG(INFO) << "Cannot find symbol data buffer for module " + << module->code_file(); + return; + } + delete [] it->second; + memory_buffers_.erase(it); +} + +SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPathFromRoot( + const CodeModule *module, const SystemInfo *system_info, + const string &root_path, string *symbol_file) { + BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath " + "requires |symbol_file|"; + assert(symbol_file); + symbol_file->clear(); + + if (!module) + return NOT_FOUND; + + // Start with the base path. + string path = root_path; + + // Append the debug (pdb) file name as a directory name. + path.append("/"); + string debug_file_name = PathnameStripper::File(module->debug_file()); + if (debug_file_name.empty()) { + BPLOG(ERROR) << "Can't construct symbol file path without debug_file " + "(code_file = " << + PathnameStripper::File(module->code_file()) << ")"; + return NOT_FOUND; + } + path.append(debug_file_name); + + // Append the identifier as a directory name. + path.append("/"); + string identifier = module->debug_identifier(); + if (identifier.empty()) { + BPLOG(ERROR) << "Can't construct symbol file path without debug_identifier " + "(code_file = " << + PathnameStripper::File(module->code_file()) << + ", debug_file = " << debug_file_name << ")"; + return NOT_FOUND; + } + path.append(identifier); + + // Transform the debug file name into one ending in .sym. If the existing + // name ends in .pdb, strip the .pdb. Otherwise, add .sym to the non-.pdb + // name. + path.append("/"); + string debug_file_extension; + if (debug_file_name.size() > 4) + debug_file_extension = debug_file_name.substr(debug_file_name.size() - 4); + std::transform(debug_file_extension.begin(), debug_file_extension.end(), + debug_file_extension.begin(), tolower); + if (debug_file_extension == ".pdb") { + path.append(debug_file_name.substr(0, debug_file_name.size() - 4)); + } else { + path.append(debug_file_name); + } + path.append(".sym"); + + if (!file_exists(path)) { + BPLOG(INFO) << "No symbol file at " << path; + return NOT_FOUND; + } + + *symbol_file = path; + return FOUND; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.h b/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.h new file mode 100644 index 0000000000..0cde85cdcd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/simple_symbol_supplier.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. + +// 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 +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/symbol_supplier.h" + +namespace google_breakpad { + +using std::map; +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 &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); + + // Allocates data buffer on heap and writes symbol data into buffer. + // Symbol supplier ALWAYS takes ownership of the data buffer. + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size); + + // Free the data buffer allocated in the above GetCStringSymbolData(); + virtual void FreeSymbolData(const CodeModule *module); + + protected: + SymbolResult GetSymbolFileAtPathFromRoot(const CodeModule *module, + const SystemInfo *system_info, + const string &root_path, + string *symbol_file); + + private: + map memory_buffers_; + vector paths_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_SIMPLE_SYMBOL_SUPPLIER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base.cc b/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base.cc new file mode 100644 index 0000000000..6eff1f9918 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base.cc @@ -0,0 +1,341 @@ +// Copyright (c) 2010 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. +// +// source_line_resolver_base.cc: Implementation of SourceLineResolverBase. +// +// See source_line_resolver_base.h and source_line_resolver_base_types.h for +// more documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include +#include +#include + +#include +#include + +#include "google_breakpad/processor/source_line_resolver_base.h" +#include "processor/source_line_resolver_base_types.h" +#include "processor/module_factory.h" + +using std::map; +using std::make_pair; + +namespace google_breakpad { + +SourceLineResolverBase::SourceLineResolverBase( + ModuleFactory *module_factory) + : modules_(new ModuleMap), + corrupt_modules_(new ModuleSet), + memory_buffers_(new MemoryMap), + module_factory_(module_factory) { +} + +SourceLineResolverBase::~SourceLineResolverBase() { + ModuleMap::iterator it; + // Iterate through ModuleMap and delete all loaded modules. + for (it = modules_->begin(); it != modules_->end(); ++it) { + // Delete individual module. + delete it->second; + } + // Delete the map of modules. + delete modules_; + modules_ = NULL; + + // Delete the set of corrupt modules. + delete corrupt_modules_; + corrupt_modules_ = NULL; + + MemoryMap::iterator iter = memory_buffers_->begin(); + for (; iter != memory_buffers_->end(); ++iter) { + delete [] iter->second; + } + // Delete the map of memory buffers. + delete memory_buffers_; + memory_buffers_ = NULL; + + delete module_factory_; + module_factory_ = NULL; +} + +bool SourceLineResolverBase::ReadSymbolFile(const string &map_file, + char **symbol_data, + size_t *symbol_data_size) { + if (symbol_data == NULL || symbol_data_size == NULL) { + BPLOG(ERROR) << "Could not Read file into Null memory pointer"; + return false; + } + + struct stat buf; + int error_code = stat(map_file.c_str(), &buf); + if (error_code == -1) { + string error_string; + error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "Could not open " << map_file << + ", error " << error_code << ": " << error_string; + return false; + } + + off_t file_size = buf.st_size; + + // Allocate memory for file contents, plus a null terminator + // since we may use strtok() on the contents. + *symbol_data_size = file_size + 1; + *symbol_data = new char[file_size + 1]; + + if (*symbol_data == NULL) { + BPLOG(ERROR) << "Could not allocate memory for " << map_file; + return false; + } + + BPLOG(INFO) << "Opening " << map_file; + + FILE *f = fopen(map_file.c_str(), "rt"); + if (!f) { + string error_string; + error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "Could not open " << map_file << + ", error " << error_code << ": " << error_string; + delete [] (*symbol_data); + *symbol_data = NULL; + return false; + } + + AutoFileCloser closer(f); + + int items_read = 0; + + items_read = fread(*symbol_data, 1, file_size, f); + + if (items_read != file_size) { + string error_string; + error_code = ErrnoString(&error_string); + BPLOG(ERROR) << "Could not slurp " << map_file << + ", error " << error_code << ": " << error_string; + delete [] (*symbol_data); + *symbol_data = NULL; + return false; + } + + (*symbol_data)[file_size] = '\0'; + return true; +} + +bool SourceLineResolverBase::LoadModule(const CodeModule *module, + const string &map_file) { + if (module == NULL) + return false; + + // Make sure we don't already have a module with the given name. + if (modules_->find(module->code_file()) != modules_->end()) { + BPLOG(INFO) << "Symbols for module " << module->code_file() + << " already loaded"; + return false; + } + + BPLOG(INFO) << "Loading symbols for module " << module->code_file() + << " from " << map_file; + + char *memory_buffer; + size_t memory_buffer_size; + if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size)) + return false; + + BPLOG(INFO) << "Read symbol file " << map_file << " succeeded"; + + bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer, + memory_buffer_size); + + if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) { + // memory_buffer has to stay alive as long as the module. + memory_buffers_->insert(make_pair(module->code_file(), memory_buffer)); + } else { + delete [] memory_buffer; + } + + return load_result; +} + +bool SourceLineResolverBase::LoadModuleUsingMapBuffer( + const CodeModule *module, const string &map_buffer) { + if (module == NULL) + return false; + + // Make sure we don't already have a module with the given name. + if (modules_->find(module->code_file()) != modules_->end()) { + BPLOG(INFO) << "Symbols for module " << module->code_file() + << " already loaded"; + return false; + } + + size_t memory_buffer_size = map_buffer.size() + 1; + char *memory_buffer = new char[memory_buffer_size]; + if (memory_buffer == NULL) { + BPLOG(ERROR) << "Could not allocate memory for " << module->code_file(); + return false; + } + + // Can't use strcpy, as the data may contain '\0's before the end. + memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size()); + memory_buffer[map_buffer.size()] = '\0'; + + bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer, + memory_buffer_size); + + if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) { + // memory_buffer has to stay alive as long as the module. + memory_buffers_->insert(make_pair(module->code_file(), memory_buffer)); + } else { + delete [] memory_buffer; + } + + return load_result; +} + +bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer( + const CodeModule *module, + char *memory_buffer, + size_t memory_buffer_size) { + if (!module) + return false; + + // Make sure we don't already have a module with the given name. + if (modules_->find(module->code_file()) != modules_->end()) { + BPLOG(INFO) << "Symbols for module " << module->code_file() + << " already loaded"; + return false; + } + + BPLOG(INFO) << "Loading symbols for module " << module->code_file() + << " from memory buffer"; + + Module *basic_module = module_factory_->CreateModule(module->code_file()); + + // Ownership of memory is NOT transfered to Module::LoadMapFromMemory(). + if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) { + BPLOG(ERROR) << "Too many error while parsing symbol data for module " + << module->code_file(); + // Returning false from here would be an indication that the symbols for + // this module are missing which would be wrong. Intentionally fall through + // and add the module to both the modules_ and the corrupt_modules_ lists. + assert(basic_module->IsCorrupt()); + } + + modules_->insert(make_pair(module->code_file(), basic_module)); + if (basic_module->IsCorrupt()) { + corrupt_modules_->insert(module->code_file()); + } + return true; +} + +bool SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule() { + return true; +} + +void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) { + if (!code_module) + return; + + ModuleMap::iterator mod_iter = modules_->find(code_module->code_file()); + if (mod_iter != modules_->end()) { + Module *symbol_module = mod_iter->second; + delete symbol_module; + corrupt_modules_->erase(mod_iter->first); + modules_->erase(mod_iter); + } + + if (ShouldDeleteMemoryBufferAfterLoadModule()) { + // No-op. Because we never store any memory buffers. + } else { + // There may be a buffer stored locally, we need to find and delete it. + MemoryMap::iterator iter = memory_buffers_->find(code_module->code_file()); + if (iter != memory_buffers_->end()) { + delete [] iter->second; + memory_buffers_->erase(iter); + } + } +} + +bool SourceLineResolverBase::HasModule(const CodeModule *module) { + if (!module) + return false; + return modules_->find(module->code_file()) != modules_->end(); +} + +bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule *module) { + if (!module) + return false; + return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end(); +} + +void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) { + if (frame->module) { + ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); + if (it != modules_->end()) { + it->second->LookupAddress(frame); + } + } +} + +WindowsFrameInfo *SourceLineResolverBase::FindWindowsFrameInfo( + const StackFrame *frame) { + if (frame->module) { + ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); + if (it != modules_->end()) { + return it->second->FindWindowsFrameInfo(frame); + } + } + return NULL; +} + +CFIFrameInfo *SourceLineResolverBase::FindCFIFrameInfo( + const StackFrame *frame) { + if (frame->module) { + ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); + if (it != modules_->end()) { + return it->second->FindCFIFrameInfo(frame); + } + } + return NULL; +} + +bool SourceLineResolverBase::CompareString::operator()( + const string &s1, const string &s2) const { + return strcmp(s1.c_str(), s2.c_str()) < 0; +} + +bool SourceLineResolverBase::Module::ParseCFIRuleSet( + const string &rule_set, CFIFrameInfo *frame_info) const { + CFIFrameInfoParseHandler handler(frame_info); + CFIRuleParser parser(&handler); + return parser.Parse(rule_set); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base_types.h b/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base_types.h new file mode 100644 index 0000000000..ca744e0015 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/source_line_resolver_base_types.h @@ -0,0 +1,167 @@ +// Copyright (c) 2010 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. + +// source_line_resolver_base_types.h: definition of nested classes/structs in +// SourceLineResolverBase. It moves the definitions out of +// source_line_resolver_base.cc, so that other classes may have access +// to these private nested types without including source_line_resolver_base.cc +// In addition, Module is defined as a pure abstract class to be implemented by +// each concrete source line resolver class. +// +// See source_line_resolver_base.h for more documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include + +#include +#include + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/source_line_resolver_base.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/cfi_frame_info.h" +#include "processor/windows_frame_info.h" + +#ifndef PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__ +#define PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__ + +namespace google_breakpad { + +class SourceLineResolverBase::AutoFileCloser { + public: + explicit AutoFileCloser(FILE *file) : file_(file) {} + ~AutoFileCloser() { + if (file_) + fclose(file_); + } + + private: + FILE *file_; +}; + +struct SourceLineResolverBase::Line { + Line() { } + Line(MemAddr addr, MemAddr code_size, int file_id, int source_line) + : address(addr) + , size(code_size) + , source_file_id(file_id) + , line(source_line) { } + + MemAddr address; + MemAddr size; + int32_t source_file_id; + int32_t line; +}; + +struct SourceLineResolverBase::Function { + Function() { } + Function(const string &function_name, + MemAddr function_address, + MemAddr code_size, + int set_parameter_size, + bool is_multiple) + : name(function_name), address(function_address), size(code_size), + parameter_size(set_parameter_size), is_multiple(is_multiple) { } + + string name; + MemAddr address; + MemAddr size; + + // The size of parameters passed to this function on the stack. + int32_t parameter_size; + + // If the function's instructions correspond to multiple symbols. + bool is_multiple; +}; + +struct SourceLineResolverBase::PublicSymbol { + PublicSymbol() { } + PublicSymbol(const string& set_name, + MemAddr set_address, + int set_parameter_size, + bool is_multiple) + : name(set_name), + address(set_address), + parameter_size(set_parameter_size), + is_multiple(is_multiple) {} + + string name; + MemAddr address; + + // If the public symbol is used as a function entry point, parameter_size + // is set to the size of the parameters passed to the funciton on the + // stack, if known. + int32_t parameter_size; + + // If the function's instructions correspond to multiple symbols. + bool is_multiple; +}; + +class SourceLineResolverBase::Module { + public: + virtual ~Module() { }; + // Loads a map from the given buffer in char* type. + // Does NOT take ownership of memory_buffer (the caller, source line resolver, + // is the owner of memory_buffer). + // The passed in |memory buffer| is of size |memory_buffer_size|. If it is + // not null terminated, LoadMapFromMemory will null terminate it by modifying + // the passed in buffer. + virtual bool LoadMapFromMemory(char *memory_buffer, + size_t memory_buffer_size) = 0; + + // Tells whether the loaded symbol data is corrupt. Return value is + // undefined, if the symbol data hasn't been loaded yet. + virtual bool IsCorrupt() const = 0; + + // Looks up the given relative address, and fills the StackFrame struct + // with the result. + virtual void LookupAddress(StackFrame *frame) const = 0; + + // If Windows stack walking information is available covering ADDRESS, + // return a WindowsFrameInfo structure describing it. If the information + // is not available, returns NULL. A NULL return value does not indicate + // an error. The caller takes ownership of any returned WindowsFrameInfo + // object. + virtual WindowsFrameInfo * + FindWindowsFrameInfo(const StackFrame *frame) const = 0; + + // If CFI stack walking information is available covering ADDRESS, + // return a CFIFrameInfo structure describing it. If the information + // is not available, return NULL. The caller takes ownership of any + // returned CFIFrameInfo object. + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) const = 0; + protected: + virtual bool ParseCFIRuleSet(const string &rule_set, + CFIFrameInfo *frame_info) const; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_cpu.cc b/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_cpu.cc new file mode 100644 index 0000000000..6175dc7f26 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_cpu.cc @@ -0,0 +1,79 @@ +// Copyright 2013 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. +// +// See google_breakpad/processor/stack_frame_cpu.h for documentation. +// +// Author: Colin Blundell + +#include "google_breakpad/processor/stack_frame_cpu.h" + +namespace google_breakpad { + +const uint64_t StackFrameARM64::CONTEXT_VALID_X0; +const uint64_t StackFrameARM64::CONTEXT_VALID_X1; +const uint64_t StackFrameARM64::CONTEXT_VALID_X2; +const uint64_t StackFrameARM64::CONTEXT_VALID_X3; +const uint64_t StackFrameARM64::CONTEXT_VALID_X4; +const uint64_t StackFrameARM64::CONTEXT_VALID_X5; +const uint64_t StackFrameARM64::CONTEXT_VALID_X6; +const uint64_t StackFrameARM64::CONTEXT_VALID_X7; +const uint64_t StackFrameARM64::CONTEXT_VALID_X8; +const uint64_t StackFrameARM64::CONTEXT_VALID_X9; +const uint64_t StackFrameARM64::CONTEXT_VALID_X10; +const uint64_t StackFrameARM64::CONTEXT_VALID_X11; +const uint64_t StackFrameARM64::CONTEXT_VALID_X12; +const uint64_t StackFrameARM64::CONTEXT_VALID_X13; +const uint64_t StackFrameARM64::CONTEXT_VALID_X14; +const uint64_t StackFrameARM64::CONTEXT_VALID_X15; +const uint64_t StackFrameARM64::CONTEXT_VALID_X16; +const uint64_t StackFrameARM64::CONTEXT_VALID_X17; +const uint64_t StackFrameARM64::CONTEXT_VALID_X18; +const uint64_t StackFrameARM64::CONTEXT_VALID_X19; +const uint64_t StackFrameARM64::CONTEXT_VALID_X20; +const uint64_t StackFrameARM64::CONTEXT_VALID_X21; +const uint64_t StackFrameARM64::CONTEXT_VALID_X22; +const uint64_t StackFrameARM64::CONTEXT_VALID_X23; +const uint64_t StackFrameARM64::CONTEXT_VALID_X24; +const uint64_t StackFrameARM64::CONTEXT_VALID_X25; +const uint64_t StackFrameARM64::CONTEXT_VALID_X26; +const uint64_t StackFrameARM64::CONTEXT_VALID_X27; +const uint64_t StackFrameARM64::CONTEXT_VALID_X28; +const uint64_t StackFrameARM64::CONTEXT_VALID_X29; +const uint64_t StackFrameARM64::CONTEXT_VALID_X30; +const uint64_t StackFrameARM64::CONTEXT_VALID_X31; +const uint64_t StackFrameARM64::CONTEXT_VALID_X32; +const uint64_t StackFrameARM64::CONTEXT_VALID_FP; +const uint64_t StackFrameARM64::CONTEXT_VALID_LR; +const uint64_t StackFrameARM64::CONTEXT_VALID_SP; +const uint64_t StackFrameARM64::CONTEXT_VALID_PC; +const uint64_t StackFrameARM64::CONTEXT_VALID_ALL; + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_symbolizer.cc b/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_symbolizer.cc new file mode 100644 index 0000000000..504971c17a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stack_frame_symbolizer.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2012 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. + +// Implementation of StackFrameSymbolizer, which encapsulates the logic of how +// SourceLineResolverInterface interacts with SymbolSupplier to fill source +// line information in a stack frame, and also looks up WindowsFrameInfo or +// CFIFrameInfo for a stack frame. + +#include "google_breakpad/processor/stack_frame_symbolizer.h" + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/symbol_supplier.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" + +namespace google_breakpad { + +StackFrameSymbolizer::StackFrameSymbolizer( + SymbolSupplier* supplier, + SourceLineResolverInterface* resolver) : supplier_(supplier), + resolver_(resolver) { } + +StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo( + const CodeModules* modules, + const CodeModules* unloaded_modules, + const SystemInfo* system_info, + StackFrame* frame) { + assert(frame); + + const CodeModule* module = NULL; + if (modules) { + module = modules->GetModuleForAddress(frame->instruction); + } + if (!module && unloaded_modules) { + module = unloaded_modules->GetModuleForAddress(frame->instruction); + } + + if (!module) return kError; + frame->module = module; + + if (!resolver_) return kError; // no resolver. + // If module is known to have missing symbol file, return. + if (no_symbol_modules_.find(module->code_file()) != + no_symbol_modules_.end()) { + return kError; + } + + // If module is already loaded, go ahead to fill source line info and return. + if (resolver_->HasModule(frame->module)) { + resolver_->FillSourceLineInfo(frame); + return resolver_->IsModuleCorrupt(frame->module) ? + kWarningCorruptSymbols : kNoError; + } + + // Module needs to fetch symbol file. First check to see if supplier exists. + if (!supplier_) { + return kError; + } + + // Start fetching symbol from supplier. + string symbol_file; + char* symbol_data = NULL; + size_t symbol_data_size; + SymbolSupplier::SymbolResult symbol_result = supplier_->GetCStringSymbolData( + module, system_info, &symbol_file, &symbol_data, &symbol_data_size); + + switch (symbol_result) { + case SymbolSupplier::FOUND: { + bool load_success = resolver_->LoadModuleUsingMemoryBuffer( + frame->module, + symbol_data, + symbol_data_size); + if (resolver_->ShouldDeleteMemoryBufferAfterLoadModule()) { + supplier_->FreeSymbolData(module); + } + + if (load_success) { + resolver_->FillSourceLineInfo(frame); + return resolver_->IsModuleCorrupt(frame->module) ? + kWarningCorruptSymbols : kNoError; + } else { + BPLOG(ERROR) << "Failed to load symbol file in resolver."; + no_symbol_modules_.insert(module->code_file()); + return kError; + } + } + + case SymbolSupplier::NOT_FOUND: + no_symbol_modules_.insert(module->code_file()); + return kError; + + case SymbolSupplier::INTERRUPT: + return kInterrupt; + + default: + BPLOG(ERROR) << "Unknown SymbolResult enum: " << symbol_result; + return kError; + } +} + +WindowsFrameInfo* StackFrameSymbolizer::FindWindowsFrameInfo( + const StackFrame* frame) { + return resolver_ ? resolver_->FindWindowsFrameInfo(frame) : NULL; +} + +CFIFrameInfo* StackFrameSymbolizer::FindCFIFrameInfo( + const StackFrame* frame) { + return resolver_ ? resolver_->FindCFIFrameInfo(frame) : NULL; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.cc new file mode 100644 index 0000000000..dc84352b61 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.cc @@ -0,0 +1,1036 @@ +// Copyright (c) 2010 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. + +// stackwalk_common.cc: Module shared by the {micro,mini}dump_stackwalck +// executables to print the content of dumps (w/ stack traces) on the console. +// +// Author: Mark Mentovai + +#include "processor/stackwalk_common.h" + +#include +#include +#include + +#include +#include + +#include "common/stdio_wrapper.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" +#include "processor/pathname_stripper.h" + +namespace google_breakpad { + +namespace { + +using std::vector; + +// Separator character for machine readable output. +static const char kOutputSeparator = '|'; + +// PrintRegister prints a register's name and value to stdout. It will +// print four registers on a line. For the first register in a set, +// pass 0 for |start_col|. For registers in a set, pass the most recent +// return value of PrintRegister. +// The caller is responsible for printing the final newline after a set +// of registers is completely printed, regardless of the number of calls +// to PrintRegister. +static const int kMaxWidth = 80; // optimize for an 80-column terminal +static int PrintRegister(const char *name, uint32_t value, int start_col) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value); + + if (start_col + static_cast(strlen(buffer)) > kMaxWidth) { + start_col = 0; + printf("\n "); + } + fputs(buffer, stdout); + + return start_col + strlen(buffer); +} + +// PrintRegister64 does the same thing, but for 64-bit registers. +static int PrintRegister64(const char *name, uint64_t value, int start_col) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value); + + if (start_col + static_cast(strlen(buffer)) > kMaxWidth) { + start_col = 0; + printf("\n "); + } + fputs(buffer, stdout); + + return start_col + strlen(buffer); +} + +// StripSeparator takes a string |original| and returns a copy +// of the string with all occurences of |kOutputSeparator| removed. +static string StripSeparator(const string &original) { + string result = original; + string::size_type position = 0; + while ((position = result.find(kOutputSeparator, position)) != string::npos) { + result.erase(position, 1); + } + position = 0; + while ((position = result.find('\n', position)) != string::npos) { + result.erase(position, 1); + } + return result; +} + +// PrintStackContents prints the stack contents of the current frame to stdout. +static void PrintStackContents(const string &indent, + const StackFrame *frame, + const StackFrame *prev_frame, + const string &cpu, + const MemoryRegion *memory, + const CodeModules* modules, + SourceLineResolverInterface *resolver) { + // Find stack range. + int word_length = 0; + uint64_t stack_begin = 0, stack_end = 0; + if (cpu == "x86") { + word_length = 4; + const StackFrameX86 *frame_x86 = static_cast(frame); + const StackFrameX86 *prev_frame_x86 = + static_cast(prev_frame); + if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) && + (prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) { + stack_begin = frame_x86->context.esp; + stack_end = prev_frame_x86->context.esp; + } + } else if (cpu == "amd64") { + word_length = 8; + const StackFrameAMD64 *frame_amd64 = + static_cast(frame); + const StackFrameAMD64 *prev_frame_amd64 = + static_cast(prev_frame); + if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) && + (prev_frame_amd64->context_validity & + StackFrameAMD64::CONTEXT_VALID_RSP)) { + stack_begin = frame_amd64->context.rsp; + stack_end = prev_frame_amd64->context.rsp; + } + } else if (cpu == "arm") { + word_length = 4; + const StackFrameARM *frame_arm = static_cast(frame); + const StackFrameARM *prev_frame_arm = + static_cast(prev_frame); + if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) && + (prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { + stack_begin = frame_arm->context.iregs[13]; + stack_end = prev_frame_arm->context.iregs[13]; + } + } else if (cpu == "arm64") { + word_length = 8; + const StackFrameARM64 *frame_arm64 = + static_cast(frame); + const StackFrameARM64 *prev_frame_arm64 = + static_cast(prev_frame); + if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) && + (prev_frame_arm64->context_validity & + StackFrameARM64::CONTEXT_VALID_SP)) { + stack_begin = frame_arm64->context.iregs[31]; + stack_end = prev_frame_arm64->context.iregs[31]; + } + } + if (!word_length || !stack_begin || !stack_end) + return; + + // Print stack contents. + printf("\n%sStack contents:", indent.c_str()); + for(uint64_t address = stack_begin; address < stack_end; ) { + // Print the start address of this row. + if (word_length == 4) + printf("\n%s %08x", indent.c_str(), static_cast(address)); + else + printf("\n%s %016" PRIx64, indent.c_str(), address); + + // Print data in hex. + const int kBytesPerRow = 16; + string data_as_string; + for (int i = 0; i < kBytesPerRow; ++i, ++address) { + uint8_t value = 0; + if (address < stack_end && + memory->GetMemoryAtAddress(address, &value)) { + printf(" %02x", value); + data_as_string.push_back(isprint(value) ? value : '.'); + } else { + printf(" "); + data_as_string.push_back(' '); + } + } + // Print data as string. + printf(" %s", data_as_string.c_str()); + } + + // Try to find instruction pointers from stack. + printf("\n%sPossible instruction pointers:\n", indent.c_str()); + for (uint64_t address = stack_begin; address < stack_end; + address += word_length) { + StackFrame pointee_frame; + + // Read a word (possible instruction pointer) from stack. + if (word_length == 4) { + uint32_t data32 = 0; + memory->GetMemoryAtAddress(address, &data32); + pointee_frame.instruction = data32; + } else { + uint64_t data64 = 0; + memory->GetMemoryAtAddress(address, &data64); + pointee_frame.instruction = data64; + } + pointee_frame.module = + modules->GetModuleForAddress(pointee_frame.instruction); + + // Try to look up the function name. + if (pointee_frame.module) + resolver->FillSourceLineInfo(&pointee_frame); + + // Print function name. + if (!pointee_frame.function_name.empty()) { + if (word_length == 4) { + printf("%s *(0x%08x) = 0x%08x", indent.c_str(), + static_cast(address), + static_cast(pointee_frame.instruction)); + } else { + printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, + indent.c_str(), address, pointee_frame.instruction); + } + printf(" <%s> [%s : %d + 0x%" PRIx64 "]\n", + pointee_frame.function_name.c_str(), + PathnameStripper::File(pointee_frame.source_file_name).c_str(), + pointee_frame.source_line, + pointee_frame.instruction - pointee_frame.source_line_base); + } + } + printf("\n"); +} + +// PrintStack prints the call stack in |stack| to stdout, in a reasonably +// useful form. Module, function, and source file names are displayed if +// they are available. The code offset to the base code address of the +// source line, function, or module is printed, preferring them in that +// order. If no source line, function, or module information is available, +// an absolute code offset is printed. +// +// If |cpu| is a recognized CPU name, relevant register state for each stack +// frame printed is also output, if available. +static void PrintStack(const CallStack *stack, + const string &cpu, + bool output_stack_contents, + const MemoryRegion* memory, + const CodeModules* modules, + SourceLineResolverInterface* resolver) { + int frame_count = stack->frames()->size(); + if (frame_count == 0) { + printf(" \n"); + } + for (int frame_index = 0; frame_index < frame_count; ++frame_index) { + const StackFrame *frame = stack->frames()->at(frame_index); + printf("%2d ", frame_index); + + uint64_t instruction_address = frame->ReturnAddress(); + + if (frame->module) { + printf("%s", PathnameStripper::File(frame->module->code_file()).c_str()); + if (!frame->function_name.empty()) { + printf("!%s", frame->function_name.c_str()); + if (!frame->source_file_name.empty()) { + string source_file = PathnameStripper::File(frame->source_file_name); + printf(" [%s : %d + 0x%" PRIx64 "]", + source_file.c_str(), + frame->source_line, + instruction_address - frame->source_line_base); + } else { + printf(" + 0x%" PRIx64, instruction_address - frame->function_base); + } + } else { + printf(" + 0x%" PRIx64, + instruction_address - frame->module->base_address()); + } + } else { + printf("0x%" PRIx64, instruction_address); + } + printf("\n "); + + int sequence = 0; + if (cpu == "x86") { + const StackFrameX86 *frame_x86 = + reinterpret_cast(frame); + + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) + sequence = PrintRegister("eip", frame_x86->context.eip, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) + sequence = PrintRegister("esp", frame_x86->context.esp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) + sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) + sequence = PrintRegister("esi", frame_x86->context.esi, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) + sequence = PrintRegister("edi", frame_x86->context.edi, sequence); + if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { + sequence = PrintRegister("eax", frame_x86->context.eax, sequence); + sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); + sequence = PrintRegister("edx", frame_x86->context.edx, sequence); + sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); + } + } else if (cpu == "ppc") { + const StackFramePPC *frame_ppc = + reinterpret_cast(frame); + + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) + sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); + } else if (cpu == "amd64") { + const StackFrameAMD64 *frame_amd64 = + reinterpret_cast(frame); + + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RAX) + sequence = PrintRegister64("rax", frame_amd64->context.rax, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDX) + sequence = PrintRegister64("rdx", frame_amd64->context.rdx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RCX) + sequence = PrintRegister64("rcx", frame_amd64->context.rcx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX) + sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSI) + sequence = PrintRegister64("rsi", frame_amd64->context.rsi, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RDI) + sequence = PrintRegister64("rdi", frame_amd64->context.rdi, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP) + sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) + sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R8) + sequence = PrintRegister64("r8", frame_amd64->context.r8, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R9) + sequence = PrintRegister64("r9", frame_amd64->context.r9, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R10) + sequence = PrintRegister64("r10", frame_amd64->context.r10, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R11) + sequence = PrintRegister64("r11", frame_amd64->context.r11, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12) + sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13) + sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14) + sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15) + sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence); + if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP) + sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence); + } else if (cpu == "sparc") { + const StackFrameSPARC *frame_sparc = + reinterpret_cast(frame); + + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP) + sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence); + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP) + sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence); + if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC) + sequence = PrintRegister("pc", frame_sparc->context.pc, sequence); + } else if (cpu == "arm") { + const StackFrameARM *frame_arm = + reinterpret_cast(frame); + + // Argument registers (caller-saves), which will likely only be valid + // for the youngest frame. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0) + sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1) + sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2) + sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3) + sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence); + + // General-purpose callee-saves registers. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4) + sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5) + sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6) + sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7) + sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8) + sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9) + sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10) + sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R12) + sequence = PrintRegister("r12", frame_arm->context.iregs[12], sequence); + + // Registers with a dedicated or conventional purpose. + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP) + sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) + sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR) + sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence); + if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC) + sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence); + } else if (cpu == "arm64") { + const StackFrameARM64 *frame_arm64 = + reinterpret_cast(frame); + + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X0) { + sequence = + PrintRegister64("x0", frame_arm64->context.iregs[0], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X1) { + sequence = + PrintRegister64("x1", frame_arm64->context.iregs[1], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X2) { + sequence = + PrintRegister64("x2", frame_arm64->context.iregs[2], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X3) { + sequence = + PrintRegister64("x3", frame_arm64->context.iregs[3], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X4) { + sequence = + PrintRegister64("x4", frame_arm64->context.iregs[4], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X5) { + sequence = + PrintRegister64("x5", frame_arm64->context.iregs[5], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X6) { + sequence = + PrintRegister64("x6", frame_arm64->context.iregs[6], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X7) { + sequence = + PrintRegister64("x7", frame_arm64->context.iregs[7], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X8) { + sequence = + PrintRegister64("x8", frame_arm64->context.iregs[8], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X9) { + sequence = + PrintRegister64("x9", frame_arm64->context.iregs[9], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X10) { + sequence = + PrintRegister64("x10", frame_arm64->context.iregs[10], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X11) { + sequence = + PrintRegister64("x11", frame_arm64->context.iregs[11], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X12) { + sequence = + PrintRegister64("x12", frame_arm64->context.iregs[12], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X13) { + sequence = + PrintRegister64("x13", frame_arm64->context.iregs[13], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X14) { + sequence = + PrintRegister64("x14", frame_arm64->context.iregs[14], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X15) { + sequence = + PrintRegister64("x15", frame_arm64->context.iregs[15], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X16) { + sequence = + PrintRegister64("x16", frame_arm64->context.iregs[16], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X17) { + sequence = + PrintRegister64("x17", frame_arm64->context.iregs[17], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X18) { + sequence = + PrintRegister64("x18", frame_arm64->context.iregs[18], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X19) { + sequence = + PrintRegister64("x19", frame_arm64->context.iregs[19], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X20) { + sequence = + PrintRegister64("x20", frame_arm64->context.iregs[20], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X21) { + sequence = + PrintRegister64("x21", frame_arm64->context.iregs[21], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X22) { + sequence = + PrintRegister64("x22", frame_arm64->context.iregs[22], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X23) { + sequence = + PrintRegister64("x23", frame_arm64->context.iregs[23], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X24) { + sequence = + PrintRegister64("x24", frame_arm64->context.iregs[24], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X25) { + sequence = + PrintRegister64("x25", frame_arm64->context.iregs[25], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X26) { + sequence = + PrintRegister64("x26", frame_arm64->context.iregs[26], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X27) { + sequence = + PrintRegister64("x27", frame_arm64->context.iregs[27], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_X28) { + sequence = + PrintRegister64("x28", frame_arm64->context.iregs[28], sequence); + } + + // Registers with a dedicated or conventional purpose. + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_FP) { + sequence = + PrintRegister64("fp", frame_arm64->context.iregs[29], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_LR) { + sequence = + PrintRegister64("lr", frame_arm64->context.iregs[30], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) { + sequence = + PrintRegister64("sp", frame_arm64->context.iregs[31], sequence); + } + if (frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_PC) { + sequence = + PrintRegister64("pc", frame_arm64->context.iregs[32], sequence); + } + } else if ((cpu == "mips") || (cpu == "mips64")) { + const StackFrameMIPS* frame_mips = + reinterpret_cast(frame); + + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_GP) + sequence = PrintRegister64("gp", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_GP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_SP) + sequence = PrintRegister64("sp", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_SP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_FP) + sequence = PrintRegister64("fp", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_FP], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_RA) + sequence = PrintRegister64("ra", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_RA], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_PC) + sequence = PrintRegister64("pc", frame_mips->context.epc, sequence); + + // Save registers s0-s7 + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S0) + sequence = PrintRegister64("s0", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S0], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S1) + sequence = PrintRegister64("s1", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S1], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S2) + sequence = PrintRegister64("s2", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S2], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S3) + sequence = PrintRegister64("s3", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S3], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S4) + sequence = PrintRegister64("s4", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S4], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S5) + sequence = PrintRegister64("s5", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S5], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S6) + sequence = PrintRegister64("s6", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S6], + sequence); + if (frame_mips->context_validity & StackFrameMIPS::CONTEXT_VALID_S7) + sequence = PrintRegister64("s7", + frame_mips->context.iregs[MD_CONTEXT_MIPS_REG_S7], + sequence); + } + printf("\n Found by: %s\n", frame->trust_description().c_str()); + + // Print stack contents. + if (output_stack_contents && frame_index + 1 < frame_count) { + const string indent(" "); + PrintStackContents(indent, frame, stack->frames()->at(frame_index + 1), + cpu, memory, modules, resolver); + } + } +} + +// PrintStackMachineReadable prints the call stack in |stack| to stdout, +// in the following machine readable pipe-delimited text format: +// thread number|frame number|module|function|source file|line|offset +// +// Module, function, source file, and source line may all be empty +// depending on availability. The code offset follows the same rules as +// PrintStack above. +static void PrintStackMachineReadable(int thread_num, const CallStack *stack) { + int frame_count = stack->frames()->size(); + for (int frame_index = 0; frame_index < frame_count; ++frame_index) { + const StackFrame *frame = stack->frames()->at(frame_index); + printf("%d%c%d%c", thread_num, kOutputSeparator, frame_index, + kOutputSeparator); + + uint64_t instruction_address = frame->ReturnAddress(); + + if (frame->module) { + assert(!frame->module->code_file().empty()); + printf("%s", StripSeparator(PathnameStripper::File( + frame->module->code_file())).c_str()); + if (!frame->function_name.empty()) { + printf("%c%s", kOutputSeparator, + StripSeparator(frame->function_name).c_str()); + if (!frame->source_file_name.empty()) { + printf("%c%s%c%d%c0x%" PRIx64, + kOutputSeparator, + StripSeparator(frame->source_file_name).c_str(), + kOutputSeparator, + frame->source_line, + kOutputSeparator, + instruction_address - frame->source_line_base); + } else { + printf("%c%c%c0x%" PRIx64, + kOutputSeparator, // empty source file + kOutputSeparator, // empty source line + kOutputSeparator, + instruction_address - frame->function_base); + } + } else { + printf("%c%c%c%c0x%" PRIx64, + kOutputSeparator, // empty function name + kOutputSeparator, // empty source file + kOutputSeparator, // empty source line + kOutputSeparator, + instruction_address - frame->module->base_address()); + } + } else { + // the printf before this prints a trailing separator for module name + printf("%c%c%c%c0x%" PRIx64, + kOutputSeparator, // empty function name + kOutputSeparator, // empty source file + kOutputSeparator, // empty source line + kOutputSeparator, + instruction_address); + } + printf("\n"); + } +} + +// ContainsModule checks whether a given |module| is in the vector +// |modules_without_symbols|. +static bool ContainsModule( + const vector *modules, + const CodeModule *module) { + assert(modules); + assert(module); + vector::const_iterator iter; + for (iter = modules->begin(); iter != modules->end(); ++iter) { + if (module->debug_file().compare((*iter)->debug_file()) == 0 && + module->debug_identifier().compare((*iter)->debug_identifier()) == 0) { + return true; + } + } + return false; +} + +// PrintModule prints a single |module| to stdout. +// |modules_without_symbols| should contain the list of modules that were +// confirmed to be missing their symbols during the stack walk. +static void PrintModule( + const CodeModule *module, + const vector *modules_without_symbols, + const vector *modules_with_corrupt_symbols, + uint64_t main_address) { + string symbol_issues; + if (ContainsModule(modules_without_symbols, module)) { + symbol_issues = " (WARNING: No symbols, " + + PathnameStripper::File(module->debug_file()) + ", " + + module->debug_identifier() + ")"; + } else if (ContainsModule(modules_with_corrupt_symbols, module)) { + symbol_issues = " (WARNING: Corrupt symbols, " + + PathnameStripper::File(module->debug_file()) + ", " + + module->debug_identifier() + ")"; + } + uint64_t base_address = module->base_address(); + printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s%s\n", + base_address, base_address + module->size() - 1, + PathnameStripper::File(module->code_file()).c_str(), + module->version().empty() ? "???" : module->version().c_str(), + main_address != 0 && base_address == main_address ? " (main)" : "", + symbol_issues.c_str()); +} + +// PrintModules prints the list of all loaded |modules| to stdout. +// |modules_without_symbols| should contain the list of modules that were +// confirmed to be missing their symbols during the stack walk. +static void PrintModules( + const CodeModules *modules, + const vector *modules_without_symbols, + const vector *modules_with_corrupt_symbols) { + if (!modules) + return; + + printf("\n"); + printf("Loaded modules:\n"); + + uint64_t main_address = 0; + const CodeModule *main_module = modules->GetMainModule(); + if (main_module) { + main_address = main_module->base_address(); + } + + unsigned int module_count = modules->module_count(); + for (unsigned int module_sequence = 0; + module_sequence < module_count; + ++module_sequence) { + const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols, + main_address); + } +} + +// PrintModulesMachineReadable outputs a list of loaded modules, +// one per line, in the following machine-readable pipe-delimited +// text format: +// Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}| +// {Base Address}|{Max Address}|{Main} +static void PrintModulesMachineReadable(const CodeModules *modules) { + if (!modules) + return; + + uint64_t main_address = 0; + const CodeModule *main_module = modules->GetMainModule(); + if (main_module) { + main_address = main_module->base_address(); + } + + unsigned int module_count = modules->module_count(); + for (unsigned int module_sequence = 0; + module_sequence < module_count; + ++module_sequence) { + const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + uint64_t base_address = module->base_address(); + printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n", + kOutputSeparator, + StripSeparator(PathnameStripper::File(module->code_file())).c_str(), + kOutputSeparator, StripSeparator(module->version()).c_str(), + kOutputSeparator, + StripSeparator(PathnameStripper::File(module->debug_file())).c_str(), + kOutputSeparator, + StripSeparator(module->debug_identifier()).c_str(), + kOutputSeparator, base_address, + kOutputSeparator, base_address + module->size() - 1, + kOutputSeparator, + main_module != NULL && base_address == main_address ? 1 : 0); + } +} + +// PrintUnloadedModulesMachineReadable outputs a list of loaded modules, +// one per line, in the following machine-readable pipe-delimited +// text format: +// UnloadedModule|{Module Filename}|{Base Address}|{Max Address}|{Main} +static void PrintUnloadedModulesMachineReadable(const CodeModules* modules) { + if (!modules) + return; + + uint64_t main_address = 0; + const CodeModule* main_module = modules->GetMainModule(); + if (main_module) { + main_address = main_module->base_address(); + } + + unsigned int module_count = modules->module_count(); + for (unsigned int module_sequence = 0; + module_sequence < module_count; + ++module_sequence) { + const CodeModule* module = modules->GetModuleAtSequence(module_sequence); + uint64_t base_address = module->base_address(); + printf("UnloadedModule%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n", + kOutputSeparator, + StripSeparator(PathnameStripper::File(module->code_file())).c_str(), + kOutputSeparator, base_address, + kOutputSeparator, base_address + module->size() - 1, + kOutputSeparator, + main_module != NULL && base_address == main_address ? 1 : 0); + } +} + +} // namespace + +void PrintProcessState(const ProcessState& process_state, + bool output_stack_contents, + SourceLineResolverInterface* resolver) { + // Print OS and CPU information. + string cpu = process_state.system_info()->cpu; + string cpu_info = process_state.system_info()->cpu_info; + printf("Operating system: %s\n", process_state.system_info()->os.c_str()); + printf(" %s\n", + process_state.system_info()->os_version.c_str()); + printf("CPU: %s\n", cpu.c_str()); + if (!cpu_info.empty()) { + // This field is optional. + printf(" %s\n", cpu_info.c_str()); + } + printf(" %d CPU%s\n", + process_state.system_info()->cpu_count, + process_state.system_info()->cpu_count != 1 ? "s" : ""); + printf("\n"); + + // Print GPU information + string gl_version = process_state.system_info()->gl_version; + string gl_vendor = process_state.system_info()->gl_vendor; + string gl_renderer = process_state.system_info()->gl_renderer; + printf("GPU:"); + if (!gl_version.empty() || !gl_vendor.empty() || !gl_renderer.empty()) { + printf(" %s\n", gl_version.c_str()); + printf(" %s\n", gl_vendor.c_str()); + printf(" %s\n", gl_renderer.c_str()); + } else { + printf(" UNKNOWN\n"); + } + printf("\n"); + + // Print crash information. + if (process_state.crashed()) { + printf("Crash reason: %s\n", process_state.crash_reason().c_str()); + printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address()); + } else { + printf("No crash\n"); + } + + string assertion = process_state.assertion(); + if (!assertion.empty()) { + printf("Assertion: %s\n", assertion.c_str()); + } + + // Compute process uptime if the process creation and crash times are + // available in the dump. + if (process_state.time_date_stamp() != 0 && + process_state.process_create_time() != 0 && + process_state.time_date_stamp() >= process_state.process_create_time()) { + printf("Process uptime: %d seconds\n", + process_state.time_date_stamp() - + process_state.process_create_time()); + } else { + printf("Process uptime: not available\n"); + } + + if (!process_state.mac_crash_info().empty()) { + printf("\n"); + printf("Application-specific information:\n"); + printf("%s", process_state.mac_crash_info().c_str()); + } + + // If the thread that requested the dump is known, print it first. + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { + const CallStack* requesting_thread_callstack = + process_state.threads()->at(requesting_thread); + printf("\n" + "Thread %d tid %u (%s)", + requesting_thread, + requesting_thread_callstack->tid(), + process_state.crashed() ? "crashed" : + "requested dump, did not crash"); + if (!requesting_thread_callstack->name().empty()) { + printf(" - %s", requesting_thread_callstack->name().c_str()); + } + PrintStack(requesting_thread_callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(requesting_thread), + process_state.modules(), resolver); + } + + // Print all of the threads in the dump. + int thread_count = process_state.threads()->size(); + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + const CallStack* callstack = process_state.threads()->at(thread_index); + printf("\n" + "Thread %d tid %u", thread_index, callstack->tid()); + if (!callstack->name().empty()) { + printf(" - %s", callstack->name().c_str()); + } + printf("\n"); + PrintStack(callstack, cpu, + output_stack_contents, + process_state.thread_memory_regions()->at(thread_index), + process_state.modules(), resolver); + } + } + + PrintModules(process_state.modules(), + process_state.modules_without_symbols(), + process_state.modules_with_corrupt_symbols()); +} + +void PrintProcessStateMachineReadable(const ProcessState& process_state) { + // Print OS and CPU information. + // OS|{OS Name}|{OS Version} + // CPU|{CPU Name}|{CPU Info}|{Number of CPUs} + // GPU|{GPU version}|{GPU vendor}|{GPU renderer} + printf("OS%c%s%c%s\n", kOutputSeparator, + StripSeparator(process_state.system_info()->os).c_str(), + kOutputSeparator, + StripSeparator(process_state.system_info()->os_version).c_str()); + printf("CPU%c%s%c%s%c%d\n", kOutputSeparator, + StripSeparator(process_state.system_info()->cpu).c_str(), + kOutputSeparator, + // this may be empty + StripSeparator(process_state.system_info()->cpu_info).c_str(), + kOutputSeparator, + process_state.system_info()->cpu_count); + printf("GPU%c%s%c%s%c%s\n", kOutputSeparator, + StripSeparator(process_state.system_info()->gl_version).c_str(), + kOutputSeparator, + StripSeparator(process_state.system_info()->gl_vendor).c_str(), + kOutputSeparator, + StripSeparator(process_state.system_info()->gl_renderer).c_str()); + + int requesting_thread = process_state.requesting_thread(); + + // Print crash information. + // Crash|{Crash Reason}|{Crash Address}|{Crashed Thread} + printf("Crash%c", kOutputSeparator); + if (process_state.crashed()) { + printf("%s%c0x%" PRIx64 "%c", + StripSeparator(process_state.crash_reason()).c_str(), + kOutputSeparator, process_state.crash_address(), kOutputSeparator); + } else { + // print assertion info, if available, in place of crash reason, + // instead of the unhelpful "No crash" + string assertion = process_state.assertion(); + if (!assertion.empty()) { + printf("%s%c%c", StripSeparator(assertion).c_str(), + kOutputSeparator, kOutputSeparator); + } else { + printf("No crash%c%c", kOutputSeparator, kOutputSeparator); + } + } + + if (requesting_thread != -1) { + printf("%d\n", requesting_thread); + } else { + printf("\n"); + } + + const crash_info_record_t* crash_info_records = + process_state.mac_crash_info_records(); + size_t num_records = + process_state.mac_crash_info_records_count(); + for (size_t i = 0; i < num_records; ++i) { + char thread_str[32]; + if (crash_info_records[i].thread) { + snprintf(thread_str, sizeof(thread_str), "0x%llx", + crash_info_records[i].thread); + } else { + strncpy(thread_str, "0", sizeof(thread_str)); + } + char dialog_mode_str[32]; + if (crash_info_records[i].dialog_mode) { + snprintf(dialog_mode_str, sizeof(dialog_mode_str), "0x%x", + crash_info_records[i].dialog_mode); + } else { + strncpy(dialog_mode_str, "0", sizeof(dialog_mode_str)); + } + char abort_cause_str[32]; + if (crash_info_records[i].abort_cause) { + snprintf(abort_cause_str, sizeof(abort_cause_str), "%lld", + crash_info_records[i].abort_cause); + } else { + strncpy(abort_cause_str, "0", sizeof(abort_cause_str)); + } + printf("MacCrashInfo%c%s%c%lu%c%s%c%s%c%s%c%s%c%s%c%s%c%s\n", + kOutputSeparator, crash_info_records[i].module_path.c_str(), + kOutputSeparator, crash_info_records[i].version, + kOutputSeparator, crash_info_records[i].message.c_str(), + kOutputSeparator, crash_info_records[i].signature_string.c_str(), + kOutputSeparator, crash_info_records[i].backtrace.c_str(), + kOutputSeparator, crash_info_records[i].message2.c_str(), + kOutputSeparator, thread_str, + kOutputSeparator, dialog_mode_str, + kOutputSeparator, abort_cause_str); + } + + PrintModulesMachineReadable(process_state.modules()); + PrintUnloadedModulesMachineReadable(process_state.unloaded_modules()); + + // blank line to indicate start of threads + printf("\n"); + + // If the thread that requested the dump is known, print it first. + if (requesting_thread != -1) { + PrintStackMachineReadable(requesting_thread, + process_state.threads()->at(requesting_thread)); + } + + // Print all of the threads in the dump. + int thread_count = process_state.threads()->size(); + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + PrintStackMachineReadable(thread_index, + process_state.threads()->at(thread_index)); + } + } +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.h new file mode 100644 index 0000000000..a74f7b6da1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalk_common.h @@ -0,0 +1,49 @@ +// Copyright (c) 2010 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. + +// stackwalk_common.cc: Module shared by the {micro,mini}dump_stackwalck +// executables to print the content of dumps (w/ stack traces) on the console. + + +#ifndef PROCESSOR_STACKWALK_COMMON_H__ +#define PROCESSOR_STACKWALK_COMMON_H__ + +namespace google_breakpad { + +class ProcessState; +class SourceLineResolverInterface; + +void PrintProcessStateMachineReadable(const ProcessState& process_state); +void PrintProcessState(const ProcessState& process_state, + bool output_stack_contents, + SourceLineResolverInterface* resolver); + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALK_COMMON_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc new file mode 100644 index 0000000000..4988ef1eb8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker.cc @@ -0,0 +1,333 @@ +// Copyright (c) 2010 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.cc: Generic stackwalker. +// +// See stackwalker.h for documentation. +// +// Author: Mark Mentovai + +#include "google_breakpad/processor/stackwalker.h" + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/linked_ptr.h" +#include "processor/logging.h" +#include "processor/stackwalker_ppc.h" +#include "processor/stackwalker_ppc64.h" +#include "processor/stackwalker_sparc.h" +#include "processor/stackwalker_x86.h" +#include "processor/stackwalker_amd64.h" +#include "processor/stackwalker_arm.h" +#include "processor/stackwalker_arm64.h" +#include "processor/stackwalker_mips.h" + +namespace google_breakpad { + +const int Stackwalker::kRASearchWords = 40; + +// This default is just a sanity check: a large enough value +// that allow capturing unbounded recursion traces, yet provide a +// guardrail against stack walking bugs. The stack walking invariants +// guarantee that the unwinding process is strictly monotonic and +// practically bounded by the size of the stack memory range. +uint32_t Stackwalker::max_frames_ = 1 << 20; // 1M +bool Stackwalker::max_frames_set_ = false; + +uint32_t Stackwalker::max_frames_scanned_ = 1 << 14; // 16k + +Stackwalker::Stackwalker(const SystemInfo* system_info, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer) + : system_info_(system_info), + memory_(memory), + modules_(modules), + unloaded_modules_(NULL), + frame_symbolizer_(frame_symbolizer) { + assert(frame_symbolizer_); +} + +void InsertSpecialAttentionModule( + StackFrameSymbolizer::SymbolizerResult symbolizer_result, + const CodeModule* module, + vector* modules) { + if (!module) { + return; + } + assert(symbolizer_result == StackFrameSymbolizer::kError || + symbolizer_result == StackFrameSymbolizer::kWarningCorruptSymbols); + bool found = false; + vector::iterator iter; + for (iter = modules->begin(); iter != modules->end(); ++iter) { + if (*iter == module) { + found = true; + break; + } + } + if (!found) { + BPLOG(INFO) << ((symbolizer_result == StackFrameSymbolizer::kError) ? + "Couldn't load symbols for: " : + "Detected corrupt symbols for: ") + << module->debug_file() << "|" << module->debug_identifier(); + modules->push_back(module); + } +} + +bool Stackwalker::Walk( + CallStack* stack, + vector* modules_without_symbols, + vector* modules_with_corrupt_symbols) { + BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|"; + assert(stack); + stack->Clear(); + + BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " + << "|modules_without_symbols|"; + BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires " + << "|modules_with_corrupt_symbols|"; + assert(modules_without_symbols); + assert(modules_with_corrupt_symbols); + + // Begin with the context frame, and keep getting callers until there are + // no more. + + // Keep track of the number of scanned or otherwise dubious frames seen + // so far, as the caller may have set a limit. + uint32_t scanned_frames = 0; + + // Take ownership of the pointer returned by GetContextFrame. + scoped_ptr frame(GetContextFrame()); + + while (frame.get()) { + // frame already contains a good frame with properly set instruction and + // frame_pointer fields. The frame structure comes from either the + // context frame (above) or a caller frame (below). + + // Resolve the module information, if a module map was provided. + StackFrameSymbolizer::SymbolizerResult symbolizer_result = + frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_, + system_info_, + frame.get()); + switch (symbolizer_result) { + case StackFrameSymbolizer::kInterrupt: + BPLOG(INFO) << "Stack walk is interrupted."; + return false; + break; + case StackFrameSymbolizer::kError: + InsertSpecialAttentionModule(symbolizer_result, frame->module, + modules_without_symbols); + break; + case StackFrameSymbolizer::kWarningCorruptSymbols: + InsertSpecialAttentionModule(symbolizer_result, frame->module, + modules_with_corrupt_symbols); + break; + case StackFrameSymbolizer::kNoError: + break; + default: + assert(false); + break; + } + + // Keep track of the number of dubious frames so far. + switch (frame.get()->trust) { + case StackFrame::FRAME_TRUST_NONE: + case StackFrame::FRAME_TRUST_SCAN: + case StackFrame::FRAME_TRUST_CFI_SCAN: + scanned_frames++; + break; + default: + break; + } + + // Add the frame to the call stack. Relinquish the ownership claim + // over the frame, because the stack now owns it. + stack->frames_.push_back(frame.release()); + if (stack->frames_.size() > max_frames_) { + // Only emit an error message in the case where the limit + // reached is the default limit, not set by the user. + if (!max_frames_set_) + BPLOG(ERROR) << "The stack is over " << max_frames_ << " frames."; + break; + } + + // Get the next frame and take ownership. + bool stack_scan_allowed = scanned_frames < max_frames_scanned_; + frame.reset(GetCallerFrame(stack, stack_scan_allowed)); + } + + return true; +} + +// static +Stackwalker* Stackwalker::StackwalkerForCPU( + const SystemInfo* system_info, + DumpContext* context, + MemoryRegion* memory, + const CodeModules* modules, + const CodeModules* unloaded_modules, + StackFrameSymbolizer* frame_symbolizer) { + if (!context) { + BPLOG(ERROR) << "Can't choose a stackwalker implementation without context"; + return NULL; + } + + Stackwalker* cpu_stackwalker = NULL; + + uint32_t cpu = context->GetContextCPU(); + switch (cpu) { + case MD_CONTEXT_X86: + cpu_stackwalker = new StackwalkerX86(system_info, + context->GetContextX86(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_PPC: + cpu_stackwalker = new StackwalkerPPC(system_info, + context->GetContextPPC(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_PPC64: + cpu_stackwalker = new StackwalkerPPC64(system_info, + context->GetContextPPC64(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_AMD64: + cpu_stackwalker = new StackwalkerAMD64(system_info, + context->GetContextAMD64(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_SPARC: + cpu_stackwalker = new StackwalkerSPARC(system_info, + context->GetContextSPARC(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_MIPS: + case MD_CONTEXT_MIPS64: + cpu_stackwalker = new StackwalkerMIPS(system_info, + context->GetContextMIPS(), + memory, modules, frame_symbolizer); + break; + + case MD_CONTEXT_ARM: + { + int fp_register = -1; + if (system_info->os_short == "ios") + fp_register = MD_CONTEXT_ARM_REG_IOS_FP; + cpu_stackwalker = new StackwalkerARM(system_info, + context->GetContextARM(), + fp_register, memory, modules, + frame_symbolizer); + break; + } + + case MD_CONTEXT_ARM64: + cpu_stackwalker = new StackwalkerARM64(system_info, + context->GetContextARM64(), + memory, modules, + frame_symbolizer); + break; + } + + BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) << + ", can't choose a stackwalker " + "implementation"; + if (cpu_stackwalker) { + cpu_stackwalker->unloaded_modules_ = unloaded_modules; + } + return cpu_stackwalker; +} + +// CONSIDER: check stack alignment? +bool Stackwalker::TerminateWalk(uint64_t caller_ip, + uint64_t caller_sp, + uint64_t callee_sp, + bool first_unwind) const { + // Treat an instruction address less than 4k as end-of-stack. + // (using InstructionAddressSeemsValid() here is very tempting, + // but we need to handle JITted code) + if (caller_ip < (1 << 12)) { + return true; + } + + // NOTE: The stack address range is implicitly checked + // when the stack memory is accessed. + + // The stack pointer should monotonically increase. For first unwind + // we allow caller_sp == callee_sp to account for architectures where + // the return address is stored in a register (so it's possible to have + // leaf functions which don't move the stack pointer) + if (first_unwind ? (caller_sp < callee_sp) : (caller_sp <= callee_sp)) { + return true; + } + + return false; +} + +bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) const { + StackFrame frame; + frame.instruction = address; + StackFrameSymbolizer::SymbolizerResult symbolizer_result = + frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_, + system_info_, &frame); + + if (!frame.module) { + // not inside any loaded module + return false; + } + + if (!frame_symbolizer_->HasImplementation()) { + // No valid implementation to symbolize stack frame, but the address is + // within a known module. + return true; + } + + if (symbolizer_result != StackFrameSymbolizer::kNoError && + symbolizer_result != StackFrameSymbolizer::kWarningCorruptSymbols) { + // Some error occurred during symbolization, but the address is within a + // known module + return true; + } + + return !frame.function_name.empty(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.cc new file mode 100644 index 0000000000..e81fec282c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2013 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_address_list.cc: a pseudo stack walker. +// +// See stackwalker_address_list.h for documentation. +// +// Author: Chris Hamilton + +#include + +#include + +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/logging.h" +#include "processor/stackwalker_address_list.h" + +namespace google_breakpad { + +StackwalkerAddressList::StackwalkerAddressList( + const uint64_t* frames, + size_t frame_count, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer) + : Stackwalker(NULL, NULL, modules, frame_symbolizer), + frames_(frames), + frame_count_(frame_count) { + assert(frames); + assert(frame_symbolizer); +} + +StackFrame* StackwalkerAddressList::GetContextFrame() { + if (frame_count_ == 0) + return NULL; + + StackFrame* frame = new StackFrame(); + frame->instruction = frames_[0]; + frame->trust = StackFrame::FRAME_TRUST_PREWALKED; + return frame; +} + +StackFrame* StackwalkerAddressList::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!stack) { + BPLOG(ERROR) << "Can't get caller frame without stack"; + return NULL; + } + + size_t frame_index = stack->frames()->size(); + + // There are no more frames to fetch. + if (frame_index >= frame_count_) + return NULL; + + // All frames have the highest level of trust because they were + // explicitly provided. + StackFrame* frame = new StackFrame(); + frame->instruction = frames_[frame_index]; + frame->trust = StackFrame::FRAME_TRUST_PREWALKED; + return frame; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.h new file mode 100644 index 0000000000..0f8c989efd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list.h @@ -0,0 +1,72 @@ +// Copyright (c) 2013 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_address_list.h: a pseudo stackwalker. +// +// Doesn't actually walk a stack, rather initializes a CallStack given an +// explicit list of already walked return addresses. +// +// Author: Chris Hamilton + +#ifndef PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ +#define PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ + +#include "common/basictypes.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/stackwalker.h" + +namespace google_breakpad { + +class CodeModules; + +class StackwalkerAddressList : public Stackwalker { + public: + // Initializes this stack walker with an explicit set of frame addresses. + // |modules| and |frame_symbolizer| are passed directly through to the base + // Stackwalker constructor. + StackwalkerAddressList(const uint64_t* frames, + size_t frame_count, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + private: + // Implementation of Stackwalker. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + const uint64_t* frames_; + size_t frame_count_; + + DISALLOW_COPY_AND_ASSIGN(StackwalkerAddressList); +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALKER_ADDRESS_LIST_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list_unittest.cc new file mode 100644 index 0000000000..ab4e9c0880 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_address_list_unittest.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2013, 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_address_list_unittest.cc: Unit tests for the +// StackwalkerAddressList class. +// +// Author: Chris Hamilton + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_address_list.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerAddressList; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::Return; +using testing::SetArgumentPointee; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +// Addresses and sizes of a couple dummy modules. +uint64_t kModule1Base = 0x40000000; +uint64_t kModule1Size = 0x10000; +uint64_t kModule2Base = 0x50000000; +uint64_t kModule2Size = 0x10000; + +// A handful of addresses that lie within the modules above. +const uint64_t kDummyFrames[] = { + 0x50003000, 0x50002000, 0x50001000, 0x40002000, 0x40001000 }; + +class StackwalkerAddressListTest : public testing::Test { + public: + StackwalkerAddressListTest() + : // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(kModule1Base, kModule1Size, "module1", "version1"), + module2(kModule2Base, kModule2Size, "module2", "version2") { + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule *module, const string &info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, NULL, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + void CheckCallStack(const CallStack& call_stack) { + const std::vector* frames = call_stack.frames(); + ASSERT_EQ(arraysize(kDummyFrames), frames->size()); + for (size_t i = 0; i < arraysize(kDummyFrames); ++i) { + ASSERT_EQ(kDummyFrames[i], frames->at(i)->instruction); + ASSERT_EQ(StackFrame::FRAME_TRUST_PREWALKED, frames->at(i)->trust); + } + ASSERT_EQ(static_cast(&module2), frames->at(0)->module); + ASSERT_EQ(static_cast(&module2), frames->at(1)->module); + ASSERT_EQ(static_cast(&module2), frames->at(2)->module); + ASSERT_EQ(static_cast(&module1), frames->at(3)->module); + ASSERT_EQ(static_cast(&module1), frames->at(4)->module); + } + + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; +}; + +TEST_F(StackwalkerAddressListTest, ScanWithoutSymbols) { + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAddressList walker(kDummyFrames, arraysize(kDummyFrames), + &modules, &frame_symbolizer); + + CallStack call_stack; + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + + // The stack starts in module2, so we expect that to be the first module + // found without symbols. + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module2", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module1", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0u, modules_with_corrupt_symbols.size()); + + ASSERT_NO_FATAL_FAILURE(CheckCallStack(call_stack)); +} + +TEST_F(StackwalkerAddressListTest, ScanWithSymbols) { + // File : FILE number(dex) name + // Function: FUNC address(hex) size(hex) parameter_size(hex) name + // Line : address(hex) size(hex) line(dec) filenum(dec) + SetModuleSymbols(&module2, + "FILE 1 module2.cc\n" + "FUNC 3000 100 10 mod2func3\n" + "3000 10 1 1\n" + "FUNC 2000 200 10 mod2func2\n" + "FUNC 1000 300 10 mod2func1\n"); + SetModuleSymbols(&module1, + "FUNC 2000 200 10 mod1func2\n" + "FUNC 1000 300 10 mod1func1\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAddressList walker(kDummyFrames, arraysize(kDummyFrames), + &modules, &frame_symbolizer); + + CallStack call_stack; + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + + ASSERT_EQ(0u, modules_without_symbols.size()); + ASSERT_EQ(0u, modules_with_corrupt_symbols.size()); + + ASSERT_NO_FATAL_FAILURE(CheckCallStack(call_stack)); + + const std::vector* frames = call_stack.frames(); + + // We have full file/line information for the first function call. + ASSERT_EQ("mod2func3", frames->at(0)->function_name); + ASSERT_EQ(0x50003000u, frames->at(0)->function_base); + ASSERT_EQ("module2.cc", frames->at(0)->source_file_name); + ASSERT_EQ(1, frames->at(0)->source_line); + ASSERT_EQ(0x50003000u, frames->at(0)->source_line_base); + + ASSERT_EQ("mod2func2", frames->at(1)->function_name); + ASSERT_EQ(0x50002000u, frames->at(1)->function_base); + + ASSERT_EQ("mod2func1", frames->at(2)->function_name); + ASSERT_EQ(0x50001000u, frames->at(2)->function_base); + + ASSERT_EQ("mod1func2", frames->at(3)->function_name); + ASSERT_EQ(0x40002000u, frames->at(3)->function_base); + + ASSERT_EQ("mod1func1", frames->at(4)->function_name); + ASSERT_EQ(0x40001000u, frames->at(4)->function_base); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.cc new file mode 100644 index 0000000000..d5ac6c652e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.cc @@ -0,0 +1,326 @@ +// Copyright (c) 2010 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.cc: amd64-specific stackwalker. +// +// See stackwalker_amd64.h for documentation. +// +// Author: Mark Mentovai, Ted Mielczarek + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/stackwalker_amd64.h" + +namespace google_breakpad { + + +const StackwalkerAMD64::CFIWalker::RegisterSet +StackwalkerAMD64::cfi_register_map_[] = { + // It may seem like $rip and $rsp are callee-saves, because the callee is + // responsible for having them restored upon return. But the callee_saves + // flags here really means that the walker should assume they're + // unchanged if the CFI doesn't mention them --- clearly wrong for $rip + // and $rsp. + { "$rax", NULL, false, + StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax }, + { "$rdx", NULL, false, + StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx }, + { "$rcx", NULL, false, + StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx }, + { "$rbx", NULL, true, + StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx }, + { "$rsi", NULL, false, + StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi }, + { "$rdi", NULL, false, + StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi }, + { "$rbp", NULL, true, + StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp }, + { "$rsp", ".cfa", false, + StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp }, + { "$r8", NULL, false, + StackFrameAMD64::CONTEXT_VALID_R8, &MDRawContextAMD64::r8 }, + { "$r9", NULL, false, + StackFrameAMD64::CONTEXT_VALID_R9, &MDRawContextAMD64::r9 }, + { "$r10", NULL, false, + StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 }, + { "$r11", NULL, false, + StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 }, + { "$r12", NULL, true, + StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 }, + { "$r13", NULL, true, + StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 }, + { "$r14", NULL, true, + StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 }, + { "$r15", NULL, true, + StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 }, + { "$rip", ".ra", false, + StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip }, +}; + +StackwalkerAMD64::StackwalkerAMD64(const SystemInfo* system_info, + const MDRawContextAMD64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), + cfi_walker_(cfi_register_map_, + (sizeof(cfi_register_map_) / sizeof(cfi_register_map_[0]))) { +} + +uint64_t StackFrameAMD64::ReturnAddress() const { + assert(context_validity & StackFrameAMD64::CONTEXT_VALID_RIP); + return context.rip; +} + +StackFrame* StackwalkerAMD64::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameAMD64* frame = new StackFrameAMD64(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFrameAMD64::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.rip; + + return frame; +} + +StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo( + const vector &frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameAMD64* last_frame = static_cast(frames.back()); + + scoped_ptr frame(new StackFrameAMD64()); + if (!cfi_walker_ + .FindCallerRegisters(*memory_, *cfi_frame_info, + last_frame->context, last_frame->context_validity, + &frame->context, &frame->context_validity)) + return NULL; + + // Make sure we recovered all the essentials. + static const int essentials = (StackFrameAMD64::CONTEXT_VALID_RIP + | StackFrameAMD64::CONTEXT_VALID_RSP); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +// Returns true if `ptr` is not in x86-64 canonical form. +// https://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details +static bool is_non_canonical(uint64_t ptr) { + return ptr > 0x7FFFFFFFFFFF && ptr < 0xFFFF800000000000; +} + +StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery( + const vector& frames) { + StackFrameAMD64* last_frame = static_cast(frames.back()); + uint64_t last_rbp = last_frame->context.rbp; + + // Assume the presence of a frame pointer. This is not mandated by the + // AMD64 ABI, c.f. section 3.2.2 footnote 7, though it is typical for + // compilers to still preserve the frame pointer and not treat %rbp as a + // general purpose register. + // + // With this assumption, the CALL instruction pushes the return address + // onto the stack and sets %rip to the procedure to enter. The procedure + // then establishes the stack frame with a prologue that PUSHes the current + // %rbp onto the stack, MOVes the current %rsp to %rbp, and then allocates + // space for any local variables. Using this procedure linking information, + // it is possible to locate frame information for the callee: + // + // %caller_rsp = *(%callee_rbp + 16) + // %caller_rip = *(%callee_rbp + 8) + // %caller_rbp = *(%callee_rbp) + + // If rbp is not 8-byte aligned it can't be a frame pointer. + if (last_rbp % 8 != 0) { + return NULL; + } + + uint64_t caller_rip, caller_rbp; + if (memory_->GetMemoryAtAddress(last_rbp + 8, &caller_rip) && + memory_->GetMemoryAtAddress(last_rbp, &caller_rbp)) { + uint64_t caller_rsp = last_rbp + 16; + + // If the recovered rip is not a canonical address it can't be + // the return address, so rbp must not have been a frame pointer. + if (is_non_canonical(caller_rip)) { + return NULL; + } + + // Check that rbp is within the right frame + if (caller_rsp <= last_rbp || caller_rbp < caller_rsp) { + return NULL; + } + + // Sanity check that resulting rbp is still inside stack memory. + uint64_t unused; + if (!memory_->GetMemoryAtAddress(caller_rbp, &unused)) { + return NULL; + } + + StackFrameAMD64* frame = new StackFrameAMD64(); + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.rip = caller_rip; + frame->context.rsp = caller_rsp; + frame->context.rbp = caller_rbp; + frame->context_validity = StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP; + return frame; + } + + return NULL; +} + +StackFrameAMD64* StackwalkerAMD64::GetCallerByStackScan( + const vector &frames) { + StackFrameAMD64* last_frame = static_cast(frames.back()); + uint64_t last_rsp = last_frame->context.rsp; + uint64_t caller_rip_address, caller_rip; + + if (!ScanForReturnAddress(last_rsp, &caller_rip_address, &caller_rip, + frames.size() == 1 /* is_context_frame */)) { + // No plausible return address was found. + return NULL; + } + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameAMD64* frame = new StackFrameAMD64(); + + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.rip = caller_rip; + // The caller's %rsp is directly underneath the return address pushed by + // the call. + frame->context.rsp = caller_rip_address + 8; + frame->context_validity = StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP; + + // Other unwinders give up if they don't have an %rbp value, so see if we + // can pass some plausible value on. + if (last_frame->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP) { + // Functions typically push their caller's %rbp immediately upon entry, + // and then set %rbp to point to that. So if the callee's %rbp is + // pointing to the first word below the alleged return address, presume + // that the caller's %rbp is saved there. + if (caller_rip_address - 8 == last_frame->context.rbp) { + uint64_t caller_rbp = 0; + if (memory_->GetMemoryAtAddress(last_frame->context.rbp, &caller_rbp) && + caller_rbp > caller_rip_address) { + frame->context.rbp = caller_rbp; + frame->context_validity |= StackFrameAMD64::CONTEXT_VALID_RBP; + } + } else if (last_frame->context.rbp >= caller_rip_address + 8) { + // If the callee's %rbp is plausible as a value for the caller's + // %rbp, presume that the callee left it unchanged. + frame->context.rbp = last_frame->context.rbp; + frame->context_validity |= StackFrameAMD64::CONTEXT_VALID_RBP; + } + } + + return frame; +} + +StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector &frames = *stack->frames(); + StackFrameAMD64* last_frame = static_cast(frames.back()); + scoped_ptr new_frame; + + // If we have DWARF CFI information, use it. + scoped_ptr cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If CFI was not available or failed, try using frame pointer recovery. + if (!new_frame.get()) { + new_frame.reset(GetCallerByFramePointerRecovery(frames)); + } + + // If all else fails, fall back to stack scanning. + if (stack_scan_allowed && !new_frame.get()) { + new_frame.reset(GetCallerByStackScan(frames)); + } + + // If nothing worked, tell the caller. + if (!new_frame.get()) + return NULL; + + if (system_info_->os_short == "nacl") { + // Apply constraints from Native Client's x86-64 sandbox. These + // registers have the 4GB-aligned sandbox base address (from r15) + // added to them, and only the bottom 32 bits are relevant for + // stack walking. + new_frame->context.rip = static_cast(new_frame->context.rip); + new_frame->context.rsp = static_cast(new_frame->context.rsp); + new_frame->context.rbp = static_cast(new_frame->context.rbp); + } + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(new_frame->context.rip, new_frame->context.rsp, + last_frame->context.rsp, frames.size() == 1)) { + return NULL; + } + + // new_frame->context.rip is the return address, which is the instruction + // after the CALL that caused us to arrive at the callee. Set + // new_frame->instruction to one less than that, so it points within the + // CALL instruction. See StackFrame::instruction for details, and + // StackFrameAMD64::ReturnAddress. + new_frame->instruction = new_frame->context.rip - 1; + + return new_frame.release(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.h new file mode 100644 index 0000000000..8f3dbd5280 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64.h @@ -0,0 +1,108 @@ +// Copyright (c) 2010 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 + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/cfi_frame_info.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, + StackFrameSymbolizer* frame_symbolizer); + + private: + // A STACK CFI-driven frame walker for the AMD64 + typedef SimpleCFIWalker CFIWalker; + + // 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, + bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameAMD64* GetCallerByCFIFrameInfo(const vector &frames, + CFIFrameInfo* cfi_frame_info); + + // Assumes a traditional frame layout where the frame pointer has not been + // omitted. The expectation is that caller's %rbp is pushed to the stack + // after the return address of the callee, and that the callee's %rsp can + // be used to find the pushed %rbp. + // Caller owns the returned frame object. Returns NULL on failure. + StackFrameAMD64* GetCallerByFramePointerRecovery( + const vector& frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameAMD64* GetCallerByStackScan(const vector &frames); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextAMD64* context_; + + // Our register map, for cfi_walker_. + static const CFIWalker::RegisterSet cfi_register_map_[]; + + // Our CFI frame walker. + const CFIWalker cfi_walker_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_AMD64_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64_unittest.cc new file mode 100644 index 0000000000..efcd812a35 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_amd64_unittest.cc @@ -0,0 +1,934 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// stackwalker_amd64_unittest.cc: Unit tests for StackwalkerAMD64 class. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_amd64.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameAMD64; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerAMD64; +using google_breakpad::SystemInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerAMD64Fixture { + public: + StackwalkerAMD64Fixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x00007400c0000000ULL, 0x10000, "module1", "version1"), + module2(0x00007500b0000000ULL, 0x10000, "module2", "version2") { + // Identify the system as a Linux system. + system_info.os = "Linux"; + system_info.os_short = "linux"; + system_info.os_version = "Horrendous Hippo"; + system_info.cpu = "x86"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule *module, const string &info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextAMD64 *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextAMD64 raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector *frames; +}; + +class GetContextFrame: public StackwalkerAMD64Fixture, public Test { }; + +class SanityCheck: public StackwalkerAMD64Fixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + // There should be no references to the stack in this walk: we don't + // provide any call frame information, so trying to reconstruct the + // context frame's caller should fail. So there's no need for us to + // provide stack contents. + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = 0x8000000080000000ULL; + + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_GE(1U, frames->size()); + StackFrameAMD64 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +TEST_F(GetContextFrame, Simple) { + // There should be no references to the stack in this walk: we don't + // provide any call frame information, so trying to reconstruct the + // context frame's caller should fail. So there's no need for us to + // provide stack contents. + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = 0x8000000080000000ULL; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_GE(1U, frames->size()); + StackFrameAMD64 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = 0x8000000080000000ULL; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_GE(1U, frames->size()); + StackFrameAMD64 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerAMD64Fixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address1 = 0x00007500b0000100ULL; + uint64_t return_address2 = 0x00007500b0000900ULL; + Label frame1_sp, frame2_sp, frame1_rbp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // junk that's not + .D64(0x00007500d0000000ULL) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // more junk + .D64(0x00007500d0000000ULL) + + .Mark(&frame1_rbp) + .D64(stack_section.start()) // This is in the right place to be + // a saved rbp, but it's bogus, so + // we shouldn't report it. + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame1_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.rip); + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); + + StackFrameAMD64 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.rip); + EXPECT_EQ(frame2_sp.Value(), frame2->context.rsp); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address = 0x00007500b0000110ULL; + Label frame1_sp, frame1_rbp; + + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // junk that's not + .D64(0x00007500b0000000ULL) // a return address + + .D64(0x00007400c0001000ULL) // a couple of plausible addresses + .D64(0x00007500b000aaaaULL) // that are not within functions + + .D64(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // end of stack + .Mark(&frame1_rbp); + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame1_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 platypus\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 echidna\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ("platypus", frame0->function_name); + EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.rip); + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); + EXPECT_EQ("echidna", frame1->function_name); + EXPECT_EQ(0x00007500b0000100ULL, frame1->function_base); +} + +// StackwalkerAMD64::GetCallerByFramePointerRecovery should never return an +// instruction pointer of 0 because IP of 0 is an end of stack marker and the +// stack walk may be terminated prematurely. Instead it should return NULL +// so that the stack walking code can proceed to stack scanning. +TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) { + MockCodeModule user32_dll(0x00007ff9cb8a0000ULL, 0x14E000, "user32.dll", + "version1"); + SetModuleSymbols(&user32_dll, // user32.dll + "PUBLIC fa60 0 DispatchMessageWorker\n" + "PUBLIC fee0 0 UserCallWinProcCheckWow\n" + "PUBLIC 1cdb0 0 _fnHkINLPMSG\n" + "STACK CFI INIT fa60 340 .cfa: $rsp .ra: .cfa 8 - ^\n" + "STACK CFI fa60 .cfa: $rsp 128 +\n" + "STACK CFI INIT fee0 49f .cfa: $rsp .ra: .cfa 8 - ^\n" + "STACK CFI fee0 .cfa: $rsp 240 +\n" + "STACK CFI INIT 1cdb0 9f .cfa: $rsp .ra: .cfa 8 - ^\n" + "STACK CFI 1cdb0 .cfa: $rsp 80 +\n"); + + // Create some modules with some stock debugging information. + MockCodeModules local_modules; + local_modules.Add(&user32_dll); + + Label frame0_rsp; + Label frame0_rbp; + Label frame1_rsp; + Label frame2_rsp; + + stack_section.start() = 0x00000099abf0f238ULL; + stack_section + .Mark(&frame0_rsp) + .D64(0x00007ff9cb8b00dcULL) + .Mark(&frame1_rsp) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000001ULL) + .D64(0x00000099abf0f308ULL) + .D64(0x00007ff9cb8bce3aULL) // Stack residue from execution of + // user32!_fnHkINLPMSG+0x8a + .D64(0x000000000000c2e0ULL) + .D64(0x00000099abf0f328ULL) + .D64(0x0000000100000001ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x00007ff9ccad53e4ULL) + .D64(0x0000000000000048ULL) + .D64(0x0000000000000001ULL) + .D64(0x00000099abf0f5e0ULL) + .D64(0x00000099b61f7388ULL) + .D64(0x0000000000000030ULL) + .D64(0xffffff66540f0a1fULL) + .D64(0xffffff6649e08c77ULL) + .D64(0x00007ff9cb8affb4ULL) // Return address in + // user32!UserCallWinProcCheckWow+0xd4 + .D64(0x0000000000000000ULL) + .D64(0x00000099abf0f368ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x0000000000000000ULL) + .D64(0x00000099a8150fd8ULL) + .D64(0x00000099abf0f3e8ULL) + .D64(0x00007ff9cb8afc07ULL) // Return address in + // user32!DispatchMessageWorker+0x1a7 + .Mark(&frame2_rsp) + .Append(256, 0) + .Mark(&frame0_rbp) // The following are expected by + // GetCallerByFramePointerRecovery. + .D64(0xfffffffffffffffeULL) // %caller_rbp = *(%callee_rbp) + .D64(0x0000000000000000ULL) // %caller_rip = *(%callee_rbp + 8) + .D64(0x00000099a3e31040ULL) // %caller_rsp = *(%callee_rbp + 16) + .Append(256, 0); + + RegionFromSection(); + raw_context.rip = 0x00000099a8150fd8ULL; // IP in context frame is guarbage + raw_context.rsp = frame0_rsp.Value(); + raw_context.rbp = frame0_rbp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, + &local_modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + + ASSERT_EQ(3U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameAMD64 *frame = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame->context_validity); + EXPECT_EQ("", frame->function_name); + EXPECT_EQ(0x00000099a8150fd8ULL, frame->instruction); + EXPECT_EQ(0x00000099a8150fd8ULL, frame->context.rip); + EXPECT_EQ(frame0_rsp.Value(), frame->context.rsp); + EXPECT_EQ(frame0_rbp.Value(), frame->context.rbp); + } + + { // To avoid reusing locals by mistake + StackFrameAMD64 *frame = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP), + frame->context_validity); + EXPECT_EQ("UserCallWinProcCheckWow", frame->function_name); + EXPECT_EQ(140710838468828ULL, frame->instruction + 1); + EXPECT_EQ(140710838468828ULL, frame->context.rip); + EXPECT_EQ(frame1_rsp.Value(), frame->context.rsp); + EXPECT_EQ(&user32_dll, frame->module); + } + + { // To avoid reusing locals by mistake + StackFrameAMD64 *frame = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP), + frame->context_validity); + EXPECT_EQ("DispatchMessageWorker", frame->function_name); + EXPECT_EQ(140710838467591ULL, frame->instruction + 1); + EXPECT_EQ(140710838467591ULL, frame->context.rip); + EXPECT_EQ(frame2_rsp.Value(), frame->context.rsp); + EXPECT_EQ(&user32_dll, frame->module); + } +} + +// Don't use frame pointer recovery if %rbp is not 8-byte aligned, which +// indicates that it's not being used as a frame pointer. +TEST_F(GetCallerFrame, FramePointerNotAligned) { + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address1 = 0x00007500b0000100ULL; + Label frame0_rbp, not_frame1_rbp, frame1_sp; + stack_section + // frame 0 + .Align(8, 0) + .Append(2, 0) // mis-align the frame pointer + .Mark(&frame0_rbp) + .D64(not_frame1_rbp) // not the previous frame pointer + .D64(0x00007500b0000a00ULL) // plausible but wrong return address + .Align(8, 0) + .D64(return_address1) // return address + // frame 1 + .Mark(&frame1_sp) + .Mark(¬_frame1_rbp) + .Append(32, 0); // end of stack + + + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame0_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.rip); + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); +} + +// Don't use frame pointer recovery if the recovered %rip is not +// a canonical x86-64 address. +TEST_F(GetCallerFrame, NonCanonicalInstructionPointerFromFramePointer) { + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address1 = 0x00007500b0000100ULL; + Label frame0_rbp, frame1_sp, not_frame1_bp; + stack_section + // frame 0 + .Align(8, 0) + .Mark(&frame0_rbp) + .D64(not_frame1_bp) // some junk on the stack + .D64(0xDADADADADADADADA) // not the return address + .D64(return_address1) // return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) + .Mark(¬_frame1_bp) + .Append(32, 0); // end of stack + + + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame0_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.rip); + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address1 = 0x00007500b0000100ULL; + uint64_t return_address2 = 0x00007500b0000900ULL; + Label frame1_sp, frame2_sp, frame1_rbp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // junk that's not + .D64(0x00007500d0000000ULL) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // more junk + .D64(0x00007500d0000000ULL) + + .Mark(&frame1_rbp) + .D64(stack_section.start()) // This is in the right place to be + // a saved rbp, but it's bogus, so + // we shouldn't report it. + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame1_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +TEST_F(GetCallerFrame, CallerPushedRBP) { + // Functions typically push their %rbp upon entry and set %rbp pointing + // there. If stackwalking finds a plausible address for the next frame's + // %rbp directly below the return address, assume that it is indeed the + // next frame's %rbp. + stack_section.start() = 0x8000000080000000ULL; + uint64_t return_address = 0x00007500b0000110ULL; + Label frame0_rbp, frame1_sp, frame1_rbp; + + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x00007400b0000000ULL) // junk that's not + .D64(0x00007500b0000000ULL) // a return address + + .D64(0x00007400c0001000ULL) // a couple of plausible addresses + .D64(0x00007500b000aaaaULL) // that are not within functions + + .Mark(&frame0_rbp) + .D64(frame1_rbp) // caller-pushed %rbp + .D64(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // body of frame1 + .Mark(&frame1_rbp) // end of stack + .D64(0); + RegionFromSection(); + + raw_context.rip = 0x00007400c0000200ULL; + raw_context.rbp = frame0_rbp.Value(); + raw_context.rsp = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 sasquatch\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 yeti\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(frame0_rbp.Value(), frame0->context.rbp); + EXPECT_EQ("sasquatch", frame0->function_name); + EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.rip); + EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp); + EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp); + EXPECT_EQ("yeti", frame1->function_name); + EXPECT_EQ(0x00007500b0000100ULL, frame1->function_base); +} + +struct CFIFixture: public StackwalkerAMD64Fixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; we'll walk to the caller + // from every point in this series, expecting to find the same set + // of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, just a return address. + "STACK CFI INIT 4000 100 .cfa: $rsp 8 + .ra: .cfa 8 - ^\n" + // Push %rbx. + "STACK CFI 4001 .cfa: $rsp 16 + $rbx: .cfa 16 - ^\n" + // Save %r12 in %rbx. Weird, but permitted. + "STACK CFI 4002 $r12: $rbx\n" + // Allocate frame space, and save %r13. + "STACK CFI 4003 .cfa: $rsp 40 + $r13: .cfa 32 - ^\n" + // Put the return address in %r13. + "STACK CFI 4005 .ra: $r13\n" + // Save %rbp, and use it as a frame pointer. + "STACK CFI 4006 .cfa: $rbp 16 + $rbp: .cfa 24 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: $rsp .ra 0\n"); + + // Provide some distinctive values for the caller's registers. + expected.rsp = 0x8000000080000000ULL; + expected.rip = 0x00007400c0005510ULL; + expected.rbp = 0x68995b1de4700266ULL; + expected.rbx = 0x5a5beeb38de23be8ULL; + expected.r12 = 0xed1b02e8cc0fc79cULL; + expected.r13 = 0x1d20ad8acacbe930ULL; + expected.r14 = 0xe94cffc2f7adaa28ULL; + expected.r15 = 0xb638d17d8da413b5ULL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set + // raw_context.rsp to the stack's starting address.) Expect two + // stack frames; in the older frame, expect the callee-saves + // registers to have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.rsp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameAMD64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x00007400c0004000ULL, frame0->function_base); + + StackFrameAMD64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP | + StackFrameAMD64::CONTEXT_VALID_RSP | + StackFrameAMD64::CONTEXT_VALID_RBP | + StackFrameAMD64::CONTEXT_VALID_RBX | + StackFrameAMD64::CONTEXT_VALID_R12 | + StackFrameAMD64::CONTEXT_VALID_R13 | + StackFrameAMD64::CONTEXT_VALID_R14 | + StackFrameAMD64::CONTEXT_VALID_R15), + frame1->context_validity); + EXPECT_EQ(expected.rip, frame1->context.rip); + EXPECT_EQ(expected.rsp, frame1->context.rsp); + EXPECT_EQ(expected.rbp, frame1->context.rbp); + EXPECT_EQ(expected.rbx, frame1->context.rbx); + EXPECT_EQ(expected.r12, frame1->context.r12); + EXPECT_EQ(expected.r13, frame1->context.r13); + EXPECT_EQ(expected.r14, frame1->context.r14); + EXPECT_EQ(expected.r15, frame1->context.r15); + EXPECT_EQ("epictetus", frame1->function_name); + } + + // The values we expect to find for the caller's registers. + MDRawContextAMD64 expected; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x00007400c0005510ULL) // return address + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004000ULL; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0x00007400c0005510ULL) // return address + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004001ULL; + raw_context.rbx = 0xbe0487d2f9eafe29ULL; // callee's (distinct) %rbx value + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0x00007400c0005510ULL) // return address + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004002ULL; + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 + raw_context.r12 = 0xb0118de918a4bceaULL; // callee's (distinct) %r12 value + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x0e023828dffd4d81ULL) // garbage + .D64(0x1d20ad8acacbe930ULL) // saved %r13 + .D64(0x319e68b49e3ace0fULL) // garbage + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0x00007400c0005510ULL) // return address + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004003ULL; + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 + raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12 + raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13 + CheckWalk(); +} + +// The results here should be the same as those at module offset 0x4003. +TEST_F(CFI, At4004) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x0e023828dffd4d81ULL) // garbage + .D64(0x1d20ad8acacbe930ULL) // saved %r13 + .D64(0x319e68b49e3ace0fULL) // garbage + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0x00007400c0005510ULL) // return address + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004004ULL; + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 + raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12 + raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13 + CheckWalk(); +} + +TEST_F(CFI, At4005) { + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x4b516dd035745953ULL) // garbage + .D64(0x1d20ad8acacbe930ULL) // saved %r13 + .D64(0xa6d445e16ae3d872ULL) // garbage + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0xaa95fa054aedfbaeULL) // garbage + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004005ULL; + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 + raw_context.r12 = 0x46b1b8868891b34aULL; // callee's %r12 + raw_context.r13 = 0x00007400c0005510ULL; // return address + CheckWalk(); +} + +TEST_F(CFI, At4006) { + Label frame0_rbp; + Label frame1_rsp = expected.rsp; + stack_section + .D64(0x043c6dfceb91aa34ULL) // garbage + .D64(0x1d20ad8acacbe930ULL) // saved %r13 + .D64(0x68995b1de4700266ULL) // saved %rbp + .Mark(&frame0_rbp) // frame pointer points here + .D64(0x5a5beeb38de23be8ULL) // saved %rbx + .D64(0xf015ee516ad89eabULL) // garbage + .Mark(&frame1_rsp); // This effectively sets stack_section.start(). + raw_context.rip = 0x00007400c0004006ULL; + raw_context.rbp = frame0_rbp.Value(); + raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12 + raw_context.r12 = 0x26e007b341acfebdULL; // callee's %r12 + raw_context.r13 = 0x00007400c0005510ULL; // return address + CheckWalk(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.cc new file mode 100644 index 0000000000..1313416f4d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.cc @@ -0,0 +1,297 @@ +// Copyright (c) 2010 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_arm.cc: arm-specific stackwalker. +// +// See stackwalker_arm.h for documentation. +// +// Author: Mark Mentovai, Ted Mielczarek, Jim Blandy + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/stackwalker_arm.h" + +namespace google_breakpad { + + +StackwalkerARM::StackwalkerARM(const SystemInfo* system_info, + const MDRawContextARM* context, + int fp_register, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), fp_register_(fp_register), + context_frame_validity_(StackFrameARM::CONTEXT_VALID_ALL) { } + + +StackFrame* StackwalkerARM::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameARM* frame = new StackFrameARM(); + + // The instruction pointer is stored directly in a register (r15), so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = context_frame_validity_; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC]; + + return frame; +} + +StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo( + const vector &frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameARM* last_frame = static_cast(frames.back()); + + static const char* register_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "fps", "cpsr", + NULL + }; + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap callee_registers; + for (int i = 0; register_names[i]; i++) + if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i)) + callee_registers[register_names[i]] = last_frame->context.iregs[i]; + + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) + return NULL; + + // Construct a new stack frame given the values the CFI recovered. + scoped_ptr frame(new StackFrameARM()); + for (int i = 0; register_names[i]; i++) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(register_names[i]); + if (entry != caller_registers.end()) { + // We recovered the value of this register; fill the context with the + // value from caller_registers. + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); + frame->context.iregs[i] = entry->second; + } else if (4 <= i && i <= 11 && (last_frame->context_validity & + StackFrameARM::RegisterValidFlag(i))) { + // If the STACK CFI data doesn't mention some callee-saves register, and + // it is valid in the callee, assume the callee has not yet changed it. + // Registers r4 through r11 are callee-saves, according to the Procedure + // Call Standard for the ARM Architecture, which the Linux ABI follows. + frame->context_validity |= StackFrameARM::RegisterValidFlag(i); + frame->context.iregs[i] = last_frame->context.iregs[i]; + } + } + // If the CFI doesn't recover the PC explicitly, then use .ra. + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + if (fp_register_ == -1) { + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = entry->second; + } else { + // The CFI updated the link register and not the program counter. + // Handle getting the program counter from the link register. + frame->context_validity |= StackFrameARM::CONTEXT_VALID_PC; + frame->context_validity |= StackFrameARM::CONTEXT_VALID_LR; + frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = entry->second; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; + } + } + } + // If the CFI doesn't recover the SP explicitly, then use .cfa. + if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(".cfa"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameARM::CONTEXT_VALID_SP; + frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = entry->second; + } + } + + // If we didn't recover the PC and the SP, then the frame isn't very useful. + static const int essentials = (StackFrameARM::CONTEXT_VALID_SP + | StackFrameARM::CONTEXT_VALID_PC); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameARM* StackwalkerARM::GetCallerByStackScan( + const vector &frames) { + StackFrameARM* last_frame = static_cast(frames.back()); + uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; + uint32_t caller_sp, caller_pc; + + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, + frames.size() == 1 /* is_context_frame */)) { + // No plausible return address was found. + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // %sp to the location above the one where the return address was + // found. + caller_sp += 4; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameARM* frame = new StackFrameARM(); + + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = caller_pc; + frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; + frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP; + + return frame; +} + +StackFrameARM* StackwalkerARM::GetCallerByFramePointer( + const vector &frames) { + StackFrameARM* last_frame = static_cast(frames.back()); + + if (!(last_frame->context_validity & + StackFrameARM::RegisterValidFlag(fp_register_))) { + return NULL; + } + + uint32_t last_fp = last_frame->context.iregs[fp_register_]; + + uint32_t caller_fp = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { + BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" + << std::hex << last_fp; + return NULL; + } + + uint32_t caller_lr = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 4, &caller_lr)) { + BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 4: 0x" + << std::hex << (last_fp + 4); + return NULL; + } + + uint32_t caller_sp = last_fp ? last_fp + 8 : + last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP]; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameARM* frame = new StackFrameARM(); + + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.iregs[fp_register_] = caller_fp; + frame->context.iregs[MD_CONTEXT_ARM_REG_SP] = caller_sp; + frame->context.iregs[MD_CONTEXT_ARM_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR]; + frame->context.iregs[MD_CONTEXT_ARM_REG_LR] = caller_lr; + frame->context_validity = StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(fp_register_) | + StackFrameARM::CONTEXT_VALID_SP; + return frame; +} + +StackFrame* StackwalkerARM::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector &frames = *stack->frames(); + StackFrameARM* last_frame = static_cast(frames.back()); + scoped_ptr frame; + + // See if there is DWARF call frame information covering this address. + // TODO(jperaza): Ignore iOS CFI info until it is properly collected. + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764 + if (!system_info_ || system_info_->os != "iOS") { + scoped_ptr cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + } + + // If CFI failed, or there wasn't CFI available, fall back + // to frame pointer, if this is configured. + if (fp_register_ >= 0 && !frame.get()) + frame.reset(GetCallerByFramePointer(frames)); + + // If everuthing failed, fall back to stack scanning. + if (stack_scan_allowed && !frame.get()) + frame.reset(GetCallerByStackScan(frames)); + + // If nothing worked, tell the caller. + if (!frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM_REG_PC], + frame->context.iregs[MD_CONTEXT_ARM_REG_SP], + last_frame->context.iregs[MD_CONTEXT_ARM_REG_SP], + frames.size() == 1)) { + return NULL; + } + + // The new frame's context's PC is the return address, which is one + // instruction past the instruction that caused us to arrive at the + // callee. Set new_frame->instruction to one less than the PC. This won't + // reference the beginning of the call instruction, but it's at least + // within it, which is sufficient to get the source line information to + // match up with the line that contains the function call. Callers that + // require the exact return address value may access + // frame->context.iregs[MD_CONTEXT_ARM_REG_PC]. + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM_REG_PC] - 2; + + return frame.release(); +} + + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.h new file mode 100644 index 0000000000..9081a40cd0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm.h @@ -0,0 +1,107 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 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_arm.h: arm-specific stackwalker. +// +// Provides stack frames given arm register context and a memory region +// corresponding to an arm stack. +// +// Author: Mark Mentovai, Ted Mielczarek + + +#ifndef PROCESSOR_STACKWALKER_ARM_H__ +#define PROCESSOR_STACKWALKER_ARM_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 StackwalkerARM : public Stackwalker { + public: + // context is an arm context object that gives access to arm-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. + StackwalkerARM(const SystemInfo* system_info, + const MDRawContextARM* context, + int fp_register, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // Change the context validity mask of the frame returned by + // GetContextFrame to VALID. This is only for use by unit tests; the + // default behavior is correct for all application code. + void SetContextFrameValidity(int valid) { context_frame_validity_ = valid; } + + private: + // Implementation of Stackwalker, using arm context and stack conventions. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameARM* GetCallerByCFIFrameInfo(const vector &frames, + CFIFrameInfo* cfi_frame_info); + + // Use the frame pointer. The caller takes ownership of the returned frame. + // Return NULL on failure. + StackFrameARM* GetCallerByFramePointer(const vector &frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameARM* GetCallerByStackScan(const vector &frames); + + // Stores the CPU context corresponding to the youngest stack frame, to + // be returned by GetContextFrame. + const MDRawContextARM* context_; + + // The register to use a as frame pointer. The value is -1 if frame pointer + // cannot be used. + int fp_register_; + + // Validity mask for youngest stack frame. This is always + // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of + // unit tests. + int context_frame_validity_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_ARM_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.cc new file mode 100644 index 0000000000..3d9232888b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.cc @@ -0,0 +1,351 @@ +// Copyright (c) 2013 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_arm64.cc: arm64-specific stackwalker. +// +// See stackwalker_arm64.h for documentation. +// +// Author: Mark Mentovai, Ted Mielczarek, Jim Blandy, Colin Blundell + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/stackwalker_arm64.h" + +namespace google_breakpad { + + +StackwalkerARM64::StackwalkerARM64(const SystemInfo* system_info, + const MDRawContextARM64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), + context_frame_validity_(StackFrameARM64::CONTEXT_VALID_ALL), + address_range_mask_(0xffffffffffffffff) { + if (modules && modules->module_count() > 0) { + // ARM64 supports storing pointer authentication codes in the upper bits of + // a pointer. Make a best guess at the range of valid addresses based on the + // range of loaded modules. + const CodeModule *high_module = + modules->GetModuleAtSequence(modules->module_count() - 1); + uint64_t mask = high_module->base_address() + high_module->size(); + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask |= mask >> 32; + address_range_mask_ = mask; + } +} + +uint64_t StackwalkerARM64::PtrauthStrip(uint64_t ptr) { + uint64_t stripped = ptr & address_range_mask_; + return modules_ && modules_->GetModuleForAddress(stripped) ? stripped : ptr; +} + +StackFrame* StackwalkerARM64::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameARM64* frame = new StackFrameARM64(); + + // The instruction pointer is stored directly in a register (x32), so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = context_frame_validity_; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]; + frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = + PtrauthStrip(frame->context.iregs[MD_CONTEXT_ARM64_REG_LR]); + + return frame; +} + +StackFrameARM64* StackwalkerARM64::GetCallerByCFIFrameInfo( + const vector &frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameARM64* last_frame = static_cast(frames.back()); + + static const char* register_names[] = { + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", + "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", + "pc", NULL + }; + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap callee_registers; + for (int i = 0; register_names[i]; i++) { + if (last_frame->context_validity & StackFrameARM64::RegisterValidFlag(i)) + callee_registers[register_names[i]] = last_frame->context.iregs[i]; + } + + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap caller_registers; + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return NULL; + } + // Construct a new stack frame given the values the CFI recovered. + scoped_ptr frame(new StackFrameARM64()); + for (int i = 0; register_names[i]; i++) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(register_names[i]); + if (entry != caller_registers.end()) { + // We recovered the value of this register; fill the context with the + // value from caller_registers. + frame->context_validity |= StackFrameARM64::RegisterValidFlag(i); + frame->context.iregs[i] = entry->second; + } else if (19 <= i && i <= 29 && (last_frame->context_validity & + StackFrameARM64::RegisterValidFlag(i))) { + // If the STACK CFI data doesn't mention some callee-saves register, and + // it is valid in the callee, assume the callee has not yet changed it. + // Registers r19 through r29 are callee-saves, according to the Procedure + // Call Standard for the ARM AARCH64 Architecture, which the Linux ABI + // follows. + frame->context_validity |= StackFrameARM64::RegisterValidFlag(i); + frame->context.iregs[i] = last_frame->context.iregs[i]; + } + } + // If the CFI doesn't recover the PC explicitly, then use .ra. + if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_PC)) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameARM64::CONTEXT_VALID_PC; + frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = entry->second; + } + } + // If the CFI doesn't recover the SP explicitly, then use .cfa. + if (!(frame->context_validity & StackFrameARM64::CONTEXT_VALID_SP)) { + CFIFrameInfo::RegisterValueMap::iterator entry = + caller_registers.find(".cfa"); + if (entry != caller_registers.end()) { + frame->context_validity |= StackFrameARM64::CONTEXT_VALID_SP; + frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = entry->second; + } + } + + // If we didn't recover the PC and the SP, then the frame isn't very useful. + static const uint64_t essentials = (StackFrameARM64::CONTEXT_VALID_SP + | StackFrameARM64::CONTEXT_VALID_PC); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + return frame.release(); +} + +StackFrameARM64* StackwalkerARM64::GetCallerByStackScan( + const vector &frames) { + StackFrameARM64* last_frame = static_cast(frames.back()); + uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]; + uint64_t caller_sp, caller_pc; + + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, + frames.size() == 1 /* is_context_frame */)) { + // No plausible return address was found. + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // %sp to the location above the one where the return address was + // found. + caller_sp += 8; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameARM64* frame = new StackFrameARM64(); + + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = caller_pc; + frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp; + frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP; + + return frame; +} + +StackFrameARM64* StackwalkerARM64::GetCallerByFramePointer( + const vector &frames) { + StackFrameARM64* last_frame = static_cast(frames.back()); + if (!(last_frame->context_validity & StackFrameARM64::CONTEXT_VALID_LR)) { + CorrectRegLRByFramePointer(frames, last_frame); + } + + uint64_t last_fp = last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; + + uint64_t caller_fp = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp, &caller_fp)) { + BPLOG(ERROR) << "Unable to read caller_fp from last_fp: 0x" + << std::hex << last_fp; + return NULL; + } + + uint64_t caller_lr = 0; + if (last_fp && !memory_->GetMemoryAtAddress(last_fp + 8, &caller_lr)) { + BPLOG(ERROR) << "Unable to read caller_lr from last_fp + 8: 0x" + << std::hex << (last_fp + 8); + return NULL; + } + + caller_lr = PtrauthStrip(caller_lr); + + uint64_t caller_sp = last_fp ? last_fp + 16 : + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]; + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameARM64* frame = new StackFrameARM64(); + + frame->trust = StackFrame::FRAME_TRUST_FP; + frame->context = last_frame->context; + frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] = caller_fp; + frame->context.iregs[MD_CONTEXT_ARM64_REG_SP] = caller_sp; + frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] = + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR]; + frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = caller_lr; + frame->context_validity = StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_LR | + StackFrameARM64::CONTEXT_VALID_FP | + StackFrameARM64::CONTEXT_VALID_SP; + return frame; +} + +void StackwalkerARM64::CorrectRegLRByFramePointer( + const vector& frames, + StackFrameARM64* last_frame) { + // Need at least two frames to correct and + // register $FP should always be greater than register $SP. + if (frames.size() < 2 || !last_frame || + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] <= + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP]) + return; + + StackFrameARM64* last_last_frame = + static_cast(*(frames.end() - 2)); + uint64_t last_last_fp = + last_last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP]; + + uint64_t last_fp = 0; + if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp, &last_fp)) { + BPLOG(ERROR) << "Unable to read last_fp from last_last_fp: 0x" + << std::hex << last_last_fp; + return; + } + // Give up if STACK CFI doesn't agree with frame pointer. + if (last_frame->context.iregs[MD_CONTEXT_ARM64_REG_FP] != last_fp) + return; + + uint64_t last_lr = 0; + if (last_last_fp && !memory_->GetMemoryAtAddress(last_last_fp + 8, &last_lr)) { + BPLOG(ERROR) << "Unable to read last_lr from (last_last_fp + 8): 0x" + << std::hex << (last_last_fp + 8); + return; + } + last_lr = PtrauthStrip(last_lr); + + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_LR] = last_lr; +} + +bool StackwalkerARM64::ValidInstructionPointerInFrame(const StackFrameARM64& frame) { + const uint64_t ip = frame.context.iregs[MD_CONTEXT_ARM64_REG_PC]; + + if ((ip < 0x1000) || (ip > 0x000fffffffffffff)) { + // The IP points into the first page or above the user space threshold + return false; + } + + return true; +} + +StackFrame* StackwalkerARM64::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector &frames = *stack->frames(); + StackFrameARM64* last_frame = static_cast(frames.back()); + scoped_ptr frame; + + // See if there is DWARF call frame information covering this address. + scoped_ptr cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If CFI failed, or there wasn't CFI available, fall back to frame pointer. + if (!frame.get() || !ValidInstructionPointerInFrame(*frame)) + frame.reset(GetCallerByFramePointer(frames)); + + // If everything failed, fall back to stack scanning. + if (stack_scan_allowed && + (!frame.get() || !ValidInstructionPointerInFrame(*frame))) + frame.reset(GetCallerByStackScan(frames)); + + // If nothing worked, tell the caller. + if (!frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(frame->context.iregs[MD_CONTEXT_ARM64_REG_PC], + frame->context.iregs[MD_CONTEXT_ARM64_REG_SP], + last_frame->context.iregs[MD_CONTEXT_ARM64_REG_SP], + frames.size() == 1)) { + return NULL; + } + + // The new frame's context's PC is the return address, which is one + // instruction past the instruction that caused us to arrive at the callee. + // ARM64 instructions have a uniform 4-byte encoding, so subtracting 4 off + // the return address gets back to the beginning of the call instruction. + // Callers that require the exact return address value may access + // frame->context.iregs[MD_CONTEXT_ARM64_REG_PC]. + frame->instruction = frame->context.iregs[MD_CONTEXT_ARM64_REG_PC] - 4; + + return frame.release(); +} + + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.h new file mode 100644 index 0000000000..3f9e4f19c4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64.h @@ -0,0 +1,121 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2013 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_arm64.h: arm64-specific stackwalker. +// +// Provides stack frames given arm64 register context and a memory region +// corresponding to an arm64 stack. +// +// Author: Mark Mentovai, Ted Mielczarek, Colin Blundell + + +#ifndef PROCESSOR_STACKWALKER_ARM64_H__ +#define PROCESSOR_STACKWALKER_ARM64_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 StackwalkerARM64 : public Stackwalker { + public: + // context is an arm64 context object that gives access to arm64-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. + StackwalkerARM64(const SystemInfo* system_info, + const MDRawContextARM64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // Change the context validity mask of the frame returned by + // GetContextFrame to VALID. This is only for use by unit tests; the + // default behavior is correct for all application code. + void SetContextFrameValidity(uint64_t valid) { + context_frame_validity_ = valid; + } + + private: + // Strip pointer authentication codes from an address. + uint64_t PtrauthStrip(uint64_t ptr); + + // Implementation of Stackwalker, using arm64 context and stack conventions. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameARM64* GetCallerByCFIFrameInfo(const vector &frames, + CFIFrameInfo* cfi_frame_info); + + // Use the frame pointer. The caller takes ownership of the returned frame. + // Return NULL on failure. + StackFrameARM64* GetCallerByFramePointer(const vector &frames); + + // Scan the stack for plausible return addresses. The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameARM64* GetCallerByStackScan(const vector &frames); + + // GetCallerByFramePointer() depends on the previous frame having recovered + // x30($LR) which may not have been done when using CFI. + // This function recovers $LR in the previous frame by using the frame-pointer + // two frames back to read it from the stack. + void CorrectRegLRByFramePointer(const vector& frames, + StackFrameARM64* last_frame); + + // Return true if the instruction pointer points into the first 4KiB of memory + bool ValidInstructionPointerInFrame(const StackFrameARM64& frame); + + // Stores the CPU context corresponding to the youngest stack frame, to + // be returned by GetContextFrame. + const MDRawContextARM64* context_; + + // Validity mask for youngest stack frame. This is always + // CONTEXT_VALID_ALL in real use; it is only changeable for the sake of + // unit tests. + uint64_t context_frame_validity_; + + // A mask of the valid address bits, determined from the address range of + // modules_. + uint64_t address_range_mask_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_ARM64_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64_unittest.cc new file mode 100644 index 0000000000..d86fa12779 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm64_unittest.cc @@ -0,0 +1,881 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// stackwalker_arm64_unittest.cc: Unit tests for StackwalkerARM64 class. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_arm64.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameARM64; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerARM64; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerARM64Fixture { + public: + StackwalkerARM64Fixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x40000000, 0x10000, "module1", "version1"), + module2(0x50000000, 0x10000, "module2", "version2") { + // Identify the system as an iOS system. + system_info.os = "iOS"; + system_info.os_short = "ios"; + system_info.cpu = "arm64"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule *module, const string &info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextARM64 *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextARM64 raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector *frames; +}; + +class SanityCheck: public StackwalkerARM64Fixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + // Since the context's frame pointer is garbage, the stack walk will end after + // the first frame. + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameARM64 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerARM64Fixture, public Test { }; + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameARM64 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerARM64Fixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); + + StackFrameARM64 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM64_REG_SP]); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint64_t return_address = 0x50000200; + Label frame1_sp; + + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(0x40001000) // a couple of plausible addresses + .D64(0x5000F000) // that are not within functions + + .D64(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x40000200; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x40000100ULL, frame0->function_base); + + StackFrameARM64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x50000100ULL, frame1->function_base); +} + +TEST_F(GetCallerFrame, ScanFirstFrame) { + // If the stackwalker resorts to stack scanning, it will scan much + // farther to find the caller of the context frame. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .Append(96, 0) // more space + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .Append(336, 0) // more space + + .D64(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x40090000) // junk that's not + .D64(0x60000000) // a return address + + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +class GetFramesByFramePointer: public StackwalkerARM64Fixture, public Test { }; + +TEST_F(GetFramesByFramePointer, OnlyFramePointer) { + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x50000100; + uint64_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + Label frame1_fp, frame2_fp; + stack_section + // frame 0 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000) // a return address. + + .Mark(&frame1_fp) // Next fp will point to the next value. + .D64(frame2_fp) // Save current frame pointer. + .D64(return_address2) // Save current link register. + .Mark(&frame1_sp) + + // frame 1 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000) // a return address. + + .Mark(&frame2_fp) + .D64(0) + .D64(0) + .Mark(&frame2_sp) + + // frame 2 + .Append(64, 0) // Whatever values on the stack. + .D64(0x0000000D) // junk that's not + .D64(0xF0000000); // a return address. + RegionFromSection(); + + + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM64_REG_LR] = return_address1; + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = frame1_fp.Value(); + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, + &stack_region, &modules, &frame_symbolizer); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM64::CONTEXT_VALID_ALL, + frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_LR | + StackFrameARM64::CONTEXT_VALID_FP | + StackFrameARM64::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(return_address2, frame1->context.iregs[MD_CONTEXT_ARM64_REG_LR]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); + EXPECT_EQ(frame2_fp.Value(), + frame1->context.iregs[MD_CONTEXT_ARM64_REG_FP]); + + StackFrameARM64 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); + ASSERT_EQ((StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_LR | + StackFrameARM64::CONTEXT_VALID_FP | + StackFrameARM64::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM64_REG_LR]); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM64_REG_SP]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM64_REG_FP]); +} + +struct CFIFixture: public StackwalkerARM64Fixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; we'll walk to the caller + // from every point in this series, expecting to find the same set + // of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the link + // register (x30). + "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: x30\n" + // Push x19, x20, the frame pointer and the link register. + "STACK CFI 4001 .cfa: sp 32 + .ra: .cfa -8 + ^" + " x19: .cfa -32 + ^ x20: .cfa -24 + ^ " + " x29: .cfa -16 + ^\n" + // Save x19..x22 in x0..x3: verify that we populate + // the youngest frame with all the values we have. + "STACK CFI 4002 x19: x0 x20: x1 x21: x2 x22: x3\n" + // Restore x19..x22. Save the non-callee-saves register x1. + "STACK CFI 4003 .cfa: sp 40 + x1: .cfa 40 - ^" + " x19: x19 x20: x20 x21: x21 x22: x22\n" + // Move the .cfa back eight bytes, to point at the return + // address, and restore the sp explicitly. + "STACK CFI 4005 .cfa: sp 32 + x1: .cfa 32 - ^" + " x29: .cfa 8 - ^ .ra: .cfa ^ sp: .cfa 8 +\n" + // Recover the PC explicitly from a new stack slot; + // provide garbage for the .ra. + "STACK CFI 4006 .cfa: sp 40 + pc: .cfa 40 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: sp 8 - .ra: x30\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n"); + + // Provide some distinctive values for the caller's registers. + expected.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040005510L; + expected.iregs[MD_CONTEXT_ARM64_REG_SP] = 0x0000000080000000L; + expected.iregs[19] = 0x5e68b5d5b5d55e68L; + expected.iregs[20] = 0x34f3ebd1ebd134f3L; + expected.iregs[21] = 0x74bca31ea31e74bcL; + expected.iregs[22] = 0x16b32dcb2dcb16b3L; + expected.iregs[23] = 0x21372ada2ada2137L; + expected.iregs[24] = 0x557dbbbbbbbb557dL; + expected.iregs[25] = 0x8ca748bf48bf8ca7L; + expected.iregs[26] = 0x21f0ab46ab4621f0L; + expected.iregs[27] = 0x146732b732b71467L; + expected.iregs[28] = 0xa673645fa673645fL; + expected.iregs[MD_CONTEXT_ARM64_REG_FP] = 0xe11081128112e110L; + + // Expect CFI to recover all callee-saves registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameARM64::CONTEXT_VALID_PC | + StackFrameARM64::CONTEXT_VALID_SP | + StackFrameARM64::CONTEXT_VALID_X19 | + StackFrameARM64::CONTEXT_VALID_X20 | + StackFrameARM64::CONTEXT_VALID_X21 | + StackFrameARM64::CONTEXT_VALID_X22 | + StackFrameARM64::CONTEXT_VALID_X23 | + StackFrameARM64::CONTEXT_VALID_X24 | + StackFrameARM64::CONTEXT_VALID_X25 | + StackFrameARM64::CONTEXT_VALID_X26 | + StackFrameARM64::CONTEXT_VALID_X27 | + StackFrameARM64::CONTEXT_VALID_X28 | + StackFrameARM64::CONTEXT_VALID_FP); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameARM64::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + walker.SetContextFrameValidity(context_frame_validity); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM64 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(context_frame_validity, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x0000000040004000UL, frame0->function_base); + + StackFrameARM64 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X1) + EXPECT_EQ(expected.iregs[1], frame1->context.iregs[1]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X19) + EXPECT_EQ(expected.iregs[19], frame1->context.iregs[19]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X20) + EXPECT_EQ(expected.iregs[20], frame1->context.iregs[20]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X21) + EXPECT_EQ(expected.iregs[21], frame1->context.iregs[21]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X22) + EXPECT_EQ(expected.iregs[22], frame1->context.iregs[22]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X23) + EXPECT_EQ(expected.iregs[23], frame1->context.iregs[23]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X24) + EXPECT_EQ(expected.iregs[24], frame1->context.iregs[24]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X25) + EXPECT_EQ(expected.iregs[25], frame1->context.iregs[25]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X26) + EXPECT_EQ(expected.iregs[26], frame1->context.iregs[26]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X27) + EXPECT_EQ(expected.iregs[27], frame1->context.iregs[27]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_X28) + EXPECT_EQ(expected.iregs[28], frame1->context.iregs[28]); + if (expected_validity & StackFrameARM64::CONTEXT_VALID_FP) + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM64_REG_FP], + frame1->context.iregs[MD_CONTEXT_ARM64_REG_FP]); + + // We would never have gotten a frame in the first place if the SP + // and PC weren't valid or ->instruction weren't set. + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM64_REG_SP], + frame1->context.iregs[MD_CONTEXT_ARM64_REG_SP]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM64_REG_PC], + frame1->context.iregs[MD_CONTEXT_ARM64_REG_PC]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM64_REG_PC], + frame1->instruction + 4); + EXPECT_EQ("epictetus", frame1->function_name); + } + + // The values we expect to find for the caller's registers. + MDRawContextARM64 expected; + + // The validity mask for expected. + uint64_t expected_validity; + + // The validity mask to impose on the context frame. + uint64_t context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + stack_section.start() = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004000L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_LR] = 0x0000000040005510L; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0x5e68b5d5b5d55e68L) // saved x19 + .D64(0x34f3ebd1ebd134f3L) // saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004001L; + // distinct callee x19, x20 and fp + raw_context.iregs[19] = 0xadc9f635a635adc9L; + raw_context.iregs[20] = 0x623135ac35ac6231L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = 0x5fc4be14be145fc4L; + CheckWalk(); +} + +// As above, but unwind from a context that has only the PC and SP. +TEST_F(CFI, At4001LimitedValidity) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0x5e68b5d5b5d55e68L) // saved x19 + .D64(0x34f3ebd1ebd134f3L) // saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + context_frame_validity = + StackFrameARM64::CONTEXT_VALID_PC | StackFrameARM64::CONTEXT_VALID_SP; + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004001L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = 0x5fc4be14be145fc4L; + + expected_validity = (StackFrameARM64::CONTEXT_VALID_PC + | StackFrameARM64::CONTEXT_VALID_SP + | StackFrameARM64::CONTEXT_VALID_FP + | StackFrameARM64::CONTEXT_VALID_X19 + | StackFrameARM64::CONTEXT_VALID_X20); + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0xff3dfb81fb81ff3dL) // no longer saved x19 + .D64(0x34f3ebd1ebd134f3L) // no longer saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004002L; + raw_context.iregs[0] = 0x5e68b5d5b5d55e68L; // saved x19 + raw_context.iregs[1] = 0x34f3ebd1ebd134f3L; // saved x20 + raw_context.iregs[2] = 0x74bca31ea31e74bcL; // saved x21 + raw_context.iregs[3] = 0x16b32dcb2dcb16b3L; // saved x22 + raw_context.iregs[19] = 0xadc9f635a635adc9L; // distinct callee x19 + raw_context.iregs[20] = 0x623135ac35ac6231L; // distinct callee x20 + raw_context.iregs[21] = 0xac4543564356ac45L; // distinct callee x21 + raw_context.iregs[22] = 0x2561562f562f2561L; // distinct callee x22 + // distinct callee fp + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = 0x5fc4be14be145fc4L; + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved x1 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved x19 + .D64(0x34f3ebd1ebd134f3L) // no longer saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004003L; + // distinct callee x1 and fp + raw_context.iregs[1] = 0xfb756319fb756319L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = 0x5fc4be14be145fc4L; + // caller's x1 + expected.iregs[1] = 0xdd5a48c848c8dd5aL; + expected_validity |= StackFrameARM64::CONTEXT_VALID_X1; + CheckWalk(); +} + +// We have no new rule at module offset 0x4004, so the results here should +// be the same as those at module offset 0x4003. +TEST_F(CFI, At4004) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved x1 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved x19 + .D64(0x34f3ebd1ebd134f3L) // no longer saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004004L; + // distinct callee x1 and fp + raw_context.iregs[1] = 0xfb756319fb756319L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_FP] = 0x5fc4be14be145fc4L; + // caller's x1 + expected.iregs[1] = 0xdd5a48c848c8dd5aL; + expected_validity |= StackFrameARM64::CONTEXT_VALID_X1; + CheckWalk(); +} + +// Here we move the .cfa, but provide an explicit rule to recover the SP, +// so again there should be no change in the registers recovered. +TEST_F(CFI, At4005) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0xdd5a48c848c8dd5aL) // saved x1 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved x19 + .D64(0x34f3ebd1ebd134f3L) // no longer saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0x0000000040005510L) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004005L; + raw_context.iregs[1] = 0xfb756319fb756319L; // distinct callee x1 + expected.iregs[1] = 0xdd5a48c848c8dd5aL; // caller's x1 + expected_validity |= StackFrameARM64::CONTEXT_VALID_X1; + CheckWalk(); +} + +// Here we provide an explicit rule for the PC, and have the saved .ra be +// bogus. +TEST_F(CFI, At4006) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM64_REG_SP]; + stack_section + .D64(0x0000000040005510L) // saved pc + .D64(0xdd5a48c848c8dd5aL) // saved x1 (even though it's not callee-saves) + .D64(0xff3dfb81fb81ff3dL) // no longer saved x19 + .D64(0x34f3ebd1ebd134f3L) // no longer saved x20 + .D64(0xe11081128112e110L) // saved fp + .D64(0xf8d157835783f8d1L) // .ra rule recovers this, which is garbage + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040004006L; + raw_context.iregs[1] = 0xfb756319fb756319L; // distinct callee x1 + expected.iregs[1] = 0xdd5a48c848c8dd5aL; // caller's x1 + expected_validity |= StackFrameARM64::CONTEXT_VALID_X1; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040006000L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = 0x0000000080000000L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_LR] = 0x0000000040005510L; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.iregs[MD_CONTEXT_ARM64_REG_PC] = 0x0000000040007000L; + raw_context.iregs[MD_CONTEXT_ARM64_REG_SP] = 0x0000000080000000L; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM64 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm_unittest.cc new file mode 100644 index 0000000000..256f7648c4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_arm_unittest.cc @@ -0,0 +1,979 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// stackwalker_arm_unittest.cc: Unit tests for StackwalkerARM class. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_arm.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameARM; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerARM; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerARMFixture { + public: + StackwalkerARMFixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x40000000, 0x10000, "module1", "version1"), + module2(0x50000000, 0x10000, "module2", "version2") { + // Identify the system as a Linux system. + system_info.os = "Linux"; + system_info.os_short = "linux"; + system_info.os_version = "Lugubrious Labrador"; + system_info.cpu = "arm"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule *module, const string &info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextARM *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextARM raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector *frames; +}; + +class SanityCheck: public StackwalkerARMFixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + // Since we have no call frame information, and all unwinding + // requires call frame information, the stack walk will end after + // the first frame. + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + // This should succeed even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameARM *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerARMFixture, public Test { }; + +TEST_F(GetContextFrame, Simple) { + // Since we have no call frame information, and all unwinding + // requires call frame information, the stack walk will end after + // the first frame. + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameARM *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameARM *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerARMFixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x50000100; + uint32_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .D32(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); + + StackFrameARM *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint32_t return_address = 0x50000200; + Label frame1_sp; + + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(0x40001000) // a couple of plausible addresses + .D32(0x5000F000) // that are not within functions + + .D32(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40000200; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x40000100U, frame0->function_base); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x50000100U, frame1->function_base); +} + +TEST_F(GetCallerFrame, ScanFirstFrame) { + // If the stackwalker resorts to stack scanning, it will scan much + // farther to find the caller of the context frame. + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x50000100; + uint32_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .Append(96, 0) // more space + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .Append(136, 0) // more space + + .D32(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x50000100; + uint32_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x40090000) // junk that's not + .D32(0x60000000) // a return address + + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .D32(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +struct CFIFixture: public StackwalkerARMFixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; we'll walk to the caller + // from every point in this series, expecting to find the same set + // of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the link register. + "STACK CFI INIT 4000 100 .cfa: sp .ra: lr\n" + // Push r4, the frame pointer, and the link register. + "STACK CFI 4001 .cfa: sp 12 + r4: .cfa 12 - ^" + " r11: .cfa 8 - ^ .ra: .cfa 4 - ^\n" + // Save r4..r7 in r0..r3: verify that we populate + // the youngest frame with all the values we have. + "STACK CFI 4002 r4: r0 r5: r1 r6: r2 r7: r3\n" + // Restore r4..r7. Save the non-callee-saves register r1. + "STACK CFI 4003 .cfa: sp 16 + r1: .cfa 16 - ^" + " r4: r4 r5: r5 r6: r6 r7: r7\n" + // Move the .cfa back four bytes, to point at the return + // address, and restore the sp explicitly. + "STACK CFI 4005 .cfa: sp 12 + r1: .cfa 12 - ^" + " r11: .cfa 4 - ^ .ra: .cfa ^ sp: .cfa 4 +\n" + // Recover the PC explicitly from a new stack slot; + // provide garbage for the .ra. + "STACK CFI 4006 .cfa: sp 16 + pc: .cfa 16 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: 0 .ra: 0\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: sp 4 - .ra: lr\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n"); + + // Provide some distinctive values for the caller's registers. + expected.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510; + expected.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000; + expected.iregs[4] = 0xb5d55e68; + expected.iregs[5] = 0xebd134f3; + expected.iregs[6] = 0xa31e74bc; + expected.iregs[7] = 0x2dcb16b3; + expected.iregs[8] = 0x2ada2137; + expected.iregs[9] = 0xbbbb557d; + expected.iregs[10] = 0x48bf8ca7; + expected.iregs[MD_CONTEXT_ARM_REG_FP] = 0x8112e110; + + // Expect CFI to recover all callee-saves registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_SP | + StackFrameARM::CONTEXT_VALID_R4 | + StackFrameARM::CONTEXT_VALID_R5 | + StackFrameARM::CONTEXT_VALID_R6 | + StackFrameARM::CONTEXT_VALID_R7 | + StackFrameARM::CONTEXT_VALID_R8 | + StackFrameARM::CONTEXT_VALID_R9 | + StackFrameARM::CONTEXT_VALID_R10 | + StackFrameARM::CONTEXT_VALID_FP); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameARM::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, + &modules, &frame_symbolizer); + walker.SetContextFrameValidity(context_frame_validity); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(context_frame_validity, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x40004000U, frame0->function_base); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R1) + EXPECT_EQ(expected.iregs[1], frame1->context.iregs[1]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R4) + EXPECT_EQ(expected.iregs[4], frame1->context.iregs[4]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R5) + EXPECT_EQ(expected.iregs[5], frame1->context.iregs[5]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R6) + EXPECT_EQ(expected.iregs[6], frame1->context.iregs[6]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R7) + EXPECT_EQ(expected.iregs[7], frame1->context.iregs[7]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R8) + EXPECT_EQ(expected.iregs[8], frame1->context.iregs[8]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R9) + EXPECT_EQ(expected.iregs[9], frame1->context.iregs[9]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_R10) + EXPECT_EQ(expected.iregs[10], frame1->context.iregs[10]); + if (expected_validity & StackFrameARM::CONTEXT_VALID_FP) + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_FP], + frame1->context.iregs[MD_CONTEXT_ARM_REG_FP]); + + // We would never have gotten a frame in the first place if the SP + // and PC weren't valid or ->instruction weren't set. + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_SP], + frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_PC], + frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_ARM_REG_PC], + frame1->instruction + 2); + EXPECT_EQ("epictetus", frame1->function_name); + } + + // The values we expect to find for the caller's registers. + MDRawContextARM expected; + + // The validity mask for expected. + int expected_validity; + + // The validity mask to impose on the context frame. + int context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + stack_section.start() = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004000; + raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = 0x40005510; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0xb5d55e68) // saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004001; + raw_context.iregs[4] = 0x635adc9f; // distinct callee r4 + raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp + CheckWalk(); +} + +// As above, but unwind from a context that has only the PC and SP. +TEST_F(CFI, At4001LimitedValidity) { + context_frame_validity = + StackFrameARM::CONTEXT_VALID_PC | StackFrameARM::CONTEXT_VALID_SP; + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004001; + raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0xb5d55e68) // saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + expected_validity = (StackFrameARM::CONTEXT_VALID_PC + | StackFrameARM::CONTEXT_VALID_SP + | StackFrameARM::CONTEXT_VALID_FP + | StackFrameARM::CONTEXT_VALID_R4); + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0xfb81ff3d) // no longer saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004002; + raw_context.iregs[0] = 0xb5d55e68; // saved r4 + raw_context.iregs[1] = 0xebd134f3; // saved r5 + raw_context.iregs[2] = 0xa31e74bc; // saved r6 + raw_context.iregs[3] = 0x2dcb16b3; // saved r7 + raw_context.iregs[4] = 0xfdd35466; // distinct callee r4 + raw_context.iregs[5] = 0xf18c946c; // distinct callee r5 + raw_context.iregs[6] = 0xac2079e8; // distinct callee r6 + raw_context.iregs[7] = 0xa449829f; // distinct callee r7 + raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0xbe145fc4; // distinct callee fp + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) + .D32(0xcb78040e) // no longer saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004003; + raw_context.iregs[1] = 0xfb756319; // distinct callee r1 + raw_context.iregs[MD_CONTEXT_ARM_REG_FP] = 0x0a2857ea; // distinct callee fp + expected.iregs[1] = 0x48c8dd5a; // caller's r1 + expected_validity |= StackFrameARM::CONTEXT_VALID_R1; + CheckWalk(); +} + +// We have no new rule at module offset 0x4004, so the results here should +// be the same as those at module offset 0x4003. +TEST_F(CFI, At4004) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) + .D32(0xcb78040e) // no longer saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004004; + raw_context.iregs[1] = 0xfb756319; // distinct callee r1 + expected.iregs[1] = 0x48c8dd5a; // caller's r1 + expected_validity |= StackFrameARM::CONTEXT_VALID_R1; + CheckWalk(); +} + +// Here we move the .cfa, but provide an explicit rule to recover the SP, +// so again there should be no change in the registers recovered. +TEST_F(CFI, At4005) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) + .D32(0xf013f841) // no longer saved r4 + .D32(0x8112e110) // saved fp + .D32(0x40005510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004005; + raw_context.iregs[1] = 0xfb756319; // distinct callee r1 + expected.iregs[1] = 0x48c8dd5a; // caller's r1 + expected_validity |= StackFrameARM::CONTEXT_VALID_R1; + CheckWalk(); +} + +// Here we provide an explicit rule for the PC, and have the saved .ra be +// bogus. +TEST_F(CFI, At4006) { + Label frame1_sp = expected.iregs[MD_CONTEXT_ARM_REG_SP]; + stack_section + .D32(0x40005510) // saved pc + .D32(0x48c8dd5a) // saved r1 (even though it's not callee-saves) + .D32(0xf013f841) // no longer saved r4 + .D32(0x8112e110) // saved fp + .D32(0xf8d15783) // .ra rule recovers this, which is garbage + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40004006; + raw_context.iregs[1] = 0xfb756319; // callee's r1, different from caller's + expected.iregs[1] = 0x48c8dd5a; // caller's r1 + expected_validity |= StackFrameARM::CONTEXT_VALID_R1; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40006000; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000; + raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = 0x40005510; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40007000; + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = 0x80000000; + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +class StackwalkerARMFixtureIOS : public StackwalkerARMFixture { + public: + StackwalkerARMFixtureIOS() { + // iOS_test is used instead of iOS because the stackwalker has a check to + // avoid using CFI for iOS dumps. This is a workaround for bad CFI being + // produced by dump_syms for iOS. + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=764 + system_info.os = "iOS_test"; + system_info.os_short = "ios_test"; + } +}; + +class GetFramesByFramePointer: public StackwalkerARMFixtureIOS, public Test { }; + +TEST_F(GetFramesByFramePointer, OnlyFramePointer) { + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x50000100; + uint32_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + Label frame1_fp, frame2_fp; + stack_section + // frame 0 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame1_fp) // Next fp will point to the next value. + .D32(frame2_fp) // Save current frame pointer. + .D32(return_address2) // Save current link register. + .Mark(&frame1_sp) + + // frame 1 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame2_fp) + .D32(0) + .D32(0) + .Mark(&frame2_sp) + + // frame 2 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000); // a return address. + RegionFromSection(); + + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x40005510; + raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = return_address1; + raw_context.iregs[MD_CONTEXT_ARM_REG_IOS_FP] = frame1_fp.Value(); + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP, + &stack_region, &modules, &frame_symbolizer); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) | + StackFrameARM::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(return_address2, frame1->context.iregs[MD_CONTEXT_ARM_REG_LR]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ(frame2_fp.Value(), + frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]); + + StackFrameARM *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame2->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) | + StackFrameARM::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_LR]); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]); +} + +TEST_F(GetFramesByFramePointer, FramePointerAndCFI) { + // Provide the standatd STACK CFI records that is obtained when exmining an + // executable produced by XCode. + SetModuleSymbols(&module1, + // Adding a function in CFI. + "FUNC 4000 1000 10 enchiridion\n" + + "STACK CFI INIT 4000 100 .cfa: sp 0 + .ra: lr\n" + "STACK CFI 4001 .cfa: sp 8 + .ra: .cfa -4 + ^" + " r7: .cfa -8 + ^\n" + "STACK CFI 4002 .cfa: r7 8 +\n" + ); + + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x40004010; + uint32_t return_address2 = 0x50000900; + Label frame1_sp, frame2_sp; + Label frame1_fp, frame2_fp; + stack_section + // frame 0 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame1_fp) // Next fp will point to the next value. + .D32(frame2_fp) // Save current frame pointer. + .D32(return_address2) // Save current link register. + .Mark(&frame1_sp) + + // frame 1 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000) // a return address. + + .Mark(&frame2_fp) + .D32(0) + .D32(0) + .Mark(&frame2_sp) + + // frame 2 + .Append(32, 0) // Whatever values on the stack. + .D32(0x0000000D) // junk that's not + .D32(0xF0000000); // a return address. + RegionFromSection(); + + + raw_context.iregs[MD_CONTEXT_ARM_REG_PC] = 0x50000400; + raw_context.iregs[MD_CONTEXT_ARM_REG_LR] = return_address1; + raw_context.iregs[MD_CONTEXT_ARM_REG_IOS_FP] = frame1_fp.Value(); + raw_context.iregs[MD_CONTEXT_ARM_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP, + &stack_region, &modules, &frame_symbolizer); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module2", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameARM *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameARM::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameARM *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) | + StackFrameARM::CONTEXT_VALID_SP), + frame1->context_validity); + EXPECT_EQ(return_address1, frame1->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(return_address2, frame1->context.iregs[MD_CONTEXT_ARM_REG_LR]); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ(frame2_fp.Value(), + frame1->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]); + EXPECT_EQ("enchiridion", frame1->function_name); + EXPECT_EQ(0x40004000U, frame1->function_base); + + + StackFrameARM *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); + ASSERT_EQ((StackFrameARM::CONTEXT_VALID_PC | + StackFrameARM::CONTEXT_VALID_LR | + StackFrameARM::RegisterValidFlag(MD_CONTEXT_ARM_REG_IOS_FP) | + StackFrameARM::CONTEXT_VALID_SP), + frame2->context_validity); + EXPECT_EQ(return_address2, frame2->context.iregs[MD_CONTEXT_ARM_REG_PC]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_LR]); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_ARM_REG_SP]); + EXPECT_EQ(0U, frame2->context.iregs[MD_CONTEXT_ARM_REG_IOS_FP]); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.cc new file mode 100644 index 0000000000..c33ecdbe96 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.cc @@ -0,0 +1,442 @@ +// Copyright (c) 2013 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_mips.cc: MIPS-specific stackwalker. +// +// See stackwalker_mips.h for documentation. +// +// Author: Tata Elxsi + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/cfi_frame_info.h" +#include "processor/logging.h" +#include "processor/postfix_evaluator-inl.h" +#include "processor/stackwalker_mips.h" +#include "processor/windows_frame_info.h" +#include "google_breakpad/common/minidump_cpu_mips.h" + +namespace google_breakpad { + +StackwalkerMIPS::StackwalkerMIPS(const SystemInfo* system_info, + const MDRawContextMIPS* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) +: Stackwalker(system_info, memory, modules, resolver_helper), + context_(context) { + if (memory_) { + if (context_->context_flags & MD_CONTEXT_MIPS64 ) { + if (0xffffffffffffffff - memory_->GetBase() < memory_->GetSize() - 1) { + BPLOG(ERROR) << "Memory out of range for stackwalking mips64: " + << HexString(memory_->GetBase()) + << "+" + << HexString(memory_->GetSize()); + memory_ = NULL; + } + } else { + if (0xffffffff - memory_->GetBase() < memory_->GetSize() - 1) { + BPLOG(ERROR) << "Memory out of range for stackwalking mips32: " + << HexString(memory_->GetBase()) + << "+" + << HexString(memory_->GetSize()); + memory_ = NULL; + } + } + } +} + +StackFrame* StackwalkerMIPS::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context."; + return NULL; + } + + StackFrameMIPS* frame = new StackFrameMIPS(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFrameMIPS::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.epc; + + return frame; +} + +// Register names for mips. +static const char* const kRegisterNames[] = { + "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$to", "$t1", + "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", + "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", + "$fp", "$ra", NULL + // TODO(gordanac): add float point save registers +}; + +StackFrameMIPS* StackwalkerMIPS::GetCallerByCFIFrameInfo( + const vector& frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameMIPS* last_frame = static_cast(frames.back()); + + if (context_->context_flags & MD_CONTEXT_MIPS) { + uint32_t pc = 0; + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap callee_registers; + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap caller_registers; + + for (int i = 0; kRegisterNames[i]; ++i) { + caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; + callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; + } + + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return NULL; + } + + CFIFrameInfo::RegisterValueMap::const_iterator entry = + caller_registers.find(".cfa"); + + if (entry != caller_registers.end()) { + caller_registers["$sp"] = entry->second; + } + + entry = caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + caller_registers["$ra"] = entry->second; + pc = entry->second - 2 * sizeof(pc); + } + caller_registers["$pc"] = pc; + // Construct a new stack frame given the values the CFI recovered. + scoped_ptr frame(new StackFrameMIPS()); + + for (int i = 0; kRegisterNames[i]; ++i) { + CFIFrameInfo::RegisterValueMap::const_iterator caller_entry = + caller_registers.find(kRegisterNames[i]); + + if (caller_entry != caller_registers.end()) { + // The value of this register is recovered; fill the context with the + // value from caller_registers. + frame->context.iregs[i] = caller_entry->second; + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); + } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) || + (i > INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) && + (last_frame->context_validity & + StackFrameMIPS::RegisterValidFlag(i))) { + // If the STACK CFI data doesn't mention some callee-save register, and + // it is valid in the callee, assume the callee has not yet changed it. + // Calee-save registers according to the MIPS o32 ABI specification are: + // $s0 to $s7 + // $sp, $s8 + frame->context.iregs[i] = last_frame->context.iregs[i]; + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); + } + } + + frame->context.epc = caller_registers["$pc"]; + frame->instruction = caller_registers["$pc"]; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"]; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + + return frame.release(); + } else { + uint64_t pc = 0; + + // Populate a dictionary with the valid register values in last_frame. + CFIFrameInfo::RegisterValueMap callee_registers; + // Use the STACK CFI data to recover the caller's register values. + CFIFrameInfo::RegisterValueMap caller_registers; + + for (int i = 0; kRegisterNames[i]; ++i) { + caller_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; + callee_registers[kRegisterNames[i]] = last_frame->context.iregs[i]; + } + + if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_, + &caller_registers)) { + return NULL; + } + + CFIFrameInfo::RegisterValueMap::const_iterator entry = + caller_registers.find(".cfa"); + + if (entry != caller_registers.end()) { + caller_registers["$sp"] = entry->second; + } + + entry = caller_registers.find(".ra"); + if (entry != caller_registers.end()) { + caller_registers["$ra"] = entry->second; + pc = entry->second - 2 * sizeof(pc); + } + caller_registers["$pc"] = pc; + // Construct a new stack frame given the values the CFI recovered. + scoped_ptr frame(new StackFrameMIPS()); + + for (int i = 0; kRegisterNames[i]; ++i) { + CFIFrameInfo::RegisterValueMap::const_iterator caller_entry = + caller_registers.find(kRegisterNames[i]); + + if (caller_entry != caller_registers.end()) { + // The value of this register is recovered; fill the context with the + // value from caller_registers. + frame->context.iregs[i] = caller_entry->second; + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); + } else if (((i >= INDEX_MIPS_REG_S0 && i <= INDEX_MIPS_REG_S7) || + (i >= INDEX_MIPS_REG_GP && i < INDEX_MIPS_REG_RA)) && + (last_frame->context_validity & + StackFrameMIPS::RegisterValidFlag(i))) { + // If the STACK CFI data doesn't mention some callee-save register, and + // it is valid in the callee, assume the callee has not yet changed it. + // Calee-save registers according to the MIPS o32 ABI specification are: + // $s0 to $s7 + // $sp, $s8 + frame->context.iregs[i] = last_frame->context.iregs[i]; + frame->context_validity |= StackFrameMIPS::RegisterValidFlag(i); + } + } + + frame->context.epc = caller_registers["$pc"]; + frame->instruction = caller_registers["$pc"]; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = caller_registers["$ra"]; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + + return frame.release(); + } +} + +StackFrame* StackwalkerMIPS::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector& frames = *stack->frames(); + StackFrameMIPS* last_frame = static_cast(frames.back()); + scoped_ptr new_frame; + + // See if there is DWARF call frame information covering this address. + scoped_ptr cfi_frame_info( + frame_symbolizer_->FindCFIFrameInfo(last_frame)); + if (cfi_frame_info.get()) + new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info.get())); + + // If caller frame is not found in CFI try analyzing the stack. + if (stack_scan_allowed && !new_frame.get()) { + new_frame.reset(GetCallerByStackScan(frames)); + } + + // If nothing worked, tell the caller. + if (!new_frame.get()) { + return NULL; + } + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(new_frame->context.epc, + new_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP], + last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP], + frames.size() == 1)) { + return NULL; + } + + return new_frame.release(); +} + +StackFrameMIPS* StackwalkerMIPS::GetCallerByStackScan( + const vector& frames) { + const uint32_t kMaxFrameStackSize = 1024; + const uint32_t kMinArgsOnStack = 4; + + StackFrameMIPS* last_frame = static_cast(frames.back()); + + if (context_->context_flags & MD_CONTEXT_MIPS) { + uint32_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]; + uint32_t caller_pc, caller_sp, caller_fp; + + // Return address cannot be obtained directly. + // Force stackwalking. + + // We cannot use frame pointer to get the return address. + // We'll scan the stack for a + // return address. This can happen if last_frame is executing code + // for a module for which we don't have symbols. + int count = kMaxFrameStackSize / sizeof(caller_pc); + + if (frames.size() > 1) { + // In case of mips32 ABI stack frame of a nonleaf function + // must have minimum stack frame assigned for 4 arguments (4 words). + // Move stack pointer for 4 words to avoid reporting non-existing frames + // for all frames except the topmost one. + // There is no way of knowing if topmost frame belongs to a leaf or + // a nonleaf function. + last_sp += kMinArgsOnStack * sizeof(caller_pc); + // Adjust 'count' so that return address is scanned only in limits + // of one stack frame. + count -= kMinArgsOnStack; + } + + do { + // Scanning for return address from stack pointer of the last frame. + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) { + // If we can't find an instruction pointer even with stack scanning, + // give up. + BPLOG(ERROR) << " ScanForReturnAddress failed "; + return NULL; + } + // Get $fp stored in the stack frame. + if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc), + &caller_fp)) { + BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ; + return NULL; + } + + count = count - (caller_sp - last_sp) / sizeof(caller_pc); + // Now scan the next address in the stack. + last_sp = caller_sp + sizeof(caller_pc); + } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0); + + if (!count) { + BPLOG(INFO) << " No frame found " ; + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // $sp to the location above the one where the return address was + // found. + caller_sp += sizeof(caller_pc); + // caller_pc is actually containing $ra value; + // $pc is two instructions before $ra, + // so the caller_pc needs to be decremented accordingly. + caller_pc -= 2 * sizeof(caller_pc); + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameMIPS* frame = new StackFrameMIPS(); + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.epc = caller_pc; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; + frame->instruction = caller_pc; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP; + frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = + caller_pc + 2 * sizeof(caller_pc); + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; + + return frame; + } else { + uint64_t last_sp = last_frame->context.iregs[MD_CONTEXT_MIPS_REG_SP]; + uint64_t caller_pc, caller_sp, caller_fp; + + // Return address cannot be obtained directly. + // Force stackwalking. + + // We cannot use frame pointer to get the return address. + // We'll scan the stack for a + // return address. This can happen if last_frame is executing code + // for a module for which we don't have symbols. + int count = kMaxFrameStackSize / sizeof(caller_pc); + + do { + // Scanning for return address from stack pointer of the last frame. + if (!ScanForReturnAddress(last_sp, &caller_sp, &caller_pc, count)) { + // If we can't find an instruction pointer even with stack scanning, + // give up. + BPLOG(ERROR) << " ScanForReturnAddress failed "; + return NULL; + } + // Get $fp stored in the stack frame. + if (!memory_->GetMemoryAtAddress(caller_sp - sizeof(caller_pc), + &caller_fp)) { + BPLOG(INFO) << " GetMemoryAtAddress for fp failed " ; + return NULL; + } + + count = count - (caller_sp - last_sp) / sizeof(caller_pc); + // Now scan the next address in the stack. + last_sp = caller_sp + sizeof(caller_pc); + } while ((caller_fp - caller_sp >= kMaxFrameStackSize) && count > 0); + + if (!count) { + BPLOG(INFO) << " No frame found " ; + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance + // $sp to the location above the one where the return address was + // found. + caller_sp += sizeof(caller_pc); + // caller_pc is actually containing $ra value; + // $pc is two instructions before $ra, + // so the caller_pc needs to be decremented accordingly. + caller_pc -= 2 * sizeof(caller_pc); + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameMIPS* frame = new StackFrameMIPS(); + frame->trust = StackFrame::FRAME_TRUST_SCAN; + frame->context = last_frame->context; + frame->context.epc = caller_pc; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_PC; + frame->instruction = caller_pc; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_SP] = caller_sp; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_SP; + frame->context.iregs[MD_CONTEXT_MIPS_REG_FP] = caller_fp; + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_FP; + + frame->context.iregs[MD_CONTEXT_MIPS_REG_RA] = + caller_pc + 2 * sizeof(caller_pc); + frame->context_validity |= StackFrameMIPS::CONTEXT_VALID_RA; + + return frame; + } +} + +} // namespace google_breakpad + diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.h new file mode 100644 index 0000000000..5f97791fb7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips.h @@ -0,0 +1,85 @@ +// Copyright (c) 2013 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_mips.h: MIPS-specific stackwalker. +// +// Provides stack frames given MIPS register context and a memory region +// corresponding to a MIPSstack. +// +// Author: Tata Elxsi + +#ifndef PROCESSOR_STACKWALKER_MIPS_H__ +#define PROCESSOR_STACKWALKER_MIPS_H__ + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/cfi_frame_info.h" + +namespace google_breakpad { + +class CodeModules; + +class StackwalkerMIPS : public Stackwalker { + public: + // Context is a MIPS context object that gives access to mips-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. + StackwalkerMIPS(const SystemInfo* system_info, + const MDRawContextMIPS* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + private: + // Implementation of Stackwalker, using mips context and stack conventions. + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameMIPS* GetCallerByCFIFrameInfo(const vector& frames, + CFIFrameInfo* cfi_frame_info); + + // Scan the stack for plausible return address and frame pointer pair. + // The caller takes ownership of the returned frame. Return NULL on failure. + StackFrameMIPS* GetCallerByStackScan(const vector& frames); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextMIPS* context_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STACKWALKER_MIPS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips64_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips64_unittest.cc new file mode 100644 index 0000000000..2a9784bf71 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips64_unittest.cc @@ -0,0 +1,716 @@ +// Copyright (c) 2013, 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. + +// Original author: Veljko Mihailovic + +// stackwalker_mips64_unittest.cc: Unit tests for StackwalkerMIPS class for +// mips64 platforms. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_mips.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameMIPS; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerMIPS; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerMIPSFixture { + public: + StackwalkerMIPSFixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x00400000, 0x10000, "module1", "version1"), + module2(0x00500000, 0x10000, "module2", "version2") { + // Identify the system as a Linux system. + system_info.os = "Linux"; + system_info.os_short = "linux"; + system_info.os_version = "Observant Opossum"; // Jealous Jellyfish + system_info.cpu = "mips64"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule* module, const string& info) { + size_t buffer_size; + char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextMIPS* raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); ++i) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextMIPS raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector* frames; +}; + +class SanityCheck: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + stack_section.start() = 0x80000000; + stack_section.D64(0).D64(0x0); + RegionFromSection(); + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed, even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(GetContextFrame, Simple) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + stack_section.start() = 0x80000000; + stack_section.D64(0).D64(0x0); + RegionFromSection(); + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x00400100; + uint64_t return_address2 = 0x00400900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D64(0x00490000) // junk that's not + .D64(0x00600000) // a return address + + .D64(frame1_sp) // stack pointer + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0) // space + + .D64(0xF0000000) // more junk + .D64(0x0000000D) + + .D64(frame2_sp) // stack pointer + .D64(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address1 - 2 * sizeof(return_address1), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + + StackFrameMIPS* frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame2->context_validity); + EXPECT_EQ(return_address2 - 2 * sizeof(return_address2), frame2->context.epc); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_MIPS_REG_SP]); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint64_t return_address = 0x00500200; + Label frame1_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D64(0x00490000) // junk that's not + .D64(0x00600000) // a return address + + .D64(0x00401000) // a couple of plausible addresses + .D64(0x0050F000) // that are not within functions + + .D64(frame1_sp) // stack pointer + .D64(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00400200; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address; + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x00400100U, frame0->function_base); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address - 2 * sizeof(return_address), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x00500100U, frame1->function_base); +} + +TEST_F(GetCallerFrame, CheckStackFrameSizeLimit) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + // If the stackwalker resorts to stack scanning, it will scan only + // 1024 bytes of stack which correspondes to maximum size of stack frame. + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x00500100; + uint64_t return_address2 = 0x00500900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D64(0x00490000) // junk that's not + .D64(0x00600000) // a return address + + .Append(96, 0) // more space + + .D64(frame1_sp) // stack pointer + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(128 * 4, 0) // space + + .D64(0x00F00000) // more junk + .D64(0x0000000D) + + .Append(128 * 4, 0) // more space + + .D64(frame2_sp) // stack pointer + .D64(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address1 - 2 * sizeof(return_address1), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + // When the stack walker resorts to scanning the stack, + // only fixed number of frames are allowed to be scanned out from stack + stack_section.start() = 0x80000000; + uint64_t return_address1 = 0x00500100; + uint64_t return_address2 = 0x00500900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D64(0x00490000) // junk that's not + .D64(0x00600000) // a return address + + .Append(96, 0) // more space + + .D64(frame1_sp) // stack pointer + .D64(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(128 * 4, 0) // space + + .D64(0x00F00000) // more junk + .D64(0x0000000D) + + .Append(128 * 4, 0) // more space + + .D64(frame2_sp) // stack pointer + .D64(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(64, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +struct CFIFixture: public StackwalkerMIPSFixture { + CFIFixture() { + // Provide some STACK CFI records; + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 0 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the $ra register. + "STACK CFI INIT 4000 1000 .cfa: $sp 0 + .ra: $ra\n" + // Move stack pointer. + "STACK CFI 4004 .cfa: $sp 32 +\n" + // store $fp and ra + "STACK CFI 4008 $fp: .cfa -8 + ^ .ra: .cfa -4 + ^\n" + // restore $fp + "STACK CFI 400c .cfa: $fp 32 +\n" + // restore $sp + "STACK CFI 4018 .cfa: $sp 32 +\n" + + "STACK CFI 4020 $fp: $fp .cfa: $sp 0 + .ra: .ra\n" + + // The calling function. + "FUNC 5000 1000 0 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 8 .cfa: $sp 0 + .ra: $ra\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: $sp 4 - .ra: $ra\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n" + ); + + // Provide some distinctive values for the caller's registers. + expected.epc = 0x00405500; + expected.iregs[MD_CONTEXT_MIPS_REG_S0] = 0x0; + expected.iregs[MD_CONTEXT_MIPS_REG_S1] = 0x1; + expected.iregs[MD_CONTEXT_MIPS_REG_S2] = 0x2; + expected.iregs[MD_CONTEXT_MIPS_REG_S3] = 0x3; + expected.iregs[MD_CONTEXT_MIPS_REG_S4] = 0x4; + expected.iregs[MD_CONTEXT_MIPS_REG_S5] = 0x5; + expected.iregs[MD_CONTEXT_MIPS_REG_S6] = 0x6; + expected.iregs[MD_CONTEXT_MIPS_REG_S7] = 0x7; + expected.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + expected.iregs[MD_CONTEXT_MIPS_REG_FP] = 0x80000000; + expected.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + // Expect CFI to recover all callee-save registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_S0 | + StackFrameMIPS::CONTEXT_VALID_S1 | + StackFrameMIPS::CONTEXT_VALID_S2 | + StackFrameMIPS::CONTEXT_VALID_S3 | + StackFrameMIPS::CONTEXT_VALID_S4 | + StackFrameMIPS::CONTEXT_VALID_S5 | + StackFrameMIPS::CONTEXT_VALID_S6 | + StackFrameMIPS::CONTEXT_VALID_S7 | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_GP | + StackFrameMIPS::CONTEXT_VALID_RA); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameMIPS::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x00404000U, frame0->function_base); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S0], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S0]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S1], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S1]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S2], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S2]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S3], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S3]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S4], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S4]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S5], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S5]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S6], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S6]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S7], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S7]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_FP], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_FP]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_RA], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_RA]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_SP], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + EXPECT_EQ(expected.epc, frame1->context.epc); + EXPECT_EQ(expected.epc, frame1->instruction); + EXPECT_EQ("epictetus", frame1->function_name); + EXPECT_EQ(0x00405000U, frame1->function_base); + } + + // The values we expect to find for the caller's registers. + MDRawContextMIPS expected; + + // The validity mask for expected. + int expected_validity; + + // The validity mask to impose on the context frame. + int context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +// TODO(gordanac): add CFI tests + +TEST_F(CFI, At4004) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + Label frame1_sp = expected.iregs[MD_CONTEXT_MIPS_REG_SP]; + stack_section + // frame0 + .Append(16, 0) // space + .D64(frame1_sp) // stack pointer + .D64(0x00405510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.epc = 0x00404004; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + raw_context.epc = 0x40005000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.context_flags = + raw_context.context_flags | MD_CONTEXT_MIPS64_FULL; + raw_context.epc = 0x00407000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips_unittest.cc new file mode 100644 index 0000000000..a172f17b9d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_mips_unittest.cc @@ -0,0 +1,704 @@ +// Copyright (c) 2013, 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. + +// Original author: Gordana Cmiljanovic + +// stackwalker_mips_unittest.cc: Unit tests for StackwalkerMIPS class. + +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_mips.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameMIPS; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerMIPS; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerMIPSFixture { + public: + StackwalkerMIPSFixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x00400000, 0x10000, "module1", "version1"), + module2(0x00500000, 0x10000, "module2", "version2") { + // Identify the system as a Linux system. + system_info.os = "Linux"; + system_info.os_short = "linux"; + system_info.os_version = "Observant Opossum"; // Jealous Jellyfish + system_info.cpu = "mips"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule* module, const string& info) { + size_t buffer_size; + char* buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextMIPS* raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); ++i) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextMIPS raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector* frames; +}; + +class SanityCheck: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + stack_section.start() = 0x80000000; + stack_section.D32(0).D32(0x0); + RegionFromSection(); + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed, even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(GetContextFrame, Simple) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + stack_section.start() = 0x80000000; + stack_section.D32(0).D32(0x0); + RegionFromSection(); + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + raw_context.epc = 0x00400020; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameMIPS* frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerMIPSFixture, public Test { }; + +TEST_F(GetCallerFrame, ScanWithoutSymbols) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + // When the stack walker resorts to scanning the stack, + // only addresses located within loaded modules are + // considered valid return addresses. + // Force scanning through three frames to ensure that the + // stack pointer is set properly in scan-recovered frames. + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x00400100; + uint32_t return_address2 = 0x00400900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x00490000) // junk that's not + .D32(0x00600000) // a return address + + .D32(frame1_sp) // stack pointer + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(16, 0) // space + + .D32(0xF0000000) // more junk + .D32(0x0000000D) + + .D32(frame2_sp) // stack pointer + .D32(return_address2) // actual return address + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address1 - 2 * sizeof(return_address1), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + + StackFrameMIPS* frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame2->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame2->context_validity); + EXPECT_EQ(return_address2 - 2 * sizeof(return_address2), frame2->context.epc); + EXPECT_EQ(frame2_sp.Value(), frame2->context.iregs[MD_CONTEXT_MIPS_REG_SP]); +} + +TEST_F(GetCallerFrame, ScanWithFunctionSymbols) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + // During stack scanning, if a potential return address + // is located within a loaded module that has symbols, + // it is only considered a valid return address if it + // lies within a function's bounds. + stack_section.start() = 0x80000000; + uint32_t return_address = 0x00500200; + Label frame1_sp; + stack_section + // frame 0 + .Append(16, 0) // space + + .D32(0x00490000) // junk that's not + .D32(0x00600000) // a return address + + .D32(0x00401000) // a couple of plausible addresses + .D32(0x0050F000) // that are not within functions + + .D32(frame1_sp) // stack pointer + .D32(return_address) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00400200; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address; + + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 100 400 10 monotreme\n"); + SetModuleSymbols(&module2, + // The calling frame's function. + "FUNC 100 400 10 marsupial\n"); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + EXPECT_EQ("monotreme", frame0->function_name); + EXPECT_EQ(0x00400100U, frame0->function_base); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address - 2 * sizeof(return_address), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + EXPECT_EQ("marsupial", frame1->function_name); + EXPECT_EQ(0x00500100U, frame1->function_base); +} + +TEST_F(GetCallerFrame, CheckStackFrameSizeLimit) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + // If the stackwalker resorts to stack scanning, it will scan only + // 1024 bytes of stack which correspondes to maximum size of stack frame. + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x00500100; + uint32_t return_address2 = 0x00500900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D32(0x00490000) // junk that's not + .D32(0x00600000) // a return address + + .Append(96, 0) // more space + + .D32(frame1_sp) // stack pointer + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(128 * 4, 0) // space + + .D32(0x00F00000) // more junk + .D32(0x0000000D) + + .Append(128 * 4, 0) // more space + + .D32(frame2_sp) // stack pointer + .D32(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(2U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ("module2", modules_without_symbols[1]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA), + frame1->context_validity); + EXPECT_EQ(return_address1 - 2 * sizeof(return_address1), frame1->context.epc); + EXPECT_EQ(frame1_sp.Value(), frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + // When the stack walker resorts to scanning the stack, + // only fixed number of frames are allowed to be scanned out from stack + stack_section.start() = 0x80000000; + uint32_t return_address1 = 0x00500100; + uint32_t return_address2 = 0x00500900; + Label frame1_sp, frame2_sp; + stack_section + // frame 0 + .Append(32, 0) // space + + .D32(0x00490000) // junk that's not + .D32(0x00600000) // a return address + + .Append(96, 0) // more space + + .D32(frame1_sp) // stack pointer + .D32(return_address1) // actual return address + // frame 1 + .Mark(&frame1_sp) + .Append(128 * 4, 0) // space + + .D32(0x00F00000) // more junk + .D32(0x0000000D) + + .Append(128 * 4, 0) // more space + + .D32(frame2_sp) // stack pointer + .D32(return_address2) // actual return address + // (won't be found) + // frame 2 + .Mark(&frame2_sp) + .Append(32, 0); // end of stack + RegionFromSection(); + + raw_context.epc = 0x00405510; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = return_address1; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context))); +} + +struct CFIFixture: public StackwalkerMIPSFixture { + CFIFixture() { + // Provide some STACK CFI records; + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 0 enchiridion\n" + // Initially, nothing has been pushed on the stack, + // and the return address is still in the $ra register. + "STACK CFI INIT 4000 1000 .cfa: $sp 0 + .ra: $ra\n" + // Move stack pointer. + "STACK CFI 4004 .cfa: $sp 32 +\n" + // store $fp and ra + "STACK CFI 4008 $fp: .cfa -8 + ^ .ra: .cfa -4 + ^\n" + // restore $fp + "STACK CFI 400c .cfa: $fp 32 +\n" + // restore $sp + "STACK CFI 4018 .cfa: $sp 32 +\n" + + "STACK CFI 4020 $fp: $fp .cfa: $sp 0 + .ra: .ra\n" + + // The calling function. + "FUNC 5000 1000 0 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 8 .cfa: $sp 0 + .ra: $ra\n" + + // A function whose CFI makes the stack pointer + // go backwards. + "FUNC 6000 1000 20 palinal\n" + "STACK CFI INIT 6000 1000 .cfa: $sp 4 - .ra: $ra\n" + + // A function with CFI expressions that can't be + // evaluated. + "FUNC 7000 1000 20 rhetorical\n" + "STACK CFI INIT 7000 1000 .cfa: moot .ra: ambiguous\n" + ); + + // Provide some distinctive values for the caller's registers. + expected.epc = 0x00405508; + expected.iregs[MD_CONTEXT_MIPS_REG_S0] = 0x0; + expected.iregs[MD_CONTEXT_MIPS_REG_S1] = 0x1; + expected.iregs[MD_CONTEXT_MIPS_REG_S2] = 0x2; + expected.iregs[MD_CONTEXT_MIPS_REG_S3] = 0x3; + expected.iregs[MD_CONTEXT_MIPS_REG_S4] = 0x4; + expected.iregs[MD_CONTEXT_MIPS_REG_S5] = 0x5; + expected.iregs[MD_CONTEXT_MIPS_REG_S6] = 0x6; + expected.iregs[MD_CONTEXT_MIPS_REG_S7] = 0x7; + expected.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + expected.iregs[MD_CONTEXT_MIPS_REG_FP] = 0x80000000; + expected.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + // Expect CFI to recover all callee-save registers. Since CFI is the + // only stack frame construction technique we have, aside from the + // context frame itself, there's no way for us to have a set of valid + // registers smaller than this. + expected_validity = (StackFrameMIPS::CONTEXT_VALID_PC | + StackFrameMIPS::CONTEXT_VALID_S0 | + StackFrameMIPS::CONTEXT_VALID_S1 | + StackFrameMIPS::CONTEXT_VALID_S2 | + StackFrameMIPS::CONTEXT_VALID_S3 | + StackFrameMIPS::CONTEXT_VALID_S4 | + StackFrameMIPS::CONTEXT_VALID_S5 | + StackFrameMIPS::CONTEXT_VALID_S6 | + StackFrameMIPS::CONTEXT_VALID_S7 | + StackFrameMIPS::CONTEXT_VALID_SP | + StackFrameMIPS::CONTEXT_VALID_FP | + StackFrameMIPS::CONTEXT_VALID_RA); + + // By default, context frames provide all registers, as normal. + context_frame_validity = StackFrameMIPS::CONTEXT_VALID_ALL; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set the stack + // pointer to the stack's starting address.) Expect two stack + // frames; in the older frame, expect the callee-saves registers to + // have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, + &modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + StackFrameMIPS* frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameMIPS::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x00404000U, frame0->function_base); + + StackFrameMIPS* frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ(expected_validity, frame1->context_validity); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S0], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S0]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S1], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S1]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S2], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S2]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S3], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S3]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S4], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S4]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S5], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S5]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S6], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S6]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_S7], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_S7]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_FP], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_FP]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_RA], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_RA]); + EXPECT_EQ(expected.iregs[MD_CONTEXT_MIPS_REG_SP], + frame1->context.iregs[MD_CONTEXT_MIPS_REG_SP]); + EXPECT_EQ(expected.epc, frame1->context.epc); + EXPECT_EQ(expected.epc, frame1->instruction); + EXPECT_EQ("epictetus", frame1->function_name); + EXPECT_EQ(0x00405000U, frame1->function_base); + } + + // The values we expect to find for the caller's registers. + MDRawContextMIPS expected; + + // The validity mask for expected. + int expected_validity; + + // The validity mask to impose on the context frame. + int context_frame_validity; +}; + +class CFI: public CFIFixture, public Test { }; + +// TODO(gordanac): add CFI tests + +TEST_F(CFI, At4004) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + Label frame1_sp = expected.iregs[MD_CONTEXT_MIPS_REG_SP]; + stack_section + // frame0 + .Append(24, 0) // space + .D32(frame1_sp) // stack pointer + .D32(0x00405510) // return address + .Mark(&frame1_sp); // This effectively sets stack_section.start(). + raw_context.epc = 0x00404004; + CheckWalk(); +} + +// Check that we reject rules that would cause the stack pointer to +// move in the wrong direction. +TEST_F(CFI, RejectBackwards) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + raw_context.epc = 0x40005000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} + +// Check that we reject rules whose expressions' evaluation fails. +TEST_F(CFI, RejectBadExpressions) { + raw_context.context_flags = raw_context.context_flags | MD_CONTEXT_MIPS_FULL; + raw_context.epc = 0x00407000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_SP] = 0x80000000; + raw_context.iregs[MD_CONTEXT_MIPS_REG_RA] = 0x00405510; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerMIPS walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.cc new file mode 100644 index 0000000000..1e34c38336 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.cc @@ -0,0 +1,155 @@ +// Copyright (c) 2010 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.cc: ppc-specific stackwalker. +// +// See stackwalker_ppc.h for documentation. +// +// Author: Mark Mentovai + + +#include "common/scoped_ptr.h" +#include "processor/stackwalker_ppc.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" + +namespace google_breakpad { + + +StackwalkerPPC::StackwalkerPPC(const SystemInfo* system_info, + const MDRawContextPPC* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context) { + if (memory_ && memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { + // This implementation only covers 32-bit ppc CPUs. The limits of the + // supplied stack are invalid. Mark memory_ = NULL, which will cause + // stackwalking to fail. + BPLOG(ERROR) << "Memory out of range for stackwalking: " << + HexString(memory_->GetBase()) << "+" << + HexString(memory_->GetSize()); + memory_ = NULL; + } +} + + +StackFrame* StackwalkerPPC::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFramePPC* frame = new StackFramePPC(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFramePPC::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.srr0; + + return frame; +} + + +StackFrame* StackwalkerPPC::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + // The instruction pointers for previous frames are saved on the stack. + // The typical ppc calling convention is for the called procedure to store + // its return address in the calling procedure's stack frame at 8(%r1), + // and to allocate its own stack frame by decrementing %r1 (the stack + // pointer) and saving the old value of %r1 at 0(%r1). Because the ppc has + // no hardware stack, there is no distinction between the stack pointer and + // frame pointer, and what is typically thought of as the frame pointer on + // an x86 is usually referred to as the stack pointer on a ppc. + + StackFramePPC* last_frame = static_cast( + stack->frames()->back()); + + // A caller frame must reside higher in memory than its callee frames. + // Anything else is an error, or an indication that we've reached the + // end of the stack. + uint32_t stack_pointer; + if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], + &stack_pointer) || + stack_pointer <= last_frame->context.gpr[1]) { + return NULL; + } + + // Mac OS X/Darwin gives 1 as the return address from the bottom-most + // frame in a stack (a thread's entry point). I haven't found any + // documentation on this, but 0 or 1 would be bogus return addresses, + // so check for them here and return false (end of stack) when they're + // hit to avoid having a phantom frame. + uint32_t instruction; + if (!memory_->GetMemoryAtAddress(stack_pointer + 8, &instruction) || + instruction <= 1) { + return NULL; + } + + scoped_ptr frame(new StackFramePPC()); + + frame->context = last_frame->context; + frame->context.srr0 = instruction; + frame->context.gpr[1] = stack_pointer; + frame->context_validity = StackFramePPC::CONTEXT_VALID_SRR0 | + StackFramePPC::CONTEXT_VALID_GPR1; + frame->trust = StackFrame::FRAME_TRUST_FP; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(instruction, + stack_pointer, + last_frame->context.gpr[1], + stack->frames()->size() == 1)) { + return NULL; + } + + // frame->context.srr0 is the return address, which is one instruction + // past the branch that caused us to arrive at the callee. Set + // frame_ppc->instruction to four less than that. Since all ppc + // instructions are 4 bytes wide, this is the address of the branch + // instruction. This allows source line information to match up with the + // line that contains a function call. Callers that require the exact + // return address value may access the context.srr0 field of StackFramePPC. + frame->instruction = frame->context.srr0 - 4; + + return frame.release(); +} + + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.h new file mode 100644 index 0000000000..012e5c32f9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc.h @@ -0,0 +1,79 @@ +// Copyright (c) 2010 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, + StackFrameSymbolizer* frame_symbolizer); + + 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, + bool stack_scan_allowed); + + // 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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.cc new file mode 100644 index 0000000000..fb2bac3c41 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.cc @@ -0,0 +1,146 @@ +// Copyright (c) 2013 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_ppc64.cc: ppc64-specific stackwalker. +// +// See stackwalker_ppc64.h for documentation. + + +#include "common/scoped_ptr.h" +#include "processor/stackwalker_ppc64.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" + +#include + +namespace google_breakpad { + + +StackwalkerPPC64::StackwalkerPPC64(const SystemInfo* system_info, + const MDRawContextPPC64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context) { +} + + +StackFrame* StackwalkerPPC64::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFramePPC64* frame = new StackFramePPC64(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFramePPC64::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.srr0; + + return frame; +} + + +StackFrame* StackwalkerPPC64::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + // The instruction pointers for previous frames are saved on the stack. + // The typical ppc64 calling convention is for the called procedure to store + // its return address in the calling procedure's stack frame at 8(%r1), + // and to allocate its own stack frame by decrementing %r1 (the stack + // pointer) and saving the old value of %r1 at 0(%r1). Because the ppc64 has + // no hardware stack, there is no distinction between the stack pointer and + // frame pointer, and what is typically thought of as the frame pointer on + // an x86 is usually referred to as the stack pointer on a ppc64. + + StackFramePPC64* last_frame = static_cast( + stack->frames()->back()); + + // A caller frame must reside higher in memory than its callee frames. + // Anything else is an error, or an indication that we've reached the + // end of the stack. + uint64_t stack_pointer; + if (!memory_->GetMemoryAtAddress(last_frame->context.gpr[1], + &stack_pointer) || + stack_pointer <= last_frame->context.gpr[1]) { + return NULL; + } + + // Mac OS X/Darwin gives 1 as the return address from the bottom-most + // frame in a stack (a thread's entry point). I haven't found any + // documentation on this, but 0 or 1 would be bogus return addresses, + // so check for them here and return false (end of stack) when they're + // hit to avoid having a phantom frame. + uint64_t instruction; + if (!memory_->GetMemoryAtAddress(stack_pointer + 16, &instruction) || + instruction <= 1) { + return NULL; + } + + scoped_ptr frame(new StackFramePPC64()); + + frame->context = last_frame->context; + frame->context.srr0 = instruction; + frame->context.gpr[1] = stack_pointer; + frame->context_validity = StackFramePPC64::CONTEXT_VALID_SRR0 | + StackFramePPC64::CONTEXT_VALID_GPR1; + frame->trust = StackFrame::FRAME_TRUST_FP; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(instruction, + stack_pointer, + last_frame->context.gpr[1], + stack->frames()->size() == 1)) { + return NULL; + } + + // frame->context.srr0 is the return address, which is one instruction + // past the branch that caused us to arrive at the callee. Set + // frame_ppc64->instruction to eight less than that. Since all ppc64 + // instructions are 8 bytes wide, this is the address of the branch + // instruction. This allows source line information to match up with the + // line that contains a function call. Callers that require the exact + // return address value may access the context.srr0 field of StackFramePPC64. + frame->instruction = frame->context.srr0 - 8; + + return frame.release(); +} + + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.h new file mode 100644 index 0000000000..a406343af4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_ppc64.h @@ -0,0 +1,77 @@ +// Copyright (c) 2013 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_ppc64.h: ppc-specific stackwalker. +// +// Provides stack frames given ppc64 register context and a memory region +// corresponding to a ppc64 stack. + + +#ifndef PROCESSOR_STACKWALKER_PPC64_H__ +#define PROCESSOR_STACKWALKER_PPC64_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 StackwalkerPPC64 : public Stackwalker { + public: + // context is a ppc64 context object that gives access to ppc64-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. + StackwalkerPPC64(const SystemInfo* system_info, + const MDRawContextPPC64* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + private: + // Implementation of Stackwalker, using ppc64 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, + bool stack_scan_allowed); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextPPC64* context_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_PPC64_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest.cc new file mode 100644 index 0000000000..f692d4c4c0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest.cc @@ -0,0 +1,433 @@ +// 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_selftest.cc: Tests StackwalkerX86 or StackwalkerPPC using the +// running process' stack as test data, if running on an x86 or ppc and +// compiled with gcc. This test is not enabled in the "make check" suite +// by default, because certain optimizations interfere with its proper +// operation. To turn it on, configure with --enable-selftest. +// +// Optimizations that cause problems: +// - stack frame reuse. The Recursor function here calls itself with +// |return Recursor|. When the caller's frame is reused, it will cause +// CountCallerFrames to correctly return the same number of frames +// in both the caller and callee. This is considered an unexpected +// condition in the test, which expects a callee to have one more +// caller frame in the stack than its caller. +// - frame pointer omission. Even with a stackwalker that understands +// this optimization, the code to harness debug information currently +// only exists to retrieve it from minidumps, not the current process. +// +// This test can also serve as a developmental and debugging aid if +// PRINT_STACKS is defined. +// +// Author: Mark Mentovai + +#include + +#include "processor/logging.h" + +#if defined(__i386) && !defined(__i386__) +#define __i386__ +#endif +#if defined(__sparc) && !defined(__sparc__) +#define __sparc__ +#endif + +#if (defined(__SUNPRO_CC) || defined(__GNUC__)) && \ + (defined(__i386__) || defined(__ppc__) || defined(__sparc__)) + + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame.h" +#include "google_breakpad/processor/stack_frame_cpu.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::MemoryRegion; +using google_breakpad::scoped_ptr; +using google_breakpad::StackFrame; +using google_breakpad::StackFramePPC; +using google_breakpad::StackFrameX86; +using google_breakpad::StackFrameSPARC; + +#if defined(__i386__) +#include "processor/stackwalker_x86.h" +using google_breakpad::StackwalkerX86; +#elif defined(__ppc__) +#include "processor/stackwalker_ppc.h" +using google_breakpad::StackwalkerPPC; +#elif defined(__sparc__) +#include "processor/stackwalker_sparc.h" +using google_breakpad::StackwalkerSPARC; +#endif // __i386__ || __ppc__ || __sparc__ + +#define RECURSION_DEPTH 100 + + +// A simple MemoryRegion subclass that provides direct access to this +// process' memory space by pointer. +class SelfMemoryRegion : public MemoryRegion { + public: + virtual uint64_t GetBase() const { return 0; } + virtual uint32_t GetSize() const { return 0xffffffff; } + + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { + return GetMemoryAtAddressInternal(address, value); } + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { + return GetMemoryAtAddressInternal(address, value); } + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { + return GetMemoryAtAddressInternal(address, value); } + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { + return GetMemoryAtAddressInternal(address, value); } + void Print() const { + assert(false); + } + + private: + template bool GetMemoryAtAddressInternal(uint64_t address, + T* value) { + // Without knowing what addresses are actually mapped, just assume that + // everything low is not mapped. This helps the stackwalker catch the + // end of a stack when it tries to dereference a null or low pointer + // in an attempt to find the caller frame. Other unmapped accesses will + // cause the program to crash, but that would properly be a test failure. + if (address < 0x100) + return false; + + uint8_t* memory = 0; + *value = *reinterpret_cast(&memory[address]); + return true; + } +}; + + +#if defined(__GNUC__) + + +#if defined(__i386__) + +// GetEBP returns the current value of the %ebp register. Because it's +// implemented as a function, %ebp itself contains GetEBP's frame pointer +// and not the caller's frame pointer. Dereference %ebp to obtain the +// caller's frame pointer, which the compiler-generated preamble stored +// on the stack (provided frame pointers are not being omitted.) Because +// this function depends on the compiler-generated preamble, inlining is +// disabled. +static uint32_t GetEBP() __attribute__((noinline)); +static uint32_t GetEBP() { + uint32_t ebp; + __asm__ __volatile__( + "movl (%%ebp), %0" + : "=a" (ebp) + ); + return ebp; +} + + +// The caller's %esp is 8 higher than the value of %ebp in this function, +// assuming that it's not inlined and that the standard prolog is used. +// The CALL instruction places a 4-byte return address on the stack above +// the caller's %esp, and this function's prolog will save the caller's %ebp +// on the stack as well, for another 4 bytes, before storing %esp in %ebp. +static uint32_t GetESP() __attribute__((noinline)); +static uint32_t GetESP() { + uint32_t ebp; + __asm__ __volatile__( + "movl %%ebp, %0" + : "=a" (ebp) + ); + return ebp + 8; +} + + +// GetEIP returns the instruction pointer identifying the next instruction +// to execute after GetEIP returns. It obtains this information from the +// stack, where it was placed by the call instruction that called GetEIP. +// This function depends on frame pointers not being omitted. It is possible +// to write a pure asm version of this routine that has no compiler-generated +// preamble and uses %esp instead of %ebp; that would function in the +// absence of frame pointers. However, the simpler approach is used here +// because GetEBP and stackwalking necessarily depends on access to frame +// pointers. Because this function depends on a call instruction and the +// compiler-generated preamble, inlining is disabled. +static uint32_t GetEIP() __attribute__((noinline)); +static uint32_t GetEIP() { + uint32_t eip; + __asm__ __volatile__( + "movl 4(%%ebp), %0" + : "=a" (eip) + ); + return eip; +} + + +#elif defined(__ppc__) + + +// GetSP returns the current value of the %r1 register, which by convention, +// is the stack pointer on ppc. Because it's implemented as a function, +// %r1 itself contains GetSP's own stack pointer and not the caller's stack +// pointer. Dereference %r1 to obtain the caller's stack pointer, which the +// compiler-generated prolog stored on the stack. Because this function +// depends on the compiler-generated prolog, inlining is disabled. +static uint32_t GetSP() __attribute__((noinline)); +static uint32_t GetSP() { + uint32_t sp; + __asm__ __volatile__( + "lwz %0, 0(r1)" + : "=r" (sp) + ); + return sp; +} + + +// GetPC returns the program counter identifying the next instruction to +// execute after GetPC returns. It obtains this information from the +// link register, where it was placed by the branch instruction that called +// GetPC. Because this function depends on the caller's use of a branch +// instruction, inlining is disabled. +static uint32_t GetPC() __attribute__((noinline)); +static uint32_t GetPC() { + uint32_t lr; + __asm__ __volatile__( + "mflr %0" + : "=r" (lr) + ); + return lr; +} + + +#elif defined(__sparc__) + + +// GetSP returns the current value of the %sp/%o6/%g_r[14] register, which +// by convention, is the stack pointer on sparc. Because it's implemented +// as a function, %sp itself contains GetSP's own stack pointer and not +// the caller's stack pointer. Dereference to obtain the caller's stack +// pointer, which the compiler-generated prolog stored on the stack. +// Because this function depends on the compiler-generated prolog, inlining +// is disabled. +static uint32_t GetSP() __attribute__((noinline)); +static uint32_t GetSP() { + uint32_t sp; + __asm__ __volatile__( + "mov %%fp, %0" + : "=r" (sp) + ); + return sp; +} + +// GetFP returns the current value of the %fp register. Because it's +// implemented as a function, %fp itself contains GetFP's frame pointer +// and not the caller's frame pointer. Dereference %fp to obtain the +// caller's frame pointer, which the compiler-generated preamble stored +// on the stack (provided frame pointers are not being omitted.) Because +// this function depends on the compiler-generated preamble, inlining is +// disabled. +static uint32_t GetFP() __attribute__((noinline)); +static uint32_t GetFP() { + uint32_t fp; + __asm__ __volatile__( + "ld [%%fp+56], %0" + : "=r" (fp) + ); + return fp; +} + +// GetPC returns the program counter identifying the next instruction to +// execute after GetPC returns. It obtains this information from the +// link register, where it was placed by the branch instruction that called +// GetPC. Because this function depends on the caller's use of a branch +// instruction, inlining is disabled. +static uint32_t GetPC() __attribute__((noinline)); +static uint32_t GetPC() { + uint32_t pc; + __asm__ __volatile__( + "mov %%i7, %0" + : "=r" (pc) + ); + return pc + 8; +} + +#endif // __i386__ || __ppc__ || __sparc__ + +#elif defined(__SUNPRO_CC) + +#if defined(__i386__) +extern "C" { +extern uint32_t GetEIP(); +extern uint32_t GetEBP(); +extern uint32_t GetESP(); +} +#elif defined(__sparc__) +extern "C" { +extern uint32_t GetPC(); +extern uint32_t GetFP(); +extern uint32_t GetSP(); +} +#endif // __i386__ || __sparc__ + +#endif // __GNUC__ || __SUNPRO_CC + +// CountCallerFrames returns the number of stack frames beneath the function +// that called CountCallerFrames. Because this function's return value +// is dependent on the size of the stack beneath it, inlining is disabled, +// and any function that calls this should not be inlined either. +#if defined(__GNUC__) +static unsigned int CountCallerFrames() __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +static unsigned int CountCallerFrames(); +#endif +static unsigned int CountCallerFrames() { + SelfMemoryRegion memory; + BasicSourceLineResolver resolver; + +#if defined(__i386__) + MDRawContextX86 context = MDRawContextX86(); + context.eip = GetEIP(); + context.ebp = GetEBP(); + context.esp = GetESP(); + + StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL, + NULL, &resolver); +#elif defined(__ppc__) + MDRawContextPPC context = MDRawContextPPC(); + context.srr0 = GetPC(); + context.gpr[1] = GetSP(); + + StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL, + NULL, &resolver); +#elif defined(__sparc__) + MDRawContextSPARC context = MDRawContextSPARC(); + context.pc = GetPC(); + context.g_r[14] = GetSP(); + context.g_r[30] = GetFP(); + + StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory, + NULL, NULL, &resolver); +#endif // __i386__ || __ppc__ || __sparc__ + + CallStack stack; + vector modules_without_symbols; + stackwalker.Walk(&stack, &modules_without_symbols); + +#ifdef PRINT_STACKS + printf("\n"); + for (unsigned int frame_index = 0; + frame_index < stack.frames()->size(); + ++frame_index) { + StackFrame *frame = stack.frames()->at(frame_index); + printf("frame %-3d instruction = 0x%08" PRIx64, + frame_index, frame->instruction); +#if defined(__i386__) + StackFrameX86 *frame_x86 = reinterpret_cast(frame); + printf(" esp = 0x%08x ebp = 0x%08x\n", + frame_x86->context.esp, frame_x86->context.ebp); +#elif defined(__ppc__) + StackFramePPC *frame_ppc = reinterpret_cast(frame); + printf(" gpr[1] = 0x%08x\n", frame_ppc->context.gpr[1]); +#elif defined(__sparc__) + StackFrameSPARC *frame_sparc = reinterpret_cast(frame); + printf(" sp = 0x%08x fp = 0x%08x\n", + frame_sparc->context.g_r[14], frame_sparc->context.g_r[30]); +#endif // __i386__ || __ppc__ || __sparc__ + } +#endif // PRINT_STACKS + + // Subtract 1 because the caller wants the number of frames beneath + // itself. Because the caller called us, subract two for our frame and its + // frame, which are included in stack.size(). + return stack.frames()->size() - 2; +} + + +// Recursor verifies that the number stack frames beneath itself is one more +// than the number of stack frames beneath its parent. When depth frames +// have been reached, Recursor stops checking and returns success. If the +// frame count check fails at any depth, Recursor will stop and return false. +// Because this calls CountCallerFrames, inlining is disabled. +#if defined(__GNUC__) +static bool Recursor(unsigned int depth, unsigned int parent_callers) + __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +static bool Recursor(unsigned int depth, unsigned int parent_callers); +#endif +static bool Recursor(unsigned int depth, unsigned int parent_callers) { + unsigned int callers = CountCallerFrames(); + if (callers != parent_callers + 1) + return false; + + if (depth) + return Recursor(depth - 1, callers); + + // depth == 0 + return true; +} + + +// Because this calls CountCallerFrames, inlining is disabled - but because +// it's main (and nobody calls it other than the entry point), it wouldn't +// be inlined anyway. +#if defined(__GNUC__) +int main(int argc, char** argv) __attribute__((noinline)); +#elif defined(__SUNPRO_CC) +int main(int argc, char** argv); +#endif +int main(int argc, char** argv) { + BPLOG_INIT(&argc, &argv); + + return Recursor(RECURSION_DEPTH, CountCallerFrames()) ? 0 : 1; +} + + +#else +// Not i386 or ppc or sparc? We can only test stacks we know how to walk. + + +int main(int argc, char **argv) { + BPLOG_INIT(&argc, &argv); + + // "make check" interprets an exit status of 77 to mean that the test is + // not supported. + BPLOG(ERROR) << "Selftest not supported here"; + return 77; +} + + +#endif // (__GNUC__ || __SUNPRO_CC) && (__i386__ || __ppc__ || __sparc__) diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest_sol.s b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest_sol.s new file mode 100644 index 0000000000..648b0499a1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_selftest_sol.s @@ -0,0 +1,111 @@ +/* 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_selftest_sol.s + * On Solaris, the recommeded compiler is CC, so we can not use gcc inline + * asm, use this method instead. + * + * How to compile: as -P -L -D_ASM -D_STDC -K PIC -o \ + * src/processor/stackwalker_selftest_sol.o \ + * src/processor/stackwalker_selftest_sol.s + * + * Author: Michael Shang + */ + +#include + +#if defined(__i386) + + +ENTRY(GetEBP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl 0x00000000(%ebp),%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + leave + ret +SET_SIZE(GetEBP) + +ENTRY(GetEIP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl 0x00000004(%ebp),%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + leave + ret +SET_SIZE(GetEIP) + +ENTRY(GetESP) + pushl %ebp + movl %esp,%ebp + subl $0x00000004,%esp + movl %ebp,%eax + movl %eax,0xfffffffc(%ebp) + movl 0xfffffffc(%ebp),%eax + addl $0x00000008,%eax + leave + ret +SET_SIZE(GetESP) + + +#elif defined(__sparc) + + +ENTRY(GetPC) + save %sp, -120, %sp + mov %i7, %i4 + inccc 8, %i4 + mov %i4, %i0 + ret + restore +SET_SIZE(GetPC) + +ENTRY(GetSP) + save %sp, -120, %sp + mov %fp, %i4 + mov %i4, %i0 + ret + restore +SET_SIZE(GetSP) + +ENTRY(GetFP) + save %sp, -120, %sp + ld [%fp + 56], %g1 + mov %g1, %i0 + ret + restore +SET_SIZE(GetFP) + + +#endif // __i386 || __sparc diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.cc new file mode 100644 index 0000000000..4de838afec --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2010 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.cc: sparc-specific stackwalker. +// +// See stackwalker_sparc.h for documentation. +// +// Author: Michael Shang + + +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" +#include "processor/stackwalker_sparc.h" + +namespace google_breakpad { + + +StackwalkerSPARC::StackwalkerSPARC(const SystemInfo* system_info, + const MDRawContextSPARC* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context) { +} + + +StackFrame* StackwalkerSPARC::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameSPARC* frame = new StackFrameSPARC(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFrameSPARC::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.pc; + + return frame; +} + + +StackFrame* StackwalkerSPARC::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + StackFrameSPARC* last_frame = static_cast( + stack->frames()->back()); + + // new: caller + // old: callee + // %fp, %i6 and g_r[30] is the same, see minidump_format.h + // %sp, %o6 and g_r[14] is the same, see minidump_format.h + // %sp_new = %fp_old + // %fp_new = *(%fp_old + 32 + 32 - 8), where the callee's %i6 + // %pc_new = *(%fp_old + 32 + 32 - 4) + 8 + // which is callee's %i7 plus 8 + + // A caller frame must reside higher in memory than its callee frames. + // Anything else is an error, or an indication that we've reached the + // end of the stack. + uint64_t stack_pointer = last_frame->context.g_r[30]; + if (stack_pointer <= last_frame->context.g_r[14]) { + return NULL; + } + + uint32_t instruction; + if (!memory_->GetMemoryAtAddress(stack_pointer + 60, + &instruction) || instruction <= 1) { + return NULL; + } + + uint32_t stack_base; + if (!memory_->GetMemoryAtAddress(stack_pointer + 56, + &stack_base) || stack_base <= 1) { + return NULL; + } + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(instruction, + stack_pointer, + last_frame->context.g_r[14], + stack->frames()->size() == 1)) { + return NULL; + } + + StackFrameSPARC* frame = new StackFrameSPARC(); + + frame->context = last_frame->context; + frame->context.g_r[14] = stack_pointer; + frame->context.g_r[30] = stack_base; + + // frame->context.pc is the return address, which is 2 instruction + // past the branch that caused us to arrive at the callee, which are + // a CALL instruction then a NOP instruction. + // frame_ppc->instruction to 8 less than that. Since all sparc + // instructions are 4 bytes wide, this is the address of the branch + // instruction. This allows source line information to match up with the + // line that contains a function call. Callers that require the exact + // return address value may access the %i7/g_r[31] field of StackFrameSPARC. + frame->context.pc = instruction + 8; + frame->instruction = instruction; + frame->context_validity = StackFrameSPARC::CONTEXT_VALID_PC | + StackFrameSPARC::CONTEXT_VALID_SP | + StackFrameSPARC::CONTEXT_VALID_FP; + frame->trust = StackFrame::FRAME_TRUST_FP; + + return frame; +} + + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.h new file mode 100644 index 0000000000..e8f2a38887 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_sparc.h @@ -0,0 +1,78 @@ +// Copyright (c) 2010 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, + StackFrameSymbolizer* frame_symbolizer); + + private: + // Implementation of Stackwalker, using sparc context (%fp, %sp, %pc) and + // stack conventions + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + // 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__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_unittest_utils.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_unittest_utils.h new file mode 100644 index 0000000000..3a92a5ea7a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_unittest_utils.h @@ -0,0 +1,220 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// Mock classes for writing stackwalker tests, shared amongst architectures. + +#ifndef PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_ +#define PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_ + +#include +#include +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/symbol_supplier.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/linked_ptr.h" + +class MockMemoryRegion: public google_breakpad::MemoryRegion { + public: + MockMemoryRegion(): base_address_(0) { } + + // Set this region's address and contents. If we have placed an + // instance of this class in a test fixture class, individual tests + // can use this to provide the region's contents. + void Init(uint64_t base_address, const string &contents) { + base_address_ = base_address; + contents_ = contents; + } + + uint64_t GetBase() const { return base_address_; } + uint32_t GetSize() const { return contents_.size(); } + + bool GetMemoryAtAddress(uint64_t address, uint8_t *value) const { + return GetMemoryLittleEndian(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint16_t *value) const { + return GetMemoryLittleEndian(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint32_t *value) const { + return GetMemoryLittleEndian(address, value); + } + bool GetMemoryAtAddress(uint64_t address, uint64_t *value) const { + return GetMemoryLittleEndian(address, value); + } + void Print() const { + assert(false); + } + + private: + // Fetch a little-endian value from ADDRESS in contents_ whose size + // is BYTES, and store it in *VALUE. Return true on success. + template + bool GetMemoryLittleEndian(uint64_t address, ValueType *value) const { + if (address < base_address_ || + address - base_address_ + sizeof(ValueType) > contents_.size()) + return false; + ValueType v = 0; + int start = address - base_address_; + // The loop condition is odd, but it's correct for size_t. + for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--) + v = (v << 8) | static_cast(contents_[start + i]); + *value = v; + return true; + } + + uint64_t base_address_; + string contents_; +}; + +class MockCodeModule: public google_breakpad::CodeModule { + public: + MockCodeModule(uint64_t base_address, uint64_t size, + const string &code_file, const string &version) + : base_address_(base_address), size_(size), code_file_(code_file) { } + + uint64_t base_address() const { return base_address_; } + uint64_t size() const { return size_; } + string code_file() const { return code_file_; } + string code_identifier() const { return code_file_; } + string debug_file() const { return code_file_; } + string debug_identifier() const { return code_file_; } + string version() const { return version_; } + google_breakpad::CodeModule *Copy() const { + abort(); // Tests won't use this. + } + virtual bool is_unloaded() const { return false; } + virtual uint64_t shrink_down_delta() const { return 0; } + virtual void SetShrinkDownDelta(uint64_t shrink_down_delta) {} + + private: + uint64_t base_address_; + uint64_t size_; + string code_file_; + string version_; +}; + +class MockCodeModules: public google_breakpad::CodeModules { + public: + typedef google_breakpad::CodeModule CodeModule; + typedef google_breakpad::CodeModules CodeModules; + + void Add(const MockCodeModule *module) { + modules_.push_back(module); + } + + unsigned int module_count() const { return modules_.size(); } + + const CodeModule *GetModuleForAddress(uint64_t address) const { + for (ModuleVector::const_iterator i = modules_.begin(); + i != modules_.end(); i++) { + const MockCodeModule *module = *i; + if (module->base_address() <= address && + address - module->base_address() < module->size()) + return module; + } + return NULL; + }; + + const CodeModule *GetMainModule() const { return modules_[0]; } + + const CodeModule *GetModuleAtSequence(unsigned int sequence) const { + return modules_.at(sequence); + } + + const CodeModule *GetModuleAtIndex(unsigned int index) const { + return modules_.at(index); + } + + CodeModules *Copy() const { abort(); } // Tests won't use this + + virtual std::vector > + GetShrunkRangeModules() const { + return std::vector >(); + } + + private: + typedef std::vector ModuleVector; + ModuleVector modules_; +}; + +class MockSymbolSupplier: public google_breakpad::SymbolSupplier { + public: + typedef google_breakpad::CodeModule CodeModule; + typedef google_breakpad::SystemInfo SystemInfo; + MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file)); + MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data)); + MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size)); + MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module)); + + // Copies the passed string contents into a newly allocated buffer. + // The newly allocated buffer will be freed during destruction. + char* CopySymbolDataAndOwnTheCopy(const string &info, + size_t *symbol_data_size) { + *symbol_data_size = info.size() + 1; + char *symbol_data = new char[*symbol_data_size]; + memcpy(symbol_data, info.c_str(), info.size()); + symbol_data[info.size()] = '\0'; + symbol_data_to_free_.push_back(symbol_data); + return symbol_data; + } + + virtual ~MockSymbolSupplier() { + for (SymbolDataVector::const_iterator i = symbol_data_to_free_.begin(); + i != symbol_data_to_free_.end(); i++) { + char* symbol_data = *i; + delete [] symbol_data; + } + } + + private: + // List of symbol data to be freed upon destruction + typedef std::vector SymbolDataVector; + SymbolDataVector symbol_data_to_free_; +}; + +#endif // PROCESSOR_STACKWALKER_UNITTEST_UTILS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.cc new file mode 100644 index 0000000000..ed2b383d4f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.cc @@ -0,0 +1,680 @@ +// Copyright (c) 2010 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.cc: x86-specific stackwalker. +// +// See stackwalker_x86.h for documentation. +// +// Author: Mark Mentovai + +#include +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/logging.h" +#include "processor/postfix_evaluator-inl.h" +#include "processor/stackwalker_x86.h" +#include "processor/windows_frame_info.h" +#include "processor/cfi_frame_info.h" + +namespace google_breakpad { + +// Max reasonable size for a single x86 frame is 128 KB. This value is used in +// a heuristic for recovering of the EBP chain after a scan for return address. +// This value is based on a stack frame size histogram built for a set of +// popular third party libraries which suggests that 99.5% of all frames are +// smaller than 128 KB. +static const uint32_t kMaxReasonableGapBetweenFrames = 128 * 1024; + +const StackwalkerX86::CFIWalker::RegisterSet +StackwalkerX86::cfi_register_map_[] = { + // It may seem like $eip and $esp are callee-saves, because (with Unix or + // cdecl calling conventions) the callee is responsible for having them + // restored upon return. But the callee_saves flags here really means + // that the walker should assume they're unchanged if the CFI doesn't + // mention them, which is clearly wrong for $eip and $esp. + { "$eip", ".ra", false, + StackFrameX86::CONTEXT_VALID_EIP, &MDRawContextX86::eip }, + { "$esp", ".cfa", false, + StackFrameX86::CONTEXT_VALID_ESP, &MDRawContextX86::esp }, + { "$ebp", NULL, true, + StackFrameX86::CONTEXT_VALID_EBP, &MDRawContextX86::ebp }, + { "$eax", NULL, false, + StackFrameX86::CONTEXT_VALID_EAX, &MDRawContextX86::eax }, + { "$ebx", NULL, true, + StackFrameX86::CONTEXT_VALID_EBX, &MDRawContextX86::ebx }, + { "$ecx", NULL, false, + StackFrameX86::CONTEXT_VALID_ECX, &MDRawContextX86::ecx }, + { "$edx", NULL, false, + StackFrameX86::CONTEXT_VALID_EDX, &MDRawContextX86::edx }, + { "$esi", NULL, true, + StackFrameX86::CONTEXT_VALID_ESI, &MDRawContextX86::esi }, + { "$edi", NULL, true, + StackFrameX86::CONTEXT_VALID_EDI, &MDRawContextX86::edi }, +}; + +StackwalkerX86::StackwalkerX86(const SystemInfo* system_info, + const MDRawContextX86* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper) + : Stackwalker(system_info, memory, modules, resolver_helper), + context_(context), + cfi_walker_(cfi_register_map_, + (sizeof(cfi_register_map_) / sizeof(cfi_register_map_[0]))) { + if (memory_ && memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { + // The x86 is a 32-bit CPU, the limits of the supplied stack are invalid. + // Mark memory_ = NULL, which will cause stackwalking to fail. + BPLOG(ERROR) << "Memory out of range for stackwalking: " << + HexString(memory_->GetBase()) << "+" << + HexString(memory_->GetSize()); + memory_ = NULL; + } +} + +StackFrameX86::~StackFrameX86() { + if (windows_frame_info) + delete windows_frame_info; + windows_frame_info = NULL; + if (cfi_frame_info) + delete cfi_frame_info; + cfi_frame_info = NULL; +} + +uint64_t StackFrameX86::ReturnAddress() const { + assert(context_validity & StackFrameX86::CONTEXT_VALID_EIP); + return context.eip; +} + +StackFrame* StackwalkerX86::GetContextFrame() { + if (!context_) { + BPLOG(ERROR) << "Can't get context frame without context"; + return NULL; + } + + StackFrameX86* frame = new StackFrameX86(); + + // The instruction pointer is stored directly in a register, so pull it + // straight out of the CPU context structure. + frame->context = *context_; + frame->context_validity = StackFrameX86::CONTEXT_VALID_ALL; + frame->trust = StackFrame::FRAME_TRUST_CONTEXT; + frame->instruction = frame->context.eip; + + return frame; +} + +StackFrameX86* StackwalkerX86::GetCallerByWindowsFrameInfo( + const vector &frames, + WindowsFrameInfo* last_frame_info, + bool stack_scan_allowed) { + StackFrame::FrameTrust trust = StackFrame::FRAME_TRUST_NONE; + + StackFrameX86* last_frame = static_cast(frames.back()); + + // Save the stack walking info we found, in case we need it later to + // find the callee of the frame we're constructing now. + last_frame->windows_frame_info = last_frame_info; + + // This function only covers the full STACK WIN case. If + // last_frame_info is VALID_PARAMETER_SIZE-only, then we should + // assume the traditional frame format or use some other strategy. + if (last_frame_info->valid != WindowsFrameInfo::VALID_ALL) + return NULL; + + // This stackwalker sets each frame's %esp to its value immediately prior + // to the CALL into the callee. This means that %esp points to the last + // callee argument pushed onto the stack, which may not be where %esp points + // after the callee returns. Specifically, the value is correct for the + // cdecl calling convention, but not other conventions. The cdecl + // convention requires a caller to pop its callee's arguments from the + // stack after the callee returns. This is usually accomplished by adding + // the known size of the arguments to %esp. Other calling conventions, + // including stdcall, thiscall, and fastcall, require the callee to pop any + // parameters stored on the stack before returning. This is usually + // accomplished by using the RET n instruction, which pops n bytes off + // the stack after popping the return address. + // + // Because each frame's %esp will point to a location on the stack after + // callee arguments have been PUSHed, when locating things in a stack frame + // relative to %esp, the size of the arguments to the callee need to be + // taken into account. This seems a little bit unclean, but it's better + // than the alternative, which would need to take these same things into + // account, but only for cdecl functions. With this implementation, we get + // to be agnostic about each function's calling convention. Furthermore, + // this is how Windows debugging tools work, so it means that the %esp + // values produced by this stackwalker directly correspond to the %esp + // values you'll see there. + // + // If the last frame has no callee (because it's the context frame), just + // set the callee parameter size to 0: the stack pointer can't point to + // callee arguments because there's no callee. This is correct as long + // as the context wasn't captured while arguments were being pushed for + // a function call. Note that there may be functions whose parameter sizes + // are unknown, 0 is also used in that case. When that happens, it should + // be possible to walk to the next frame without reference to %esp. + + uint32_t last_frame_callee_parameter_size = 0; + int frames_already_walked = frames.size(); + if (frames_already_walked >= 2) { + const StackFrameX86* last_frame_callee + = static_cast(frames[frames_already_walked - 2]); + WindowsFrameInfo* last_frame_callee_info + = last_frame_callee->windows_frame_info; + if (last_frame_callee_info && + (last_frame_callee_info->valid + & WindowsFrameInfo::VALID_PARAMETER_SIZE)) { + last_frame_callee_parameter_size = + last_frame_callee_info->parameter_size; + } + } + + // Set up the dictionary for the PostfixEvaluator. %ebp, %esp, and sometimes + // %ebx are used in program strings, and their previous values are known, so + // set them here. + PostfixEvaluator::DictionaryType dictionary; + // Provide the current register values. + dictionary["$ebp"] = last_frame->context.ebp; + dictionary["$esp"] = last_frame->context.esp; + if (last_frame->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + dictionary["$ebx"] = last_frame->context.ebx; + // Provide constants from the debug info for last_frame and its callee. + // .cbCalleeParams is a Breakpad extension that allows us to use the + // PostfixEvaluator engine when certain types of debugging information + // are present without having to write the constants into the program + // string as literals. + dictionary[".cbCalleeParams"] = last_frame_callee_parameter_size; + dictionary[".cbSavedRegs"] = last_frame_info->saved_register_size; + dictionary[".cbLocals"] = last_frame_info->local_size; + + uint32_t raSearchStart = last_frame->context.esp + + last_frame_callee_parameter_size + + last_frame_info->local_size + + last_frame_info->saved_register_size; + + uint32_t raSearchStartOld = raSearchStart; + uint32_t found = 0; // dummy value + // Scan up to three words above the calculated search value, in case + // the stack was aligned to a quadword boundary. + // + // TODO(ivan.penkov): Consider cleaning up the scan for return address that + // follows. The purpose of this scan is to adjust the .raSearchStart + // calculation (which is based on register %esp) in the cases where register + // %esp may have been aligned (up to a quadword). There are two problems + // with this approach: + // 1) In practice, 64 byte boundary alignment is seen which clearly can not + // be handled by a three word scan. + // 2) A search for a return address is "guesswork" by definition because + // the results will be different depending on what is left on the stack + // from previous executions. + // So, basically, the results from this scan should be ignored if other means + // for calculation of the value of .raSearchStart are available. + if (ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3) && + last_frame->trust == StackFrame::FRAME_TRUST_CONTEXT && + last_frame->windows_frame_info != NULL && + last_frame_info->type_ == WindowsFrameInfo::STACK_INFO_FPO && + raSearchStartOld == raSearchStart && + found == last_frame->context.eip) { + // The context frame represents an FPO-optimized Windows system call. + // On the top of the stack we have a pointer to the current instruction. + // This means that the callee has returned but the return address is still + // on the top of the stack which is very atypical situaltion. + // Skip one slot from the stack and do another scan in order to get the + // actual return address. + raSearchStart += 4; + ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3); + } + + dictionary[".cbParams"] = last_frame_info->parameter_size; + + // Decide what type of program string to use. The program string is in + // postfix notation and will be passed to PostfixEvaluator::Evaluate. + // Given the dictionary and the program string, it is possible to compute + // the return address and the values of other registers in the calling + // function. Because of bugs described below, the stack may need to be + // scanned for these values. The results of program string evaluation + // will be used to determine whether to scan for better values. + string program_string; + bool recover_ebp = true; + + trust = StackFrame::FRAME_TRUST_CFI; + if (!last_frame_info->program_string.empty()) { + // The FPO data has its own program string, which will tell us how to + // get to the caller frame, and may even fill in the values of + // nonvolatile registers and provide pointers to local variables and + // parameters. In some cases, particularly with program strings that use + // .raSearchStart, the stack may need to be scanned afterward. + program_string = last_frame_info->program_string; + } else if (last_frame_info->allocates_base_pointer) { + // The function corresponding to the last frame doesn't use the frame + // pointer for conventional purposes, but it does allocate a new + // frame pointer and use it for its own purposes. Its callee's + // information is still accessed relative to %esp, and the previous + // value of %ebp can be recovered from a location in its stack frame, + // within the saved-register area. + // + // Functions that fall into this category use the %ebp register for + // a purpose other than the frame pointer. They restore the caller's + // %ebp before returning. These functions create their stack frame + // after a CALL by decrementing the stack pointer in an amount + // sufficient to store local variables, and then PUSHing saved + // registers onto the stack. Arguments to a callee function, if any, + // are PUSHed after that. Walking up to the caller, therefore, + // can be done solely with calculations relative to the stack pointer + // (%esp). The return address is recovered from the memory location + // above the known sizes of the callee's parameters, saved registers, + // and locals. The caller's stack pointer (the value of %esp when + // the caller executed CALL) is the location immediately above the + // saved return address. The saved value of %ebp to be restored for + // the caller is at a known location in the saved-register area of + // the stack frame. + // + // For this type of frame, MSVC 14 (from Visual Studio 8/2005) in + // link-time code generation mode (/LTCG and /GL) can generate erroneous + // debugging data. The reported size of saved registers can be 0, + // which is clearly an error because these frames must, at the very + // least, save %ebp. For this reason, in addition to those given above + // about the use of .raSearchStart, the stack may need to be scanned + // for a better return address and a better frame pointer after the + // program string is evaluated. + // + // %eip_new = *(%esp_old + callee_params + saved_regs + locals) + // %ebp_new = *(%esp_old + callee_params + saved_regs - 8) + // %esp_new = %esp_old + callee_params + saved_regs + locals + 4 + program_string = "$eip .raSearchStart ^ = " + "$ebp $esp .cbCalleeParams + .cbSavedRegs + 8 - ^ = " + "$esp .raSearchStart 4 + ="; + } else { + // The function corresponding to the last frame doesn't use %ebp at + // all. The callee frame is located relative to %esp. + // + // The called procedure's instruction pointer and stack pointer are + // recovered in the same way as the case above, except that no + // frame pointer (%ebp) is used at all, so it is not saved anywhere + // in the callee's stack frame and does not need to be recovered. + // Because %ebp wasn't used in the callee, whatever value it has + // is the value that it had in the caller, so it can be carried + // straight through without bringing its validity into question. + // + // Because of the use of .raSearchStart, the stack will possibly be + // examined to locate a better return address after program string + // evaluation. The stack will not be examined to locate a saved + // %ebp value, because these frames do not save (or use) %ebp. + // + // We also propagate %ebx through, as it is commonly unmodifed after + // calling simple forwarding functions in ntdll (that are this non-EBP + // using type). It's not clear that this is always correct, but it is + // important for some functions to get a correct walk. + // + // %eip_new = *(%esp_old + callee_params + saved_regs + locals) + // %esp_new = %esp_old + callee_params + saved_regs + locals + 4 + // %ebp_new = %ebp_old + // %ebx_new = %ebx_old // If available. + program_string = "$eip .raSearchStart ^ = " + "$esp .raSearchStart 4 + ="; + if (last_frame->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + program_string += " $ebx $ebx ="; + recover_ebp = false; + } + + // Check for alignment operators in the program string. If alignment + // operators are found, then current %ebp must be valid and it is the only + // reliable data point that can be used for getting to the previous frame. + // E.g. the .raSearchStart calculation (above) is based on %esp and since + // %esp was aligned in the current frame (which is a lossy operation) the + // calculated value of .raSearchStart cannot be correct and should not be + // used. Instead .raSearchStart must be calculated based on %ebp. + // The code that follows assumes that .raSearchStart is supposed to point + // at the saved return address (ebp + 4). + // For some more details on this topic, take a look at the following thread: + // https://groups.google.com/forum/#!topic/google-breakpad-dev/ZP1FA9B1JjM + if ((StackFrameX86::CONTEXT_VALID_EBP & last_frame->context_validity) != 0 && + program_string.find('@') != string::npos) { + raSearchStart = last_frame->context.ebp + 4; + } + + // The difference between raSearch and raSearchStart is unknown, + // but making them the same seems to work well in practice. + dictionary[".raSearchStart"] = raSearchStart; + dictionary[".raSearch"] = raSearchStart; + + // Now crank it out, making sure that the program string set at least the + // two required variables. + PostfixEvaluator evaluator = + PostfixEvaluator(&dictionary, memory_); + PostfixEvaluator::DictionaryValidityType dictionary_validity; + if (!evaluator.Evaluate(program_string, &dictionary_validity) || + dictionary_validity.find("$eip") == dictionary_validity.end() || + dictionary_validity.find("$esp") == dictionary_validity.end()) { + // Program string evaluation failed. It may be that %eip is not somewhere + // with stack frame info, and %ebp is pointing to non-stack memory, so + // our evaluation couldn't succeed. We'll scan the stack for a return + // address. This can happen if the stack is in a module for which + // we don't have symbols, and that module is compiled without a + // frame pointer. + uint32_t location_start = last_frame->context.esp; + uint32_t location, eip; + if (!stack_scan_allowed + || !ScanForReturnAddress(location_start, &location, &eip, + frames.size() == 1 /* is_context_frame */)) { + // if we can't find an instruction pointer even with stack scanning, + // give up. + return NULL; + } + + // This seems like a reasonable return address. Since program string + // evaluation failed, use it and set %esp to the location above the + // one where the return address was found. + dictionary["$eip"] = eip; + dictionary["$esp"] = location + 4; + trust = StackFrame::FRAME_TRUST_SCAN; + } + + // Since this stack frame did not use %ebp in a traditional way, + // locating the return address isn't entirely deterministic. In that + // case, the stack can be scanned to locate the return address. + // + // However, if program string evaluation resulted in both %eip and + // %ebp values of 0, trust that the end of the stack has been + // reached and don't scan for anything else. + if (dictionary["$eip"] != 0 || dictionary["$ebp"] != 0) { + int offset = 0; + + // This scan can only be done if a CodeModules object is available, to + // check that candidate return addresses are in fact inside a module. + // + // TODO(mmentovai): This ignores dynamically-generated code. One possible + // solution is to check the minidump's memory map to see if the candidate + // %eip value comes from a mapped executable page, although this would + // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad + // client doesn't currently write (it would need to call MiniDumpWriteDump + // with the MiniDumpWithFullMemoryInfo type bit set). Even given this + // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce + // an independent execute privilege on memory pages. + + uint32_t eip = dictionary["$eip"]; + if (modules_ && !modules_->GetModuleForAddress(eip)) { + // The instruction pointer at .raSearchStart was invalid, so start + // looking one 32-bit word above that location. + uint32_t location_start = dictionary[".raSearchStart"] + 4; + uint32_t location; + if (stack_scan_allowed + && ScanForReturnAddress(location_start, &location, &eip, + frames.size() == 1 /* is_context_frame */)) { + // This is a better return address that what program string + // evaluation found. Use it, and set %esp to the location above the + // one where the return address was found. + dictionary["$eip"] = eip; + dictionary["$esp"] = location + 4; + offset = location - location_start; + trust = StackFrame::FRAME_TRUST_CFI_SCAN; + } + } + + if (recover_ebp) { + // When trying to recover the previous value of the frame pointer (%ebp), + // start looking at the lowest possible address in the saved-register + // area, and look at the entire saved register area, increased by the + // size of |offset| to account for additional data that may be on the + // stack. The scan is performed from the highest possible address to + // the lowest, because the expectation is that the function's prolog + // would have saved %ebp early. + uint32_t ebp = dictionary["$ebp"]; + + // When a scan for return address is used, it is possible to skip one or + // more frames (when return address is not in a known module). One + // indication for skipped frames is when the value of %ebp is lower than + // the location of the return address on the stack + bool has_skipped_frames = + (trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset); + + uint32_t value; // throwaway variable to check pointer validity + if (has_skipped_frames || !memory_->GetMemoryAtAddress(ebp, &value)) { + int fp_search_bytes = last_frame_info->saved_register_size + offset; + uint32_t location_end = last_frame->context.esp + + last_frame_callee_parameter_size; + + for (uint32_t location = location_end + fp_search_bytes; + location >= location_end; + location -= 4) { + if (!memory_->GetMemoryAtAddress(location, &ebp)) + break; + + if (memory_->GetMemoryAtAddress(ebp, &value)) { + // The candidate value is a pointer to the same memory region + // (the stack). Prefer it as a recovered %ebp result. + dictionary["$ebp"] = ebp; + break; + } + } + } + } + } + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameX86* frame = new StackFrameX86(); + + frame->trust = trust; + frame->context = last_frame->context; + frame->context.eip = dictionary["$eip"]; + frame->context.esp = dictionary["$esp"]; + frame->context.ebp = dictionary["$ebp"]; + frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP; + + // These are nonvolatile (callee-save) registers, and the program string + // may have filled them in. + if (dictionary_validity.find("$ebx") != dictionary_validity.end()) { + frame->context.ebx = dictionary["$ebx"]; + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EBX; + } + if (dictionary_validity.find("$esi") != dictionary_validity.end()) { + frame->context.esi = dictionary["$esi"]; + frame->context_validity |= StackFrameX86::CONTEXT_VALID_ESI; + } + if (dictionary_validity.find("$edi") != dictionary_validity.end()) { + frame->context.edi = dictionary["$edi"]; + frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI; + } + + return frame; +} + +StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo( + const vector &frames, + CFIFrameInfo* cfi_frame_info) { + StackFrameX86* last_frame = static_cast(frames.back()); + last_frame->cfi_frame_info = cfi_frame_info; + + scoped_ptr frame(new StackFrameX86()); + if (!cfi_walker_ + .FindCallerRegisters(*memory_, *cfi_frame_info, + last_frame->context, last_frame->context_validity, + &frame->context, &frame->context_validity)) + return NULL; + + // Make sure we recovered all the essentials. + static const int essentials = (StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP); + if ((frame->context_validity & essentials) != essentials) + return NULL; + + frame->trust = StackFrame::FRAME_TRUST_CFI; + + return frame.release(); +} + +StackFrameX86* StackwalkerX86::GetCallerByEBPAtBase( + const vector &frames, + bool stack_scan_allowed) { + StackFrame::FrameTrust trust; + StackFrameX86* last_frame = static_cast(frames.back()); + uint32_t last_esp = last_frame->context.esp; + uint32_t last_ebp = last_frame->context.ebp; + + // Assume that the standard %ebp-using x86 calling convention is in + // use. + // + // The typical x86 calling convention, when frame pointers are present, + // is for the calling procedure to use CALL, which pushes the return + // address onto the stack and sets the instruction pointer (%eip) to + // the entry point of the called routine. The called routine then + // PUSHes the calling routine's frame pointer (%ebp) onto the stack + // before copying the stack pointer (%esp) to the frame pointer (%ebp). + // Therefore, the calling procedure's frame pointer is always available + // by dereferencing the called procedure's frame pointer, and the return + // address is always available at the memory location immediately above + // the address pointed to by the called procedure's frame pointer. The + // calling procedure's stack pointer (%esp) is 8 higher than the value + // of the called procedure's frame pointer at the time the calling + // procedure made the CALL: 4 bytes for the return address pushed by the + // CALL itself, and 4 bytes for the callee's PUSH of the caller's frame + // pointer. + // + // %eip_new = *(%ebp_old + 4) + // %esp_new = %ebp_old + 8 + // %ebp_new = *(%ebp_old) + + uint32_t caller_eip, caller_esp, caller_ebp; + + if (memory_->GetMemoryAtAddress(last_ebp + 4, &caller_eip) && + memory_->GetMemoryAtAddress(last_ebp, &caller_ebp)) { + caller_esp = last_ebp + 8; + trust = StackFrame::FRAME_TRUST_FP; + } else { + // We couldn't read the memory %ebp refers to. It may be that %ebp + // is pointing to non-stack memory. We'll scan the stack for a + // return address. This can happen if last_frame is executing code + // for a module for which we don't have symbols, and that module + // is compiled without a frame pointer. + if (!stack_scan_allowed + || !ScanForReturnAddress(last_esp, &caller_esp, &caller_eip, + frames.size() == 1 /* is_context_frame */)) { + // if we can't find an instruction pointer even with stack scanning, + // give up. + return NULL; + } + + // ScanForReturnAddress found a reasonable return address. Advance %esp to + // the location immediately above the one where the return address was + // found. + caller_esp += 4; + // Try to restore the %ebp chain. The caller %ebp should be stored at a + // location immediately below the one where the return address was found. + // A valid caller %ebp must be greater than the address where it is stored + // and the gap between the two adjacent frames should be reasonable. + uint32_t restored_ebp_chain = caller_esp - 8; + if (!memory_->GetMemoryAtAddress(restored_ebp_chain, &caller_ebp) || + caller_ebp <= restored_ebp_chain || + caller_ebp - restored_ebp_chain > kMaxReasonableGapBetweenFrames) { + // The restored %ebp chain doesn't appear to be valid. + // Assume that %ebp is unchanged. + caller_ebp = last_ebp; + } + + trust = StackFrame::FRAME_TRUST_SCAN; + } + + // Create a new stack frame (ownership will be transferred to the caller) + // and fill it in. + StackFrameX86* frame = new StackFrameX86(); + + frame->trust = trust; + frame->context = last_frame->context; + frame->context.eip = caller_eip; + frame->context.esp = caller_esp; + frame->context.ebp = caller_ebp; + frame->context_validity = StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP; + + return frame; +} + +StackFrame* StackwalkerX86::GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) { + if (!memory_ || !stack) { + BPLOG(ERROR) << "Can't get caller frame without memory or stack"; + return NULL; + } + + const vector &frames = *stack->frames(); + StackFrameX86* last_frame = static_cast(frames.back()); + scoped_ptr new_frame; + + // If the resolver has Windows stack walking information, use that. + WindowsFrameInfo* windows_frame_info + = frame_symbolizer_->FindWindowsFrameInfo(last_frame); + if (windows_frame_info) + new_frame.reset(GetCallerByWindowsFrameInfo(frames, windows_frame_info, + stack_scan_allowed)); + + // If the resolver has DWARF CFI information, use that. + if (!new_frame.get()) { + CFIFrameInfo* cfi_frame_info = + frame_symbolizer_->FindCFIFrameInfo(last_frame); + if (cfi_frame_info) + new_frame.reset(GetCallerByCFIFrameInfo(frames, cfi_frame_info)); + } + + // Otherwise, hope that the program was using a traditional frame structure. + if (!new_frame.get()) + new_frame.reset(GetCallerByEBPAtBase(frames, stack_scan_allowed)); + + // If nothing worked, tell the caller. + if (!new_frame.get()) + return NULL; + + // Should we terminate the stack walk? (end-of-stack or broken invariant) + if (TerminateWalk(new_frame->context.eip, + new_frame->context.esp, + last_frame->context.esp, + frames.size() == 1)) { + return NULL; + } + + // new_frame->context.eip is the return address, which is the instruction + // after the CALL that caused us to arrive at the callee. Set + // new_frame->instruction to one less than that, so it points within the + // CALL instruction. See StackFrame::instruction for details, and + // StackFrameAMD64::ReturnAddress. + new_frame->instruction = new_frame->context.eip - 1; + + return new_frame.release(); +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.h b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.h new file mode 100644 index 0000000000..0659a13bf4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86.h @@ -0,0 +1,117 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 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 + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stackwalker.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/cfi_frame_info.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, + StackFrameSymbolizer* frame_symbolizer); + + private: + // A STACK CFI-driven frame walker for the X86. + typedef SimpleCFIWalker CFIWalker; + + // 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 any WindowsFrameInfo available for the + // code in question.). + virtual StackFrame* GetContextFrame(); + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed); + + // Use windows_frame_info (derived from STACK WIN and FUNC records) + // to construct the frame that called frames.back(). The caller + // takes ownership of the returned frame. Return NULL on failure. + StackFrameX86* GetCallerByWindowsFrameInfo( + const vector &frames, + WindowsFrameInfo* windows_frame_info, + bool stack_scan_allowed); + + // Use cfi_frame_info (derived from STACK CFI records) to construct + // the frame that called frames.back(). The caller takes ownership + // of the returned frame. Return NULL on failure. + StackFrameX86* GetCallerByCFIFrameInfo(const vector &frames, + CFIFrameInfo* cfi_frame_info); + + // Assuming a traditional frame layout --- where the caller's %ebp + // has been pushed just after the return address and the callee's + // %ebp points to the saved %ebp --- construct the frame that called + // frames.back(). The caller takes ownership of the returned frame. + // Return NULL on failure. + StackFrameX86* GetCallerByEBPAtBase(const vector &frames, + bool stack_scan_allowed); + + // Stores the CPU context corresponding to the innermost stack frame to + // be returned by GetContextFrame. + const MDRawContextX86* context_; + + // Our register map, for cfi_walker_. + static const CFIWalker::RegisterSet cfi_register_map_[]; + + // Our CFI frame walker. + const CFIWalker cfi_walker_; +}; + + +} // namespace google_breakpad + + +#endif // PROCESSOR_STACKWALKER_X86_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86_unittest.cc new file mode 100644 index 0000000000..359f1c863b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/stackwalker_x86_unittest.cc @@ -0,0 +1,2266 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// stackwalker_x86_unittest.cc: Unit tests for StackwalkerX86 class. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/source_line_resolver_interface.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "processor/stackwalker_unittest_utils.h" +#include "processor/stackwalker_x86.h" +#include "processor/windows_frame_info.h" + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameX86; +using google_breakpad::Stackwalker; +using google_breakpad::StackwalkerX86; +using google_breakpad::SystemInfo; +using google_breakpad::WindowsFrameInfo; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; +using google_breakpad::test_assembler::Section; +using std::vector; +using testing::_; +using testing::AnyNumber; +using testing::DoAll; +using testing::Return; +using testing::SetArgumentPointee; +using testing::Test; + +class StackwalkerX86Fixture { + public: + StackwalkerX86Fixture() + : stack_section(kLittleEndian), + // Give the two modules reasonable standard locations and names + // for tests to play with. + module1(0x40000000, 0x10000, "module1", "version1"), + module2(0x50000000, 0x10000, "module2", "version2"), + module3(0x771d0000, 0x180000, "module3", "version3"), + module4(0x75f90000, 0x46000, "module4", "version4"), + module5(0x75730000, 0x110000, "module5", "version5"), + module6(0x647f0000, 0x1ba8000, "module6", "version6") { + // Identify the system as a Linux system. + system_info.os = "Linux"; + system_info.os_short = "linux"; + system_info.os_version = "Salacious Skink"; + system_info.cpu = "x86"; + system_info.cpu_info = ""; + + // Put distinctive values in the raw CPU context. + BrandContext(&raw_context); + + // Create some modules with some stock debugging information. + modules.Add(&module1); + modules.Add(&module2); + modules.Add(&module3); + modules.Add(&module4); + modules.Add(&module5); + modules.Add(&module6); + + // By default, none of the modules have symbol info; call + // SetModuleSymbols to override this. + EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _)) + .WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND)); + + // Avoid GMOCK WARNING "Uninteresting mock function call - returning + // directly" for FreeSymbolData(). + EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber()); + + // Reset max_frames_scanned since it's static. + Stackwalker::set_max_frames_scanned(1024); + } + + // Set the Breakpad symbol information that supplier should return for + // MODULE to INFO. + void SetModuleSymbols(MockCodeModule *module, const string &info) { + size_t buffer_size; + char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size); + EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _)) + .WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer), + SetArgumentPointee<4>(buffer_size), + Return(MockSymbolSupplier::FOUND))); + } + + // Populate stack_region with the contents of stack_section. Use + // stack_section.start() as the region's starting address. + void RegionFromSection() { + string contents; + ASSERT_TRUE(stack_section.GetContents(&contents)); + stack_region.Init(stack_section.start().Value(), contents); + } + + // Fill RAW_CONTEXT with pseudo-random data, for round-trip checking. + void BrandContext(MDRawContextX86 *raw_context) { + uint8_t x = 173; + for (size_t i = 0; i < sizeof(*raw_context); i++) + reinterpret_cast(raw_context)[i] = (x += 17); + } + + SystemInfo system_info; + MDRawContextX86 raw_context; + Section stack_section; + MockMemoryRegion stack_region; + MockCodeModule module1; + MockCodeModule module2; + MockCodeModule module3; + MockCodeModule module4; + MockCodeModule module5; + MockCodeModule module6; + MockCodeModules modules; + MockSymbolSupplier supplier; + BasicSourceLineResolver resolver; + CallStack call_stack; + const vector *frames; +}; + +class SanityCheck: public StackwalkerX86Fixture, public Test { }; + +TEST_F(SanityCheck, NoResolver) { + stack_section.start() = 0x80000000; + stack_section.D32(0).D32(0); // end-of-stack marker + RegionFromSection(); + raw_context.eip = 0x40000200; + raw_context.ebp = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(NULL, NULL); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + // This should succeed, even without a resolver or supplier. + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameX86 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetContextFrame: public StackwalkerX86Fixture, public Test { }; + +TEST_F(GetContextFrame, Simple) { + stack_section.start() = 0x80000000; + stack_section.D32(0).D32(0); // end-of-stack marker + RegionFromSection(); + raw_context.eip = 0x40000200; + raw_context.ebp = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameX86 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +// The stackwalker should be able to produce the context frame even +// without stack memory present. +TEST_F(GetContextFrame, NoStackMemory) { + raw_context.eip = 0x40000200; + raw_context.ebp = 0x80000000; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + StackFrameX86 *frame = static_cast(frames->at(0)); + // Check that the values from the original raw context made it + // through to the context in the stack frame. + EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context))); +} + +class GetCallerFrame: public StackwalkerX86Fixture, public Test { + protected: + void IPAddressIsNotInKnownModuleTestImpl(bool has_corrupt_symbols); +}; + +// Walk a traditional frame. A traditional frame saves the caller's +// %ebp just below the return address, and has its own %ebp pointing +// at the saved %ebp. +TEST_F(GetCallerFrame, Traditional) { + stack_section.start() = 0x80000000; + Label frame0_ebp, frame1_ebp; + stack_section + .Append(12, 0) // frame 0: space + .Mark(&frame0_ebp) // frame 0 %ebp points here + .D32(frame1_ebp) // frame 0: saved %ebp + .D32(0x40008679) // frame 0: return address + .Append(8, 0) // frame 1: space + .Mark(&frame1_ebp) // frame 1 %ebp points here + .D32(0) // frame 1: saved %ebp (stack end) + .D32(0); // frame 1: return address (stack end) + RegionFromSection(); + raw_context.eip = 0x4000c7a5; + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = frame0_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + EXPECT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000c7a5U, frame0->instruction); + EXPECT_EQ(0x4000c7a5U, frame0->context.eip); + EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); + EXPECT_EQ(NULL, frame0->windows_frame_info); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x40008679U, frame1->instruction + 1); + EXPECT_EQ(0x40008679U, frame1->context.eip); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Walk a traditional frame, but use a bogus %ebp value, forcing a scan +// of the stack for something that looks like a return address. +TEST_F(GetCallerFrame, TraditionalScan) { + stack_section.start() = 0x80000000; + Label frame1_ebp; + Label frame1_esp; + stack_section + // frame 0 + .D32(0xf065dc76) // locals area: + .D32(0x46ee2167) // garbage that doesn't look like + .D32(0xbab023ec) // a return address + .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan) + .D32(0x4000129d) // return address + // frame 1 + .Mark(&frame1_esp) + .Append(8, 0) // space + .Mark(&frame1_ebp) // %ebp points here + .D32(0) // saved %ebp (stack end) + .D32(0); // return address (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000f49d; + raw_context.esp = stack_section.start().Value(); + // Make the frame pointer bogus, to make the stackwalker scan the stack + // for something that looks like a return address. + raw_context.ebp = 0xd43eed6e; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000f49dU, frame0->instruction); + EXPECT_EQ(0x4000f49dU, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); + EXPECT_EQ(NULL, frame0->windows_frame_info); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x4000129dU, frame1->instruction + 1); + EXPECT_EQ(0x4000129dU, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Force scanning for a return address a long way down the stack +TEST_F(GetCallerFrame, TraditionalScanLongWay) { + stack_section.start() = 0x80000000; + Label frame1_ebp; + Label frame1_esp; + stack_section + // frame 0 + .D32(0xf065dc76) // locals area: + .D32(0x46ee2167) // garbage that doesn't look like + .D32(0xbab023ec) // a return address + .Append(20 * 4, 0) // a bunch of space + .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan) + .D32(0x4000129d) // return address + // frame 1 + .Mark(&frame1_esp) + .Append(8, 0) // space + .Mark(&frame1_ebp) // %ebp points here + .D32(0) // saved %ebp (stack end) + .D32(0); // return address (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000f49d; + raw_context.esp = stack_section.start().Value(); + // Make the frame pointer bogus, to make the stackwalker scan the stack + // for something that looks like a return address. + raw_context.ebp = 0xd43eed6e; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000f49dU, frame0->instruction); + EXPECT_EQ(0x4000f49dU, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); + EXPECT_EQ(NULL, frame0->windows_frame_info); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x4000129dU, frame1->instruction + 1); + EXPECT_EQ(0x4000129dU, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Test that set_max_frames_scanned prevents using stack scanning +// to find caller frames. +TEST_F(GetCallerFrame, ScanningNotAllowed) { + stack_section.start() = 0x80000000; + Label frame1_ebp; + stack_section + // frame 0 + .D32(0xf065dc76) // locals area: + .D32(0x46ee2167) // garbage that doesn't look like + .D32(0xbab023ec) // a return address + .D32(frame1_ebp) // saved %ebp (%ebp fails to point here, forcing scan) + .D32(0x4000129d) // return address + // frame 1 + .Append(8, 0) // space + .Mark(&frame1_ebp) // %ebp points here + .D32(0) // saved %ebp (stack end) + .D32(0); // return address (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000f49d; + raw_context.esp = stack_section.start().Value(); + // Make the frame pointer bogus, to make the stackwalker scan the stack + // for something that looks like a return address. + raw_context.ebp = 0xd43eed6e; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + Stackwalker::set_max_frames_scanned(0); + + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module1", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(1U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000f49dU, frame0->instruction); + EXPECT_EQ(0x4000f49dU, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(0xd43eed6eU, frame0->context.ebp); + EXPECT_EQ(NULL, frame0->windows_frame_info); + } +} + +// Use Windows frame data (a "STACK WIN 4" record, from a +// FrameTypeFrameData DIA record) to walk a stack frame. +TEST_F(GetCallerFrame, WindowsFrameData) { + SetModuleSymbols(&module1, + "STACK WIN 4 aa85 176 0 0 4 10 4 0 1" + " $T2 $esp .cbSavedRegs + =" + " $T0 .raSearchStart =" + " $eip $T0 ^ =" + " $esp $T0 4 + =" + " $ebx $T2 4 - ^ =" + " $edi $T2 8 - ^ =" + " $esi $T2 12 - ^ =" + " $ebp $T2 16 - ^ =\n"); + Label frame1_esp, frame1_ebp; + stack_section.start() = 0x80000000; + stack_section + // frame 0 + .D32(frame1_ebp) // saved regs: %ebp + .D32(0xa7120d1a) // %esi + .D32(0x630891be) // %edi + .D32(0x9068a878) // %ebx + .D32(0xa08ea45f) // locals: unused + .D32(0x40001350) // return address + // frame 1 + .Mark(&frame1_esp) + .Append(12, 0) // empty space + .Mark(&frame1_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000aa85; + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = 0xf052c1de; // should not be needed to walk frame + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000aa85U, frame0->instruction); + EXPECT_EQ(0x4000aa85U, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(0xf052c1deU, frame0->context.ebp); + EXPECT_TRUE(frame0->windows_frame_info != NULL); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP + | StackFrameX86::CONTEXT_VALID_EBX + | StackFrameX86::CONTEXT_VALID_ESI + | StackFrameX86::CONTEXT_VALID_EDI), + frame1->context_validity); + EXPECT_EQ(0x40001350U, frame1->instruction + 1); + EXPECT_EQ(0x40001350U, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(0x9068a878U, frame1->context.ebx); + EXPECT_EQ(0xa7120d1aU, frame1->context.esi); + EXPECT_EQ(0x630891beU, frame1->context.edi); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Use Windows frame data (a "STACK WIN 4" record, from a +// FrameTypeFrameData DIA record) to walk a stack frame where the stack +// is aligned and we must search +TEST_F(GetCallerFrame, WindowsFrameDataAligned) { + SetModuleSymbols(&module1, + "STACK WIN 4 aa85 176 0 0 4 4 8 0 1" + " $T1 .raSearch =" + " $T0 $T1 4 - 8 @ =" + " $ebp $T1 4 - ^ =" + " $eip $T1 ^ =" + " $esp $T1 4 + ="); + Label frame0_esp, frame0_ebp; + Label frame1_esp, frame1_ebp; + stack_section.start() = 0x80000000; + stack_section + // frame 0 + .Mark(&frame0_esp) + .D32(0x0ffa0ffa) // unused saved register + .D32(0xdeaddead) // locals + .D32(0xbeefbeef) + .D32(0) // 8-byte alignment + .Mark(&frame0_ebp) + .D32(frame1_ebp) // saved %ebp + .D32(0x5000129d) // return address + // frame 1 + .Mark(&frame1_esp) + .D32(0x1) // parameter + .Mark(&frame1_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000aa85; + raw_context.esp = frame0_esp.Value(); + raw_context.ebp = frame0_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(1U, modules_without_symbols.size()); + ASSERT_EQ("module2", modules_without_symbols[0]->debug_file()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000aa85U, frame0->instruction); + EXPECT_EQ(0x4000aa85U, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); + EXPECT_TRUE(frame0->windows_frame_info != NULL); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x5000129dU, frame1->instruction + 1); + EXPECT_EQ(0x5000129dU, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Use Windows frame data (a "STACK WIN 4" record, from a +// FrameTypeFrameData DIA record) to walk a frame, and depend on the +// parameter size from the callee as well. +TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) { + SetModuleSymbols(&module1, "FUNC 1000 100 c module1::wheedle\n"); + SetModuleSymbols(&module2, + // Note bogus parameter size in FUNC record; the stack walker + // should prefer the STACK WIN record, and see '4' below. + "FUNC aa85 176 beef module2::whine\n" + "STACK WIN 4 aa85 176 0 0 4 10 4 0 1" + " $T2 $esp .cbLocals + .cbSavedRegs + =" + " $T0 .raSearchStart =" + " $eip $T0 ^ =" + " $esp $T0 4 + =" + " $ebp $T0 20 - ^ =" + " $ebx $T0 8 - ^ =\n"); + Label frame0_esp, frame0_ebp; + Label frame1_esp; + Label frame2_esp, frame2_ebp; + stack_section.start() = 0x80000000; + stack_section + // frame 0, in module1::wheedle. Traditional frame. + .Mark(&frame0_esp) + .Append(16, 0) // frame space + .Mark(&frame0_ebp) + .D32(0x6fa902e0) // saved %ebp. Not a frame pointer. + .D32(0x5000aa95) // return address, in module2::whine + // frame 1, in module2::whine. FrameData frame. + .Mark(&frame1_esp) + .D32(0xbaa0cb7a) // argument 3 passed to module1::wheedle + .D32(0xbdc92f9f) // argument 2 + .D32(0x0b1d8442) // argument 1 + .D32(frame2_ebp) // saved %ebp + .D32(0xb1b90a15) // unused + .D32(0xf18e072d) // unused + .D32(0x2558c7f3) // saved %ebx + .D32(0x0365e25e) // unused + .D32(0x2a179e38) // return address; $T0 points here + // frame 2, in no module + .Mark(&frame2_esp) + .Append(12, 0) // empty space + .Mark(&frame2_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x40001004; // in module1::wheedle + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = frame0_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(3U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x40001004U, frame0->instruction); + EXPECT_EQ(0x40001004U, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); + EXPECT_EQ(&module1, frame0->module); + EXPECT_EQ("module1::wheedle", frame0->function_name); + EXPECT_EQ(0x40001000U, frame0->function_base); + // The FUNC record for module1::wheedle should have produced a + // WindowsFrameInfo structure with only the parameter size valid. + ASSERT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, + frame0->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_UNKNOWN, + frame0->windows_frame_info->type_); + EXPECT_EQ(12U, frame0->windows_frame_info->parameter_size); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x5000aa95U, frame1->instruction + 1); + EXPECT_EQ(0x5000aa95U, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(0x6fa902e0U, frame1->context.ebp); + EXPECT_EQ(&module2, frame1->module); + EXPECT_EQ("module2::whine", frame1->function_name); + EXPECT_EQ(0x5000aa85U, frame1->function_base); + ASSERT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame1->windows_frame_info->type_); + // This should not see the 0xbeef parameter size from the FUNC + // record, but should instead see the STACK WIN record. + EXPECT_EQ(4U, frame1->windows_frame_info->parameter_size); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP + | StackFrameX86::CONTEXT_VALID_EBX), + frame2->context_validity); + EXPECT_EQ(0x2a179e38U, frame2->instruction + 1); + EXPECT_EQ(0x2a179e38U, frame2->context.eip); + EXPECT_EQ(frame2_esp.Value(), frame2->context.esp); + EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp); + EXPECT_EQ(0x2558c7f3U, frame2->context.ebx); + EXPECT_EQ(NULL, frame2->module); + EXPECT_EQ(NULL, frame2->windows_frame_info); + } +} + +// Use Windows frame data (a "STACK WIN 4" record, from a +// FrameTypeFrameData DIA record) to walk a stack frame, where the +// expression fails to yield both an $eip and an $ebp value, and the stack +// walker must scan. +TEST_F(GetCallerFrame, WindowsFrameDataScan) { + SetModuleSymbols(&module1, + "STACK WIN 4 c8c 111 0 0 4 10 4 0 1 bad program string\n"); + // Mark frame 1's PC as the end of the stack. + SetModuleSymbols(&module2, + "FUNC 7c38 accf 0 module2::function\n" + "STACK WIN 4 7c38 accf 0 0 4 10 4 0 1 $eip 0 = $ebp 0 =\n"); + Label frame1_esp; + stack_section.start() = 0x80000000; + stack_section + // frame 0 + .Append(16, 0x2a) // unused, garbage + .D32(0x50007ce9) // return address + // frame 1 + .Mark(&frame1_esp) + .Append(8, 0); // empty space + + RegionFromSection(); + raw_context.eip = 0x40000c9c; + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = 0x2ae314cd; // should not be needed to walk frame + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x40000c9cU, frame0->instruction); + EXPECT_EQ(0x40000c9cU, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(0x2ae314cdU, frame0->context.ebp); + EXPECT_TRUE(frame0->windows_frame_info != NULL); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the walker + // does not actually fetch the EBP after a scan (forcing the next frame + // to be scanned as well). But let's grandfather the existing behavior in + // for now. + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x50007ce9U, frame1->instruction + 1); + EXPECT_EQ(0x50007ce9U, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_TRUE(frame1->windows_frame_info != NULL); + } +} + +// Use Windows frame data (a "STACK WIN 4" record, from a +// FrameTypeFrameData DIA record) to walk a stack frame, where the +// expression yields an $eip that falls outside of any module, and the +// stack walker must scan. +TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) { + SetModuleSymbols(&module1, + "STACK WIN 4 6e6 e7 0 0 0 8 4 0 1" + // A traditional frame, actually. + " $eip $ebp 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =\n"); + // Mark frame 1's PC as the end of the stack. + SetModuleSymbols(&module2, + "FUNC cfdb 8406 0 module2::function\n" + "STACK WIN 4 cfdb 8406 0 0 0 0 0 0 1 $eip 0 = $ebp 0 =\n"); + stack_section.start() = 0x80000000; + + // In this stack, the context's %ebp is pointing at the wrong place, so + // the stack walker needs to scan to find the return address, and then + // scan again to find the caller's saved %ebp. + Label frame0_ebp, frame1_ebp, frame1_esp; + stack_section + // frame 0 + .Append(8, 0x2a) // garbage + .Mark(&frame0_ebp) // frame 0 %ebp points here, but should point + // at *** below + // The STACK WIN record says that the following two values are + // frame 1's saved %ebp and return address, but the %ebp is wrong; + // they're garbage. The stack walker will scan for the right values. + .D32(0x3d937b2b) // alleged to be frame 1's saved %ebp + .D32(0x17847f5b) // alleged to be frame 1's return address + .D32(frame1_ebp) // frame 1's real saved %ebp; scan will find + .D32(0x2b2b2b2b) // first word of realigned register save area + // *** frame 0 %ebp ought to be pointing here + .D32(0x2c2c2c2c) // realigned locals area + .D32(0x5000d000) // frame 1's real saved %eip; scan will find + // Frame 1, in module2::function. The STACK WIN record describes + // this as the oldest frame, without referring to its contents, so + // we needn't to provide any actual data here. + .Mark(&frame1_esp) + .Mark(&frame1_ebp) // frame 1 %ebp points here + // A dummy value for frame 1's %ebp to point at. The scan recognizes the + // saved %ebp because it points to a valid word in the stack memory region. + .D32(0x2d2d2d2d); + + RegionFromSection(); + raw_context.eip = 0x40000700; + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = frame0_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x40000700U, frame0->instruction); + EXPECT_EQ(0x40000700U, frame0->context.eip); + EXPECT_EQ(stack_section.start().Value(), frame0->context.esp); + EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); + EXPECT_TRUE(frame0->windows_frame_info != NULL); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); + // I'd argue that CONTEXT_VALID_EBP shouldn't be here, since the + // walker does not actually fetch the EBP after a scan (forcing the + // next frame to be scanned as well). But let's grandfather the existing + // behavior in for now. + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x5000d000U, frame1->instruction + 1); + EXPECT_EQ(0x5000d000U, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_TRUE(frame1->windows_frame_info != NULL); + } +} + +// Use Windows FrameTypeFPO data to walk a stack frame for a function that +// does not modify %ebp from the value it had in the caller. +TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) { + SetModuleSymbols(&module1, + // Note bogus parameter size in FUNC record; the walker + // should prefer the STACK WIN record, and see the '8' below. + "FUNC e8a8 100 feeb module1::discombobulated\n" + "STACK WIN 0 e8a8 100 0 0 8 4 10 0 0 0\n"); + Label frame0_esp; + Label frame1_esp, frame1_ebp; + stack_section.start() = 0x80000000; + stack_section + // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame. + .Mark(&frame0_esp) + // no outgoing parameters; this is the youngest frame. + .D32(0x7c521352) // four bytes of saved registers + .Append(0x10, 0x42) // local area + .D32(0x40009b5b) // return address, in module1, no function + // frame 1, in module1, no function. + .Mark(&frame1_esp) + .D32(0xf60ea7fc) // junk + .Mark(&frame1_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x4000e8b8; // in module1::whine + raw_context.esp = stack_section.start().Value(); + // Frame pointer unchanged from caller. + raw_context.ebp = frame1_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x4000e8b8U, frame0->instruction); + EXPECT_EQ(0x4000e8b8U, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + // unchanged from caller + EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); + EXPECT_EQ(&module1, frame0->module); + EXPECT_EQ("module1::discombobulated", frame0->function_name); + EXPECT_EQ(0x4000e8a8U, frame0->function_base); + // The STACK WIN record for module1::discombobulated should have + // produced a fully populated WindowsFrameInfo structure. + ASSERT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, + frame0->windows_frame_info->type_); + EXPECT_EQ(0x10U, frame0->windows_frame_info->local_size); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP + | StackFrameX86::CONTEXT_VALID_EBX), + frame1->context_validity); + EXPECT_EQ(0x40009b5bU, frame1->instruction + 1); + EXPECT_EQ(0x40009b5bU, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(&module1, frame1->module); + EXPECT_EQ("", frame1->function_name); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// Use Windows FrameTypeFPO data to walk a stack frame for a function +// that uses %ebp for its own purposes, saving the value it had in the +// caller in the standard place in the saved register area. +TEST_F(GetCallerFrame, WindowsFPOUsedEBP) { + SetModuleSymbols(&module1, + // Note bogus parameter size in FUNC record; the walker + // should prefer the STACK WIN record, and see the '8' below. + "FUNC 9aa8 e6 abbe module1::RaisedByTheAliens\n" + "STACK WIN 0 9aa8 e6 a 0 10 8 4 0 0 1\n"); + Label frame0_esp; + Label frame1_esp, frame1_ebp; + stack_section.start() = 0x80000000; + stack_section + // frame 0, in module1::wheedle. FrameTypeFPO (STACK WIN 0) frame. + .Mark(&frame0_esp) + // no outgoing parameters; this is the youngest frame. + .D32(frame1_ebp) // saved register area: saved %ebp + .D32(0xb68bd5f9) // saved register area: something else + .D32(0xd25d05fc) // local area + .D32(0x4000debe) // return address, in module1, no function + // frame 1, in module1, no function. + .Mark(&frame1_esp) + .D32(0xf0c9a974) // junk + .Mark(&frame1_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x40009ab8; // in module1::RaisedByTheAliens + raw_context.esp = stack_section.start().Value(); + // RaisedByTheAliens uses %ebp for its own mysterious purposes. + raw_context.ebp = 0xecbdd1a5; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x40009ab8U, frame0->instruction); + EXPECT_EQ(0x40009ab8U, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + EXPECT_EQ(0xecbdd1a5, frame0->context.ebp); + EXPECT_EQ(&module1, frame0->module); + EXPECT_EQ("module1::RaisedByTheAliens", frame0->function_name); + EXPECT_EQ(0x40009aa8U, frame0->function_base); + // The STACK WIN record for module1::RaisedByTheAliens should have + // produced a fully populated WindowsFrameInfo structure. + ASSERT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, + frame0->windows_frame_info->type_); + EXPECT_EQ("", frame0->windows_frame_info->program_string); + EXPECT_TRUE(frame0->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x4000debeU, frame1->instruction + 1); + EXPECT_EQ(0x4000debeU, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(&module1, frame1->module); + EXPECT_EQ("", frame1->function_name); + EXPECT_EQ(NULL, frame1->windows_frame_info); + } +} + +// This is a regression test for FPO code that references the initial value of +// EBX. +TEST_F(GetCallerFrame, WindowsFPOReferencesEBX) { + MockCodeModule ntdll(0x776e0000, 0x142000, "ntdll", "ntdllver"); + MockCodeModule kernel32(0x77250000, 0xd5000, "kernel32", "kernel32ver"); + MockCodeModule chrome_child(0x5a710000, 0x2b7c000, "chrome_child", + "chrome_childver"); + MockCodeModules modules; + modules.Add(&ntdll); + modules.Add(&kernel32); + modules.Add(&chrome_child); + SetModuleSymbols(&ntdll, + "PUBLIC 46bf4 0 KiFastSystemCallRet\n" + "STACK WIN 0 46bf4 1 0 0 0 0 0 0 0 0\n" + + "PUBLIC 46550 10 NtWaitForKeyedEvent\n" + "STACK WIN 0 46550 f 0 0 10 0 0 0 0 0\n" + + "PUBLIC 4965 10 RtlSleepConditionVariableSRW\n" + + "STACK WIN 4 4965 23 23 0 10 8 38 0 1 $T0 $ebx = " + "$eip $T0 4 + ^ = $ebx $T0 ^ = $esp $T0 8 + = " + "$ebp $ebp ^ = $L $ebp = $P $T0 8 + .cbParams + =\n" + + "STACK WIN 4 4988 e3 0 0 10 8 38 0 1 $T0 $ebx = " + "$eip $T0 4 + ^ = $ebx $T0 ^ = $esp $T0 8 + = " + "$ebp $ebp ^ = $L $ebp = $P $T0 8 + .cbParams + =\n" + + "STACK WIN 4 4b2e b 0 0 10 8 38 0 1 $T0 $ebx = " + "$eip $T0 4 + ^ = $ebx $T0 ^ = $esp $T0 8 + = " + "$ebp $ebp ^ = $L $ebp = $P $T0 8 + .cbParams + =\n"); + + SetModuleSymbols(&kernel32, + "PUBLIC 3217a 10 SleepConditionVariableSRW\n" + "STACK WIN 4 3217a 40 8 0 10 0 8 0 1 $T0 $ebp = $eip $T0 4 " + "+ ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs - = " + "$P $T0 8 + .cbParams + =\n"); + + SetModuleSymbols(&chrome_child, + "FUNC 4f4851 20 0 base::ConditionVariable::TimedWait\n"); + + stack_section.start() = 0x0026c048; + stack_section + .D32(0x7772655c) + .D32(0x776e4a3f) + .D32(0x00000000) + .D32(0x0026c070) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000001) + .D32(0x0026c168) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x0026c070) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x0026c164) + .D32(0x00be0000) + .D32(0x0026fc60) + .D32(0x0026c164) + .D32(0x00000000) + .D32(0xfffffffe) + .D32(0x00000000) + .D32(0x0026c0d0) + .D32(0x7728219e) + .D32(0x000003e8) + .D32(0x00000000) + .D32(0x7728219e) + .D32(0x0026c168) + .D32(0x0026c164) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x0026c168) + .D32(0x000003e8) + .D32(0x000003e8) + .D32(0x0026c0ec) + .D32(0x5ac0486c) + .D32(0x0026c168) + .D32(0x0026c108) + .D32(0x5ac0484c) + .D32(0x0026c100) + .D32(0x0026c160); + + RegionFromSection(); + raw_context.eip = 0x77726bf4; // in ntdll!KiFastSystemCallRet + raw_context.esp = stack_section.start().Value(); + raw_context.ebp = 0x26c0a0; + raw_context.ebx = 0x26c0ac; + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + + ASSERT_EQ(5U, frames->size()); + { + const StackFrameX86 &frame = *static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame.trust); + EXPECT_EQ(0x77726bf4U, frame.context.eip); + EXPECT_EQ("KiFastSystemCallRet", frame.function_name); + } + { + const StackFrameX86 &frame = *static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); + EXPECT_EQ(0x7772655cU, frame.context.eip); + EXPECT_EQ("NtWaitForKeyedEvent", frame.function_name); + } + { + const StackFrameX86 &frame = *static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); + EXPECT_EQ(0x776e4a3fU, frame.context.eip); + EXPECT_EQ("RtlSleepConditionVariableSRW", frame.function_name); + } + { + const StackFrameX86 &frame = *static_cast(frames->at(3)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); + EXPECT_EQ(0x7728219eU, frame.context.eip); + EXPECT_EQ("SleepConditionVariableSRW", frame.function_name); + } + { + const StackFrameX86 &frame = *static_cast(frames->at(4)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame.trust); + EXPECT_EQ(0x5ac0486cU, frame.context.eip); + EXPECT_EQ("base::ConditionVariable::TimedWait", frame.function_name); + } +} + +// This is a regression unit test which covers a bug which has to do with +// FPO-optimized Windows system call stubs in the context frame. There is +// a more recent Windows system call dispatch mechanism which differs from +// the one which is being tested here. The newer system call dispatch +// mechanism creates an extra context frame (KiFastSystemCallRet). +TEST_F(GetCallerFrame, WindowsFPOSystemCall) { + SetModuleSymbols(&module3, // ntdll.dll + "PUBLIC 1f8ac c ZwWaitForSingleObject\n" + "STACK WIN 0 1f8ac 1b 0 0 c 0 0 0 0 0\n"); + SetModuleSymbols(&module4, // kernelbase.dll + "PUBLIC 109f9 c WaitForSingleObjectEx\n" + "PUBLIC 36590 0 _except_handler4\n" + "STACK WIN 4 109f9 df c 0 c c 48 0 1 $T0 $ebp = $eip " + "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " + "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n" + "STACK WIN 4 36590 154 17 0 10 0 14 0 1 $T0 $ebp = $eip " + "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 " + ".cbSavedRegs - = $P $T0 8 + .cbParams + =\n"); + SetModuleSymbols(&module5, // kernel32.dll + "PUBLIC 11136 8 WaitForSingleObject\n" + "PUBLIC 11151 c WaitForSingleObjectExImplementation\n" + "STACK WIN 4 11136 16 5 0 8 0 0 0 1 $T0 $ebp = $eip " + "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " + "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n" + "STACK WIN 4 11151 7a 5 0 c 0 0 0 1 $T0 $ebp = $eip " + "$T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " + "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =\n"); + SetModuleSymbols(&module6, // chrome.dll + "FILE 7038 some_file_name.h\n" + "FILE 839776 some_file_name.cc\n" + "FUNC 217fda 17 4 function_217fda\n" + "217fda 4 102 839776\n" + "FUNC 217ff1 a 4 function_217ff1\n" + "217ff1 0 594 7038\n" + "217ff1 a 596 7038\n" + "STACK WIN 0 217ff1 a 0 0 4 0 0 0 0 0\n"); + + Label frame0_esp, frame1_esp; + Label frame1_ebp, frame2_ebp, frame3_ebp; + stack_section.start() = 0x002ff290; + stack_section + .Mark(&frame0_esp) + .D32(0x771ef8c1) // EIP in frame 0 (system call) + .D32(0x75fa0a91) // return address of frame 0 + .Mark(&frame1_esp) + .D32(0x000017b0) // args to child + .D32(0x00000000) + .D32(0x002ff2d8) + .D32(0x88014a2e) + .D32(0x002ff364) + .D32(0x000017b0) + .D32(0x00000000) + .D32(0x00000024) + .D32(0x00000001) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x9e3b9800) + .D32(0xfffffff7) + .D32(0x00000000) + .D32(0x002ff2a4) + .D32(0x64a07ff1) // random value to be confused with a return address + .D32(0x002ff8dc) + .D32(0x75fc6590) // random value to be confused with a return address + .D32(0xfdd2c6ea) + .D32(0x00000000) + .Mark(&frame1_ebp) + .D32(frame2_ebp) // Child EBP + .D32(0x75741194) // return address of frame 1 + .D32(0x000017b0) // args to child + .D32(0x0036ee80) + .D32(0x00000000) + .D32(0x65bc7d14) + .Mark(&frame2_ebp) + .D32(frame3_ebp) // Child EBP + .D32(0x75741148) // return address of frame 2 + .D32(0x000017b0) // args to child + .D32(0x0036ee80) + .D32(0x00000000) + .Mark(&frame3_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x771ef8c1; // in ntdll::ZwWaitForSingleObject + raw_context.esp = stack_section.start().Value(); + ASSERT_TRUE(raw_context.esp == frame0_esp.Value()); + raw_context.ebp = frame1_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + + ASSERT_EQ(4U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x771ef8c1U, frame0->instruction); + EXPECT_EQ(0x771ef8c1U, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame0->context.ebp); + EXPECT_EQ(&module3, frame0->module); + EXPECT_EQ("ZwWaitForSingleObject", frame0->function_name); + // The STACK WIN record for module3!ZwWaitForSingleObject should have + // produced a fully populated WindowsFrameInfo structure. + ASSERT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FPO, + frame0->windows_frame_info->type_); + EXPECT_EQ("", frame0->windows_frame_info->program_string); + EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP + | StackFrameX86::CONTEXT_VALID_ESP + | StackFrameX86::CONTEXT_VALID_EBP + | StackFrameX86::CONTEXT_VALID_EBX), + frame1->context_validity); + EXPECT_EQ(0x75fa0a91U, frame1->instruction + 1); + EXPECT_EQ(0x75fa0a91U, frame1->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(&module4, frame1->module); + EXPECT_EQ("WaitForSingleObjectEx", frame1->function_name); + // The STACK WIN record for module4!WaitForSingleObjectEx should have + // produced a fully populated WindowsFrameInfo structure. + ASSERT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame1->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L " + "$T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", + frame1->windows_frame_info->program_string); + EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer); + } +} + +// Scan the stack for a better return address and potentially skip frames +// when the calculated return address is not in a known module. Note, that +// the span of this scan is somewhat arbitrarily limited to 160 search words +// for the context frame and 40 search words (pointers) for the other frames: +// const int kRASearchWords = 40; +// This means that frames can be skipped only when their size is relatively +// small: smaller than 4 * kRASearchWords * sizeof(InstructionType) +TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) { + MockCodeModule msvcrt_dll(0x77be0000, 0x58000, "msvcrt.dll", "version1"); + SetModuleSymbols(&msvcrt_dll, // msvcrt.dll + "PUBLIC 38180 0 wcsstr\n" + "STACK WIN 4 38180 61 10 0 8 0 0 0 1 $T0 $ebp = $eip $T0 " + "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " + "- = $P $T0 4 + .cbParams + =\n"); + + MockCodeModule kernel32_dll(0x7c800000, 0x103000, "kernel32.dll", "version1"); + SetModuleSymbols(&kernel32_dll, // kernel32.dll + "PUBLIC efda 8 FindNextFileW\n" + "STACK WIN 4 efda 1bb c 0 8 8 3c 0 1 $T0 $ebp = $eip $T0 " + "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " + "- = $P $T0 4 + .cbParams + =\n"); + + MockCodeModule chrome_dll(0x1c30000, 0x28C8000, "chrome.dll", "version1"); + SetModuleSymbols(&chrome_dll, // chrome.dll + "FUNC e3cff 4af 0 file_util::FileEnumerator::Next()\n" + "e3cff 1a 711 2505\n" + "STACK WIN 4 e3cff 4af 20 0 4 c 94 0 1 $T1 .raSearch = " + "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp " + "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 " + "$T0 160 - ^ =\n"); + + // Create some modules with some stock debugging information. + MockCodeModules local_modules; + local_modules.Add(&msvcrt_dll); + local_modules.Add(&kernel32_dll); + local_modules.Add(&chrome_dll); + + Label frame0_esp; + Label frame0_ebp; + Label frame1_ebp; + Label frame2_ebp; + Label frame3_ebp; + + stack_section.start() = 0x0932f2d0; + stack_section + .Mark(&frame0_esp) + .D32(0x0764e000) + .D32(0x0764e068) + .Mark(&frame0_ebp) + .D32(frame1_ebp) // Child EBP + .D32(0x001767a0) // return address of frame 0 + // Not in known module + .D32(0x0764e0c6) + .D32(0x001bb1b8) + .D32(0x0764e068) + .D32(0x00000003) + .D32(0x0764e068) + .D32(0x00000003) + .D32(0x07578828) + .D32(0x0764e000) + .D32(0x00000000) + .D32(0x001c0010) + .D32(0x0764e0c6) + .Mark(&frame1_ebp) + .D32(frame2_ebp) // Child EBP + .D32(0x7c80f10f) // return address of frame 1 + // inside kernel32!FindNextFileW + .D32(0x000008f8) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x0932f34c) + .D32(0x0764e000) + .D32(0x00001000) + .D32(0x00000000) + .D32(0x00000001) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x0932f6a8) + .D32(0x00000000) + .D32(0x0932f6d8) + .D32(0x00000000) + .D32(0x000000d6) + .D32(0x0764e000) + .D32(0x7ff9a000) + .D32(0x0932f3fc) + .D32(0x00000001) + .D32(0x00000001) + .D32(0x07578828) + .D32(0x0000002e) + .D32(0x0932f340) + .D32(0x0932eef4) + .D32(0x0932ffdc) + .D32(0x7c839ad8) + .D32(0x7c80f0d8) + .D32(0x00000000) + .Mark(&frame2_ebp) + .D32(frame3_ebp) // Child EBP + .D32(0x01d13f91) // return address of frame 2 + // inside chrome_dll!file_util::FileEnumerator::Next + .D32(0x07578828) + .D32(0x0932f6ac) + .D32(0x0932f9c4) + .D32(0x0932f9b4) + .D32(0x00000000) + .D32(0x00000003) + .D32(0x0932f978) + .D32(0x01094330) + .D32(0x00000000) + .D32(0x00000001) + .D32(0x01094330) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x07f30000) + .D32(0x01c3ba17) + .D32(0x08bab840) + .D32(0x07f31580) + .D32(0x00000000) + .D32(0x00000007) + .D32(0x0932f940) + .D32(0x0000002e) + .D32(0x0932f40c) + .D32(0x01d13b53) + .D32(0x0932f958) + .D32(0x00000001) + .D32(0x00000007) + .D32(0x0932f940) + .D32(0x0000002e) + .D32(0x00000000) + .D32(0x0932f6ac) + .D32(0x01e13ef0) + .D32(0x00000001) + .D32(0x00000007) + .D32(0x0932f958) + .D32(0x08bab840) + .D32(0x0932f9b4) + .D32(0x00000000) + .D32(0x0932f9b4) + .D32(0x000000a7) + .D32(0x000000a7) + .D32(0x0932f998) + .D32(0x579627a2) + .Mark(&frame3_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x77c181cd; // inside msvcrt!wcsstr + raw_context.esp = frame0_esp.Value(); + raw_context.ebp = frame0_ebp.Value(); + // sanity + ASSERT_TRUE(raw_context.esp == stack_section.start().Value()); + ASSERT_TRUE(raw_context.ebp == stack_section.start().Value() + 8); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, + &local_modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + + ASSERT_EQ(3U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(0x77c181cdU, frame0->instruction); + EXPECT_EQ(0x77c181cdU, frame0->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame0->context.esp); + EXPECT_EQ(frame0_ebp.Value(), frame0->context.ebp); + EXPECT_EQ(&msvcrt_dll, frame0->module); + EXPECT_EQ("wcsstr", frame0->function_name); + ASSERT_TRUE(frame0->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame0->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame0->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 " + "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " + "- = $P $T0 4 + .cbParams + =", + frame0->windows_frame_info->program_string); + // It has program string, so allocates_base_pointer is not expected + EXPECT_FALSE(frame0->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI_SCAN, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(0x7c80f10fU, frame1->instruction + 1); + EXPECT_EQ(0x7c80f10fU, frame1->context.eip); + // frame 1 was skipped, so intead of frame1_ebp compare with frame2_ebp. + EXPECT_EQ(frame2_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(&kernel32_dll, frame1->module); + EXPECT_EQ("FindNextFileW", frame1->function_name); + ASSERT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame1->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 " + "4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = $L $T0 .cbSavedRegs " + "- = $P $T0 4 + .cbParams + =", + frame1->windows_frame_info->program_string); + EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame2->context_validity); + EXPECT_EQ(0x01d13f91U, frame2->instruction + 1); + EXPECT_EQ(0x01d13f91U, frame2->context.eip); + // frame 1 was skipped, so intead of frame2_ebp compare with frame3_ebp. + EXPECT_EQ(frame3_ebp.Value(), frame2->context.ebp); + EXPECT_EQ(&chrome_dll, frame2->module); + EXPECT_EQ("file_util::FileEnumerator::Next()", frame2->function_name); + ASSERT_TRUE(frame2->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame2->windows_frame_info->type_); + EXPECT_EQ("$T1 .raSearch = " + "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp " + "$T1 4 + = $20 $T0 152 - ^ = $23 $T0 156 - ^ = $24 " + "$T0 160 - ^ =", + frame2->windows_frame_info->program_string); + EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer); + } +} + +// Test the .raSearchStart/.raSearch calculation when alignment operators are +// used in the program string. The current %ebp must be valid and it is the +// only reliable data point that can be used for that calculation. +TEST_F(GetCallerFrame, HandleAlignmentInProgramString) { + MockCodeModule chrome_dll(0x59630000, 0x19e3000, "chrome.dll", "version1"); + SetModuleSymbols(&chrome_dll, // chrome.dll + "FUNC 56422 50c 8 base::MessageLoop::RunTask" + "(base::PendingTask const &)\n" + "56422 e 458 4589\n" + "STACK WIN 4 56422 50c 11 0 8 c ac 0 1 $T1 .raSearch = $T0 " + "$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + = " + "$20 $T0 176 - ^ = $23 $T0 180 - ^ = $24 $T0 184 - ^ =\n" + "FUNC 55d34 34a 0 base::MessageLoop::DoWork()\n" + "55d34 11 596 4589\n" + "STACK WIN 4 55d34 34a 19 0 0 c 134 0 1 $T1 .raSearch = " + "$T0 $T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp " + "$T1 4 + = $20 $T0 312 - ^ = $23 $T0 316 - ^ = $24 $T0 " + "320 - ^ =\n" + "FUNC 55c39 fb 0 base::MessagePumpForIO::DoRunLoop()\n" + "55c39 d 518 19962\n" + "STACK WIN 4 55c39 fb d 0 0 c 34 0 1 $T1 .raSearch = $T0 " + "$T1 4 - 64 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + " + "= $20 $T0 56 - ^ = $23 $T0 60 - ^ = $24 $T0 64 - ^ =\n" + "FUNC 55bf0 49 4 base::MessagePumpWin::Run(base::" + "MessagePump::Delegate *)\n" + "55bf0 49 48 4724\n" + "STACK WIN 4 55bf0 49 c 0 4 0 10 0 1 $T0 $ebp = $eip $T0 4 " + "+ ^ = $ebp $T0 ^ = $esp $T0 8 + =\n" + "FUNC 165d de 4 malloc\n" + "165d 6 119 54\n" + "STACK WIN 4 165d de d 0 4 8 0 0 1 $T1 .raSearch = $T0 " + "$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 " + "+ = $23 $T0 4 - ^ = $24 $T0 8 - ^ =\n" + "FUNC 55ac9 79 0 base::MessageLoop::RunInternal()\n" + "55ac9 d 427 4589\n" + "STACK WIN 4 55ac9 79 d 0 0 8 10 0 1 $T1 .raSearch = $T0 " + "$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + = " + "$23 $T0 20 - ^ = $24 $T0 24 - ^ =\n"); + + // Create some modules with some stock debugging information. + MockCodeModules local_modules; + local_modules.Add(&chrome_dll); + + Label frame0_esp; + Label frame0_ebp; + Label frame1_esp; + Label frame1_ebp; + Label frame2_esp; + Label frame2_ebp; + Label frame3_esp; + Label frame3_ebp; + + stack_section.start() = 0x046bfc80; + stack_section + .D32(0) + .Mark(&frame0_esp) + .D32(0x01e235a0) + .D32(0x00000000) + .D32(0x01e9f580) + .D32(0x01e9f580) + .D32(0x00000020) + .D32(0x00000000) + .D32(0x00463674) + .D32(0x00000020) + .D32(0x00000000) + .D32(0x046bfcd8) + .D32(0x046bfcd8) + .D32(0x0001204b) + .D32(0x00000000) + .D32(0xfdddb523) + .D32(0x00000000) + .D32(0x00000007) + .D32(0x00000040) + .D32(0x00000000) + .D32(0x59631693) // chrome_59630000!malloc+0x36 + .D32(0x01e9f580) + .D32(0x01e9f580) + .D32(0x046bfcf8) + .D32(0x77da6704) // ntdll!NtSetIoCompletion+0xc + .D32(0x046bfd4c) + .D32(0x59685bec) // chrome_59630000!base::MessageLoop::StartHistogrammer.. + .D32(0x01e235a0) + + .Mark(&frame0_ebp) + .D32(frame1_ebp) // Child EBP .D32(0x046bfd0c) + .D32(0x59685c2e) // Return address in + // chrome_59630000!base::MessagePumpWin::Run+0x3e + .Mark(&frame1_esp) + .D32(0x01e75a90) + .D32(0x046bfd4c) + .D32(0x01e75a90) + .D32(0x00000000) + .D32(0x00000300) + .D32(0x00000001) + + .Mark(&frame1_ebp) + .D32(frame2_ebp) // Child EBP .D32(0x046bfd30) + .D32(0x59685b3c) // Return address in + // chrome_59630000!base::MessageLoop::RunInternal+0x73 + .Mark(&frame2_esp) + .D32(0x01e75a90) + .D32(0x00000000) + .D32(0x046bfd4c) + .D32(0x59658123) // chrome_59630000!std::deque.. + .D32(0x046bfda0) + .D32(0x01e79d70) + .D32(0x046bfda0) + + .Mark(&frame2_ebp) // .D32(0x046bfd40) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x59685c46; // Context frame in + // base::MessagePumpForIO::DoRunLoop + raw_context.esp = frame0_esp.Value(); + raw_context.ebp = frame0_ebp.Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, + &local_modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + + ASSERT_EQ(3U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame->context_validity); + EXPECT_EQ("base::MessagePumpForIO::DoRunLoop()", frame->function_name); + EXPECT_EQ(0x59685c46U, frame->instruction); + EXPECT_EQ(0x59685c46U, frame->context.eip); + EXPECT_EQ(frame0_esp.Value(), frame->context.esp); + EXPECT_EQ(frame0_ebp.Value(), frame->context.ebp); + EXPECT_EQ(&chrome_dll, frame->module); + ASSERT_TRUE(frame->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame->windows_frame_info->type_); + EXPECT_EQ("$T1 .raSearch = $T0 " + "$T1 4 - 64 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + " + "= $20 $T0 56 - ^ = $23 $T0 60 - ^ = $24 $T0 64 - ^ =", + frame->windows_frame_info->program_string); + EXPECT_FALSE(frame->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame->context_validity); + EXPECT_EQ("base::MessagePumpWin::Run(base::MessagePump::Delegate *)", + frame->function_name); + EXPECT_EQ(1500011566U, frame->instruction + 1); + EXPECT_EQ(1500011566U, frame->context.eip); + EXPECT_EQ(frame1_esp.Value(), frame->context.esp); + EXPECT_EQ(frame1_ebp.Value(), frame->context.ebp); + EXPECT_EQ(&chrome_dll, frame->module); + ASSERT_TRUE(frame->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =", + frame->windows_frame_info->program_string); + EXPECT_FALSE(frame->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame->context_validity); + EXPECT_EQ("base::MessageLoop::RunInternal()", frame->function_name); + EXPECT_EQ(1500011324U, frame->instruction + 1); + EXPECT_EQ(1500011324U, frame->context.eip); + EXPECT_EQ(frame2_esp.Value(), frame->context.esp); + EXPECT_EQ(frame2_ebp.Value(), frame->context.ebp); + EXPECT_EQ(&chrome_dll, frame->module); + ASSERT_TRUE(frame->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame->windows_frame_info->type_); + EXPECT_EQ("$T1 .raSearch = $T0 " + "$T1 4 - 8 @ = $ebp $T1 4 - ^ = $eip $T1 ^ = $esp $T1 4 + = " + "$23 $T0 20 - ^ = $24 $T0 24 - ^ =", + frame->windows_frame_info->program_string); + EXPECT_FALSE(frame->windows_frame_info->allocates_base_pointer); + } +} + +// Scan the stack for a return address and potentially skip frames when the +// current IP address is not in a known module. Note, that that the span of +// this scan is limited to 120 search words for the context frame and 30 +// search words (pointers) for the other frames: +// const int kRASearchWords = 30; +void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl( + bool has_corrupt_symbols) { + MockCodeModule remoting_core_dll(0x54080000, 0x501000, "remoting_core.dll", + "version1"); + string symbols_func_section = + "FUNC 137214 17d 10 PK11_Verify\n" + "FUNC 15c834 37 14 nsc_ECDSAVerifyStub\n" + "FUNC 1611d3 91 14 NSC_Verify\n" + "FUNC 162ff7 60 4 sftk_SessionFromHandle\n"; + string symbols_stack_section = + "STACK WIN 4 137214 17d 9 0 10 0 10 0 1 $T0 $ebp = " + "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n" + "STACK WIN 4 15c834 37 6 0 14 0 18 0 1 $T0 $ebp = " + "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n" + "STACK WIN 4 1611d3 91 7 0 14 0 8 0 1 $T0 $ebp = " + "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n" + "STACK WIN 4 162ff7 60 5 0 4 0 0 0 1 $T0 $ebp = " + "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"; + + string symbols = symbols_func_section; + if (has_corrupt_symbols) { + symbols.append(string(1, '\0')); // null terminator in the middle + symbols.append("\n"); + symbols.append("FUNC 1234\n" // invalid FUNC records + "FUNNC 1234\n" + "STACK WIN 4 1234 234 23 " // invalid STACK record + "23423423 234 23 234 234 " + "234 23 234 23 234 234 " + "234 234 234\n"); + } + symbols.append(symbols_stack_section); + SetModuleSymbols(&remoting_core_dll, symbols); + + // Create some modules with some stock debugging information. + MockCodeModules local_modules; + local_modules.Add(&remoting_core_dll); + + Label frame0_esp; + Label frame0_ebp; + Label frame1_ebp; + Label frame1_esp; + Label frame2_ebp; + Label frame2_esp; + Label frame3_ebp; + Label frame3_esp; + Label bogus_stack_location_1; + Label bogus_stack_location_2; + Label bogus_stack_location_3; + + stack_section.start() = 0x01a3ea28; + stack_section + .Mark(&frame0_esp) + .D32(bogus_stack_location_2) + .D32(bogus_stack_location_1) + .D32(0x042478e4) + .D32(bogus_stack_location_2) + .D32(0x00000000) + .D32(0x041f0420) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000001) + .D32(0x00b7e0d0) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000001) + .D32(0x00b7f570) + .Mark(&bogus_stack_location_1) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x04289530) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x00b7e910) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x00b7d998) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x00b7dec0) + .Mark(&bogus_stack_location_2) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x04289428) + .D32(0x00000000) + .D32(0x00000040) + .D32(0x00000008) + .D32(0x00b7f258) + .Mark(&bogus_stack_location_3) + .D32(0x00000000) + .D32(0x041f3560) + .D32(0x00000041) + .D32(0x00000020) + .D32(0xffffffff) + .Mark(&frame0_ebp) + .D32(frame1_ebp) // Child %ebp + .D32(0x541dc866) // return address of frame 0 + // inside remoting_core!nsc_ECDSAVerifyStub+0x32 + .Mark(&frame1_esp) + .D32(0x04247860) + .D32(0x01a3eaec) + .D32(0x01a3eaf8) + .D32(0x541e304f) // remoting_core!sftk_SessionFromHandle+0x58 + .D32(0x0404c620) + .D32(0x00000040) + .D32(0x01a3eb2c) + .D32(0x01a3ec08) + .D32(0x00000014) + .Mark(&frame1_ebp) + .D32(frame2_ebp) // Child %ebp + .D32(0x541e1234) // return address of frame 1 + // inside remoting_core!NSC_Verify+0x61 + .Mark(&frame2_esp) + .D32(0x04247858) + .D32(0x0404c620) + .D32(0x00000040) + .D32(0x01a3ec08) + .D32(0x00000014) + .D32(0x01000005) + .D32(0x00b2f7a0) + .D32(0x041f0420) + .D32(0x041f3650) + .Mark(&frame2_ebp) + .D32(frame3_ebp) // Child %ebp + .D32(0x541b734d) // return address of frame 1 + // inside remoting_core!PK11_Verify+0x139 + .Mark(&frame3_esp) + .D32(0x01000005) + .D32(0x01a3ec08) + .D32(0x00000014) + .D32(0x0404c620) + .D32(0x00000040) + .D32(0x04073e00) + .D32(0x04073e00) + .D32(0x04247050) + .D32(0x00001041) + .D32(0x00000000) + .D32(0x00000000) + .D32(0x00000000) + .Mark(&frame3_ebp) + .D32(0) // saved %ebp (stack end) + .D32(0); // saved %eip (stack end) + + RegionFromSection(); + raw_context.eip = 0x4247860; // IP address not in known module + raw_context.ebp = 0x5420362d; // bogus + raw_context.esp = frame0_esp.Value(); + + // sanity + ASSERT_TRUE(raw_context.esp == stack_section.start().Value()); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, + &local_modules, &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + if (has_corrupt_symbols) { + ASSERT_EQ(1U, modules_with_corrupt_symbols.size()); + ASSERT_EQ("remoting_core.dll", + modules_with_corrupt_symbols[0]->debug_file()); + } else { + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + } + frames = call_stack.frames(); + + ASSERT_EQ(4U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ(raw_context.eip, frame0->context.eip); + EXPECT_EQ(raw_context.ebp, frame0->context.ebp); + EXPECT_EQ(raw_context.esp, frame0->context.esp); + EXPECT_EQ(NULL, frame0->module); // IP not in known module + EXPECT_EQ("", frame0->function_name); + ASSERT_EQ(NULL, frame0->windows_frame_info); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame1->context_validity); + EXPECT_EQ(frame1_ebp.Value(), frame1->context.ebp); + EXPECT_EQ(frame1_esp.Value(), frame1->context.esp); + EXPECT_EQ(&remoting_core_dll, frame1->module); + EXPECT_EQ("nsc_ECDSAVerifyStub", frame1->function_name); + ASSERT_TRUE(frame1->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame1->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame1->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =", + frame1->windows_frame_info->program_string); + EXPECT_FALSE(frame1->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame2 = static_cast(frames->at(2)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame2->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame2->context_validity); + EXPECT_EQ(frame2_ebp.Value(), frame2->context.ebp); + EXPECT_EQ(frame2_esp.Value(), frame2->context.esp); + EXPECT_EQ(&remoting_core_dll, frame2->module); + EXPECT_EQ("NSC_Verify", frame2->function_name); + ASSERT_TRUE(frame2->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame2->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame2->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =", + frame2->windows_frame_info->program_string); + EXPECT_FALSE(frame2->windows_frame_info->allocates_base_pointer); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame3 = static_cast(frames->at(3)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame3->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP), + frame3->context_validity); + EXPECT_EQ(frame3_ebp.Value(), frame3->context.ebp); + EXPECT_EQ(frame3_esp.Value(), frame3->context.esp); + EXPECT_EQ(&remoting_core_dll, frame3->module); + EXPECT_EQ("PK11_Verify", frame3->function_name); + ASSERT_TRUE(frame3->windows_frame_info != NULL); + EXPECT_EQ(WindowsFrameInfo::VALID_ALL, frame3->windows_frame_info->valid); + EXPECT_EQ(WindowsFrameInfo::STACK_INFO_FRAME_DATA, + frame3->windows_frame_info->type_); + EXPECT_EQ("$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =", + frame3->windows_frame_info->program_string); + EXPECT_FALSE(frame3->windows_frame_info->allocates_base_pointer); + } +} + +// Runs IPAddressIsNotInKnownModule test with good symbols +TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) { + IPAddressIsNotInKnownModuleTestImpl(false /* has_corrupt_modules */); +} + +// Runs IPAddressIsNotInKnownModule test with corrupt symbols +TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule_CorruptSymbols) { + IPAddressIsNotInKnownModuleTestImpl(true /* has_corrupt_modules */); +} + +struct CFIFixture: public StackwalkerX86Fixture { + CFIFixture() { + // Provide a bunch of STACK CFI records; individual tests walk to the + // caller from every point in this series, expecting to find the same + // set of register values. + SetModuleSymbols(&module1, + // The youngest frame's function. + "FUNC 4000 1000 10 enchiridion\n" + // Initially, just a return address. + "STACK CFI INIT 4000 100 .cfa: $esp 4 + .ra: .cfa 4 - ^\n" + // Push %ebx. + "STACK CFI 4001 .cfa: $esp 8 + $ebx: .cfa 8 - ^\n" + // Move %esi into %ebx. Weird, but permitted. + "STACK CFI 4002 $esi: $ebx\n" + // Allocate frame space, and save %edi. + "STACK CFI 4003 .cfa: $esp 20 + $edi: .cfa 16 - ^\n" + // Put the return address in %edi. + "STACK CFI 4005 .ra: $edi\n" + // Save %ebp, and use it as a frame pointer. + "STACK CFI 4006 .cfa: $ebp 8 + $ebp: .cfa 12 - ^\n" + + // The calling function. + "FUNC 5000 1000 10 epictetus\n" + // Mark it as end of stack. + "STACK CFI INIT 5000 1000 .cfa: $esp .ra 0\n"); + + // Provide some distinctive values for the caller's registers. + expected.esp = 0x80000000; + expected.eip = 0x40005510; + expected.ebp = 0xc0d4aab9; + expected.ebx = 0x60f20ce6; + expected.esi = 0x53d1379d; + expected.edi = 0xafbae234; + + // By default, registers are unchanged. + raw_context = expected; + } + + // Walk the stack, using stack_section as the contents of the stack + // and raw_context as the current register values. (Set + // raw_context.esp to the stack's starting address.) Expect two + // stack frames; in the older frame, expect the callee-saves + // registers to have values matching those in 'expected'. + void CheckWalk() { + RegionFromSection(); + raw_context.esp = stack_section.start().Value(); + + StackFrameSymbolizer frame_symbolizer(&supplier, &resolver); + StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules, + &frame_symbolizer); + vector modules_without_symbols; + vector modules_with_corrupt_symbols; + ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols, + &modules_with_corrupt_symbols)); + ASSERT_EQ(0U, modules_without_symbols.size()); + ASSERT_EQ(0U, modules_with_corrupt_symbols.size()); + frames = call_stack.frames(); + ASSERT_EQ(2U, frames->size()); + + { // To avoid reusing locals by mistake + StackFrameX86 *frame0 = static_cast(frames->at(0)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust); + ASSERT_EQ(StackFrameX86::CONTEXT_VALID_ALL, frame0->context_validity); + EXPECT_EQ("enchiridion", frame0->function_name); + EXPECT_EQ(0x40004000U, frame0->function_base); + ASSERT_TRUE(frame0->windows_frame_info != NULL); + ASSERT_EQ(WindowsFrameInfo::VALID_PARAMETER_SIZE, + frame0->windows_frame_info->valid); + ASSERT_TRUE(frame0->cfi_frame_info != NULL); + } + + { // To avoid reusing locals by mistake + StackFrameX86 *frame1 = static_cast(frames->at(1)); + EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust); + ASSERT_EQ((StackFrameX86::CONTEXT_VALID_EIP | + StackFrameX86::CONTEXT_VALID_ESP | + StackFrameX86::CONTEXT_VALID_EBP | + StackFrameX86::CONTEXT_VALID_EBX | + StackFrameX86::CONTEXT_VALID_ESI | + StackFrameX86::CONTEXT_VALID_EDI), + frame1->context_validity); + EXPECT_EQ(expected.eip, frame1->context.eip); + EXPECT_EQ(expected.esp, frame1->context.esp); + EXPECT_EQ(expected.ebp, frame1->context.ebp); + EXPECT_EQ(expected.ebx, frame1->context.ebx); + EXPECT_EQ(expected.esi, frame1->context.esi); + EXPECT_EQ(expected.edi, frame1->context.edi); + EXPECT_EQ("epictetus", frame1->function_name); + } + } + + // The values the stack walker should find for the caller's registers. + MDRawContextX86 expected; +}; + +class CFI: public CFIFixture, public Test { }; + +TEST_F(CFI, At4000) { + Label frame1_esp = expected.esp; + stack_section + .D32(0x40005510) // return address + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004000; + CheckWalk(); +} + +TEST_F(CFI, At4001) { + Label frame1_esp = expected.esp; + stack_section + .D32(0x60f20ce6) // saved %ebx + .D32(0x40005510) // return address + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004001; + raw_context.ebx = 0x91aa9a8b; // callee's %ebx value + CheckWalk(); +} + +TEST_F(CFI, At4002) { + Label frame1_esp = expected.esp; + stack_section + .D32(0x60f20ce6) // saved %ebx + .D32(0x40005510) // return address + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004002; + raw_context.ebx = 0x53d1379d; // saved %esi + raw_context.esi = 0xa5c790ed; // callee's %esi value + CheckWalk(); +} + +TEST_F(CFI, At4003) { + Label frame1_esp = expected.esp; + stack_section + .D32(0x56ec3db7) // garbage + .D32(0xafbae234) // saved %edi + .D32(0x53d67131) // garbage + .D32(0x60f20ce6) // saved %ebx + .D32(0x40005510) // return address + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004003; + raw_context.ebx = 0x53d1379d; // saved %esi + raw_context.esi = 0xa97f229d; // callee's %esi + raw_context.edi = 0xb05cc997; // callee's %edi + CheckWalk(); +} + +// The results here should be the same as those at module offset +// 0x4003. +TEST_F(CFI, At4004) { + Label frame1_esp = expected.esp; + stack_section + .D32(0xe29782c2) // garbage + .D32(0xafbae234) // saved %edi + .D32(0x5ba29ce9) // garbage + .D32(0x60f20ce6) // saved %ebx + .D32(0x40005510) // return address + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004004; + raw_context.ebx = 0x53d1379d; // saved %esi + raw_context.esi = 0x0fb7dc4e; // callee's %esi + raw_context.edi = 0x993b4280; // callee's %edi + CheckWalk(); +} + +TEST_F(CFI, At4005) { + Label frame1_esp = expected.esp; + stack_section + .D32(0xe29782c2) // garbage + .D32(0xafbae234) // saved %edi + .D32(0x5ba29ce9) // garbage + .D32(0x60f20ce6) // saved %ebx + .D32(0x8036cc02) // garbage + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004005; + raw_context.ebx = 0x53d1379d; // saved %esi + raw_context.esi = 0x0fb7dc4e; // callee's %esi + raw_context.edi = 0x40005510; // return address + CheckWalk(); +} + +TEST_F(CFI, At4006) { + Label frame0_ebp; + Label frame1_esp = expected.esp; + stack_section + .D32(0xdcdd25cd) // garbage + .D32(0xafbae234) // saved %edi + .D32(0xc0d4aab9) // saved %ebp + .Mark(&frame0_ebp) // frame pointer points here + .D32(0x60f20ce6) // saved %ebx + .D32(0x8036cc02) // garbage + .Mark(&frame1_esp); // This effectively sets stack_section.start(). + raw_context.eip = 0x40004006; + raw_context.ebp = frame0_ebp.Value(); + raw_context.ebx = 0x53d1379d; // saved %esi + raw_context.esi = 0x743833c9; // callee's %esi + raw_context.edi = 0x40005510; // return address + CheckWalk(); +} + diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_address_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map-inl.h new file mode 100644 index 0000000000..67e07976e0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map-inl.h @@ -0,0 +1,71 @@ +// Copyright (c) 2010, 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. + +// static_address_map-inl.h: StaticAddressMap implementation. +// +// See static_address_map.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_ADDRESS_MAP_INL_H__ +#define PROCESSOR_STATIC_ADDRESS_MAP_INL_H__ + +#include "processor/static_address_map.h" + +#include "processor/logging.h" + +namespace google_breakpad { + +template +bool StaticAddressMap::Retrieve( + const AddressType &address, + const EntryType *&entry, AddressType *entry_address) const { + + // 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.GetValuePtr(); + // Make sure AddressType is a copyable basic type + if (entry_address) + *entry_address = iterator.GetKey(); + + return true; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_ADDRESS_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_address_map.h b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map.h new file mode 100644 index 0000000000..6bafc66750 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map.h @@ -0,0 +1,78 @@ +// Copyright (c) 2010, 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. + +// static_address_map.h: StaticAddressMap. +// +// StaticAddressMap is a wrapper class of StaticMap, just as AddressMap wraps +// std::map. StaticAddressMap provides read-only Retrieve() operation, similar +// as AddressMap. However, the difference between StaticAddressMap and +// AddressMap is that StaticAddressMap does not support dynamic operation +// Store() due to the static nature of the underlying StaticMap. +// +// See address_map.h for reference. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_ADDRESS_MAP_H__ +#define PROCESSOR_STATIC_ADDRESS_MAP_H__ + +#include "processor/static_map-inl.h" + +namespace google_breakpad { + +// AddressType MUST be a basic type, e.g.: integer types etc +// EntryType could be a complex type, so we retrieve its pointer instead. +template +class StaticAddressMap { + public: + StaticAddressMap(): map_() { } + explicit StaticAddressMap(const char *map_data): map_(map_data) { } + + // 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, + const EntryType *&entry, AddressType *entry_address) const; + + private: + friend class ModuleComparer; + // Convenience types. + typedef StaticAddressMap* SelfPtr; + typedef StaticMap AddressToEntryMap; + typedef typename AddressToEntryMap::const_iterator MapConstIterator; + + AddressToEntryMap map_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_ADDRESS_MAP_H__ + diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_address_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map_unittest.cc new file mode 100644 index 0000000000..12c735cff0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_address_map_unittest.cc @@ -0,0 +1,236 @@ +// Copyright (c) 2010, 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. + +// static_address_map_unittest.cc: Unit tests for StaticAddressMap. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include +#include +#include +#include +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "processor/address_map-inl.h" +#include "processor/static_address_map-inl.h" +#include "processor/simple_serializer-inl.h" +#include "map_serializers-inl.h" + +typedef google_breakpad::StaticAddressMap TestMap; +typedef google_breakpad::AddressMap AddrMap; + +class TestStaticAddressMap : public ::testing::Test { + protected: + void SetUp() { + for (int testcase = 0; testcase < kNumberTestCases; ++testcase) { + testdata[testcase] = new int[testsize[testcase]]; + } + + // Test data set0: NULL (empty map) + + // Test data set1: single element. + testdata[1][0] = 10; + + // Test data set2: six elements. + const int tempdata[] = {5, 10, 14, 15, 16, 20}; + for (int i = 0; i < testsize[2]; ++i) + testdata[2][i] = tempdata[i]; + + // Test data set3: + srand(time(NULL)); + for (int i = 0; i < testsize[3]; ++i) + testdata[3][i] = rand(); + + // Setup maps. + std::stringstream sstream; + for (int testcase = 0; testcase < kNumberTestCases; ++testcase) { + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + sstream.clear(); + sstream << "test " << testdata[testcase][data_item]; + addr_map[testcase].Store(testdata[testcase][data_item], sstream.str()); + } + map_data[testcase] = serializer.Serialize(addr_map[testcase], NULL); + test_map[testcase] = TestMap(map_data[testcase]); + } + } + + void TearDown() { + for (int i = 0; i < kNumberTestCases; ++i) { + delete [] map_data[i]; + delete [] testdata[i]; + } + } + + void CompareRetrieveResult(int testcase, int target) { + int address; + int address_test; + string entry; + string entry_test; + const char *entry_cstring = NULL; + bool found; + bool found_test; + + found = addr_map[testcase].Retrieve(target, &entry, &address); + found_test = + test_map[testcase].Retrieve(target, entry_cstring, &address_test); + + ASSERT_EQ(found, found_test); + + if (found && found_test) { + ASSERT_EQ(address, address_test); + entry_test = entry_cstring; + ASSERT_EQ(entry, entry_test); + } + } + + void RetrieveTester(int testcase) { + int target; + target = INT_MIN; + CompareRetrieveResult(testcase, target); + target = INT_MAX; + CompareRetrieveResult(testcase, target); + + srand(time(0)); + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + // Retrive (aka, search) for target address and compare results from + // AddressMap and StaticAddressMap. + + // First, assign the search target to be one of original testdata that is + // known to exist in the map. + target = testdata[testcase][data_item]; + CompareRetrieveResult(testcase, target); + // Then, add +2 / -1 bias to target value, in order to test searching for + // a target address not stored in the map. + target -= 1; + CompareRetrieveResult(testcase, target); + target += 3; + CompareRetrieveResult(testcase, target); + // Repeatedly test searching for random target addresses. + target = rand(); + CompareRetrieveResult(testcase, target); + } + } + + // Test data sets: + static const int kNumberTestCases = 4; + static const int testsize[]; + int *testdata[kNumberTestCases]; + + AddrMap addr_map[kNumberTestCases]; + TestMap test_map[kNumberTestCases]; + char *map_data[kNumberTestCases]; + google_breakpad::AddressMapSerializer serializer; +}; + +const int TestStaticAddressMap::testsize[] = {0, 1, 6, 1000}; + +TEST_F(TestStaticAddressMap, TestEmptyMap) { + int testcase = 0; + int target; + target = INT_MIN; + CompareRetrieveResult(testcase, target); + target = INT_MAX; + CompareRetrieveResult(testcase, target); + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + target = testdata[testcase][data_item]; + CompareRetrieveResult(testcase, target); + target -= 1; + CompareRetrieveResult(testcase, target); + target += 3; + CompareRetrieveResult(testcase, target); + target = rand(); + CompareRetrieveResult(testcase, target); + } +} + +TEST_F(TestStaticAddressMap, TestOneElementMap) { + int testcase = 1; + int target; + target = INT_MIN; + CompareRetrieveResult(testcase, target); + target = INT_MAX; + CompareRetrieveResult(testcase, target); + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + target = testdata[testcase][data_item]; + CompareRetrieveResult(testcase, target); + target -= 1; + CompareRetrieveResult(testcase, target); + target += 3; + CompareRetrieveResult(testcase, target); + target = rand(); + CompareRetrieveResult(testcase, target); + } +} + +TEST_F(TestStaticAddressMap, TestSixElementsMap) { + int testcase = 2; + int target; + target = INT_MIN; + CompareRetrieveResult(testcase, target); + target = INT_MAX; + CompareRetrieveResult(testcase, target); + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + target = testdata[testcase][data_item]; + CompareRetrieveResult(testcase, target); + target -= 1; + CompareRetrieveResult(testcase, target); + target += 3; + CompareRetrieveResult(testcase, target); + target = rand(); + CompareRetrieveResult(testcase, target); + } +} + +TEST_F(TestStaticAddressMap, Test1000RandomElementsMap) { + int testcase = 3; + int target; + target = INT_MIN; + CompareRetrieveResult(testcase, target); + target = INT_MAX; + CompareRetrieveResult(testcase, target); + for (int data_item = 0; data_item < testsize[testcase]; ++data_item) { + target = testdata[testcase][data_item]; + CompareRetrieveResult(testcase, target); + target -= 1; + CompareRetrieveResult(testcase, target); + target += 3; + CompareRetrieveResult(testcase, target); + target = rand(); + CompareRetrieveResult(testcase, target); + } +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map-inl.h new file mode 100644 index 0000000000..777c762184 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map-inl.h @@ -0,0 +1,92 @@ +// Copyright (c) 2010, 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. + +// static_contained_range_map-inl.h: Hierarchically-organized range map, +// i.e., StaticContainedRangeMap implementation. +// +// See static_contained_range_map.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_CONTAINED_RANGE_MAP_INL_H__ +#define PROCESSOR_STATIC_CONTAINED_RANGE_MAP_INL_H__ + +#include "processor/static_contained_range_map.h" +#include "processor/logging.h" + +namespace google_breakpad { + +template +StaticContainedRangeMap::StaticContainedRangeMap( + const char *base) + : base_(*(reinterpret_cast(base))), + entry_size_(*(reinterpret_cast(base + sizeof(base_)))), + entry_ptr_(reinterpret_cast( + base + sizeof(base_) + sizeof(entry_size_))), + map_(base + sizeof(base_) + sizeof(entry_size_) + entry_size_) { + if (entry_size_ == 0) + entry_ptr_ = NULL; +} + + +template +bool StaticContainedRangeMap::RetrieveRange( + const AddressType &address, const EntryType *&entry) const { + + // 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()) + return false; + + const char *memory_child = + reinterpret_cast(iterator.GetValuePtr()); + + StaticContainedRangeMap child_map(memory_child); + + if (address < child_map.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 (!child_map.RetrieveRange(address, entry)) + entry = child_map.entry_ptr_; + + return true; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_CONTAINED_RANGE_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map.h b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map.h new file mode 100644 index 0000000000..6a9b8b7b6d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map.h @@ -0,0 +1,96 @@ +// Copyright (c) 2010, 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. + +// static_contained_range_map.h: StaticContainedRangeMap. +// +// StaticContainedRangeMap is similar to ContainedRangeMap. However, +// StaticContainedRangeMap wraps a StaticMap instead of std::map, and does not +// support dynamic operations like StoreRange(...). +// StaticContainedRangeMap provides same RetrieveRange(...) interfaces as +// ContainedRangeMap. +// +// Please see contained_range_map.h for more documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__ +#define PROCESSOR_STATIC_CONTAINED_RANGE_MAP_H__ + +#include "processor/static_map-inl.h" + +namespace google_breakpad { + +template +class StaticContainedRangeMap { + public: + StaticContainedRangeMap(): base_(), entry_size_(), entry_ptr_(), map_() { } + explicit StaticContainedRangeMap(const char *base); + + // 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, const EntryType *&entry) const; + + private: + friend class ModuleComparer; + // AddressToRangeMap stores pointers. This makes reparenting simpler in + // StoreRange, because it doesn't need to copy entire objects. + typedef StaticContainedRangeMap* SelfPtr; + typedef + StaticMap AddressToRangeMap; + typedef typename AddressToRangeMap::const_iterator MapConstIterator; + + // 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|. + 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|. + uint32_t entry_size_; + const EntryType *entry_ptr_; + + // 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_STATIC_CONTAINED_RANGE_MAP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map_unittest.cc new file mode 100644 index 0000000000..4ee47578e2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_contained_range_map_unittest.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2010, 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. + +// static_contained_range_map_unittest.cc: Unit tests for +// StaticContainedRangeMap. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include "breakpad_googletest_includes.h" +#include "common/scoped_ptr.h" +#include "processor/contained_range_map-inl.h" +#include "processor/static_contained_range_map-inl.h" +#include "processor/simple_serializer-inl.h" +#include "processor/map_serializers-inl.h" +#include "processor/logging.h" + +namespace { + +typedef google_breakpad::ContainedRangeMap CRMMap; +typedef google_breakpad::StaticContainedRangeMap TestMap; + +// Each element in test_data contains the expected result when calling +// RetrieveRange on an address. +const int test_data[] = { + 0, // 0 + 0, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 9, // 8 + 7, // 9 + 1, // 10 + 5, // 11 + 6, // 12 + 6, // 13 + 6, // 14 + 6, // 15 + 6, // 16 + 6, // 17 + 6, // 18 + 5, // 19 + 7, // 20 + 8, // 21 + 0, // 22 + 0, // 23 + 0, // 24 + 0, // 25 + 0, // 26 + 0, // 27 + 0, // 28 + 0, // 29 + 10, // 30 + 10, // 31 + 10, // 32 + 11, // 33 + 11, // 34 + 11, // 35 + 0, // 36 + 0, // 37 + 0, // 38 + 0, // 39 + 14, // 40 + 14, // 41 + 14, // 42 + 14, // 43 + 15, // 44 + 15, // 45 + 15, // 46 + 15, // 47 + 0, // 48 + 0, // 49 + 19, // 50 + 18, // 51 + 18, // 52 + 18, // 53 + 18, // 54 + 18, // 55 + 18, // 56 + 18, // 57 + 18, // 58 + 20, // 59 + 21, // 60 + 25, // 61 + 26, // 62 + 26, // 63 + 26, // 64 + 26, // 65 + 26, // 66 + 26, // 67 + 24, // 68 + 22, // 69 + 30, // 70 + 30, // 71 + 30, // 72 + 30, // 73 + 31, // 74 + 31, // 75 + 30, // 76 + 32, // 77 + 32, // 78 + 30, // 79 + 34, // 80 + 35, // 81 + 36, // 82 + 39, // 83 + 38, // 84 + 37, // 85 + 43, // 86 + 44, // 87 + 41, // 88 + 45, // 89 + 42, // 90 + 0, // 91 + 0, // 92 + 0, // 93 + 0, // 94 + 0, // 95 + 0, // 96 + 0, // 97 + 0, // 98 + 0 // 99 +}; + +} // namespace + +namespace google_breakpad { + +class TestStaticCRMMap : public ::testing::Test { + protected: + void SetUp(); + + // A referrence map for testing StaticCRMMap. + google_breakpad::ContainedRangeMap crm_map_; + + // Static version of crm_map using serialized data of crm_map. + // The goal of testing is to make sure TestMap provides same results for + // lookup operation(s) as CRMMap does. + google_breakpad::StaticContainedRangeMap test_map_; + + google_breakpad::ContainedRangeMapSerializer serializer_; + + scoped_array serialized_data_; +}; + +void TestStaticCRMMap::SetUp() { + // First, do the StoreRange tests. This validates the containment + // rules. + // We confirm the referrence map correctly stores data during setup. + ASSERT_TRUE (crm_map_.StoreRange(10, 10, 1)); + ASSERT_FALSE(crm_map_.StoreRange(10, 10, 2)); // exactly equal to 1 + ASSERT_FALSE(crm_map_.StoreRange(11, 10, 3)); // begins inside 1 and extends up + ASSERT_FALSE(crm_map_.StoreRange( 9, 10, 4)); // begins below 1 and ends inside + ASSERT_TRUE (crm_map_.StoreRange(11, 9, 5)); // contained by existing + ASSERT_TRUE (crm_map_.StoreRange(12, 7, 6)); + ASSERT_TRUE (crm_map_.StoreRange( 9, 12, 7)); // contains existing + ASSERT_TRUE (crm_map_.StoreRange( 9, 13, 8)); + ASSERT_TRUE (crm_map_.StoreRange( 8, 14, 9)); + ASSERT_TRUE (crm_map_.StoreRange(30, 3, 10)); + ASSERT_TRUE (crm_map_.StoreRange(33, 3, 11)); + ASSERT_TRUE (crm_map_.StoreRange(30, 6, 12)); // storable but totally masked + ASSERT_TRUE (crm_map_.StoreRange(40, 8, 13)); // will be totally masked + ASSERT_TRUE (crm_map_.StoreRange(40, 4, 14)); + ASSERT_TRUE (crm_map_.StoreRange(44, 4, 15)); + ASSERT_FALSE(crm_map_.StoreRange(32, 10, 16)); // begins in #10, ends in #14 + ASSERT_FALSE(crm_map_.StoreRange(50, 0, 17)); // zero length + ASSERT_TRUE (crm_map_.StoreRange(50, 10, 18)); + ASSERT_TRUE (crm_map_.StoreRange(50, 1, 19)); + ASSERT_TRUE (crm_map_.StoreRange(59, 1, 20)); + ASSERT_TRUE (crm_map_.StoreRange(60, 1, 21)); + ASSERT_TRUE (crm_map_.StoreRange(69, 1, 22)); + ASSERT_TRUE (crm_map_.StoreRange(60, 10, 23)); + ASSERT_TRUE (crm_map_.StoreRange(68, 1, 24)); + ASSERT_TRUE (crm_map_.StoreRange(61, 1, 25)); + ASSERT_TRUE (crm_map_.StoreRange(61, 8, 26)); + ASSERT_FALSE(crm_map_.StoreRange(59, 9, 27)); + ASSERT_FALSE(crm_map_.StoreRange(59, 10, 28)); + ASSERT_FALSE(crm_map_.StoreRange(59, 11, 29)); + ASSERT_TRUE (crm_map_.StoreRange(70, 10, 30)); + ASSERT_TRUE (crm_map_.StoreRange(74, 2, 31)); + ASSERT_TRUE (crm_map_.StoreRange(77, 2, 32)); + ASSERT_FALSE(crm_map_.StoreRange(72, 6, 33)); + ASSERT_TRUE (crm_map_.StoreRange(80, 3, 34)); + ASSERT_TRUE (crm_map_.StoreRange(81, 1, 35)); + ASSERT_TRUE (crm_map_.StoreRange(82, 1, 36)); + ASSERT_TRUE (crm_map_.StoreRange(83, 3, 37)); + ASSERT_TRUE (crm_map_.StoreRange(84, 1, 38)); + ASSERT_TRUE (crm_map_.StoreRange(83, 1, 39)); + ASSERT_TRUE (crm_map_.StoreRange(86, 5, 40)); + ASSERT_TRUE (crm_map_.StoreRange(88, 1, 41)); + ASSERT_TRUE (crm_map_.StoreRange(90, 1, 42)); + ASSERT_TRUE (crm_map_.StoreRange(86, 1, 43)); + ASSERT_TRUE (crm_map_.StoreRange(87, 1, 44)); + ASSERT_TRUE (crm_map_.StoreRange(89, 1, 45)); + ASSERT_TRUE (crm_map_.StoreRange(87, 4, 46)); + ASSERT_TRUE (crm_map_.StoreRange(87, 3, 47)); + ASSERT_FALSE(crm_map_.StoreRange(86, 2, 48)); + + // Serialize crm_map to generate serialized data. + unsigned int size; + serialized_data_.reset(serializer_.Serialize(&crm_map_, &size)); + BPLOG(INFO) << "Serialized data size: " << size << " Bytes."; + + // Construct test_map_ from serialized data. + test_map_ = TestMap(serialized_data_.get()); +} + +TEST_F(TestStaticCRMMap, TestEmptyMap) { + CRMMap empty_crm_map; + + unsigned int size; + scoped_array serialized_data; + serialized_data.reset(serializer_.Serialize(&empty_crm_map, &size)); + scoped_ptr test_map(new TestMap(serialized_data.get())); + + const unsigned int kCorrectSizeForEmptyMap = 16; + ASSERT_EQ(kCorrectSizeForEmptyMap, size); + + const int *entry_test; + ASSERT_FALSE(test_map->RetrieveRange(-1, entry_test)); + ASSERT_FALSE(test_map->RetrieveRange(0, entry_test)); + ASSERT_FALSE(test_map->RetrieveRange(10, entry_test)); +} + +TEST_F(TestStaticCRMMap, TestSingleElementMap) { + CRMMap crm_map; + // Test on one element: + int entry = 1; + crm_map.StoreRange(10, 10, entry); + + unsigned int size; + scoped_array serialized_data; + serialized_data.reset(serializer_.Serialize(&crm_map, &size)); + scoped_ptr test_map(new TestMap(serialized_data.get())); + + const unsigned int kCorrectSizeForSingleElementMap = 40; + ASSERT_EQ(kCorrectSizeForSingleElementMap, size); + + const int *entry_test; + ASSERT_FALSE(test_map->RetrieveRange(-1, entry_test)); + ASSERT_FALSE(test_map->RetrieveRange(0, entry_test)); + ASSERT_TRUE(test_map->RetrieveRange(10, entry_test)); + ASSERT_EQ(*entry_test, entry); + ASSERT_TRUE(test_map->RetrieveRange(13, entry_test)); + ASSERT_EQ(*entry_test, entry); +} + +TEST_F(TestStaticCRMMap, RunTestData) { + unsigned int test_high = sizeof(test_data) / sizeof(test_data[0]); + + // Now, do the RetrieveRange tests. This further validates that the + // objects were stored properly and that retrieval returns the correct + // object. + // If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a + // new test_data array will be printed. Exercise caution when doing this. + // Be sure to verify the results manually! +#ifdef GENERATE_TEST_DATA + printf(" const int test_data[] = {\n"); +#endif // GENERATE_TEST_DATA + + for (unsigned int address = 0; address < test_high; ++address) { + const int *entryptr; + int value = 0; + if (test_map_.RetrieveRange(address, entryptr)) + value = *entryptr; + +#ifndef GENERATE_TEST_DATA + // Don't use ASSERT inside the loop because it won't show the failed + // |address|, and the line number will always be the same. That makes + // it difficult to figure out which test failed. + EXPECT_EQ(value, test_data[address]) << "FAIL: retrieve address " + << address; +#else // !GENERATE_TEST_DATA + printf(" %d%c%s // %d\n", value, + address == test_high - 1 ? ' ' : ',', + value < 10 ? " " : "", + address); +#endif // !GENERATE_TEST_DATA + } + +#ifdef GENERATE_TEST_DATA + printf(" };\n"); +#endif // GENERATE_TEST_DATA +} + +} // namespace google_breakpad + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/static_map-inl.h new file mode 100644 index 0000000000..e6aac6aba4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_map-inl.h @@ -0,0 +1,176 @@ +// Copyright 2010 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. + +// static_map-inl.h: StaticMap implementation. +// +// See static_map.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + + +#ifndef PROCESSOR_STATIC_MAP_INL_H__ +#define PROCESSOR_STATIC_MAP_INL_H__ + +#include "processor/static_map.h" +#include "processor/static_map_iterator-inl.h" +#include "processor/logging.h" + +namespace google_breakpad { + +template +StaticMap::StaticMap(const char* raw_data) + : raw_data_(raw_data), + compare_() { + // First 4 Bytes store the number of nodes. + num_nodes_ = *(reinterpret_cast(raw_data_)); + + offsets_ = reinterpret_cast( + raw_data_ + sizeof(num_nodes_)); + + keys_ = reinterpret_cast( + raw_data_ + (1 + num_nodes_) * sizeof(uint32_t)); +} + +// find(), lower_bound() and upper_bound() implement binary search algorithm. +template +StaticMapIterator +StaticMap::find(const Key &key) const { + int begin = 0; + int end = num_nodes_; + int middle; + int compare_result; + while (begin < end) { + middle = begin + (end - begin) / 2; + compare_result = compare_(key, GetKeyAtIndex(middle)); + if (compare_result == 0) + return IteratorAtIndex(middle); + if (compare_result < 0) { + end = middle; + } else { + begin = middle + 1; + } + } + return this->end(); +} + +template +StaticMapIterator +StaticMap::lower_bound(const Key &key) const { + int begin = 0; + int end = num_nodes_; + int middle; + int comp_result; + while (begin < end) { + middle = begin + (end - begin) / 2; + comp_result = compare_(key, GetKeyAtIndex(middle)); + if (comp_result == 0) + return IteratorAtIndex(middle); + if (comp_result < 0) { + end = middle; + } else { + begin = middle + 1; + } + } + return IteratorAtIndex(begin); +} + +template +StaticMapIterator +StaticMap::upper_bound(const Key &key) const { + int begin = 0; + int end = num_nodes_; + int middle; + int compare_result; + while (begin < end) { + middle = begin + (end - begin) / 2; + compare_result = compare_(key, GetKeyAtIndex(middle)); + if (compare_result == 0) + return IteratorAtIndex(middle + 1); + if (compare_result < 0) { + end = middle; + } else { + begin = middle + 1; + } + } + return IteratorAtIndex(begin); +} + +template +bool StaticMap::ValidateInMemoryStructure() const { + // check the number of nodes is non-negative: + if (!raw_data_) return false; + int32_t num_nodes = *(reinterpret_cast(raw_data_)); + if (num_nodes < 0) { + BPLOG(INFO) << "StaticMap check failed: negative number of nodes"; + return false; + } + + int node_index = 0; + if (num_nodes_) { + uint64_t first_offset = sizeof(int32_t) * (num_nodes_ + 1) + + sizeof(Key) * num_nodes_; + // Num_nodes_ is too large. + if (first_offset > 0xffffffffUL) { + BPLOG(INFO) << "StaticMap check failed: size exceeds limit"; + return false; + } + if (offsets_[node_index] != static_cast(first_offset)) { + BPLOG(INFO) << "StaticMap check failed: first node offset is incorrect"; + return false; + } + } + + for (node_index = 1; node_index < num_nodes_; ++node_index) { + // Check offsets[i] is strictly increasing: + if (offsets_[node_index] <= offsets_[node_index - 1]) { + BPLOG(INFO) << "StaticMap check failed: node offsets non-increasing"; + return false; + } + // Check Key[i] is strictly increasing as no duplicate keys are allowed. + if (compare_(GetKeyAtIndex(node_index), + GetKeyAtIndex(node_index - 1)) <= 0) { + BPLOG(INFO) << "StaticMap check failed: node keys non-increasing"; + return false; + } + } + return true; +} + +template +const Key StaticMap::GetKeyAtIndex(int index) const { + if (index < 0 || index >= num_nodes_) { + BPLOG(ERROR) << "Key index out of range error"; + // Key type is required to be primitive type. Return 0 if index is invalid. + return 0; + } + return keys_[index]; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_map.h b/toolkit/crashreporter/google-breakpad/src/processor/static_map.h new file mode 100644 index 0000000000..9723ab2a84 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_map.h @@ -0,0 +1,144 @@ +// Copyright 2010 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. + +// static_map.h: StaticMap. +// +// StaticMap provides lookup interfaces and iterators similar as stl::map's. +// These lookup operations are purely Read-Only, thus memory +// allocation & deallocation is mostly avoided (intentionally). +// +// The chunk of memory should contain data with pre-defined pattern: +// **************** header *************** +// uint32 (4 bytes): number of nodes +// uint32 (4 bytes): address offset of node1's mapped_value +// uint32 (4 bytes): address offset of node2's mapped_value +// ... +// uint32 (4 bytes): address offset of nodeN's mapped_value +// +// ************* Key array ************ +// (X bytes): node1's key +// (X bytes): node2's key +// ... +// (X bytes): nodeN's key +// +// ************* Value array ********** +// (? bytes): node1's mapped_value +// (? bytes): node2's mapped_value +// ... +// (? bytes): nodeN's mapped_value +// +// REQUIREMENT: Key type MUST be primitive type or pointers so that: +// X = sizeof(typename Key); +// +// Note: since address offset is stored as uint32, user should keep in mind that +// StaticMap only supports up to 4GB size of memory data. + +// Author: Siyang Xie (lambxsy@google.com) + + +#ifndef PROCESSOR_STATIC_MAP_H__ +#define PROCESSOR_STATIC_MAP_H__ + +#include "processor/static_map_iterator-inl.h" + +namespace google_breakpad { + +// Default functor to compare keys. +template +class DefaultCompare { + public: + int operator()(const Key &k1, const Key &k2) const { + if (k1 < k2) return -1; + if (k1 == k2) return 0; + return 1; + } +}; + +template > +class StaticMap { + public: + typedef StaticMapIterator iterator; + typedef StaticMapIterator const_iterator; + + StaticMap() : raw_data_(0), + num_nodes_(0), + offsets_(0), + compare_() { } + + explicit StaticMap(const char* raw_data); + + inline bool empty() const { return num_nodes_ == 0; } + inline unsigned int size() const { return num_nodes_; } + + // Return iterators. + inline iterator begin() const { return IteratorAtIndex(0); } + inline iterator last() const { return IteratorAtIndex(num_nodes_ - 1); } + inline iterator end() const { return IteratorAtIndex(num_nodes_); } + inline iterator IteratorAtIndex(int index) const { + return iterator(raw_data_, index); + } + + // Lookup operations. + iterator find(const Key &k) const; + + // lower_bound(k) searches in a sorted range for the first element that has a + // key not less than the argument k. + iterator lower_bound(const Key &k) const; + + // upper_bound(k) searches in a sorted range for the first element that has a + // key greater than the argument k. + iterator upper_bound(const Key &k) const; + + // Checks if the underlying memory data conforms to the predefined pattern: + // first check the number of nodes is non-negative, + // then check both offsets and keys are strictly increasing (sorted). + bool ValidateInMemoryStructure() const; + + private: + const Key GetKeyAtIndex(int i) const; + + // Start address of a raw memory chunk with serialized data. + const char* raw_data_; + + // Number of nodes in the static map. + int32_t num_nodes_; + + // Array of offset addresses for stored values. + // For example: + // address_of_i-th_node_value = raw_data_ + offsets_[i] + const uint32_t* offsets_; + + // keys_[i] = key of i_th node + const Key* keys_; + + Compare compare_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_MAP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator-inl.h new file mode 100644 index 0000000000..7a7db5ad93 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator-inl.h @@ -0,0 +1,147 @@ +// Copyright 2010 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. + +// static_map_iterator-inl.h: StaticMapIterator implementation. +// +// See static_map_iterator.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_MAP_ITERATOR_INL_H__ +#define PROCESSOR_STATIC_MAP_ITERATOR_INL_H__ + +#include "processor/static_map_iterator.h" + +#include "processor/logging.h" + +namespace google_breakpad { + +template +StaticMapIterator::StaticMapIterator(const char* base, + const int &index): + index_(index), base_(base) { + // See static_map.h for documentation on + // bytes format of serialized StaticMap data. + num_nodes_ = *(reinterpret_cast(base_)); + offsets_ = reinterpret_cast(base_ + sizeof(num_nodes_)); + keys_ = reinterpret_cast( + base_ + (1 + num_nodes_) * sizeof(num_nodes_)); +} + +// Increment & Decrement operators: +template +StaticMapIterator& +StaticMapIterator::operator++() { + if (!IsValid()) { + BPLOG(ERROR) << "operator++ on invalid iterator"; + return *this; + } + if (++index_ > num_nodes_) index_ = num_nodes_; + return *this; +} + +template +StaticMapIterator +StaticMapIterator::operator++(int postfix_operator) { + if (!IsValid()) { + BPLOG(ERROR) << "operator++ on invalid iterator"; + return *this; + } + StaticMapIterator tmp = *this; + if (++index_ > num_nodes_) index_ = num_nodes_; + return tmp; +} + +template +StaticMapIterator& +StaticMapIterator::operator--() { + if (!IsValid()) { + BPLOG(ERROR) << "operator++ on invalid iterator"; + return *this; + } + + if (--index_ < 0) index_ = 0; + return *this; +} + +template +StaticMapIterator +StaticMapIterator::operator--(int postfix_operator) { + if (!IsValid()) { + BPLOG(ERROR) << "operator++ on invalid iterator"; + return *this; + } + StaticMapIterator tmp = *this; + + if (--index_ < 0) index_ = 0; + return tmp; +} + +template +const Key* StaticMapIterator::GetKeyPtr() const { + if (!IsValid()) { + BPLOG(ERROR) << "call GetKeyPtr() on invalid iterator"; + return NULL; + } + return &(keys_[index_]); +} + +template +const char* StaticMapIterator::GetValueRawPtr() const { + if (!IsValid()) { + BPLOG(ERROR) << "call GetValuePtr() on invalid iterator"; + return NULL; + } + return base_ + offsets_[index_]; +} + +template +bool StaticMapIterator::operator==( + const StaticMapIterator& x) const { + return base_ == x.base_ && index_ == x.index_; +} + +template +bool StaticMapIterator::operator!=( + const StaticMapIterator& x) const { + // Only need to compare base_ and index_. + // Other data members are auxiliary. + return base_ != x.base_ || index_ != x.index_; +} + +template +bool StaticMapIterator::IsValid() const { + if (!base_ || index_ < 0 || index_ > num_nodes_) + return false; + + return true; +} + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_MAP_ITERATOR_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator.h b/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator.h new file mode 100644 index 0000000000..1af8fff454 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_map_iterator.h @@ -0,0 +1,112 @@ +// Copyright 2010 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. + +// static_map_iterator.h: StaticMapIterator template class declaration. +// +// StaticMapIterator provides increment and decrement operators to iterate +// through a StaticMap map. It does not provide *, -> operators, user should +// use GetKeyPtr(), GetKey(), GetValuePtr() interfaces to retrieve data or +// pointer to data. StaticMapIterator is essentially a const_iterator. +// +// Author: Siyang Xie (lambxsy@google.com) + + +#ifndef PROCESSOR_STATIC_MAP_ITERATOR_H__ +#define PROCESSOR_STATIC_MAP_ITERATOR_H__ + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// Forward declaration. +template class StaticMap; + +// StaticMapIterator does not support operator*() or operator->(), +// User should use GetKey(), GetKeyPtr(), GetValuePtr() instead; +template +class StaticMapIterator { + public: + // Constructors. + StaticMapIterator(): index_(-1), base_(NULL) { } + + // Increment & Decrement operators: + StaticMapIterator& operator++(); + StaticMapIterator operator++(int post_fix_operator); + + StaticMapIterator& operator--(); + StaticMapIterator operator--(int post_fix_operator); + + // Interface for retrieving data / pointer to data. + const Key* GetKeyPtr() const; + + // Run time error will occur if GetKey() is called on an invalid iterator. + inline const Key GetKey() const { return *GetKeyPtr(); } + + // return a raw memory pointer that points to the start address of value. + const char* GetValueRawPtr() const; + + // return a reinterpret-casted pointer to the value. + inline const Value* GetValuePtr() const { + return reinterpret_cast(GetValueRawPtr()); + } + + bool operator==(const StaticMapIterator& x) const; + bool operator!=(const StaticMapIterator& x) const; + + // Check if this iterator is valid. + // If iterator is invalid, user is forbidden to use ++/-- operator + // or interfaces for retrieving data / pointer to data. + bool IsValid() const; + + private: + friend class StaticMap; + + // Only StaticMap can call this constructor. + explicit StaticMapIterator(const char* base, const int32_t &index); + + // Index of node that the iterator is pointing to. + int32_t index_; + + // Beginning address of the serialized map data. + const char* base_; + + // Number of nodes in the map. Use it to identify end() iterator. + int32_t num_nodes_; + + // offsets_ is an array of offset addresses of mapped values. + // For example: + // address_of_i-th_node_value = base_ + offsets_[i] + const uint32_t* offsets_; + + // keys_[i] = key of i_th node. + const Key* keys_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_MAP_ITERATOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/static_map_unittest.cc new file mode 100644 index 0000000000..393d43d5c5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_map_unittest.cc @@ -0,0 +1,386 @@ +// Copyright (c) 2010 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. + +// static_map_unittest.cc: Unit tests for StaticMap. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "processor/static_map-inl.h" + + +typedef int ValueType; +typedef int KeyType; +typedef google_breakpad::StaticMap< KeyType, ValueType > TestMap; +typedef std::map< KeyType, ValueType > StdMap; + +template +class SimpleMapSerializer { + public: + static char* Serialize(const std::map &stdmap, + unsigned int* size = NULL) { + unsigned int size_per_node = + sizeof(uint32_t) + sizeof(Key) + sizeof(Value); + unsigned int memsize = sizeof(int32_t) + size_per_node * stdmap.size(); + if (size) *size = memsize; + + // Allocate memory for serialized data: + char* mem = reinterpret_cast(operator new(memsize)); + char* address = mem; + + // Writer the number of nodes: + new (address) uint32_t(static_cast(stdmap.size())); + address += sizeof(uint32_t); + + // Nodes' offset: + uint32_t* offsets = reinterpret_cast(address); + address += sizeof(uint32_t) * stdmap.size(); + + // Keys: + Key* keys = reinterpret_cast(address); + address += sizeof(Key) * stdmap.size(); + + // Traversing map: + typename std::map::const_iterator iter = stdmap.begin(); + for (int index = 0; iter != stdmap.end(); ++iter, ++index) { + offsets[index] = static_cast(address - mem); + keys[index] = iter->first; + new (address) Value(iter->second); + address += sizeof(Value); + } + return mem; + } +}; + + +class TestInvalidMap : public ::testing::Test { + protected: + void SetUp() { + memset(data, 0, kMemorySize); + } + + // 40 Bytes memory can hold a StaticMap with up to 3 nodes. + static const int kMemorySize = 40; + char data[kMemorySize]; + TestMap test_map; +}; + +TEST_F(TestInvalidMap, TestNegativeNumberNodes) { + memset(data, 0xff, sizeof(uint32_t)); // Set the number of nodes = -1 + test_map = TestMap(data); + ASSERT_FALSE(test_map.ValidateInMemoryStructure()); +} + +TEST_F(TestInvalidMap, TestWrongOffsets) { + uint32_t* header = reinterpret_cast(data); + const uint32_t kNumNodes = 2; + const uint32_t kHeaderOffset = + sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType)); + + header[0] = kNumNodes; + header[1] = kHeaderOffset + 3; // Wrong offset for first node + test_map = TestMap(data); + ASSERT_FALSE(test_map.ValidateInMemoryStructure()); + + header[1] = kHeaderOffset; // Correct offset for first node + header[2] = kHeaderOffset - 1; // Wrong offset for second node + test_map = TestMap(data); + ASSERT_FALSE(test_map.ValidateInMemoryStructure()); +} + +TEST_F(TestInvalidMap, TestUnSortedKeys) { + uint32_t* header = reinterpret_cast(data); + const uint32_t kNumNodes = 2; + const uint32_t kHeaderOffset = + sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType)); + header[0] = kNumNodes; + header[1] = kHeaderOffset; + header[2] = kHeaderOffset + sizeof(ValueType); + + KeyType* keys = reinterpret_cast( + data + (kNumNodes + 1) * sizeof(uint32_t)); + // Set keys in non-increasing order. + keys[0] = 10; + keys[1] = 7; + test_map = TestMap(data); + ASSERT_FALSE(test_map.ValidateInMemoryStructure()); +} + + +class TestValidMap : public ::testing::Test { + protected: + void SetUp() { + int testcase = 0; + + // Empty map. + map_data[testcase] = + serializer.Serialize(std_map[testcase], &size[testcase]); + test_map[testcase] = TestMap(map_data[testcase]); + ++testcase; + + // Single element. + std_map[testcase].insert(std::make_pair(2, 8)); + map_data[testcase] = + serializer.Serialize(std_map[testcase], &size[testcase]); + test_map[testcase] = TestMap(map_data[testcase]); + ++testcase; + + // 100 elements. + for (int i = 0; i < 100; ++i) + std_map[testcase].insert(std::make_pair(i, 2 * i)); + map_data[testcase] = + serializer.Serialize(std_map[testcase], &size[testcase]); + test_map[testcase] = TestMap(map_data[testcase]); + ++testcase; + + // 1000 random elements. + for (int i = 0; i < 1000; ++i) + std_map[testcase].insert(std::make_pair(rand(), rand())); + map_data[testcase] = + serializer.Serialize(std_map[testcase], &size[testcase]); + test_map[testcase] = TestMap(map_data[testcase]); + + // Set correct size of memory allocation for each test case. + unsigned int size_per_node = + sizeof(uint32_t) + sizeof(KeyType) + sizeof(ValueType); + for (testcase = 0; testcase < kNumberTestCases; ++testcase) { + correct_size[testcase] = + sizeof(uint32_t) + std_map[testcase].size() * size_per_node; + } + } + + void TearDown() { + for (int i = 0;i < kNumberTestCases; ++i) + ::operator delete(map_data[i]); + } + + + void IteratorTester(int test_case) { + // scan through: + iter_test = test_map[test_case].begin(); + iter_std = std_map[test_case].begin(); + + for (; iter_test != test_map[test_case].end() && + iter_std != std_map[test_case].end(); + ++iter_test, ++iter_std) { + ASSERT_EQ(iter_test.GetKey(), iter_std->first); + ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second); + } + ASSERT_TRUE(iter_test == test_map[test_case].end() + && iter_std == std_map[test_case].end()); + + // Boundary testcase. + if (!std_map[test_case].empty()) { + // rear boundary case: + iter_test = test_map[test_case].end(); + iter_std = std_map[test_case].end(); + --iter_std; + --iter_test; + ASSERT_EQ(iter_test.GetKey(), iter_std->first); + ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second); + + ++iter_test; + ++iter_std; + ASSERT_TRUE(iter_test == test_map[test_case].end()); + + --iter_test; + --iter_std; + ASSERT_TRUE(iter_test != test_map[test_case].end()); + ASSERT_TRUE(iter_test == test_map[test_case].last()); + ASSERT_EQ(iter_test.GetKey(), iter_std->first); + ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second); + + // front boundary case: + iter_test = test_map[test_case].begin(); + --iter_test; + ASSERT_TRUE(iter_test == test_map[test_case].begin()); + } + } + + void CompareLookupResult(int test_case) { + bool found1 = (iter_test != test_map[test_case].end()); + bool found2 = (iter_std != std_map[test_case].end()); + ASSERT_EQ(found1, found2); + + if (found1 && found2) { + ASSERT_EQ(iter_test.GetKey(), iter_std->first); + ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second); + } + } + + void FindTester(int test_case, const KeyType &key) { + iter_test = test_map[test_case].find(key); + iter_std = std_map[test_case].find(key); + CompareLookupResult(test_case); + } + + void LowerBoundTester(int test_case, const KeyType &key) { + iter_test = test_map[test_case].lower_bound(key); + iter_std = std_map[test_case].lower_bound(key); + CompareLookupResult(test_case); + } + + void UpperBoundTester(int test_case, const KeyType &key) { + iter_test = test_map[test_case].upper_bound(key); + iter_std = std_map[test_case].upper_bound(key); + CompareLookupResult(test_case); + } + + void LookupTester(int test_case) { + StdMap::const_iterator iter; + // Test find(): + for (iter = std_map[test_case].begin(); + iter != std_map[test_case].end(); + ++iter) { + FindTester(test_case, iter->first); + FindTester(test_case, iter->first + 1); + FindTester(test_case, iter->first - 1); + } + FindTester(test_case, INT_MIN); + FindTester(test_case, INT_MAX); + // random test: + for (int i = 0; i < rand()%5000 + 5000; ++i) + FindTester(test_case, rand()); + + // Test lower_bound(): + for (iter = std_map[test_case].begin(); + iter != std_map[test_case].end(); + ++iter) { + LowerBoundTester(test_case, iter->first); + LowerBoundTester(test_case, iter->first + 1); + LowerBoundTester(test_case, iter->first - 1); + } + LowerBoundTester(test_case, INT_MIN); + LowerBoundTester(test_case, INT_MAX); + // random test: + for (int i = 0; i < rand()%5000 + 5000; ++i) + LowerBoundTester(test_case, rand()); + + // Test upper_bound(): + for (iter = std_map[test_case].begin(); + iter != std_map[test_case].end(); + ++iter) { + UpperBoundTester(test_case, iter->first); + UpperBoundTester(test_case, iter->first + 1); + UpperBoundTester(test_case, iter->first - 1); + } + UpperBoundTester(test_case, INT_MIN); + UpperBoundTester(test_case, INT_MAX); + // random test: + for (int i = 0; i < rand()%5000 + 5000; ++i) + UpperBoundTester(test_case, rand()); + } + + static const int kNumberTestCases = 4; + StdMap std_map[kNumberTestCases]; + TestMap test_map[kNumberTestCases]; + TestMap::const_iterator iter_test; + StdMap::const_iterator iter_std; + char* map_data[kNumberTestCases]; + unsigned int size[kNumberTestCases]; + unsigned int correct_size[kNumberTestCases]; + SimpleMapSerializer serializer; +}; + +TEST_F(TestValidMap, TestEmptyMap) { + int test_case = 0; + // Assert memory size allocated during serialization is correct. + ASSERT_EQ(correct_size[test_case], size[test_case]); + + // Sanity check of serialized data: + ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure()); + ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty()); + ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size()); + + // Test Iterator. + IteratorTester(test_case); + + // Test lookup operations. + LookupTester(test_case); +} + +TEST_F(TestValidMap, TestSingleElement) { + int test_case = 1; + // Assert memory size allocated during serialization is correct. + ASSERT_EQ(correct_size[test_case], size[test_case]); + + // Sanity check of serialized data: + ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure()); + ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty()); + ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size()); + + // Test Iterator. + IteratorTester(test_case); + + // Test lookup operations. + LookupTester(test_case); +} + +TEST_F(TestValidMap, Test100Elements) { + int test_case = 2; + // Assert memory size allocated during serialization is correct. + ASSERT_EQ(correct_size[test_case], size[test_case]); + + // Sanity check of serialized data: + ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure()); + ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty()); + ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size()); + + // Test Iterator. + IteratorTester(test_case); + + // Test lookup operations. + LookupTester(test_case); +} + +TEST_F(TestValidMap, Test1000RandomElements) { + int test_case = 3; + // Assert memory size allocated during serialization is correct. + ASSERT_EQ(correct_size[test_case], size[test_case]); + + // Sanity check of serialized data: + ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure()); + ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty()); + ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size()); + + // Test Iterator. + IteratorTester(test_case); + + // Test lookup operations. + LookupTester(test_case); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_range_map-inl.h b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map-inl.h new file mode 100644 index 0000000000..f6cef1a9ee --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map-inl.h @@ -0,0 +1,130 @@ +// Copyright (c) 2010 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. + +// static_range_map-inl.h: StaticRangeMap implementation. +// +// See static_range_map.h for documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_RANGE_MAP_INL_H__ +#define PROCESSOR_STATIC_RANGE_MAP_INL_H__ + +#include "processor/static_range_map.h" +#include "processor/logging.h" + +namespace google_breakpad { + +template +bool StaticRangeMap::RetrieveRange( + const AddressType &address, const EntryType *&entry, + AddressType *entry_base, AddressType *entry_size) const { + 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. + + const Range *range = iterator.GetValuePtr(); + + // Make sure AddressType and EntryType are copyable basic types + // e.g.: integer types, pointers etc + if (address < range->base()) + return false; + + entry = range->entryptr(); + if (entry_base) + *entry_base = range->base(); + if (entry_size) + *entry_size = iterator.GetKey() - range->base() + 1; + + return true; +} + + +template +bool StaticRangeMap::RetrieveNearestRange( + const AddressType &address, const EntryType *&entry, + AddressType *entry_base, AddressType *entry_size) const { + // 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; + + const Range *range = iterator.GetValuePtr(); + entry = range->entryptr(); + if (entry_base) + *entry_base = range->base(); + if (entry_size) + *entry_size = iterator.GetKey() - range->base() + 1; + + return true; +} + +template +bool StaticRangeMap::RetrieveRangeAtIndex( + int index, const EntryType *&entry, + AddressType *entry_base, AddressType *entry_size) const { + + if (index >= GetCount()) { + BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount(); + return false; + } + + MapConstIterator iterator = map_.IteratorAtIndex(index); + + const Range *range = iterator.GetValuePtr(); + + entry = range->entryptr(); + if (entry_base) + *entry_base = range->base(); + if (entry_size) + *entry_size = iterator.GetKey() - range->base() + 1; + + return true; +} + +} // namespace google_breakpad + + +#endif // PROCESSOR_STATIC_RANGE_MAP_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_range_map.h b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map.h new file mode 100644 index 0000000000..91aabb0324 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map.h @@ -0,0 +1,106 @@ +// Copyright (c) 2010, 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. +// +// static_range_map.h: StaticRangeMap. +// +// StaticRangeMap is similar as RangeMap. However, StaticRangeMap wraps a +// StaticMap instead of std::map, and does not support dynamic operations like +// StoreRange(...). StaticRangeMap provides same Retrieve*() interfaces as +// RangeMap. Please see range_map.h for more documentation. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef PROCESSOR_STATIC_RANGE_MAP_H__ +#define PROCESSOR_STATIC_RANGE_MAP_H__ + + +#include "processor/static_map-inl.h" + +namespace google_breakpad { + +// AddressType is basic type, e.g.: integer types, pointers etc +// EntryType could be a complex type, so we retrieve its pointer instead. +template +class StaticRangeMap { + public: + StaticRangeMap(): map_() { } + explicit StaticRangeMap(const char *memory): map_(memory) { } + + // 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, const 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, const 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, const EntryType *&entry, + AddressType *entry_base, AddressType *entry_size) + const; + + // Returns the number of ranges stored in the RangeMap. + inline int GetCount() const { return map_.size(); } + + private: + friend class ModuleComparer; + class Range { + public: + AddressType base() const { + return *(reinterpret_cast(this)); + } + const EntryType* entryptr() const { + return reinterpret_cast(this + sizeof(AddressType)); + } + }; + + // Convenience types. + typedef StaticRangeMap* SelfPtr; + typedef StaticMap AddressToRangeMap; + typedef typename AddressToRangeMap::const_iterator MapConstIterator; + + AddressToRangeMap map_; +}; + +} // namespace google_breakpad + +#endif // PROCESSOR_STATIC_RANGE_MAP_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/static_range_map_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map_unittest.cc new file mode 100644 index 0000000000..2821736224 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/static_range_map_unittest.cc @@ -0,0 +1,421 @@ +// Copyright (c) 2010 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. + +// static_range_map_unittest.cc: Unit tests for StaticRangeMap. +// +// Author: Siyang Xie (lambxsy@google.com) + +#include "breakpad_googletest_includes.h" +#include "common/scoped_ptr.h" +#include "processor/range_map-inl.h" +#include "processor/static_range_map-inl.h" +#include "processor/simple_serializer-inl.h" +#include "processor/map_serializers-inl.h" +#include "processor/logging.h" + + +namespace { +// Types used for testing. +typedef int AddressType; +typedef int EntryType; +typedef google_breakpad::StaticRangeMap< AddressType, EntryType > TestMap; +typedef google_breakpad::RangeMap< AddressType, EntryType > RMap; + +// RangeTest contains data to use for store and retrieve tests. See +// RunTests for descriptions of the tests. +struct RangeTest { + // Base address to use for test + AddressType address; + + // Size of range to use for test + AddressType size; + + // Unique ID of range - unstorable ranges must have unique IDs too + EntryType id; + + // Whether this range is expected to be stored successfully or not + bool expect_storable; +}; + +// A RangeTestSet encompasses multiple RangeTests, which are run in +// sequence on the same RangeMap. +struct RangeTestSet { + // An array of RangeTests + const RangeTest* range_tests; + + // The number of tests in the set + unsigned int range_test_count; +}; + +// These tests will be run sequentially. The first set of tests exercises +// most functions of RangeTest, and verifies all of the bounds-checking. +const RangeTest range_tests_0[] = { + { INT_MIN, 16, 1, true }, // lowest possible range + { -2, 5, 2, true }, // a range through zero + { INT_MAX - 9, 11, 3, false }, // tests anti-overflow + { INT_MAX - 9, 10, 4, true }, // highest possible range + { 5, 0, 5, false }, // tests anti-zero-size + { 5, 1, 6, true }, // smallest possible range + { -20, 15, 7, true }, // entirely negative + + { 10, 10, 10, true }, // causes the following tests to fail + { 9, 10, 11, false }, // one-less base, one-less high + { 9, 11, 12, false }, // one-less base, identical high + { 9, 12, 13, false }, // completely contains existing + { 10, 9, 14, false }, // identical base, one-less high + { 10, 10, 15, false }, // exactly identical to existing range + { 10, 11, 16, false }, // identical base, one-greater high + { 11, 8, 17, false }, // contained completely within + { 11, 9, 18, false }, // one-greater base, identical high + { 11, 10, 19, false }, // one-greater base, one-greater high + { 9, 2, 20, false }, // overlaps bottom by one + { 10, 1, 21, false }, // overlaps bottom by one, contained + { 19, 1, 22, false }, // overlaps top by one, contained + { 19, 2, 23, false }, // overlaps top by one + + { 9, 1, 24, true }, // directly below without overlap + { 20, 1, 25, true }, // directly above without overlap + + { 6, 3, 26, true }, // exactly between two ranges, gapless + { 7, 3, 27, false }, // tries to span two ranges + { 7, 5, 28, false }, // tries to span three ranges + { 4, 20, 29, false }, // tries to contain several ranges + + { 30, 50, 30, true }, + { 90, 25, 31, true }, + { 35, 65, 32, false }, // tries to span two noncontiguous + { 120, 10000, 33, true }, // > 8-bit + { 20000, 20000, 34, true }, // > 8-bit + { 0x10001, 0x10001, 35, true }, // > 16-bit + + { 27, -1, 36, false } // tests high < base +}; + +// Attempt to fill the entire space. The entire space must be filled with +// three stores because AddressType is signed for these tests, so RangeMap +// treats the size as signed and rejects sizes that appear to be negative. +// Even if these tests were run as unsigned, two stores would be needed +// to fill the space because the entire size of the space could only be +// described by using one more bit than would be present in AddressType. +const RangeTest range_tests_1[] = { + { INT_MIN, INT_MAX, 50, true }, // From INT_MIN to -2, inclusive + { -1, 2, 51, true }, // From -1 to 0, inclusive + { 1, INT_MAX, 52, true }, // From 1 to INT_MAX, inclusive + { INT_MIN, INT_MAX, 53, false }, // Can't fill the space twice + { -1, 2, 54, false }, + { 1, INT_MAX, 55, false }, + { -3, 6, 56, false }, // -3 to 2, inclusive - spans 3 ranges +}; + +// A light round of testing to verify that RetrieveRange does the right +// the right thing at the extremities of the range when nothing is stored +// there. Checks are forced without storing anything at the extremities +// by setting size = 0. +const RangeTest range_tests_2[] = { + { INT_MIN, 0, 100, false }, // makes RetrieveRange check low end + { -1, 3, 101, true }, + { INT_MAX, 0, 102, false }, // makes RetrieveRange check high end +}; + +// Similar to the previous test set, but with a couple of ranges closer +// to the extremities. +const RangeTest range_tests_3[] = { + { INT_MIN + 1, 1, 110, true }, + { INT_MAX - 1, 1, 111, true }, + { INT_MIN, 0, 112, false }, // makes RetrieveRange check low end + { INT_MAX, 0, 113, false } // makes RetrieveRange check high end +}; + +// The range map is cleared between sets of tests listed here. +const RangeTestSet range_test_sets[] = { + { range_tests_0, sizeof(range_tests_0) / sizeof(RangeTest) }, + { range_tests_1, sizeof(range_tests_1) / sizeof(RangeTest) }, + { range_tests_2, sizeof(range_tests_2) / sizeof(RangeTest) }, + { range_tests_3, sizeof(range_tests_3) / sizeof(RangeTest) }, + { range_tests_0, sizeof(range_tests_0) / sizeof(RangeTest) } // Run again +}; + +} // namespace + +namespace google_breakpad { +class TestStaticRangeMap : public ::testing::Test { + protected: + void SetUp() { + kTestCasesCount_ = sizeof(range_test_sets) / sizeof(RangeTestSet); + } + + // StoreTest uses the data in a RangeTest and calls StoreRange on the + // test RangeMap. It returns true if the expected result occurred, and + // false if something else happened. + void StoreTest(RMap* range_map, const RangeTest* range_test); + + // RetrieveTest uses the data in RangeTest and calls RetrieveRange on the + // test RangeMap. If it retrieves the expected value (which can be no + // map entry at the specified range,) it returns true, otherwise, it returns + // false. RetrieveTest will check the values around the base address and + // the high address of a range to guard against off-by-one errors. + void RetrieveTest(TestMap* range_map, const RangeTest* range_test); + + // Test RetrieveRangeAtIndex, which is supposed to return objects in order + // according to their addresses. This test is performed by looping through + // the map, calling RetrieveRangeAtIndex for all possible indices in sequence, + // and verifying that each call returns a different object than the previous + // call, and that ranges are returned with increasing base addresses. Returns + // false if the test fails. + void RetrieveIndexTest(const TestMap* range_map, int set); + + void RunTestCase(int test_case); + + unsigned int kTestCasesCount_; + RangeMapSerializer serializer_; +}; + +void TestStaticRangeMap::StoreTest(RMap* range_map, + const RangeTest* range_test) { + bool stored = range_map->StoreRange(range_test->address, + range_test->size, + range_test->id); + EXPECT_EQ(stored, range_test->expect_storable) + << "StoreRange id " << range_test->id << "FAILED"; +} + +void TestStaticRangeMap::RetrieveTest(TestMap* range_map, + const RangeTest* range_test) { + for (unsigned int side = 0; side <= 1; ++side) { + // When side == 0, check the low side (base address) of each range. + // When side == 1, check the high side (base + size) of each range. + + // Check one-less and one-greater than the target address in addition + // to the target address itself. + + // If the size of the range is only 1, don't check one greater than + // the base or one less than the high - for a successfully stored + // range, these tests would erroneously fail because the range is too + // small. + AddressType low_offset = -1; + AddressType high_offset = 1; + if (range_test->size == 1) { + if (!side) // When checking the low side, + high_offset = 0; // don't check one over the target. + else // When checking the high side, + low_offset = 0; // don't check one under the target. + } + + for (AddressType offset = low_offset; offset <= high_offset; ++offset) { + AddressType address = + offset + + (!side ? range_test->address : + range_test->address + range_test->size - 1); + + bool expected_result = false; // This is correct for tests not stored. + if (range_test->expect_storable) { + if (offset == 0) // When checking the target address, + expected_result = true; // test should always succeed. + else if (offset == -1) // When checking one below the target, + expected_result = side; // should fail low and succeed high. + else // When checking one above the target, + expected_result = !side; // should succeed low and fail high. + } + + const EntryType* id; + AddressType retrieved_base; + AddressType retrieved_size; + bool retrieved = range_map->RetrieveRange(address, id, + &retrieved_base, + &retrieved_size); + + bool observed_result = retrieved && *id == range_test->id; + EXPECT_EQ(observed_result, expected_result) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + + // If a range was successfully retrieved, check that the returned + // bounds match the range as stored. + if (observed_result == true) { + EXPECT_EQ(retrieved_base, range_test->address) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + EXPECT_EQ(retrieved_size, range_test->size) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + } + + // Now, check RetrieveNearestRange. The nearest range is always + // expected to be different from the test range when checking one + // less than the low side. + bool expected_nearest = range_test->expect_storable; + if (!side && offset < 0) + expected_nearest = false; + + AddressType nearest_base; + AddressType nearest_size; + bool retrieved_nearest = range_map->RetrieveNearestRange(address, + id, + &nearest_base, + &nearest_size); + + // When checking one greater than the high side, RetrieveNearestRange + // should usually return the test range. When a different range begins + // at that address, though, then RetrieveNearestRange should return the + // range at the address instead of the test range. + if (side && offset > 0 && nearest_base == address) { + expected_nearest = false; + } + + bool observed_nearest = retrieved_nearest && + *id == range_test->id; + + EXPECT_EQ(observed_nearest, expected_nearest) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + + // If a range was successfully retrieved, check that the returned + // bounds match the range as stored. + if (expected_nearest ==true) { + EXPECT_EQ(nearest_base, range_test->address) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + EXPECT_EQ(nearest_size, range_test->size) + << "RetrieveRange id " << range_test->id + << ", side " << side << ", offset " << offset << " FAILED."; + } + } + } +} + +void TestStaticRangeMap::RetrieveIndexTest(const TestMap* range_map, int set) { + AddressType last_base = 0; + const EntryType* last_entry = 0; + const EntryType* entry; + int object_count = range_map->GetCount(); + for (int object_index = 0; object_index < object_count; ++object_index) { + AddressType base; + ASSERT_TRUE(range_map->RetrieveRangeAtIndex(object_index, + entry, + &base, + NULL)) + << "FAILED: RetrieveRangeAtIndex set " << set + << " index " << object_index; + + ASSERT_TRUE(entry) << "FAILED: RetrieveRangeAtIndex set " << set + << " index " << object_index; + + // It's impossible to do these comparisons unless there's a previous + // object to compare against. + if (last_entry) { + // The object must be different from the last_entry one. + EXPECT_NE(*entry, *last_entry) << "FAILED: RetrieveRangeAtIndex set " + << set << " index " << object_index; + // Each object must have a base greater than the previous object's base. + EXPECT_GT(base, last_base) << "FAILED: RetrieveRangeAtIndex set " << set + << " index " << object_index; + } + last_entry = entry; + last_base = base; + } + + // Make sure that RetrieveRangeAtIndex doesn't allow lookups at indices that + // are too high. + ASSERT_FALSE(range_map->RetrieveRangeAtIndex( + object_count, entry, NULL, NULL)) << "FAILED: RetrieveRangeAtIndex set " + << set << " index " << object_count + << " (too large)"; +} + +// RunTests runs a series of test sets. +void TestStaticRangeMap::RunTestCase(int test_case) { + // Maintain the range map in a pointer so that deletion can be meaningfully + // tested. + scoped_ptr rmap(new RMap()); + + const RangeTest* range_tests = range_test_sets[test_case].range_tests; + unsigned int range_test_count = range_test_sets[test_case].range_test_count; + + // Run the StoreRange test, which validates StoreRange and initializes + // the RangeMap with data for the RetrieveRange test. + int stored_count = 0; // The number of ranges successfully stored + for (unsigned int range_test_index = 0; + range_test_index < range_test_count; + ++range_test_index) { + const RangeTest* range_test = &range_tests[range_test_index]; + StoreTest(rmap.get(), range_test); + + if (range_test->expect_storable) + ++stored_count; + } + + scoped_array memaddr(serializer_.Serialize(*rmap, NULL)); + scoped_ptr static_range_map(new TestMap(memaddr.get())); + + // The RangeMap's own count of objects should also match. + EXPECT_EQ(static_range_map->GetCount(), stored_count); + + // Run the RetrieveRange test + for (unsigned int range_test_index = 0; + range_test_index < range_test_count; + ++range_test_index) { + const RangeTest* range_test = &range_tests[range_test_index]; + RetrieveTest(static_range_map.get(), range_test); + } + + RetrieveIndexTest(static_range_map.get(), test_case); +} + +TEST_F(TestStaticRangeMap, TestCase0) { + int test_case = 0; + RunTestCase(test_case); +} + +TEST_F(TestStaticRangeMap, TestCase1) { + int test_case = 1; + RunTestCase(test_case); +} + +TEST_F(TestStaticRangeMap, TestCase2) { + int test_case = 2; + RunTestCase(test_case); +} + +TEST_F(TestStaticRangeMap, TestCase3) { + int test_case = 3; + RunTestCase(test_case); +} + +TEST_F(TestStaticRangeMap, RunTestCase0Again) { + int test_case = 0; + RunTestCase(test_case); +} + +} // namespace google_breakpad + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.cc b/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.cc new file mode 100644 index 0000000000..e01a46ab1f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.cc @@ -0,0 +1,10958 @@ +// Copyright (c) 2015 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. + +// ntstatus_reason_win.h: Windows NTSTATUS code to string. +// +// Provides a means to convert NTSTATUS codes to strings. +// +// Author: Ben Wagner + +#include +#include + +#include "common/stdio_wrapper.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_exception_win32.h" +#include "processor/symbolic_constants_win.h" + +namespace google_breakpad { + +// The content of this array was created from ntstatus.h in the 10 SDK +// (version 10.0.19041.0) with +// +// egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h +// | tr -d '\r' +// | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' +// | sort +// | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2,@' +// +// With easy copy to clipboard with +// | xclip -selection c # on linux +// | clip # on windows +// | pbcopy # on mac +static const uint32_t kNTStatusValues[] = { + MD_NTSTATUS_WIN_STATUS_SUCCESS, + MD_NTSTATUS_WIN_STATUS_WAIT_0, + MD_NTSTATUS_WIN_STATUS_WAIT_1, + MD_NTSTATUS_WIN_STATUS_WAIT_2, + MD_NTSTATUS_WIN_STATUS_WAIT_3, + MD_NTSTATUS_WIN_STATUS_WAIT_63, + MD_NTSTATUS_WIN_STATUS_ABANDONED, + MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_0, + MD_NTSTATUS_WIN_STATUS_ABANDONED_WAIT_63, + MD_NTSTATUS_WIN_STATUS_USER_APC, + MD_NTSTATUS_WIN_STATUS_ALREADY_COMPLETE, + MD_NTSTATUS_WIN_STATUS_KERNEL_APC, + MD_NTSTATUS_WIN_STATUS_ALERTED, + MD_NTSTATUS_WIN_STATUS_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_PENDING, + MD_NTSTATUS_WIN_STATUS_REPARSE, + MD_NTSTATUS_WIN_STATUS_MORE_ENTRIES, + MD_NTSTATUS_WIN_STATUS_NOT_ALL_ASSIGNED, + MD_NTSTATUS_WIN_STATUS_SOME_NOT_MAPPED, + MD_NTSTATUS_WIN_STATUS_OPLOCK_BREAK_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_VOLUME_MOUNTED, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMITTED, + MD_NTSTATUS_WIN_STATUS_NOTIFY_CLEANUP, + MD_NTSTATUS_WIN_STATUS_NOTIFY_ENUM_DIR, + MD_NTSTATUS_WIN_STATUS_NO_QUOTAS_FOR_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_TRANSITION, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_DEMAND_ZERO, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_COPY_ON_WRITE, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_GUARD_PAGE, + MD_NTSTATUS_WIN_STATUS_PAGE_FAULT_PAGING_FILE, + MD_NTSTATUS_WIN_STATUS_CACHE_PAGE_LOCKED, + MD_NTSTATUS_WIN_STATUS_CRASH_DUMP, + MD_NTSTATUS_WIN_STATUS_BUFFER_ALL_ZEROS, + MD_NTSTATUS_WIN_STATUS_REPARSE_OBJECT, + MD_NTSTATUS_WIN_STATUS_RESOURCE_REQUIREMENTS_CHANGED, + MD_NTSTATUS_WIN_STATUS_TRANSLATION_COMPLETE, + MD_NTSTATUS_WIN_STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY, + MD_NTSTATUS_WIN_STATUS_NOTHING_TO_TERMINATE, + MD_NTSTATUS_WIN_STATUS_PROCESS_NOT_IN_JOB, + MD_NTSTATUS_WIN_STATUS_PROCESS_IN_JOB, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_HIBERNATE_READY, + MD_NTSTATUS_WIN_STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY, + MD_NTSTATUS_WIN_STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED, + MD_NTSTATUS_WIN_STATUS_INTERRUPT_STILL_CONNECTED, + MD_NTSTATUS_WIN_STATUS_PROCESS_CLONED, + MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_ONLY_READERS, + MD_NTSTATUS_WIN_STATUS_FILE_LOCKED_WITH_WRITERS, + MD_NTSTATUS_WIN_STATUS_VALID_IMAGE_HASH, + MD_NTSTATUS_WIN_STATUS_VALID_CATALOG_HASH, + MD_NTSTATUS_WIN_STATUS_VALID_STRONG_CODE_HASH, + MD_NTSTATUS_WIN_STATUS_GHOSTED, + MD_NTSTATUS_WIN_STATUS_DATA_OVERWRITTEN, + MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_READ_ONLY, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_EMPTY, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_FULL, + MD_NTSTATUS_WIN_STATUS_RING_PREVIOUSLY_ABOVE_QUOTA, + MD_NTSTATUS_WIN_STATUS_RING_NEWLY_EMPTY, + MD_NTSTATUS_WIN_STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT, + MD_NTSTATUS_WIN_STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, + MD_NTSTATUS_WIN_STATUS_OPLOCK_HANDLE_CLOSED, + MD_NTSTATUS_WIN_STATUS_WAIT_FOR_OPLOCK, + MD_NTSTATUS_WIN_STATUS_REPARSE_GLOBAL, + MD_NTSTATUS_WIN_DBG_EXCEPTION_HANDLED, + MD_NTSTATUS_WIN_DBG_CONTINUE, + MD_NTSTATUS_WIN_STATUS_FLT_IO_COMPLETE, + MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_CONTINUE, + MD_NTSTATUS_WIN_STATUS_RTPM_CONTEXT_COMPLETE, + MD_NTSTATUS_WIN_STATUS_HV_PENDING_PAGE_REQUESTS, + MD_NTSTATUS_WIN_STATUS_SPACES_REPAIRED, + MD_NTSTATUS_WIN_STATUS_SPACES_PAUSE, + MD_NTSTATUS_WIN_STATUS_SPACES_COMPLETE, + MD_NTSTATUS_WIN_STATUS_SPACES_REDIRECT, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_EXISTS, + MD_NTSTATUS_WIN_STATUS_THREAD_WAS_SUSPENDED, + MD_NTSTATUS_WIN_STATUS_WORKING_SET_LIMIT_RANGE, + MD_NTSTATUS_WIN_STATUS_IMAGE_NOT_AT_BASE, + MD_NTSTATUS_WIN_STATUS_RXACT_STATE_CREATED, + MD_NTSTATUS_WIN_STATUS_SEGMENT_NOTIFICATION, + MD_NTSTATUS_WIN_STATUS_LOCAL_USER_SESSION_KEY, + MD_NTSTATUS_WIN_STATUS_BAD_CURRENT_DIRECTORY, + MD_NTSTATUS_WIN_STATUS_SERIAL_MORE_WRITES, + MD_NTSTATUS_WIN_STATUS_REGISTRY_RECOVERED, + MD_NTSTATUS_WIN_STATUS_FT_READ_RECOVERY_FROM_BACKUP, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_RECOVERY, + MD_NTSTATUS_WIN_STATUS_SERIAL_COUNTER_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_NULL_LM_PASSWORD, + MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL, + MD_NTSTATUS_WIN_STATUS_RECEIVE_EXPEDITED, + MD_NTSTATUS_WIN_STATUS_RECEIVE_PARTIAL_EXPEDITED, + MD_NTSTATUS_WIN_STATUS_EVENT_DONE, + MD_NTSTATUS_WIN_STATUS_EVENT_PENDING, + MD_NTSTATUS_WIN_STATUS_CHECKING_FILE_SYSTEM, + MD_NTSTATUS_WIN_STATUS_FATAL_APP_EXIT, + MD_NTSTATUS_WIN_STATUS_PREDEFINED_HANDLE, + MD_NTSTATUS_WIN_STATUS_WAS_UNLOCKED, + MD_NTSTATUS_WIN_STATUS_SERVICE_NOTIFICATION, + MD_NTSTATUS_WIN_STATUS_WAS_LOCKED, + MD_NTSTATUS_WIN_STATUS_LOG_HARD_ERROR, + MD_NTSTATUS_WIN_STATUS_ALREADY_WIN32, + MD_NTSTATUS_WIN_STATUS_WX86_UNSIMULATE, + MD_NTSTATUS_WIN_STATUS_WX86_CONTINUE, + MD_NTSTATUS_WIN_STATUS_WX86_SINGLE_STEP, + MD_NTSTATUS_WIN_STATUS_WX86_BREAKPOINT, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CONTINUE, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_LASTCHANCE, + MD_NTSTATUS_WIN_STATUS_WX86_EXCEPTION_CHAIN, + MD_NTSTATUS_WIN_STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE, + MD_NTSTATUS_WIN_STATUS_NO_YIELD_PERFORMED, + MD_NTSTATUS_WIN_STATUS_TIMER_RESUME_IGNORED, + MD_NTSTATUS_WIN_STATUS_ARBITRATION_UNHANDLED, + MD_NTSTATUS_WIN_STATUS_CARDBUS_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_WX86_CREATEWX86TIB, + MD_NTSTATUS_WIN_STATUS_MP_PROCESSOR_MISMATCH, + MD_NTSTATUS_WIN_STATUS_HIBERNATED, + MD_NTSTATUS_WIN_STATUS_RESUME_HIBERNATION, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_UPDATED, + MD_NTSTATUS_WIN_STATUS_DRIVERS_LEAKING_LOCKED_PAGES, + MD_NTSTATUS_WIN_STATUS_MESSAGE_RETRIEVED, + MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_TRANSITION, + MD_NTSTATUS_WIN_STATUS_ALPC_CHECK_COMPLETION_LIST, + MD_NTSTATUS_WIN_STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, + MD_NTSTATUS_WIN_STATUS_ACCESS_AUDIT_BY_POLICY, + MD_NTSTATUS_WIN_STATUS_ABANDON_HIBERFILE, + MD_NTSTATUS_WIN_STATUS_BIZRULES_NOT_ENABLED, + MD_NTSTATUS_WIN_STATUS_FT_READ_FROM_COPY, + MD_NTSTATUS_WIN_STATUS_IMAGE_AT_DIFFERENT_BASE, + MD_NTSTATUS_WIN_STATUS_PATCH_DEFERRED, + MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM, + MD_NTSTATUS_WIN_STATUS_DS_SHUTTING_DOWN, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_REDIRECTED, + MD_NTSTATUS_WIN_STATUS_SERVICES_FAILED_AUTOSTART, + MD_NTSTATUS_WIN_DBG_REPLY_LATER, + MD_NTSTATUS_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE, + MD_NTSTATUS_WIN_DBG_TERMINATE_THREAD, + MD_NTSTATUS_WIN_DBG_TERMINATE_PROCESS, + MD_NTSTATUS_WIN_DBG_CONTROL_C, + MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_C, + MD_NTSTATUS_WIN_DBG_RIPEXCEPTION, + MD_NTSTATUS_WIN_DBG_CONTROL_BREAK, + MD_NTSTATUS_WIN_DBG_COMMAND_EXCEPTION, + MD_NTSTATUS_WIN_DBG_PRINTEXCEPTION_WIDE_C, + MD_NTSTATUS_WIN_RPC_NT_UUID_LOCAL_ONLY, + MD_NTSTATUS_WIN_RPC_NT_SEND_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_CTX_CDM_CONNECT, + MD_NTSTATUS_WIN_STATUS_CTX_CDM_DISCONNECT, + MD_NTSTATUS_WIN_STATUS_SXS_RELEASE_ACTIVATION_CONTEXT, + MD_NTSTATUS_WIN_STATUS_HEURISTIC_DAMAGE_POSSIBLE, + MD_NTSTATUS_WIN_STATUS_RECOVERY_NOT_NEEDED, + MD_NTSTATUS_WIN_STATUS_RM_ALREADY_STARTED, + MD_NTSTATUS_WIN_STATUS_LOG_NO_RESTART, + MD_NTSTATUS_WIN_STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARTIAL_DATA_POPULATED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_PINNED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_PREFERRED_MODE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DATASET_IS_EMPTY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_START_DEFERRED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_START_DEFERRED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS, + MD_NTSTATUS_WIN_STATUS_NDIS_INDICATION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_PCP_UNSUPPORTED_PSS_SALT, + MD_NTSTATUS_WIN_STATUS_GUARD_PAGE_VIOLATION, + MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT, + MD_NTSTATUS_WIN_STATUS_BREAKPOINT, + MD_NTSTATUS_WIN_STATUS_SINGLE_STEP, + MD_NTSTATUS_WIN_STATUS_BUFFER_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_NO_MORE_FILES, + MD_NTSTATUS_WIN_STATUS_WAKE_SYSTEM_DEBUGGER, + MD_NTSTATUS_WIN_STATUS_HANDLES_CLOSED, + MD_NTSTATUS_WIN_STATUS_NO_INHERITANCE, + MD_NTSTATUS_WIN_STATUS_GUID_SUBSTITUTION_MADE, + MD_NTSTATUS_WIN_STATUS_PARTIAL_COPY, + MD_NTSTATUS_WIN_STATUS_DEVICE_PAPER_EMPTY, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWERED_OFF, + MD_NTSTATUS_WIN_STATUS_DEVICE_OFF_LINE, + MD_NTSTATUS_WIN_STATUS_DEVICE_BUSY, + MD_NTSTATUS_WIN_STATUS_NO_MORE_EAS, + MD_NTSTATUS_WIN_STATUS_INVALID_EA_NAME, + MD_NTSTATUS_WIN_STATUS_EA_LIST_INCONSISTENT, + MD_NTSTATUS_WIN_STATUS_INVALID_EA_FLAG, + MD_NTSTATUS_WIN_STATUS_VERIFY_REQUIRED, + MD_NTSTATUS_WIN_STATUS_EXTRANEOUS_INFORMATION, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_NECESSARY, + MD_NTSTATUS_WIN_STATUS_NO_MORE_ENTRIES, + MD_NTSTATUS_WIN_STATUS_FILEMARK_DETECTED, + MD_NTSTATUS_WIN_STATUS_MEDIA_CHANGED, + MD_NTSTATUS_WIN_STATUS_BUS_RESET, + MD_NTSTATUS_WIN_STATUS_END_OF_MEDIA, + MD_NTSTATUS_WIN_STATUS_BEGINNING_OF_MEDIA, + MD_NTSTATUS_WIN_STATUS_MEDIA_CHECK, + MD_NTSTATUS_WIN_STATUS_SETMARK_DETECTED, + MD_NTSTATUS_WIN_STATUS_NO_DATA_DETECTED, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_HAS_OPEN_HANDLES, + MD_NTSTATUS_WIN_STATUS_SERVER_HAS_OPEN_HANDLES, + MD_NTSTATUS_WIN_STATUS_ALREADY_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_LONGJUMP, + MD_NTSTATUS_WIN_STATUS_CLEANER_CARTRIDGE_INSTALLED, + MD_NTSTATUS_WIN_STATUS_PLUGPLAY_QUERY_VETOED, + MD_NTSTATUS_WIN_STATUS_UNWIND_CONSOLIDATE, + MD_NTSTATUS_WIN_STATUS_REGISTRY_HIVE_RECOVERED, + MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INSECURE, + MD_NTSTATUS_WIN_STATUS_DLL_MIGHT_BE_INCOMPATIBLE, + MD_NTSTATUS_WIN_STATUS_STOPPED_ON_SYMLINK, + MD_NTSTATUS_WIN_STATUS_CANNOT_GRANT_REQUESTED_OPLOCK, + MD_NTSTATUS_WIN_STATUS_NO_ACE_CONDITION, + MD_NTSTATUS_WIN_STATUS_DEVICE_SUPPORT_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_CYCLE_REQUIRED, + MD_NTSTATUS_WIN_STATUS_NO_WORK_DONE, + MD_NTSTATUS_WIN_STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT, + MD_NTSTATUS_WIN_STATUS_DEVICE_REQUIRES_CLEANING, + MD_NTSTATUS_WIN_STATUS_DEVICE_DOOR_OPEN, + MD_NTSTATUS_WIN_STATUS_DATA_LOST_REPAIR, + MD_NTSTATUS_WIN_STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS, + MD_NTSTATUS_WIN_DBG_EXCEPTION_NOT_HANDLED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_UP, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_DOWN, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_ONLINE, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_ALREADY_MEMBER, + MD_NTSTATUS_WIN_STATUS_COULD_NOT_RESIZE_LOG, + MD_NTSTATUS_WIN_STATUS_NO_TXF_METADATA, + MD_NTSTATUS_WIN_STATUS_CANT_RECOVER_WITH_HANDLE_OPEN, + MD_NTSTATUS_WIN_STATUS_TXF_METADATA_ALREADY_PRESENT, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, + MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED, + MD_NTSTATUS_WIN_STATUS_FLT_BUFFER_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_FVE_PARTIAL_METADATA, + MD_NTSTATUS_WIN_STATUS_FVE_TRANSIENT_STATE, + MD_NTSTATUS_WIN_STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_REGENERATION, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION, + MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED, + MD_NTSTATUS_WIN_STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED, + MD_NTSTATUS_WIN_STATUS_QUERY_STORAGE_ERROR, + MD_NTSTATUS_WIN_STATUS_GDI_HANDLE_LEAK, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_ENABLED, + MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL, + MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED, + MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS, + MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH, + MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION, + MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA, + MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC, + MD_NTSTATUS_WIN_STATUS_INVALID_CID, + MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST, + MD_NTSTATUS_WIN_STATUS_END_OF_FILE, + MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR, + MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED, + MD_NTSTATUS_WIN_STATUS_NO_MEMORY, + MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION, + MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE, + MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE, + MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION, + MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED, + MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION, + MD_NTSTATUS_WIN_STATUS_UNWIND, + MD_NTSTATUS_WIN_STATUS_BAD_STACK, + MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET, + MD_NTSTATUS_WIN_STATUS_NOT_LOCKED, + MD_NTSTATUS_WIN_STATUS_PARITY_ERROR, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM, + MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES, + MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX, + MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER, + MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION, + MD_NTSTATUS_WIN_STATUS_PORT_DO_NOT_DISTURB, + MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD, + MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN, + MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR, + MD_NTSTATUS_WIN_STATUS_DATA_ERROR, + MD_NTSTATUS_WIN_STATUS_CRC_ERROR, + MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG, + MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE, + MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION, + MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION, + MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED, + MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE, + MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING, + MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP, + MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION, + MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY, + MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE, + MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR, + MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT, + MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED, + MD_NTSTATUS_WIN_STATUS_DELETE_PENDING, + MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION, + MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH, + MD_NTSTATUS_WIN_STATUS_INVALID_OWNER, + MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP, + MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN, + MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY, + MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE, + MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD, + MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME, + MD_NTSTATUS_WIN_STATUS_USER_EXISTS, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER, + MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP, + MD_NTSTATUS_WIN_STATUS_LAST_ADMIN, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD, + MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS, + MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION, + MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED, + MD_NTSTATUS_WIN_STATUS_NONE_MAPPED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED, + MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY, + MD_NTSTATUS_WIN_STATUS_INVALID_ACL, + MD_NTSTATUS_WIN_STATUS_INVALID_SID, + MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR, + MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT, + MD_NTSTATUS_WIN_STATUS_NO_TOKEN, + MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED, + MD_NTSTATUS_WIN_STATUS_DISK_FULL, + MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED, + MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED, + MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY, + MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA, + MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND, + MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO, + MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT, + MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION, + MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK, + MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW, + MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO, + MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES, + MD_NTSTATUS_WIN_STATUS_FILE_INVALID, + MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES, + MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND, + MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE, + MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE, + MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED, + MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA, + MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY, + MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES, + MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS, + MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS, + MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE, + MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD, + MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT, + MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE, + MD_NTSTATUS_WIN_STATUS_PIPE_BUSY, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION, + MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING, + MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED, + MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING, + MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE, + MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED, + MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET, + MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH, + MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY, + MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS, + MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR, + MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR, + MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER, + MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL, + MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE, + MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED, + MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED, + MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS, + MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED, + MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED, + MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT, + MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT, + MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE, + MD_NTSTATUS_WIN_STATUS_FILE_RENAMED, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT, + MD_NTSTATUS_WIN_STATUS_CANT_WAIT, + MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY, + MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO, + MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF, + MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN, + MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS, + MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED, + MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION, + MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED, + MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR, + MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE, + MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE, + MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY, + MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR, + MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY, + MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION, + MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_FILES_OPEN, + MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE, + MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE, + MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION, + MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID, + MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR, + MD_NTSTATUS_WIN_STATUS_NO_LDT, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT, + MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES, + MD_NTSTATUS_WIN_STATUS_CANCELLED, + MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE, + MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME, + MD_NTSTATUS_WIN_STATUS_FILE_DELETED, + MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP, + MD_NTSTATUS_WIN_STATUS_SPECIAL_USER, + MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP, + MD_NTSTATUS_WIN_STATUS_FILE_CLOSED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS, + MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16, + MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT, + MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC, + MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_OPEN_FAILED, + MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED, + MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT, + MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT, + MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT, + MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES, + MD_NTSTATUS_WIN_STATUS_LINK_FAILED, + MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED, + MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE, + MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED, + MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE, + MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT, + MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN, + MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT, + MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED, + MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME, + MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS, + MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS, + MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS, + MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR, + MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS, + MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED, + MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE, + MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR, + MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER, + MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER, + MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME, + MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER, + MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR, + MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS, + MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED, + MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED, + MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED, + MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY, + MD_NTSTATUS_WIN_STATUS_FT_ORPHANING, + MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT, + MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE, + MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA, + MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER, + MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER, + MD_NTSTATUS_WIN_STATUS_KEY_DELETED, + MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS, + MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN, + MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE, + MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR, + MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE, + MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR, + MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR, + MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER, + MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL, + MD_NTSTATUS_WIN_STATUS_TOO_LATE, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE, + MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START, + MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE, + MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED, + MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK, + MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT, + MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED, + MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT, + MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING, + MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME, + MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE, + MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION, + MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED, + MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES, + MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE, + MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED, + MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED, + MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE, + MD_NTSTATUS_WIN_STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_NOT_SAME_OBJECT, + MD_NTSTATUS_WIN_STATUS_FATAL_MEMORY_EXHAUSTION, + MD_NTSTATUS_WIN_STATUS_ERROR_PROCESS_NOT_IN_JOB, + MD_NTSTATUS_WIN_STATUS_CPU_SET_INVALID, + MD_NTSTATUS_WIN_STATUS_IO_DEVICE_INVALID_DATA, + MD_NTSTATUS_WIN_STATUS_IO_UNALIGNED_WRITE, + MD_NTSTATUS_WIN_STATUS_CONTROL_STACK_VIOLATION, + MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY, + MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED, + MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES, + MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED, + MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE, + MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION, + MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION, + MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE, + MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED, + MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED, + MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED, + MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND, + MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR, + MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT, + MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA, + MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID, + MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE, + MD_NTSTATUS_WIN_STATUS_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM, + MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ, + MD_NTSTATUS_WIN_STATUS_FAIL_CHECK, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID, + MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS, + MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE, + MD_NTSTATUS_WIN_STATUS_RETRY, + MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE, + MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET, + MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT, + MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE, + MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED, + MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED, + MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED, + MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE, + MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED, + MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER, + MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE, + MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED, + MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET, + MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT, + MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO, + MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT, + MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT, + MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2, + MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT, + MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED, + MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE, + MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT, + MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT, + MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION, + MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE, + MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH, + MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS, + MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT, + MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE, + MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION, + MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF, + MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD, + MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED, + MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK, + MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE, + MD_NTSTATUS_WIN_STATUS_NO_MATCH, + MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES, + MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_CONTEXT_STOWED_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT, + MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT, + MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY, + MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS, + MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED, + MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED, + MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY, + MD_NTSTATUS_WIN_STATUS_NO_EFS, + MD_NTSTATUS_WIN_STATUS_WRONG_EFS, + MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED, + MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT, + MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN, + MD_NTSTATUS_WIN_STATUS_SHARED_POLICY, + MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS, + MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR, + MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE, + MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS, + MD_NTSTATUS_WIN_STATUS_DS_BUSY, + MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED, + MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS, + MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR, + MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS, + MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED, + MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED, + MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT, + MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS, + MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED, + MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_NOINTERFACE, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED, + MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP, + MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED, + MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE, + MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR, + MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY, + MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM, + MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION, + MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED, + MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION, + MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION, + MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID, + MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED, + MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, + MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, + MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS, + MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY, + MD_NTSTATUS_WIN_STATUS_DS_CANT_START, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, + MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS, + MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION, + MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE, + MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE, + MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED, + MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY, + MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES, + MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE, + MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID, + MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC, + MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS, + MD_NTSTATUS_WIN_STATUS_NO_PA_DATA, + MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED, + MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST, + MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER, + MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE, + MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED, + MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED, + MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE, + MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED, + MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR, + MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH, + MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED, + MD_NTSTATUS_WIN_STATUS_LOST_MODE_LOGON_RESTRICTION, + MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE, + MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY, + MD_NTSTATUS_WIN_STATUS_HOST_DOWN, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH, + MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG, + MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET, + MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE, + MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE, + MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED, + MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT, + MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64, + MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS, + MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED, + MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK, + MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED, + MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER, + MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY, + MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR, + MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER, + MD_NTSTATUS_WIN_STATUS_MCA_OCCURED, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED, + MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR, + MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE, + MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL, + MD_NTSTATUS_WIN_STATUS_NO_SECRETS, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, + MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH, + MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR, + MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C, + MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT, + MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE, + MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND, + MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE, + MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED, + MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN, + MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT, + MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED, + MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE, + MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED, + MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED, + MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED, + MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, + MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER, + MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED, + MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST, + MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME, + MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE, + MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP, + MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED, + MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH, + MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE, + MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE, + MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT, + MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT, + MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE, + MD_NTSTATUS_WIN_STATUS_BEYOND_VDL, + MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_PTE_CHANGED, + MD_NTSTATUS_WIN_STATUS_PURGE_FAILED, + MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE, + MD_NTSTATUS_WIN_STATUS_INVALID_LABEL, + MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED, + MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE, + MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES, + MD_NTSTATUS_WIN_STATUS_INVALID_SESSION, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION, + MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT, + MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED, + MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED, + MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION, + MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN, + MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES, + MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING, + MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE, + MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED, + MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_BENEFICIAL, + MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR, + MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION, + MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS, + MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT, + MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST, + MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH, + MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED, + MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE, + MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION, + MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN, + MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_SLOT_INVALID, + MD_NTSTATUS_WIN_STATUS_FIRMWARE_IMAGE_INVALID, + MD_NTSTATUS_WIN_STATUS_STORAGE_TOPOLOGY_ID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_WIM_NOT_BOOTABLE, + MD_NTSTATUS_WIN_STATUS_BLOCKED_BY_PARENTAL_CONTROLS, + MD_NTSTATUS_WIN_STATUS_NEEDS_REGISTRATION, + MD_NTSTATUS_WIN_STATUS_QUOTA_ACTIVITY, + MD_NTSTATUS_WIN_STATUS_CALLBACK_INVOKE_INLINE, + MD_NTSTATUS_WIN_STATUS_BLOCK_TOO_MANY_REFERENCES, + MD_NTSTATUS_WIN_STATUS_MARKED_TO_DISALLOW_WRITES, + MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED_EDP, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_FAILURE, + MD_NTSTATUS_WIN_STATUS_PNP_NO_COMPAT_DRIVERS, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_PNP_FUNCTION_DRIVER_REQUIRED, + MD_NTSTATUS_WIN_STATUS_PNP_DEVICE_CONFIGURATION_PENDING, + MD_NTSTATUS_WIN_STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_PACKAGE_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_DEVICE_IN_MAINTENANCE, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_DAX, + MD_NTSTATUS_WIN_STATUS_FREE_SPACE_TOO_FRAGMENTED, + MD_NTSTATUS_WIN_STATUS_DAX_MAPPING_EXISTS, + MD_NTSTATUS_WIN_STATUS_CHILD_PROCESS_BLOCKED, + MD_NTSTATUS_WIN_STATUS_STORAGE_LOST_DATA_PERSISTENCE, + MD_NTSTATUS_WIN_STATUS_VRF_CFG_AND_IO_ENABLED, + MD_NTSTATUS_WIN_STATUS_PARTITION_TERMINATING, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_VIOLATION, + MD_NTSTATUS_WIN_STATUS_FILE_PROTECTED_UNDER_DPL, + MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_CLUSTER_ALIGNED, + MD_NTSTATUS_WIN_STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND, + MD_NTSTATUS_WIN_STATUS_APPX_FILE_NOT_ENCRYPTED, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE, + MD_NTSTATUS_WIN_STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER, + MD_NTSTATUS_WIN_STATUS_FT_READ_FAILURE, + MD_NTSTATUS_WIN_STATUS_PATCH_CONFLICT, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ID_INVALID, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_DOES_NOT_EXIST, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_STORAGE_RESERVE_NOT_EMPTY, + MD_NTSTATUS_WIN_STATUS_NOT_A_DAX_VOLUME, + MD_NTSTATUS_WIN_STATUS_NOT_DAX_MAPPABLE, + MD_NTSTATUS_WIN_STATUS_CASE_DIFFERING_NAMES_IN_DIR, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_WITH_BTT, + MD_NTSTATUS_WIN_STATUS_ENCRYPTION_DISABLED, + MD_NTSTATUS_WIN_STATUS_ENCRYPTING_METADATA_DISALLOWED, + MD_NTSTATUS_WIN_STATUS_CANT_CLEAR_ENCRYPTION_FLAG, + MD_NTSTATUS_WIN_STATUS_UNSATISFIED_DEPENDENCIES, + MD_NTSTATUS_WIN_STATUS_CASE_SENSITIVE_PATH, + MD_NTSTATUS_WIN_STATUS_HAS_SYSTEM_CRITICAL_FILES, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK, + MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE, + MD_NTSTATUS_WIN_STATUS_INVALID_CAP, + MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS, + MD_NTSTATUS_WIN_STATUS_DEVICE_HUNG, + MD_NTSTATUS_WIN_STATUS_CONTAINER_ASSIGNED, + MD_NTSTATUS_WIN_STATUS_JOB_NO_CONTAINER, + MD_NTSTATUS_WIN_STATUS_DEVICE_UNRESPONSIVE, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_ENCOUNTERED, + MD_NTSTATUS_WIN_STATUS_ATTRIBUTE_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_NOT_A_TIERED_VOLUME, + MD_NTSTATUS_WIN_STATUS_ALREADY_HAS_STREAM_ID, + MD_NTSTATUS_WIN_STATUS_JOB_NOT_EMPTY, + MD_NTSTATUS_WIN_STATUS_ALREADY_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_NOT_TERMINATED, + MD_NTSTATUS_WIN_STATUS_ENCLAVE_IS_TERMINATING, + MD_NTSTATUS_WIN_STATUS_SMB1_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_SMR_GARBAGE_COLLECTION_REQUIRED, + MD_NTSTATUS_WIN_STATUS_INTERRUPTED, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_RUNNING, + MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED, + MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_EXPIRED, + MD_NTSTATUS_WIN_STATUS_STRICT_CFG_VIOLATION, + MD_NTSTATUS_WIN_STATUS_SET_CONTEXT_DENIED, + MD_NTSTATUS_WIN_STATUS_CROSS_PARTITION_VIOLATION, + MD_NTSTATUS_WIN_STATUS_PORT_CLOSED, + MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST, + MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE, + MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED, + MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH, + MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED, + MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE, + MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE, + MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING, + MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED, + MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION, + MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE, + MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED, + MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION, + MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION, + MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED, + MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY, + MD_NTSTATUS_WIN_STATUS_INVALID_THREAD, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY, + MD_NTSTATUS_WIN_STATUS_LPC_HANDLE_COUNT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_EXECUTABLE_MEMORY_WRITE, + MD_NTSTATUS_WIN_STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE, + MD_NTSTATUS_WIN_STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE, + MD_NTSTATUS_WIN_STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED, + MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS, + MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED, + MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS, + MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT, + MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED, + MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE, + MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE, + MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED, + MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED, + MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED, + MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE, + MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK, + MD_NTSTATUS_WIN_STATUS_BAD_KEY, + MD_NTSTATUS_WIN_STATUS_BAD_DATA, + MD_NTSTATUS_WIN_STATUS_NO_KEY, + MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED, + MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION, + MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH, + MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION, + MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION, + MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION, + MD_NTSTATUS_WIN_STATUS_HANDLE_REVOKED, + MD_NTSTATUS_WIN_STATUS_EOF_ON_GHOSTED_RANGE, + MD_NTSTATUS_WIN_STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN, + MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, + MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR, + MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR, + MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT, + MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE, + MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS, + MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED, + MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID, + MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET, + MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED, + MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE, + MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL, + MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER, + MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH, + MD_NTSTATUS_WIN_STATUS_LPAC_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_ADMINLESS_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED, + MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_WOF_WIM_HEADER_CORRUPT, + MD_NTSTATUS_WIN_STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_CIMFS_IMAGE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_METADATA_TOO_LARGE, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_FILE, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_IN_SYNC, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ALREADY_CONNECTED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INVALID_REQUEST, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_READ_ONLY_VOLUME, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_VALIDATION_FAILED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_AUTHENTICATION_FAILED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_UNSUCCESSFUL, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_IN_USE, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PINNED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_ABORTED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_CORRUPT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_CANCELED, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_PROVIDER_TERMINATED, + MD_NTSTATUS_WIN_STATUS_NOT_A_CLOUD_SYNC_ROOT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_REQUEST_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_IO_NOT_COORDINATED, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_UNEXPECTED_ERROR, + MD_NTSTATUS_WIN_STATUS_FILE_SNAP_INVALID_PARAMETER, + MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE, + MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING, + MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED, + MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR, + MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT, + MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED, + MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED, + MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF, + MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS, + MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT, + MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES, + MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE, + MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS, + MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE, + MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND, + MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX, + MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS, + MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE, + MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL, + MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND, + MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE, + MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL, + MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE, + MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY, + MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP, + MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED, + MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT, + MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME, + MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS, + MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED, + MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND, + MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID, + MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT, + MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE, + MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR, + MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE, + MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR, + MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO, + MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW, + MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW, + MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS, + MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND, + MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE, + MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT, + MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES, + MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED, + MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE, + MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL, + MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME, + MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR, + MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR, + MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL, + MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED, + MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE, + MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED, + MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH, + MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE, + MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER, + MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE, + MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL, + MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION, + MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION, + MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION, + MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION, + MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED, + MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR, + MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY, + MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE, + MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED, + MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED, + MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID, + MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD, + MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING, + MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME, + MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE, + MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY, + MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE, + MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID, + MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD, + MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED, + MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING, + MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED, + MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR, + MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS, + MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED, + MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL, + MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NO_SNAPSHOTS, + MD_NTSTATUS_WIN_STATUS_CSV_IO_PAUSE_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE, + MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT, + MD_NTSTATUS_WIN_STATUS_ACPI_FATAL, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE, + MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT, + MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE, + MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE, + MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK, + MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER, + MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE, + MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED, + MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED, + MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR, + MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED, + MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT, + MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE, + MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET, + MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION, + MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION, + MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR, + MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY, + MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED, + MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG, + MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED, + MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED, + MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT, + MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED, + MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE, + MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE, + MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER, + MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID, + MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED, + MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID, + MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, + MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS, + MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID, + MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED, + MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR, + MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT, + MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, + MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY, + MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY, + MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST, + MD_NTSTATUS_WIN_STATUS_TM_VOLATILE, + MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED, + MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION, + MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME, + MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES, + MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION, + MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK, + MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH, + MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR, + MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED, + MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT, + MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL, + MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT, + MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_FULL, + MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED, + MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL, + MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED, + MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED, + MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY, + MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION, + MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD, + MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST, + MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY, + MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP, + MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT, + MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL, + MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY, + MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION, + MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS, + MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED, + MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED, + MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY, + MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR, + MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK, + MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_INVALID_WINDOW, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VAIL_STATE_CHANGED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION, + MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE, + MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED, + MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED, + MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE, + MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR, + MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK, + MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG, + MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED, + MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER, + MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY, + MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED, + MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY, + MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED, + MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE, + MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED, + MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG, + MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID, + MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE, + MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE, + MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED, + MD_NTSTATUS_WIN_STATUS_FVE_OSV_KSR_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_FWP_IN_USE, + MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION, + MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED, + MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN, + MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER, + MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY, + MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS, + MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED, + MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL, + MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT, + MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS, + MD_NTSTATUS_WIN_STATUS_FWP_RESERVED, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP, + MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT, + MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL, + MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME, + MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON, + MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING, + MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE, + MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND, + MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP, + MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED, + MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED, + MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA, + MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA, + MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE, + MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE, + MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED, + MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT, + MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS, + MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED, + MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE, + MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE, + MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED, + MD_NTSTATUS_WIN_STATUS_NDIS_NO_QUEUES, + MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_QUIC_HANDSHAKE_FAILURE, + MD_NTSTATUS_WIN_STATUS_QUIC_VER_NEG_FAILURE, + MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK, + MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL, + MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE, + MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED, + MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD, + MD_NTSTATUS_WIN_STATUS_TPM_FAIL, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL, + MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC, + MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO, + MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE, + MD_NTSTATUS_WIN_STATUS_TPM_NOSRK, + MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES, + MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM, + MD_NTSTATUS_WIN_STATUS_TPM_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR, + MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL, + MD_NTSTATUS_WIN_STATUS_TPM_BADTAG, + MD_NTSTATUS_WIN_STATUS_TPM_IOERROR, + MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR, + MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE, + MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION, + MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL, + MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE, + MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE, + MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY, + MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION, + MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT, + MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY, + MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY, + MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE, + MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT, + MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE, + MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP, + MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES, + MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN, + MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE, + MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT, + MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS, + MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION, + MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE, + MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY, + MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ASYMMETRIC, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ATTRIBUTES, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HASH, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_VALUE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HIERARCHY, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_MGF, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_MODE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TYPE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KDF, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_RANGE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_FAIL, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NONCE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PP, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SCHEME, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SYMMETRIC, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TAG, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SELECTOR, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INSUFFICIENT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_KEY, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_FAIL, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INTEGRITY, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TICKET, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_RESERVED_BITS, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_AUTH, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXPIRED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY_CC, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BINDING, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_CURVE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_POINT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_INITIALIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_FAILURE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SEQUENCE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PRIVATE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_HMAC, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_DISABLED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_EXCLUSIVE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_ECC_CURVE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_TYPE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_MISSING, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_POLICY, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PCR_CHANGED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_UPGRADE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_TOO_MANY_CONTEXTS, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_REBOOT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_UNBALANCED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_COMMAND_CODE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTHSIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_AUTH_CONTEXT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_RANGE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SIZE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_LOCKED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_AUTHORIZATION, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_UNINITIALIZED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_SPACE, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NV_DEFINED, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_BAD_CONTEXT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_CPHASH, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_PARENT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NEEDS_TEST, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_NO_RESULT, + MD_NTSTATUS_WIN_STATUS_TPM_20_E_SENSITIVE, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED, + MD_NTSTATUS_WIN_STATUS_TPM_RETRY, + MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST, + MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST, + MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED, + MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER, + MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER, + MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED, + MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PCP_WRONG_PARENT, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_LOADED, + MD_NTSTATUS_WIN_STATUS_PCP_NO_KEY_CERTIFICATION, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_FINALIZED, + MD_NTSTATUS_WIN_STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET, + MD_NTSTATUS_WIN_STATUS_PCP_NOT_PCR_BOUND, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_ALREADY_FINALIZED, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_USAGE_POLICY_INVALID, + MD_NTSTATUS_WIN_STATUS_PCP_SOFT_KEY_ERROR, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AUTHENTICATED, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_AIK, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_NOT_SIGNING_KEY, + MD_NTSTATUS_WIN_STATUS_PCP_LOCKED_OUT, + MD_NTSTATUS_WIN_STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_TPM_VERSION_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_LENGTH_MISMATCH, + MD_NTSTATUS_WIN_STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED, + MD_NTSTATUS_WIN_STATUS_PCP_TICKET_MISSING, + MD_NTSTATUS_WIN_STATUS_PCP_RAW_POLICY_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_PCP_KEY_HANDLE_INVALIDATED, + MD_NTSTATUS_WIN_STATUS_RTPM_NO_RESULT, + MD_NTSTATUS_WIN_STATUS_RTPM_PCR_READ_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_RTPM_INVALID_CONTEXT, + MD_NTSTATUS_WIN_STATUS_RTPM_UNSUPPORTED_CMD, + MD_NTSTATUS_WIN_STATUS_TPM_ZERO_EXHAUST_ENABLED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER, + MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED, + MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY, + MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY, + MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_STATE, + MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE, + MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO, + MD_NTSTATUS_WIN_STATUS_HV_NO_DATA, + MD_NTSTATUS_WIN_STATUS_HV_INACTIVE, + MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES, + MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS, + MD_NTSTATUS_WIN_STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR, + MD_NTSTATUS_WIN_STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR, + MD_NTSTATUS_WIN_STATUS_HV_PROCESSOR_STARTUP_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_HV_SMX_ENABLED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_REGISTER_VALUE, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VTL_STATE, + MD_NTSTATUS_WIN_STATUS_HV_NX_NOT_DETECTED, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_ID, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_DEVICE_STATE, + MD_NTSTATUS_WIN_STATUS_HV_PAGE_REQUEST_INVALID, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_ID, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CPU_GROUP_STATE, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_FAILED, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_ROOT_MEMORY, + MD_NTSTATUS_WIN_STATUS_HV_EVENT_BUFFER_ALREADY_FREED, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY, + MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI, + MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED, + MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA, + MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED, + MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET, + MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED, + MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP, + MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP, + MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES, + MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER, + MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS, + MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL, + MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT, + MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED, + MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX, + MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE, + MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE, + MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE, + MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE, + MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED, + MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED, + MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT, + MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET, + MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE, + MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE, + MD_NTSTATUS_WIN_STATUS_VID_VTL_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH, + MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING, + MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS, + MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE, + MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE, + MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE, + MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE, + MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE, + MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_CHANGE_TRACKING_ID, + MD_NTSTATUS_WIN_STATUS_VHD_CHANGE_TRACKING_DISABLED, + MD_NTSTATUS_WIN_STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION, + MD_NTSTATUS_WIN_STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA, + MD_NTSTATUS_WIN_STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE, + MD_NTSTATUS_WIN_STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE, + MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY, + MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL, + MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL, + MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED, + MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY, + MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION, + MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION, + MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION, + MD_NTSTATUS_WIN_STATUS_RDBSS_RETRY_LOOKUP, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UNKNOWN, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_BASE_POLICY, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY, + MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY, + MD_NTSTATUS_WIN_STATUS_VSM_NOT_INITIALIZED, + MD_NTSTATUS_WIN_STATUS_VSM_DMA_PROTECTION_NOT_IN_USE, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_ACTIVATION_TIMEOUT, + MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED, + MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT, + MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE, + MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH, + MD_NTSTATUS_WIN_STATUS_VHD_SHARED, + MD_NTSTATUS_WIN_STATUS_SVHDX_NO_INITIATOR, + MD_NTSTATUS_WIN_STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP, + MD_NTSTATUS_WIN_STATUS_SMB_BAD_CLUSTER_DIALECT, + MD_NTSTATUS_WIN_STATUS_SMB_GUEST_LOGON_BLOCKED, + MD_NTSTATUS_WIN_STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_REDUNDANCY_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES, + MD_NTSTATUS_WIN_STATUS_SPACES_EXTENDED_ERROR, + MD_NTSTATUS_WIN_STATUS_SPACES_PROVISIONING_TYPE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_ALLOCATION_SIZE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_ENCLOSURE_AWARE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_WRITE_CACHE_SIZE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_GROUPS_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_UPDATE_COLUMN_STATE, + MD_NTSTATUS_WIN_STATUS_SPACES_MAP_REQUIRED, + MD_NTSTATUS_WIN_STATUS_SPACES_UNSUPPORTED_VERSION, + MD_NTSTATUS_WIN_STATUS_SPACES_CORRUPT_METADATA, + MD_NTSTATUS_WIN_STATUS_SPACES_DRT_FULL, + MD_NTSTATUS_WIN_STATUS_SPACES_INCONSISTENCY, + MD_NTSTATUS_WIN_STATUS_SPACES_LOG_NOT_READY, + MD_NTSTATUS_WIN_STATUS_SPACES_NO_REDUNDANCY, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_NOT_READY, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SPLIT, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_LOST_DATA, + MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INCOMPLETE, + MD_NTSTATUS_WIN_STATUS_SPACES_ENTRY_INVALID, + MD_NTSTATUS_WIN_STATUS_SPACES_MARK_DIRTY, + MD_NTSTATUS_WIN_STATUS_SECCORE_INVALID_COMMAND, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_INVALID_POLICY, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES, + MD_NTSTATUS_WIN_STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED, + MD_NTSTATUS_WIN_STATUS_NO_APPLICABLE_APP_LICENSES_FOUND, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_CLIP_DEVICE_LICENSE_MISSING, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_INVALID_SIGNATURE, + MD_NTSTATUS_WIN_STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_EXPIRED, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_NOT_SIGNED, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE, + MD_NTSTATUS_WIN_STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_INVALID, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_ACTIVE, + MD_NTSTATUS_WIN_STATUS_PLATFORM_MANIFEST_NOT_SIGNED, + MD_NTSTATUS_WIN_STATUS_APPEXEC_CONDITION_NOT_SATISFIED, + MD_NTSTATUS_WIN_STATUS_APPEXEC_HANDLE_INVALIDATED, + MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_GENERATION, + MD_NTSTATUS_WIN_STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION, + MD_NTSTATUS_WIN_STATUS_APPEXEC_INVALID_HOST_STATE, + MD_NTSTATUS_WIN_STATUS_APPEXEC_NO_DONOR, + MD_NTSTATUS_WIN_STATUS_APPEXEC_HOST_ID_MISMATCH, + MD_NTSTATUS_WIN_STATUS_APPEXEC_UNKNOWN_USER, +}; + +// The content of this array was created from ntstatus.h in the 10 SDK +// (version 10.0.19041.0) with +// +// egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0x[048C][0-9A-F]+L\)' ntstatus.h +// | tr -d '\r' +// | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0x[048C][0-9A-F]+)L\).*@\2 \1@' +// | sort +// | sed -r 's@(0x[048C][0-9A-F]+) ([A-Z_0-9]+)@ "\2",@' +// +// With easy copy to clipboard with +// | xclip -selection c # on linux +// | clip # on windows +// | pbcopy # on mac +static const char* kNTStatusStrings[] = { + "STATUS_SUCCESS", + "STATUS_WAIT_0", + "STATUS_WAIT_1", + "STATUS_WAIT_2", + "STATUS_WAIT_3", + "STATUS_WAIT_63", + "STATUS_ABANDONED", + "STATUS_ABANDONED_WAIT_0", + "STATUS_ABANDONED_WAIT_63", + "STATUS_USER_APC", + "STATUS_ALREADY_COMPLETE", + "STATUS_KERNEL_APC", + "STATUS_ALERTED", + "STATUS_TIMEOUT", + "STATUS_PENDING", + "STATUS_REPARSE", + "STATUS_MORE_ENTRIES", + "STATUS_NOT_ALL_ASSIGNED", + "STATUS_SOME_NOT_MAPPED", + "STATUS_OPLOCK_BREAK_IN_PROGRESS", + "STATUS_VOLUME_MOUNTED", + "STATUS_RXACT_COMMITTED", + "STATUS_NOTIFY_CLEANUP", + "STATUS_NOTIFY_ENUM_DIR", + "STATUS_NO_QUOTAS_FOR_ACCOUNT", + "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED", + "STATUS_PAGE_FAULT_TRANSITION", + "STATUS_PAGE_FAULT_DEMAND_ZERO", + "STATUS_PAGE_FAULT_COPY_ON_WRITE", + "STATUS_PAGE_FAULT_GUARD_PAGE", + "STATUS_PAGE_FAULT_PAGING_FILE", + "STATUS_CACHE_PAGE_LOCKED", + "STATUS_CRASH_DUMP", + "STATUS_BUFFER_ALL_ZEROS", + "STATUS_REPARSE_OBJECT", + "STATUS_RESOURCE_REQUIREMENTS_CHANGED", + "STATUS_TRANSLATION_COMPLETE", + "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY", + "STATUS_NOTHING_TO_TERMINATE", + "STATUS_PROCESS_NOT_IN_JOB", + "STATUS_PROCESS_IN_JOB", + "STATUS_VOLSNAP_HIBERNATE_READY", + "STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY", + "STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED", + "STATUS_INTERRUPT_STILL_CONNECTED", + "STATUS_PROCESS_CLONED", + "STATUS_FILE_LOCKED_WITH_ONLY_READERS", + "STATUS_FILE_LOCKED_WITH_WRITERS", + "STATUS_VALID_IMAGE_HASH", + "STATUS_VALID_CATALOG_HASH", + "STATUS_VALID_STRONG_CODE_HASH", + "STATUS_GHOSTED", + "STATUS_DATA_OVERWRITTEN", + "STATUS_RESOURCEMANAGER_READ_ONLY", + "STATUS_RING_PREVIOUSLY_EMPTY", + "STATUS_RING_PREVIOUSLY_FULL", + "STATUS_RING_PREVIOUSLY_ABOVE_QUOTA", + "STATUS_RING_NEWLY_EMPTY", + "STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT", + "STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE", + "STATUS_OPLOCK_HANDLE_CLOSED", + "STATUS_WAIT_FOR_OPLOCK", + "STATUS_REPARSE_GLOBAL", + "DBG_EXCEPTION_HANDLED", + "DBG_CONTINUE", + "STATUS_FLT_IO_COMPLETE", + "STATUS_RTPM_CONTEXT_CONTINUE", + "STATUS_RTPM_CONTEXT_COMPLETE", + "STATUS_HV_PENDING_PAGE_REQUESTS", + "STATUS_SPACES_REPAIRED", + "STATUS_SPACES_PAUSE", + "STATUS_SPACES_COMPLETE", + "STATUS_SPACES_REDIRECT", + "STATUS_OBJECT_NAME_EXISTS", + "STATUS_THREAD_WAS_SUSPENDED", + "STATUS_WORKING_SET_LIMIT_RANGE", + "STATUS_IMAGE_NOT_AT_BASE", + "STATUS_RXACT_STATE_CREATED", + "STATUS_SEGMENT_NOTIFICATION", + "STATUS_LOCAL_USER_SESSION_KEY", + "STATUS_BAD_CURRENT_DIRECTORY", + "STATUS_SERIAL_MORE_WRITES", + "STATUS_REGISTRY_RECOVERED", + "STATUS_FT_READ_RECOVERY_FROM_BACKUP", + "STATUS_FT_WRITE_RECOVERY", + "STATUS_SERIAL_COUNTER_TIMEOUT", + "STATUS_NULL_LM_PASSWORD", + "STATUS_IMAGE_MACHINE_TYPE_MISMATCH", + "STATUS_RECEIVE_PARTIAL", + "STATUS_RECEIVE_EXPEDITED", + "STATUS_RECEIVE_PARTIAL_EXPEDITED", + "STATUS_EVENT_DONE", + "STATUS_EVENT_PENDING", + "STATUS_CHECKING_FILE_SYSTEM", + "STATUS_FATAL_APP_EXIT", + "STATUS_PREDEFINED_HANDLE", + "STATUS_WAS_UNLOCKED", + "STATUS_SERVICE_NOTIFICATION", + "STATUS_WAS_LOCKED", + "STATUS_LOG_HARD_ERROR", + "STATUS_ALREADY_WIN32", + "STATUS_WX86_UNSIMULATE", + "STATUS_WX86_CONTINUE", + "STATUS_WX86_SINGLE_STEP", + "STATUS_WX86_BREAKPOINT", + "STATUS_WX86_EXCEPTION_CONTINUE", + "STATUS_WX86_EXCEPTION_LASTCHANCE", + "STATUS_WX86_EXCEPTION_CHAIN", + "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE", + "STATUS_NO_YIELD_PERFORMED", + "STATUS_TIMER_RESUME_IGNORED", + "STATUS_ARBITRATION_UNHANDLED", + "STATUS_CARDBUS_NOT_SUPPORTED", + "STATUS_WX86_CREATEWX86TIB", + "STATUS_MP_PROCESSOR_MISMATCH", + "STATUS_HIBERNATED", + "STATUS_RESUME_HIBERNATION", + "STATUS_FIRMWARE_UPDATED", + "STATUS_DRIVERS_LEAKING_LOCKED_PAGES", + "STATUS_MESSAGE_RETRIEVED", + "STATUS_SYSTEM_POWERSTATE_TRANSITION", + "STATUS_ALPC_CHECK_COMPLETION_LIST", + "STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION", + "STATUS_ACCESS_AUDIT_BY_POLICY", + "STATUS_ABANDON_HIBERFILE", + "STATUS_BIZRULES_NOT_ENABLED", + "STATUS_FT_READ_FROM_COPY", + "STATUS_IMAGE_AT_DIFFERENT_BASE", + "STATUS_PATCH_DEFERRED", + "STATUS_WAKE_SYSTEM", + "STATUS_DS_SHUTTING_DOWN", + "STATUS_DISK_REPAIR_REDIRECTED", + "STATUS_SERVICES_FAILED_AUTOSTART", + "DBG_REPLY_LATER", + "DBG_UNABLE_TO_PROVIDE_HANDLE", + "DBG_TERMINATE_THREAD", + "DBG_TERMINATE_PROCESS", + "DBG_CONTROL_C", + "DBG_PRINTEXCEPTION_C", + "DBG_RIPEXCEPTION", + "DBG_CONTROL_BREAK", + "DBG_COMMAND_EXCEPTION", + "DBG_PRINTEXCEPTION_WIDE_C", + "RPC_NT_UUID_LOCAL_ONLY", + "RPC_NT_SEND_INCOMPLETE", + "STATUS_CTX_CDM_CONNECT", + "STATUS_CTX_CDM_DISCONNECT", + "STATUS_SXS_RELEASE_ACTIVATION_CONTEXT", + "STATUS_HEURISTIC_DAMAGE_POSSIBLE", + "STATUS_RECOVERY_NOT_NEEDED", + "STATUS_RM_ALREADY_STARTED", + "STATUS_LOG_NO_RESTART", + "STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST", + "STATUS_GRAPHICS_PARTIAL_DATA_POPULATED", + "STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION", + "STATUS_GRAPHICS_MODE_NOT_PINNED", + "STATUS_GRAPHICS_NO_PREFERRED_MODE", + "STATUS_GRAPHICS_DATASET_IS_EMPTY", + "STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET", + "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED", + "STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS", + "STATUS_GRAPHICS_LEADLINK_START_DEFERRED", + "STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY", + "STATUS_GRAPHICS_START_DEFERRED", + "STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS", + "STATUS_NDIS_INDICATION_REQUIRED", + "STATUS_PCP_UNSUPPORTED_PSS_SALT", + "STATUS_GUARD_PAGE_VIOLATION", + "STATUS_DATATYPE_MISALIGNMENT", + "STATUS_BREAKPOINT", + "STATUS_SINGLE_STEP", + "STATUS_BUFFER_OVERFLOW", + "STATUS_NO_MORE_FILES", + "STATUS_WAKE_SYSTEM_DEBUGGER", + "STATUS_HANDLES_CLOSED", + "STATUS_NO_INHERITANCE", + "STATUS_GUID_SUBSTITUTION_MADE", + "STATUS_PARTIAL_COPY", + "STATUS_DEVICE_PAPER_EMPTY", + "STATUS_DEVICE_POWERED_OFF", + "STATUS_DEVICE_OFF_LINE", + "STATUS_DEVICE_BUSY", + "STATUS_NO_MORE_EAS", + "STATUS_INVALID_EA_NAME", + "STATUS_EA_LIST_INCONSISTENT", + "STATUS_INVALID_EA_FLAG", + "STATUS_VERIFY_REQUIRED", + "STATUS_EXTRANEOUS_INFORMATION", + "STATUS_RXACT_COMMIT_NECESSARY", + "STATUS_NO_MORE_ENTRIES", + "STATUS_FILEMARK_DETECTED", + "STATUS_MEDIA_CHANGED", + "STATUS_BUS_RESET", + "STATUS_END_OF_MEDIA", + "STATUS_BEGINNING_OF_MEDIA", + "STATUS_MEDIA_CHECK", + "STATUS_SETMARK_DETECTED", + "STATUS_NO_DATA_DETECTED", + "STATUS_REDIRECTOR_HAS_OPEN_HANDLES", + "STATUS_SERVER_HAS_OPEN_HANDLES", + "STATUS_ALREADY_DISCONNECTED", + "STATUS_LONGJUMP", + "STATUS_CLEANER_CARTRIDGE_INSTALLED", + "STATUS_PLUGPLAY_QUERY_VETOED", + "STATUS_UNWIND_CONSOLIDATE", + "STATUS_REGISTRY_HIVE_RECOVERED", + "STATUS_DLL_MIGHT_BE_INSECURE", + "STATUS_DLL_MIGHT_BE_INCOMPATIBLE", + "STATUS_STOPPED_ON_SYMLINK", + "STATUS_CANNOT_GRANT_REQUESTED_OPLOCK", + "STATUS_NO_ACE_CONDITION", + "STATUS_DEVICE_SUPPORT_IN_PROGRESS", + "STATUS_DEVICE_POWER_CYCLE_REQUIRED", + "STATUS_NO_WORK_DONE", + "STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT", + "STATUS_DEVICE_REQUIRES_CLEANING", + "STATUS_DEVICE_DOOR_OPEN", + "STATUS_DATA_LOST_REPAIR", + "STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED", + "STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH", + "STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE", + "STATUS_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS", + "DBG_EXCEPTION_NOT_HANDLED", + "STATUS_CLUSTER_NODE_ALREADY_UP", + "STATUS_CLUSTER_NODE_ALREADY_DOWN", + "STATUS_CLUSTER_NETWORK_ALREADY_ONLINE", + "STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE", + "STATUS_CLUSTER_NODE_ALREADY_MEMBER", + "STATUS_COULD_NOT_RESIZE_LOG", + "STATUS_NO_TXF_METADATA", + "STATUS_CANT_RECOVER_WITH_HANDLE_OPEN", + "STATUS_TXF_METADATA_ALREADY_PRESENT", + "STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET", + "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED", + "STATUS_FLT_BUFFER_TOO_SMALL", + "STATUS_FVE_PARTIAL_METADATA", + "STATUS_FVE_TRANSIENT_STATE", + "STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED", + "STATUS_VOLMGR_INCOMPLETE_REGENERATION", + "STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION", + "STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED", + "STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED", + "STATUS_QUERY_STORAGE_ERROR", + "STATUS_GDI_HANDLE_LEAK", + "STATUS_SECUREBOOT_NOT_ENABLED", + "STATUS_UNSUCCESSFUL", + "STATUS_NOT_IMPLEMENTED", + "STATUS_INVALID_INFO_CLASS", + "STATUS_INFO_LENGTH_MISMATCH", + "STATUS_ACCESS_VIOLATION", + "STATUS_IN_PAGE_ERROR", + "STATUS_PAGEFILE_QUOTA", + "STATUS_INVALID_HANDLE", + "STATUS_BAD_INITIAL_STACK", + "STATUS_BAD_INITIAL_PC", + "STATUS_INVALID_CID", + "STATUS_TIMER_NOT_CANCELED", + "STATUS_INVALID_PARAMETER", + "STATUS_NO_SUCH_DEVICE", + "STATUS_NO_SUCH_FILE", + "STATUS_INVALID_DEVICE_REQUEST", + "STATUS_END_OF_FILE", + "STATUS_WRONG_VOLUME", + "STATUS_NO_MEDIA_IN_DEVICE", + "STATUS_UNRECOGNIZED_MEDIA", + "STATUS_NONEXISTENT_SECTOR", + "STATUS_MORE_PROCESSING_REQUIRED", + "STATUS_NO_MEMORY", + "STATUS_CONFLICTING_ADDRESSES", + "STATUS_NOT_MAPPED_VIEW", + "STATUS_UNABLE_TO_FREE_VM", + "STATUS_UNABLE_TO_DELETE_SECTION", + "STATUS_INVALID_SYSTEM_SERVICE", + "STATUS_ILLEGAL_INSTRUCTION", + "STATUS_INVALID_LOCK_SEQUENCE", + "STATUS_INVALID_VIEW_SIZE", + "STATUS_INVALID_FILE_FOR_SECTION", + "STATUS_ALREADY_COMMITTED", + "STATUS_ACCESS_DENIED", + "STATUS_BUFFER_TOO_SMALL", + "STATUS_OBJECT_TYPE_MISMATCH", + "STATUS_NONCONTINUABLE_EXCEPTION", + "STATUS_INVALID_DISPOSITION", + "STATUS_UNWIND", + "STATUS_BAD_STACK", + "STATUS_INVALID_UNWIND_TARGET", + "STATUS_NOT_LOCKED", + "STATUS_PARITY_ERROR", + "STATUS_UNABLE_TO_DECOMMIT_VM", + "STATUS_NOT_COMMITTED", + "STATUS_INVALID_PORT_ATTRIBUTES", + "STATUS_PORT_MESSAGE_TOO_LONG", + "STATUS_INVALID_PARAMETER_MIX", + "STATUS_INVALID_QUOTA_LOWER", + "STATUS_DISK_CORRUPT_ERROR", + "STATUS_OBJECT_NAME_INVALID", + "STATUS_OBJECT_NAME_NOT_FOUND", + "STATUS_OBJECT_NAME_COLLISION", + "STATUS_PORT_DO_NOT_DISTURB", + "STATUS_PORT_DISCONNECTED", + "STATUS_DEVICE_ALREADY_ATTACHED", + "STATUS_OBJECT_PATH_INVALID", + "STATUS_OBJECT_PATH_NOT_FOUND", + "STATUS_OBJECT_PATH_SYNTAX_BAD", + "STATUS_DATA_OVERRUN", + "STATUS_DATA_LATE_ERROR", + "STATUS_DATA_ERROR", + "STATUS_CRC_ERROR", + "STATUS_SECTION_TOO_BIG", + "STATUS_PORT_CONNECTION_REFUSED", + "STATUS_INVALID_PORT_HANDLE", + "STATUS_SHARING_VIOLATION", + "STATUS_QUOTA_EXCEEDED", + "STATUS_INVALID_PAGE_PROTECTION", + "STATUS_MUTANT_NOT_OWNED", + "STATUS_SEMAPHORE_LIMIT_EXCEEDED", + "STATUS_PORT_ALREADY_SET", + "STATUS_SECTION_NOT_IMAGE", + "STATUS_SUSPEND_COUNT_EXCEEDED", + "STATUS_THREAD_IS_TERMINATING", + "STATUS_BAD_WORKING_SET_LIMIT", + "STATUS_INCOMPATIBLE_FILE_MAP", + "STATUS_SECTION_PROTECTION", + "STATUS_EAS_NOT_SUPPORTED", + "STATUS_EA_TOO_LARGE", + "STATUS_NONEXISTENT_EA_ENTRY", + "STATUS_NO_EAS_ON_FILE", + "STATUS_EA_CORRUPT_ERROR", + "STATUS_FILE_LOCK_CONFLICT", + "STATUS_LOCK_NOT_GRANTED", + "STATUS_DELETE_PENDING", + "STATUS_CTL_FILE_NOT_SUPPORTED", + "STATUS_UNKNOWN_REVISION", + "STATUS_REVISION_MISMATCH", + "STATUS_INVALID_OWNER", + "STATUS_INVALID_PRIMARY_GROUP", + "STATUS_NO_IMPERSONATION_TOKEN", + "STATUS_CANT_DISABLE_MANDATORY", + "STATUS_NO_LOGON_SERVERS", + "STATUS_NO_SUCH_LOGON_SESSION", + "STATUS_NO_SUCH_PRIVILEGE", + "STATUS_PRIVILEGE_NOT_HELD", + "STATUS_INVALID_ACCOUNT_NAME", + "STATUS_USER_EXISTS", + "STATUS_NO_SUCH_USER", + "STATUS_GROUP_EXISTS", + "STATUS_NO_SUCH_GROUP", + "STATUS_MEMBER_IN_GROUP", + "STATUS_MEMBER_NOT_IN_GROUP", + "STATUS_LAST_ADMIN", + "STATUS_WRONG_PASSWORD", + "STATUS_ILL_FORMED_PASSWORD", + "STATUS_PASSWORD_RESTRICTION", + "STATUS_LOGON_FAILURE", + "STATUS_ACCOUNT_RESTRICTION", + "STATUS_INVALID_LOGON_HOURS", + "STATUS_INVALID_WORKSTATION", + "STATUS_PASSWORD_EXPIRED", + "STATUS_ACCOUNT_DISABLED", + "STATUS_NONE_MAPPED", + "STATUS_TOO_MANY_LUIDS_REQUESTED", + "STATUS_LUIDS_EXHAUSTED", + "STATUS_INVALID_SUB_AUTHORITY", + "STATUS_INVALID_ACL", + "STATUS_INVALID_SID", + "STATUS_INVALID_SECURITY_DESCR", + "STATUS_PROCEDURE_NOT_FOUND", + "STATUS_INVALID_IMAGE_FORMAT", + "STATUS_NO_TOKEN", + "STATUS_BAD_INHERITANCE_ACL", + "STATUS_RANGE_NOT_LOCKED", + "STATUS_DISK_FULL", + "STATUS_SERVER_DISABLED", + "STATUS_SERVER_NOT_DISABLED", + "STATUS_TOO_MANY_GUIDS_REQUESTED", + "STATUS_GUIDS_EXHAUSTED", + "STATUS_INVALID_ID_AUTHORITY", + "STATUS_AGENTS_EXHAUSTED", + "STATUS_INVALID_VOLUME_LABEL", + "STATUS_SECTION_NOT_EXTENDED", + "STATUS_NOT_MAPPED_DATA", + "STATUS_RESOURCE_DATA_NOT_FOUND", + "STATUS_RESOURCE_TYPE_NOT_FOUND", + "STATUS_RESOURCE_NAME_NOT_FOUND", + "STATUS_ARRAY_BOUNDS_EXCEEDED", + "STATUS_FLOAT_DENORMAL_OPERAND", + "STATUS_FLOAT_DIVIDE_BY_ZERO", + "STATUS_FLOAT_INEXACT_RESULT", + "STATUS_FLOAT_INVALID_OPERATION", + "STATUS_FLOAT_OVERFLOW", + "STATUS_FLOAT_STACK_CHECK", + "STATUS_FLOAT_UNDERFLOW", + "STATUS_INTEGER_DIVIDE_BY_ZERO", + "STATUS_INTEGER_OVERFLOW", + "STATUS_PRIVILEGED_INSTRUCTION", + "STATUS_TOO_MANY_PAGING_FILES", + "STATUS_FILE_INVALID", + "STATUS_ALLOTTED_SPACE_EXCEEDED", + "STATUS_INSUFFICIENT_RESOURCES", + "STATUS_DFS_EXIT_PATH_FOUND", + "STATUS_DEVICE_DATA_ERROR", + "STATUS_DEVICE_NOT_CONNECTED", + "STATUS_DEVICE_POWER_FAILURE", + "STATUS_FREE_VM_NOT_AT_BASE", + "STATUS_MEMORY_NOT_ALLOCATED", + "STATUS_WORKING_SET_QUOTA", + "STATUS_MEDIA_WRITE_PROTECTED", + "STATUS_DEVICE_NOT_READY", + "STATUS_INVALID_GROUP_ATTRIBUTES", + "STATUS_BAD_IMPERSONATION_LEVEL", + "STATUS_CANT_OPEN_ANONYMOUS", + "STATUS_BAD_VALIDATION_CLASS", + "STATUS_BAD_TOKEN_TYPE", + "STATUS_BAD_MASTER_BOOT_RECORD", + "STATUS_INSTRUCTION_MISALIGNMENT", + "STATUS_INSTANCE_NOT_AVAILABLE", + "STATUS_PIPE_NOT_AVAILABLE", + "STATUS_INVALID_PIPE_STATE", + "STATUS_PIPE_BUSY", + "STATUS_ILLEGAL_FUNCTION", + "STATUS_PIPE_DISCONNECTED", + "STATUS_PIPE_CLOSING", + "STATUS_PIPE_CONNECTED", + "STATUS_PIPE_LISTENING", + "STATUS_INVALID_READ_MODE", + "STATUS_IO_TIMEOUT", + "STATUS_FILE_FORCED_CLOSED", + "STATUS_PROFILING_NOT_STARTED", + "STATUS_PROFILING_NOT_STOPPED", + "STATUS_COULD_NOT_INTERPRET", + "STATUS_FILE_IS_A_DIRECTORY", + "STATUS_NOT_SUPPORTED", + "STATUS_REMOTE_NOT_LISTENING", + "STATUS_DUPLICATE_NAME", + "STATUS_BAD_NETWORK_PATH", + "STATUS_NETWORK_BUSY", + "STATUS_DEVICE_DOES_NOT_EXIST", + "STATUS_TOO_MANY_COMMANDS", + "STATUS_ADAPTER_HARDWARE_ERROR", + "STATUS_INVALID_NETWORK_RESPONSE", + "STATUS_UNEXPECTED_NETWORK_ERROR", + "STATUS_BAD_REMOTE_ADAPTER", + "STATUS_PRINT_QUEUE_FULL", + "STATUS_NO_SPOOL_SPACE", + "STATUS_PRINT_CANCELLED", + "STATUS_NETWORK_NAME_DELETED", + "STATUS_NETWORK_ACCESS_DENIED", + "STATUS_BAD_DEVICE_TYPE", + "STATUS_BAD_NETWORK_NAME", + "STATUS_TOO_MANY_NAMES", + "STATUS_TOO_MANY_SESSIONS", + "STATUS_SHARING_PAUSED", + "STATUS_REQUEST_NOT_ACCEPTED", + "STATUS_REDIRECTOR_PAUSED", + "STATUS_NET_WRITE_FAULT", + "STATUS_PROFILING_AT_LIMIT", + "STATUS_NOT_SAME_DEVICE", + "STATUS_FILE_RENAMED", + "STATUS_VIRTUAL_CIRCUIT_CLOSED", + "STATUS_NO_SECURITY_ON_OBJECT", + "STATUS_CANT_WAIT", + "STATUS_PIPE_EMPTY", + "STATUS_CANT_ACCESS_DOMAIN_INFO", + "STATUS_CANT_TERMINATE_SELF", + "STATUS_INVALID_SERVER_STATE", + "STATUS_INVALID_DOMAIN_STATE", + "STATUS_INVALID_DOMAIN_ROLE", + "STATUS_NO_SUCH_DOMAIN", + "STATUS_DOMAIN_EXISTS", + "STATUS_DOMAIN_LIMIT_EXCEEDED", + "STATUS_OPLOCK_NOT_GRANTED", + "STATUS_INVALID_OPLOCK_PROTOCOL", + "STATUS_INTERNAL_DB_CORRUPTION", + "STATUS_INTERNAL_ERROR", + "STATUS_GENERIC_NOT_MAPPED", + "STATUS_BAD_DESCRIPTOR_FORMAT", + "STATUS_INVALID_USER_BUFFER", + "STATUS_UNEXPECTED_IO_ERROR", + "STATUS_UNEXPECTED_MM_CREATE_ERR", + "STATUS_UNEXPECTED_MM_MAP_ERROR", + "STATUS_UNEXPECTED_MM_EXTEND_ERR", + "STATUS_NOT_LOGON_PROCESS", + "STATUS_LOGON_SESSION_EXISTS", + "STATUS_INVALID_PARAMETER_1", + "STATUS_INVALID_PARAMETER_2", + "STATUS_INVALID_PARAMETER_3", + "STATUS_INVALID_PARAMETER_4", + "STATUS_INVALID_PARAMETER_5", + "STATUS_INVALID_PARAMETER_6", + "STATUS_INVALID_PARAMETER_7", + "STATUS_INVALID_PARAMETER_8", + "STATUS_INVALID_PARAMETER_9", + "STATUS_INVALID_PARAMETER_10", + "STATUS_INVALID_PARAMETER_11", + "STATUS_INVALID_PARAMETER_12", + "STATUS_REDIRECTOR_NOT_STARTED", + "STATUS_REDIRECTOR_STARTED", + "STATUS_STACK_OVERFLOW", + "STATUS_NO_SUCH_PACKAGE", + "STATUS_BAD_FUNCTION_TABLE", + "STATUS_VARIABLE_NOT_FOUND", + "STATUS_DIRECTORY_NOT_EMPTY", + "STATUS_FILE_CORRUPT_ERROR", + "STATUS_NOT_A_DIRECTORY", + "STATUS_BAD_LOGON_SESSION_STATE", + "STATUS_LOGON_SESSION_COLLISION", + "STATUS_NAME_TOO_LONG", + "STATUS_FILES_OPEN", + "STATUS_CONNECTION_IN_USE", + "STATUS_MESSAGE_NOT_FOUND", + "STATUS_PROCESS_IS_TERMINATING", + "STATUS_INVALID_LOGON_TYPE", + "STATUS_NO_GUID_TRANSLATION", + "STATUS_CANNOT_IMPERSONATE", + "STATUS_IMAGE_ALREADY_LOADED", + "STATUS_ABIOS_NOT_PRESENT", + "STATUS_ABIOS_LID_NOT_EXIST", + "STATUS_ABIOS_LID_ALREADY_OWNED", + "STATUS_ABIOS_NOT_LID_OWNER", + "STATUS_ABIOS_INVALID_COMMAND", + "STATUS_ABIOS_INVALID_LID", + "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", + "STATUS_ABIOS_INVALID_SELECTOR", + "STATUS_NO_LDT", + "STATUS_INVALID_LDT_SIZE", + "STATUS_INVALID_LDT_OFFSET", + "STATUS_INVALID_LDT_DESCRIPTOR", + "STATUS_INVALID_IMAGE_NE_FORMAT", + "STATUS_RXACT_INVALID_STATE", + "STATUS_RXACT_COMMIT_FAILURE", + "STATUS_MAPPED_FILE_SIZE_ZERO", + "STATUS_TOO_MANY_OPENED_FILES", + "STATUS_CANCELLED", + "STATUS_CANNOT_DELETE", + "STATUS_INVALID_COMPUTER_NAME", + "STATUS_FILE_DELETED", + "STATUS_SPECIAL_ACCOUNT", + "STATUS_SPECIAL_GROUP", + "STATUS_SPECIAL_USER", + "STATUS_MEMBERS_PRIMARY_GROUP", + "STATUS_FILE_CLOSED", + "STATUS_TOO_MANY_THREADS", + "STATUS_THREAD_NOT_IN_PROCESS", + "STATUS_TOKEN_ALREADY_IN_USE", + "STATUS_PAGEFILE_QUOTA_EXCEEDED", + "STATUS_COMMITMENT_LIMIT", + "STATUS_INVALID_IMAGE_LE_FORMAT", + "STATUS_INVALID_IMAGE_NOT_MZ", + "STATUS_INVALID_IMAGE_PROTECT", + "STATUS_INVALID_IMAGE_WIN_16", + "STATUS_LOGON_SERVER_CONFLICT", + "STATUS_TIME_DIFFERENCE_AT_DC", + "STATUS_SYNCHRONIZATION_REQUIRED", + "STATUS_DLL_NOT_FOUND", + "STATUS_OPEN_FAILED", + "STATUS_IO_PRIVILEGE_FAILED", + "STATUS_ORDINAL_NOT_FOUND", + "STATUS_ENTRYPOINT_NOT_FOUND", + "STATUS_CONTROL_C_EXIT", + "STATUS_LOCAL_DISCONNECT", + "STATUS_REMOTE_DISCONNECT", + "STATUS_REMOTE_RESOURCES", + "STATUS_LINK_FAILED", + "STATUS_LINK_TIMEOUT", + "STATUS_INVALID_CONNECTION", + "STATUS_INVALID_ADDRESS", + "STATUS_DLL_INIT_FAILED", + "STATUS_MISSING_SYSTEMFILE", + "STATUS_UNHANDLED_EXCEPTION", + "STATUS_APP_INIT_FAILURE", + "STATUS_PAGEFILE_CREATE_FAILED", + "STATUS_NO_PAGEFILE", + "STATUS_INVALID_LEVEL", + "STATUS_WRONG_PASSWORD_CORE", + "STATUS_ILLEGAL_FLOAT_CONTEXT", + "STATUS_PIPE_BROKEN", + "STATUS_REGISTRY_CORRUPT", + "STATUS_REGISTRY_IO_FAILED", + "STATUS_NO_EVENT_PAIR", + "STATUS_UNRECOGNIZED_VOLUME", + "STATUS_SERIAL_NO_DEVICE_INITED", + "STATUS_NO_SUCH_ALIAS", + "STATUS_MEMBER_NOT_IN_ALIAS", + "STATUS_MEMBER_IN_ALIAS", + "STATUS_ALIAS_EXISTS", + "STATUS_LOGON_NOT_GRANTED", + "STATUS_TOO_MANY_SECRETS", + "STATUS_SECRET_TOO_LONG", + "STATUS_INTERNAL_DB_ERROR", + "STATUS_FULLSCREEN_MODE", + "STATUS_TOO_MANY_CONTEXT_IDS", + "STATUS_LOGON_TYPE_NOT_GRANTED", + "STATUS_NOT_REGISTRY_FILE", + "STATUS_NT_CROSS_ENCRYPTION_REQUIRED", + "STATUS_DOMAIN_CTRLR_CONFIG_ERROR", + "STATUS_FT_MISSING_MEMBER", + "STATUS_ILL_FORMED_SERVICE_ENTRY", + "STATUS_ILLEGAL_CHARACTER", + "STATUS_UNMAPPABLE_CHARACTER", + "STATUS_UNDEFINED_CHARACTER", + "STATUS_FLOPPY_VOLUME", + "STATUS_FLOPPY_ID_MARK_NOT_FOUND", + "STATUS_FLOPPY_WRONG_CYLINDER", + "STATUS_FLOPPY_UNKNOWN_ERROR", + "STATUS_FLOPPY_BAD_REGISTERS", + "STATUS_DISK_RECALIBRATE_FAILED", + "STATUS_DISK_OPERATION_FAILED", + "STATUS_DISK_RESET_FAILED", + "STATUS_SHARED_IRQ_BUSY", + "STATUS_FT_ORPHANING", + "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT", + "STATUS_PARTITION_FAILURE", + "STATUS_INVALID_BLOCK_LENGTH", + "STATUS_DEVICE_NOT_PARTITIONED", + "STATUS_UNABLE_TO_LOCK_MEDIA", + "STATUS_UNABLE_TO_UNLOAD_MEDIA", + "STATUS_EOM_OVERFLOW", + "STATUS_NO_MEDIA", + "STATUS_NO_SUCH_MEMBER", + "STATUS_INVALID_MEMBER", + "STATUS_KEY_DELETED", + "STATUS_NO_LOG_SPACE", + "STATUS_TOO_MANY_SIDS", + "STATUS_LM_CROSS_ENCRYPTION_REQUIRED", + "STATUS_KEY_HAS_CHILDREN", + "STATUS_CHILD_MUST_BE_VOLATILE", + "STATUS_DEVICE_CONFIGURATION_ERROR", + "STATUS_DRIVER_INTERNAL_ERROR", + "STATUS_INVALID_DEVICE_STATE", + "STATUS_IO_DEVICE_ERROR", + "STATUS_DEVICE_PROTOCOL_ERROR", + "STATUS_BACKUP_CONTROLLER", + "STATUS_LOG_FILE_FULL", + "STATUS_TOO_LATE", + "STATUS_NO_TRUST_LSA_SECRET", + "STATUS_NO_TRUST_SAM_ACCOUNT", + "STATUS_TRUSTED_DOMAIN_FAILURE", + "STATUS_TRUSTED_RELATIONSHIP_FAILURE", + "STATUS_EVENTLOG_FILE_CORRUPT", + "STATUS_EVENTLOG_CANT_START", + "STATUS_TRUST_FAILURE", + "STATUS_MUTANT_LIMIT_EXCEEDED", + "STATUS_NETLOGON_NOT_STARTED", + "STATUS_ACCOUNT_EXPIRED", + "STATUS_POSSIBLE_DEADLOCK", + "STATUS_NETWORK_CREDENTIAL_CONFLICT", + "STATUS_REMOTE_SESSION_LIMIT", + "STATUS_EVENTLOG_FILE_CHANGED", + "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", + "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", + "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", + "STATUS_DOMAIN_TRUST_INCONSISTENT", + "STATUS_FS_DRIVER_REQUIRED", + "STATUS_IMAGE_ALREADY_LOADED_AS_DLL", + "STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING", + "STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME", + "STATUS_SECURITY_STREAM_IS_INCONSISTENT", + "STATUS_INVALID_LOCK_RANGE", + "STATUS_INVALID_ACE_CONDITION", + "STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT", + "STATUS_NOTIFICATION_GUID_ALREADY_DEFINED", + "STATUS_INVALID_EXCEPTION_HANDLER", + "STATUS_DUPLICATE_PRIVILEGES", + "STATUS_NOT_ALLOWED_ON_SYSTEM_FILE", + "STATUS_REPAIR_NEEDED", + "STATUS_QUOTA_NOT_ENABLED", + "STATUS_NO_APPLICATION_PACKAGE", + "STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS", + "STATUS_NOT_SAME_OBJECT", + "STATUS_FATAL_MEMORY_EXHAUSTION", + "STATUS_ERROR_PROCESS_NOT_IN_JOB", + "STATUS_CPU_SET_INVALID", + "STATUS_IO_DEVICE_INVALID_DATA", + "STATUS_IO_UNALIGNED_WRITE", + "STATUS_CONTROL_STACK_VIOLATION", + "STATUS_NETWORK_OPEN_RESTRICTION", + "STATUS_NO_USER_SESSION_KEY", + "STATUS_USER_SESSION_DELETED", + "STATUS_RESOURCE_LANG_NOT_FOUND", + "STATUS_INSUFF_SERVER_RESOURCES", + "STATUS_INVALID_BUFFER_SIZE", + "STATUS_INVALID_ADDRESS_COMPONENT", + "STATUS_INVALID_ADDRESS_WILDCARD", + "STATUS_TOO_MANY_ADDRESSES", + "STATUS_ADDRESS_ALREADY_EXISTS", + "STATUS_ADDRESS_CLOSED", + "STATUS_CONNECTION_DISCONNECTED", + "STATUS_CONNECTION_RESET", + "STATUS_TOO_MANY_NODES", + "STATUS_TRANSACTION_ABORTED", + "STATUS_TRANSACTION_TIMED_OUT", + "STATUS_TRANSACTION_NO_RELEASE", + "STATUS_TRANSACTION_NO_MATCH", + "STATUS_TRANSACTION_RESPONDED", + "STATUS_TRANSACTION_INVALID_ID", + "STATUS_TRANSACTION_INVALID_TYPE", + "STATUS_NOT_SERVER_SESSION", + "STATUS_NOT_CLIENT_SESSION", + "STATUS_CANNOT_LOAD_REGISTRY_FILE", + "STATUS_DEBUG_ATTACH_FAILED", + "STATUS_SYSTEM_PROCESS_TERMINATED", + "STATUS_DATA_NOT_ACCEPTED", + "STATUS_NO_BROWSER_SERVERS_FOUND", + "STATUS_VDM_HARD_ERROR", + "STATUS_DRIVER_CANCEL_TIMEOUT", + "STATUS_REPLY_MESSAGE_MISMATCH", + "STATUS_MAPPED_ALIGNMENT", + "STATUS_IMAGE_CHECKSUM_MISMATCH", + "STATUS_LOST_WRITEBEHIND_DATA", + "STATUS_CLIENT_SERVER_PARAMETERS_INVALID", + "STATUS_PASSWORD_MUST_CHANGE", + "STATUS_NOT_FOUND", + "STATUS_NOT_TINY_STREAM", + "STATUS_RECOVERY_FAILURE", + "STATUS_STACK_OVERFLOW_READ", + "STATUS_FAIL_CHECK", + "STATUS_DUPLICATE_OBJECTID", + "STATUS_OBJECTID_EXISTS", + "STATUS_CONVERT_TO_LARGE", + "STATUS_RETRY", + "STATUS_FOUND_OUT_OF_SCOPE", + "STATUS_ALLOCATE_BUCKET", + "STATUS_PROPSET_NOT_FOUND", + "STATUS_MARSHALL_OVERFLOW", + "STATUS_INVALID_VARIANT", + "STATUS_DOMAIN_CONTROLLER_NOT_FOUND", + "STATUS_ACCOUNT_LOCKED_OUT", + "STATUS_HANDLE_NOT_CLOSABLE", + "STATUS_CONNECTION_REFUSED", + "STATUS_GRACEFUL_DISCONNECT", + "STATUS_ADDRESS_ALREADY_ASSOCIATED", + "STATUS_ADDRESS_NOT_ASSOCIATED", + "STATUS_CONNECTION_INVALID", + "STATUS_CONNECTION_ACTIVE", + "STATUS_NETWORK_UNREACHABLE", + "STATUS_HOST_UNREACHABLE", + "STATUS_PROTOCOL_UNREACHABLE", + "STATUS_PORT_UNREACHABLE", + "STATUS_REQUEST_ABORTED", + "STATUS_CONNECTION_ABORTED", + "STATUS_BAD_COMPRESSION_BUFFER", + "STATUS_USER_MAPPED_FILE", + "STATUS_AUDIT_FAILED", + "STATUS_TIMER_RESOLUTION_NOT_SET", + "STATUS_CONNECTION_COUNT_LIMIT", + "STATUS_LOGIN_TIME_RESTRICTION", + "STATUS_LOGIN_WKSTA_RESTRICTION", + "STATUS_IMAGE_MP_UP_MISMATCH", + "STATUS_INSUFFICIENT_LOGON_INFO", + "STATUS_BAD_DLL_ENTRYPOINT", + "STATUS_BAD_SERVICE_ENTRYPOINT", + "STATUS_LPC_REPLY_LOST", + "STATUS_IP_ADDRESS_CONFLICT1", + "STATUS_IP_ADDRESS_CONFLICT2", + "STATUS_REGISTRY_QUOTA_LIMIT", + "STATUS_PATH_NOT_COVERED", + "STATUS_NO_CALLBACK_ACTIVE", + "STATUS_LICENSE_QUOTA_EXCEEDED", + "STATUS_PWD_TOO_SHORT", + "STATUS_PWD_TOO_RECENT", + "STATUS_PWD_HISTORY_CONFLICT", + "STATUS_PLUGPLAY_NO_DEVICE", + "STATUS_UNSUPPORTED_COMPRESSION", + "STATUS_INVALID_HW_PROFILE", + "STATUS_INVALID_PLUGPLAY_DEVICE_PATH", + "STATUS_DRIVER_ORDINAL_NOT_FOUND", + "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", + "STATUS_RESOURCE_NOT_OWNED", + "STATUS_TOO_MANY_LINKS", + "STATUS_QUOTA_LIST_INCONSISTENT", + "STATUS_FILE_IS_OFFLINE", + "STATUS_EVALUATION_EXPIRATION", + "STATUS_ILLEGAL_DLL_RELOCATION", + "STATUS_LICENSE_VIOLATION", + "STATUS_DLL_INIT_FAILED_LOGOFF", + "STATUS_DRIVER_UNABLE_TO_LOAD", + "STATUS_DFS_UNAVAILABLE", + "STATUS_VOLUME_DISMOUNTED", + "STATUS_WX86_INTERNAL_ERROR", + "STATUS_WX86_FLOAT_STACK_CHECK", + "STATUS_VALIDATE_CONTINUE", + "STATUS_NO_MATCH", + "STATUS_NO_MORE_MATCHES", + "STATUS_NOT_A_REPARSE_POINT", + "STATUS_IO_REPARSE_TAG_INVALID", + "STATUS_IO_REPARSE_TAG_MISMATCH", + "STATUS_IO_REPARSE_DATA_INVALID", + "STATUS_IO_REPARSE_TAG_NOT_HANDLED", + "STATUS_PWD_TOO_LONG", + "STATUS_STOWED_EXCEPTION", + "STATUS_CONTEXT_STOWED_EXCEPTION", + "STATUS_REPARSE_POINT_NOT_RESOLVED", + "STATUS_DIRECTORY_IS_A_REPARSE_POINT", + "STATUS_RANGE_LIST_CONFLICT", + "STATUS_SOURCE_ELEMENT_EMPTY", + "STATUS_DESTINATION_ELEMENT_FULL", + "STATUS_ILLEGAL_ELEMENT_ADDRESS", + "STATUS_MAGAZINE_NOT_PRESENT", + "STATUS_REINITIALIZATION_NEEDED", + "STATUS_ENCRYPTION_FAILED", + "STATUS_DECRYPTION_FAILED", + "STATUS_RANGE_NOT_FOUND", + "STATUS_NO_RECOVERY_POLICY", + "STATUS_NO_EFS", + "STATUS_WRONG_EFS", + "STATUS_NO_USER_KEYS", + "STATUS_FILE_NOT_ENCRYPTED", + "STATUS_NOT_EXPORT_FORMAT", + "STATUS_FILE_ENCRYPTED", + "STATUS_WMI_GUID_NOT_FOUND", + "STATUS_WMI_INSTANCE_NOT_FOUND", + "STATUS_WMI_ITEMID_NOT_FOUND", + "STATUS_WMI_TRY_AGAIN", + "STATUS_SHARED_POLICY", + "STATUS_POLICY_OBJECT_NOT_FOUND", + "STATUS_POLICY_ONLY_IN_DS", + "STATUS_VOLUME_NOT_UPGRADED", + "STATUS_REMOTE_STORAGE_NOT_ACTIVE", + "STATUS_REMOTE_STORAGE_MEDIA_ERROR", + "STATUS_NO_TRACKING_SERVICE", + "STATUS_SERVER_SID_MISMATCH", + "STATUS_DS_NO_ATTRIBUTE_OR_VALUE", + "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX", + "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED", + "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS", + "STATUS_DS_BUSY", + "STATUS_DS_UNAVAILABLE", + "STATUS_DS_NO_RIDS_ALLOCATED", + "STATUS_DS_NO_MORE_RIDS", + "STATUS_DS_INCORRECT_ROLE_OWNER", + "STATUS_DS_RIDMGR_INIT_ERROR", + "STATUS_DS_OBJ_CLASS_VIOLATION", + "STATUS_DS_CANT_ON_NON_LEAF", + "STATUS_DS_CANT_ON_RDN", + "STATUS_DS_CANT_MOD_OBJ_CLASS", + "STATUS_DS_CROSS_DOM_MOVE_FAILED", + "STATUS_DS_GC_NOT_AVAILABLE", + "STATUS_DIRECTORY_SERVICE_REQUIRED", + "STATUS_REPARSE_ATTRIBUTE_CONFLICT", + "STATUS_CANT_ENABLE_DENY_ONLY", + "STATUS_FLOAT_MULTIPLE_FAULTS", + "STATUS_FLOAT_MULTIPLE_TRAPS", + "STATUS_DEVICE_REMOVED", + "STATUS_JOURNAL_DELETE_IN_PROGRESS", + "STATUS_JOURNAL_NOT_ACTIVE", + "STATUS_NOINTERFACE", + "STATUS_DS_RIDMGR_DISABLED", + "STATUS_DS_ADMIN_LIMIT_EXCEEDED", + "STATUS_DRIVER_FAILED_SLEEP", + "STATUS_MUTUAL_AUTHENTICATION_FAILED", + "STATUS_CORRUPT_SYSTEM_FILE", + "STATUS_DATATYPE_MISALIGNMENT_ERROR", + "STATUS_WMI_READ_ONLY", + "STATUS_WMI_SET_FAILURE", + "STATUS_COMMITMENT_MINIMUM", + "STATUS_REG_NAT_CONSUMPTION", + "STATUS_TRANSPORT_FULL", + "STATUS_DS_SAM_INIT_FAILURE", + "STATUS_ONLY_IF_CONNECTED", + "STATUS_DS_SENSITIVE_GROUP_VIOLATION", + "STATUS_PNP_RESTART_ENUMERATION", + "STATUS_JOURNAL_ENTRY_DELETED", + "STATUS_DS_CANT_MOD_PRIMARYGROUPID", + "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE", + "STATUS_PNP_REBOOT_REQUIRED", + "STATUS_POWER_STATE_INVALID", + "STATUS_DS_INVALID_GROUP_TYPE", + "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN", + "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN", + "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER", + "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER", + "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER", + "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER", + "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER", + "STATUS_DS_HAVE_PRIMARY_MEMBERS", + "STATUS_WMI_NOT_SUPPORTED", + "STATUS_INSUFFICIENT_POWER", + "STATUS_SAM_NEED_BOOTKEY_PASSWORD", + "STATUS_SAM_NEED_BOOTKEY_FLOPPY", + "STATUS_DS_CANT_START", + "STATUS_DS_INIT_FAILURE", + "STATUS_SAM_INIT_FAILURE", + "STATUS_DS_GC_REQUIRED", + "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY", + "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS", + "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED", + "STATUS_MULTIPLE_FAULT_VIOLATION", + "STATUS_CURRENT_DOMAIN_NOT_ALLOWED", + "STATUS_CANNOT_MAKE", + "STATUS_SYSTEM_SHUTDOWN", + "STATUS_DS_INIT_FAILURE_CONSOLE", + "STATUS_DS_SAM_INIT_FAILURE_CONSOLE", + "STATUS_UNFINISHED_CONTEXT_DELETED", + "STATUS_NO_TGT_REPLY", + "STATUS_OBJECTID_NOT_FOUND", + "STATUS_NO_IP_ADDRESSES", + "STATUS_WRONG_CREDENTIAL_HANDLE", + "STATUS_CRYPTO_SYSTEM_INVALID", + "STATUS_MAX_REFERRALS_EXCEEDED", + "STATUS_MUST_BE_KDC", + "STATUS_STRONG_CRYPTO_NOT_SUPPORTED", + "STATUS_TOO_MANY_PRINCIPALS", + "STATUS_NO_PA_DATA", + "STATUS_PKINIT_NAME_MISMATCH", + "STATUS_SMARTCARD_LOGON_REQUIRED", + "STATUS_KDC_INVALID_REQUEST", + "STATUS_KDC_UNABLE_TO_REFER", + "STATUS_KDC_UNKNOWN_ETYPE", + "STATUS_SHUTDOWN_IN_PROGRESS", + "STATUS_SERVER_SHUTDOWN_IN_PROGRESS", + "STATUS_NOT_SUPPORTED_ON_SBS", + "STATUS_WMI_GUID_DISCONNECTED", + "STATUS_WMI_ALREADY_DISABLED", + "STATUS_WMI_ALREADY_ENABLED", + "STATUS_MFT_TOO_FRAGMENTED", + "STATUS_COPY_PROTECTION_FAILURE", + "STATUS_CSS_AUTHENTICATION_FAILURE", + "STATUS_CSS_KEY_NOT_PRESENT", + "STATUS_CSS_KEY_NOT_ESTABLISHED", + "STATUS_CSS_SCRAMBLED_SECTOR", + "STATUS_CSS_REGION_MISMATCH", + "STATUS_CSS_RESETS_EXHAUSTED", + "STATUS_PASSWORD_CHANGE_REQUIRED", + "STATUS_LOST_MODE_LOGON_RESTRICTION", + "STATUS_PKINIT_FAILURE", + "STATUS_SMARTCARD_SUBSYSTEM_FAILURE", + "STATUS_NO_KERB_KEY", + "STATUS_HOST_DOWN", + "STATUS_UNSUPPORTED_PREAUTH", + "STATUS_EFS_ALG_BLOB_TOO_BIG", + "STATUS_PORT_NOT_SET", + "STATUS_DEBUGGER_INACTIVE", + "STATUS_DS_VERSION_CHECK_FAILURE", + "STATUS_AUDITING_DISABLED", + "STATUS_PRENT4_MACHINE_ACCOUNT", + "STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER", + "STATUS_INVALID_IMAGE_WIN_32", + "STATUS_INVALID_IMAGE_WIN_64", + "STATUS_BAD_BINDINGS", + "STATUS_NETWORK_SESSION_EXPIRED", + "STATUS_APPHELP_BLOCK", + "STATUS_ALL_SIDS_FILTERED", + "STATUS_NOT_SAFE_MODE_DRIVER", + "STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT", + "STATUS_ACCESS_DISABLED_BY_POLICY_PATH", + "STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER", + "STATUS_ACCESS_DISABLED_BY_POLICY_OTHER", + "STATUS_FAILED_DRIVER_ENTRY", + "STATUS_DEVICE_ENUMERATION_ERROR", + "STATUS_MOUNT_POINT_NOT_RESOLVED", + "STATUS_INVALID_DEVICE_OBJECT_PARAMETER", + "STATUS_MCA_OCCURED", + "STATUS_DRIVER_BLOCKED_CRITICAL", + "STATUS_DRIVER_BLOCKED", + "STATUS_DRIVER_DATABASE_ERROR", + "STATUS_SYSTEM_HIVE_TOO_LARGE", + "STATUS_INVALID_IMPORT_OF_NON_DLL", + "STATUS_NO_SECRETS", + "STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY", + "STATUS_FAILED_STACK_SWITCH", + "STATUS_HEAP_CORRUPTION", + "STATUS_SMARTCARD_WRONG_PIN", + "STATUS_SMARTCARD_CARD_BLOCKED", + "STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED", + "STATUS_SMARTCARD_NO_CARD", + "STATUS_SMARTCARD_NO_KEY_CONTAINER", + "STATUS_SMARTCARD_NO_CERTIFICATE", + "STATUS_SMARTCARD_NO_KEYSET", + "STATUS_SMARTCARD_IO_ERROR", + "STATUS_DOWNGRADE_DETECTED", + "STATUS_SMARTCARD_CERT_REVOKED", + "STATUS_ISSUING_CA_UNTRUSTED", + "STATUS_REVOCATION_OFFLINE_C", + "STATUS_PKINIT_CLIENT_FAILURE", + "STATUS_SMARTCARD_CERT_EXPIRED", + "STATUS_DRIVER_FAILED_PRIOR_UNLOAD", + "STATUS_SMARTCARD_SILENT_CONTEXT", + "STATUS_PER_USER_TRUST_QUOTA_EXCEEDED", + "STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED", + "STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED", + "STATUS_DS_NAME_NOT_UNIQUE", + "STATUS_DS_DUPLICATE_ID_FOUND", + "STATUS_DS_GROUP_CONVERSION_ERROR", + "STATUS_VOLSNAP_PREPARE_HIBERNATE", + "STATUS_USER2USER_REQUIRED", + "STATUS_STACK_BUFFER_OVERRUN", + "STATUS_NO_S4U_PROT_SUPPORT", + "STATUS_CROSSREALM_DELEGATION_FAILURE", + "STATUS_REVOCATION_OFFLINE_KDC", + "STATUS_ISSUING_CA_UNTRUSTED_KDC", + "STATUS_KDC_CERT_EXPIRED", + "STATUS_KDC_CERT_REVOKED", + "STATUS_PARAMETER_QUOTA_EXCEEDED", + "STATUS_HIBERNATION_FAILURE", + "STATUS_DELAY_LOAD_FAILED", + "STATUS_AUTHENTICATION_FIREWALL_FAILED", + "STATUS_VDM_DISALLOWED", + "STATUS_HUNG_DISPLAY_DRIVER_THREAD", + "STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE", + "STATUS_INVALID_CRUNTIME_PARAMETER", + "STATUS_NTLM_BLOCKED", + "STATUS_DS_SRC_SID_EXISTS_IN_FOREST", + "STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST", + "STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST", + "STATUS_INVALID_USER_PRINCIPAL_NAME", + "STATUS_FATAL_USER_CALLBACK_EXCEPTION", + "STATUS_ASSERTION_FAILURE", + "STATUS_VERIFIER_STOP", + "STATUS_CALLBACK_POP_STACK", + "STATUS_INCOMPATIBLE_DRIVER_BLOCKED", + "STATUS_HIVE_UNLOADED", + "STATUS_COMPRESSION_DISABLED", + "STATUS_FILE_SYSTEM_LIMITATION", + "STATUS_INVALID_IMAGE_HASH", + "STATUS_NOT_CAPABLE", + "STATUS_REQUEST_OUT_OF_SEQUENCE", + "STATUS_IMPLEMENTATION_LIMIT", + "STATUS_ELEVATION_REQUIRED", + "STATUS_NO_SECURITY_CONTEXT", + "STATUS_PKU2U_CERT_FAILURE", + "STATUS_BEYOND_VDL", + "STATUS_ENCOUNTERED_WRITE_IN_PROGRESS", + "STATUS_PTE_CHANGED", + "STATUS_PURGE_FAILED", + "STATUS_CRED_REQUIRES_CONFIRMATION", + "STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE", + "STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER", + "STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE", + "STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE", + "STATUS_CS_ENCRYPTION_FILE_NOT_CSE", + "STATUS_INVALID_LABEL", + "STATUS_DRIVER_PROCESS_TERMINATED", + "STATUS_AMBIGUOUS_SYSTEM_DEVICE", + "STATUS_SYSTEM_DEVICE_NOT_FOUND", + "STATUS_RESTART_BOOT_APPLICATION", + "STATUS_INSUFFICIENT_NVRAM_RESOURCES", + "STATUS_INVALID_SESSION", + "STATUS_THREAD_ALREADY_IN_SESSION", + "STATUS_THREAD_NOT_IN_SESSION", + "STATUS_INVALID_WEIGHT", + "STATUS_REQUEST_PAUSED", + "STATUS_NO_RANGES_PROCESSED", + "STATUS_DISK_RESOURCES_EXHAUSTED", + "STATUS_NEEDS_REMEDIATION", + "STATUS_DEVICE_FEATURE_NOT_SUPPORTED", + "STATUS_DEVICE_UNREACHABLE", + "STATUS_INVALID_TOKEN", + "STATUS_SERVER_UNAVAILABLE", + "STATUS_FILE_NOT_AVAILABLE", + "STATUS_DEVICE_INSUFFICIENT_RESOURCES", + "STATUS_PACKAGE_UPDATING", + "STATUS_NOT_READ_FROM_COPY", + "STATUS_FT_WRITE_FAILURE", + "STATUS_FT_DI_SCAN_REQUIRED", + "STATUS_OBJECT_NOT_EXTERNALLY_BACKED", + "STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN", + "STATUS_COMPRESSION_NOT_BENEFICIAL", + "STATUS_DATA_CHECKSUM_ERROR", + "STATUS_INTERMIXED_KERNEL_EA_OPERATION", + "STATUS_TRIM_READ_ZERO_NOT_SUPPORTED", + "STATUS_TOO_MANY_SEGMENT_DESCRIPTORS", + "STATUS_INVALID_OFFSET_ALIGNMENT", + "STATUS_INVALID_FIELD_IN_PARAMETER_LIST", + "STATUS_OPERATION_IN_PROGRESS", + "STATUS_INVALID_INITIATOR_TARGET_PATH", + "STATUS_SCRUB_DATA_DISABLED", + "STATUS_NOT_REDUNDANT_STORAGE", + "STATUS_RESIDENT_FILE_NOT_SUPPORTED", + "STATUS_COMPRESSED_FILE_NOT_SUPPORTED", + "STATUS_DIRECTORY_NOT_SUPPORTED", + "STATUS_IO_OPERATION_TIMEOUT", + "STATUS_SYSTEM_NEEDS_REMEDIATION", + "STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN", + "STATUS_SHARE_UNAVAILABLE", + "STATUS_APISET_NOT_HOSTED", + "STATUS_APISET_NOT_PRESENT", + "STATUS_DEVICE_HARDWARE_ERROR", + "STATUS_FIRMWARE_SLOT_INVALID", + "STATUS_FIRMWARE_IMAGE_INVALID", + "STATUS_STORAGE_TOPOLOGY_ID_MISMATCH", + "STATUS_WIM_NOT_BOOTABLE", + "STATUS_BLOCKED_BY_PARENTAL_CONTROLS", + "STATUS_NEEDS_REGISTRATION", + "STATUS_QUOTA_ACTIVITY", + "STATUS_CALLBACK_INVOKE_INLINE", + "STATUS_BLOCK_TOO_MANY_REFERENCES", + "STATUS_MARKED_TO_DISALLOW_WRITES", + "STATUS_NETWORK_ACCESS_DENIED_EDP", + "STATUS_ENCLAVE_FAILURE", + "STATUS_PNP_NO_COMPAT_DRIVERS", + "STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND", + "STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND", + "STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE", + "STATUS_PNP_FUNCTION_DRIVER_REQUIRED", + "STATUS_PNP_DEVICE_CONFIGURATION_PENDING", + "STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL", + "STATUS_PACKAGE_NOT_AVAILABLE", + "STATUS_DEVICE_IN_MAINTENANCE", + "STATUS_NOT_SUPPORTED_ON_DAX", + "STATUS_FREE_SPACE_TOO_FRAGMENTED", + "STATUS_DAX_MAPPING_EXISTS", + "STATUS_CHILD_PROCESS_BLOCKED", + "STATUS_STORAGE_LOST_DATA_PERSISTENCE", + "STATUS_VRF_CFG_AND_IO_ENABLED", + "STATUS_PARTITION_TERMINATING", + "STATUS_EXTERNAL_SYSKEY_NOT_SUPPORTED", + "STATUS_ENCLAVE_VIOLATION", + "STATUS_FILE_PROTECTED_UNDER_DPL", + "STATUS_VOLUME_NOT_CLUSTER_ALIGNED", + "STATUS_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND", + "STATUS_APPX_FILE_NOT_ENCRYPTED", + "STATUS_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED", + "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET", + "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE", + "STATUS_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER", + "STATUS_FT_READ_FAILURE", + "STATUS_PATCH_CONFLICT", + "STATUS_STORAGE_RESERVE_ID_INVALID", + "STATUS_STORAGE_RESERVE_DOES_NOT_EXIST", + "STATUS_STORAGE_RESERVE_ALREADY_EXISTS", + "STATUS_STORAGE_RESERVE_NOT_EMPTY", + "STATUS_NOT_A_DAX_VOLUME", + "STATUS_NOT_DAX_MAPPABLE", + "STATUS_CASE_DIFFERING_NAMES_IN_DIR", + "STATUS_FILE_NOT_SUPPORTED", + "STATUS_NOT_SUPPORTED_WITH_BTT", + "STATUS_ENCRYPTION_DISABLED", + "STATUS_ENCRYPTING_METADATA_DISALLOWED", + "STATUS_CANT_CLEAR_ENCRYPTION_FLAG", + "STATUS_UNSATISFIED_DEPENDENCIES", + "STATUS_CASE_SENSITIVE_PATH", + "STATUS_HAS_SYSTEM_CRITICAL_FILES", + "STATUS_INVALID_TASK_NAME", + "STATUS_INVALID_TASK_INDEX", + "STATUS_THREAD_ALREADY_IN_TASK", + "STATUS_CALLBACK_BYPASS", + "STATUS_UNDEFINED_SCOPE", + "STATUS_INVALID_CAP", + "STATUS_NOT_GUI_PROCESS", + "STATUS_DEVICE_HUNG", + "STATUS_CONTAINER_ASSIGNED", + "STATUS_JOB_NO_CONTAINER", + "STATUS_DEVICE_UNRESPONSIVE", + "STATUS_REPARSE_POINT_ENCOUNTERED", + "STATUS_ATTRIBUTE_NOT_PRESENT", + "STATUS_NOT_A_TIERED_VOLUME", + "STATUS_ALREADY_HAS_STREAM_ID", + "STATUS_JOB_NOT_EMPTY", + "STATUS_ALREADY_INITIALIZED", + "STATUS_ENCLAVE_NOT_TERMINATED", + "STATUS_ENCLAVE_IS_TERMINATING", + "STATUS_SMB1_NOT_AVAILABLE", + "STATUS_SMR_GARBAGE_COLLECTION_REQUIRED", + "STATUS_INTERRUPTED", + "STATUS_THREAD_NOT_RUNNING", + "STATUS_FAIL_FAST_EXCEPTION", + "STATUS_IMAGE_CERT_REVOKED", + "STATUS_DYNAMIC_CODE_BLOCKED", + "STATUS_IMAGE_CERT_EXPIRED", + "STATUS_STRICT_CFG_VIOLATION", + "STATUS_SET_CONTEXT_DENIED", + "STATUS_CROSS_PARTITION_VIOLATION", + "STATUS_PORT_CLOSED", + "STATUS_MESSAGE_LOST", + "STATUS_INVALID_MESSAGE", + "STATUS_REQUEST_CANCELED", + "STATUS_RECURSIVE_DISPATCH", + "STATUS_LPC_RECEIVE_BUFFER_EXPECTED", + "STATUS_LPC_INVALID_CONNECTION_USAGE", + "STATUS_LPC_REQUESTS_NOT_ALLOWED", + "STATUS_RESOURCE_IN_USE", + "STATUS_HARDWARE_MEMORY_ERROR", + "STATUS_THREADPOOL_HANDLE_EXCEPTION", + "STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED", + "STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED", + "STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED", + "STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED", + "STATUS_THREADPOOL_RELEASED_DURING_OPERATION", + "STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING", + "STATUS_APC_RETURNED_WHILE_IMPERSONATING", + "STATUS_PROCESS_IS_PROTECTED", + "STATUS_MCA_EXCEPTION", + "STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE", + "STATUS_SYMLINK_CLASS_DISABLED", + "STATUS_INVALID_IDN_NORMALIZATION", + "STATUS_NO_UNICODE_TRANSLATION", + "STATUS_ALREADY_REGISTERED", + "STATUS_CONTEXT_MISMATCH", + "STATUS_PORT_ALREADY_HAS_COMPLETION_LIST", + "STATUS_CALLBACK_RETURNED_THREAD_PRIORITY", + "STATUS_INVALID_THREAD", + "STATUS_CALLBACK_RETURNED_TRANSACTION", + "STATUS_CALLBACK_RETURNED_LDR_LOCK", + "STATUS_CALLBACK_RETURNED_LANG", + "STATUS_CALLBACK_RETURNED_PRI_BACK", + "STATUS_CALLBACK_RETURNED_THREAD_AFFINITY", + "STATUS_LPC_HANDLE_COUNT_EXCEEDED", + "STATUS_EXECUTABLE_MEMORY_WRITE", + "STATUS_KERNEL_EXECUTABLE_MEMORY_WRITE", + "STATUS_ATTACHED_EXECUTABLE_MEMORY_WRITE", + "STATUS_TRIGGERED_EXECUTABLE_MEMORY_WRITE", + "STATUS_DISK_REPAIR_DISABLED", + "STATUS_DS_DOMAIN_RENAME_IN_PROGRESS", + "STATUS_DISK_QUOTA_EXCEEDED", + "STATUS_CONTENT_BLOCKED", + "STATUS_BAD_CLUSTERS", + "STATUS_VOLUME_DIRTY", + "STATUS_DISK_REPAIR_UNSUCCESSFUL", + "STATUS_CORRUPT_LOG_OVERFULL", + "STATUS_CORRUPT_LOG_CORRUPTED", + "STATUS_CORRUPT_LOG_UNAVAILABLE", + "STATUS_CORRUPT_LOG_DELETED_FULL", + "STATUS_CORRUPT_LOG_CLEARED", + "STATUS_ORPHAN_NAME_EXHAUSTED", + "STATUS_PROACTIVE_SCAN_IN_PROGRESS", + "STATUS_ENCRYPTED_IO_NOT_POSSIBLE", + "STATUS_CORRUPT_LOG_UPLEVEL_RECORDS", + "STATUS_FILE_CHECKED_OUT", + "STATUS_CHECKOUT_REQUIRED", + "STATUS_BAD_FILE_TYPE", + "STATUS_FILE_TOO_LARGE", + "STATUS_FORMS_AUTH_REQUIRED", + "STATUS_VIRUS_INFECTED", + "STATUS_VIRUS_DELETED", + "STATUS_BAD_MCFG_TABLE", + "STATUS_CANNOT_BREAK_OPLOCK", + "STATUS_BAD_KEY", + "STATUS_BAD_DATA", + "STATUS_NO_KEY", + "STATUS_FILE_HANDLE_REVOKED", + "STATUS_WOW_ASSERTION", + "STATUS_INVALID_SIGNATURE", + "STATUS_HMAC_NOT_SUPPORTED", + "STATUS_AUTH_TAG_MISMATCH", + "STATUS_INVALID_STATE_TRANSITION", + "STATUS_INVALID_KERNEL_INFO_VERSION", + "STATUS_INVALID_PEP_INFO_VERSION", + "STATUS_HANDLE_REVOKED", + "STATUS_EOF_ON_GHOSTED_RANGE", + "STATUS_CC_NEEDS_CALLBACK_SECTION_DRAIN", + "STATUS_IPSEC_QUEUE_OVERFLOW", + "STATUS_ND_QUEUE_OVERFLOW", + "STATUS_HOPLIMIT_EXCEEDED", + "STATUS_PROTOCOL_NOT_SUPPORTED", + "STATUS_FASTPATH_REJECTED", + "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED", + "STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR", + "STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR", + "STATUS_XML_PARSE_ERROR", + "STATUS_XMLDSIG_ERROR", + "STATUS_WRONG_COMPARTMENT", + "STATUS_AUTHIP_FAILURE", + "STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS", + "STATUS_DS_OID_NOT_FOUND", + "STATUS_INCORRECT_ACCOUNT_TYPE", + "STATUS_HASH_NOT_SUPPORTED", + "STATUS_HASH_NOT_PRESENT", + "STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED", + "STATUS_GPIO_CLIENT_INFORMATION_INVALID", + "STATUS_GPIO_VERSION_NOT_SUPPORTED", + "STATUS_GPIO_INVALID_REGISTRATION_PACKET", + "STATUS_GPIO_OPERATION_DENIED", + "STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE", + "STATUS_CANNOT_SWITCH_RUNLEVEL", + "STATUS_INVALID_RUNLEVEL_SETTING", + "STATUS_RUNLEVEL_SWITCH_TIMEOUT", + "STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT", + "STATUS_RUNLEVEL_SWITCH_IN_PROGRESS", + "STATUS_NOT_APPCONTAINER", + "STATUS_NOT_SUPPORTED_IN_APPCONTAINER", + "STATUS_INVALID_PACKAGE_SID_LENGTH", + "STATUS_LPAC_ACCESS_DENIED", + "STATUS_ADMINLESS_ACCESS_DENIED", + "STATUS_APP_DATA_NOT_FOUND", + "STATUS_APP_DATA_EXPIRED", + "STATUS_APP_DATA_CORRUPT", + "STATUS_APP_DATA_LIMIT_EXCEEDED", + "STATUS_APP_DATA_REBOOT_REQUIRED", + "STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED", + "STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED", + "STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED", + "STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED", + "STATUS_WOF_WIM_HEADER_CORRUPT", + "STATUS_WOF_WIM_RESOURCE_TABLE_CORRUPT", + "STATUS_WOF_FILE_RESOURCE_TABLE_CORRUPT", + "STATUS_CIMFS_IMAGE_CORRUPT", + "STATUS_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE", + "STATUS_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT", + "STATUS_FILE_SYSTEM_VIRTUALIZATION_BUSY", + "STATUS_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN", + "STATUS_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION", + "STATUS_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT", + "STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING", + "STATUS_CLOUD_FILE_METADATA_CORRUPT", + "STATUS_CLOUD_FILE_METADATA_TOO_LARGE", + "STATUS_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED", + "STATUS_NOT_A_CLOUD_FILE", + "STATUS_CLOUD_FILE_NOT_IN_SYNC", + "STATUS_CLOUD_FILE_ALREADY_CONNECTED", + "STATUS_CLOUD_FILE_NOT_SUPPORTED", + "STATUS_CLOUD_FILE_INVALID_REQUEST", + "STATUS_CLOUD_FILE_READ_ONLY_VOLUME", + "STATUS_CLOUD_FILE_CONNECTED_PROVIDER_ONLY", + "STATUS_CLOUD_FILE_VALIDATION_FAILED", + "STATUS_CLOUD_FILE_AUTHENTICATION_FAILED", + "STATUS_CLOUD_FILE_INSUFFICIENT_RESOURCES", + "STATUS_CLOUD_FILE_NETWORK_UNAVAILABLE", + "STATUS_CLOUD_FILE_UNSUCCESSFUL", + "STATUS_CLOUD_FILE_NOT_UNDER_SYNC_ROOT", + "STATUS_CLOUD_FILE_IN_USE", + "STATUS_CLOUD_FILE_PINNED", + "STATUS_CLOUD_FILE_REQUEST_ABORTED", + "STATUS_CLOUD_FILE_PROPERTY_CORRUPT", + "STATUS_CLOUD_FILE_ACCESS_DENIED", + "STATUS_CLOUD_FILE_INCOMPATIBLE_HARDLINKS", + "STATUS_CLOUD_FILE_PROPERTY_LOCK_CONFLICT", + "STATUS_CLOUD_FILE_REQUEST_CANCELED", + "STATUS_CLOUD_FILE_PROVIDER_TERMINATED", + "STATUS_NOT_A_CLOUD_SYNC_ROOT", + "STATUS_CLOUD_FILE_REQUEST_TIMEOUT", + "STATUS_CLOUD_FILE_DEHYDRATION_DISALLOWED", + "STATUS_FILE_SNAP_IN_PROGRESS", + "STATUS_FILE_SNAP_USER_SECTION_NOT_SUPPORTED", + "STATUS_FILE_SNAP_MODIFY_NOT_SUPPORTED", + "STATUS_FILE_SNAP_IO_NOT_COORDINATED", + "STATUS_FILE_SNAP_UNEXPECTED_ERROR", + "STATUS_FILE_SNAP_INVALID_PARAMETER", + "DBG_NO_STATE_CHANGE", + "DBG_APP_NOT_IDLE", + "RPC_NT_INVALID_STRING_BINDING", + "RPC_NT_WRONG_KIND_OF_BINDING", + "RPC_NT_INVALID_BINDING", + "RPC_NT_PROTSEQ_NOT_SUPPORTED", + "RPC_NT_INVALID_RPC_PROTSEQ", + "RPC_NT_INVALID_STRING_UUID", + "RPC_NT_INVALID_ENDPOINT_FORMAT", + "RPC_NT_INVALID_NET_ADDR", + "RPC_NT_NO_ENDPOINT_FOUND", + "RPC_NT_INVALID_TIMEOUT", + "RPC_NT_OBJECT_NOT_FOUND", + "RPC_NT_ALREADY_REGISTERED", + "RPC_NT_TYPE_ALREADY_REGISTERED", + "RPC_NT_ALREADY_LISTENING", + "RPC_NT_NO_PROTSEQS_REGISTERED", + "RPC_NT_NOT_LISTENING", + "RPC_NT_UNKNOWN_MGR_TYPE", + "RPC_NT_UNKNOWN_IF", + "RPC_NT_NO_BINDINGS", + "RPC_NT_NO_PROTSEQS", + "RPC_NT_CANT_CREATE_ENDPOINT", + "RPC_NT_OUT_OF_RESOURCES", + "RPC_NT_SERVER_UNAVAILABLE", + "RPC_NT_SERVER_TOO_BUSY", + "RPC_NT_INVALID_NETWORK_OPTIONS", + "RPC_NT_NO_CALL_ACTIVE", + "RPC_NT_CALL_FAILED", + "RPC_NT_CALL_FAILED_DNE", + "RPC_NT_PROTOCOL_ERROR", + "RPC_NT_UNSUPPORTED_TRANS_SYN", + "RPC_NT_UNSUPPORTED_TYPE", + "RPC_NT_INVALID_TAG", + "RPC_NT_INVALID_BOUND", + "RPC_NT_NO_ENTRY_NAME", + "RPC_NT_INVALID_NAME_SYNTAX", + "RPC_NT_UNSUPPORTED_NAME_SYNTAX", + "RPC_NT_UUID_NO_ADDRESS", + "RPC_NT_DUPLICATE_ENDPOINT", + "RPC_NT_UNKNOWN_AUTHN_TYPE", + "RPC_NT_MAX_CALLS_TOO_SMALL", + "RPC_NT_STRING_TOO_LONG", + "RPC_NT_PROTSEQ_NOT_FOUND", + "RPC_NT_PROCNUM_OUT_OF_RANGE", + "RPC_NT_BINDING_HAS_NO_AUTH", + "RPC_NT_UNKNOWN_AUTHN_SERVICE", + "RPC_NT_UNKNOWN_AUTHN_LEVEL", + "RPC_NT_INVALID_AUTH_IDENTITY", + "RPC_NT_UNKNOWN_AUTHZ_SERVICE", + "EPT_NT_INVALID_ENTRY", + "EPT_NT_CANT_PERFORM_OP", + "EPT_NT_NOT_REGISTERED", + "RPC_NT_NOTHING_TO_EXPORT", + "RPC_NT_INCOMPLETE_NAME", + "RPC_NT_INVALID_VERS_OPTION", + "RPC_NT_NO_MORE_MEMBERS", + "RPC_NT_NOT_ALL_OBJS_UNEXPORTED", + "RPC_NT_INTERFACE_NOT_FOUND", + "RPC_NT_ENTRY_ALREADY_EXISTS", + "RPC_NT_ENTRY_NOT_FOUND", + "RPC_NT_NAME_SERVICE_UNAVAILABLE", + "RPC_NT_INVALID_NAF_ID", + "RPC_NT_CANNOT_SUPPORT", + "RPC_NT_NO_CONTEXT_AVAILABLE", + "RPC_NT_INTERNAL_ERROR", + "RPC_NT_ZERO_DIVIDE", + "RPC_NT_ADDRESS_ERROR", + "RPC_NT_FP_DIV_ZERO", + "RPC_NT_FP_UNDERFLOW", + "RPC_NT_FP_OVERFLOW", + "RPC_NT_CALL_IN_PROGRESS", + "RPC_NT_NO_MORE_BINDINGS", + "RPC_NT_GROUP_MEMBER_NOT_FOUND", + "EPT_NT_CANT_CREATE", + "RPC_NT_INVALID_OBJECT", + "RPC_NT_NO_INTERFACES", + "RPC_NT_CALL_CANCELLED", + "RPC_NT_BINDING_INCOMPLETE", + "RPC_NT_COMM_FAILURE", + "RPC_NT_UNSUPPORTED_AUTHN_LEVEL", + "RPC_NT_NO_PRINC_NAME", + "RPC_NT_NOT_RPC_ERROR", + "RPC_NT_SEC_PKG_ERROR", + "RPC_NT_NOT_CANCELLED", + "RPC_NT_INVALID_ASYNC_HANDLE", + "RPC_NT_INVALID_ASYNC_CALL", + "RPC_NT_PROXY_ACCESS_DENIED", + "RPC_NT_COOKIE_AUTH_FAILED", + "RPC_NT_NO_MORE_ENTRIES", + "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL", + "RPC_NT_SS_CHAR_TRANS_SHORT_FILE", + "RPC_NT_SS_IN_NULL_CONTEXT", + "RPC_NT_SS_CONTEXT_MISMATCH", + "RPC_NT_SS_CONTEXT_DAMAGED", + "RPC_NT_SS_HANDLES_MISMATCH", + "RPC_NT_SS_CANNOT_GET_CALL_HANDLE", + "RPC_NT_NULL_REF_POINTER", + "RPC_NT_ENUM_VALUE_OUT_OF_RANGE", + "RPC_NT_BYTE_COUNT_TOO_SMALL", + "RPC_NT_BAD_STUB_DATA", + "RPC_NT_INVALID_ES_ACTION", + "RPC_NT_WRONG_ES_VERSION", + "RPC_NT_WRONG_STUB_VERSION", + "RPC_NT_INVALID_PIPE_OBJECT", + "RPC_NT_INVALID_PIPE_OPERATION", + "RPC_NT_WRONG_PIPE_VERSION", + "RPC_NT_PIPE_CLOSED", + "RPC_NT_PIPE_DISCIPLINE_ERROR", + "RPC_NT_PIPE_EMPTY", + "STATUS_PNP_BAD_MPS_TABLE", + "STATUS_PNP_TRANSLATION_FAILED", + "STATUS_PNP_IRQ_TRANSLATION_FAILED", + "STATUS_PNP_INVALID_ID", + "STATUS_IO_REISSUE_AS_CACHED", + "STATUS_CTX_WINSTATION_NAME_INVALID", + "STATUS_CTX_INVALID_PD", + "STATUS_CTX_PD_NOT_FOUND", + "STATUS_CTX_CLOSE_PENDING", + "STATUS_CTX_NO_OUTBUF", + "STATUS_CTX_MODEM_INF_NOT_FOUND", + "STATUS_CTX_INVALID_MODEMNAME", + "STATUS_CTX_RESPONSE_ERROR", + "STATUS_CTX_MODEM_RESPONSE_TIMEOUT", + "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER", + "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE", + "STATUS_CTX_MODEM_RESPONSE_BUSY", + "STATUS_CTX_MODEM_RESPONSE_VOICE", + "STATUS_CTX_TD_ERROR", + "STATUS_CTX_LICENSE_CLIENT_INVALID", + "STATUS_CTX_LICENSE_NOT_AVAILABLE", + "STATUS_CTX_LICENSE_EXPIRED", + "STATUS_CTX_WINSTATION_NOT_FOUND", + "STATUS_CTX_WINSTATION_NAME_COLLISION", + "STATUS_CTX_WINSTATION_BUSY", + "STATUS_CTX_BAD_VIDEO_MODE", + "STATUS_CTX_GRAPHICS_INVALID", + "STATUS_CTX_NOT_CONSOLE", + "STATUS_CTX_CLIENT_QUERY_TIMEOUT", + "STATUS_CTX_CONSOLE_DISCONNECT", + "STATUS_CTX_CONSOLE_CONNECT", + "STATUS_CTX_SHADOW_DENIED", + "STATUS_CTX_WINSTATION_ACCESS_DENIED", + "STATUS_CTX_INVALID_WD", + "STATUS_CTX_WD_NOT_FOUND", + "STATUS_CTX_SHADOW_INVALID", + "STATUS_CTX_SHADOW_DISABLED", + "STATUS_RDP_PROTOCOL_ERROR", + "STATUS_CTX_CLIENT_LICENSE_NOT_SET", + "STATUS_CTX_CLIENT_LICENSE_IN_USE", + "STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE", + "STATUS_CTX_SHADOW_NOT_RUNNING", + "STATUS_CTX_LOGON_DISABLED", + "STATUS_CTX_SECURITY_LAYER_ERROR", + "STATUS_TS_INCOMPATIBLE_SESSIONS", + "STATUS_TS_VIDEO_SUBSYSTEM_ERROR", + "STATUS_MUI_FILE_NOT_FOUND", + "STATUS_MUI_INVALID_FILE", + "STATUS_MUI_INVALID_RC_CONFIG", + "STATUS_MUI_INVALID_LOCALE_NAME", + "STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME", + "STATUS_MUI_FILE_NOT_LOADED", + "STATUS_RESOURCE_ENUM_USER_STOP", + "STATUS_CLUSTER_INVALID_NODE", + "STATUS_CLUSTER_NODE_EXISTS", + "STATUS_CLUSTER_JOIN_IN_PROGRESS", + "STATUS_CLUSTER_NODE_NOT_FOUND", + "STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND", + "STATUS_CLUSTER_NETWORK_EXISTS", + "STATUS_CLUSTER_NETWORK_NOT_FOUND", + "STATUS_CLUSTER_NETINTERFACE_EXISTS", + "STATUS_CLUSTER_NETINTERFACE_NOT_FOUND", + "STATUS_CLUSTER_INVALID_REQUEST", + "STATUS_CLUSTER_INVALID_NETWORK_PROVIDER", + "STATUS_CLUSTER_NODE_DOWN", + "STATUS_CLUSTER_NODE_UNREACHABLE", + "STATUS_CLUSTER_NODE_NOT_MEMBER", + "STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS", + "STATUS_CLUSTER_INVALID_NETWORK", + "STATUS_CLUSTER_NO_NET_ADAPTERS", + "STATUS_CLUSTER_NODE_UP", + "STATUS_CLUSTER_NODE_PAUSED", + "STATUS_CLUSTER_NODE_NOT_PAUSED", + "STATUS_CLUSTER_NO_SECURITY_CONTEXT", + "STATUS_CLUSTER_NETWORK_NOT_INTERNAL", + "STATUS_CLUSTER_POISONED", + "STATUS_CLUSTER_NON_CSV_PATH", + "STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL", + "STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS", + "STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR", + "STATUS_CLUSTER_CSV_REDIRECTED", + "STATUS_CLUSTER_CSV_NOT_REDIRECTED", + "STATUS_CLUSTER_CSV_VOLUME_DRAINING", + "STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS", + "STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL", + "STATUS_CLUSTER_CSV_NO_SNAPSHOTS", + "STATUS_CSV_IO_PAUSE_TIMEOUT", + "STATUS_CLUSTER_CSV_INVALID_HANDLE", + "STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR", + "STATUS_CLUSTER_CAM_TICKET_REPLAY_DETECTED", + "STATUS_ACPI_INVALID_OPCODE", + "STATUS_ACPI_STACK_OVERFLOW", + "STATUS_ACPI_ASSERT_FAILED", + "STATUS_ACPI_INVALID_INDEX", + "STATUS_ACPI_INVALID_ARGUMENT", + "STATUS_ACPI_FATAL", + "STATUS_ACPI_INVALID_SUPERNAME", + "STATUS_ACPI_INVALID_ARGTYPE", + "STATUS_ACPI_INVALID_OBJTYPE", + "STATUS_ACPI_INVALID_TARGETTYPE", + "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT", + "STATUS_ACPI_ADDRESS_NOT_MAPPED", + "STATUS_ACPI_INVALID_EVENTTYPE", + "STATUS_ACPI_HANDLER_COLLISION", + "STATUS_ACPI_INVALID_DATA", + "STATUS_ACPI_INVALID_REGION", + "STATUS_ACPI_INVALID_ACCESS_SIZE", + "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK", + "STATUS_ACPI_ALREADY_INITIALIZED", + "STATUS_ACPI_NOT_INITIALIZED", + "STATUS_ACPI_INVALID_MUTEX_LEVEL", + "STATUS_ACPI_MUTEX_NOT_OWNED", + "STATUS_ACPI_MUTEX_NOT_OWNER", + "STATUS_ACPI_RS_ACCESS", + "STATUS_ACPI_INVALID_TABLE", + "STATUS_ACPI_REG_HANDLER_FAILED", + "STATUS_ACPI_POWER_REQUEST_FAILED", + "STATUS_SXS_SECTION_NOT_FOUND", + "STATUS_SXS_CANT_GEN_ACTCTX", + "STATUS_SXS_INVALID_ACTCTXDATA_FORMAT", + "STATUS_SXS_ASSEMBLY_NOT_FOUND", + "STATUS_SXS_MANIFEST_FORMAT_ERROR", + "STATUS_SXS_MANIFEST_PARSE_ERROR", + "STATUS_SXS_ACTIVATION_CONTEXT_DISABLED", + "STATUS_SXS_KEY_NOT_FOUND", + "STATUS_SXS_VERSION_CONFLICT", + "STATUS_SXS_WRONG_SECTION_TYPE", + "STATUS_SXS_THREAD_QUERIES_DISABLED", + "STATUS_SXS_ASSEMBLY_MISSING", + "STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET", + "STATUS_SXS_EARLY_DEACTIVATION", + "STATUS_SXS_INVALID_DEACTIVATION", + "STATUS_SXS_MULTIPLE_DEACTIVATION", + "STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY", + "STATUS_SXS_PROCESS_TERMINATION_REQUESTED", + "STATUS_SXS_CORRUPT_ACTIVATION_STACK", + "STATUS_SXS_CORRUPTION", + "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE", + "STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME", + "STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE", + "STATUS_SXS_IDENTITY_PARSE_ERROR", + "STATUS_SXS_COMPONENT_STORE_CORRUPT", + "STATUS_SXS_FILE_HASH_MISMATCH", + "STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT", + "STATUS_SXS_IDENTITIES_DIFFERENT", + "STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT", + "STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY", + "STATUS_ADVANCED_INSTALLER_FAILED", + "STATUS_XML_ENCODING_MISMATCH", + "STATUS_SXS_MANIFEST_TOO_BIG", + "STATUS_SXS_SETTING_NOT_REGISTERED", + "STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE", + "STATUS_SMI_PRIMITIVE_INSTALLER_FAILED", + "STATUS_GENERIC_COMMAND_FAILED", + "STATUS_SXS_FILE_HASH_MISSING", + "STATUS_TRANSACTIONAL_CONFLICT", + "STATUS_INVALID_TRANSACTION", + "STATUS_TRANSACTION_NOT_ACTIVE", + "STATUS_TM_INITIALIZATION_FAILED", + "STATUS_RM_NOT_ACTIVE", + "STATUS_RM_METADATA_CORRUPT", + "STATUS_TRANSACTION_NOT_JOINED", + "STATUS_DIRECTORY_NOT_RM", + "STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE", + "STATUS_LOG_RESIZE_INVALID_SIZE", + "STATUS_REMOTE_FILE_VERSION_MISMATCH", + "STATUS_CRM_PROTOCOL_ALREADY_EXISTS", + "STATUS_TRANSACTION_PROPAGATION_FAILED", + "STATUS_CRM_PROTOCOL_NOT_FOUND", + "STATUS_TRANSACTION_SUPERIOR_EXISTS", + "STATUS_TRANSACTION_REQUEST_NOT_VALID", + "STATUS_TRANSACTION_NOT_REQUESTED", + "STATUS_TRANSACTION_ALREADY_ABORTED", + "STATUS_TRANSACTION_ALREADY_COMMITTED", + "STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER", + "STATUS_CURRENT_TRANSACTION_NOT_VALID", + "STATUS_LOG_GROWTH_FAILED", + "STATUS_OBJECT_NO_LONGER_EXISTS", + "STATUS_STREAM_MINIVERSION_NOT_FOUND", + "STATUS_STREAM_MINIVERSION_NOT_VALID", + "STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION", + "STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT", + "STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS", + "STATUS_HANDLE_NO_LONGER_VALID", + "STATUS_LOG_CORRUPTION_DETECTED", + "STATUS_RM_DISCONNECTED", + "STATUS_ENLISTMENT_NOT_SUPERIOR", + "STATUS_FILE_IDENTITY_NOT_PERSISTENT", + "STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY", + "STATUS_CANT_CROSS_RM_BOUNDARY", + "STATUS_TXF_DIR_NOT_EMPTY", + "STATUS_INDOUBT_TRANSACTIONS_EXIST", + "STATUS_TM_VOLATILE", + "STATUS_ROLLBACK_TIMER_EXPIRED", + "STATUS_TXF_ATTRIBUTE_CORRUPT", + "STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION", + "STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED", + "STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE", + "STATUS_TRANSACTION_REQUIRED_PROMOTION", + "STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION", + "STATUS_TRANSACTIONS_NOT_FROZEN", + "STATUS_TRANSACTION_FREEZE_IN_PROGRESS", + "STATUS_NOT_SNAPSHOT_VOLUME", + "STATUS_NO_SAVEPOINT_WITH_OPEN_FILES", + "STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION", + "STATUS_TM_IDENTITY_MISMATCH", + "STATUS_FLOATED_SECTION", + "STATUS_CANNOT_ACCEPT_TRANSACTED_WORK", + "STATUS_CANNOT_ABORT_TRANSACTIONS", + "STATUS_TRANSACTION_NOT_FOUND", + "STATUS_RESOURCEMANAGER_NOT_FOUND", + "STATUS_ENLISTMENT_NOT_FOUND", + "STATUS_TRANSACTIONMANAGER_NOT_FOUND", + "STATUS_TRANSACTIONMANAGER_NOT_ONLINE", + "STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION", + "STATUS_TRANSACTION_NOT_ROOT", + "STATUS_TRANSACTION_OBJECT_EXPIRED", + "STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION", + "STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED", + "STATUS_TRANSACTION_RECORD_TOO_LONG", + "STATUS_NO_LINK_TRACKING_IN_TRANSACTION", + "STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION", + "STATUS_TRANSACTION_INTEGRITY_VIOLATED", + "STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH", + "STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT", + "STATUS_TRANSACTION_MUST_WRITETHROUGH", + "STATUS_TRANSACTION_NO_SUPERIOR", + "STATUS_EXPIRED_HANDLE", + "STATUS_TRANSACTION_NOT_ENLISTED", + "STATUS_LOG_SECTOR_INVALID", + "STATUS_LOG_SECTOR_PARITY_INVALID", + "STATUS_LOG_SECTOR_REMAPPED", + "STATUS_LOG_BLOCK_INCOMPLETE", + "STATUS_LOG_INVALID_RANGE", + "STATUS_LOG_BLOCKS_EXHAUSTED", + "STATUS_LOG_READ_CONTEXT_INVALID", + "STATUS_LOG_RESTART_INVALID", + "STATUS_LOG_BLOCK_VERSION", + "STATUS_LOG_BLOCK_INVALID", + "STATUS_LOG_READ_MODE_INVALID", + "STATUS_LOG_METADATA_CORRUPT", + "STATUS_LOG_METADATA_INVALID", + "STATUS_LOG_METADATA_INCONSISTENT", + "STATUS_LOG_RESERVATION_INVALID", + "STATUS_LOG_CANT_DELETE", + "STATUS_LOG_CONTAINER_LIMIT_EXCEEDED", + "STATUS_LOG_START_OF_LOG", + "STATUS_LOG_POLICY_ALREADY_INSTALLED", + "STATUS_LOG_POLICY_NOT_INSTALLED", + "STATUS_LOG_POLICY_INVALID", + "STATUS_LOG_POLICY_CONFLICT", + "STATUS_LOG_PINNED_ARCHIVE_TAIL", + "STATUS_LOG_RECORD_NONEXISTENT", + "STATUS_LOG_RECORDS_RESERVED_INVALID", + "STATUS_LOG_SPACE_RESERVED_INVALID", + "STATUS_LOG_TAIL_INVALID", + "STATUS_LOG_FULL", + "STATUS_LOG_MULTIPLEXED", + "STATUS_LOG_DEDICATED", + "STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS", + "STATUS_LOG_ARCHIVE_IN_PROGRESS", + "STATUS_LOG_EPHEMERAL", + "STATUS_LOG_NOT_ENOUGH_CONTAINERS", + "STATUS_LOG_CLIENT_ALREADY_REGISTERED", + "STATUS_LOG_CLIENT_NOT_REGISTERED", + "STATUS_LOG_FULL_HANDLER_IN_PROGRESS", + "STATUS_LOG_CONTAINER_READ_FAILED", + "STATUS_LOG_CONTAINER_WRITE_FAILED", + "STATUS_LOG_CONTAINER_OPEN_FAILED", + "STATUS_LOG_CONTAINER_STATE_INVALID", + "STATUS_LOG_STATE_INVALID", + "STATUS_LOG_PINNED", + "STATUS_LOG_METADATA_FLUSH_FAILED", + "STATUS_LOG_INCONSISTENT_SECURITY", + "STATUS_LOG_APPENDED_FLUSH_FAILED", + "STATUS_LOG_PINNED_RESERVATION", + "STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD", + "STATUS_FLT_NO_HANDLER_DEFINED", + "STATUS_FLT_CONTEXT_ALREADY_DEFINED", + "STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST", + "STATUS_FLT_DISALLOW_FAST_IO", + "STATUS_FLT_INVALID_NAME_REQUEST", + "STATUS_FLT_NOT_SAFE_TO_POST_OPERATION", + "STATUS_FLT_NOT_INITIALIZED", + "STATUS_FLT_FILTER_NOT_READY", + "STATUS_FLT_POST_OPERATION_CLEANUP", + "STATUS_FLT_INTERNAL_ERROR", + "STATUS_FLT_DELETING_OBJECT", + "STATUS_FLT_MUST_BE_NONPAGED_POOL", + "STATUS_FLT_DUPLICATE_ENTRY", + "STATUS_FLT_CBDQ_DISABLED", + "STATUS_FLT_DO_NOT_ATTACH", + "STATUS_FLT_DO_NOT_DETACH", + "STATUS_FLT_INSTANCE_ALTITUDE_COLLISION", + "STATUS_FLT_INSTANCE_NAME_COLLISION", + "STATUS_FLT_FILTER_NOT_FOUND", + "STATUS_FLT_VOLUME_NOT_FOUND", + "STATUS_FLT_INSTANCE_NOT_FOUND", + "STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND", + "STATUS_FLT_INVALID_CONTEXT_REGISTRATION", + "STATUS_FLT_NAME_CACHE_MISS", + "STATUS_FLT_NO_DEVICE_OBJECT", + "STATUS_FLT_VOLUME_ALREADY_MOUNTED", + "STATUS_FLT_ALREADY_ENLISTED", + "STATUS_FLT_CONTEXT_ALREADY_LINKED", + "STATUS_FLT_NO_WAITER_FOR_REPLY", + "STATUS_FLT_REGISTRATION_BUSY", + "STATUS_MONITOR_NO_DESCRIPTOR", + "STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT", + "STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM", + "STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK", + "STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED", + "STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK", + "STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK", + "STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA", + "STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK", + "STATUS_MONITOR_INVALID_MANUFACTURE_DATE", + "STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER", + "STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER", + "STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER", + "STATUS_GRAPHICS_ADAPTER_WAS_RESET", + "STATUS_GRAPHICS_INVALID_DRIVER_MODEL", + "STATUS_GRAPHICS_PRESENT_MODE_CHANGED", + "STATUS_GRAPHICS_PRESENT_OCCLUDED", + "STATUS_GRAPHICS_PRESENT_DENIED", + "STATUS_GRAPHICS_CANNOTCOLORCONVERT", + "STATUS_GRAPHICS_DRIVER_MISMATCH", + "STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED", + "STATUS_GRAPHICS_PRESENT_UNOCCLUDED", + "STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE", + "STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED", + "STATUS_GRAPHICS_PRESENT_INVALID_WINDOW", + "STATUS_GRAPHICS_PRESENT_BUFFER_NOT_BOUND", + "STATUS_GRAPHICS_VAIL_STATE_CHANGED", + "STATUS_GRAPHICS_INDIRECT_DISPLAY_ABANDON_SWAPCHAIN", + "STATUS_GRAPHICS_INDIRECT_DISPLAY_DEVICE_STOPPED", + "STATUS_GRAPHICS_NO_VIDEO_MEMORY", + "STATUS_GRAPHICS_CANT_LOCK_MEMORY", + "STATUS_GRAPHICS_ALLOCATION_BUSY", + "STATUS_GRAPHICS_TOO_MANY_REFERENCES", + "STATUS_GRAPHICS_TRY_AGAIN_LATER", + "STATUS_GRAPHICS_TRY_AGAIN_NOW", + "STATUS_GRAPHICS_ALLOCATION_INVALID", + "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE", + "STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED", + "STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION", + "STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE", + "STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION", + "STATUS_GRAPHICS_ALLOCATION_CLOSED", + "STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE", + "STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE", + "STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE", + "STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST", + "STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE", + "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY", + "STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED", + "STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED", + "STATUS_GRAPHICS_INVALID_VIDPN", + "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE", + "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET", + "STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED", + "STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET", + "STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET", + "STATUS_GRAPHICS_INVALID_FREQUENCY", + "STATUS_GRAPHICS_INVALID_ACTIVE_REGION", + "STATUS_GRAPHICS_INVALID_TOTAL_REGION", + "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE", + "STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE", + "STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET", + "STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY", + "STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET", + "STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET", + "STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET", + "STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET", + "STATUS_GRAPHICS_TARGET_ALREADY_IN_SET", + "STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH", + "STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY", + "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET", + "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE", + "STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET", + "STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET", + "STATUS_GRAPHICS_STALE_MODESET", + "STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET", + "STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE", + "STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN", + "STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE", + "STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION", + "STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES", + "STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY", + "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE", + "STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET", + "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET", + "STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR", + "STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET", + "STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET", + "STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE", + "STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE", + "STATUS_GRAPHICS_RESOURCES_NOT_RELATED", + "STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE", + "STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE", + "STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET", + "STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER", + "STATUS_GRAPHICS_NO_VIDPNMGR", + "STATUS_GRAPHICS_NO_ACTIVE_VIDPN", + "STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY", + "STATUS_GRAPHICS_MONITOR_NOT_CONNECTED", + "STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY", + "STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE", + "STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE", + "STATUS_GRAPHICS_INVALID_STRIDE", + "STATUS_GRAPHICS_INVALID_PIXELFORMAT", + "STATUS_GRAPHICS_INVALID_COLORBASIS", + "STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE", + "STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY", + "STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT", + "STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE", + "STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN", + "STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL", + "STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION", + "STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED", + "STATUS_GRAPHICS_INVALID_GAMMA_RAMP", + "STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED", + "STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED", + "STATUS_GRAPHICS_MODE_NOT_IN_MODESET", + "STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON", + "STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE", + "STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE", + "STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS", + "STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING", + "STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED", + "STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS", + "STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT", + "STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM", + "STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN", + "STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT", + "STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED", + "STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION", + "STATUS_GRAPHICS_INVALID_CLIENT_TYPE", + "STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET", + "STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED", + "STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED", + "STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER", + "STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED", + "STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED", + "STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY", + "STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED", + "STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON", + "STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE", + "STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER", + "STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED", + "STATUS_GRAPHICS_OPM_NOT_SUPPORTED", + "STATUS_GRAPHICS_COPP_NOT_SUPPORTED", + "STATUS_GRAPHICS_UAB_NOT_SUPPORTED", + "STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS", + "STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST", + "STATUS_GRAPHICS_OPM_INTERNAL_ERROR", + "STATUS_GRAPHICS_OPM_INVALID_HANDLE", + "STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH", + "STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED", + "STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED", + "STATUS_GRAPHICS_PVP_HFS_FAILED", + "STATUS_GRAPHICS_OPM_INVALID_SRM", + "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP", + "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP", + "STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA", + "STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET", + "STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH", + "STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE", + "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS", + "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS", + "STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST", + "STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR", + "STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS", + "STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED", + "STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST", + "STATUS_GRAPHICS_I2C_NOT_SUPPORTED", + "STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST", + "STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA", + "STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA", + "STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED", + "STATUS_GRAPHICS_DDCCI_INVALID_DATA", + "STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE", + "STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING", + "STATUS_GRAPHICS_MCA_INTERNAL_ERROR", + "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND", + "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH", + "STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM", + "STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE", + "STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS", + "STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED", + "STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME", + "STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP", + "STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED", + "STATUS_GRAPHICS_INVALID_POINTER", + "STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE", + "STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL", + "STATUS_GRAPHICS_INTERNAL_ERROR", + "STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS", + "STATUS_FVE_LOCKED_VOLUME", + "STATUS_FVE_NOT_ENCRYPTED", + "STATUS_FVE_BAD_INFORMATION", + "STATUS_FVE_TOO_SMALL", + "STATUS_FVE_FAILED_WRONG_FS", + "STATUS_FVE_BAD_PARTITION_SIZE", + "STATUS_FVE_FS_NOT_EXTENDED", + "STATUS_FVE_FS_MOUNTED", + "STATUS_FVE_NO_LICENSE", + "STATUS_FVE_ACTION_NOT_ALLOWED", + "STATUS_FVE_BAD_DATA", + "STATUS_FVE_VOLUME_NOT_BOUND", + "STATUS_FVE_NOT_DATA_VOLUME", + "STATUS_FVE_CONV_READ_ERROR", + "STATUS_FVE_CONV_WRITE_ERROR", + "STATUS_FVE_OVERLAPPED_UPDATE", + "STATUS_FVE_FAILED_SECTOR_SIZE", + "STATUS_FVE_FAILED_AUTHENTICATION", + "STATUS_FVE_NOT_OS_VOLUME", + "STATUS_FVE_KEYFILE_NOT_FOUND", + "STATUS_FVE_KEYFILE_INVALID", + "STATUS_FVE_KEYFILE_NO_VMK", + "STATUS_FVE_TPM_DISABLED", + "STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO", + "STATUS_FVE_TPM_INVALID_PCR", + "STATUS_FVE_TPM_NO_VMK", + "STATUS_FVE_PIN_INVALID", + "STATUS_FVE_AUTH_INVALID_APPLICATION", + "STATUS_FVE_AUTH_INVALID_CONFIG", + "STATUS_FVE_DEBUGGER_ENABLED", + "STATUS_FVE_DRY_RUN_FAILED", + "STATUS_FVE_BAD_METADATA_POINTER", + "STATUS_FVE_OLD_METADATA_COPY", + "STATUS_FVE_REBOOT_REQUIRED", + "STATUS_FVE_RAW_ACCESS", + "STATUS_FVE_RAW_BLOCKED", + "STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY", + "STATUS_FVE_MOR_FAILED", + "STATUS_FVE_NO_FEATURE_LICENSE", + "STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED", + "STATUS_FVE_CONV_RECOVERY_FAILED", + "STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG", + "STATUS_FVE_INVALID_DATUM_TYPE", + "STATUS_FVE_VOLUME_TOO_SMALL", + "STATUS_FVE_ENH_PIN_INVALID", + "STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE", + "STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE", + "STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK", + "STATUS_FVE_NOT_ALLOWED_ON_CLUSTER", + "STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING", + "STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE", + "STATUS_FVE_EDRIVE_DRY_RUN_FAILED", + "STATUS_FVE_SECUREBOOT_DISABLED", + "STATUS_FVE_SECUREBOOT_CONFIG_CHANGE", + "STATUS_FVE_DEVICE_LOCKEDOUT", + "STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT", + "STATUS_FVE_NOT_DE_VOLUME", + "STATUS_FVE_PROTECTION_DISABLED", + "STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED", + "STATUS_FVE_OSV_KSR_NOT_ALLOWED", + "STATUS_FWP_CALLOUT_NOT_FOUND", + "STATUS_FWP_CONDITION_NOT_FOUND", + "STATUS_FWP_FILTER_NOT_FOUND", + "STATUS_FWP_LAYER_NOT_FOUND", + "STATUS_FWP_PROVIDER_NOT_FOUND", + "STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND", + "STATUS_FWP_SUBLAYER_NOT_FOUND", + "STATUS_FWP_NOT_FOUND", + "STATUS_FWP_ALREADY_EXISTS", + "STATUS_FWP_IN_USE", + "STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS", + "STATUS_FWP_WRONG_SESSION", + "STATUS_FWP_NO_TXN_IN_PROGRESS", + "STATUS_FWP_TXN_IN_PROGRESS", + "STATUS_FWP_TXN_ABORTED", + "STATUS_FWP_SESSION_ABORTED", + "STATUS_FWP_INCOMPATIBLE_TXN", + "STATUS_FWP_TIMEOUT", + "STATUS_FWP_NET_EVENTS_DISABLED", + "STATUS_FWP_INCOMPATIBLE_LAYER", + "STATUS_FWP_KM_CLIENTS_ONLY", + "STATUS_FWP_LIFETIME_MISMATCH", + "STATUS_FWP_BUILTIN_OBJECT", + "STATUS_FWP_TOO_MANY_CALLOUTS", + "STATUS_FWP_NOTIFICATION_DROPPED", + "STATUS_FWP_TRAFFIC_MISMATCH", + "STATUS_FWP_INCOMPATIBLE_SA_STATE", + "STATUS_FWP_NULL_POINTER", + "STATUS_FWP_INVALID_ENUMERATOR", + "STATUS_FWP_INVALID_FLAGS", + "STATUS_FWP_INVALID_NET_MASK", + "STATUS_FWP_INVALID_RANGE", + "STATUS_FWP_INVALID_INTERVAL", + "STATUS_FWP_ZERO_LENGTH_ARRAY", + "STATUS_FWP_NULL_DISPLAY_NAME", + "STATUS_FWP_INVALID_ACTION_TYPE", + "STATUS_FWP_INVALID_WEIGHT", + "STATUS_FWP_MATCH_TYPE_MISMATCH", + "STATUS_FWP_TYPE_MISMATCH", + "STATUS_FWP_OUT_OF_BOUNDS", + "STATUS_FWP_RESERVED", + "STATUS_FWP_DUPLICATE_CONDITION", + "STATUS_FWP_DUPLICATE_KEYMOD", + "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER", + "STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER", + "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER", + "STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT", + "STATUS_FWP_INCOMPATIBLE_AUTH_METHOD", + "STATUS_FWP_INCOMPATIBLE_DH_GROUP", + "STATUS_FWP_EM_NOT_SUPPORTED", + "STATUS_FWP_NEVER_MATCH", + "STATUS_FWP_PROVIDER_CONTEXT_MISMATCH", + "STATUS_FWP_INVALID_PARAMETER", + "STATUS_FWP_TOO_MANY_SUBLAYERS", + "STATUS_FWP_CALLOUT_NOTIFICATION_FAILED", + "STATUS_FWP_INVALID_AUTH_TRANSFORM", + "STATUS_FWP_INVALID_CIPHER_TRANSFORM", + "STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM", + "STATUS_FWP_INVALID_TRANSFORM_COMBINATION", + "STATUS_FWP_DUPLICATE_AUTH_METHOD", + "STATUS_FWP_INVALID_TUNNEL_ENDPOINT", + "STATUS_FWP_L2_DRIVER_NOT_READY", + "STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED", + "STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL", + "STATUS_FWP_CONNECTIONS_DISABLED", + "STATUS_FWP_INVALID_DNS_NAME", + "STATUS_FWP_STILL_ON", + "STATUS_FWP_IKEEXT_NOT_RUNNING", + "STATUS_FWP_TCPIP_NOT_READY", + "STATUS_FWP_INJECT_HANDLE_CLOSING", + "STATUS_FWP_INJECT_HANDLE_STALE", + "STATUS_FWP_CANNOT_PEND", + "STATUS_FWP_DROP_NOICMP", + "STATUS_NDIS_CLOSING", + "STATUS_NDIS_BAD_VERSION", + "STATUS_NDIS_BAD_CHARACTERISTICS", + "STATUS_NDIS_ADAPTER_NOT_FOUND", + "STATUS_NDIS_OPEN_FAILED", + "STATUS_NDIS_DEVICE_FAILED", + "STATUS_NDIS_MULTICAST_FULL", + "STATUS_NDIS_MULTICAST_EXISTS", + "STATUS_NDIS_MULTICAST_NOT_FOUND", + "STATUS_NDIS_REQUEST_ABORTED", + "STATUS_NDIS_RESET_IN_PROGRESS", + "STATUS_NDIS_INVALID_PACKET", + "STATUS_NDIS_INVALID_DEVICE_REQUEST", + "STATUS_NDIS_ADAPTER_NOT_READY", + "STATUS_NDIS_INVALID_LENGTH", + "STATUS_NDIS_INVALID_DATA", + "STATUS_NDIS_BUFFER_TOO_SHORT", + "STATUS_NDIS_INVALID_OID", + "STATUS_NDIS_ADAPTER_REMOVED", + "STATUS_NDIS_UNSUPPORTED_MEDIA", + "STATUS_NDIS_GROUP_ADDRESS_IN_USE", + "STATUS_NDIS_FILE_NOT_FOUND", + "STATUS_NDIS_ERROR_READING_FILE", + "STATUS_NDIS_ALREADY_MAPPED", + "STATUS_NDIS_RESOURCE_CONFLICT", + "STATUS_NDIS_MEDIA_DISCONNECTED", + "STATUS_NDIS_INVALID_ADDRESS", + "STATUS_NDIS_PAUSED", + "STATUS_NDIS_INTERFACE_NOT_FOUND", + "STATUS_NDIS_UNSUPPORTED_REVISION", + "STATUS_NDIS_INVALID_PORT", + "STATUS_NDIS_INVALID_PORT_STATE", + "STATUS_NDIS_LOW_POWER_STATE", + "STATUS_NDIS_REINIT_REQUIRED", + "STATUS_NDIS_NO_QUEUES", + "STATUS_NDIS_NOT_SUPPORTED", + "STATUS_NDIS_OFFLOAD_POLICY", + "STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED", + "STATUS_NDIS_OFFLOAD_PATH_REJECTED", + "STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED", + "STATUS_NDIS_DOT11_MEDIA_IN_USE", + "STATUS_NDIS_DOT11_POWER_STATE_INVALID", + "STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL", + "STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL", + "STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE", + "STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE", + "STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED", + "STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED", + "STATUS_QUIC_HANDSHAKE_FAILURE", + "STATUS_QUIC_VER_NEG_FAILURE", + "STATUS_TPM_ERROR_MASK", + "STATUS_TPM_AUTHFAIL", + "STATUS_TPM_BADINDEX", + "STATUS_TPM_BAD_PARAMETER", + "STATUS_TPM_AUDITFAILURE", + "STATUS_TPM_CLEAR_DISABLED", + "STATUS_TPM_DEACTIVATED", + "STATUS_TPM_DISABLED", + "STATUS_TPM_DISABLED_CMD", + "STATUS_TPM_FAIL", + "STATUS_TPM_BAD_ORDINAL", + "STATUS_TPM_INSTALL_DISABLED", + "STATUS_TPM_INVALID_KEYHANDLE", + "STATUS_TPM_KEYNOTFOUND", + "STATUS_TPM_INAPPROPRIATE_ENC", + "STATUS_TPM_MIGRATEFAIL", + "STATUS_TPM_INVALID_PCR_INFO", + "STATUS_TPM_NOSPACE", + "STATUS_TPM_NOSRK", + "STATUS_TPM_NOTSEALED_BLOB", + "STATUS_TPM_OWNER_SET", + "STATUS_TPM_RESOURCES", + "STATUS_TPM_SHORTRANDOM", + "STATUS_TPM_SIZE", + "STATUS_TPM_WRONGPCRVAL", + "STATUS_TPM_BAD_PARAM_SIZE", + "STATUS_TPM_SHA_THREAD", + "STATUS_TPM_SHA_ERROR", + "STATUS_TPM_FAILEDSELFTEST", + "STATUS_TPM_AUTH2FAIL", + "STATUS_TPM_BADTAG", + "STATUS_TPM_IOERROR", + "STATUS_TPM_ENCRYPT_ERROR", + "STATUS_TPM_DECRYPT_ERROR", + "STATUS_TPM_INVALID_AUTHHANDLE", + "STATUS_TPM_NO_ENDORSEMENT", + "STATUS_TPM_INVALID_KEYUSAGE", + "STATUS_TPM_WRONG_ENTITYTYPE", + "STATUS_TPM_INVALID_POSTINIT", + "STATUS_TPM_INAPPROPRIATE_SIG", + "STATUS_TPM_BAD_KEY_PROPERTY", + "STATUS_TPM_BAD_MIGRATION", + "STATUS_TPM_BAD_SCHEME", + "STATUS_TPM_BAD_DATASIZE", + "STATUS_TPM_BAD_MODE", + "STATUS_TPM_BAD_PRESENCE", + "STATUS_TPM_BAD_VERSION", + "STATUS_TPM_NO_WRAP_TRANSPORT", + "STATUS_TPM_AUDITFAIL_UNSUCCESSFUL", + "STATUS_TPM_AUDITFAIL_SUCCESSFUL", + "STATUS_TPM_NOTRESETABLE", + "STATUS_TPM_NOTLOCAL", + "STATUS_TPM_BAD_TYPE", + "STATUS_TPM_INVALID_RESOURCE", + "STATUS_TPM_NOTFIPS", + "STATUS_TPM_INVALID_FAMILY", + "STATUS_TPM_NO_NV_PERMISSION", + "STATUS_TPM_REQUIRES_SIGN", + "STATUS_TPM_KEY_NOTSUPPORTED", + "STATUS_TPM_AUTH_CONFLICT", + "STATUS_TPM_AREA_LOCKED", + "STATUS_TPM_BAD_LOCALITY", + "STATUS_TPM_READ_ONLY", + "STATUS_TPM_PER_NOWRITE", + "STATUS_TPM_FAMILYCOUNT", + "STATUS_TPM_WRITE_LOCKED", + "STATUS_TPM_BAD_ATTRIBUTES", + "STATUS_TPM_INVALID_STRUCTURE", + "STATUS_TPM_KEY_OWNER_CONTROL", + "STATUS_TPM_BAD_COUNTER", + "STATUS_TPM_NOT_FULLWRITE", + "STATUS_TPM_CONTEXT_GAP", + "STATUS_TPM_MAXNVWRITES", + "STATUS_TPM_NOOPERATOR", + "STATUS_TPM_RESOURCEMISSING", + "STATUS_TPM_DELEGATE_LOCK", + "STATUS_TPM_DELEGATE_FAMILY", + "STATUS_TPM_DELEGATE_ADMIN", + "STATUS_TPM_TRANSPORT_NOTEXCLUSIVE", + "STATUS_TPM_OWNER_CONTROL", + "STATUS_TPM_DAA_RESOURCES", + "STATUS_TPM_DAA_INPUT_DATA0", + "STATUS_TPM_DAA_INPUT_DATA1", + "STATUS_TPM_DAA_ISSUER_SETTINGS", + "STATUS_TPM_DAA_TPM_SETTINGS", + "STATUS_TPM_DAA_STAGE", + "STATUS_TPM_DAA_ISSUER_VALIDITY", + "STATUS_TPM_DAA_WRONG_W", + "STATUS_TPM_BAD_HANDLE", + "STATUS_TPM_BAD_DELEGATE", + "STATUS_TPM_BADCONTEXT", + "STATUS_TPM_TOOMANYCONTEXTS", + "STATUS_TPM_MA_TICKET_SIGNATURE", + "STATUS_TPM_MA_DESTINATION", + "STATUS_TPM_MA_SOURCE", + "STATUS_TPM_MA_AUTHORITY", + "STATUS_TPM_PERMANENTEK", + "STATUS_TPM_BAD_SIGNATURE", + "STATUS_TPM_NOCONTEXTSPACE", + "STATUS_TPM_20_E_ASYMMETRIC", + "STATUS_TPM_20_E_ATTRIBUTES", + "STATUS_TPM_20_E_HASH", + "STATUS_TPM_20_E_VALUE", + "STATUS_TPM_20_E_HIERARCHY", + "STATUS_TPM_20_E_KEY_SIZE", + "STATUS_TPM_20_E_MGF", + "STATUS_TPM_20_E_MODE", + "STATUS_TPM_20_E_TYPE", + "STATUS_TPM_20_E_HANDLE", + "STATUS_TPM_20_E_KDF", + "STATUS_TPM_20_E_RANGE", + "STATUS_TPM_20_E_AUTH_FAIL", + "STATUS_TPM_20_E_NONCE", + "STATUS_TPM_20_E_PP", + "STATUS_TPM_20_E_SCHEME", + "STATUS_TPM_20_E_SIZE", + "STATUS_TPM_20_E_SYMMETRIC", + "STATUS_TPM_20_E_TAG", + "STATUS_TPM_20_E_SELECTOR", + "STATUS_TPM_20_E_INSUFFICIENT", + "STATUS_TPM_20_E_SIGNATURE", + "STATUS_TPM_20_E_KEY", + "STATUS_TPM_20_E_POLICY_FAIL", + "STATUS_TPM_20_E_INTEGRITY", + "STATUS_TPM_20_E_TICKET", + "STATUS_TPM_20_E_RESERVED_BITS", + "STATUS_TPM_20_E_BAD_AUTH", + "STATUS_TPM_20_E_EXPIRED", + "STATUS_TPM_20_E_POLICY_CC", + "STATUS_TPM_20_E_BINDING", + "STATUS_TPM_20_E_CURVE", + "STATUS_TPM_20_E_ECC_POINT", + "STATUS_TPM_20_E_INITIALIZE", + "STATUS_TPM_20_E_FAILURE", + "STATUS_TPM_20_E_SEQUENCE", + "STATUS_TPM_20_E_PRIVATE", + "STATUS_TPM_20_E_HMAC", + "STATUS_TPM_20_E_DISABLED", + "STATUS_TPM_20_E_EXCLUSIVE", + "STATUS_TPM_20_E_ECC_CURVE", + "STATUS_TPM_20_E_AUTH_TYPE", + "STATUS_TPM_20_E_AUTH_MISSING", + "STATUS_TPM_20_E_POLICY", + "STATUS_TPM_20_E_PCR", + "STATUS_TPM_20_E_PCR_CHANGED", + "STATUS_TPM_20_E_UPGRADE", + "STATUS_TPM_20_E_TOO_MANY_CONTEXTS", + "STATUS_TPM_20_E_AUTH_UNAVAILABLE", + "STATUS_TPM_20_E_REBOOT", + "STATUS_TPM_20_E_UNBALANCED", + "STATUS_TPM_20_E_COMMAND_SIZE", + "STATUS_TPM_20_E_COMMAND_CODE", + "STATUS_TPM_20_E_AUTHSIZE", + "STATUS_TPM_20_E_AUTH_CONTEXT", + "STATUS_TPM_20_E_NV_RANGE", + "STATUS_TPM_20_E_NV_SIZE", + "STATUS_TPM_20_E_NV_LOCKED", + "STATUS_TPM_20_E_NV_AUTHORIZATION", + "STATUS_TPM_20_E_NV_UNINITIALIZED", + "STATUS_TPM_20_E_NV_SPACE", + "STATUS_TPM_20_E_NV_DEFINED", + "STATUS_TPM_20_E_BAD_CONTEXT", + "STATUS_TPM_20_E_CPHASH", + "STATUS_TPM_20_E_PARENT", + "STATUS_TPM_20_E_NEEDS_TEST", + "STATUS_TPM_20_E_NO_RESULT", + "STATUS_TPM_20_E_SENSITIVE", + "STATUS_TPM_COMMAND_BLOCKED", + "STATUS_TPM_INVALID_HANDLE", + "STATUS_TPM_DUPLICATE_VHANDLE", + "STATUS_TPM_EMBEDDED_COMMAND_BLOCKED", + "STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED", + "STATUS_TPM_RETRY", + "STATUS_TPM_NEEDS_SELFTEST", + "STATUS_TPM_DOING_SELFTEST", + "STATUS_TPM_DEFEND_LOCK_RUNNING", + "STATUS_TPM_COMMAND_CANCELED", + "STATUS_TPM_TOO_MANY_CONTEXTS", + "STATUS_TPM_NOT_FOUND", + "STATUS_TPM_ACCESS_DENIED", + "STATUS_TPM_INSUFFICIENT_BUFFER", + "STATUS_TPM_PPI_FUNCTION_UNSUPPORTED", + "STATUS_PCP_ERROR_MASK", + "STATUS_PCP_DEVICE_NOT_READY", + "STATUS_PCP_INVALID_HANDLE", + "STATUS_PCP_INVALID_PARAMETER", + "STATUS_PCP_FLAG_NOT_SUPPORTED", + "STATUS_PCP_NOT_SUPPORTED", + "STATUS_PCP_BUFFER_TOO_SMALL", + "STATUS_PCP_INTERNAL_ERROR", + "STATUS_PCP_AUTHENTICATION_FAILED", + "STATUS_PCP_AUTHENTICATION_IGNORED", + "STATUS_PCP_POLICY_NOT_FOUND", + "STATUS_PCP_PROFILE_NOT_FOUND", + "STATUS_PCP_VALIDATION_FAILED", + "STATUS_PCP_DEVICE_NOT_FOUND", + "STATUS_PCP_WRONG_PARENT", + "STATUS_PCP_KEY_NOT_LOADED", + "STATUS_PCP_NO_KEY_CERTIFICATION", + "STATUS_PCP_KEY_NOT_FINALIZED", + "STATUS_PCP_ATTESTATION_CHALLENGE_NOT_SET", + "STATUS_PCP_NOT_PCR_BOUND", + "STATUS_PCP_KEY_ALREADY_FINALIZED", + "STATUS_PCP_KEY_USAGE_POLICY_NOT_SUPPORTED", + "STATUS_PCP_KEY_USAGE_POLICY_INVALID", + "STATUS_PCP_SOFT_KEY_ERROR", + "STATUS_PCP_KEY_NOT_AUTHENTICATED", + "STATUS_PCP_KEY_NOT_AIK", + "STATUS_PCP_KEY_NOT_SIGNING_KEY", + "STATUS_PCP_LOCKED_OUT", + "STATUS_PCP_CLAIM_TYPE_NOT_SUPPORTED", + "STATUS_PCP_TPM_VERSION_NOT_SUPPORTED", + "STATUS_PCP_BUFFER_LENGTH_MISMATCH", + "STATUS_PCP_IFX_RSA_KEY_CREATION_BLOCKED", + "STATUS_PCP_TICKET_MISSING", + "STATUS_PCP_RAW_POLICY_NOT_SUPPORTED", + "STATUS_PCP_KEY_HANDLE_INVALIDATED", + "STATUS_RTPM_NO_RESULT", + "STATUS_RTPM_PCR_READ_INCOMPLETE", + "STATUS_RTPM_INVALID_CONTEXT", + "STATUS_RTPM_UNSUPPORTED_CMD", + "STATUS_TPM_ZERO_EXHAUST_ENABLED", + "STATUS_HV_INVALID_HYPERCALL_CODE", + "STATUS_HV_INVALID_HYPERCALL_INPUT", + "STATUS_HV_INVALID_ALIGNMENT", + "STATUS_HV_INVALID_PARAMETER", + "STATUS_HV_ACCESS_DENIED", + "STATUS_HV_INVALID_PARTITION_STATE", + "STATUS_HV_OPERATION_DENIED", + "STATUS_HV_UNKNOWN_PROPERTY", + "STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE", + "STATUS_HV_INSUFFICIENT_MEMORY", + "STATUS_HV_PARTITION_TOO_DEEP", + "STATUS_HV_INVALID_PARTITION_ID", + "STATUS_HV_INVALID_VP_INDEX", + "STATUS_HV_INVALID_PORT_ID", + "STATUS_HV_INVALID_CONNECTION_ID", + "STATUS_HV_INSUFFICIENT_BUFFERS", + "STATUS_HV_NOT_ACKNOWLEDGED", + "STATUS_HV_INVALID_VP_STATE", + "STATUS_HV_ACKNOWLEDGED", + "STATUS_HV_INVALID_SAVE_RESTORE_STATE", + "STATUS_HV_INVALID_SYNIC_STATE", + "STATUS_HV_OBJECT_IN_USE", + "STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO", + "STATUS_HV_NO_DATA", + "STATUS_HV_INACTIVE", + "STATUS_HV_NO_RESOURCES", + "STATUS_HV_FEATURE_UNAVAILABLE", + "STATUS_HV_INSUFFICIENT_BUFFER", + "STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS", + "STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR", + "STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR", + "STATUS_HV_PROCESSOR_STARTUP_TIMEOUT", + "STATUS_HV_SMX_ENABLED", + "STATUS_HV_INVALID_LP_INDEX", + "STATUS_HV_INVALID_REGISTER_VALUE", + "STATUS_HV_INVALID_VTL_STATE", + "STATUS_HV_NX_NOT_DETECTED", + "STATUS_HV_INVALID_DEVICE_ID", + "STATUS_HV_INVALID_DEVICE_STATE", + "STATUS_HV_PAGE_REQUEST_INVALID", + "STATUS_HV_INVALID_CPU_GROUP_ID", + "STATUS_HV_INVALID_CPU_GROUP_STATE", + "STATUS_HV_OPERATION_FAILED", + "STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE", + "STATUS_HV_INSUFFICIENT_ROOT_MEMORY", + "STATUS_HV_EVENT_BUFFER_ALREADY_FREED", + "STATUS_HV_INSUFFICIENT_CONTIGUOUS_MEMORY", + "STATUS_HV_NOT_PRESENT", + "STATUS_IPSEC_BAD_SPI", + "STATUS_IPSEC_SA_LIFETIME_EXPIRED", + "STATUS_IPSEC_WRONG_SA", + "STATUS_IPSEC_REPLAY_CHECK_FAILED", + "STATUS_IPSEC_INVALID_PACKET", + "STATUS_IPSEC_INTEGRITY_CHECK_FAILED", + "STATUS_IPSEC_CLEAR_TEXT_DROP", + "STATUS_IPSEC_AUTH_FIREWALL_DROP", + "STATUS_IPSEC_THROTTLE_DROP", + "STATUS_IPSEC_DOSP_BLOCK", + "STATUS_IPSEC_DOSP_RECEIVED_MULTICAST", + "STATUS_IPSEC_DOSP_INVALID_PACKET", + "STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED", + "STATUS_IPSEC_DOSP_MAX_ENTRIES", + "STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED", + "STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES", + "STATUS_VID_DUPLICATE_HANDLER", + "STATUS_VID_TOO_MANY_HANDLERS", + "STATUS_VID_QUEUE_FULL", + "STATUS_VID_HANDLER_NOT_PRESENT", + "STATUS_VID_INVALID_OBJECT_NAME", + "STATUS_VID_PARTITION_NAME_TOO_LONG", + "STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG", + "STATUS_VID_PARTITION_ALREADY_EXISTS", + "STATUS_VID_PARTITION_DOES_NOT_EXIST", + "STATUS_VID_PARTITION_NAME_NOT_FOUND", + "STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS", + "STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT", + "STATUS_VID_MB_STILL_REFERENCED", + "STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED", + "STATUS_VID_INVALID_NUMA_SETTINGS", + "STATUS_VID_INVALID_NUMA_NODE_INDEX", + "STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED", + "STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE", + "STATUS_VID_PAGE_RANGE_OVERFLOW", + "STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE", + "STATUS_VID_INVALID_GPA_RANGE_HANDLE", + "STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE", + "STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED", + "STATUS_VID_INVALID_PPM_HANDLE", + "STATUS_VID_MBPS_ARE_LOCKED", + "STATUS_VID_MESSAGE_QUEUE_CLOSED", + "STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED", + "STATUS_VID_STOP_PENDING", + "STATUS_VID_INVALID_PROCESSOR_STATE", + "STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT", + "STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED", + "STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET", + "STATUS_VID_MMIO_RANGE_DESTROYED", + "STATUS_VID_INVALID_CHILD_GPA_PAGE_SET", + "STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED", + "STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL", + "STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE", + "STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT", + "STATUS_VID_SAVED_STATE_CORRUPT", + "STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM", + "STATUS_VID_SAVED_STATE_INCOMPATIBLE", + "STATUS_VID_VTL_ACCESS_DENIED", + "STATUS_VOLMGR_DATABASE_FULL", + "STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED", + "STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC", + "STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED", + "STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME", + "STATUS_VOLMGR_DISK_DUPLICATE", + "STATUS_VOLMGR_DISK_DYNAMIC", + "STATUS_VOLMGR_DISK_ID_INVALID", + "STATUS_VOLMGR_DISK_INVALID", + "STATUS_VOLMGR_DISK_LAST_VOTER", + "STATUS_VOLMGR_DISK_LAYOUT_INVALID", + "STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS", + "STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED", + "STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL", + "STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS", + "STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS", + "STATUS_VOLMGR_DISK_MISSING", + "STATUS_VOLMGR_DISK_NOT_EMPTY", + "STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE", + "STATUS_VOLMGR_DISK_REVECTORING_FAILED", + "STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID", + "STATUS_VOLMGR_DISK_SET_NOT_CONTAINED", + "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS", + "STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES", + "STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED", + "STATUS_VOLMGR_EXTENT_ALREADY_USED", + "STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS", + "STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION", + "STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED", + "STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION", + "STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH", + "STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED", + "STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID", + "STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS", + "STATUS_VOLMGR_MEMBER_IN_SYNC", + "STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE", + "STATUS_VOLMGR_MEMBER_INDEX_INVALID", + "STATUS_VOLMGR_MEMBER_MISSING", + "STATUS_VOLMGR_MEMBER_NOT_DETACHED", + "STATUS_VOLMGR_MEMBER_REGENERATING", + "STATUS_VOLMGR_ALL_DISKS_FAILED", + "STATUS_VOLMGR_NO_REGISTERED_USERS", + "STATUS_VOLMGR_NO_SUCH_USER", + "STATUS_VOLMGR_NOTIFICATION_RESET", + "STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID", + "STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID", + "STATUS_VOLMGR_PACK_DUPLICATE", + "STATUS_VOLMGR_PACK_ID_INVALID", + "STATUS_VOLMGR_PACK_INVALID", + "STATUS_VOLMGR_PACK_NAME_INVALID", + "STATUS_VOLMGR_PACK_OFFLINE", + "STATUS_VOLMGR_PACK_HAS_QUORUM", + "STATUS_VOLMGR_PACK_WITHOUT_QUORUM", + "STATUS_VOLMGR_PARTITION_STYLE_INVALID", + "STATUS_VOLMGR_PARTITION_UPDATE_FAILED", + "STATUS_VOLMGR_PLEX_IN_SYNC", + "STATUS_VOLMGR_PLEX_INDEX_DUPLICATE", + "STATUS_VOLMGR_PLEX_INDEX_INVALID", + "STATUS_VOLMGR_PLEX_LAST_ACTIVE", + "STATUS_VOLMGR_PLEX_MISSING", + "STATUS_VOLMGR_PLEX_REGENERATING", + "STATUS_VOLMGR_PLEX_TYPE_INVALID", + "STATUS_VOLMGR_PLEX_NOT_RAID5", + "STATUS_VOLMGR_PLEX_NOT_SIMPLE", + "STATUS_VOLMGR_STRUCTURE_SIZE_INVALID", + "STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS", + "STATUS_VOLMGR_TRANSACTION_IN_PROGRESS", + "STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE", + "STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK", + "STATUS_VOLMGR_VOLUME_ID_INVALID", + "STATUS_VOLMGR_VOLUME_LENGTH_INVALID", + "STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE", + "STATUS_VOLMGR_VOLUME_NOT_MIRRORED", + "STATUS_VOLMGR_VOLUME_NOT_RETAINED", + "STATUS_VOLMGR_VOLUME_OFFLINE", + "STATUS_VOLMGR_VOLUME_RETAINED", + "STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID", + "STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE", + "STATUS_VOLMGR_BAD_BOOT_DISK", + "STATUS_VOLMGR_PACK_CONFIG_OFFLINE", + "STATUS_VOLMGR_PACK_CONFIG_ONLINE", + "STATUS_VOLMGR_NOT_PRIMARY_PACK", + "STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED", + "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID", + "STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID", + "STATUS_VOLMGR_VOLUME_MIRRORED", + "STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED", + "STATUS_VOLMGR_NO_VALID_LOG_COPIES", + "STATUS_VOLMGR_PRIMARY_PACK_PRESENT", + "STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID", + "STATUS_VOLMGR_MIRROR_NOT_SUPPORTED", + "STATUS_VOLMGR_RAID5_NOT_SUPPORTED", + "STATUS_BCD_TOO_MANY_ELEMENTS", + "STATUS_VHD_DRIVE_FOOTER_MISSING", + "STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH", + "STATUS_VHD_DRIVE_FOOTER_CORRUPT", + "STATUS_VHD_FORMAT_UNKNOWN", + "STATUS_VHD_FORMAT_UNSUPPORTED_VERSION", + "STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH", + "STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION", + "STATUS_VHD_SPARSE_HEADER_CORRUPT", + "STATUS_VHD_BLOCK_ALLOCATION_FAILURE", + "STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT", + "STATUS_VHD_INVALID_BLOCK_SIZE", + "STATUS_VHD_BITMAP_MISMATCH", + "STATUS_VHD_PARENT_VHD_NOT_FOUND", + "STATUS_VHD_CHILD_PARENT_ID_MISMATCH", + "STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH", + "STATUS_VHD_METADATA_READ_FAILURE", + "STATUS_VHD_METADATA_WRITE_FAILURE", + "STATUS_VHD_INVALID_SIZE", + "STATUS_VHD_INVALID_FILE_SIZE", + "STATUS_VIRTDISK_PROVIDER_NOT_FOUND", + "STATUS_VIRTDISK_NOT_VIRTUAL_DISK", + "STATUS_VHD_PARENT_VHD_ACCESS_DENIED", + "STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH", + "STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED", + "STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT", + "STATUS_VIRTUAL_DISK_LIMITATION", + "STATUS_VHD_INVALID_TYPE", + "STATUS_VHD_INVALID_STATE", + "STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE", + "STATUS_VIRTDISK_DISK_ALREADY_OWNED", + "STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE", + "STATUS_CTLOG_TRACKING_NOT_INITIALIZED", + "STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE", + "STATUS_CTLOG_VHD_CHANGED_OFFLINE", + "STATUS_CTLOG_INVALID_TRACKING_STATE", + "STATUS_CTLOG_INCONSISTENT_TRACKING_FILE", + "STATUS_VHD_METADATA_FULL", + "STATUS_VHD_INVALID_CHANGE_TRACKING_ID", + "STATUS_VHD_CHANGE_TRACKING_DISABLED", + "STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION", + "STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA", + "STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE", + "STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE", + "STATUS_RKF_KEY_NOT_FOUND", + "STATUS_RKF_DUPLICATE_KEY", + "STATUS_RKF_BLOB_FULL", + "STATUS_RKF_STORE_FULL", + "STATUS_RKF_FILE_BLOCKED", + "STATUS_RKF_ACTIVE_KEY", + "STATUS_RDBSS_RESTART_OPERATION", + "STATUS_RDBSS_CONTINUE_OPERATION", + "STATUS_RDBSS_POST_OPERATION", + "STATUS_RDBSS_RETRY_LOOKUP", + "STATUS_BTH_ATT_INVALID_HANDLE", + "STATUS_BTH_ATT_READ_NOT_PERMITTED", + "STATUS_BTH_ATT_WRITE_NOT_PERMITTED", + "STATUS_BTH_ATT_INVALID_PDU", + "STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION", + "STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED", + "STATUS_BTH_ATT_INVALID_OFFSET", + "STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION", + "STATUS_BTH_ATT_PREPARE_QUEUE_FULL", + "STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND", + "STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG", + "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE", + "STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH", + "STATUS_BTH_ATT_UNLIKELY", + "STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION", + "STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE", + "STATUS_BTH_ATT_INSUFFICIENT_RESOURCES", + "STATUS_BTH_ATT_UNKNOWN_ERROR", + "STATUS_SECUREBOOT_ROLLBACK_DETECTED", + "STATUS_SECUREBOOT_POLICY_VIOLATION", + "STATUS_SECUREBOOT_INVALID_POLICY", + "STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND", + "STATUS_SECUREBOOT_POLICY_NOT_SIGNED", + "STATUS_SECUREBOOT_FILE_REPLACED", + "STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED", + "STATUS_SECUREBOOT_POLICY_UNKNOWN", + "STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION", + "STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH", + "STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED", + "STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH", + "STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING", + "STATUS_SECUREBOOT_NOT_BASE_POLICY", + "STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY", + "STATUS_AUDIO_ENGINE_NODE_NOT_FOUND", + "STATUS_HDAUDIO_EMPTY_CONNECTION_LIST", + "STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED", + "STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED", + "STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY", + "STATUS_VSM_NOT_INITIALIZED", + "STATUS_VSM_DMA_PROTECTION_NOT_IN_USE", + "STATUS_VOLSNAP_BOOTFILE_NOT_VALID", + "STATUS_VOLSNAP_ACTIVATION_TIMEOUT", + "STATUS_IO_PREEMPTED", + "STATUS_SVHDX_ERROR_STORED", + "STATUS_SVHDX_ERROR_NOT_AVAILABLE", + "STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE", + "STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED", + "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED", + "STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED", + "STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED", + "STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED", + "STATUS_SVHDX_RESERVATION_CONFLICT", + "STATUS_SVHDX_WRONG_FILE_TYPE", + "STATUS_SVHDX_VERSION_MISMATCH", + "STATUS_VHD_SHARED", + "STATUS_SVHDX_NO_INITIATOR", + "STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND", + "STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", + "STATUS_SMB_BAD_CLUSTER_DIALECT", + "STATUS_SMB_GUEST_LOGON_BLOCKED", + "STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID", + "STATUS_SPACES_RESILIENCY_TYPE_INVALID", + "STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID", + "STATUS_SPACES_DRIVE_REDUNDANCY_INVALID", + "STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID", + "STATUS_SPACES_INTERLEAVE_LENGTH_INVALID", + "STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID", + "STATUS_SPACES_NOT_ENOUGH_DRIVES", + "STATUS_SPACES_EXTENDED_ERROR", + "STATUS_SPACES_PROVISIONING_TYPE_INVALID", + "STATUS_SPACES_ALLOCATION_SIZE_INVALID", + "STATUS_SPACES_ENCLOSURE_AWARE_INVALID", + "STATUS_SPACES_WRITE_CACHE_SIZE_INVALID", + "STATUS_SPACES_NUMBER_OF_GROUPS_INVALID", + "STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID", + "STATUS_SPACES_UPDATE_COLUMN_STATE", + "STATUS_SPACES_MAP_REQUIRED", + "STATUS_SPACES_UNSUPPORTED_VERSION", + "STATUS_SPACES_CORRUPT_METADATA", + "STATUS_SPACES_DRT_FULL", + "STATUS_SPACES_INCONSISTENCY", + "STATUS_SPACES_LOG_NOT_READY", + "STATUS_SPACES_NO_REDUNDANCY", + "STATUS_SPACES_DRIVE_NOT_READY", + "STATUS_SPACES_DRIVE_SPLIT", + "STATUS_SPACES_DRIVE_LOST_DATA", + "STATUS_SPACES_ENTRY_INCOMPLETE", + "STATUS_SPACES_ENTRY_INVALID", + "STATUS_SPACES_MARK_DIRTY", + "STATUS_SECCORE_INVALID_COMMAND", + "STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED", + "STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION", + "STATUS_SYSTEM_INTEGRITY_INVALID_POLICY", + "STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED", + "STATUS_SYSTEM_INTEGRITY_TOO_MANY_POLICIES", + "STATUS_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED", + "STATUS_NO_APPLICABLE_APP_LICENSES_FOUND", + "STATUS_CLIP_LICENSE_NOT_FOUND", + "STATUS_CLIP_DEVICE_LICENSE_MISSING", + "STATUS_CLIP_LICENSE_INVALID_SIGNATURE", + "STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID", + "STATUS_CLIP_LICENSE_EXPIRED", + "STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE", + "STATUS_CLIP_LICENSE_NOT_SIGNED", + "STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE", + "STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH", + "STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED", + "STATUS_PLATFORM_MANIFEST_INVALID", + "STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED", + "STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED", + "STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND", + "STATUS_PLATFORM_MANIFEST_NOT_ACTIVE", + "STATUS_PLATFORM_MANIFEST_NOT_SIGNED", + "STATUS_APPEXEC_CONDITION_NOT_SATISFIED", + "STATUS_APPEXEC_HANDLE_INVALIDATED", + "STATUS_APPEXEC_INVALID_HOST_GENERATION", + "STATUS_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION", + "STATUS_APPEXEC_INVALID_HOST_STATE", + "STATUS_APPEXEC_NO_DONOR", + "STATUS_APPEXEC_HOST_ID_MISMATCH", + "STATUS_APPEXEC_UNKNOWN_USER", +}; + +const char* NTStatusToString(uint32_t ntstatus) { + auto itr = std::find(std::begin(kNTStatusValues), + std::end(kNTStatusValues), + ntstatus); + if (itr == std::end(kNTStatusValues)) { + return nullptr; + } + + return kNTStatusStrings[itr - std::begin(kNTStatusValues)]; +} + +// The content of this array was created from winnt.h in the 10 SDK +// (version 10.0.19041.0) with the following script: +// +// egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h +// | tr -d '\r' +// | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' +// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_FAST_FAIL_WIN_\2,@' +// | head -n -1 +static const uint8_t kFastFailValues[] = { + MD_FAST_FAIL_WIN_LEGACY_GS_VIOLATION, + MD_FAST_FAIL_WIN_VTGUARD_CHECK_FAILURE, + MD_FAST_FAIL_WIN_STACK_COOKIE_CHECK_FAILURE, + MD_FAST_FAIL_WIN_CORRUPT_LIST_ENTRY, + MD_FAST_FAIL_WIN_INCORRECT_STACK, + MD_FAST_FAIL_WIN_INVALID_ARG, + MD_FAST_FAIL_WIN_GS_COOKIE_INIT, + MD_FAST_FAIL_WIN_FATAL_APP_EXIT, + MD_FAST_FAIL_WIN_RANGE_CHECK_FAILURE, + MD_FAST_FAIL_WIN_UNSAFE_REGISTRY_ACCESS, + MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_FAILURE, + MD_FAST_FAIL_WIN_GUARD_WRITE_CHECK_FAILURE, + MD_FAST_FAIL_WIN_INVALID_FIBER_SWITCH, + MD_FAST_FAIL_WIN_INVALID_SET_OF_CONTEXT, + MD_FAST_FAIL_WIN_INVALID_REFERENCE_COUNT, + MD_FAST_FAIL_WIN_INVALID_JUMP_BUFFER, + MD_FAST_FAIL_WIN_MRDATA_MODIFIED, + MD_FAST_FAIL_WIN_CERTIFICATION_FAILURE, + MD_FAST_FAIL_WIN_INVALID_EXCEPTION_CHAIN, + MD_FAST_FAIL_WIN_CRYPTO_LIBRARY, + MD_FAST_FAIL_WIN_INVALID_CALL_IN_DLL_CALLOUT, + MD_FAST_FAIL_WIN_INVALID_IMAGE_BASE, + MD_FAST_FAIL_WIN_DLOAD_PROTECTION_FAILURE, + MD_FAST_FAIL_WIN_UNSAFE_EXTENSION_CALL, + MD_FAST_FAIL_WIN_DEPRECATED_SERVICE_INVOKED, + MD_FAST_FAIL_WIN_INVALID_BUFFER_ACCESS, + MD_FAST_FAIL_WIN_INVALID_BALANCED_TREE, + MD_FAST_FAIL_WIN_INVALID_NEXT_THREAD, + MD_FAST_FAIL_WIN_GUARD_ICALL_CHECK_SUPPRESSED, + MD_FAST_FAIL_WIN_APCS_DISABLED, + MD_FAST_FAIL_WIN_INVALID_IDLE_STATE, + MD_FAST_FAIL_WIN_MRDATA_PROTECTION_FAILURE, + MD_FAST_FAIL_WIN_UNEXPECTED_HEAP_EXCEPTION, + MD_FAST_FAIL_WIN_INVALID_LOCK_STATE, + MD_FAST_FAIL_WIN_GUARD_JUMPTABLE, + MD_FAST_FAIL_WIN_INVALID_LONGJUMP_TARGET, + MD_FAST_FAIL_WIN_INVALID_DISPATCH_CONTEXT, + MD_FAST_FAIL_WIN_INVALID_THREAD, + MD_FAST_FAIL_WIN_INVALID_SYSCALL_NUMBER, + MD_FAST_FAIL_WIN_INVALID_FILE_OPERATION, + MD_FAST_FAIL_WIN_LPAC_ACCESS_DENIED, + MD_FAST_FAIL_WIN_GUARD_SS_FAILURE, + MD_FAST_FAIL_WIN_LOADER_CONTINUITY_FAILURE, + MD_FAST_FAIL_WIN_GUARD_EXPORT_SUPPRESSION_FAILURE, + MD_FAST_FAIL_WIN_INVALID_CONTROL_STACK, + MD_FAST_FAIL_WIN_SET_CONTEXT_DENIED, + MD_FAST_FAIL_WIN_INVALID_IAT, + MD_FAST_FAIL_WIN_HEAP_METADATA_CORRUPTION, + MD_FAST_FAIL_WIN_PAYLOAD_RESTRICTION_VIOLATION, + MD_FAST_FAIL_WIN_LOW_LABEL_ACCESS_DENIED, + MD_FAST_FAIL_WIN_ENCLAVE_CALL_FAILURE, + MD_FAST_FAIL_WIN_UNHANDLED_LSS_EXCEPTON, + MD_FAST_FAIL_WIN_ADMINLESS_ACCESS_DENIED, + MD_FAST_FAIL_WIN_UNEXPECTED_CALL, + MD_FAST_FAIL_WIN_CONTROL_INVALID_RETURN_ADDRESS, + MD_FAST_FAIL_WIN_UNEXPECTED_HOST_BEHAVIOR, + MD_FAST_FAIL_WIN_FLAGS_CORRUPTION, + MD_FAST_FAIL_WIN_VEH_CORRUPTION, + MD_FAST_FAIL_WIN_ETW_CORRUPTION, + MD_FAST_FAIL_WIN_RIO_ABORT, + MD_FAST_FAIL_WIN_INVALID_PFN, +}; + +// The content of this array was created from winnt.h in the 10 SDK +// (version 10.0.19041.0) with the following script: +// +// egrep '#define FAST_FAIL_[A-Z_0-9]+\s+[0-9]' winnt.h +// | tr -d '\r' +// | sed -r 's@#define FAST_FAIL_([A-Z_0-9]+)\s+([0-9]+).*@\2 \1@' +// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ "FAST_FAIL_\2",@' +// | head -n -1 +static const char* kFastFailStrings[] = { + "FAST_FAIL_LEGACY_GS_VIOLATION", + "FAST_FAIL_VTGUARD_CHECK_FAILURE", + "FAST_FAIL_STACK_COOKIE_CHECK_FAILURE", + "FAST_FAIL_CORRUPT_LIST_ENTRY", + "FAST_FAIL_INCORRECT_STACK", + "FAST_FAIL_INVALID_ARG", + "FAST_FAIL_GS_COOKIE_INIT", + "FAST_FAIL_FATAL_APP_EXIT", + "FAST_FAIL_RANGE_CHECK_FAILURE", + "FAST_FAIL_UNSAFE_REGISTRY_ACCESS", + "FAST_FAIL_GUARD_ICALL_CHECK_FAILURE", + "FAST_FAIL_GUARD_WRITE_CHECK_FAILURE", + "FAST_FAIL_INVALID_FIBER_SWITCH", + "FAST_FAIL_INVALID_SET_OF_CONTEXT", + "FAST_FAIL_INVALID_REFERENCE_COUNT", + "FAST_FAIL_INVALID_JUMP_BUFFER", + "FAST_FAIL_MRDATA_MODIFIED", + "FAST_FAIL_CERTIFICATION_FAILURE", + "FAST_FAIL_INVALID_EXCEPTION_CHAIN", + "FAST_FAIL_CRYPTO_LIBRARY", + "FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT", + "FAST_FAIL_INVALID_IMAGE_BASE", + "FAST_FAIL_DLOAD_PROTECTION_FAILURE", + "FAST_FAIL_UNSAFE_EXTENSION_CALL", + "FAST_FAIL_DEPRECATED_SERVICE_INVOKED", + "FAST_FAIL_INVALID_BUFFER_ACCESS", + "FAST_FAIL_INVALID_BALANCED_TREE", + "FAST_FAIL_INVALID_NEXT_THREAD", + "FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED", + "FAST_FAIL_APCS_DISABLED", + "FAST_FAIL_INVALID_IDLE_STATE", + "FAST_FAIL_MRDATA_PROTECTION_FAILURE", + "FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION", + "FAST_FAIL_INVALID_LOCK_STATE", + "FAST_FAIL_GUARD_JUMPTABLE", + "FAST_FAIL_INVALID_LONGJUMP_TARGET", + "FAST_FAIL_INVALID_DISPATCH_CONTEXT", + "FAST_FAIL_INVALID_THREAD", + "FAST_FAIL_INVALID_SYSCALL_NUMBER", + "FAST_FAIL_INVALID_FILE_OPERATION", + "FAST_FAIL_LPAC_ACCESS_DENIED", + "FAST_FAIL_GUARD_SS_FAILURE", + "FAST_FAIL_LOADER_CONTINUITY_FAILURE", + "FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE", + "FAST_FAIL_INVALID_CONTROL_STACK", + "FAST_FAIL_SET_CONTEXT_DENIED", + "FAST_FAIL_INVALID_IAT", + "FAST_FAIL_HEAP_METADATA_CORRUPTION", + "FAST_FAIL_PAYLOAD_RESTRICTION_VIOLATION", + "FAST_FAIL_LOW_LABEL_ACCESS_DENIED", + "FAST_FAIL_ENCLAVE_CALL_FAILURE", + "FAST_FAIL_UNHANDLED_LSS_EXCEPTON", + "FAST_FAIL_ADMINLESS_ACCESS_DENIED", + "FAST_FAIL_UNEXPECTED_CALL", + "FAST_FAIL_CONTROL_INVALID_RETURN_ADDRESS", + "FAST_FAIL_UNEXPECTED_HOST_BEHAVIOR", + "FAST_FAIL_FLAGS_CORRUPTION", + "FAST_FAIL_VEH_CORRUPTION", + "FAST_FAIL_ETW_CORRUPTION", + "FAST_FAIL_RIO_ABORT", + "FAST_FAIL_INVALID_PFN", +}; + +const char* FastFailToString(uint32_t fast_fail_code) { + auto itr = std::find(std::begin(kFastFailValues), + std::end(kFastFailValues), + fast_fail_code); + if (itr == std::end(kFastFailValues)) { + return nullptr; + } + + return kFastFailStrings[itr - std::begin(kFastFailValues)]; +} + +// The content of this array was created from winerror.h in the 10 SDK +// (version 10.0.19041.0) with the following script: +// +// egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h +// | tr -d '\r' +// | sed -r 's@#define ERROR_([A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' +// | sort -n +// | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ MD_ERROR_WIN_\2,@' +static const uint16_t kWinErrorValues[] = { + MD_ERROR_WIN_SUCCESS, + MD_ERROR_WIN_INVALID_FUNCTION, + MD_ERROR_WIN_FILE_NOT_FOUND, + MD_ERROR_WIN_PATH_NOT_FOUND, + MD_ERROR_WIN_TOO_MANY_OPEN_FILES, + MD_ERROR_WIN_ACCESS_DENIED, + MD_ERROR_WIN_INVALID_HANDLE, + MD_ERROR_WIN_ARENA_TRASHED, + MD_ERROR_WIN_NOT_ENOUGH_MEMORY, + MD_ERROR_WIN_INVALID_BLOCK, + MD_ERROR_WIN_BAD_ENVIRONMENT, + MD_ERROR_WIN_BAD_FORMAT, + MD_ERROR_WIN_INVALID_ACCESS, + MD_ERROR_WIN_INVALID_DATA, + MD_ERROR_WIN_OUTOFMEMORY, + MD_ERROR_WIN_INVALID_DRIVE, + MD_ERROR_WIN_CURRENT_DIRECTORY, + MD_ERROR_WIN_NOT_SAME_DEVICE, + MD_ERROR_WIN_NO_MORE_FILES, + MD_ERROR_WIN_WRITE_PROTECT, + MD_ERROR_WIN_BAD_UNIT, + MD_ERROR_WIN_NOT_READY, + MD_ERROR_WIN_BAD_COMMAND, + MD_ERROR_WIN_CRC, + MD_ERROR_WIN_BAD_LENGTH, + MD_ERROR_WIN_SEEK, + MD_ERROR_WIN_NOT_DOS_DISK, + MD_ERROR_WIN_SECTOR_NOT_FOUND, + MD_ERROR_WIN_OUT_OF_PAPER, + MD_ERROR_WIN_WRITE_FAULT, + MD_ERROR_WIN_READ_FAULT, + MD_ERROR_WIN_GEN_FAILURE, + MD_ERROR_WIN_SHARING_VIOLATION, + MD_ERROR_WIN_LOCK_VIOLATION, + MD_ERROR_WIN_WRONG_DISK, + MD_ERROR_WIN_SHARING_BUFFER_EXCEEDED, + MD_ERROR_WIN_HANDLE_EOF, + MD_ERROR_WIN_HANDLE_DISK_FULL, + MD_ERROR_WIN_NOT_SUPPORTED, + MD_ERROR_WIN_REM_NOT_LIST, + MD_ERROR_WIN_DUP_NAME, + MD_ERROR_WIN_BAD_NETPATH, + MD_ERROR_WIN_NETWORK_BUSY, + MD_ERROR_WIN_DEV_NOT_EXIST, + MD_ERROR_WIN_TOO_MANY_CMDS, + MD_ERROR_WIN_ADAP_HDW_ERR, + MD_ERROR_WIN_BAD_NET_RESP, + MD_ERROR_WIN_UNEXP_NET_ERR, + MD_ERROR_WIN_BAD_REM_ADAP, + MD_ERROR_WIN_PRINTQ_FULL, + MD_ERROR_WIN_NO_SPOOL_SPACE, + MD_ERROR_WIN_PRINT_CANCELLED, + MD_ERROR_WIN_NETNAME_DELETED, + MD_ERROR_WIN_NETWORK_ACCESS_DENIED, + MD_ERROR_WIN_BAD_DEV_TYPE, + MD_ERROR_WIN_BAD_NET_NAME, + MD_ERROR_WIN_TOO_MANY_NAMES, + MD_ERROR_WIN_TOO_MANY_SESS, + MD_ERROR_WIN_SHARING_PAUSED, + MD_ERROR_WIN_REQ_NOT_ACCEP, + MD_ERROR_WIN_REDIR_PAUSED, + MD_ERROR_WIN_FILE_EXISTS, + MD_ERROR_WIN_CANNOT_MAKE, + MD_ERROR_WIN_FAIL_I24, + MD_ERROR_WIN_OUT_OF_STRUCTURES, + MD_ERROR_WIN_ALREADY_ASSIGNED, + MD_ERROR_WIN_INVALID_PASSWORD, + MD_ERROR_WIN_INVALID_PARAMETER, + MD_ERROR_WIN_NET_WRITE_FAULT, + MD_ERROR_WIN_NO_PROC_SLOTS, + MD_ERROR_WIN_TOO_MANY_SEMAPHORES, + MD_ERROR_WIN_EXCL_SEM_ALREADY_OWNED, + MD_ERROR_WIN_SEM_IS_SET, + MD_ERROR_WIN_TOO_MANY_SEM_REQUESTS, + MD_ERROR_WIN_INVALID_AT_INTERRUPT_TIME, + MD_ERROR_WIN_SEM_OWNER_DIED, + MD_ERROR_WIN_SEM_USER_LIMIT, + MD_ERROR_WIN_DISK_CHANGE, + MD_ERROR_WIN_DRIVE_LOCKED, + MD_ERROR_WIN_BROKEN_PIPE, + MD_ERROR_WIN_OPEN_FAILED, + MD_ERROR_WIN_BUFFER_OVERFLOW, + MD_ERROR_WIN_DISK_FULL, + MD_ERROR_WIN_NO_MORE_SEARCH_HANDLES, + MD_ERROR_WIN_INVALID_TARGET_HANDLE, + MD_ERROR_WIN_INVALID_CATEGORY, + MD_ERROR_WIN_INVALID_VERIFY_SWITCH, + MD_ERROR_WIN_BAD_DRIVER_LEVEL, + MD_ERROR_WIN_CALL_NOT_IMPLEMENTED, + MD_ERROR_WIN_SEM_TIMEOUT, + MD_ERROR_WIN_INSUFFICIENT_BUFFER, + MD_ERROR_WIN_INVALID_NAME, + MD_ERROR_WIN_INVALID_LEVEL, + MD_ERROR_WIN_NO_VOLUME_LABEL, + MD_ERROR_WIN_MOD_NOT_FOUND, + MD_ERROR_WIN_PROC_NOT_FOUND, + MD_ERROR_WIN_WAIT_NO_CHILDREN, + MD_ERROR_WIN_CHILD_NOT_COMPLETE, + MD_ERROR_WIN_DIRECT_ACCESS_HANDLE, + MD_ERROR_WIN_NEGATIVE_SEEK, + MD_ERROR_WIN_SEEK_ON_DEVICE, + MD_ERROR_WIN_IS_JOIN_TARGET, + MD_ERROR_WIN_IS_JOINED, + MD_ERROR_WIN_IS_SUBSTED, + MD_ERROR_WIN_NOT_JOINED, + MD_ERROR_WIN_NOT_SUBSTED, + MD_ERROR_WIN_JOIN_TO_JOIN, + MD_ERROR_WIN_SUBST_TO_SUBST, + MD_ERROR_WIN_JOIN_TO_SUBST, + MD_ERROR_WIN_SUBST_TO_JOIN, + MD_ERROR_WIN_BUSY_DRIVE, + MD_ERROR_WIN_SAME_DRIVE, + MD_ERROR_WIN_DIR_NOT_ROOT, + MD_ERROR_WIN_DIR_NOT_EMPTY, + MD_ERROR_WIN_IS_SUBST_PATH, + MD_ERROR_WIN_IS_JOIN_PATH, + MD_ERROR_WIN_PATH_BUSY, + MD_ERROR_WIN_IS_SUBST_TARGET, + MD_ERROR_WIN_SYSTEM_TRACE, + MD_ERROR_WIN_INVALID_EVENT_COUNT, + MD_ERROR_WIN_TOO_MANY_MUXWAITERS, + MD_ERROR_WIN_INVALID_LIST_FORMAT, + MD_ERROR_WIN_LABEL_TOO_LONG, + MD_ERROR_WIN_TOO_MANY_TCBS, + MD_ERROR_WIN_SIGNAL_REFUSED, + MD_ERROR_WIN_DISCARDED, + MD_ERROR_WIN_NOT_LOCKED, + MD_ERROR_WIN_BAD_THREADID_ADDR, + MD_ERROR_WIN_BAD_ARGUMENTS, + MD_ERROR_WIN_BAD_PATHNAME, + MD_ERROR_WIN_SIGNAL_PENDING, + MD_ERROR_WIN_MAX_THRDS_REACHED, + MD_ERROR_WIN_LOCK_FAILED, + MD_ERROR_WIN_BUSY, + MD_ERROR_WIN_DEVICE_SUPPORT_IN_PROGRESS, + MD_ERROR_WIN_CANCEL_VIOLATION, + MD_ERROR_WIN_ATOMIC_LOCKS_NOT_SUPPORTED, + MD_ERROR_WIN_INVALID_SEGMENT_NUMBER, + MD_ERROR_WIN_INVALID_ORDINAL, + MD_ERROR_WIN_ALREADY_EXISTS, + MD_ERROR_WIN_INVALID_FLAG_NUMBER, + MD_ERROR_WIN_SEM_NOT_FOUND, + MD_ERROR_WIN_INVALID_STARTING_CODESEG, + MD_ERROR_WIN_INVALID_STACKSEG, + MD_ERROR_WIN_INVALID_MODULETYPE, + MD_ERROR_WIN_INVALID_EXE_SIGNATURE, + MD_ERROR_WIN_EXE_MARKED_INVALID, + MD_ERROR_WIN_BAD_EXE_FORMAT, + MD_ERROR_WIN_INVALID_MINALLOCSIZE, + MD_ERROR_WIN_DYNLINK_FROM_INVALID_RING, + MD_ERROR_WIN_IOPL_NOT_ENABLED, + MD_ERROR_WIN_INVALID_SEGDPL, + MD_ERROR_WIN_RING2SEG_MUST_BE_MOVABLE, + MD_ERROR_WIN_RELOC_CHAIN_XEEDS_SEGLIM, + MD_ERROR_WIN_INFLOOP_IN_RELOC_CHAIN, + MD_ERROR_WIN_ENVVAR_NOT_FOUND, + MD_ERROR_WIN_NO_SIGNAL_SENT, + MD_ERROR_WIN_FILENAME_EXCED_RANGE, + MD_ERROR_WIN_RING2_STACK_IN_USE, + MD_ERROR_WIN_META_EXPANSION_TOO_LONG, + MD_ERROR_WIN_INVALID_SIGNAL_NUMBER, + MD_ERROR_WIN_THREAD_1_INACTIVE, + MD_ERROR_WIN_LOCKED, + MD_ERROR_WIN_TOO_MANY_MODULES, + MD_ERROR_WIN_NESTING_NOT_ALLOWED, + MD_ERROR_WIN_EXE_MACHINE_TYPE_MISMATCH, + MD_ERROR_WIN_EXE_CANNOT_MODIFY_SIGNED_BINARY, + MD_ERROR_WIN_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY, + MD_ERROR_WIN_FILE_CHECKED_OUT, + MD_ERROR_WIN_CHECKOUT_REQUIRED, + MD_ERROR_WIN_BAD_FILE_TYPE, + MD_ERROR_WIN_FILE_TOO_LARGE, + MD_ERROR_WIN_FORMS_AUTH_REQUIRED, + MD_ERROR_WIN_VIRUS_INFECTED, + MD_ERROR_WIN_VIRUS_DELETED, + MD_ERROR_WIN_PIPE_LOCAL, + MD_ERROR_WIN_BAD_PIPE, + MD_ERROR_WIN_PIPE_BUSY, + MD_ERROR_WIN_NO_DATA, + MD_ERROR_WIN_PIPE_NOT_CONNECTED, + MD_ERROR_WIN_MORE_DATA, + MD_ERROR_WIN_NO_WORK_DONE, + MD_ERROR_WIN_VC_DISCONNECTED, + MD_ERROR_WIN_INVALID_EA_NAME, + MD_ERROR_WIN_EA_LIST_INCONSISTENT, + MD_ERROR_WIN_NO_MORE_ITEMS, + MD_ERROR_WIN_CANNOT_COPY, + MD_ERROR_WIN_DIRECTORY, + MD_ERROR_WIN_EAS_DIDNT_FIT, + MD_ERROR_WIN_EA_FILE_CORRUPT, + MD_ERROR_WIN_EA_TABLE_FULL, + MD_ERROR_WIN_INVALID_EA_HANDLE, + MD_ERROR_WIN_EAS_NOT_SUPPORTED, + MD_ERROR_WIN_NOT_OWNER, + MD_ERROR_WIN_TOO_MANY_POSTS, + MD_ERROR_WIN_PARTIAL_COPY, + MD_ERROR_WIN_OPLOCK_NOT_GRANTED, + MD_ERROR_WIN_INVALID_OPLOCK_PROTOCOL, + MD_ERROR_WIN_DISK_TOO_FRAGMENTED, + MD_ERROR_WIN_DELETE_PENDING, + MD_ERROR_WIN_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING, + MD_ERROR_WIN_SHORT_NAMES_NOT_ENABLED_ON_VOLUME, + MD_ERROR_WIN_SECURITY_STREAM_IS_INCONSISTENT, + MD_ERROR_WIN_INVALID_LOCK_RANGE, + MD_ERROR_WIN_IMAGE_SUBSYSTEM_NOT_PRESENT, + MD_ERROR_WIN_NOTIFICATION_GUID_ALREADY_DEFINED, + MD_ERROR_WIN_INVALID_EXCEPTION_HANDLER, + MD_ERROR_WIN_DUPLICATE_PRIVILEGES, + MD_ERROR_WIN_NO_RANGES_PROCESSED, + MD_ERROR_WIN_NOT_ALLOWED_ON_SYSTEM_FILE, + MD_ERROR_WIN_DISK_RESOURCES_EXHAUSTED, + MD_ERROR_WIN_INVALID_TOKEN, + MD_ERROR_WIN_DEVICE_FEATURE_NOT_SUPPORTED, + MD_ERROR_WIN_MR_MID_NOT_FOUND, + MD_ERROR_WIN_SCOPE_NOT_FOUND, + MD_ERROR_WIN_UNDEFINED_SCOPE, + MD_ERROR_WIN_INVALID_CAP, + MD_ERROR_WIN_DEVICE_UNREACHABLE, + MD_ERROR_WIN_DEVICE_NO_RESOURCES, + MD_ERROR_WIN_DATA_CHECKSUM_ERROR, + MD_ERROR_WIN_INTERMIXED_KERNEL_EA_OPERATION, + MD_ERROR_WIN_FILE_LEVEL_TRIM_NOT_SUPPORTED, + MD_ERROR_WIN_OFFSET_ALIGNMENT_VIOLATION, + MD_ERROR_WIN_INVALID_FIELD_IN_PARAMETER_LIST, + MD_ERROR_WIN_OPERATION_IN_PROGRESS, + MD_ERROR_WIN_BAD_DEVICE_PATH, + MD_ERROR_WIN_TOO_MANY_DESCRIPTORS, + MD_ERROR_WIN_SCRUB_DATA_DISABLED, + MD_ERROR_WIN_NOT_REDUNDANT_STORAGE, + MD_ERROR_WIN_RESIDENT_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_COMPRESSED_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_DIRECTORY_NOT_SUPPORTED, + MD_ERROR_WIN_NOT_READ_FROM_COPY, + MD_ERROR_WIN_FT_WRITE_FAILURE, + MD_ERROR_WIN_FT_DI_SCAN_REQUIRED, + MD_ERROR_WIN_INVALID_KERNEL_INFO_VERSION, + MD_ERROR_WIN_INVALID_PEP_INFO_VERSION, + MD_ERROR_WIN_OBJECT_NOT_EXTERNALLY_BACKED, + MD_ERROR_WIN_EXTERNAL_BACKING_PROVIDER_UNKNOWN, + MD_ERROR_WIN_COMPRESSION_NOT_BENEFICIAL, + MD_ERROR_WIN_STORAGE_TOPOLOGY_ID_MISMATCH, + MD_ERROR_WIN_BLOCKED_BY_PARENTAL_CONTROLS, + MD_ERROR_WIN_BLOCK_TOO_MANY_REFERENCES, + MD_ERROR_WIN_MARKED_TO_DISALLOW_WRITES, + MD_ERROR_WIN_ENCLAVE_FAILURE, + MD_ERROR_WIN_FAIL_NOACTION_REBOOT, + MD_ERROR_WIN_FAIL_SHUTDOWN, + MD_ERROR_WIN_FAIL_RESTART, + MD_ERROR_WIN_MAX_SESSIONS_REACHED, + MD_ERROR_WIN_NETWORK_ACCESS_DENIED_EDP, + MD_ERROR_WIN_DEVICE_HINT_NAME_BUFFER_TOO_SMALL, + MD_ERROR_WIN_EDP_POLICY_DENIES_OPERATION, + MD_ERROR_WIN_EDP_DPL_POLICY_CANT_BE_SATISFIED, + MD_ERROR_WIN_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT, + MD_ERROR_WIN_DEVICE_IN_MAINTENANCE, + MD_ERROR_WIN_NOT_SUPPORTED_ON_DAX, + MD_ERROR_WIN_DAX_MAPPING_EXISTS, + MD_ERROR_WIN_CLOUD_FILE_PROVIDER_NOT_RUNNING, + MD_ERROR_WIN_CLOUD_FILE_METADATA_CORRUPT, + MD_ERROR_WIN_CLOUD_FILE_METADATA_TOO_LARGE, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH, + MD_ERROR_WIN_CHILD_PROCESS_BLOCKED, + MD_ERROR_WIN_STORAGE_LOST_DATA_PERSISTENCE, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_BUSY, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN, + MD_ERROR_WIN_GDI_HANDLE_LEAK, + MD_ERROR_WIN_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED, + MD_ERROR_WIN_NOT_A_CLOUD_FILE, + MD_ERROR_WIN_CLOUD_FILE_NOT_IN_SYNC, + MD_ERROR_WIN_CLOUD_FILE_ALREADY_CONNECTED, + MD_ERROR_WIN_CLOUD_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_CLOUD_FILE_INVALID_REQUEST, + MD_ERROR_WIN_CLOUD_FILE_READ_ONLY_VOLUME, + MD_ERROR_WIN_CLOUD_FILE_CONNECTED_PROVIDER_ONLY, + MD_ERROR_WIN_CLOUD_FILE_VALIDATION_FAILED, + MD_ERROR_WIN_SMB1_NOT_AVAILABLE, + MD_ERROR_WIN_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION, + MD_ERROR_WIN_CLOUD_FILE_AUTHENTICATION_FAILED, + MD_ERROR_WIN_CLOUD_FILE_INSUFFICIENT_RESOURCES, + MD_ERROR_WIN_CLOUD_FILE_NETWORK_UNAVAILABLE, + MD_ERROR_WIN_CLOUD_FILE_UNSUCCESSFUL, + MD_ERROR_WIN_CLOUD_FILE_NOT_UNDER_SYNC_ROOT, + MD_ERROR_WIN_CLOUD_FILE_IN_USE, + MD_ERROR_WIN_CLOUD_FILE_PINNED, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_ABORTED, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_CORRUPT, + MD_ERROR_WIN_CLOUD_FILE_ACCESS_DENIED, + MD_ERROR_WIN_CLOUD_FILE_INCOMPATIBLE_HARDLINKS, + MD_ERROR_WIN_CLOUD_FILE_PROPERTY_LOCK_CONFLICT, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_CANCELED, + MD_ERROR_WIN_EXTERNAL_SYSKEY_NOT_SUPPORTED, + MD_ERROR_WIN_THREAD_MODE_ALREADY_BACKGROUND, + MD_ERROR_WIN_THREAD_MODE_NOT_BACKGROUND, + MD_ERROR_WIN_PROCESS_MODE_ALREADY_BACKGROUND, + MD_ERROR_WIN_PROCESS_MODE_NOT_BACKGROUND, + MD_ERROR_WIN_CLOUD_FILE_PROVIDER_TERMINATED, + MD_ERROR_WIN_NOT_A_CLOUD_SYNC_ROOT, + MD_ERROR_WIN_FILE_PROTECTED_UNDER_DPL, + MD_ERROR_WIN_VOLUME_NOT_CLUSTER_ALIGNED, + MD_ERROR_WIN_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND, + MD_ERROR_WIN_APPX_FILE_NOT_ENCRYPTED, + MD_ERROR_WIN_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE, + MD_ERROR_WIN_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER, + MD_ERROR_WIN_LINUX_SUBSYSTEM_NOT_PRESENT, + MD_ERROR_WIN_FT_READ_FAILURE, + MD_ERROR_WIN_STORAGE_RESERVE_ID_INVALID, + MD_ERROR_WIN_STORAGE_RESERVE_DOES_NOT_EXIST, + MD_ERROR_WIN_STORAGE_RESERVE_ALREADY_EXISTS, + MD_ERROR_WIN_STORAGE_RESERVE_NOT_EMPTY, + MD_ERROR_WIN_NOT_A_DAX_VOLUME, + MD_ERROR_WIN_NOT_DAX_MAPPABLE, + MD_ERROR_WIN_TIME_SENSITIVE_THREAD, + MD_ERROR_WIN_DPL_NOT_SUPPORTED_FOR_USER, + MD_ERROR_WIN_CASE_DIFFERING_NAMES_IN_DIR, + MD_ERROR_WIN_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_CLOUD_FILE_REQUEST_TIMEOUT, + MD_ERROR_WIN_NO_TASK_QUEUE, + MD_ERROR_WIN_SRC_SRV_DLL_LOAD_FAILED, + MD_ERROR_WIN_NOT_SUPPORTED_WITH_BTT, + MD_ERROR_WIN_ENCRYPTION_DISABLED, + MD_ERROR_WIN_ENCRYPTING_METADATA_DISALLOWED, + MD_ERROR_WIN_CANT_CLEAR_ENCRYPTION_FLAG, + MD_ERROR_WIN_NO_SUCH_DEVICE, + MD_ERROR_WIN_CLOUD_FILE_DEHYDRATION_DISALLOWED, + MD_ERROR_WIN_FILE_SNAP_IN_PROGRESS, + MD_ERROR_WIN_FILE_SNAP_USER_SECTION_NOT_SUPPORTED, + MD_ERROR_WIN_FILE_SNAP_MODIFY_NOT_SUPPORTED, + MD_ERROR_WIN_FILE_SNAP_IO_NOT_COORDINATED, + MD_ERROR_WIN_FILE_SNAP_UNEXPECTED_ERROR, + MD_ERROR_WIN_FILE_SNAP_INVALID_PARAMETER, + MD_ERROR_WIN_UNSATISFIED_DEPENDENCIES, + MD_ERROR_WIN_CASE_SENSITIVE_PATH, + MD_ERROR_WIN_UNEXPECTED_NTCACHEMANAGER_ERROR, + MD_ERROR_WIN_LINUX_SUBSYSTEM_UPDATE_REQUIRED, + MD_ERROR_WIN_DLP_POLICY_WARNS_AGAINST_OPERATION, + MD_ERROR_WIN_DLP_POLICY_DENIES_OPERATION, + MD_ERROR_WIN_DLP_POLICY_SILENTLY_FAIL, + MD_ERROR_WIN_CAPAUTHZ_NOT_DEVUNLOCKED, + MD_ERROR_WIN_CAPAUTHZ_CHANGE_TYPE, + MD_ERROR_WIN_CAPAUTHZ_NOT_PROVISIONED, + MD_ERROR_WIN_CAPAUTHZ_NOT_AUTHORIZED, + MD_ERROR_WIN_CAPAUTHZ_NO_POLICY, + MD_ERROR_WIN_CAPAUTHZ_DB_CORRUPTED, + MD_ERROR_WIN_CAPAUTHZ_SCCD_INVALID_CATALOG, + MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_AUTH_ENTITY, + MD_ERROR_WIN_CAPAUTHZ_SCCD_PARSE_ERROR, + MD_ERROR_WIN_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED, + MD_ERROR_WIN_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH, + MD_ERROR_WIN_CIMFS_IMAGE_CORRUPT, + MD_ERROR_WIN_PNP_QUERY_REMOVE_DEVICE_TIMEOUT, + MD_ERROR_WIN_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT, + MD_ERROR_WIN_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT, + MD_ERROR_WIN_DEVICE_HARDWARE_ERROR, + MD_ERROR_WIN_INVALID_ADDRESS, + MD_ERROR_WIN_HAS_SYSTEM_CRITICAL_FILES, + MD_ERROR_WIN_USER_PROFILE_LOAD, + MD_ERROR_WIN_ARITHMETIC_OVERFLOW, + MD_ERROR_WIN_PIPE_CONNECTED, + MD_ERROR_WIN_PIPE_LISTENING, + MD_ERROR_WIN_VERIFIER_STOP, + MD_ERROR_WIN_ABIOS_ERROR, + MD_ERROR_WIN_WX86_WARNING, + MD_ERROR_WIN_WX86_ERROR, + MD_ERROR_WIN_TIMER_NOT_CANCELED, + MD_ERROR_WIN_UNWIND, + MD_ERROR_WIN_BAD_STACK, + MD_ERROR_WIN_INVALID_UNWIND_TARGET, + MD_ERROR_WIN_INVALID_PORT_ATTRIBUTES, + MD_ERROR_WIN_PORT_MESSAGE_TOO_LONG, + MD_ERROR_WIN_INVALID_QUOTA_LOWER, + MD_ERROR_WIN_DEVICE_ALREADY_ATTACHED, + MD_ERROR_WIN_INSTRUCTION_MISALIGNMENT, + MD_ERROR_WIN_PROFILING_NOT_STARTED, + MD_ERROR_WIN_PROFILING_NOT_STOPPED, + MD_ERROR_WIN_COULD_NOT_INTERPRET, + MD_ERROR_WIN_PROFILING_AT_LIMIT, + MD_ERROR_WIN_CANT_WAIT, + MD_ERROR_WIN_CANT_TERMINATE_SELF, + MD_ERROR_WIN_UNEXPECTED_MM_CREATE_ERR, + MD_ERROR_WIN_UNEXPECTED_MM_MAP_ERROR, + MD_ERROR_WIN_UNEXPECTED_MM_EXTEND_ERR, + MD_ERROR_WIN_BAD_FUNCTION_TABLE, + MD_ERROR_WIN_NO_GUID_TRANSLATION, + MD_ERROR_WIN_INVALID_LDT_SIZE, + MD_ERROR_WIN_INVALID_LDT_OFFSET, + MD_ERROR_WIN_INVALID_LDT_DESCRIPTOR, + MD_ERROR_WIN_TOO_MANY_THREADS, + MD_ERROR_WIN_THREAD_NOT_IN_PROCESS, + MD_ERROR_WIN_PAGEFILE_QUOTA_EXCEEDED, + MD_ERROR_WIN_LOGON_SERVER_CONFLICT, + MD_ERROR_WIN_SYNCHRONIZATION_REQUIRED, + MD_ERROR_WIN_NET_OPEN_FAILED, + MD_ERROR_WIN_IO_PRIVILEGE_FAILED, + MD_ERROR_WIN_CONTROL_C_EXIT, + MD_ERROR_WIN_MISSING_SYSTEMFILE, + MD_ERROR_WIN_UNHANDLED_EXCEPTION, + MD_ERROR_WIN_APP_INIT_FAILURE, + MD_ERROR_WIN_PAGEFILE_CREATE_FAILED, + MD_ERROR_WIN_INVALID_IMAGE_HASH, + MD_ERROR_WIN_NO_PAGEFILE, + MD_ERROR_WIN_ILLEGAL_FLOAT_CONTEXT, + MD_ERROR_WIN_NO_EVENT_PAIR, + MD_ERROR_WIN_DOMAIN_CTRLR_CONFIG_ERROR, + MD_ERROR_WIN_ILLEGAL_CHARACTER, + MD_ERROR_WIN_UNDEFINED_CHARACTER, + MD_ERROR_WIN_FLOPPY_VOLUME, + MD_ERROR_WIN_BIOS_FAILED_TO_CONNECT_INTERRUPT, + MD_ERROR_WIN_BACKUP_CONTROLLER, + MD_ERROR_WIN_MUTANT_LIMIT_EXCEEDED, + MD_ERROR_WIN_FS_DRIVER_REQUIRED, + MD_ERROR_WIN_CANNOT_LOAD_REGISTRY_FILE, + MD_ERROR_WIN_DEBUG_ATTACH_FAILED, + MD_ERROR_WIN_SYSTEM_PROCESS_TERMINATED, + MD_ERROR_WIN_DATA_NOT_ACCEPTED, + MD_ERROR_WIN_VDM_HARD_ERROR, + MD_ERROR_WIN_DRIVER_CANCEL_TIMEOUT, + MD_ERROR_WIN_REPLY_MESSAGE_MISMATCH, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA, + MD_ERROR_WIN_CLIENT_SERVER_PARAMETERS_INVALID, + MD_ERROR_WIN_NOT_TINY_STREAM, + MD_ERROR_WIN_STACK_OVERFLOW_READ, + MD_ERROR_WIN_CONVERT_TO_LARGE, + MD_ERROR_WIN_FOUND_OUT_OF_SCOPE, + MD_ERROR_WIN_ALLOCATE_BUCKET, + MD_ERROR_WIN_MARSHALL_OVERFLOW, + MD_ERROR_WIN_INVALID_VARIANT, + MD_ERROR_WIN_BAD_COMPRESSION_BUFFER, + MD_ERROR_WIN_AUDIT_FAILED, + MD_ERROR_WIN_TIMER_RESOLUTION_NOT_SET, + MD_ERROR_WIN_INSUFFICIENT_LOGON_INFO, + MD_ERROR_WIN_BAD_DLL_ENTRYPOINT, + MD_ERROR_WIN_BAD_SERVICE_ENTRYPOINT, + MD_ERROR_WIN_IP_ADDRESS_CONFLICT1, + MD_ERROR_WIN_IP_ADDRESS_CONFLICT2, + MD_ERROR_WIN_REGISTRY_QUOTA_LIMIT, + MD_ERROR_WIN_NO_CALLBACK_ACTIVE, + MD_ERROR_WIN_PWD_TOO_SHORT, + MD_ERROR_WIN_PWD_TOO_RECENT, + MD_ERROR_WIN_PWD_HISTORY_CONFLICT, + MD_ERROR_WIN_UNSUPPORTED_COMPRESSION, + MD_ERROR_WIN_INVALID_HW_PROFILE, + MD_ERROR_WIN_INVALID_PLUGPLAY_DEVICE_PATH, + MD_ERROR_WIN_QUOTA_LIST_INCONSISTENT, + MD_ERROR_WIN_EVALUATION_EXPIRATION, + MD_ERROR_WIN_ILLEGAL_DLL_RELOCATION, + MD_ERROR_WIN_DLL_INIT_FAILED_LOGOFF, + MD_ERROR_WIN_VALIDATE_CONTINUE, + MD_ERROR_WIN_NO_MORE_MATCHES, + MD_ERROR_WIN_RANGE_LIST_CONFLICT, + MD_ERROR_WIN_SERVER_SID_MISMATCH, + MD_ERROR_WIN_CANT_ENABLE_DENY_ONLY, + MD_ERROR_WIN_FLOAT_MULTIPLE_FAULTS, + MD_ERROR_WIN_FLOAT_MULTIPLE_TRAPS, + MD_ERROR_WIN_NOINTERFACE, + MD_ERROR_WIN_DRIVER_FAILED_SLEEP, + MD_ERROR_WIN_CORRUPT_SYSTEM_FILE, + MD_ERROR_WIN_COMMITMENT_MINIMUM, + MD_ERROR_WIN_PNP_RESTART_ENUMERATION, + MD_ERROR_WIN_SYSTEM_IMAGE_BAD_SIGNATURE, + MD_ERROR_WIN_PNP_REBOOT_REQUIRED, + MD_ERROR_WIN_INSUFFICIENT_POWER, + MD_ERROR_WIN_MULTIPLE_FAULT_VIOLATION, + MD_ERROR_WIN_SYSTEM_SHUTDOWN, + MD_ERROR_WIN_PORT_NOT_SET, + MD_ERROR_WIN_DS_VERSION_CHECK_FAILURE, + MD_ERROR_WIN_RANGE_NOT_FOUND, + MD_ERROR_WIN_NOT_SAFE_MODE_DRIVER, + MD_ERROR_WIN_FAILED_DRIVER_ENTRY, + MD_ERROR_WIN_DEVICE_ENUMERATION_ERROR, + MD_ERROR_WIN_MOUNT_POINT_NOT_RESOLVED, + MD_ERROR_WIN_INVALID_DEVICE_OBJECT_PARAMETER, + MD_ERROR_WIN_MCA_OCCURED, + MD_ERROR_WIN_DRIVER_DATABASE_ERROR, + MD_ERROR_WIN_SYSTEM_HIVE_TOO_LARGE, + MD_ERROR_WIN_DRIVER_FAILED_PRIOR_UNLOAD, + MD_ERROR_WIN_VOLSNAP_PREPARE_HIBERNATE, + MD_ERROR_WIN_HIBERNATION_FAILURE, + MD_ERROR_WIN_PWD_TOO_LONG, + MD_ERROR_WIN_FILE_SYSTEM_LIMITATION, + MD_ERROR_WIN_ASSERTION_FAILURE, + MD_ERROR_WIN_ACPI_ERROR, + MD_ERROR_WIN_WOW_ASSERTION, + MD_ERROR_WIN_PNP_BAD_MPS_TABLE, + MD_ERROR_WIN_PNP_TRANSLATION_FAILED, + MD_ERROR_WIN_PNP_IRQ_TRANSLATION_FAILED, + MD_ERROR_WIN_PNP_INVALID_ID, + MD_ERROR_WIN_WAKE_SYSTEM_DEBUGGER, + MD_ERROR_WIN_HANDLES_CLOSED, + MD_ERROR_WIN_EXTRANEOUS_INFORMATION, + MD_ERROR_WIN_RXACT_COMMIT_NECESSARY, + MD_ERROR_WIN_MEDIA_CHECK, + MD_ERROR_WIN_GUID_SUBSTITUTION_MADE, + MD_ERROR_WIN_STOPPED_ON_SYMLINK, + MD_ERROR_WIN_LONGJUMP, + MD_ERROR_WIN_PLUGPLAY_QUERY_VETOED, + MD_ERROR_WIN_UNWIND_CONSOLIDATE, + MD_ERROR_WIN_REGISTRY_HIVE_RECOVERED, + MD_ERROR_WIN_DLL_MIGHT_BE_INSECURE, + MD_ERROR_WIN_DLL_MIGHT_BE_INCOMPATIBLE, + MD_ERROR_WIN_DBG_EXCEPTION_NOT_HANDLED, + MD_ERROR_WIN_DBG_REPLY_LATER, + MD_ERROR_WIN_DBG_UNABLE_TO_PROVIDE_HANDLE, + MD_ERROR_WIN_DBG_TERMINATE_THREAD, + MD_ERROR_WIN_DBG_TERMINATE_PROCESS, + MD_ERROR_WIN_DBG_CONTROL_C, + MD_ERROR_WIN_DBG_PRINTEXCEPTION_C, + MD_ERROR_WIN_DBG_RIPEXCEPTION, + MD_ERROR_WIN_DBG_CONTROL_BREAK, + MD_ERROR_WIN_DBG_COMMAND_EXCEPTION, + MD_ERROR_WIN_OBJECT_NAME_EXISTS, + MD_ERROR_WIN_THREAD_WAS_SUSPENDED, + MD_ERROR_WIN_IMAGE_NOT_AT_BASE, + MD_ERROR_WIN_RXACT_STATE_CREATED, + MD_ERROR_WIN_SEGMENT_NOTIFICATION, + MD_ERROR_WIN_BAD_CURRENT_DIRECTORY, + MD_ERROR_WIN_FT_READ_RECOVERY_FROM_BACKUP, + MD_ERROR_WIN_FT_WRITE_RECOVERY, + MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH, + MD_ERROR_WIN_RECEIVE_PARTIAL, + MD_ERROR_WIN_RECEIVE_EXPEDITED, + MD_ERROR_WIN_RECEIVE_PARTIAL_EXPEDITED, + MD_ERROR_WIN_EVENT_DONE, + MD_ERROR_WIN_EVENT_PENDING, + MD_ERROR_WIN_CHECKING_FILE_SYSTEM, + MD_ERROR_WIN_FATAL_APP_EXIT, + MD_ERROR_WIN_PREDEFINED_HANDLE, + MD_ERROR_WIN_WAS_UNLOCKED, + MD_ERROR_WIN_SERVICE_NOTIFICATION, + MD_ERROR_WIN_WAS_LOCKED, + MD_ERROR_WIN_LOG_HARD_ERROR, + MD_ERROR_WIN_ALREADY_WIN32, + MD_ERROR_WIN_IMAGE_MACHINE_TYPE_MISMATCH_EXE, + MD_ERROR_WIN_NO_YIELD_PERFORMED, + MD_ERROR_WIN_TIMER_RESUME_IGNORED, + MD_ERROR_WIN_ARBITRATION_UNHANDLED, + MD_ERROR_WIN_CARDBUS_NOT_SUPPORTED, + MD_ERROR_WIN_MP_PROCESSOR_MISMATCH, + MD_ERROR_WIN_HIBERNATED, + MD_ERROR_WIN_RESUME_HIBERNATION, + MD_ERROR_WIN_FIRMWARE_UPDATED, + MD_ERROR_WIN_DRIVERS_LEAKING_LOCKED_PAGES, + MD_ERROR_WIN_WAKE_SYSTEM, + MD_ERROR_WIN_WAIT_1, + MD_ERROR_WIN_WAIT_2, + MD_ERROR_WIN_WAIT_3, + MD_ERROR_WIN_WAIT_63, + MD_ERROR_WIN_ABANDONED_WAIT_0, + MD_ERROR_WIN_ABANDONED_WAIT_63, + MD_ERROR_WIN_USER_APC, + MD_ERROR_WIN_KERNEL_APC, + MD_ERROR_WIN_ALERTED, + MD_ERROR_WIN_ELEVATION_REQUIRED, + MD_ERROR_WIN_REPARSE, + MD_ERROR_WIN_OPLOCK_BREAK_IN_PROGRESS, + MD_ERROR_WIN_VOLUME_MOUNTED, + MD_ERROR_WIN_RXACT_COMMITTED, + MD_ERROR_WIN_NOTIFY_CLEANUP, + MD_ERROR_WIN_PRIMARY_TRANSPORT_CONNECT_FAILED, + MD_ERROR_WIN_PAGE_FAULT_TRANSITION, + MD_ERROR_WIN_PAGE_FAULT_DEMAND_ZERO, + MD_ERROR_WIN_PAGE_FAULT_COPY_ON_WRITE, + MD_ERROR_WIN_PAGE_FAULT_GUARD_PAGE, + MD_ERROR_WIN_PAGE_FAULT_PAGING_FILE, + MD_ERROR_WIN_CACHE_PAGE_LOCKED, + MD_ERROR_WIN_CRASH_DUMP, + MD_ERROR_WIN_BUFFER_ALL_ZEROS, + MD_ERROR_WIN_REPARSE_OBJECT, + MD_ERROR_WIN_RESOURCE_REQUIREMENTS_CHANGED, + MD_ERROR_WIN_TRANSLATION_COMPLETE, + MD_ERROR_WIN_NOTHING_TO_TERMINATE, + MD_ERROR_WIN_PROCESS_NOT_IN_JOB, + MD_ERROR_WIN_PROCESS_IN_JOB, + MD_ERROR_WIN_VOLSNAP_HIBERNATE_READY, + MD_ERROR_WIN_FSFILTER_OP_COMPLETED_SUCCESSFULLY, + MD_ERROR_WIN_INTERRUPT_VECTOR_ALREADY_CONNECTED, + MD_ERROR_WIN_INTERRUPT_STILL_CONNECTED, + MD_ERROR_WIN_WAIT_FOR_OPLOCK, + MD_ERROR_WIN_DBG_EXCEPTION_HANDLED, + MD_ERROR_WIN_DBG_CONTINUE, + MD_ERROR_WIN_CALLBACK_POP_STACK, + MD_ERROR_WIN_COMPRESSION_DISABLED, + MD_ERROR_WIN_CANTFETCHBACKWARDS, + MD_ERROR_WIN_CANTSCROLLBACKWARDS, + MD_ERROR_WIN_ROWSNOTRELEASED, + MD_ERROR_WIN_BAD_ACCESSOR_FLAGS, + MD_ERROR_WIN_ERRORS_ENCOUNTERED, + MD_ERROR_WIN_NOT_CAPABLE, + MD_ERROR_WIN_REQUEST_OUT_OF_SEQUENCE, + MD_ERROR_WIN_VERSION_PARSE_ERROR, + MD_ERROR_WIN_BADSTARTPOSITION, + MD_ERROR_WIN_MEMORY_HARDWARE, + MD_ERROR_WIN_DISK_REPAIR_DISABLED, + MD_ERROR_WIN_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE, + MD_ERROR_WIN_SYSTEM_POWERSTATE_TRANSITION, + MD_ERROR_WIN_SYSTEM_POWERSTATE_COMPLEX_TRANSITION, + MD_ERROR_WIN_MCA_EXCEPTION, + MD_ERROR_WIN_ACCESS_AUDIT_BY_POLICY, + MD_ERROR_WIN_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY, + MD_ERROR_WIN_ABANDON_HIBERFILE, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR, + MD_ERROR_WIN_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR, + MD_ERROR_WIN_BAD_MCFG_TABLE, + MD_ERROR_WIN_DISK_REPAIR_REDIRECTED, + MD_ERROR_WIN_DISK_REPAIR_UNSUCCESSFUL, + MD_ERROR_WIN_CORRUPT_LOG_OVERFULL, + MD_ERROR_WIN_CORRUPT_LOG_CORRUPTED, + MD_ERROR_WIN_CORRUPT_LOG_UNAVAILABLE, + MD_ERROR_WIN_CORRUPT_LOG_DELETED_FULL, + MD_ERROR_WIN_CORRUPT_LOG_CLEARED, + MD_ERROR_WIN_ORPHAN_NAME_EXHAUSTED, + MD_ERROR_WIN_OPLOCK_SWITCHED_TO_NEW_HANDLE, + MD_ERROR_WIN_CANNOT_GRANT_REQUESTED_OPLOCK, + MD_ERROR_WIN_CANNOT_BREAK_OPLOCK, + MD_ERROR_WIN_OPLOCK_HANDLE_CLOSED, + MD_ERROR_WIN_NO_ACE_CONDITION, + MD_ERROR_WIN_INVALID_ACE_CONDITION, + MD_ERROR_WIN_FILE_HANDLE_REVOKED, + MD_ERROR_WIN_IMAGE_AT_DIFFERENT_BASE, + MD_ERROR_WIN_ENCRYPTED_IO_NOT_POSSIBLE, + MD_ERROR_WIN_FILE_METADATA_OPTIMIZATION_IN_PROGRESS, + MD_ERROR_WIN_QUOTA_ACTIVITY, + MD_ERROR_WIN_HANDLE_REVOKED, + MD_ERROR_WIN_CALLBACK_INVOKE_INLINE, + MD_ERROR_WIN_CPU_SET_INVALID, + MD_ERROR_WIN_ENCLAVE_NOT_TERMINATED, + MD_ERROR_WIN_ENCLAVE_VIOLATION, + MD_ERROR_WIN_EA_ACCESS_DENIED, + MD_ERROR_WIN_OPERATION_ABORTED, + MD_ERROR_WIN_IO_INCOMPLETE, + MD_ERROR_WIN_IO_PENDING, + MD_ERROR_WIN_NOACCESS, + MD_ERROR_WIN_SWAPERROR, + MD_ERROR_WIN_STACK_OVERFLOW, + MD_ERROR_WIN_INVALID_MESSAGE, + MD_ERROR_WIN_CAN_NOT_COMPLETE, + MD_ERROR_WIN_INVALID_FLAGS, + MD_ERROR_WIN_UNRECOGNIZED_VOLUME, + MD_ERROR_WIN_FILE_INVALID, + MD_ERROR_WIN_FULLSCREEN_MODE, + MD_ERROR_WIN_NO_TOKEN, + MD_ERROR_WIN_BADDB, + MD_ERROR_WIN_BADKEY, + MD_ERROR_WIN_CANTOPEN, + MD_ERROR_WIN_CANTREAD, + MD_ERROR_WIN_CANTWRITE, + MD_ERROR_WIN_REGISTRY_RECOVERED, + MD_ERROR_WIN_REGISTRY_CORRUPT, + MD_ERROR_WIN_REGISTRY_IO_FAILED, + MD_ERROR_WIN_NOT_REGISTRY_FILE, + MD_ERROR_WIN_KEY_DELETED, + MD_ERROR_WIN_NO_LOG_SPACE, + MD_ERROR_WIN_KEY_HAS_CHILDREN, + MD_ERROR_WIN_CHILD_MUST_BE_VOLATILE, + MD_ERROR_WIN_NOTIFY_ENUM_DIR, + MD_ERROR_WIN_DEPENDENT_SERVICES_RUNNING, + MD_ERROR_WIN_INVALID_SERVICE_CONTROL, + MD_ERROR_WIN_SERVICE_REQUEST_TIMEOUT, + MD_ERROR_WIN_SERVICE_NO_THREAD, + MD_ERROR_WIN_SERVICE_DATABASE_LOCKED, + MD_ERROR_WIN_SERVICE_ALREADY_RUNNING, + MD_ERROR_WIN_INVALID_SERVICE_ACCOUNT, + MD_ERROR_WIN_SERVICE_DISABLED, + MD_ERROR_WIN_CIRCULAR_DEPENDENCY, + MD_ERROR_WIN_SERVICE_DOES_NOT_EXIST, + MD_ERROR_WIN_SERVICE_CANNOT_ACCEPT_CTRL, + MD_ERROR_WIN_SERVICE_NOT_ACTIVE, + MD_ERROR_WIN_FAILED_SERVICE_CONTROLLER_CONNECT, + MD_ERROR_WIN_EXCEPTION_IN_SERVICE, + MD_ERROR_WIN_DATABASE_DOES_NOT_EXIST, + MD_ERROR_WIN_SERVICE_SPECIFIC_ERROR, + MD_ERROR_WIN_PROCESS_ABORTED, + MD_ERROR_WIN_SERVICE_DEPENDENCY_FAIL, + MD_ERROR_WIN_SERVICE_LOGON_FAILED, + MD_ERROR_WIN_SERVICE_START_HANG, + MD_ERROR_WIN_INVALID_SERVICE_LOCK, + MD_ERROR_WIN_SERVICE_MARKED_FOR_DELETE, + MD_ERROR_WIN_SERVICE_EXISTS, + MD_ERROR_WIN_ALREADY_RUNNING_LKG, + MD_ERROR_WIN_SERVICE_DEPENDENCY_DELETED, + MD_ERROR_WIN_BOOT_ALREADY_ACCEPTED, + MD_ERROR_WIN_SERVICE_NEVER_STARTED, + MD_ERROR_WIN_DUPLICATE_SERVICE_NAME, + MD_ERROR_WIN_DIFFERENT_SERVICE_ACCOUNT, + MD_ERROR_WIN_CANNOT_DETECT_DRIVER_FAILURE, + MD_ERROR_WIN_CANNOT_DETECT_PROCESS_ABORT, + MD_ERROR_WIN_NO_RECOVERY_PROGRAM, + MD_ERROR_WIN_SERVICE_NOT_IN_EXE, + MD_ERROR_WIN_NOT_SAFEBOOT_SERVICE, + MD_ERROR_WIN_END_OF_MEDIA, + MD_ERROR_WIN_FILEMARK_DETECTED, + MD_ERROR_WIN_BEGINNING_OF_MEDIA, + MD_ERROR_WIN_SETMARK_DETECTED, + MD_ERROR_WIN_NO_DATA_DETECTED, + MD_ERROR_WIN_PARTITION_FAILURE, + MD_ERROR_WIN_INVALID_BLOCK_LENGTH, + MD_ERROR_WIN_DEVICE_NOT_PARTITIONED, + MD_ERROR_WIN_UNABLE_TO_LOCK_MEDIA, + MD_ERROR_WIN_UNABLE_TO_UNLOAD_MEDIA, + MD_ERROR_WIN_MEDIA_CHANGED, + MD_ERROR_WIN_BUS_RESET, + MD_ERROR_WIN_NO_MEDIA_IN_DRIVE, + MD_ERROR_WIN_NO_UNICODE_TRANSLATION, + MD_ERROR_WIN_DLL_INIT_FAILED, + MD_ERROR_WIN_SHUTDOWN_IN_PROGRESS, + MD_ERROR_WIN_NO_SHUTDOWN_IN_PROGRESS, + MD_ERROR_WIN_IO_DEVICE, + MD_ERROR_WIN_SERIAL_NO_DEVICE, + MD_ERROR_WIN_IRQ_BUSY, + MD_ERROR_WIN_MORE_WRITES, + MD_ERROR_WIN_COUNTER_TIMEOUT, + MD_ERROR_WIN_FLOPPY_ID_MARK_NOT_FOUND, + MD_ERROR_WIN_FLOPPY_WRONG_CYLINDER, + MD_ERROR_WIN_FLOPPY_UNKNOWN_ERROR, + MD_ERROR_WIN_FLOPPY_BAD_REGISTERS, + MD_ERROR_WIN_DISK_RECALIBRATE_FAILED, + MD_ERROR_WIN_DISK_OPERATION_FAILED, + MD_ERROR_WIN_DISK_RESET_FAILED, + MD_ERROR_WIN_EOM_OVERFLOW, + MD_ERROR_WIN_NOT_ENOUGH_SERVER_MEMORY, + MD_ERROR_WIN_POSSIBLE_DEADLOCK, + MD_ERROR_WIN_MAPPED_ALIGNMENT, + MD_ERROR_WIN_SET_POWER_STATE_VETOED, + MD_ERROR_WIN_SET_POWER_STATE_FAILED, + MD_ERROR_WIN_TOO_MANY_LINKS, + MD_ERROR_WIN_OLD_WIN_VERSION, + MD_ERROR_WIN_APP_WRONG_OS, + MD_ERROR_WIN_SINGLE_INSTANCE_APP, + MD_ERROR_WIN_RMODE_APP, + MD_ERROR_WIN_INVALID_DLL, + MD_ERROR_WIN_NO_ASSOCIATION, + MD_ERROR_WIN_DDE_FAIL, + MD_ERROR_WIN_DLL_NOT_FOUND, + MD_ERROR_WIN_NO_MORE_USER_HANDLES, + MD_ERROR_WIN_MESSAGE_SYNC_ONLY, + MD_ERROR_WIN_SOURCE_ELEMENT_EMPTY, + MD_ERROR_WIN_DESTINATION_ELEMENT_FULL, + MD_ERROR_WIN_ILLEGAL_ELEMENT_ADDRESS, + MD_ERROR_WIN_MAGAZINE_NOT_PRESENT, + MD_ERROR_WIN_DEVICE_REINITIALIZATION_NEEDED, + MD_ERROR_WIN_DEVICE_REQUIRES_CLEANING, + MD_ERROR_WIN_DEVICE_DOOR_OPEN, + MD_ERROR_WIN_DEVICE_NOT_CONNECTED, + MD_ERROR_WIN_NOT_FOUND, + MD_ERROR_WIN_NO_MATCH, + MD_ERROR_WIN_SET_NOT_FOUND, + MD_ERROR_WIN_POINT_NOT_FOUND, + MD_ERROR_WIN_NO_TRACKING_SERVICE, + MD_ERROR_WIN_NO_VOLUME_ID, + MD_ERROR_WIN_UNABLE_TO_REMOVE_REPLACED, + MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT, + MD_ERROR_WIN_UNABLE_TO_MOVE_REPLACEMENT_2, + MD_ERROR_WIN_JOURNAL_DELETE_IN_PROGRESS, + MD_ERROR_WIN_JOURNAL_NOT_ACTIVE, + MD_ERROR_WIN_POTENTIAL_FILE_FOUND, + MD_ERROR_WIN_JOURNAL_ENTRY_DELETED, + MD_ERROR_WIN_VRF_CFG_AND_IO_ENABLED, + MD_ERROR_WIN_PARTITION_TERMINATING, + MD_ERROR_WIN_SHUTDOWN_IS_SCHEDULED, + MD_ERROR_WIN_SHUTDOWN_USERS_LOGGED_ON, + MD_ERROR_WIN_BAD_DEVICE, + MD_ERROR_WIN_CONNECTION_UNAVAIL, + MD_ERROR_WIN_DEVICE_ALREADY_REMEMBERED, + MD_ERROR_WIN_NO_NET_OR_BAD_PATH, + MD_ERROR_WIN_BAD_PROVIDER, + MD_ERROR_WIN_CANNOT_OPEN_PROFILE, + MD_ERROR_WIN_BAD_PROFILE, + MD_ERROR_WIN_NOT_CONTAINER, + MD_ERROR_WIN_EXTENDED_ERROR, + MD_ERROR_WIN_INVALID_GROUPNAME, + MD_ERROR_WIN_INVALID_COMPUTERNAME, + MD_ERROR_WIN_INVALID_EVENTNAME, + MD_ERROR_WIN_INVALID_DOMAINNAME, + MD_ERROR_WIN_INVALID_SERVICENAME, + MD_ERROR_WIN_INVALID_NETNAME, + MD_ERROR_WIN_INVALID_SHARENAME, + MD_ERROR_WIN_INVALID_PASSWORDNAME, + MD_ERROR_WIN_INVALID_MESSAGENAME, + MD_ERROR_WIN_INVALID_MESSAGEDEST, + MD_ERROR_WIN_SESSION_CREDENTIAL_CONFLICT, + MD_ERROR_WIN_REMOTE_SESSION_LIMIT_EXCEEDED, + MD_ERROR_WIN_DUP_DOMAINNAME, + MD_ERROR_WIN_NO_NETWORK, + MD_ERROR_WIN_CANCELLED, + MD_ERROR_WIN_USER_MAPPED_FILE, + MD_ERROR_WIN_CONNECTION_REFUSED, + MD_ERROR_WIN_GRACEFUL_DISCONNECT, + MD_ERROR_WIN_ADDRESS_ALREADY_ASSOCIATED, + MD_ERROR_WIN_ADDRESS_NOT_ASSOCIATED, + MD_ERROR_WIN_CONNECTION_INVALID, + MD_ERROR_WIN_CONNECTION_ACTIVE, + MD_ERROR_WIN_NETWORK_UNREACHABLE, + MD_ERROR_WIN_HOST_UNREACHABLE, + MD_ERROR_WIN_PROTOCOL_UNREACHABLE, + MD_ERROR_WIN_PORT_UNREACHABLE, + MD_ERROR_WIN_REQUEST_ABORTED, + MD_ERROR_WIN_CONNECTION_ABORTED, + MD_ERROR_WIN_RETRY, + MD_ERROR_WIN_CONNECTION_COUNT_LIMIT, + MD_ERROR_WIN_LOGIN_TIME_RESTRICTION, + MD_ERROR_WIN_LOGIN_WKSTA_RESTRICTION, + MD_ERROR_WIN_INCORRECT_ADDRESS, + MD_ERROR_WIN_ALREADY_REGISTERED, + MD_ERROR_WIN_SERVICE_NOT_FOUND, + MD_ERROR_WIN_NOT_AUTHENTICATED, + MD_ERROR_WIN_NOT_LOGGED_ON, + MD_ERROR_WIN_CONTINUE, + MD_ERROR_WIN_ALREADY_INITIALIZED, + MD_ERROR_WIN_NO_MORE_DEVICES, + MD_ERROR_WIN_NO_SUCH_SITE, + MD_ERROR_WIN_DOMAIN_CONTROLLER_EXISTS, + MD_ERROR_WIN_ONLY_IF_CONNECTED, + MD_ERROR_WIN_OVERRIDE_NOCHANGES, + MD_ERROR_WIN_BAD_USER_PROFILE, + MD_ERROR_WIN_NOT_SUPPORTED_ON_SBS, + MD_ERROR_WIN_SERVER_SHUTDOWN_IN_PROGRESS, + MD_ERROR_WIN_HOST_DOWN, + MD_ERROR_WIN_NON_ACCOUNT_SID, + MD_ERROR_WIN_NON_DOMAIN_SID, + MD_ERROR_WIN_APPHELP_BLOCK, + MD_ERROR_WIN_ACCESS_DISABLED_BY_POLICY, + MD_ERROR_WIN_REG_NAT_CONSUMPTION, + MD_ERROR_WIN_CSCSHARE_OFFLINE, + MD_ERROR_WIN_PKINIT_FAILURE, + MD_ERROR_WIN_SMARTCARD_SUBSYSTEM_FAILURE, + MD_ERROR_WIN_DOWNGRADE_DETECTED, + MD_ERROR_WIN_MACHINE_LOCKED, + MD_ERROR_WIN_SMB_GUEST_LOGON_BLOCKED, + MD_ERROR_WIN_CALLBACK_SUPPLIED_INVALID_DATA, + MD_ERROR_WIN_SYNC_FOREGROUND_REFRESH_REQUIRED, + MD_ERROR_WIN_DRIVER_BLOCKED, + MD_ERROR_WIN_INVALID_IMPORT_OF_NON_DLL, + MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE, + MD_ERROR_WIN_ACCESS_DISABLED_WEBBLADE_TAMPER, + MD_ERROR_WIN_RECOVERY_FAILURE, + MD_ERROR_WIN_ALREADY_FIBER, + MD_ERROR_WIN_ALREADY_THREAD, + MD_ERROR_WIN_STACK_BUFFER_OVERRUN, + MD_ERROR_WIN_PARAMETER_QUOTA_EXCEEDED, + MD_ERROR_WIN_DEBUGGER_INACTIVE, + MD_ERROR_WIN_DELAY_LOAD_FAILED, + MD_ERROR_WIN_VDM_DISALLOWED, + MD_ERROR_WIN_UNIDENTIFIED_ERROR, + MD_ERROR_WIN_INVALID_CRUNTIME_PARAMETER, + MD_ERROR_WIN_BEYOND_VDL, + MD_ERROR_WIN_INCOMPATIBLE_SERVICE_SID_TYPE, + MD_ERROR_WIN_DRIVER_PROCESS_TERMINATED, + MD_ERROR_WIN_IMPLEMENTATION_LIMIT, + MD_ERROR_WIN_PROCESS_IS_PROTECTED, + MD_ERROR_WIN_SERVICE_NOTIFY_CLIENT_LAGGING, + MD_ERROR_WIN_DISK_QUOTA_EXCEEDED, + MD_ERROR_WIN_CONTENT_BLOCKED, + MD_ERROR_WIN_INCOMPATIBLE_SERVICE_PRIVILEGE, + MD_ERROR_WIN_APP_HANG, + MD_ERROR_WIN_INVALID_LABEL, + MD_ERROR_WIN_NOT_ALL_ASSIGNED, + MD_ERROR_WIN_SOME_NOT_MAPPED, + MD_ERROR_WIN_NO_QUOTAS_FOR_ACCOUNT, + MD_ERROR_WIN_LOCAL_USER_SESSION_KEY, + MD_ERROR_WIN_NULL_LM_PASSWORD, + MD_ERROR_WIN_UNKNOWN_REVISION, + MD_ERROR_WIN_REVISION_MISMATCH, + MD_ERROR_WIN_INVALID_OWNER, + MD_ERROR_WIN_INVALID_PRIMARY_GROUP, + MD_ERROR_WIN_NO_IMPERSONATION_TOKEN, + MD_ERROR_WIN_CANT_DISABLE_MANDATORY, + MD_ERROR_WIN_NO_LOGON_SERVERS, + MD_ERROR_WIN_NO_SUCH_LOGON_SESSION, + MD_ERROR_WIN_NO_SUCH_PRIVILEGE, + MD_ERROR_WIN_PRIVILEGE_NOT_HELD, + MD_ERROR_WIN_INVALID_ACCOUNT_NAME, + MD_ERROR_WIN_USER_EXISTS, + MD_ERROR_WIN_NO_SUCH_USER, + MD_ERROR_WIN_GROUP_EXISTS, + MD_ERROR_WIN_NO_SUCH_GROUP, + MD_ERROR_WIN_MEMBER_IN_GROUP, + MD_ERROR_WIN_MEMBER_NOT_IN_GROUP, + MD_ERROR_WIN_LAST_ADMIN, + MD_ERROR_WIN_WRONG_PASSWORD, + MD_ERROR_WIN_ILL_FORMED_PASSWORD, + MD_ERROR_WIN_PASSWORD_RESTRICTION, + MD_ERROR_WIN_LOGON_FAILURE, + MD_ERROR_WIN_ACCOUNT_RESTRICTION, + MD_ERROR_WIN_INVALID_LOGON_HOURS, + MD_ERROR_WIN_INVALID_WORKSTATION, + MD_ERROR_WIN_PASSWORD_EXPIRED, + MD_ERROR_WIN_ACCOUNT_DISABLED, + MD_ERROR_WIN_NONE_MAPPED, + MD_ERROR_WIN_TOO_MANY_LUIDS_REQUESTED, + MD_ERROR_WIN_LUIDS_EXHAUSTED, + MD_ERROR_WIN_INVALID_SUB_AUTHORITY, + MD_ERROR_WIN_INVALID_ACL, + MD_ERROR_WIN_INVALID_SID, + MD_ERROR_WIN_INVALID_SECURITY_DESCR, + MD_ERROR_WIN_BAD_INHERITANCE_ACL, + MD_ERROR_WIN_SERVER_DISABLED, + MD_ERROR_WIN_SERVER_NOT_DISABLED, + MD_ERROR_WIN_INVALID_ID_AUTHORITY, + MD_ERROR_WIN_ALLOTTED_SPACE_EXCEEDED, + MD_ERROR_WIN_INVALID_GROUP_ATTRIBUTES, + MD_ERROR_WIN_BAD_IMPERSONATION_LEVEL, + MD_ERROR_WIN_CANT_OPEN_ANONYMOUS, + MD_ERROR_WIN_BAD_VALIDATION_CLASS, + MD_ERROR_WIN_BAD_TOKEN_TYPE, + MD_ERROR_WIN_NO_SECURITY_ON_OBJECT, + MD_ERROR_WIN_CANT_ACCESS_DOMAIN_INFO, + MD_ERROR_WIN_INVALID_SERVER_STATE, + MD_ERROR_WIN_INVALID_DOMAIN_STATE, + MD_ERROR_WIN_INVALID_DOMAIN_ROLE, + MD_ERROR_WIN_NO_SUCH_DOMAIN, + MD_ERROR_WIN_DOMAIN_EXISTS, + MD_ERROR_WIN_DOMAIN_LIMIT_EXCEEDED, + MD_ERROR_WIN_INTERNAL_DB_CORRUPTION, + MD_ERROR_WIN_INTERNAL_ERROR, + MD_ERROR_WIN_GENERIC_NOT_MAPPED, + MD_ERROR_WIN_BAD_DESCRIPTOR_FORMAT, + MD_ERROR_WIN_NOT_LOGON_PROCESS, + MD_ERROR_WIN_LOGON_SESSION_EXISTS, + MD_ERROR_WIN_NO_SUCH_PACKAGE, + MD_ERROR_WIN_BAD_LOGON_SESSION_STATE, + MD_ERROR_WIN_LOGON_SESSION_COLLISION, + MD_ERROR_WIN_INVALID_LOGON_TYPE, + MD_ERROR_WIN_CANNOT_IMPERSONATE, + MD_ERROR_WIN_RXACT_INVALID_STATE, + MD_ERROR_WIN_RXACT_COMMIT_FAILURE, + MD_ERROR_WIN_SPECIAL_ACCOUNT, + MD_ERROR_WIN_SPECIAL_GROUP, + MD_ERROR_WIN_SPECIAL_USER, + MD_ERROR_WIN_MEMBERS_PRIMARY_GROUP, + MD_ERROR_WIN_TOKEN_ALREADY_IN_USE, + MD_ERROR_WIN_NO_SUCH_ALIAS, + MD_ERROR_WIN_MEMBER_NOT_IN_ALIAS, + MD_ERROR_WIN_MEMBER_IN_ALIAS, + MD_ERROR_WIN_ALIAS_EXISTS, + MD_ERROR_WIN_LOGON_NOT_GRANTED, + MD_ERROR_WIN_TOO_MANY_SECRETS, + MD_ERROR_WIN_SECRET_TOO_LONG, + MD_ERROR_WIN_INTERNAL_DB_ERROR, + MD_ERROR_WIN_TOO_MANY_CONTEXT_IDS, + MD_ERROR_WIN_LOGON_TYPE_NOT_GRANTED, + MD_ERROR_WIN_NT_CROSS_ENCRYPTION_REQUIRED, + MD_ERROR_WIN_NO_SUCH_MEMBER, + MD_ERROR_WIN_INVALID_MEMBER, + MD_ERROR_WIN_TOO_MANY_SIDS, + MD_ERROR_WIN_LM_CROSS_ENCRYPTION_REQUIRED, + MD_ERROR_WIN_NO_INHERITANCE, + MD_ERROR_WIN_FILE_CORRUPT, + MD_ERROR_WIN_DISK_CORRUPT, + MD_ERROR_WIN_NO_USER_SESSION_KEY, + MD_ERROR_WIN_LICENSE_QUOTA_EXCEEDED, + MD_ERROR_WIN_WRONG_TARGET_NAME, + MD_ERROR_WIN_MUTUAL_AUTH_FAILED, + MD_ERROR_WIN_TIME_SKEW, + MD_ERROR_WIN_CURRENT_DOMAIN_NOT_ALLOWED, + MD_ERROR_WIN_INVALID_WINDOW_HANDLE, + MD_ERROR_WIN_INVALID_MENU_HANDLE, + MD_ERROR_WIN_INVALID_CURSOR_HANDLE, + MD_ERROR_WIN_INVALID_ACCEL_HANDLE, + MD_ERROR_WIN_INVALID_HOOK_HANDLE, + MD_ERROR_WIN_INVALID_DWP_HANDLE, + MD_ERROR_WIN_TLW_WITH_WSCHILD, + MD_ERROR_WIN_CANNOT_FIND_WND_CLASS, + MD_ERROR_WIN_WINDOW_OF_OTHER_THREAD, + MD_ERROR_WIN_HOTKEY_ALREADY_REGISTERED, + MD_ERROR_WIN_CLASS_ALREADY_EXISTS, + MD_ERROR_WIN_CLASS_DOES_NOT_EXIST, + MD_ERROR_WIN_CLASS_HAS_WINDOWS, + MD_ERROR_WIN_INVALID_INDEX, + MD_ERROR_WIN_INVALID_ICON_HANDLE, + MD_ERROR_WIN_PRIVATE_DIALOG_INDEX, + MD_ERROR_WIN_LISTBOX_ID_NOT_FOUND, + MD_ERROR_WIN_NO_WILDCARD_CHARACTERS, + MD_ERROR_WIN_CLIPBOARD_NOT_OPEN, + MD_ERROR_WIN_HOTKEY_NOT_REGISTERED, + MD_ERROR_WIN_WINDOW_NOT_DIALOG, + MD_ERROR_WIN_CONTROL_ID_NOT_FOUND, + MD_ERROR_WIN_INVALID_COMBOBOX_MESSAGE, + MD_ERROR_WIN_WINDOW_NOT_COMBOBOX, + MD_ERROR_WIN_INVALID_EDIT_HEIGHT, + MD_ERROR_WIN_DC_NOT_FOUND, + MD_ERROR_WIN_INVALID_HOOK_FILTER, + MD_ERROR_WIN_INVALID_FILTER_PROC, + MD_ERROR_WIN_HOOK_NEEDS_HMOD, + MD_ERROR_WIN_GLOBAL_ONLY_HOOK, + MD_ERROR_WIN_JOURNAL_HOOK_SET, + MD_ERROR_WIN_HOOK_NOT_INSTALLED, + MD_ERROR_WIN_INVALID_LB_MESSAGE, + MD_ERROR_WIN_SETCOUNT_ON_BAD_LB, + MD_ERROR_WIN_LB_WITHOUT_TABSTOPS, + MD_ERROR_WIN_DESTROY_OBJECT_OF_OTHER_THREAD, + MD_ERROR_WIN_CHILD_WINDOW_MENU, + MD_ERROR_WIN_NO_SYSTEM_MENU, + MD_ERROR_WIN_INVALID_MSGBOX_STYLE, + MD_ERROR_WIN_INVALID_SPI_VALUE, + MD_ERROR_WIN_SCREEN_ALREADY_LOCKED, + MD_ERROR_WIN_HWNDS_HAVE_DIFF_PARENT, + MD_ERROR_WIN_NOT_CHILD_WINDOW, + MD_ERROR_WIN_INVALID_GW_COMMAND, + MD_ERROR_WIN_INVALID_THREAD_ID, + MD_ERROR_WIN_NON_MDICHILD_WINDOW, + MD_ERROR_WIN_POPUP_ALREADY_ACTIVE, + MD_ERROR_WIN_NO_SCROLLBARS, + MD_ERROR_WIN_INVALID_SCROLLBAR_RANGE, + MD_ERROR_WIN_INVALID_SHOWWIN_COMMAND, + MD_ERROR_WIN_NO_SYSTEM_RESOURCES, + MD_ERROR_WIN_NONPAGED_SYSTEM_RESOURCES, + MD_ERROR_WIN_PAGED_SYSTEM_RESOURCES, + MD_ERROR_WIN_WORKING_SET_QUOTA, + MD_ERROR_WIN_PAGEFILE_QUOTA, + MD_ERROR_WIN_COMMITMENT_LIMIT, + MD_ERROR_WIN_MENU_ITEM_NOT_FOUND, + MD_ERROR_WIN_INVALID_KEYBOARD_HANDLE, + MD_ERROR_WIN_HOOK_TYPE_NOT_ALLOWED, + MD_ERROR_WIN_REQUIRES_INTERACTIVE_WINDOWSTATION, + MD_ERROR_WIN_TIMEOUT, + MD_ERROR_WIN_INVALID_MONITOR_HANDLE, + MD_ERROR_WIN_INCORRECT_SIZE, + MD_ERROR_WIN_SYMLINK_CLASS_DISABLED, + MD_ERROR_WIN_SYMLINK_NOT_SUPPORTED, + MD_ERROR_WIN_XML_PARSE_ERROR, + MD_ERROR_WIN_XMLDSIG_ERROR, + MD_ERROR_WIN_RESTART_APPLICATION, + MD_ERROR_WIN_WRONG_COMPARTMENT, + MD_ERROR_WIN_AUTHIP_FAILURE, + MD_ERROR_WIN_NO_NVRAM_RESOURCES, + MD_ERROR_WIN_NOT_GUI_PROCESS, + MD_ERROR_WIN_EVENTLOG_FILE_CORRUPT, + MD_ERROR_WIN_EVENTLOG_CANT_START, + MD_ERROR_WIN_LOG_FILE_FULL, + MD_ERROR_WIN_EVENTLOG_FILE_CHANGED, + MD_ERROR_WIN_CONTAINER_ASSIGNED, + MD_ERROR_WIN_JOB_NO_CONTAINER, + MD_ERROR_WIN_INVALID_TASK_NAME, + MD_ERROR_WIN_INVALID_TASK_INDEX, + MD_ERROR_WIN_THREAD_ALREADY_IN_TASK, + MD_ERROR_WIN_INSTALL_SERVICE_FAILURE, + MD_ERROR_WIN_INSTALL_USEREXIT, + MD_ERROR_WIN_INSTALL_FAILURE, + MD_ERROR_WIN_INSTALL_SUSPEND, + MD_ERROR_WIN_UNKNOWN_PRODUCT, + MD_ERROR_WIN_UNKNOWN_FEATURE, + MD_ERROR_WIN_UNKNOWN_COMPONENT, + MD_ERROR_WIN_UNKNOWN_PROPERTY, + MD_ERROR_WIN_INVALID_HANDLE_STATE, + MD_ERROR_WIN_BAD_CONFIGURATION, + MD_ERROR_WIN_INDEX_ABSENT, + MD_ERROR_WIN_INSTALL_SOURCE_ABSENT, + MD_ERROR_WIN_INSTALL_PACKAGE_VERSION, + MD_ERROR_WIN_PRODUCT_UNINSTALLED, + MD_ERROR_WIN_BAD_QUERY_SYNTAX, + MD_ERROR_WIN_INVALID_FIELD, + MD_ERROR_WIN_DEVICE_REMOVED, + MD_ERROR_WIN_INSTALL_ALREADY_RUNNING, + MD_ERROR_WIN_INSTALL_PACKAGE_OPEN_FAILED, + MD_ERROR_WIN_INSTALL_PACKAGE_INVALID, + MD_ERROR_WIN_INSTALL_UI_FAILURE, + MD_ERROR_WIN_INSTALL_LOG_FAILURE, + MD_ERROR_WIN_INSTALL_LANGUAGE_UNSUPPORTED, + MD_ERROR_WIN_INSTALL_TRANSFORM_FAILURE, + MD_ERROR_WIN_INSTALL_PACKAGE_REJECTED, + MD_ERROR_WIN_FUNCTION_NOT_CALLED, + MD_ERROR_WIN_FUNCTION_FAILED, + MD_ERROR_WIN_INVALID_TABLE, + MD_ERROR_WIN_DATATYPE_MISMATCH, + MD_ERROR_WIN_UNSUPPORTED_TYPE, + MD_ERROR_WIN_CREATE_FAILED, + MD_ERROR_WIN_INSTALL_TEMP_UNWRITABLE, + MD_ERROR_WIN_INSTALL_PLATFORM_UNSUPPORTED, + MD_ERROR_WIN_INSTALL_NOTUSED, + MD_ERROR_WIN_PATCH_PACKAGE_OPEN_FAILED, + MD_ERROR_WIN_PATCH_PACKAGE_INVALID, + MD_ERROR_WIN_PATCH_PACKAGE_UNSUPPORTED, + MD_ERROR_WIN_PRODUCT_VERSION, + MD_ERROR_WIN_INVALID_COMMAND_LINE, + MD_ERROR_WIN_INSTALL_REMOTE_DISALLOWED, + MD_ERROR_WIN_SUCCESS_REBOOT_INITIATED, + MD_ERROR_WIN_PATCH_TARGET_NOT_FOUND, + MD_ERROR_WIN_PATCH_PACKAGE_REJECTED, + MD_ERROR_WIN_INSTALL_TRANSFORM_REJECTED, + MD_ERROR_WIN_INSTALL_REMOTE_PROHIBITED, + MD_ERROR_WIN_PATCH_REMOVAL_UNSUPPORTED, + MD_ERROR_WIN_UNKNOWN_PATCH, + MD_ERROR_WIN_PATCH_NO_SEQUENCE, + MD_ERROR_WIN_PATCH_REMOVAL_DISALLOWED, + MD_ERROR_WIN_INVALID_PATCH_XML, + MD_ERROR_WIN_PATCH_MANAGED_ADVERTISED_PRODUCT, + MD_ERROR_WIN_INSTALL_SERVICE_SAFEBOOT, + MD_ERROR_WIN_FAIL_FAST_EXCEPTION, + MD_ERROR_WIN_INSTALL_REJECTED, + MD_ERROR_WIN_DYNAMIC_CODE_BLOCKED, + MD_ERROR_WIN_NOT_SAME_OBJECT, + MD_ERROR_WIN_STRICT_CFG_VIOLATION, + MD_ERROR_WIN_SET_CONTEXT_DENIED, + MD_ERROR_WIN_CROSS_PARTITION_VIOLATION, + MD_ERROR_WIN_RETURN_ADDRESS_HIJACK_ATTEMPT, + MD_ERROR_WIN_INVALID_USER_BUFFER, + MD_ERROR_WIN_UNRECOGNIZED_MEDIA, + MD_ERROR_WIN_NO_TRUST_LSA_SECRET, + MD_ERROR_WIN_NO_TRUST_SAM_ACCOUNT, + MD_ERROR_WIN_TRUSTED_DOMAIN_FAILURE, + MD_ERROR_WIN_TRUSTED_RELATIONSHIP_FAILURE, + MD_ERROR_WIN_TRUST_FAILURE, + MD_ERROR_WIN_NETLOGON_NOT_STARTED, + MD_ERROR_WIN_ACCOUNT_EXPIRED, + MD_ERROR_WIN_REDIRECTOR_HAS_OPEN_HANDLES, + MD_ERROR_WIN_PRINTER_DRIVER_ALREADY_INSTALLED, + MD_ERROR_WIN_UNKNOWN_PORT, + MD_ERROR_WIN_UNKNOWN_PRINTER_DRIVER, + MD_ERROR_WIN_UNKNOWN_PRINTPROCESSOR, + MD_ERROR_WIN_INVALID_SEPARATOR_FILE, + MD_ERROR_WIN_INVALID_PRIORITY, + MD_ERROR_WIN_INVALID_PRINTER_NAME, + MD_ERROR_WIN_PRINTER_ALREADY_EXISTS, + MD_ERROR_WIN_INVALID_PRINTER_COMMAND, + MD_ERROR_WIN_INVALID_DATATYPE, + MD_ERROR_WIN_INVALID_ENVIRONMENT, + MD_ERROR_WIN_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, + MD_ERROR_WIN_NOLOGON_WORKSTATION_TRUST_ACCOUNT, + MD_ERROR_WIN_NOLOGON_SERVER_TRUST_ACCOUNT, + MD_ERROR_WIN_DOMAIN_TRUST_INCONSISTENT, + MD_ERROR_WIN_SERVER_HAS_OPEN_HANDLES, + MD_ERROR_WIN_RESOURCE_DATA_NOT_FOUND, + MD_ERROR_WIN_RESOURCE_TYPE_NOT_FOUND, + MD_ERROR_WIN_RESOURCE_NAME_NOT_FOUND, + MD_ERROR_WIN_RESOURCE_LANG_NOT_FOUND, + MD_ERROR_WIN_NOT_ENOUGH_QUOTA, + MD_ERROR_WIN_INVALID_TIME, + MD_ERROR_WIN_INVALID_FORM_NAME, + MD_ERROR_WIN_INVALID_FORM_SIZE, + MD_ERROR_WIN_ALREADY_WAITING, + MD_ERROR_WIN_PRINTER_DELETED, + MD_ERROR_WIN_INVALID_PRINTER_STATE, + MD_ERROR_WIN_PASSWORD_MUST_CHANGE, + MD_ERROR_WIN_DOMAIN_CONTROLLER_NOT_FOUND, + MD_ERROR_WIN_ACCOUNT_LOCKED_OUT, + MD_ERROR_WIN_NO_SITENAME, + MD_ERROR_WIN_CANT_ACCESS_FILE, + MD_ERROR_WIN_CANT_RESOLVE_FILENAME, + MD_ERROR_WIN_KM_DRIVER_BLOCKED, + MD_ERROR_WIN_CONTEXT_EXPIRED, + MD_ERROR_WIN_PER_USER_TRUST_QUOTA_EXCEEDED, + MD_ERROR_WIN_ALL_USER_TRUST_QUOTA_EXCEEDED, + MD_ERROR_WIN_USER_DELETE_TRUST_QUOTA_EXCEEDED, + MD_ERROR_WIN_AUTHENTICATION_FIREWALL_FAILED, + MD_ERROR_WIN_REMOTE_PRINT_CONNECTIONS_BLOCKED, + MD_ERROR_WIN_NTLM_BLOCKED, + MD_ERROR_WIN_PASSWORD_CHANGE_REQUIRED, + MD_ERROR_WIN_LOST_MODE_LOGON_RESTRICTION, + MD_ERROR_WIN_INVALID_PIXEL_FORMAT, + MD_ERROR_WIN_BAD_DRIVER, + MD_ERROR_WIN_INVALID_WINDOW_STYLE, + MD_ERROR_WIN_METAFILE_NOT_SUPPORTED, + MD_ERROR_WIN_TRANSFORM_NOT_SUPPORTED, + MD_ERROR_WIN_CLIPPING_NOT_SUPPORTED, + MD_ERROR_WIN_INVALID_CMM, + MD_ERROR_WIN_INVALID_PROFILE, + MD_ERROR_WIN_TAG_NOT_FOUND, + MD_ERROR_WIN_TAG_NOT_PRESENT, + MD_ERROR_WIN_DUPLICATE_TAG, + MD_ERROR_WIN_PROFILE_NOT_ASSOCIATED_WITH_DEVICE, + MD_ERROR_WIN_PROFILE_NOT_FOUND, + MD_ERROR_WIN_INVALID_COLORSPACE, + MD_ERROR_WIN_ICM_NOT_ENABLED, + MD_ERROR_WIN_DELETING_ICM_XFORM, + MD_ERROR_WIN_INVALID_TRANSFORM, + MD_ERROR_WIN_COLORSPACE_MISMATCH, + MD_ERROR_WIN_INVALID_COLORINDEX, + MD_ERROR_WIN_PROFILE_DOES_NOT_MATCH_DEVICE, + MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD, + MD_ERROR_WIN_CONNECTED_OTHER_PASSWORD_DEFAULT, + MD_ERROR_WIN_BAD_USERNAME, + MD_ERROR_WIN_NOT_CONNECTED, + MD_ERROR_WIN_OPEN_FILES, + MD_ERROR_WIN_ACTIVE_CONNECTIONS, + MD_ERROR_WIN_DEVICE_IN_USE, + MD_ERROR_WIN_UNKNOWN_PRINT_MONITOR, + MD_ERROR_WIN_PRINTER_DRIVER_IN_USE, + MD_ERROR_WIN_SPOOL_FILE_NOT_FOUND, + MD_ERROR_WIN_SPL_NO_STARTDOC, + MD_ERROR_WIN_SPL_NO_ADDJOB, + MD_ERROR_WIN_PRINT_PROCESSOR_ALREADY_INSTALLED, + MD_ERROR_WIN_PRINT_MONITOR_ALREADY_INSTALLED, + MD_ERROR_WIN_INVALID_PRINT_MONITOR, + MD_ERROR_WIN_PRINT_MONITOR_IN_USE, + MD_ERROR_WIN_PRINTER_HAS_JOBS_QUEUED, + MD_ERROR_WIN_SUCCESS_REBOOT_REQUIRED, + MD_ERROR_WIN_SUCCESS_RESTART_REQUIRED, + MD_ERROR_WIN_PRINTER_NOT_FOUND, + MD_ERROR_WIN_PRINTER_DRIVER_WARNED, + MD_ERROR_WIN_PRINTER_DRIVER_BLOCKED, + MD_ERROR_WIN_PRINTER_DRIVER_PACKAGE_IN_USE, + MD_ERROR_WIN_CORE_DRIVER_PACKAGE_NOT_FOUND, + MD_ERROR_WIN_FAIL_REBOOT_REQUIRED, + MD_ERROR_WIN_FAIL_REBOOT_INITIATED, + MD_ERROR_WIN_PRINTER_DRIVER_DOWNLOAD_NEEDED, + MD_ERROR_WIN_PRINT_JOB_RESTART_REQUIRED, + MD_ERROR_WIN_INVALID_PRINTER_DRIVER_MANIFEST, + MD_ERROR_WIN_PRINTER_NOT_SHAREABLE, + MD_ERROR_WIN_REQUEST_PAUSED, + MD_ERROR_WIN_APPEXEC_CONDITION_NOT_SATISFIED, + MD_ERROR_WIN_APPEXEC_HANDLE_INVALIDATED, + MD_ERROR_WIN_APPEXEC_INVALID_HOST_GENERATION, + MD_ERROR_WIN_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION, + MD_ERROR_WIN_APPEXEC_INVALID_HOST_STATE, + MD_ERROR_WIN_APPEXEC_NO_DONOR, + MD_ERROR_WIN_APPEXEC_HOST_ID_MISMATCH, + MD_ERROR_WIN_APPEXEC_UNKNOWN_USER, + MD_ERROR_WIN_IO_REISSUE_AS_CACHED, + MD_ERROR_WIN_WINS_INTERNAL, + MD_ERROR_WIN_CAN_NOT_DEL_LOCAL_WINS, + MD_ERROR_WIN_STATIC_INIT, + MD_ERROR_WIN_INC_BACKUP, + MD_ERROR_WIN_FULL_BACKUP, + MD_ERROR_WIN_REC_NON_EXISTENT, + MD_ERROR_WIN_RPL_NOT_ALLOWED, + MD_ERROR_WIN_DHCP_ADDRESS_CONFLICT, + MD_ERROR_WIN_WMI_GUID_NOT_FOUND, + MD_ERROR_WIN_WMI_INSTANCE_NOT_FOUND, + MD_ERROR_WIN_WMI_ITEMID_NOT_FOUND, + MD_ERROR_WIN_WMI_TRY_AGAIN, + MD_ERROR_WIN_WMI_DP_NOT_FOUND, + MD_ERROR_WIN_WMI_UNRESOLVED_INSTANCE_REF, + MD_ERROR_WIN_WMI_ALREADY_ENABLED, + MD_ERROR_WIN_WMI_GUID_DISCONNECTED, + MD_ERROR_WIN_WMI_SERVER_UNAVAILABLE, + MD_ERROR_WIN_WMI_DP_FAILED, + MD_ERROR_WIN_WMI_INVALID_MOF, + MD_ERROR_WIN_WMI_INVALID_REGINFO, + MD_ERROR_WIN_WMI_ALREADY_DISABLED, + MD_ERROR_WIN_WMI_READ_ONLY, + MD_ERROR_WIN_WMI_SET_FAILURE, + MD_ERROR_WIN_NOT_APPCONTAINER, + MD_ERROR_WIN_APPCONTAINER_REQUIRED, + MD_ERROR_WIN_NOT_SUPPORTED_IN_APPCONTAINER, + MD_ERROR_WIN_INVALID_PACKAGE_SID_LENGTH, + MD_ERROR_WIN_INVALID_MEDIA, + MD_ERROR_WIN_INVALID_LIBRARY, + MD_ERROR_WIN_INVALID_MEDIA_POOL, + MD_ERROR_WIN_DRIVE_MEDIA_MISMATCH, + MD_ERROR_WIN_MEDIA_OFFLINE, + MD_ERROR_WIN_LIBRARY_OFFLINE, + MD_ERROR_WIN_EMPTY, + MD_ERROR_WIN_NOT_EMPTY, + MD_ERROR_WIN_MEDIA_UNAVAILABLE, + MD_ERROR_WIN_RESOURCE_DISABLED, + MD_ERROR_WIN_INVALID_CLEANER, + MD_ERROR_WIN_UNABLE_TO_CLEAN, + MD_ERROR_WIN_OBJECT_NOT_FOUND, + MD_ERROR_WIN_DATABASE_FAILURE, + MD_ERROR_WIN_DATABASE_FULL, + MD_ERROR_WIN_MEDIA_INCOMPATIBLE, + MD_ERROR_WIN_RESOURCE_NOT_PRESENT, + MD_ERROR_WIN_INVALID_OPERATION, + MD_ERROR_WIN_MEDIA_NOT_AVAILABLE, + MD_ERROR_WIN_DEVICE_NOT_AVAILABLE, + MD_ERROR_WIN_REQUEST_REFUSED, + MD_ERROR_WIN_INVALID_DRIVE_OBJECT, + MD_ERROR_WIN_LIBRARY_FULL, + MD_ERROR_WIN_MEDIUM_NOT_ACCESSIBLE, + MD_ERROR_WIN_UNABLE_TO_LOAD_MEDIUM, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_DRIVE, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_SLOT, + MD_ERROR_WIN_UNABLE_TO_INVENTORY_TRANSPORT, + MD_ERROR_WIN_TRANSPORT_FULL, + MD_ERROR_WIN_CONTROLLING_IEPORT, + MD_ERROR_WIN_UNABLE_TO_EJECT_MOUNTED_MEDIA, + MD_ERROR_WIN_CLEANER_SLOT_SET, + MD_ERROR_WIN_CLEANER_SLOT_NOT_SET, + MD_ERROR_WIN_CLEANER_CARTRIDGE_SPENT, + MD_ERROR_WIN_UNEXPECTED_OMID, + MD_ERROR_WIN_CANT_DELETE_LAST_ITEM, + MD_ERROR_WIN_MESSAGE_EXCEEDS_MAX_SIZE, + MD_ERROR_WIN_VOLUME_CONTAINS_SYS_FILES, + MD_ERROR_WIN_INDIGENOUS_TYPE, + MD_ERROR_WIN_NO_SUPPORTING_DRIVES, + MD_ERROR_WIN_CLEANER_CARTRIDGE_INSTALLED, + MD_ERROR_WIN_IEPORT_FULL, + MD_ERROR_WIN_FILE_OFFLINE, + MD_ERROR_WIN_REMOTE_STORAGE_NOT_ACTIVE, + MD_ERROR_WIN_REMOTE_STORAGE_MEDIA_ERROR, + MD_ERROR_WIN_NOT_A_REPARSE_POINT, + MD_ERROR_WIN_REPARSE_ATTRIBUTE_CONFLICT, + MD_ERROR_WIN_INVALID_REPARSE_DATA, + MD_ERROR_WIN_REPARSE_TAG_INVALID, + MD_ERROR_WIN_REPARSE_TAG_MISMATCH, + MD_ERROR_WIN_REPARSE_POINT_ENCOUNTERED, + MD_ERROR_WIN_APP_DATA_NOT_FOUND, + MD_ERROR_WIN_APP_DATA_EXPIRED, + MD_ERROR_WIN_APP_DATA_CORRUPT, + MD_ERROR_WIN_APP_DATA_LIMIT_EXCEEDED, + MD_ERROR_WIN_APP_DATA_REBOOT_REQUIRED, + MD_ERROR_WIN_SECUREBOOT_ROLLBACK_DETECTED, + MD_ERROR_WIN_SECUREBOOT_POLICY_VIOLATION, + MD_ERROR_WIN_SECUREBOOT_INVALID_POLICY, + MD_ERROR_WIN_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND, + MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_SIGNED, + MD_ERROR_WIN_SECUREBOOT_NOT_ENABLED, + MD_ERROR_WIN_SECUREBOOT_FILE_REPLACED, + MD_ERROR_WIN_SECUREBOOT_POLICY_NOT_AUTHORIZED, + MD_ERROR_WIN_SECUREBOOT_POLICY_UNKNOWN, + MD_ERROR_WIN_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION, + MD_ERROR_WIN_SECUREBOOT_PLATFORM_ID_MISMATCH, + MD_ERROR_WIN_SECUREBOOT_POLICY_ROLLBACK_DETECTED, + MD_ERROR_WIN_SECUREBOOT_POLICY_UPGRADE_MISMATCH, + MD_ERROR_WIN_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING, + MD_ERROR_WIN_SECUREBOOT_NOT_BASE_POLICY, + MD_ERROR_WIN_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY, + MD_ERROR_WIN_OFFLOAD_READ_FLT_NOT_SUPPORTED, + MD_ERROR_WIN_OFFLOAD_WRITE_FLT_NOT_SUPPORTED, + MD_ERROR_WIN_OFFLOAD_READ_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_OFFLOAD_WRITE_FILE_NOT_SUPPORTED, + MD_ERROR_WIN_ALREADY_HAS_STREAM_ID, + MD_ERROR_WIN_SMR_GARBAGE_COLLECTION_REQUIRED, + MD_ERROR_WIN_WOF_WIM_HEADER_CORRUPT, + MD_ERROR_WIN_WOF_WIM_RESOURCE_TABLE_CORRUPT, + MD_ERROR_WIN_WOF_FILE_RESOURCE_TABLE_CORRUPT, + MD_ERROR_WIN_VOLUME_NOT_SIS_ENABLED, + MD_ERROR_WIN_SYSTEM_INTEGRITY_ROLLBACK_DETECTED, + MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_VIOLATION, + MD_ERROR_WIN_SYSTEM_INTEGRITY_INVALID_POLICY, + MD_ERROR_WIN_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED, + MD_ERROR_WIN_SYSTEM_INTEGRITY_TOO_MANY_POLICIES, + MD_ERROR_WIN_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED, + MD_ERROR_WIN_VSM_NOT_INITIALIZED, + MD_ERROR_WIN_VSM_DMA_PROTECTION_NOT_IN_USE, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_AUTHORIZED, + MD_ERROR_WIN_PLATFORM_MANIFEST_INVALID, + MD_ERROR_WIN_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED, + MD_ERROR_WIN_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED, + MD_ERROR_WIN_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_ACTIVE, + MD_ERROR_WIN_PLATFORM_MANIFEST_NOT_SIGNED, + MD_ERROR_WIN_DEPENDENT_RESOURCE_EXISTS, + MD_ERROR_WIN_DEPENDENCY_NOT_FOUND, + MD_ERROR_WIN_DEPENDENCY_ALREADY_EXISTS, + MD_ERROR_WIN_RESOURCE_NOT_ONLINE, + MD_ERROR_WIN_HOST_NODE_NOT_AVAILABLE, + MD_ERROR_WIN_RESOURCE_NOT_AVAILABLE, + MD_ERROR_WIN_RESOURCE_NOT_FOUND, + MD_ERROR_WIN_SHUTDOWN_CLUSTER, + MD_ERROR_WIN_CANT_EVICT_ACTIVE_NODE, + MD_ERROR_WIN_OBJECT_ALREADY_EXISTS, + MD_ERROR_WIN_OBJECT_IN_LIST, + MD_ERROR_WIN_GROUP_NOT_AVAILABLE, + MD_ERROR_WIN_GROUP_NOT_FOUND, + MD_ERROR_WIN_GROUP_NOT_ONLINE, + MD_ERROR_WIN_HOST_NODE_NOT_RESOURCE_OWNER, + MD_ERROR_WIN_HOST_NODE_NOT_GROUP_OWNER, + MD_ERROR_WIN_RESMON_CREATE_FAILED, + MD_ERROR_WIN_RESMON_ONLINE_FAILED, + MD_ERROR_WIN_RESOURCE_ONLINE, + MD_ERROR_WIN_QUORUM_RESOURCE, + MD_ERROR_WIN_NOT_QUORUM_CAPABLE, + MD_ERROR_WIN_CLUSTER_SHUTTING_DOWN, + MD_ERROR_WIN_INVALID_STATE, + MD_ERROR_WIN_RESOURCE_PROPERTIES_STORED, + MD_ERROR_WIN_NOT_QUORUM_CLASS, + MD_ERROR_WIN_CORE_RESOURCE, + MD_ERROR_WIN_QUORUM_RESOURCE_ONLINE_FAILED, + MD_ERROR_WIN_QUORUMLOG_OPEN_FAILED, + MD_ERROR_WIN_CLUSTERLOG_CORRUPT, + MD_ERROR_WIN_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE, + MD_ERROR_WIN_CLUSTERLOG_EXCEEDS_MAXSIZE, + MD_ERROR_WIN_CLUSTERLOG_CHKPOINT_NOT_FOUND, + MD_ERROR_WIN_CLUSTERLOG_NOT_ENOUGH_SPACE, + MD_ERROR_WIN_QUORUM_OWNER_ALIVE, + MD_ERROR_WIN_NETWORK_NOT_AVAILABLE, + MD_ERROR_WIN_NODE_NOT_AVAILABLE, + MD_ERROR_WIN_ALL_NODES_NOT_AVAILABLE, + MD_ERROR_WIN_RESOURCE_FAILED, + MD_ERROR_WIN_CLUSTER_INVALID_NODE, + MD_ERROR_WIN_CLUSTER_NODE_EXISTS, + MD_ERROR_WIN_CLUSTER_JOIN_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_NODE_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_LOCAL_NODE_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_NETWORK_EXISTS, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_NETINTERFACE_EXISTS, + MD_ERROR_WIN_CLUSTER_NETINTERFACE_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_INVALID_REQUEST, + MD_ERROR_WIN_CLUSTER_INVALID_NETWORK_PROVIDER, + MD_ERROR_WIN_CLUSTER_NODE_DOWN, + MD_ERROR_WIN_CLUSTER_NODE_UNREACHABLE, + MD_ERROR_WIN_CLUSTER_NODE_NOT_MEMBER, + MD_ERROR_WIN_CLUSTER_JOIN_NOT_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_INVALID_NETWORK, + MD_ERROR_WIN_CLUSTER_NODE_UP, + MD_ERROR_WIN_CLUSTER_IPADDR_IN_USE, + MD_ERROR_WIN_CLUSTER_NODE_NOT_PAUSED, + MD_ERROR_WIN_CLUSTER_NO_SECURITY_CONTEXT, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_INTERNAL, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_UP, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_DOWN, + MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_ONLINE, + MD_ERROR_WIN_CLUSTER_NETWORK_ALREADY_OFFLINE, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_MEMBER, + MD_ERROR_WIN_CLUSTER_LAST_INTERNAL_NETWORK, + MD_ERROR_WIN_CLUSTER_NETWORK_HAS_DEPENDENTS, + MD_ERROR_WIN_INVALID_OPERATION_ON_QUORUM, + MD_ERROR_WIN_DEPENDENCY_NOT_ALLOWED, + MD_ERROR_WIN_CLUSTER_NODE_PAUSED, + MD_ERROR_WIN_NODE_CANT_HOST_RESOURCE, + MD_ERROR_WIN_CLUSTER_NODE_NOT_READY, + MD_ERROR_WIN_CLUSTER_NODE_SHUTTING_DOWN, + MD_ERROR_WIN_CLUSTER_JOIN_ABORTED, + MD_ERROR_WIN_CLUSTER_INCOMPATIBLE_VERSIONS, + MD_ERROR_WIN_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED, + MD_ERROR_WIN_CLUSTER_SYSTEM_CONFIG_CHANGED, + MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_RESTYPE_NOT_SUPPORTED, + MD_ERROR_WIN_CLUSTER_RESNAME_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_NO_RPC_PACKAGES_REGISTERED, + MD_ERROR_WIN_CLUSTER_OWNER_NOT_IN_PREFLIST, + MD_ERROR_WIN_CLUSTER_DATABASE_SEQMISMATCH, + MD_ERROR_WIN_RESMON_INVALID_STATE, + MD_ERROR_WIN_CLUSTER_GUM_NOT_LOCKER, + MD_ERROR_WIN_QUORUM_DISK_NOT_FOUND, + MD_ERROR_WIN_DATABASE_BACKUP_CORRUPT, + MD_ERROR_WIN_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT, + MD_ERROR_WIN_RESOURCE_PROPERTY_UNCHANGEABLE, + MD_ERROR_WIN_NO_ADMIN_ACCESS_POINT, + MD_ERROR_WIN_CLUSTER_MEMBERSHIP_INVALID_STATE, + MD_ERROR_WIN_CLUSTER_QUORUMLOG_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_MEMBERSHIP_HALT, + MD_ERROR_WIN_CLUSTER_INSTANCE_ID_MISMATCH, + MD_ERROR_WIN_CLUSTER_NETWORK_NOT_FOUND_FOR_IP, + MD_ERROR_WIN_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH, + MD_ERROR_WIN_CLUSTER_EVICT_WITHOUT_CLEANUP, + MD_ERROR_WIN_CLUSTER_PARAMETER_MISMATCH, + MD_ERROR_WIN_NODE_CANNOT_BE_CLUSTERED, + MD_ERROR_WIN_CLUSTER_WRONG_OS_VERSION, + MD_ERROR_WIN_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME, + MD_ERROR_WIN_CLUSCFG_ALREADY_COMMITTED, + MD_ERROR_WIN_CLUSCFG_ROLLBACK_FAILED, + MD_ERROR_WIN_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT, + MD_ERROR_WIN_CLUSTER_OLD_VERSION, + MD_ERROR_WIN_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME, + MD_ERROR_WIN_CLUSTER_NO_NET_ADAPTERS, + MD_ERROR_WIN_CLUSTER_POISONED, + MD_ERROR_WIN_CLUSTER_GROUP_MOVING, + MD_ERROR_WIN_CLUSTER_RESOURCE_TYPE_BUSY, + MD_ERROR_WIN_RESOURCE_CALL_TIMED_OUT, + MD_ERROR_WIN_INVALID_CLUSTER_IPV6_ADDRESS, + MD_ERROR_WIN_CLUSTER_INTERNAL_INVALID_FUNCTION, + MD_ERROR_WIN_CLUSTER_PARAMETER_OUT_OF_BOUNDS, + MD_ERROR_WIN_CLUSTER_PARTIAL_SEND, + MD_ERROR_WIN_CLUSTER_REGISTRY_INVALID_FUNCTION, + MD_ERROR_WIN_CLUSTER_INVALID_STRING_TERMINATION, + MD_ERROR_WIN_CLUSTER_INVALID_STRING_FORMAT, + MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_NULL_DATA, + MD_ERROR_WIN_CLUSTER_PARTIAL_READ, + MD_ERROR_WIN_CLUSTER_PARTIAL_WRITE, + MD_ERROR_WIN_CLUSTER_CANT_DESERIALIZE_DATA, + MD_ERROR_WIN_DEPENDENT_RESOURCE_PROPERTY_CONFLICT, + MD_ERROR_WIN_CLUSTER_NO_QUORUM, + MD_ERROR_WIN_CLUSTER_INVALID_IPV6_NETWORK, + MD_ERROR_WIN_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK, + MD_ERROR_WIN_QUORUM_NOT_ALLOWED_IN_THIS_GROUP, + MD_ERROR_WIN_DEPENDENCY_TREE_TOO_COMPLEX, + MD_ERROR_WIN_EXCEPTION_IN_RESOURCE_CALL, + MD_ERROR_WIN_CLUSTER_RHS_FAILED_INITIALIZATION, + MD_ERROR_WIN_CLUSTER_NOT_INSTALLED, + MD_ERROR_WIN_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE, + MD_ERROR_WIN_CLUSTER_MAX_NODES_IN_CLUSTER, + MD_ERROR_WIN_CLUSTER_TOO_MANY_NODES, + MD_ERROR_WIN_CLUSTER_OBJECT_ALREADY_USED, + MD_ERROR_WIN_NONCORE_GROUPS_FOUND, + MD_ERROR_WIN_FILE_SHARE_RESOURCE_CONFLICT, + MD_ERROR_WIN_CLUSTER_EVICT_INVALID_REQUEST, + MD_ERROR_WIN_CLUSTER_SINGLETON_RESOURCE, + MD_ERROR_WIN_CLUSTER_GROUP_SINGLETON_RESOURCE, + MD_ERROR_WIN_CLUSTER_RESOURCE_PROVIDER_FAILED, + MD_ERROR_WIN_CLUSTER_RESOURCE_CONFIGURATION_ERROR, + MD_ERROR_WIN_CLUSTER_GROUP_BUSY, + MD_ERROR_WIN_CLUSTER_NOT_SHARED_VOLUME, + MD_ERROR_WIN_CLUSTER_INVALID_SECURITY_DESCRIPTOR, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUMES_IN_USE, + MD_ERROR_WIN_CLUSTER_USE_SHARED_VOLUMES_API, + MD_ERROR_WIN_CLUSTER_BACKUP_IN_PROGRESS, + MD_ERROR_WIN_NON_CSV_PATH, + MD_ERROR_WIN_CSV_VOLUME_NOT_LOCAL, + MD_ERROR_WIN_CLUSTER_WATCHDOG_TERMINATING, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES, + MD_ERROR_WIN_CLUSTER_INVALID_NODE_WEIGHT, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_CALL, + MD_ERROR_WIN_RESMON_SYSTEM_RESOURCES_LACKING, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION, + MD_ERROR_WIN_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE, + MD_ERROR_WIN_CLUSTER_GROUP_QUEUED, + MD_ERROR_WIN_CLUSTER_RESOURCE_LOCKED_STATUS, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED, + MD_ERROR_WIN_CLUSTER_NODE_DRAIN_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_DISK_NOT_CONNECTED, + MD_ERROR_WIN_DISK_NOT_CSV_CAPABLE, + MD_ERROR_WIN_RESOURCE_NOT_IN_AVAILABLE_STORAGE, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_REDIRECTED, + MD_ERROR_WIN_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED, + MD_ERROR_WIN_CLUSTER_CANNOT_RETURN_PROPERTIES, + MD_ERROR_WIN_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE, + MD_ERROR_WIN_CLUSTER_AFFINITY_CONFLICT, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE, + MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS, + MD_ERROR_WIN_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED, + MD_ERROR_WIN_CLUSTER_UPGRADE_RESTART_REQUIRED, + MD_ERROR_WIN_CLUSTER_UPGRADE_IN_PROGRESS, + MD_ERROR_WIN_CLUSTER_UPGRADE_INCOMPLETE, + MD_ERROR_WIN_CLUSTER_NODE_IN_GRACE_PERIOD, + MD_ERROR_WIN_CLUSTER_CSV_IO_PAUSE_TIMEOUT, + MD_ERROR_WIN_NODE_NOT_ACTIVE_CLUSTER_MEMBER, + MD_ERROR_WIN_CLUSTER_RESOURCE_NOT_MONITORED, + MD_ERROR_WIN_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED, + MD_ERROR_WIN_CLUSTER_RESOURCE_IS_REPLICATED, + MD_ERROR_WIN_CLUSTER_NODE_ISOLATED, + MD_ERROR_WIN_CLUSTER_NODE_QUARANTINED, + MD_ERROR_WIN_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED, + MD_ERROR_WIN_CLUSTER_SPACE_DEGRADED, + MD_ERROR_WIN_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED, + MD_ERROR_WIN_CLUSTER_CSV_INVALID_HANDLE, + MD_ERROR_WIN_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR, + MD_ERROR_WIN_GROUPSET_NOT_AVAILABLE, + MD_ERROR_WIN_GROUPSET_NOT_FOUND, + MD_ERROR_WIN_GROUPSET_CANT_PROVIDE, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION, + MD_ERROR_WIN_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS, + MD_ERROR_WIN_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME, + MD_ERROR_WIN_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE, + MD_ERROR_WIN_ENCRYPTION_FAILED, + MD_ERROR_WIN_DECRYPTION_FAILED, + MD_ERROR_WIN_FILE_ENCRYPTED, + MD_ERROR_WIN_NO_RECOVERY_POLICY, + MD_ERROR_WIN_NO_EFS, + MD_ERROR_WIN_WRONG_EFS, + MD_ERROR_WIN_NO_USER_KEYS, + MD_ERROR_WIN_FILE_NOT_ENCRYPTED, + MD_ERROR_WIN_NOT_EXPORT_FORMAT, + MD_ERROR_WIN_FILE_READ_ONLY, + MD_ERROR_WIN_DIR_EFS_DISALLOWED, + MD_ERROR_WIN_EFS_SERVER_NOT_TRUSTED, + MD_ERROR_WIN_BAD_RECOVERY_POLICY, + MD_ERROR_WIN_EFS_ALG_BLOB_TOO_BIG, + MD_ERROR_WIN_VOLUME_NOT_SUPPORT_EFS, + MD_ERROR_WIN_EFS_DISABLED, + MD_ERROR_WIN_EFS_VERSION_NOT_SUPPORT, + MD_ERROR_WIN_CS_ENCRYPTION_INVALID_SERVER_RESPONSE, + MD_ERROR_WIN_CS_ENCRYPTION_UNSUPPORTED_SERVER, + MD_ERROR_WIN_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE, + MD_ERROR_WIN_CS_ENCRYPTION_NEW_ENCRYPTED_FILE, + MD_ERROR_WIN_CS_ENCRYPTION_FILE_NOT_CSE, + MD_ERROR_WIN_ENCRYPTION_POLICY_DENIES_OPERATION, + MD_ERROR_WIN_WIP_ENCRYPTION_FAILED, + MD_ERROR_WIN_NO_BROWSER_SERVERS_FOUND, + MD_ERROR_WIN_CLUSTER_OBJECT_IS_CLUSTER_SET_VM, + MD_ERROR_WIN_LOG_SECTOR_INVALID, + MD_ERROR_WIN_LOG_SECTOR_PARITY_INVALID, + MD_ERROR_WIN_LOG_SECTOR_REMAPPED, + MD_ERROR_WIN_LOG_BLOCK_INCOMPLETE, + MD_ERROR_WIN_LOG_INVALID_RANGE, + MD_ERROR_WIN_LOG_BLOCKS_EXHAUSTED, + MD_ERROR_WIN_LOG_READ_CONTEXT_INVALID, + MD_ERROR_WIN_LOG_RESTART_INVALID, + MD_ERROR_WIN_LOG_BLOCK_VERSION, + MD_ERROR_WIN_LOG_BLOCK_INVALID, + MD_ERROR_WIN_LOG_READ_MODE_INVALID, + MD_ERROR_WIN_LOG_NO_RESTART, + MD_ERROR_WIN_LOG_METADATA_CORRUPT, + MD_ERROR_WIN_LOG_METADATA_INVALID, + MD_ERROR_WIN_LOG_METADATA_INCONSISTENT, + MD_ERROR_WIN_LOG_RESERVATION_INVALID, + MD_ERROR_WIN_LOG_CANT_DELETE, + MD_ERROR_WIN_LOG_CONTAINER_LIMIT_EXCEEDED, + MD_ERROR_WIN_LOG_START_OF_LOG, + MD_ERROR_WIN_LOG_POLICY_ALREADY_INSTALLED, + MD_ERROR_WIN_LOG_POLICY_NOT_INSTALLED, + MD_ERROR_WIN_LOG_POLICY_INVALID, + MD_ERROR_WIN_LOG_POLICY_CONFLICT, + MD_ERROR_WIN_LOG_PINNED_ARCHIVE_TAIL, + MD_ERROR_WIN_LOG_RECORD_NONEXISTENT, + MD_ERROR_WIN_LOG_RECORDS_RESERVED_INVALID, + MD_ERROR_WIN_LOG_SPACE_RESERVED_INVALID, + MD_ERROR_WIN_LOG_TAIL_INVALID, + MD_ERROR_WIN_LOG_FULL, + MD_ERROR_WIN_COULD_NOT_RESIZE_LOG, + MD_ERROR_WIN_LOG_MULTIPLEXED, + MD_ERROR_WIN_LOG_DEDICATED, + MD_ERROR_WIN_LOG_ARCHIVE_NOT_IN_PROGRESS, + MD_ERROR_WIN_LOG_ARCHIVE_IN_PROGRESS, + MD_ERROR_WIN_LOG_EPHEMERAL, + MD_ERROR_WIN_LOG_NOT_ENOUGH_CONTAINERS, + MD_ERROR_WIN_LOG_CLIENT_ALREADY_REGISTERED, + MD_ERROR_WIN_LOG_CLIENT_NOT_REGISTERED, + MD_ERROR_WIN_LOG_FULL_HANDLER_IN_PROGRESS, + MD_ERROR_WIN_LOG_CONTAINER_READ_FAILED, + MD_ERROR_WIN_LOG_CONTAINER_WRITE_FAILED, + MD_ERROR_WIN_LOG_CONTAINER_OPEN_FAILED, + MD_ERROR_WIN_LOG_CONTAINER_STATE_INVALID, + MD_ERROR_WIN_LOG_STATE_INVALID, + MD_ERROR_WIN_LOG_PINNED, + MD_ERROR_WIN_LOG_METADATA_FLUSH_FAILED, + MD_ERROR_WIN_LOG_INCONSISTENT_SECURITY, + MD_ERROR_WIN_LOG_APPENDED_FLUSH_FAILED, + MD_ERROR_WIN_LOG_PINNED_RESERVATION, + MD_ERROR_WIN_INVALID_TRANSACTION, + MD_ERROR_WIN_TRANSACTION_NOT_ACTIVE, + MD_ERROR_WIN_TRANSACTION_REQUEST_NOT_VALID, + MD_ERROR_WIN_TRANSACTION_NOT_REQUESTED, + MD_ERROR_WIN_TRANSACTION_ALREADY_ABORTED, + MD_ERROR_WIN_TRANSACTION_ALREADY_COMMITTED, + MD_ERROR_WIN_TM_INITIALIZATION_FAILED, + MD_ERROR_WIN_RESOURCEMANAGER_READ_ONLY, + MD_ERROR_WIN_TRANSACTION_NOT_JOINED, + MD_ERROR_WIN_TRANSACTION_SUPERIOR_EXISTS, + MD_ERROR_WIN_CRM_PROTOCOL_ALREADY_EXISTS, + MD_ERROR_WIN_TRANSACTION_PROPAGATION_FAILED, + MD_ERROR_WIN_CRM_PROTOCOL_NOT_FOUND, + MD_ERROR_WIN_TRANSACTION_INVALID_MARSHALL_BUFFER, + MD_ERROR_WIN_CURRENT_TRANSACTION_NOT_VALID, + MD_ERROR_WIN_TRANSACTION_NOT_FOUND, + MD_ERROR_WIN_RESOURCEMANAGER_NOT_FOUND, + MD_ERROR_WIN_ENLISTMENT_NOT_FOUND, + MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_FOUND, + MD_ERROR_WIN_TRANSACTIONMANAGER_NOT_ONLINE, + MD_ERROR_WIN_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION, + MD_ERROR_WIN_TRANSACTION_NOT_ROOT, + MD_ERROR_WIN_TRANSACTION_OBJECT_EXPIRED, + MD_ERROR_WIN_TRANSACTION_RESPONSE_NOT_ENLISTED, + MD_ERROR_WIN_TRANSACTION_RECORD_TOO_LONG, + MD_ERROR_WIN_IMPLICIT_TRANSACTION_NOT_SUPPORTED, + MD_ERROR_WIN_TRANSACTION_INTEGRITY_VIOLATED, + MD_ERROR_WIN_TRANSACTIONMANAGER_IDENTITY_MISMATCH, + MD_ERROR_WIN_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT, + MD_ERROR_WIN_TRANSACTION_MUST_WRITETHROUGH, + MD_ERROR_WIN_TRANSACTION_NO_SUPERIOR, + MD_ERROR_WIN_HEURISTIC_DAMAGE_POSSIBLE, + MD_ERROR_WIN_TRANSACTIONAL_CONFLICT, + MD_ERROR_WIN_RM_NOT_ACTIVE, + MD_ERROR_WIN_RM_METADATA_CORRUPT, + MD_ERROR_WIN_DIRECTORY_NOT_RM, + MD_ERROR_WIN_TRANSACTIONS_UNSUPPORTED_REMOTE, + MD_ERROR_WIN_LOG_RESIZE_INVALID_SIZE, + MD_ERROR_WIN_OBJECT_NO_LONGER_EXISTS, + MD_ERROR_WIN_STREAM_MINIVERSION_NOT_FOUND, + MD_ERROR_WIN_STREAM_MINIVERSION_NOT_VALID, + MD_ERROR_WIN_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION, + MD_ERROR_WIN_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT, + MD_ERROR_WIN_CANT_CREATE_MORE_STREAM_MINIVERSIONS, + MD_ERROR_WIN_REMOTE_FILE_VERSION_MISMATCH, + MD_ERROR_WIN_HANDLE_NO_LONGER_VALID, + MD_ERROR_WIN_NO_TXF_METADATA, + MD_ERROR_WIN_LOG_CORRUPTION_DETECTED, + MD_ERROR_WIN_CANT_RECOVER_WITH_HANDLE_OPEN, + MD_ERROR_WIN_RM_DISCONNECTED, + MD_ERROR_WIN_ENLISTMENT_NOT_SUPERIOR, + MD_ERROR_WIN_RECOVERY_NOT_NEEDED, + MD_ERROR_WIN_RM_ALREADY_STARTED, + MD_ERROR_WIN_FILE_IDENTITY_NOT_PERSISTENT, + MD_ERROR_WIN_CANT_BREAK_TRANSACTIONAL_DEPENDENCY, + MD_ERROR_WIN_CANT_CROSS_RM_BOUNDARY, + MD_ERROR_WIN_TXF_DIR_NOT_EMPTY, + MD_ERROR_WIN_INDOUBT_TRANSACTIONS_EXIST, + MD_ERROR_WIN_TM_VOLATILE, + MD_ERROR_WIN_ROLLBACK_TIMER_EXPIRED, + MD_ERROR_WIN_TXF_ATTRIBUTE_CORRUPT, + MD_ERROR_WIN_EFS_NOT_ALLOWED_IN_TRANSACTION, + MD_ERROR_WIN_TRANSACTIONAL_OPEN_NOT_ALLOWED, + MD_ERROR_WIN_LOG_GROWTH_FAILED, + MD_ERROR_WIN_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE, + MD_ERROR_WIN_TXF_METADATA_ALREADY_PRESENT, + MD_ERROR_WIN_TRANSACTION_SCOPE_CALLBACKS_NOT_SET, + MD_ERROR_WIN_TRANSACTION_REQUIRED_PROMOTION, + MD_ERROR_WIN_CANNOT_EXECUTE_FILE_IN_TRANSACTION, + MD_ERROR_WIN_TRANSACTIONS_NOT_FROZEN, + MD_ERROR_WIN_TRANSACTION_FREEZE_IN_PROGRESS, + MD_ERROR_WIN_NOT_SNAPSHOT_VOLUME, + MD_ERROR_WIN_NO_SAVEPOINT_WITH_OPEN_FILES, + MD_ERROR_WIN_DATA_LOST_REPAIR, + MD_ERROR_WIN_SPARSE_NOT_ALLOWED_IN_TRANSACTION, + MD_ERROR_WIN_TM_IDENTITY_MISMATCH, + MD_ERROR_WIN_FLOATED_SECTION, + MD_ERROR_WIN_CANNOT_ACCEPT_TRANSACTED_WORK, + MD_ERROR_WIN_CANNOT_ABORT_TRANSACTIONS, + MD_ERROR_WIN_BAD_CLUSTERS, + MD_ERROR_WIN_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION, + MD_ERROR_WIN_VOLUME_DIRTY, + MD_ERROR_WIN_NO_LINK_TRACKING_IN_TRANSACTION, + MD_ERROR_WIN_OPERATION_NOT_SUPPORTED_IN_TRANSACTION, + MD_ERROR_WIN_EXPIRED_HANDLE, + MD_ERROR_WIN_TRANSACTION_NOT_ENLISTED, + MD_ERROR_WIN_CTX_WINSTATION_NAME_INVALID, + MD_ERROR_WIN_CTX_INVALID_PD, + MD_ERROR_WIN_CTX_PD_NOT_FOUND, + MD_ERROR_WIN_CTX_WD_NOT_FOUND, + MD_ERROR_WIN_CTX_CANNOT_MAKE_EVENTLOG_ENTRY, + MD_ERROR_WIN_CTX_SERVICE_NAME_COLLISION, + MD_ERROR_WIN_CTX_CLOSE_PENDING, + MD_ERROR_WIN_CTX_NO_OUTBUF, + MD_ERROR_WIN_CTX_MODEM_INF_NOT_FOUND, + MD_ERROR_WIN_CTX_INVALID_MODEMNAME, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_ERROR, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_TIMEOUT, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_CARRIER, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_NO_DIALTONE, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_BUSY, + MD_ERROR_WIN_CTX_MODEM_RESPONSE_VOICE, + MD_ERROR_WIN_CTX_TD_ERROR, + MD_ERROR_WIN_CTX_WINSTATION_NOT_FOUND, + MD_ERROR_WIN_CTX_WINSTATION_ALREADY_EXISTS, + MD_ERROR_WIN_CTX_WINSTATION_BUSY, + MD_ERROR_WIN_CTX_BAD_VIDEO_MODE, + MD_ERROR_WIN_CTX_GRAPHICS_INVALID, + MD_ERROR_WIN_CTX_LOGON_DISABLED, + MD_ERROR_WIN_CTX_NOT_CONSOLE, + MD_ERROR_WIN_CTX_CLIENT_QUERY_TIMEOUT, + MD_ERROR_WIN_CTX_CONSOLE_DISCONNECT, + MD_ERROR_WIN_CTX_CONSOLE_CONNECT, + MD_ERROR_WIN_CTX_SHADOW_DENIED, + MD_ERROR_WIN_CTX_WINSTATION_ACCESS_DENIED, + MD_ERROR_WIN_CTX_INVALID_WD, + MD_ERROR_WIN_CTX_SHADOW_INVALID, + MD_ERROR_WIN_CTX_SHADOW_DISABLED, + MD_ERROR_WIN_CTX_CLIENT_LICENSE_IN_USE, + MD_ERROR_WIN_CTX_CLIENT_LICENSE_NOT_SET, + MD_ERROR_WIN_CTX_LICENSE_NOT_AVAILABLE, + MD_ERROR_WIN_CTX_LICENSE_CLIENT_INVALID, + MD_ERROR_WIN_CTX_LICENSE_EXPIRED, + MD_ERROR_WIN_CTX_SHADOW_NOT_RUNNING, + MD_ERROR_WIN_CTX_SHADOW_ENDED_BY_MODE_CHANGE, + MD_ERROR_WIN_ACTIVATION_COUNT_EXCEEDED, + MD_ERROR_WIN_CTX_WINSTATIONS_DISABLED, + MD_ERROR_WIN_CTX_ENCRYPTION_LEVEL_REQUIRED, + MD_ERROR_WIN_CTX_SESSION_IN_USE, + MD_ERROR_WIN_CTX_NO_FORCE_LOGOFF, + MD_ERROR_WIN_CTX_ACCOUNT_RESTRICTION, + MD_ERROR_WIN_RDP_PROTOCOL_ERROR, + MD_ERROR_WIN_CTX_CDM_CONNECT, + MD_ERROR_WIN_CTX_CDM_DISCONNECT, + MD_ERROR_WIN_CTX_SECURITY_LAYER_ERROR, + MD_ERROR_WIN_TS_INCOMPATIBLE_SESSIONS, + MD_ERROR_WIN_TS_VIDEO_SUBSYSTEM_ERROR, + MD_ERROR_WIN_DS_NOT_INSTALLED, + MD_ERROR_WIN_DS_MEMBERSHIP_EVALUATED_LOCALLY, + MD_ERROR_WIN_DS_NO_ATTRIBUTE_OR_VALUE, + MD_ERROR_WIN_DS_INVALID_ATTRIBUTE_SYNTAX, + MD_ERROR_WIN_DS_ATTRIBUTE_TYPE_UNDEFINED, + MD_ERROR_WIN_DS_ATTRIBUTE_OR_VALUE_EXISTS, + MD_ERROR_WIN_DS_BUSY, + MD_ERROR_WIN_DS_UNAVAILABLE, + MD_ERROR_WIN_DS_NO_RIDS_ALLOCATED, + MD_ERROR_WIN_DS_NO_MORE_RIDS, + MD_ERROR_WIN_DS_INCORRECT_ROLE_OWNER, + MD_ERROR_WIN_DS_RIDMGR_INIT_ERROR, + MD_ERROR_WIN_DS_OBJ_CLASS_VIOLATION, + MD_ERROR_WIN_DS_CANT_ON_NON_LEAF, + MD_ERROR_WIN_DS_CANT_ON_RDN, + MD_ERROR_WIN_DS_CANT_MOD_OBJ_CLASS, + MD_ERROR_WIN_DS_CROSS_DOM_MOVE_ERROR, + MD_ERROR_WIN_DS_GC_NOT_AVAILABLE, + MD_ERROR_WIN_SHARED_POLICY, + MD_ERROR_WIN_POLICY_OBJECT_NOT_FOUND, + MD_ERROR_WIN_POLICY_ONLY_IN_DS, + MD_ERROR_WIN_PROMOTION_ACTIVE, + MD_ERROR_WIN_NO_PROMOTION_ACTIVE, + MD_ERROR_WIN_DS_OPERATIONS_ERROR, + MD_ERROR_WIN_DS_PROTOCOL_ERROR, + MD_ERROR_WIN_DS_TIMELIMIT_EXCEEDED, + MD_ERROR_WIN_DS_SIZELIMIT_EXCEEDED, + MD_ERROR_WIN_DS_ADMIN_LIMIT_EXCEEDED, + MD_ERROR_WIN_DS_COMPARE_FALSE, + MD_ERROR_WIN_DS_COMPARE_TRUE, + MD_ERROR_WIN_DS_AUTH_METHOD_NOT_SUPPORTED, + MD_ERROR_WIN_DS_STRONG_AUTH_REQUIRED, + MD_ERROR_WIN_DS_INAPPROPRIATE_AUTH, + MD_ERROR_WIN_DS_AUTH_UNKNOWN, + MD_ERROR_WIN_DS_REFERRAL, + MD_ERROR_WIN_DS_UNAVAILABLE_CRIT_EXTENSION, + MD_ERROR_WIN_DS_CONFIDENTIALITY_REQUIRED, + MD_ERROR_WIN_DS_INAPPROPRIATE_MATCHING, + MD_ERROR_WIN_DS_CONSTRAINT_VIOLATION, + MD_ERROR_WIN_DS_NO_SUCH_OBJECT, + MD_ERROR_WIN_DS_ALIAS_PROBLEM, + MD_ERROR_WIN_DS_INVALID_DN_SYNTAX, + MD_ERROR_WIN_DS_IS_LEAF, + MD_ERROR_WIN_DS_ALIAS_DEREF_PROBLEM, + MD_ERROR_WIN_DS_UNWILLING_TO_PERFORM, + MD_ERROR_WIN_DS_LOOP_DETECT, + MD_ERROR_WIN_DS_NAMING_VIOLATION, + MD_ERROR_WIN_DS_OBJECT_RESULTS_TOO_LARGE, + MD_ERROR_WIN_DS_AFFECTS_MULTIPLE_DSAS, + MD_ERROR_WIN_DS_SERVER_DOWN, + MD_ERROR_WIN_DS_LOCAL_ERROR, + MD_ERROR_WIN_DS_ENCODING_ERROR, + MD_ERROR_WIN_DS_DECODING_ERROR, + MD_ERROR_WIN_DS_FILTER_UNKNOWN, + MD_ERROR_WIN_DS_PARAM_ERROR, + MD_ERROR_WIN_DS_NOT_SUPPORTED, + MD_ERROR_WIN_DS_NO_RESULTS_RETURNED, + MD_ERROR_WIN_DS_CONTROL_NOT_FOUND, + MD_ERROR_WIN_DS_CLIENT_LOOP, + MD_ERROR_WIN_DS_REFERRAL_LIMIT_EXCEEDED, + MD_ERROR_WIN_DS_SORT_CONTROL_MISSING, + MD_ERROR_WIN_DS_OFFSET_RANGE_ERROR, + MD_ERROR_WIN_DS_RIDMGR_DISABLED, + MD_ERROR_WIN_DS_ROOT_MUST_BE_NC, + MD_ERROR_WIN_DS_ADD_REPLICA_INHIBITED, + MD_ERROR_WIN_DS_ATT_NOT_DEF_IN_SCHEMA, + MD_ERROR_WIN_DS_MAX_OBJ_SIZE_EXCEEDED, + MD_ERROR_WIN_DS_OBJ_STRING_NAME_EXISTS, + MD_ERROR_WIN_DS_NO_RDN_DEFINED_IN_SCHEMA, + MD_ERROR_WIN_DS_RDN_DOESNT_MATCH_SCHEMA, + MD_ERROR_WIN_DS_NO_REQUESTED_ATTS_FOUND, + MD_ERROR_WIN_DS_USER_BUFFER_TO_SMALL, + MD_ERROR_WIN_DS_ATT_IS_NOT_ON_OBJ, + MD_ERROR_WIN_DS_ILLEGAL_MOD_OPERATION, + MD_ERROR_WIN_DS_OBJ_TOO_LARGE, + MD_ERROR_WIN_DS_BAD_INSTANCE_TYPE, + MD_ERROR_WIN_DS_MASTERDSA_REQUIRED, + MD_ERROR_WIN_DS_OBJECT_CLASS_REQUIRED, + MD_ERROR_WIN_DS_MISSING_REQUIRED_ATT, + MD_ERROR_WIN_DS_ATT_NOT_DEF_FOR_CLASS, + MD_ERROR_WIN_DS_ATT_ALREADY_EXISTS, + MD_ERROR_WIN_DS_CANT_ADD_ATT_VALUES, + MD_ERROR_WIN_DS_SINGLE_VALUE_CONSTRAINT, + MD_ERROR_WIN_DS_RANGE_CONSTRAINT, + MD_ERROR_WIN_DS_ATT_VAL_ALREADY_EXISTS, + MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT, + MD_ERROR_WIN_DS_CANT_REM_MISSING_ATT_VAL, + MD_ERROR_WIN_DS_ROOT_CANT_BE_SUBREF, + MD_ERROR_WIN_DS_NO_CHAINING, + MD_ERROR_WIN_DS_NO_CHAINED_EVAL, + MD_ERROR_WIN_DS_NO_PARENT_OBJECT, + MD_ERROR_WIN_DS_PARENT_IS_AN_ALIAS, + MD_ERROR_WIN_DS_CANT_MIX_MASTER_AND_REPS, + MD_ERROR_WIN_DS_CHILDREN_EXIST, + MD_ERROR_WIN_DS_OBJ_NOT_FOUND, + MD_ERROR_WIN_DS_ALIASED_OBJ_MISSING, + MD_ERROR_WIN_DS_BAD_NAME_SYNTAX, + MD_ERROR_WIN_DS_ALIAS_POINTS_TO_ALIAS, + MD_ERROR_WIN_DS_CANT_DEREF_ALIAS, + MD_ERROR_WIN_DS_OUT_OF_SCOPE, + MD_ERROR_WIN_DS_OBJECT_BEING_REMOVED, + MD_ERROR_WIN_DS_CANT_DELETE_DSA_OBJ, + MD_ERROR_WIN_DS_GENERIC_ERROR, + MD_ERROR_WIN_DS_DSA_MUST_BE_INT_MASTER, + MD_ERROR_WIN_DS_CLASS_NOT_DSA, + MD_ERROR_WIN_DS_INSUFF_ACCESS_RIGHTS, + MD_ERROR_WIN_DS_ILLEGAL_SUPERIOR, + MD_ERROR_WIN_DS_ATTRIBUTE_OWNED_BY_SAM, + MD_ERROR_WIN_DS_NAME_TOO_MANY_PARTS, + MD_ERROR_WIN_DS_NAME_TOO_LONG, + MD_ERROR_WIN_DS_NAME_VALUE_TOO_LONG, + MD_ERROR_WIN_DS_NAME_UNPARSEABLE, + MD_ERROR_WIN_DS_NAME_TYPE_UNKNOWN, + MD_ERROR_WIN_DS_NOT_AN_OBJECT, + MD_ERROR_WIN_DS_SEC_DESC_TOO_SHORT, + MD_ERROR_WIN_DS_SEC_DESC_INVALID, + MD_ERROR_WIN_DS_NO_DELETED_NAME, + MD_ERROR_WIN_DS_SUBREF_MUST_HAVE_PARENT, + MD_ERROR_WIN_DS_NCNAME_MUST_BE_NC, + MD_ERROR_WIN_DS_CANT_ADD_SYSTEM_ONLY, + MD_ERROR_WIN_DS_CLASS_MUST_BE_CONCRETE, + MD_ERROR_WIN_DS_INVALID_DMD, + MD_ERROR_WIN_DS_OBJ_GUID_EXISTS, + MD_ERROR_WIN_DS_NOT_ON_BACKLINK, + MD_ERROR_WIN_DS_NO_CROSSREF_FOR_NC, + MD_ERROR_WIN_DS_SHUTTING_DOWN, + MD_ERROR_WIN_DS_UNKNOWN_OPERATION, + MD_ERROR_WIN_DS_INVALID_ROLE_OWNER, + MD_ERROR_WIN_DS_COULDNT_CONTACT_FSMO, + MD_ERROR_WIN_DS_CROSS_NC_DN_RENAME, + MD_ERROR_WIN_DS_CANT_MOD_SYSTEM_ONLY, + MD_ERROR_WIN_DS_REPLICATOR_ONLY, + MD_ERROR_WIN_DS_OBJ_CLASS_NOT_DEFINED, + MD_ERROR_WIN_DS_OBJ_CLASS_NOT_SUBCLASS, + MD_ERROR_WIN_DS_NAME_REFERENCE_INVALID, + MD_ERROR_WIN_DS_CROSS_REF_EXISTS, + MD_ERROR_WIN_DS_CANT_DEL_MASTER_CROSSREF, + MD_ERROR_WIN_DS_SUBTREE_NOTIFY_NOT_NC_HEAD, + MD_ERROR_WIN_DS_NOTIFY_FILTER_TOO_COMPLEX, + MD_ERROR_WIN_DS_DUP_RDN, + MD_ERROR_WIN_DS_DUP_OID, + MD_ERROR_WIN_DS_DUP_MAPI_ID, + MD_ERROR_WIN_DS_DUP_SCHEMA_ID_GUID, + MD_ERROR_WIN_DS_DUP_LDAP_DISPLAY_NAME, + MD_ERROR_WIN_DS_SEMANTIC_ATT_TEST, + MD_ERROR_WIN_DS_SYNTAX_MISMATCH, + MD_ERROR_WIN_DS_EXISTS_IN_MUST_HAVE, + MD_ERROR_WIN_DS_EXISTS_IN_MAY_HAVE, + MD_ERROR_WIN_DS_NONEXISTENT_MAY_HAVE, + MD_ERROR_WIN_DS_NONEXISTENT_MUST_HAVE, + MD_ERROR_WIN_DS_AUX_CLS_TEST_FAIL, + MD_ERROR_WIN_DS_NONEXISTENT_POSS_SUP, + MD_ERROR_WIN_DS_SUB_CLS_TEST_FAIL, + MD_ERROR_WIN_DS_BAD_RDN_ATT_ID_SYNTAX, + MD_ERROR_WIN_DS_EXISTS_IN_AUX_CLS, + MD_ERROR_WIN_DS_EXISTS_IN_SUB_CLS, + MD_ERROR_WIN_DS_EXISTS_IN_POSS_SUP, + MD_ERROR_WIN_DS_RECALCSCHEMA_FAILED, + MD_ERROR_WIN_DS_TREE_DELETE_NOT_FINISHED, + MD_ERROR_WIN_DS_CANT_DELETE, + MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_ID, + MD_ERROR_WIN_DS_BAD_ATT_SCHEMA_SYNTAX, + MD_ERROR_WIN_DS_CANT_CACHE_ATT, + MD_ERROR_WIN_DS_CANT_CACHE_CLASS, + MD_ERROR_WIN_DS_CANT_REMOVE_ATT_CACHE, + MD_ERROR_WIN_DS_CANT_REMOVE_CLASS_CACHE, + MD_ERROR_WIN_DS_CANT_RETRIEVE_DN, + MD_ERROR_WIN_DS_MISSING_SUPREF, + MD_ERROR_WIN_DS_CANT_RETRIEVE_INSTANCE, + MD_ERROR_WIN_DS_CODE_INCONSISTENCY, + MD_ERROR_WIN_DS_DATABASE_ERROR, + MD_ERROR_WIN_DS_GOVERNSID_MISSING, + MD_ERROR_WIN_DS_MISSING_EXPECTED_ATT, + MD_ERROR_WIN_DS_NCNAME_MISSING_CR_REF, + MD_ERROR_WIN_DS_SECURITY_CHECKING_ERROR, + MD_ERROR_WIN_DS_SCHEMA_NOT_LOADED, + MD_ERROR_WIN_DS_SCHEMA_ALLOC_FAILED, + MD_ERROR_WIN_DS_ATT_SCHEMA_REQ_SYNTAX, + MD_ERROR_WIN_DS_GCVERIFY_ERROR, + MD_ERROR_WIN_DS_DRA_SCHEMA_MISMATCH, + MD_ERROR_WIN_DS_CANT_FIND_DSA_OBJ, + MD_ERROR_WIN_DS_CANT_FIND_EXPECTED_NC, + MD_ERROR_WIN_DS_CANT_FIND_NC_IN_CACHE, + MD_ERROR_WIN_DS_CANT_RETRIEVE_CHILD, + MD_ERROR_WIN_DS_SECURITY_ILLEGAL_MODIFY, + MD_ERROR_WIN_DS_CANT_REPLACE_HIDDEN_REC, + MD_ERROR_WIN_DS_BAD_HIERARCHY_FILE, + MD_ERROR_WIN_DS_BUILD_HIERARCHY_TABLE_FAILED, + MD_ERROR_WIN_DS_CONFIG_PARAM_MISSING, + MD_ERROR_WIN_DS_COUNTING_AB_INDICES_FAILED, + MD_ERROR_WIN_DS_HIERARCHY_TABLE_MALLOC_FAILED, + MD_ERROR_WIN_DS_INTERNAL_FAILURE, + MD_ERROR_WIN_DS_UNKNOWN_ERROR, + MD_ERROR_WIN_DS_ROOT_REQUIRES_CLASS_TOP, + MD_ERROR_WIN_DS_REFUSING_FSMO_ROLES, + MD_ERROR_WIN_DS_MISSING_FSMO_SETTINGS, + MD_ERROR_WIN_DS_UNABLE_TO_SURRENDER_ROLES, + MD_ERROR_WIN_DS_DRA_GENERIC, + MD_ERROR_WIN_DS_DRA_INVALID_PARAMETER, + MD_ERROR_WIN_DS_DRA_BUSY, + MD_ERROR_WIN_DS_DRA_BAD_DN, + MD_ERROR_WIN_DS_DRA_BAD_NC, + MD_ERROR_WIN_DS_DRA_DN_EXISTS, + MD_ERROR_WIN_DS_DRA_INTERNAL_ERROR, + MD_ERROR_WIN_DS_DRA_INCONSISTENT_DIT, + MD_ERROR_WIN_DS_DRA_CONNECTION_FAILED, + MD_ERROR_WIN_DS_DRA_BAD_INSTANCE_TYPE, + MD_ERROR_WIN_DS_DRA_OUT_OF_MEM, + MD_ERROR_WIN_DS_DRA_MAIL_PROBLEM, + MD_ERROR_WIN_DS_DRA_REF_ALREADY_EXISTS, + MD_ERROR_WIN_DS_DRA_REF_NOT_FOUND, + MD_ERROR_WIN_DS_DRA_OBJ_IS_REP_SOURCE, + MD_ERROR_WIN_DS_DRA_DB_ERROR, + MD_ERROR_WIN_DS_DRA_NO_REPLICA, + MD_ERROR_WIN_DS_DRA_ACCESS_DENIED, + MD_ERROR_WIN_DS_DRA_NOT_SUPPORTED, + MD_ERROR_WIN_DS_DRA_RPC_CANCELLED, + MD_ERROR_WIN_DS_DRA_SOURCE_DISABLED, + MD_ERROR_WIN_DS_DRA_SINK_DISABLED, + MD_ERROR_WIN_DS_DRA_NAME_COLLISION, + MD_ERROR_WIN_DS_DRA_SOURCE_REINSTALLED, + MD_ERROR_WIN_DS_DRA_MISSING_PARENT, + MD_ERROR_WIN_DS_DRA_PREEMPTED, + MD_ERROR_WIN_DS_DRA_ABANDON_SYNC, + MD_ERROR_WIN_DS_DRA_SHUTDOWN, + MD_ERROR_WIN_DS_DRA_INCOMPATIBLE_PARTIAL_SET, + MD_ERROR_WIN_DS_DRA_SOURCE_IS_PARTIAL_REPLICA, + MD_ERROR_WIN_DS_DRA_EXTN_CONNECTION_FAILED, + MD_ERROR_WIN_DS_INSTALL_SCHEMA_MISMATCH, + MD_ERROR_WIN_DS_DUP_LINK_ID, + MD_ERROR_WIN_DS_NAME_ERROR_RESOLVING, + MD_ERROR_WIN_DS_NAME_ERROR_NOT_FOUND, + MD_ERROR_WIN_DS_NAME_ERROR_NOT_UNIQUE, + MD_ERROR_WIN_DS_NAME_ERROR_NO_MAPPING, + MD_ERROR_WIN_DS_NAME_ERROR_DOMAIN_ONLY, + MD_ERROR_WIN_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING, + MD_ERROR_WIN_DS_CONSTRUCTED_ATT_MOD, + MD_ERROR_WIN_DS_WRONG_OM_OBJ_CLASS, + MD_ERROR_WIN_DS_DRA_REPL_PENDING, + MD_ERROR_WIN_DS_DS_REQUIRED, + MD_ERROR_WIN_DS_INVALID_LDAP_DISPLAY_NAME, + MD_ERROR_WIN_DS_NON_BASE_SEARCH, + MD_ERROR_WIN_DS_CANT_RETRIEVE_ATTS, + MD_ERROR_WIN_DS_BACKLINK_WITHOUT_LINK, + MD_ERROR_WIN_DS_EPOCH_MISMATCH, + MD_ERROR_WIN_DS_SRC_NAME_MISMATCH, + MD_ERROR_WIN_DS_SRC_AND_DST_NC_IDENTICAL, + MD_ERROR_WIN_DS_DST_NC_MISMATCH, + MD_ERROR_WIN_DS_NOT_AUTHORITIVE_FOR_DST_NC, + MD_ERROR_WIN_DS_SRC_GUID_MISMATCH, + MD_ERROR_WIN_DS_CANT_MOVE_DELETED_OBJECT, + MD_ERROR_WIN_DS_PDC_OPERATION_IN_PROGRESS, + MD_ERROR_WIN_DS_CROSS_DOMAIN_CLEANUP_REQD, + MD_ERROR_WIN_DS_ILLEGAL_XDOM_MOVE_OPERATION, + MD_ERROR_WIN_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS, + MD_ERROR_WIN_DS_NC_MUST_HAVE_NC_PARENT, + MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE, + MD_ERROR_WIN_DS_DST_DOMAIN_NOT_NATIVE, + MD_ERROR_WIN_DS_MISSING_INFRASTRUCTURE_CONTAINER, + MD_ERROR_WIN_DS_CANT_MOVE_ACCOUNT_GROUP, + MD_ERROR_WIN_DS_CANT_MOVE_RESOURCE_GROUP, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG, + MD_ERROR_WIN_DS_NO_TREE_DELETE_ABOVE_NC, + MD_ERROR_WIN_DS_COULDNT_LOCK_TREE_FOR_DELETE, + MD_ERROR_WIN_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE, + MD_ERROR_WIN_DS_SAM_INIT_FAILURE, + MD_ERROR_WIN_DS_SENSITIVE_GROUP_VIOLATION, + MD_ERROR_WIN_DS_CANT_MOD_PRIMARYGROUPID, + MD_ERROR_WIN_DS_ILLEGAL_BASE_SCHEMA_MOD, + MD_ERROR_WIN_DS_NONSAFE_SCHEMA_CHANGE, + MD_ERROR_WIN_DS_SCHEMA_UPDATE_DISALLOWED, + MD_ERROR_WIN_DS_CANT_CREATE_UNDER_SCHEMA, + MD_ERROR_WIN_DS_INSTALL_NO_SRC_SCH_VERSION, + MD_ERROR_WIN_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE, + MD_ERROR_WIN_DS_INVALID_GROUP_TYPE, + MD_ERROR_WIN_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN, + MD_ERROR_WIN_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER, + MD_ERROR_WIN_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER, + MD_ERROR_WIN_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER, + MD_ERROR_WIN_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER, + MD_ERROR_WIN_DS_HAVE_PRIMARY_MEMBERS, + MD_ERROR_WIN_DS_STRING_SD_CONVERSION_FAILED, + MD_ERROR_WIN_DS_NAMING_MASTER_GC, + MD_ERROR_WIN_DS_DNS_LOOKUP_FAILURE, + MD_ERROR_WIN_DS_COULDNT_UPDATE_SPNS, + MD_ERROR_WIN_DS_CANT_RETRIEVE_SD, + MD_ERROR_WIN_DS_KEY_NOT_UNIQUE, + MD_ERROR_WIN_DS_WRONG_LINKED_ATT_SYNTAX, + MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_PASSWORD, + MD_ERROR_WIN_DS_SAM_NEED_BOOTKEY_FLOPPY, + MD_ERROR_WIN_DS_CANT_START, + MD_ERROR_WIN_DS_INIT_FAILURE, + MD_ERROR_WIN_DS_NO_PKT_PRIVACY_ON_CONNECTION, + MD_ERROR_WIN_DS_SOURCE_DOMAIN_IN_FOREST, + MD_ERROR_WIN_DS_DESTINATION_DOMAIN_NOT_IN_FOREST, + MD_ERROR_WIN_DS_DESTINATION_AUDITING_NOT_ENABLED, + MD_ERROR_WIN_DS_CANT_FIND_DC_FOR_SRC_DOMAIN, + MD_ERROR_WIN_DS_SRC_OBJ_NOT_GROUP_OR_USER, + MD_ERROR_WIN_DS_SRC_SID_EXISTS_IN_FOREST, + MD_ERROR_WIN_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH, + MD_ERROR_WIN_SAM_INIT_FAILURE, + MD_ERROR_WIN_DS_DRA_SCHEMA_INFO_SHIP, + MD_ERROR_WIN_DS_DRA_SCHEMA_CONFLICT, + MD_ERROR_WIN_DS_DRA_EARLIER_SCHEMA_CONFLICT, + MD_ERROR_WIN_DS_DRA_OBJ_NC_MISMATCH, + MD_ERROR_WIN_DS_NC_STILL_HAS_DSAS, + MD_ERROR_WIN_DS_GC_REQUIRED, + MD_ERROR_WIN_DS_LOCAL_MEMBER_OF_LOCAL_ONLY, + MD_ERROR_WIN_DS_NO_FPO_IN_UNIVERSAL_GROUPS, + MD_ERROR_WIN_DS_CANT_ADD_TO_GC, + MD_ERROR_WIN_DS_NO_CHECKPOINT_WITH_PDC, + MD_ERROR_WIN_DS_SOURCE_AUDITING_NOT_ENABLED, + MD_ERROR_WIN_DS_CANT_CREATE_IN_NONDOMAIN_NC, + MD_ERROR_WIN_DS_INVALID_NAME_FOR_SPN, + MD_ERROR_WIN_DS_FILTER_USES_CONTRUCTED_ATTRS, + MD_ERROR_WIN_DS_UNICODEPWD_NOT_IN_QUOTES, + MD_ERROR_WIN_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED, + MD_ERROR_WIN_DS_MUST_BE_RUN_ON_DST_DC, + MD_ERROR_WIN_DS_SRC_DC_MUST_BE_SP4_OR_GREATER, + MD_ERROR_WIN_DS_CANT_TREE_DELETE_CRITICAL_OBJ, + MD_ERROR_WIN_DS_INIT_FAILURE_CONSOLE, + MD_ERROR_WIN_DS_SAM_INIT_FAILURE_CONSOLE, + MD_ERROR_WIN_DS_FOREST_VERSION_TOO_HIGH, + MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_HIGH, + MD_ERROR_WIN_DS_FOREST_VERSION_TOO_LOW, + MD_ERROR_WIN_DS_DOMAIN_VERSION_TOO_LOW, + MD_ERROR_WIN_DS_INCOMPATIBLE_VERSION, + MD_ERROR_WIN_DS_LOW_DSA_VERSION, + MD_ERROR_WIN_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN, + MD_ERROR_WIN_DS_NOT_SUPPORTED_SORT_ORDER, + MD_ERROR_WIN_DS_NAME_NOT_UNIQUE, + MD_ERROR_WIN_DS_MACHINE_ACCOUNT_CREATED_PRENT4, + MD_ERROR_WIN_DS_OUT_OF_VERSION_STORE, + MD_ERROR_WIN_DS_INCOMPATIBLE_CONTROLS_USED, + MD_ERROR_WIN_DS_NO_REF_DOMAIN, + MD_ERROR_WIN_DS_RESERVED_LINK_ID, + MD_ERROR_WIN_DS_LINK_ID_NOT_AVAILABLE, + MD_ERROR_WIN_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER, + MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE, + MD_ERROR_WIN_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC, + MD_ERROR_WIN_DS_MODIFYDN_DISALLOWED_BY_FLAG, + MD_ERROR_WIN_DS_MODIFYDN_WRONG_GRANDPARENT, + MD_ERROR_WIN_DS_NAME_ERROR_TRUST_REFERRAL, + MD_ERROR_WIN_NOT_SUPPORTED_ON_STANDARD_SERVER, + MD_ERROR_WIN_DS_CANT_ACCESS_REMOTE_PART_OF_AD, + MD_ERROR_WIN_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2, + MD_ERROR_WIN_DS_THREAD_LIMIT_EXCEEDED, + MD_ERROR_WIN_DS_NOT_CLOSEST, + MD_ERROR_WIN_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF, + MD_ERROR_WIN_DS_SINGLE_USER_MODE_FAILED, + MD_ERROR_WIN_DS_NTDSCRIPT_SYNTAX_ERROR, + MD_ERROR_WIN_DS_NTDSCRIPT_PROCESS_ERROR, + MD_ERROR_WIN_DS_DIFFERENT_REPL_EPOCHS, + MD_ERROR_WIN_DS_DRS_EXTENSIONS_CHANGED, + MD_ERROR_WIN_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR, + MD_ERROR_WIN_DS_NO_MSDS_INTID, + MD_ERROR_WIN_DS_DUP_MSDS_INTID, + MD_ERROR_WIN_DS_EXISTS_IN_RDNATTID, + MD_ERROR_WIN_DS_AUTHORIZATION_FAILED, + MD_ERROR_WIN_DS_INVALID_SCRIPT, + MD_ERROR_WIN_DS_REMOTE_CROSSREF_OP_FAILED, + MD_ERROR_WIN_DS_CROSS_REF_BUSY, + MD_ERROR_WIN_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN, + MD_ERROR_WIN_DS_CANT_DEMOTE_WITH_WRITEABLE_NC, + MD_ERROR_WIN_DS_DUPLICATE_ID_FOUND, + MD_ERROR_WIN_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT, + MD_ERROR_WIN_DS_GROUP_CONVERSION_ERROR, + MD_ERROR_WIN_DS_CANT_MOVE_APP_BASIC_GROUP, + MD_ERROR_WIN_DS_CANT_MOVE_APP_QUERY_GROUP, + MD_ERROR_WIN_DS_ROLE_NOT_VERIFIED, + MD_ERROR_WIN_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL, + MD_ERROR_WIN_DS_DOMAIN_RENAME_IN_PROGRESS, + MD_ERROR_WIN_DS_EXISTING_AD_CHILD_NC, + MD_ERROR_WIN_DS_REPL_LIFETIME_EXCEEDED, + MD_ERROR_WIN_DS_DISALLOWED_IN_SYSTEM_CONTAINER, + MD_ERROR_WIN_DS_LDAP_SEND_QUEUE_FULL, + MD_ERROR_WIN_DS_DRA_OUT_SCHEDULE_WINDOW, + MD_ERROR_WIN_DS_POLICY_NOT_KNOWN, + MD_ERROR_WIN_NO_SITE_SETTINGS_OBJECT, + MD_ERROR_WIN_NO_SECRETS, + MD_ERROR_WIN_NO_WRITABLE_DC_FOUND, + MD_ERROR_WIN_DS_NO_SERVER_OBJECT, + MD_ERROR_WIN_DS_NO_NTDSA_OBJECT, + MD_ERROR_WIN_DS_NON_ASQ_SEARCH, + MD_ERROR_WIN_DS_AUDIT_FAILURE, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_SUBTREE, + MD_ERROR_WIN_DS_INVALID_SEARCH_FLAG_TUPLE, + MD_ERROR_WIN_DS_HIERARCHY_TABLE_TOO_DEEP, + MD_ERROR_WIN_DS_DRA_CORRUPT_UTD_VECTOR, + MD_ERROR_WIN_DS_DRA_SECRETS_DENIED, + MD_ERROR_WIN_DS_RESERVED_MAPI_ID, + MD_ERROR_WIN_DS_MAPI_ID_NOT_AVAILABLE, + MD_ERROR_WIN_DS_DRA_MISSING_KRBTGT_SECRET, + MD_ERROR_WIN_DS_DOMAIN_NAME_EXISTS_IN_FOREST, + MD_ERROR_WIN_DS_FLAT_NAME_EXISTS_IN_FOREST, + MD_ERROR_WIN_INVALID_USER_PRINCIPAL_NAME, + MD_ERROR_WIN_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS, + MD_ERROR_WIN_DS_OID_NOT_FOUND, + MD_ERROR_WIN_DS_DRA_RECYCLED_TARGET, + MD_ERROR_WIN_DS_DISALLOWED_NC_REDIRECT, + MD_ERROR_WIN_DS_HIGH_ADLDS_FFL, + MD_ERROR_WIN_DS_HIGH_DSA_VERSION, + MD_ERROR_WIN_DS_LOW_ADLDS_FFL, + MD_ERROR_WIN_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION, + MD_ERROR_WIN_DS_UNDELETE_SAM_VALIDATION_FAILED, + MD_ERROR_WIN_INCORRECT_ACCOUNT_TYPE, + MD_ERROR_WIN_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST, + MD_ERROR_WIN_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST, + MD_ERROR_WIN_DS_MISSING_FOREST_TRUST, + MD_ERROR_WIN_DS_VALUE_KEY_NOT_UNIQUE, + MD_ERROR_WIN_IPSEC_QM_POLICY_EXISTS, + MD_ERROR_WIN_IPSEC_QM_POLICY_NOT_FOUND, + MD_ERROR_WIN_IPSEC_QM_POLICY_IN_USE, + MD_ERROR_WIN_IPSEC_MM_POLICY_EXISTS, + MD_ERROR_WIN_IPSEC_MM_POLICY_NOT_FOUND, + MD_ERROR_WIN_IPSEC_MM_POLICY_IN_USE, + MD_ERROR_WIN_IPSEC_MM_FILTER_EXISTS, + MD_ERROR_WIN_IPSEC_MM_FILTER_NOT_FOUND, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_EXISTS, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_NOT_FOUND, + MD_ERROR_WIN_IPSEC_MM_AUTH_EXISTS, + MD_ERROR_WIN_IPSEC_MM_AUTH_NOT_FOUND, + MD_ERROR_WIN_IPSEC_MM_AUTH_IN_USE, + MD_ERROR_WIN_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND, + MD_ERROR_WIN_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND, + MD_ERROR_WIN_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_EXISTS, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_NOT_FOUND, + MD_ERROR_WIN_IPSEC_MM_FILTER_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_TRANSPORT_FILTER_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_TUNNEL_FILTER_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_MM_POLICY_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_MM_AUTH_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_QM_POLICY_PENDING_DELETION, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_BEGIN, + MD_ERROR_WIN_IPSEC_IKE_AUTH_FAIL, + MD_ERROR_WIN_IPSEC_IKE_ATTRIB_FAIL, + MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_PENDING, + MD_ERROR_WIN_IPSEC_IKE_GENERAL_PROCESSING_ERROR, + MD_ERROR_WIN_IPSEC_IKE_TIMED_OUT, + MD_ERROR_WIN_IPSEC_IKE_NO_CERT, + MD_ERROR_WIN_IPSEC_IKE_SA_DELETED, + MD_ERROR_WIN_IPSEC_IKE_SA_REAPED, + MD_ERROR_WIN_IPSEC_IKE_MM_ACQUIRE_DROP, + MD_ERROR_WIN_IPSEC_IKE_QM_ACQUIRE_DROP, + MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_MM, + MD_ERROR_WIN_IPSEC_IKE_QUEUE_DROP_NO_MM, + MD_ERROR_WIN_IPSEC_IKE_DROP_NO_RESPONSE, + MD_ERROR_WIN_IPSEC_IKE_MM_DELAY_DROP, + MD_ERROR_WIN_IPSEC_IKE_QM_DELAY_DROP, + MD_ERROR_WIN_IPSEC_IKE_ERROR, + MD_ERROR_WIN_IPSEC_IKE_CRL_FAILED, + MD_ERROR_WIN_IPSEC_IKE_INVALID_KEY_USAGE, + MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_TYPE, + MD_ERROR_WIN_IPSEC_IKE_NO_PRIVATE_KEY, + MD_ERROR_WIN_IPSEC_IKE_SIMULTANEOUS_REKEY, + MD_ERROR_WIN_IPSEC_IKE_DH_FAIL, + MD_ERROR_WIN_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HEADER, + MD_ERROR_WIN_IPSEC_IKE_NO_POLICY, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SIGNATURE, + MD_ERROR_WIN_IPSEC_IKE_KERBEROS_ERROR, + MD_ERROR_WIN_IPSEC_IKE_NO_PUBLIC_KEY, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SA, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_PROP, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_TRANS, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_KE, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_ID, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_CERT_REQ, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_HASH, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_SIG, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NONCE, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NOTIFY, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_DELETE, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_VENDOR, + MD_ERROR_WIN_IPSEC_IKE_INVALID_PAYLOAD, + MD_ERROR_WIN_IPSEC_IKE_LOAD_SOFT_SA, + MD_ERROR_WIN_IPSEC_IKE_SOFT_SA_TORN_DOWN, + MD_ERROR_WIN_IPSEC_IKE_INVALID_COOKIE, + MD_ERROR_WIN_IPSEC_IKE_NO_PEER_CERT, + MD_ERROR_WIN_IPSEC_IKE_PEER_CRL_FAILED, + MD_ERROR_WIN_IPSEC_IKE_POLICY_CHANGE, + MD_ERROR_WIN_IPSEC_IKE_NO_MM_POLICY, + MD_ERROR_WIN_IPSEC_IKE_NOTCBPRIV, + MD_ERROR_WIN_IPSEC_IKE_SECLOADFAIL, + MD_ERROR_WIN_IPSEC_IKE_FAILSSPINIT, + MD_ERROR_WIN_IPSEC_IKE_FAILQUERYSSP, + MD_ERROR_WIN_IPSEC_IKE_SRVACQFAIL, + MD_ERROR_WIN_IPSEC_IKE_SRVQUERYCRED, + MD_ERROR_WIN_IPSEC_IKE_GETSPIFAIL, + MD_ERROR_WIN_IPSEC_IKE_INVALID_FILTER, + MD_ERROR_WIN_IPSEC_IKE_OUT_OF_MEMORY, + MD_ERROR_WIN_IPSEC_IKE_ADD_UPDATE_KEY_FAILED, + MD_ERROR_WIN_IPSEC_IKE_INVALID_POLICY, + MD_ERROR_WIN_IPSEC_IKE_UNKNOWN_DOI, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SITUATION, + MD_ERROR_WIN_IPSEC_IKE_DH_FAILURE, + MD_ERROR_WIN_IPSEC_IKE_INVALID_GROUP, + MD_ERROR_WIN_IPSEC_IKE_ENCRYPT, + MD_ERROR_WIN_IPSEC_IKE_DECRYPT, + MD_ERROR_WIN_IPSEC_IKE_POLICY_MATCH, + MD_ERROR_WIN_IPSEC_IKE_UNSUPPORTED_ID, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_ALG, + MD_ERROR_WIN_IPSEC_IKE_INVALID_HASH_SIZE, + MD_ERROR_WIN_IPSEC_IKE_INVALID_ENCRYPT_ALG, + MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_ALG, + MD_ERROR_WIN_IPSEC_IKE_INVALID_SIG, + MD_ERROR_WIN_IPSEC_IKE_LOAD_FAILED, + MD_ERROR_WIN_IPSEC_IKE_RPC_DELETE, + MD_ERROR_WIN_IPSEC_IKE_BENIGN_REINIT, + MD_ERROR_WIN_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY, + MD_ERROR_WIN_IPSEC_IKE_INVALID_MAJOR_VERSION, + MD_ERROR_WIN_IPSEC_IKE_INVALID_CERT_KEYLEN, + MD_ERROR_WIN_IPSEC_IKE_MM_LIMIT, + MD_ERROR_WIN_IPSEC_IKE_NEGOTIATION_DISABLED, + MD_ERROR_WIN_IPSEC_IKE_QM_LIMIT, + MD_ERROR_WIN_IPSEC_IKE_MM_EXPIRED, + MD_ERROR_WIN_IPSEC_IKE_PEER_MM_ASSUMED_INVALID, + MD_ERROR_WIN_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH, + MD_ERROR_WIN_IPSEC_IKE_UNEXPECTED_MESSAGE_ID, + MD_ERROR_WIN_IPSEC_IKE_INVALID_AUTH_PAYLOAD, + MD_ERROR_WIN_IPSEC_IKE_DOS_COOKIE_SENT, + MD_ERROR_WIN_IPSEC_IKE_SHUTTING_DOWN, + MD_ERROR_WIN_IPSEC_IKE_CGA_AUTH_FAILED, + MD_ERROR_WIN_IPSEC_IKE_PROCESS_ERR_NATOA, + MD_ERROR_WIN_IPSEC_IKE_INVALID_MM_FOR_QM, + MD_ERROR_WIN_IPSEC_IKE_QM_EXPIRED, + MD_ERROR_WIN_IPSEC_IKE_TOO_MANY_FILTERS, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_END, + MD_ERROR_WIN_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL, + MD_ERROR_WIN_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE, + MD_ERROR_WIN_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING, + MD_ERROR_WIN_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING, + MD_ERROR_WIN_IPSEC_IKE_COEXISTENCE_SUPPRESS, + MD_ERROR_WIN_IPSEC_IKE_RATELIMIT_DROP, + MD_ERROR_WIN_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE, + MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE, + MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE, + MD_ERROR_WIN_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY, + MD_ERROR_WIN_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE, + MD_ERROR_WIN_IPSEC_IKE_NEG_STATUS_EXTENDED_END, + MD_ERROR_WIN_IPSEC_BAD_SPI, + MD_ERROR_WIN_IPSEC_SA_LIFETIME_EXPIRED, + MD_ERROR_WIN_IPSEC_WRONG_SA, + MD_ERROR_WIN_IPSEC_REPLAY_CHECK_FAILED, + MD_ERROR_WIN_IPSEC_INVALID_PACKET, + MD_ERROR_WIN_IPSEC_INTEGRITY_CHECK_FAILED, + MD_ERROR_WIN_IPSEC_CLEAR_TEXT_DROP, + MD_ERROR_WIN_IPSEC_AUTH_FIREWALL_DROP, + MD_ERROR_WIN_IPSEC_THROTTLE_DROP, + MD_ERROR_WIN_IPSEC_DOSP_BLOCK, + MD_ERROR_WIN_IPSEC_DOSP_RECEIVED_MULTICAST, + MD_ERROR_WIN_IPSEC_DOSP_INVALID_PACKET, + MD_ERROR_WIN_IPSEC_DOSP_STATE_LOOKUP_FAILED, + MD_ERROR_WIN_IPSEC_DOSP_MAX_ENTRIES, + MD_ERROR_WIN_IPSEC_DOSP_KEYMOD_NOT_ALLOWED, + MD_ERROR_WIN_IPSEC_DOSP_NOT_INSTALLED, + MD_ERROR_WIN_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES, + MD_ERROR_WIN_SXS_SECTION_NOT_FOUND, + MD_ERROR_WIN_SXS_CANT_GEN_ACTCTX, + MD_ERROR_WIN_SXS_INVALID_ACTCTXDATA_FORMAT, + MD_ERROR_WIN_SXS_ASSEMBLY_NOT_FOUND, + MD_ERROR_WIN_SXS_MANIFEST_FORMAT_ERROR, + MD_ERROR_WIN_SXS_MANIFEST_PARSE_ERROR, + MD_ERROR_WIN_SXS_ACTIVATION_CONTEXT_DISABLED, + MD_ERROR_WIN_SXS_KEY_NOT_FOUND, + MD_ERROR_WIN_SXS_VERSION_CONFLICT, + MD_ERROR_WIN_SXS_WRONG_SECTION_TYPE, + MD_ERROR_WIN_SXS_THREAD_QUERIES_DISABLED, + MD_ERROR_WIN_SXS_PROCESS_DEFAULT_ALREADY_SET, + MD_ERROR_WIN_SXS_UNKNOWN_ENCODING_GROUP, + MD_ERROR_WIN_SXS_UNKNOWN_ENCODING, + MD_ERROR_WIN_SXS_INVALID_XML_NAMESPACE_URI, + MD_ERROR_WIN_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED, + MD_ERROR_WIN_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED, + MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE, + MD_ERROR_WIN_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE, + MD_ERROR_WIN_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE, + MD_ERROR_WIN_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT, + MD_ERROR_WIN_SXS_DUPLICATE_DLL_NAME, + MD_ERROR_WIN_SXS_DUPLICATE_WINDOWCLASS_NAME, + MD_ERROR_WIN_SXS_DUPLICATE_CLSID, + MD_ERROR_WIN_SXS_DUPLICATE_IID, + MD_ERROR_WIN_SXS_DUPLICATE_TLBID, + MD_ERROR_WIN_SXS_DUPLICATE_PROGID, + MD_ERROR_WIN_SXS_DUPLICATE_ASSEMBLY_NAME, + MD_ERROR_WIN_SXS_FILE_HASH_MISMATCH, + MD_ERROR_WIN_SXS_POLICY_PARSE_ERROR, + MD_ERROR_WIN_SXS_XML_E_MISSINGQUOTE, + MD_ERROR_WIN_SXS_XML_E_COMMENTSYNTAX, + MD_ERROR_WIN_SXS_XML_E_BADSTARTNAMECHAR, + MD_ERROR_WIN_SXS_XML_E_BADNAMECHAR, + MD_ERROR_WIN_SXS_XML_E_BADCHARINSTRING, + MD_ERROR_WIN_SXS_XML_E_XMLDECLSYNTAX, + MD_ERROR_WIN_SXS_XML_E_BADCHARDATA, + MD_ERROR_WIN_SXS_XML_E_MISSINGWHITESPACE, + MD_ERROR_WIN_SXS_XML_E_EXPECTINGTAGEND, + MD_ERROR_WIN_SXS_XML_E_MISSINGSEMICOLON, + MD_ERROR_WIN_SXS_XML_E_UNBALANCEDPAREN, + MD_ERROR_WIN_SXS_XML_E_INTERNALERROR, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_WHITESPACE, + MD_ERROR_WIN_SXS_XML_E_INCOMPLETE_ENCODING, + MD_ERROR_WIN_SXS_XML_E_MISSING_PAREN, + MD_ERROR_WIN_SXS_XML_E_EXPECTINGCLOSEQUOTE, + MD_ERROR_WIN_SXS_XML_E_MULTIPLE_COLONS, + MD_ERROR_WIN_SXS_XML_E_INVALID_DECIMAL, + MD_ERROR_WIN_SXS_XML_E_INVALID_HEXIDECIMAL, + MD_ERROR_WIN_SXS_XML_E_INVALID_UNICODE, + MD_ERROR_WIN_SXS_XML_E_WHITESPACEORQUESTIONMARK, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDENDTAG, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDTAG, + MD_ERROR_WIN_SXS_XML_E_DUPLICATEATTRIBUTE, + MD_ERROR_WIN_SXS_XML_E_MULTIPLEROOTS, + MD_ERROR_WIN_SXS_XML_E_INVALIDATROOTLEVEL, + MD_ERROR_WIN_SXS_XML_E_BADXMLDECL, + MD_ERROR_WIN_SXS_XML_E_MISSINGROOT, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTEDEOF, + MD_ERROR_WIN_SXS_XML_E_BADPEREFINSUBSET, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTARTTAG, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDENDTAG, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDSTRING, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCOMMENT, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDDECL, + MD_ERROR_WIN_SXS_XML_E_UNCLOSEDCDATA, + MD_ERROR_WIN_SXS_XML_E_RESERVEDNAMESPACE, + MD_ERROR_WIN_SXS_XML_E_INVALIDENCODING, + MD_ERROR_WIN_SXS_XML_E_INVALIDSWITCH, + MD_ERROR_WIN_SXS_XML_E_BADXMLCASE, + MD_ERROR_WIN_SXS_XML_E_INVALID_STANDALONE, + MD_ERROR_WIN_SXS_XML_E_UNEXPECTED_STANDALONE, + MD_ERROR_WIN_SXS_XML_E_INVALID_VERSION, + MD_ERROR_WIN_SXS_XML_E_MISSINGEQUALS, + MD_ERROR_WIN_SXS_PROTECTION_RECOVERY_FAILED, + MD_ERROR_WIN_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT, + MD_ERROR_WIN_SXS_PROTECTION_CATALOG_NOT_VALID, + MD_ERROR_WIN_SXS_UNTRANSLATABLE_HRESULT, + MD_ERROR_WIN_SXS_PROTECTION_CATALOG_FILE_MISSING, + MD_ERROR_WIN_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE, + MD_ERROR_WIN_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME, + MD_ERROR_WIN_SXS_ASSEMBLY_MISSING, + MD_ERROR_WIN_SXS_CORRUPT_ACTIVATION_STACK, + MD_ERROR_WIN_SXS_CORRUPTION, + MD_ERROR_WIN_SXS_EARLY_DEACTIVATION, + MD_ERROR_WIN_SXS_INVALID_DEACTIVATION, + MD_ERROR_WIN_SXS_MULTIPLE_DEACTIVATION, + MD_ERROR_WIN_SXS_PROCESS_TERMINATION_REQUESTED, + MD_ERROR_WIN_SXS_RELEASE_ACTIVATION_CONTEXT, + MD_ERROR_WIN_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY, + MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE, + MD_ERROR_WIN_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME, + MD_ERROR_WIN_SXS_IDENTITY_DUPLICATE_ATTRIBUTE, + MD_ERROR_WIN_SXS_IDENTITY_PARSE_ERROR, + MD_ERROR_WIN_MALFORMED_SUBSTITUTION_STRING, + MD_ERROR_WIN_SXS_INCORRECT_PUBLIC_KEY_TOKEN, + MD_ERROR_WIN_UNMAPPED_SUBSTITUTION_STRING, + MD_ERROR_WIN_SXS_ASSEMBLY_NOT_LOCKED, + MD_ERROR_WIN_SXS_COMPONENT_STORE_CORRUPT, + MD_ERROR_WIN_ADVANCED_INSTALLER_FAILED, + MD_ERROR_WIN_XML_ENCODING_MISMATCH, + MD_ERROR_WIN_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT, + MD_ERROR_WIN_SXS_IDENTITIES_DIFFERENT, + MD_ERROR_WIN_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT, + MD_ERROR_WIN_SXS_FILE_NOT_PART_OF_ASSEMBLY, + MD_ERROR_WIN_SXS_MANIFEST_TOO_BIG, + MD_ERROR_WIN_SXS_SETTING_NOT_REGISTERED, + MD_ERROR_WIN_SXS_TRANSACTION_CLOSURE_INCOMPLETE, + MD_ERROR_WIN_SMI_PRIMITIVE_INSTALLER_FAILED, + MD_ERROR_WIN_GENERIC_COMMAND_FAILED, + MD_ERROR_WIN_SXS_FILE_HASH_MISSING, + MD_ERROR_WIN_SXS_DUPLICATE_ACTIVATABLE_CLASS, + MD_ERROR_WIN_EVT_INVALID_CHANNEL_PATH, + MD_ERROR_WIN_EVT_INVALID_QUERY, + MD_ERROR_WIN_EVT_PUBLISHER_METADATA_NOT_FOUND, + MD_ERROR_WIN_EVT_EVENT_TEMPLATE_NOT_FOUND, + MD_ERROR_WIN_EVT_INVALID_PUBLISHER_NAME, + MD_ERROR_WIN_EVT_INVALID_EVENT_DATA, + MD_ERROR_WIN_EVT_CHANNEL_NOT_FOUND, + MD_ERROR_WIN_EVT_MALFORMED_XML_TEXT, + MD_ERROR_WIN_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL, + MD_ERROR_WIN_EVT_CONFIGURATION_ERROR, + MD_ERROR_WIN_EVT_QUERY_RESULT_STALE, + MD_ERROR_WIN_EVT_QUERY_RESULT_INVALID_POSITION, + MD_ERROR_WIN_EVT_NON_VALIDATING_MSXML, + MD_ERROR_WIN_EVT_FILTER_ALREADYSCOPED, + MD_ERROR_WIN_EVT_FILTER_NOTELTSET, + MD_ERROR_WIN_EVT_FILTER_INVARG, + MD_ERROR_WIN_EVT_FILTER_INVTEST, + MD_ERROR_WIN_EVT_FILTER_INVTYPE, + MD_ERROR_WIN_EVT_FILTER_PARSEERR, + MD_ERROR_WIN_EVT_FILTER_UNSUPPORTEDOP, + MD_ERROR_WIN_EVT_FILTER_UNEXPECTEDTOKEN, + MD_ERROR_WIN_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL, + MD_ERROR_WIN_EVT_INVALID_CHANNEL_PROPERTY_VALUE, + MD_ERROR_WIN_EVT_INVALID_PUBLISHER_PROPERTY_VALUE, + MD_ERROR_WIN_EVT_CHANNEL_CANNOT_ACTIVATE, + MD_ERROR_WIN_EVT_FILTER_TOO_COMPLEX, + MD_ERROR_WIN_EVT_MESSAGE_NOT_FOUND, + MD_ERROR_WIN_EVT_MESSAGE_ID_NOT_FOUND, + MD_ERROR_WIN_EVT_UNRESOLVED_VALUE_INSERT, + MD_ERROR_WIN_EVT_UNRESOLVED_PARAMETER_INSERT, + MD_ERROR_WIN_EVT_MAX_INSERTS_REACHED, + MD_ERROR_WIN_EVT_EVENT_DEFINITION_NOT_FOUND, + MD_ERROR_WIN_EVT_MESSAGE_LOCALE_NOT_FOUND, + MD_ERROR_WIN_EVT_VERSION_TOO_OLD, + MD_ERROR_WIN_EVT_VERSION_TOO_NEW, + MD_ERROR_WIN_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY, + MD_ERROR_WIN_EVT_PUBLISHER_DISABLED, + MD_ERROR_WIN_EVT_FILTER_OUT_OF_RANGE, + MD_ERROR_WIN_EC_SUBSCRIPTION_CANNOT_ACTIVATE, + MD_ERROR_WIN_EC_LOG_DISABLED, + MD_ERROR_WIN_EC_CIRCULAR_FORWARDING, + MD_ERROR_WIN_EC_CREDSTORE_FULL, + MD_ERROR_WIN_EC_CRED_NOT_FOUND, + MD_ERROR_WIN_EC_NO_ACTIVE_CHANNEL, + MD_ERROR_WIN_MUI_FILE_NOT_FOUND, + MD_ERROR_WIN_MUI_INVALID_FILE, + MD_ERROR_WIN_MUI_INVALID_RC_CONFIG, + MD_ERROR_WIN_MUI_INVALID_LOCALE_NAME, + MD_ERROR_WIN_MUI_INVALID_ULTIMATEFALLBACK_NAME, + MD_ERROR_WIN_MUI_FILE_NOT_LOADED, + MD_ERROR_WIN_RESOURCE_ENUM_USER_STOP, + MD_ERROR_WIN_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED, + MD_ERROR_WIN_MUI_INTLSETTINGS_INVALID_LOCALE_NAME, + MD_ERROR_WIN_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE, + MD_ERROR_WIN_MRM_INVALID_PRICONFIG, + MD_ERROR_WIN_MRM_INVALID_FILE_TYPE, + MD_ERROR_WIN_MRM_UNKNOWN_QUALIFIER, + MD_ERROR_WIN_MRM_INVALID_QUALIFIER_VALUE, + MD_ERROR_WIN_MRM_NO_CANDIDATE, + MD_ERROR_WIN_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE, + MD_ERROR_WIN_MRM_RESOURCE_TYPE_MISMATCH, + MD_ERROR_WIN_MRM_DUPLICATE_MAP_NAME, + MD_ERROR_WIN_MRM_DUPLICATE_ENTRY, + MD_ERROR_WIN_MRM_INVALID_RESOURCE_IDENTIFIER, + MD_ERROR_WIN_MRM_FILEPATH_TOO_LONG, + MD_ERROR_WIN_MRM_UNSUPPORTED_DIRECTORY_TYPE, + MD_ERROR_WIN_MRM_INVALID_PRI_FILE, + MD_ERROR_WIN_MRM_NAMED_RESOURCE_NOT_FOUND, + MD_ERROR_WIN_MRM_MAP_NOT_FOUND, + MD_ERROR_WIN_MRM_UNSUPPORTED_PROFILE_TYPE, + MD_ERROR_WIN_MRM_INVALID_QUALIFIER_OPERATOR, + MD_ERROR_WIN_MRM_INDETERMINATE_QUALIFIER_VALUE, + MD_ERROR_WIN_MRM_AUTOMERGE_ENABLED, + MD_ERROR_WIN_MRM_TOO_MANY_RESOURCES, + MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE, + MD_ERROR_WIN_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE, + MD_ERROR_WIN_MRM_NO_CURRENT_VIEW_ON_THREAD, + MD_ERROR_WIN_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST, + MD_ERROR_WIN_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT, + MD_ERROR_WIN_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE, + MD_ERROR_WIN_MRM_GENERATION_COUNT_MISMATCH, + MD_ERROR_WIN_PRI_MERGE_VERSION_MISMATCH, + MD_ERROR_WIN_PRI_MERGE_MISSING_SCHEMA, + MD_ERROR_WIN_PRI_MERGE_LOAD_FILE_FAILED, + MD_ERROR_WIN_PRI_MERGE_ADD_FILE_FAILED, + MD_ERROR_WIN_PRI_MERGE_WRITE_FILE_FAILED, + MD_ERROR_WIN_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED, + MD_ERROR_WIN_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED, + MD_ERROR_WIN_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED, + MD_ERROR_WIN_PRI_MERGE_MAIN_PACKAGE_REQUIRED, + MD_ERROR_WIN_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED, + MD_ERROR_WIN_PRI_MERGE_INVALID_FILE_NAME, + MD_ERROR_WIN_MRM_PACKAGE_NOT_FOUND, + MD_ERROR_WIN_MRM_MISSING_DEFAULT_LANGUAGE, + MD_ERROR_WIN_MCA_INVALID_CAPABILITIES_STRING, + MD_ERROR_WIN_MCA_INVALID_VCP_VERSION, + MD_ERROR_WIN_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION, + MD_ERROR_WIN_MCA_MCCS_VERSION_MISMATCH, + MD_ERROR_WIN_MCA_UNSUPPORTED_MCCS_VERSION, + MD_ERROR_WIN_MCA_INTERNAL_ERROR, + MD_ERROR_WIN_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED, + MD_ERROR_WIN_MCA_UNSUPPORTED_COLOR_TEMPERATURE, + MD_ERROR_WIN_AMBIGUOUS_SYSTEM_DEVICE, + MD_ERROR_WIN_SYSTEM_DEVICE_NOT_FOUND, + MD_ERROR_WIN_HASH_NOT_SUPPORTED, + MD_ERROR_WIN_HASH_NOT_PRESENT, + MD_ERROR_WIN_SECONDARY_IC_PROVIDER_NOT_REGISTERED, + MD_ERROR_WIN_GPIO_CLIENT_INFORMATION_INVALID, + MD_ERROR_WIN_GPIO_VERSION_NOT_SUPPORTED, + MD_ERROR_WIN_GPIO_INVALID_REGISTRATION_PACKET, + MD_ERROR_WIN_GPIO_OPERATION_DENIED, + MD_ERROR_WIN_GPIO_INCOMPATIBLE_CONNECT_MODE, + MD_ERROR_WIN_GPIO_INTERRUPT_ALREADY_UNMASKED, + MD_ERROR_WIN_CANNOT_SWITCH_RUNLEVEL, + MD_ERROR_WIN_INVALID_RUNLEVEL_SETTING, + MD_ERROR_WIN_RUNLEVEL_SWITCH_TIMEOUT, + MD_ERROR_WIN_RUNLEVEL_SWITCH_AGENT_TIMEOUT, + MD_ERROR_WIN_RUNLEVEL_SWITCH_IN_PROGRESS, + MD_ERROR_WIN_SERVICES_FAILED_AUTOSTART, + MD_ERROR_WIN_COM_TASK_STOP_PENDING, + MD_ERROR_WIN_INSTALL_OPEN_PACKAGE_FAILED, + MD_ERROR_WIN_INSTALL_PACKAGE_NOT_FOUND, + MD_ERROR_WIN_INSTALL_INVALID_PACKAGE, + MD_ERROR_WIN_INSTALL_RESOLVE_DEPENDENCY_FAILED, + MD_ERROR_WIN_INSTALL_OUT_OF_DISK_SPACE, + MD_ERROR_WIN_INSTALL_NETWORK_FAILURE, + MD_ERROR_WIN_INSTALL_REGISTRATION_FAILURE, + MD_ERROR_WIN_INSTALL_DEREGISTRATION_FAILURE, + MD_ERROR_WIN_INSTALL_CANCEL, + MD_ERROR_WIN_INSTALL_FAILED, + MD_ERROR_WIN_REMOVE_FAILED, + MD_ERROR_WIN_PACKAGE_ALREADY_EXISTS, + MD_ERROR_WIN_NEEDS_REMEDIATION, + MD_ERROR_WIN_INSTALL_PREREQUISITE_FAILED, + MD_ERROR_WIN_PACKAGE_REPOSITORY_CORRUPTED, + MD_ERROR_WIN_INSTALL_POLICY_FAILURE, + MD_ERROR_WIN_PACKAGE_UPDATING, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_POLICY, + MD_ERROR_WIN_PACKAGES_IN_USE, + MD_ERROR_WIN_RECOVERY_FILE_CORRUPT, + MD_ERROR_WIN_INVALID_STAGED_SIGNATURE, + MD_ERROR_WIN_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED, + MD_ERROR_WIN_INSTALL_PACKAGE_DOWNGRADE, + MD_ERROR_WIN_SYSTEM_NEEDS_REMEDIATION, + MD_ERROR_WIN_APPX_INTEGRITY_FAILURE_CLR_NGEN, + MD_ERROR_WIN_RESILIENCY_FILE_CORRUPT, + MD_ERROR_WIN_INSTALL_FIREWALL_SERVICE_NOT_RUNNING, + MD_ERROR_WIN_PACKAGE_MOVE_FAILED, + MD_ERROR_WIN_INSTALL_VOLUME_NOT_EMPTY, + MD_ERROR_WIN_INSTALL_VOLUME_OFFLINE, + MD_ERROR_WIN_INSTALL_VOLUME_CORRUPT, + MD_ERROR_WIN_NEEDS_REGISTRATION, + MD_ERROR_WIN_INSTALL_WRONG_PROCESSOR_ARCHITECTURE, + MD_ERROR_WIN_DEV_SIDELOAD_LIMIT_EXCEEDED, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE, + MD_ERROR_WIN_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM, + MD_ERROR_WIN_PACKAGE_MOVE_BLOCKED_BY_STREAMING, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE, + MD_ERROR_WIN_PACKAGE_STAGING_ONHOLD, + MD_ERROR_WIN_INSTALL_INVALID_RELATED_SET_UPDATE, + MD_ERROR_WIN_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF, + MD_ERROR_WIN_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED, + MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_FAILED, + MD_ERROR_WIN_PACKAGES_REPUTATION_CHECK_TIMEDOUT, + MD_ERROR_WIN_DEPLOYMENT_OPTION_NOT_SUPPORTED, + MD_ERROR_WIN_APPINSTALLER_ACTIVATION_BLOCKED, + MD_ERROR_WIN_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED, + MD_ERROR_WIN_APPX_RAW_DATA_WRITE_FAILED, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE, + MD_ERROR_WIN_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY, + MD_ERROR_WIN_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY, + MD_ERROR_WIN_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER, + MD_ERROR_WIN_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED, + MD_ERROR_WIN_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE, + MD_ERROR_WIN_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES, + MD_ERROR_WIN_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED, + MD_ERROR_WIN_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST, + MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_CONTENT, + MD_ERROR_WIN_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE, + MD_ERROR_WIN_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE, + MD_ERROR_WIN_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED, + MD_ERROR_WIN_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY, + MD_ERROR_WIN_STATE_LOAD_STORE_FAILED, + MD_ERROR_WIN_STATE_GET_VERSION_FAILED, + MD_ERROR_WIN_STATE_SET_VERSION_FAILED, + MD_ERROR_WIN_STATE_STRUCTURED_RESET_FAILED, + MD_ERROR_WIN_STATE_OPEN_CONTAINER_FAILED, + MD_ERROR_WIN_STATE_CREATE_CONTAINER_FAILED, + MD_ERROR_WIN_STATE_DELETE_CONTAINER_FAILED, + MD_ERROR_WIN_STATE_READ_SETTING_FAILED, + MD_ERROR_WIN_STATE_WRITE_SETTING_FAILED, + MD_ERROR_WIN_STATE_DELETE_SETTING_FAILED, + MD_ERROR_WIN_STATE_QUERY_SETTING_FAILED, + MD_ERROR_WIN_STATE_READ_COMPOSITE_SETTING_FAILED, + MD_ERROR_WIN_STATE_WRITE_COMPOSITE_SETTING_FAILED, + MD_ERROR_WIN_STATE_ENUMERATE_CONTAINER_FAILED, + MD_ERROR_WIN_STATE_ENUMERATE_SETTINGS_FAILED, + MD_ERROR_WIN_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED, + MD_ERROR_WIN_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED, + MD_ERROR_WIN_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED, + MD_ERROR_WIN_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED, + MD_ERROR_WIN_API_UNAVAILABLE, +}; + +// The content of this array was created from winerror.h in the 10 SDK +// (version 10.0.19041.0) with the following script: +// +// egrep -o '#define ERROR_[A-Z_0-9]+\s+[0-9]+L' winerror.h +// | tr -d '\r' +// | sed -r 's@#define (ERROR_[A-Z_0-9]+)\s+([0-9]+)L@\2 \1@' +// | sort -n | sed -r 's@([0-9]+) ([A-Z_0-9]+)@ "\2",@' +static const char* kWinErrorStrings[] = { + "ERROR_SUCCESS", + "ERROR_INVALID_FUNCTION", + "ERROR_FILE_NOT_FOUND", + "ERROR_PATH_NOT_FOUND", + "ERROR_TOO_MANY_OPEN_FILES", + "ERROR_ACCESS_DENIED", + "ERROR_INVALID_HANDLE", + "ERROR_ARENA_TRASHED", + "ERROR_NOT_ENOUGH_MEMORY", + "ERROR_INVALID_BLOCK", + "ERROR_BAD_ENVIRONMENT", + "ERROR_BAD_FORMAT", + "ERROR_INVALID_ACCESS", + "ERROR_INVALID_DATA", + "ERROR_OUTOFMEMORY", + "ERROR_INVALID_DRIVE", + "ERROR_CURRENT_DIRECTORY", + "ERROR_NOT_SAME_DEVICE", + "ERROR_NO_MORE_FILES", + "ERROR_WRITE_PROTECT", + "ERROR_BAD_UNIT", + "ERROR_NOT_READY", + "ERROR_BAD_COMMAND", + "ERROR_CRC", + "ERROR_BAD_LENGTH", + "ERROR_SEEK", + "ERROR_NOT_DOS_DISK", + "ERROR_SECTOR_NOT_FOUND", + "ERROR_OUT_OF_PAPER", + "ERROR_WRITE_FAULT", + "ERROR_READ_FAULT", + "ERROR_GEN_FAILURE", + "ERROR_SHARING_VIOLATION", + "ERROR_LOCK_VIOLATION", + "ERROR_WRONG_DISK", + "ERROR_SHARING_BUFFER_EXCEEDED", + "ERROR_HANDLE_EOF", + "ERROR_HANDLE_DISK_FULL", + "ERROR_NOT_SUPPORTED", + "ERROR_REM_NOT_LIST", + "ERROR_DUP_NAME", + "ERROR_BAD_NETPATH", + "ERROR_NETWORK_BUSY", + "ERROR_DEV_NOT_EXIST", + "ERROR_TOO_MANY_CMDS", + "ERROR_ADAP_HDW_ERR", + "ERROR_BAD_NET_RESP", + "ERROR_UNEXP_NET_ERR", + "ERROR_BAD_REM_ADAP", + "ERROR_PRINTQ_FULL", + "ERROR_NO_SPOOL_SPACE", + "ERROR_PRINT_CANCELLED", + "ERROR_NETNAME_DELETED", + "ERROR_NETWORK_ACCESS_DENIED", + "ERROR_BAD_DEV_TYPE", + "ERROR_BAD_NET_NAME", + "ERROR_TOO_MANY_NAMES", + "ERROR_TOO_MANY_SESS", + "ERROR_SHARING_PAUSED", + "ERROR_REQ_NOT_ACCEP", + "ERROR_REDIR_PAUSED", + "ERROR_FILE_EXISTS", + "ERROR_CANNOT_MAKE", + "ERROR_FAIL_I24", + "ERROR_OUT_OF_STRUCTURES", + "ERROR_ALREADY_ASSIGNED", + "ERROR_INVALID_PASSWORD", + "ERROR_INVALID_PARAMETER", + "ERROR_NET_WRITE_FAULT", + "ERROR_NO_PROC_SLOTS", + "ERROR_TOO_MANY_SEMAPHORES", + "ERROR_EXCL_SEM_ALREADY_OWNED", + "ERROR_SEM_IS_SET", + "ERROR_TOO_MANY_SEM_REQUESTS", + "ERROR_INVALID_AT_INTERRUPT_TIME", + "ERROR_SEM_OWNER_DIED", + "ERROR_SEM_USER_LIMIT", + "ERROR_DISK_CHANGE", + "ERROR_DRIVE_LOCKED", + "ERROR_BROKEN_PIPE", + "ERROR_OPEN_FAILED", + "ERROR_BUFFER_OVERFLOW", + "ERROR_DISK_FULL", + "ERROR_NO_MORE_SEARCH_HANDLES", + "ERROR_INVALID_TARGET_HANDLE", + "ERROR_INVALID_CATEGORY", + "ERROR_INVALID_VERIFY_SWITCH", + "ERROR_BAD_DRIVER_LEVEL", + "ERROR_CALL_NOT_IMPLEMENTED", + "ERROR_SEM_TIMEOUT", + "ERROR_INSUFFICIENT_BUFFER", + "ERROR_INVALID_NAME", + "ERROR_INVALID_LEVEL", + "ERROR_NO_VOLUME_LABEL", + "ERROR_MOD_NOT_FOUND", + "ERROR_PROC_NOT_FOUND", + "ERROR_WAIT_NO_CHILDREN", + "ERROR_CHILD_NOT_COMPLETE", + "ERROR_DIRECT_ACCESS_HANDLE", + "ERROR_NEGATIVE_SEEK", + "ERROR_SEEK_ON_DEVICE", + "ERROR_IS_JOIN_TARGET", + "ERROR_IS_JOINED", + "ERROR_IS_SUBSTED", + "ERROR_NOT_JOINED", + "ERROR_NOT_SUBSTED", + "ERROR_JOIN_TO_JOIN", + "ERROR_SUBST_TO_SUBST", + "ERROR_JOIN_TO_SUBST", + "ERROR_SUBST_TO_JOIN", + "ERROR_BUSY_DRIVE", + "ERROR_SAME_DRIVE", + "ERROR_DIR_NOT_ROOT", + "ERROR_DIR_NOT_EMPTY", + "ERROR_IS_SUBST_PATH", + "ERROR_IS_JOIN_PATH", + "ERROR_PATH_BUSY", + "ERROR_IS_SUBST_TARGET", + "ERROR_SYSTEM_TRACE", + "ERROR_INVALID_EVENT_COUNT", + "ERROR_TOO_MANY_MUXWAITERS", + "ERROR_INVALID_LIST_FORMAT", + "ERROR_LABEL_TOO_LONG", + "ERROR_TOO_MANY_TCBS", + "ERROR_SIGNAL_REFUSED", + "ERROR_DISCARDED", + "ERROR_NOT_LOCKED", + "ERROR_BAD_THREADID_ADDR", + "ERROR_BAD_ARGUMENTS", + "ERROR_BAD_PATHNAME", + "ERROR_SIGNAL_PENDING", + "ERROR_MAX_THRDS_REACHED", + "ERROR_LOCK_FAILED", + "ERROR_BUSY", + "ERROR_DEVICE_SUPPORT_IN_PROGRESS", + "ERROR_CANCEL_VIOLATION", + "ERROR_ATOMIC_LOCKS_NOT_SUPPORTED", + "ERROR_INVALID_SEGMENT_NUMBER", + "ERROR_INVALID_ORDINAL", + "ERROR_ALREADY_EXISTS", + "ERROR_INVALID_FLAG_NUMBER", + "ERROR_SEM_NOT_FOUND", + "ERROR_INVALID_STARTING_CODESEG", + "ERROR_INVALID_STACKSEG", + "ERROR_INVALID_MODULETYPE", + "ERROR_INVALID_EXE_SIGNATURE", + "ERROR_EXE_MARKED_INVALID", + "ERROR_BAD_EXE_FORMAT", + "ERROR_INVALID_MINALLOCSIZE", + "ERROR_DYNLINK_FROM_INVALID_RING", + "ERROR_IOPL_NOT_ENABLED", + "ERROR_INVALID_SEGDPL", + "ERROR_RING2SEG_MUST_BE_MOVABLE", + "ERROR_RELOC_CHAIN_XEEDS_SEGLIM", + "ERROR_INFLOOP_IN_RELOC_CHAIN", + "ERROR_ENVVAR_NOT_FOUND", + "ERROR_NO_SIGNAL_SENT", + "ERROR_FILENAME_EXCED_RANGE", + "ERROR_RING2_STACK_IN_USE", + "ERROR_META_EXPANSION_TOO_LONG", + "ERROR_INVALID_SIGNAL_NUMBER", + "ERROR_THREAD_1_INACTIVE", + "ERROR_LOCKED", + "ERROR_TOO_MANY_MODULES", + "ERROR_NESTING_NOT_ALLOWED", + "ERROR_EXE_MACHINE_TYPE_MISMATCH", + "ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY", + "ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY", + "ERROR_FILE_CHECKED_OUT", + "ERROR_CHECKOUT_REQUIRED", + "ERROR_BAD_FILE_TYPE", + "ERROR_FILE_TOO_LARGE", + "ERROR_FORMS_AUTH_REQUIRED", + "ERROR_VIRUS_INFECTED", + "ERROR_VIRUS_DELETED", + "ERROR_PIPE_LOCAL", + "ERROR_BAD_PIPE", + "ERROR_PIPE_BUSY", + "ERROR_NO_DATA", + "ERROR_PIPE_NOT_CONNECTED", + "ERROR_MORE_DATA", + "ERROR_NO_WORK_DONE", + "ERROR_VC_DISCONNECTED", + "ERROR_INVALID_EA_NAME", + "ERROR_EA_LIST_INCONSISTENT", + "ERROR_NO_MORE_ITEMS", + "ERROR_CANNOT_COPY", + "ERROR_DIRECTORY", + "ERROR_EAS_DIDNT_FIT", + "ERROR_EA_FILE_CORRUPT", + "ERROR_EA_TABLE_FULL", + "ERROR_INVALID_EA_HANDLE", + "ERROR_EAS_NOT_SUPPORTED", + "ERROR_NOT_OWNER", + "ERROR_TOO_MANY_POSTS", + "ERROR_PARTIAL_COPY", + "ERROR_OPLOCK_NOT_GRANTED", + "ERROR_INVALID_OPLOCK_PROTOCOL", + "ERROR_DISK_TOO_FRAGMENTED", + "ERROR_DELETE_PENDING", + "ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING", + "ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME", + "ERROR_SECURITY_STREAM_IS_INCONSISTENT", + "ERROR_INVALID_LOCK_RANGE", + "ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT", + "ERROR_NOTIFICATION_GUID_ALREADY_DEFINED", + "ERROR_INVALID_EXCEPTION_HANDLER", + "ERROR_DUPLICATE_PRIVILEGES", + "ERROR_NO_RANGES_PROCESSED", + "ERROR_NOT_ALLOWED_ON_SYSTEM_FILE", + "ERROR_DISK_RESOURCES_EXHAUSTED", + "ERROR_INVALID_TOKEN", + "ERROR_DEVICE_FEATURE_NOT_SUPPORTED", + "ERROR_MR_MID_NOT_FOUND", + "ERROR_SCOPE_NOT_FOUND", + "ERROR_UNDEFINED_SCOPE", + "ERROR_INVALID_CAP", + "ERROR_DEVICE_UNREACHABLE", + "ERROR_DEVICE_NO_RESOURCES", + "ERROR_DATA_CHECKSUM_ERROR", + "ERROR_INTERMIXED_KERNEL_EA_OPERATION", + "ERROR_FILE_LEVEL_TRIM_NOT_SUPPORTED", + "ERROR_OFFSET_ALIGNMENT_VIOLATION", + "ERROR_INVALID_FIELD_IN_PARAMETER_LIST", + "ERROR_OPERATION_IN_PROGRESS", + "ERROR_BAD_DEVICE_PATH", + "ERROR_TOO_MANY_DESCRIPTORS", + "ERROR_SCRUB_DATA_DISABLED", + "ERROR_NOT_REDUNDANT_STORAGE", + "ERROR_RESIDENT_FILE_NOT_SUPPORTED", + "ERROR_COMPRESSED_FILE_NOT_SUPPORTED", + "ERROR_DIRECTORY_NOT_SUPPORTED", + "ERROR_NOT_READ_FROM_COPY", + "ERROR_FT_WRITE_FAILURE", + "ERROR_FT_DI_SCAN_REQUIRED", + "ERROR_INVALID_KERNEL_INFO_VERSION", + "ERROR_INVALID_PEP_INFO_VERSION", + "ERROR_OBJECT_NOT_EXTERNALLY_BACKED", + "ERROR_EXTERNAL_BACKING_PROVIDER_UNKNOWN", + "ERROR_COMPRESSION_NOT_BENEFICIAL", + "ERROR_STORAGE_TOPOLOGY_ID_MISMATCH", + "ERROR_BLOCKED_BY_PARENTAL_CONTROLS", + "ERROR_BLOCK_TOO_MANY_REFERENCES", + "ERROR_MARKED_TO_DISALLOW_WRITES", + "ERROR_ENCLAVE_FAILURE", + "ERROR_FAIL_NOACTION_REBOOT", + "ERROR_FAIL_SHUTDOWN", + "ERROR_FAIL_RESTART", + "ERROR_MAX_SESSIONS_REACHED", + "ERROR_NETWORK_ACCESS_DENIED_EDP", + "ERROR_DEVICE_HINT_NAME_BUFFER_TOO_SMALL", + "ERROR_EDP_POLICY_DENIES_OPERATION", + "ERROR_EDP_DPL_POLICY_CANT_BE_SATISFIED", + "ERROR_CLOUD_FILE_SYNC_ROOT_METADATA_CORRUPT", + "ERROR_DEVICE_IN_MAINTENANCE", + "ERROR_NOT_SUPPORTED_ON_DAX", + "ERROR_DAX_MAPPING_EXISTS", + "ERROR_CLOUD_FILE_PROVIDER_NOT_RUNNING", + "ERROR_CLOUD_FILE_METADATA_CORRUPT", + "ERROR_CLOUD_FILE_METADATA_TOO_LARGE", + "ERROR_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE", + "ERROR_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH", + "ERROR_CHILD_PROCESS_BLOCKED", + "ERROR_STORAGE_LOST_DATA_PERSISTENCE", + "ERROR_FILE_SYSTEM_VIRTUALIZATION_UNAVAILABLE", + "ERROR_FILE_SYSTEM_VIRTUALIZATION_METADATA_CORRUPT", + "ERROR_FILE_SYSTEM_VIRTUALIZATION_BUSY", + "ERROR_FILE_SYSTEM_VIRTUALIZATION_PROVIDER_UNKNOWN", + "ERROR_GDI_HANDLE_LEAK", + "ERROR_CLOUD_FILE_TOO_MANY_PROPERTY_BLOBS", + "ERROR_CLOUD_FILE_PROPERTY_VERSION_NOT_SUPPORTED", + "ERROR_NOT_A_CLOUD_FILE", + "ERROR_CLOUD_FILE_NOT_IN_SYNC", + "ERROR_CLOUD_FILE_ALREADY_CONNECTED", + "ERROR_CLOUD_FILE_NOT_SUPPORTED", + "ERROR_CLOUD_FILE_INVALID_REQUEST", + "ERROR_CLOUD_FILE_READ_ONLY_VOLUME", + "ERROR_CLOUD_FILE_CONNECTED_PROVIDER_ONLY", + "ERROR_CLOUD_FILE_VALIDATION_FAILED", + "ERROR_SMB1_NOT_AVAILABLE", + "ERROR_FILE_SYSTEM_VIRTUALIZATION_INVALID_OPERATION", + "ERROR_CLOUD_FILE_AUTHENTICATION_FAILED", + "ERROR_CLOUD_FILE_INSUFFICIENT_RESOURCES", + "ERROR_CLOUD_FILE_NETWORK_UNAVAILABLE", + "ERROR_CLOUD_FILE_UNSUCCESSFUL", + "ERROR_CLOUD_FILE_NOT_UNDER_SYNC_ROOT", + "ERROR_CLOUD_FILE_IN_USE", + "ERROR_CLOUD_FILE_PINNED", + "ERROR_CLOUD_FILE_REQUEST_ABORTED", + "ERROR_CLOUD_FILE_PROPERTY_CORRUPT", + "ERROR_CLOUD_FILE_ACCESS_DENIED", + "ERROR_CLOUD_FILE_INCOMPATIBLE_HARDLINKS", + "ERROR_CLOUD_FILE_PROPERTY_LOCK_CONFLICT", + "ERROR_CLOUD_FILE_REQUEST_CANCELED", + "ERROR_EXTERNAL_SYSKEY_NOT_SUPPORTED", + "ERROR_THREAD_MODE_ALREADY_BACKGROUND", + "ERROR_THREAD_MODE_NOT_BACKGROUND", + "ERROR_PROCESS_MODE_ALREADY_BACKGROUND", + "ERROR_PROCESS_MODE_NOT_BACKGROUND", + "ERROR_CLOUD_FILE_PROVIDER_TERMINATED", + "ERROR_NOT_A_CLOUD_SYNC_ROOT", + "ERROR_FILE_PROTECTED_UNDER_DPL", + "ERROR_VOLUME_NOT_CLUSTER_ALIGNED", + "ERROR_NO_PHYSICALLY_ALIGNED_FREE_SPACE_FOUND", + "ERROR_APPX_FILE_NOT_ENCRYPTED", + "ERROR_RWRAW_ENCRYPTED_FILE_NOT_ENCRYPTED", + "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILEOFFSET", + "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_FILERANGE", + "ERROR_RWRAW_ENCRYPTED_INVALID_EDATAINFO_PARAMETER", + "ERROR_LINUX_SUBSYSTEM_NOT_PRESENT", + "ERROR_FT_READ_FAILURE", + "ERROR_STORAGE_RESERVE_ID_INVALID", + "ERROR_STORAGE_RESERVE_DOES_NOT_EXIST", + "ERROR_STORAGE_RESERVE_ALREADY_EXISTS", + "ERROR_STORAGE_RESERVE_NOT_EMPTY", + "ERROR_NOT_A_DAX_VOLUME", + "ERROR_NOT_DAX_MAPPABLE", + "ERROR_TIME_SENSITIVE_THREAD", + "ERROR_DPL_NOT_SUPPORTED_FOR_USER", + "ERROR_CASE_DIFFERING_NAMES_IN_DIR", + "ERROR_FILE_NOT_SUPPORTED", + "ERROR_CLOUD_FILE_REQUEST_TIMEOUT", + "ERROR_NO_TASK_QUEUE", + "ERROR_SRC_SRV_DLL_LOAD_FAILED", + "ERROR_NOT_SUPPORTED_WITH_BTT", + "ERROR_ENCRYPTION_DISABLED", + "ERROR_ENCRYPTING_METADATA_DISALLOWED", + "ERROR_CANT_CLEAR_ENCRYPTION_FLAG", + "ERROR_NO_SUCH_DEVICE", + "ERROR_CLOUD_FILE_DEHYDRATION_DISALLOWED", + "ERROR_FILE_SNAP_IN_PROGRESS", + "ERROR_FILE_SNAP_USER_SECTION_NOT_SUPPORTED", + "ERROR_FILE_SNAP_MODIFY_NOT_SUPPORTED", + "ERROR_FILE_SNAP_IO_NOT_COORDINATED", + "ERROR_FILE_SNAP_UNEXPECTED_ERROR", + "ERROR_FILE_SNAP_INVALID_PARAMETER", + "ERROR_UNSATISFIED_DEPENDENCIES", + "ERROR_CASE_SENSITIVE_PATH", + "ERROR_UNEXPECTED_NTCACHEMANAGER_ERROR", + "ERROR_LINUX_SUBSYSTEM_UPDATE_REQUIRED", + "ERROR_DLP_POLICY_WARNS_AGAINST_OPERATION", + "ERROR_DLP_POLICY_DENIES_OPERATION", + "ERROR_DLP_POLICY_SILENTLY_FAIL", + "ERROR_CAPAUTHZ_NOT_DEVUNLOCKED", + "ERROR_CAPAUTHZ_CHANGE_TYPE", + "ERROR_CAPAUTHZ_NOT_PROVISIONED", + "ERROR_CAPAUTHZ_NOT_AUTHORIZED", + "ERROR_CAPAUTHZ_NO_POLICY", + "ERROR_CAPAUTHZ_DB_CORRUPTED", + "ERROR_CAPAUTHZ_SCCD_INVALID_CATALOG", + "ERROR_CAPAUTHZ_SCCD_NO_AUTH_ENTITY", + "ERROR_CAPAUTHZ_SCCD_PARSE_ERROR", + "ERROR_CAPAUTHZ_SCCD_DEV_MODE_REQUIRED", + "ERROR_CAPAUTHZ_SCCD_NO_CAPABILITY_MATCH", + "ERROR_CIMFS_IMAGE_CORRUPT", + "ERROR_PNP_QUERY_REMOVE_DEVICE_TIMEOUT", + "ERROR_PNP_QUERY_REMOVE_RELATED_DEVICE_TIMEOUT", + "ERROR_PNP_QUERY_REMOVE_UNRELATED_DEVICE_TIMEOUT", + "ERROR_DEVICE_HARDWARE_ERROR", + "ERROR_INVALID_ADDRESS", + "ERROR_HAS_SYSTEM_CRITICAL_FILES", + "ERROR_USER_PROFILE_LOAD", + "ERROR_ARITHMETIC_OVERFLOW", + "ERROR_PIPE_CONNECTED", + "ERROR_PIPE_LISTENING", + "ERROR_VERIFIER_STOP", + "ERROR_ABIOS_ERROR", + "ERROR_WX86_WARNING", + "ERROR_WX86_ERROR", + "ERROR_TIMER_NOT_CANCELED", + "ERROR_UNWIND", + "ERROR_BAD_STACK", + "ERROR_INVALID_UNWIND_TARGET", + "ERROR_INVALID_PORT_ATTRIBUTES", + "ERROR_PORT_MESSAGE_TOO_LONG", + "ERROR_INVALID_QUOTA_LOWER", + "ERROR_DEVICE_ALREADY_ATTACHED", + "ERROR_INSTRUCTION_MISALIGNMENT", + "ERROR_PROFILING_NOT_STARTED", + "ERROR_PROFILING_NOT_STOPPED", + "ERROR_COULD_NOT_INTERPRET", + "ERROR_PROFILING_AT_LIMIT", + "ERROR_CANT_WAIT", + "ERROR_CANT_TERMINATE_SELF", + "ERROR_UNEXPECTED_MM_CREATE_ERR", + "ERROR_UNEXPECTED_MM_MAP_ERROR", + "ERROR_UNEXPECTED_MM_EXTEND_ERR", + "ERROR_BAD_FUNCTION_TABLE", + "ERROR_NO_GUID_TRANSLATION", + "ERROR_INVALID_LDT_SIZE", + "ERROR_INVALID_LDT_OFFSET", + "ERROR_INVALID_LDT_DESCRIPTOR", + "ERROR_TOO_MANY_THREADS", + "ERROR_THREAD_NOT_IN_PROCESS", + "ERROR_PAGEFILE_QUOTA_EXCEEDED", + "ERROR_LOGON_SERVER_CONFLICT", + "ERROR_SYNCHRONIZATION_REQUIRED", + "ERROR_NET_OPEN_FAILED", + "ERROR_IO_PRIVILEGE_FAILED", + "ERROR_CONTROL_C_EXIT", + "ERROR_MISSING_SYSTEMFILE", + "ERROR_UNHANDLED_EXCEPTION", + "ERROR_APP_INIT_FAILURE", + "ERROR_PAGEFILE_CREATE_FAILED", + "ERROR_INVALID_IMAGE_HASH", + "ERROR_NO_PAGEFILE", + "ERROR_ILLEGAL_FLOAT_CONTEXT", + "ERROR_NO_EVENT_PAIR", + "ERROR_DOMAIN_CTRLR_CONFIG_ERROR", + "ERROR_ILLEGAL_CHARACTER", + "ERROR_UNDEFINED_CHARACTER", + "ERROR_FLOPPY_VOLUME", + "ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT", + "ERROR_BACKUP_CONTROLLER", + "ERROR_MUTANT_LIMIT_EXCEEDED", + "ERROR_FS_DRIVER_REQUIRED", + "ERROR_CANNOT_LOAD_REGISTRY_FILE", + "ERROR_DEBUG_ATTACH_FAILED", + "ERROR_SYSTEM_PROCESS_TERMINATED", + "ERROR_DATA_NOT_ACCEPTED", + "ERROR_VDM_HARD_ERROR", + "ERROR_DRIVER_CANCEL_TIMEOUT", + "ERROR_REPLY_MESSAGE_MISMATCH", + "ERROR_LOST_WRITEBEHIND_DATA", + "ERROR_CLIENT_SERVER_PARAMETERS_INVALID", + "ERROR_NOT_TINY_STREAM", + "ERROR_STACK_OVERFLOW_READ", + "ERROR_CONVERT_TO_LARGE", + "ERROR_FOUND_OUT_OF_SCOPE", + "ERROR_ALLOCATE_BUCKET", + "ERROR_MARSHALL_OVERFLOW", + "ERROR_INVALID_VARIANT", + "ERROR_BAD_COMPRESSION_BUFFER", + "ERROR_AUDIT_FAILED", + "ERROR_TIMER_RESOLUTION_NOT_SET", + "ERROR_INSUFFICIENT_LOGON_INFO", + "ERROR_BAD_DLL_ENTRYPOINT", + "ERROR_BAD_SERVICE_ENTRYPOINT", + "ERROR_IP_ADDRESS_CONFLICT1", + "ERROR_IP_ADDRESS_CONFLICT2", + "ERROR_REGISTRY_QUOTA_LIMIT", + "ERROR_NO_CALLBACK_ACTIVE", + "ERROR_PWD_TOO_SHORT", + "ERROR_PWD_TOO_RECENT", + "ERROR_PWD_HISTORY_CONFLICT", + "ERROR_UNSUPPORTED_COMPRESSION", + "ERROR_INVALID_HW_PROFILE", + "ERROR_INVALID_PLUGPLAY_DEVICE_PATH", + "ERROR_QUOTA_LIST_INCONSISTENT", + "ERROR_EVALUATION_EXPIRATION", + "ERROR_ILLEGAL_DLL_RELOCATION", + "ERROR_DLL_INIT_FAILED_LOGOFF", + "ERROR_VALIDATE_CONTINUE", + "ERROR_NO_MORE_MATCHES", + "ERROR_RANGE_LIST_CONFLICT", + "ERROR_SERVER_SID_MISMATCH", + "ERROR_CANT_ENABLE_DENY_ONLY", + "ERROR_FLOAT_MULTIPLE_FAULTS", + "ERROR_FLOAT_MULTIPLE_TRAPS", + "ERROR_NOINTERFACE", + "ERROR_DRIVER_FAILED_SLEEP", + "ERROR_CORRUPT_SYSTEM_FILE", + "ERROR_COMMITMENT_MINIMUM", + "ERROR_PNP_RESTART_ENUMERATION", + "ERROR_SYSTEM_IMAGE_BAD_SIGNATURE", + "ERROR_PNP_REBOOT_REQUIRED", + "ERROR_INSUFFICIENT_POWER", + "ERROR_MULTIPLE_FAULT_VIOLATION", + "ERROR_SYSTEM_SHUTDOWN", + "ERROR_PORT_NOT_SET", + "ERROR_DS_VERSION_CHECK_FAILURE", + "ERROR_RANGE_NOT_FOUND", + "ERROR_NOT_SAFE_MODE_DRIVER", + "ERROR_FAILED_DRIVER_ENTRY", + "ERROR_DEVICE_ENUMERATION_ERROR", + "ERROR_MOUNT_POINT_NOT_RESOLVED", + "ERROR_INVALID_DEVICE_OBJECT_PARAMETER", + "ERROR_MCA_OCCURED", + "ERROR_DRIVER_DATABASE_ERROR", + "ERROR_SYSTEM_HIVE_TOO_LARGE", + "ERROR_DRIVER_FAILED_PRIOR_UNLOAD", + "ERROR_VOLSNAP_PREPARE_HIBERNATE", + "ERROR_HIBERNATION_FAILURE", + "ERROR_PWD_TOO_LONG", + "ERROR_FILE_SYSTEM_LIMITATION", + "ERROR_ASSERTION_FAILURE", + "ERROR_ACPI_ERROR", + "ERROR_WOW_ASSERTION", + "ERROR_PNP_BAD_MPS_TABLE", + "ERROR_PNP_TRANSLATION_FAILED", + "ERROR_PNP_IRQ_TRANSLATION_FAILED", + "ERROR_PNP_INVALID_ID", + "ERROR_WAKE_SYSTEM_DEBUGGER", + "ERROR_HANDLES_CLOSED", + "ERROR_EXTRANEOUS_INFORMATION", + "ERROR_RXACT_COMMIT_NECESSARY", + "ERROR_MEDIA_CHECK", + "ERROR_GUID_SUBSTITUTION_MADE", + "ERROR_STOPPED_ON_SYMLINK", + "ERROR_LONGJUMP", + "ERROR_PLUGPLAY_QUERY_VETOED", + "ERROR_UNWIND_CONSOLIDATE", + "ERROR_REGISTRY_HIVE_RECOVERED", + "ERROR_DLL_MIGHT_BE_INSECURE", + "ERROR_DLL_MIGHT_BE_INCOMPATIBLE", + "ERROR_DBG_EXCEPTION_NOT_HANDLED", + "ERROR_DBG_REPLY_LATER", + "ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE", + "ERROR_DBG_TERMINATE_THREAD", + "ERROR_DBG_TERMINATE_PROCESS", + "ERROR_DBG_CONTROL_C", + "ERROR_DBG_PRINTEXCEPTION_C", + "ERROR_DBG_RIPEXCEPTION", + "ERROR_DBG_CONTROL_BREAK", + "ERROR_DBG_COMMAND_EXCEPTION", + "ERROR_OBJECT_NAME_EXISTS", + "ERROR_THREAD_WAS_SUSPENDED", + "ERROR_IMAGE_NOT_AT_BASE", + "ERROR_RXACT_STATE_CREATED", + "ERROR_SEGMENT_NOTIFICATION", + "ERROR_BAD_CURRENT_DIRECTORY", + "ERROR_FT_READ_RECOVERY_FROM_BACKUP", + "ERROR_FT_WRITE_RECOVERY", + "ERROR_IMAGE_MACHINE_TYPE_MISMATCH", + "ERROR_RECEIVE_PARTIAL", + "ERROR_RECEIVE_EXPEDITED", + "ERROR_RECEIVE_PARTIAL_EXPEDITED", + "ERROR_EVENT_DONE", + "ERROR_EVENT_PENDING", + "ERROR_CHECKING_FILE_SYSTEM", + "ERROR_FATAL_APP_EXIT", + "ERROR_PREDEFINED_HANDLE", + "ERROR_WAS_UNLOCKED", + "ERROR_SERVICE_NOTIFICATION", + "ERROR_WAS_LOCKED", + "ERROR_LOG_HARD_ERROR", + "ERROR_ALREADY_WIN32", + "ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE", + "ERROR_NO_YIELD_PERFORMED", + "ERROR_TIMER_RESUME_IGNORED", + "ERROR_ARBITRATION_UNHANDLED", + "ERROR_CARDBUS_NOT_SUPPORTED", + "ERROR_MP_PROCESSOR_MISMATCH", + "ERROR_HIBERNATED", + "ERROR_RESUME_HIBERNATION", + "ERROR_FIRMWARE_UPDATED", + "ERROR_DRIVERS_LEAKING_LOCKED_PAGES", + "ERROR_WAKE_SYSTEM", + "ERROR_WAIT_1", + "ERROR_WAIT_2", + "ERROR_WAIT_3", + "ERROR_WAIT_63", + "ERROR_ABANDONED_WAIT_0", + "ERROR_ABANDONED_WAIT_63", + "ERROR_USER_APC", + "ERROR_KERNEL_APC", + "ERROR_ALERTED", + "ERROR_ELEVATION_REQUIRED", + "ERROR_REPARSE", + "ERROR_OPLOCK_BREAK_IN_PROGRESS", + "ERROR_VOLUME_MOUNTED", + "ERROR_RXACT_COMMITTED", + "ERROR_NOTIFY_CLEANUP", + "ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED", + "ERROR_PAGE_FAULT_TRANSITION", + "ERROR_PAGE_FAULT_DEMAND_ZERO", + "ERROR_PAGE_FAULT_COPY_ON_WRITE", + "ERROR_PAGE_FAULT_GUARD_PAGE", + "ERROR_PAGE_FAULT_PAGING_FILE", + "ERROR_CACHE_PAGE_LOCKED", + "ERROR_CRASH_DUMP", + "ERROR_BUFFER_ALL_ZEROS", + "ERROR_REPARSE_OBJECT", + "ERROR_RESOURCE_REQUIREMENTS_CHANGED", + "ERROR_TRANSLATION_COMPLETE", + "ERROR_NOTHING_TO_TERMINATE", + "ERROR_PROCESS_NOT_IN_JOB", + "ERROR_PROCESS_IN_JOB", + "ERROR_VOLSNAP_HIBERNATE_READY", + "ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY", + "ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED", + "ERROR_INTERRUPT_STILL_CONNECTED", + "ERROR_WAIT_FOR_OPLOCK", + "ERROR_DBG_EXCEPTION_HANDLED", + "ERROR_DBG_CONTINUE", + "ERROR_CALLBACK_POP_STACK", + "ERROR_COMPRESSION_DISABLED", + "ERROR_CANTFETCHBACKWARDS", + "ERROR_CANTSCROLLBACKWARDS", + "ERROR_ROWSNOTRELEASED", + "ERROR_BAD_ACCESSOR_FLAGS", + "ERROR_ERRORS_ENCOUNTERED", + "ERROR_NOT_CAPABLE", + "ERROR_REQUEST_OUT_OF_SEQUENCE", + "ERROR_VERSION_PARSE_ERROR", + "ERROR_BADSTARTPOSITION", + "ERROR_MEMORY_HARDWARE", + "ERROR_DISK_REPAIR_DISABLED", + "ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE", + "ERROR_SYSTEM_POWERSTATE_TRANSITION", + "ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION", + "ERROR_MCA_EXCEPTION", + "ERROR_ACCESS_AUDIT_BY_POLICY", + "ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY", + "ERROR_ABANDON_HIBERFILE", + "ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED", + "ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR", + "ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR", + "ERROR_BAD_MCFG_TABLE", + "ERROR_DISK_REPAIR_REDIRECTED", + "ERROR_DISK_REPAIR_UNSUCCESSFUL", + "ERROR_CORRUPT_LOG_OVERFULL", + "ERROR_CORRUPT_LOG_CORRUPTED", + "ERROR_CORRUPT_LOG_UNAVAILABLE", + "ERROR_CORRUPT_LOG_DELETED_FULL", + "ERROR_CORRUPT_LOG_CLEARED", + "ERROR_ORPHAN_NAME_EXHAUSTED", + "ERROR_OPLOCK_SWITCHED_TO_NEW_HANDLE", + "ERROR_CANNOT_GRANT_REQUESTED_OPLOCK", + "ERROR_CANNOT_BREAK_OPLOCK", + "ERROR_OPLOCK_HANDLE_CLOSED", + "ERROR_NO_ACE_CONDITION", + "ERROR_INVALID_ACE_CONDITION", + "ERROR_FILE_HANDLE_REVOKED", + "ERROR_IMAGE_AT_DIFFERENT_BASE", + "ERROR_ENCRYPTED_IO_NOT_POSSIBLE", + "ERROR_FILE_METADATA_OPTIMIZATION_IN_PROGRESS", + "ERROR_QUOTA_ACTIVITY", + "ERROR_HANDLE_REVOKED", + "ERROR_CALLBACK_INVOKE_INLINE", + "ERROR_CPU_SET_INVALID", + "ERROR_ENCLAVE_NOT_TERMINATED", + "ERROR_ENCLAVE_VIOLATION", + "ERROR_EA_ACCESS_DENIED", + "ERROR_OPERATION_ABORTED", + "ERROR_IO_INCOMPLETE", + "ERROR_IO_PENDING", + "ERROR_NOACCESS", + "ERROR_SWAPERROR", + "ERROR_STACK_OVERFLOW", + "ERROR_INVALID_MESSAGE", + "ERROR_CAN_NOT_COMPLETE", + "ERROR_INVALID_FLAGS", + "ERROR_UNRECOGNIZED_VOLUME", + "ERROR_FILE_INVALID", + "ERROR_FULLSCREEN_MODE", + "ERROR_NO_TOKEN", + "ERROR_BADDB", + "ERROR_BADKEY", + "ERROR_CANTOPEN", + "ERROR_CANTREAD", + "ERROR_CANTWRITE", + "ERROR_REGISTRY_RECOVERED", + "ERROR_REGISTRY_CORRUPT", + "ERROR_REGISTRY_IO_FAILED", + "ERROR_NOT_REGISTRY_FILE", + "ERROR_KEY_DELETED", + "ERROR_NO_LOG_SPACE", + "ERROR_KEY_HAS_CHILDREN", + "ERROR_CHILD_MUST_BE_VOLATILE", + "ERROR_NOTIFY_ENUM_DIR", + "ERROR_DEPENDENT_SERVICES_RUNNING", + "ERROR_INVALID_SERVICE_CONTROL", + "ERROR_SERVICE_REQUEST_TIMEOUT", + "ERROR_SERVICE_NO_THREAD", + "ERROR_SERVICE_DATABASE_LOCKED", + "ERROR_SERVICE_ALREADY_RUNNING", + "ERROR_INVALID_SERVICE_ACCOUNT", + "ERROR_SERVICE_DISABLED", + "ERROR_CIRCULAR_DEPENDENCY", + "ERROR_SERVICE_DOES_NOT_EXIST", + "ERROR_SERVICE_CANNOT_ACCEPT_CTRL", + "ERROR_SERVICE_NOT_ACTIVE", + "ERROR_FAILED_SERVICE_CONTROLLER_CONNECT", + "ERROR_EXCEPTION_IN_SERVICE", + "ERROR_DATABASE_DOES_NOT_EXIST", + "ERROR_SERVICE_SPECIFIC_ERROR", + "ERROR_PROCESS_ABORTED", + "ERROR_SERVICE_DEPENDENCY_FAIL", + "ERROR_SERVICE_LOGON_FAILED", + "ERROR_SERVICE_START_HANG", + "ERROR_INVALID_SERVICE_LOCK", + "ERROR_SERVICE_MARKED_FOR_DELETE", + "ERROR_SERVICE_EXISTS", + "ERROR_ALREADY_RUNNING_LKG", + "ERROR_SERVICE_DEPENDENCY_DELETED", + "ERROR_BOOT_ALREADY_ACCEPTED", + "ERROR_SERVICE_NEVER_STARTED", + "ERROR_DUPLICATE_SERVICE_NAME", + "ERROR_DIFFERENT_SERVICE_ACCOUNT", + "ERROR_CANNOT_DETECT_DRIVER_FAILURE", + "ERROR_CANNOT_DETECT_PROCESS_ABORT", + "ERROR_NO_RECOVERY_PROGRAM", + "ERROR_SERVICE_NOT_IN_EXE", + "ERROR_NOT_SAFEBOOT_SERVICE", + "ERROR_END_OF_MEDIA", + "ERROR_FILEMARK_DETECTED", + "ERROR_BEGINNING_OF_MEDIA", + "ERROR_SETMARK_DETECTED", + "ERROR_NO_DATA_DETECTED", + "ERROR_PARTITION_FAILURE", + "ERROR_INVALID_BLOCK_LENGTH", + "ERROR_DEVICE_NOT_PARTITIONED", + "ERROR_UNABLE_TO_LOCK_MEDIA", + "ERROR_UNABLE_TO_UNLOAD_MEDIA", + "ERROR_MEDIA_CHANGED", + "ERROR_BUS_RESET", + "ERROR_NO_MEDIA_IN_DRIVE", + "ERROR_NO_UNICODE_TRANSLATION", + "ERROR_DLL_INIT_FAILED", + "ERROR_SHUTDOWN_IN_PROGRESS", + "ERROR_NO_SHUTDOWN_IN_PROGRESS", + "ERROR_IO_DEVICE", + "ERROR_SERIAL_NO_DEVICE", + "ERROR_IRQ_BUSY", + "ERROR_MORE_WRITES", + "ERROR_COUNTER_TIMEOUT", + "ERROR_FLOPPY_ID_MARK_NOT_FOUND", + "ERROR_FLOPPY_WRONG_CYLINDER", + "ERROR_FLOPPY_UNKNOWN_ERROR", + "ERROR_FLOPPY_BAD_REGISTERS", + "ERROR_DISK_RECALIBRATE_FAILED", + "ERROR_DISK_OPERATION_FAILED", + "ERROR_DISK_RESET_FAILED", + "ERROR_EOM_OVERFLOW", + "ERROR_NOT_ENOUGH_SERVER_MEMORY", + "ERROR_POSSIBLE_DEADLOCK", + "ERROR_MAPPED_ALIGNMENT", + "ERROR_SET_POWER_STATE_VETOED", + "ERROR_SET_POWER_STATE_FAILED", + "ERROR_TOO_MANY_LINKS", + "ERROR_OLD_WIN_VERSION", + "ERROR_APP_WRONG_OS", + "ERROR_SINGLE_INSTANCE_APP", + "ERROR_RMODE_APP", + "ERROR_INVALID_DLL", + "ERROR_NO_ASSOCIATION", + "ERROR_DDE_FAIL", + "ERROR_DLL_NOT_FOUND", + "ERROR_NO_MORE_USER_HANDLES", + "ERROR_MESSAGE_SYNC_ONLY", + "ERROR_SOURCE_ELEMENT_EMPTY", + "ERROR_DESTINATION_ELEMENT_FULL", + "ERROR_ILLEGAL_ELEMENT_ADDRESS", + "ERROR_MAGAZINE_NOT_PRESENT", + "ERROR_DEVICE_REINITIALIZATION_NEEDED", + "ERROR_DEVICE_REQUIRES_CLEANING", + "ERROR_DEVICE_DOOR_OPEN", + "ERROR_DEVICE_NOT_CONNECTED", + "ERROR_NOT_FOUND", + "ERROR_NO_MATCH", + "ERROR_SET_NOT_FOUND", + "ERROR_POINT_NOT_FOUND", + "ERROR_NO_TRACKING_SERVICE", + "ERROR_NO_VOLUME_ID", + "ERROR_UNABLE_TO_REMOVE_REPLACED", + "ERROR_UNABLE_TO_MOVE_REPLACEMENT", + "ERROR_UNABLE_TO_MOVE_REPLACEMENT_2", + "ERROR_JOURNAL_DELETE_IN_PROGRESS", + "ERROR_JOURNAL_NOT_ACTIVE", + "ERROR_POTENTIAL_FILE_FOUND", + "ERROR_JOURNAL_ENTRY_DELETED", + "ERROR_VRF_CFG_AND_IO_ENABLED", + "ERROR_PARTITION_TERMINATING", + "ERROR_SHUTDOWN_IS_SCHEDULED", + "ERROR_SHUTDOWN_USERS_LOGGED_ON", + "ERROR_BAD_DEVICE", + "ERROR_CONNECTION_UNAVAIL", + "ERROR_DEVICE_ALREADY_REMEMBERED", + "ERROR_NO_NET_OR_BAD_PATH", + "ERROR_BAD_PROVIDER", + "ERROR_CANNOT_OPEN_PROFILE", + "ERROR_BAD_PROFILE", + "ERROR_NOT_CONTAINER", + "ERROR_EXTENDED_ERROR", + "ERROR_INVALID_GROUPNAME", + "ERROR_INVALID_COMPUTERNAME", + "ERROR_INVALID_EVENTNAME", + "ERROR_INVALID_DOMAINNAME", + "ERROR_INVALID_SERVICENAME", + "ERROR_INVALID_NETNAME", + "ERROR_INVALID_SHARENAME", + "ERROR_INVALID_PASSWORDNAME", + "ERROR_INVALID_MESSAGENAME", + "ERROR_INVALID_MESSAGEDEST", + "ERROR_SESSION_CREDENTIAL_CONFLICT", + "ERROR_REMOTE_SESSION_LIMIT_EXCEEDED", + "ERROR_DUP_DOMAINNAME", + "ERROR_NO_NETWORK", + "ERROR_CANCELLED", + "ERROR_USER_MAPPED_FILE", + "ERROR_CONNECTION_REFUSED", + "ERROR_GRACEFUL_DISCONNECT", + "ERROR_ADDRESS_ALREADY_ASSOCIATED", + "ERROR_ADDRESS_NOT_ASSOCIATED", + "ERROR_CONNECTION_INVALID", + "ERROR_CONNECTION_ACTIVE", + "ERROR_NETWORK_UNREACHABLE", + "ERROR_HOST_UNREACHABLE", + "ERROR_PROTOCOL_UNREACHABLE", + "ERROR_PORT_UNREACHABLE", + "ERROR_REQUEST_ABORTED", + "ERROR_CONNECTION_ABORTED", + "ERROR_RETRY", + "ERROR_CONNECTION_COUNT_LIMIT", + "ERROR_LOGIN_TIME_RESTRICTION", + "ERROR_LOGIN_WKSTA_RESTRICTION", + "ERROR_INCORRECT_ADDRESS", + "ERROR_ALREADY_REGISTERED", + "ERROR_SERVICE_NOT_FOUND", + "ERROR_NOT_AUTHENTICATED", + "ERROR_NOT_LOGGED_ON", + "ERROR_CONTINUE", + "ERROR_ALREADY_INITIALIZED", + "ERROR_NO_MORE_DEVICES", + "ERROR_NO_SUCH_SITE", + "ERROR_DOMAIN_CONTROLLER_EXISTS", + "ERROR_ONLY_IF_CONNECTED", + "ERROR_OVERRIDE_NOCHANGES", + "ERROR_BAD_USER_PROFILE", + "ERROR_NOT_SUPPORTED_ON_SBS", + "ERROR_SERVER_SHUTDOWN_IN_PROGRESS", + "ERROR_HOST_DOWN", + "ERROR_NON_ACCOUNT_SID", + "ERROR_NON_DOMAIN_SID", + "ERROR_APPHELP_BLOCK", + "ERROR_ACCESS_DISABLED_BY_POLICY", + "ERROR_REG_NAT_CONSUMPTION", + "ERROR_CSCSHARE_OFFLINE", + "ERROR_PKINIT_FAILURE", + "ERROR_SMARTCARD_SUBSYSTEM_FAILURE", + "ERROR_DOWNGRADE_DETECTED", + "ERROR_MACHINE_LOCKED", + "ERROR_SMB_GUEST_LOGON_BLOCKED", + "ERROR_CALLBACK_SUPPLIED_INVALID_DATA", + "ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED", + "ERROR_DRIVER_BLOCKED", + "ERROR_INVALID_IMPORT_OF_NON_DLL", + "ERROR_ACCESS_DISABLED_WEBBLADE", + "ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER", + "ERROR_RECOVERY_FAILURE", + "ERROR_ALREADY_FIBER", + "ERROR_ALREADY_THREAD", + "ERROR_STACK_BUFFER_OVERRUN", + "ERROR_PARAMETER_QUOTA_EXCEEDED", + "ERROR_DEBUGGER_INACTIVE", + "ERROR_DELAY_LOAD_FAILED", + "ERROR_VDM_DISALLOWED", + "ERROR_UNIDENTIFIED_ERROR", + "ERROR_INVALID_CRUNTIME_PARAMETER", + "ERROR_BEYOND_VDL", + "ERROR_INCOMPATIBLE_SERVICE_SID_TYPE", + "ERROR_DRIVER_PROCESS_TERMINATED", + "ERROR_IMPLEMENTATION_LIMIT", + "ERROR_PROCESS_IS_PROTECTED", + "ERROR_SERVICE_NOTIFY_CLIENT_LAGGING", + "ERROR_DISK_QUOTA_EXCEEDED", + "ERROR_CONTENT_BLOCKED", + "ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE", + "ERROR_APP_HANG", + "ERROR_INVALID_LABEL", + "ERROR_NOT_ALL_ASSIGNED", + "ERROR_SOME_NOT_MAPPED", + "ERROR_NO_QUOTAS_FOR_ACCOUNT", + "ERROR_LOCAL_USER_SESSION_KEY", + "ERROR_NULL_LM_PASSWORD", + "ERROR_UNKNOWN_REVISION", + "ERROR_REVISION_MISMATCH", + "ERROR_INVALID_OWNER", + "ERROR_INVALID_PRIMARY_GROUP", + "ERROR_NO_IMPERSONATION_TOKEN", + "ERROR_CANT_DISABLE_MANDATORY", + "ERROR_NO_LOGON_SERVERS", + "ERROR_NO_SUCH_LOGON_SESSION", + "ERROR_NO_SUCH_PRIVILEGE", + "ERROR_PRIVILEGE_NOT_HELD", + "ERROR_INVALID_ACCOUNT_NAME", + "ERROR_USER_EXISTS", + "ERROR_NO_SUCH_USER", + "ERROR_GROUP_EXISTS", + "ERROR_NO_SUCH_GROUP", + "ERROR_MEMBER_IN_GROUP", + "ERROR_MEMBER_NOT_IN_GROUP", + "ERROR_LAST_ADMIN", + "ERROR_WRONG_PASSWORD", + "ERROR_ILL_FORMED_PASSWORD", + "ERROR_PASSWORD_RESTRICTION", + "ERROR_LOGON_FAILURE", + "ERROR_ACCOUNT_RESTRICTION", + "ERROR_INVALID_LOGON_HOURS", + "ERROR_INVALID_WORKSTATION", + "ERROR_PASSWORD_EXPIRED", + "ERROR_ACCOUNT_DISABLED", + "ERROR_NONE_MAPPED", + "ERROR_TOO_MANY_LUIDS_REQUESTED", + "ERROR_LUIDS_EXHAUSTED", + "ERROR_INVALID_SUB_AUTHORITY", + "ERROR_INVALID_ACL", + "ERROR_INVALID_SID", + "ERROR_INVALID_SECURITY_DESCR", + "ERROR_BAD_INHERITANCE_ACL", + "ERROR_SERVER_DISABLED", + "ERROR_SERVER_NOT_DISABLED", + "ERROR_INVALID_ID_AUTHORITY", + "ERROR_ALLOTTED_SPACE_EXCEEDED", + "ERROR_INVALID_GROUP_ATTRIBUTES", + "ERROR_BAD_IMPERSONATION_LEVEL", + "ERROR_CANT_OPEN_ANONYMOUS", + "ERROR_BAD_VALIDATION_CLASS", + "ERROR_BAD_TOKEN_TYPE", + "ERROR_NO_SECURITY_ON_OBJECT", + "ERROR_CANT_ACCESS_DOMAIN_INFO", + "ERROR_INVALID_SERVER_STATE", + "ERROR_INVALID_DOMAIN_STATE", + "ERROR_INVALID_DOMAIN_ROLE", + "ERROR_NO_SUCH_DOMAIN", + "ERROR_DOMAIN_EXISTS", + "ERROR_DOMAIN_LIMIT_EXCEEDED", + "ERROR_INTERNAL_DB_CORRUPTION", + "ERROR_INTERNAL_ERROR", + "ERROR_GENERIC_NOT_MAPPED", + "ERROR_BAD_DESCRIPTOR_FORMAT", + "ERROR_NOT_LOGON_PROCESS", + "ERROR_LOGON_SESSION_EXISTS", + "ERROR_NO_SUCH_PACKAGE", + "ERROR_BAD_LOGON_SESSION_STATE", + "ERROR_LOGON_SESSION_COLLISION", + "ERROR_INVALID_LOGON_TYPE", + "ERROR_CANNOT_IMPERSONATE", + "ERROR_RXACT_INVALID_STATE", + "ERROR_RXACT_COMMIT_FAILURE", + "ERROR_SPECIAL_ACCOUNT", + "ERROR_SPECIAL_GROUP", + "ERROR_SPECIAL_USER", + "ERROR_MEMBERS_PRIMARY_GROUP", + "ERROR_TOKEN_ALREADY_IN_USE", + "ERROR_NO_SUCH_ALIAS", + "ERROR_MEMBER_NOT_IN_ALIAS", + "ERROR_MEMBER_IN_ALIAS", + "ERROR_ALIAS_EXISTS", + "ERROR_LOGON_NOT_GRANTED", + "ERROR_TOO_MANY_SECRETS", + "ERROR_SECRET_TOO_LONG", + "ERROR_INTERNAL_DB_ERROR", + "ERROR_TOO_MANY_CONTEXT_IDS", + "ERROR_LOGON_TYPE_NOT_GRANTED", + "ERROR_NT_CROSS_ENCRYPTION_REQUIRED", + "ERROR_NO_SUCH_MEMBER", + "ERROR_INVALID_MEMBER", + "ERROR_TOO_MANY_SIDS", + "ERROR_LM_CROSS_ENCRYPTION_REQUIRED", + "ERROR_NO_INHERITANCE", + "ERROR_FILE_CORRUPT", + "ERROR_DISK_CORRUPT", + "ERROR_NO_USER_SESSION_KEY", + "ERROR_LICENSE_QUOTA_EXCEEDED", + "ERROR_WRONG_TARGET_NAME", + "ERROR_MUTUAL_AUTH_FAILED", + "ERROR_TIME_SKEW", + "ERROR_CURRENT_DOMAIN_NOT_ALLOWED", + "ERROR_INVALID_WINDOW_HANDLE", + "ERROR_INVALID_MENU_HANDLE", + "ERROR_INVALID_CURSOR_HANDLE", + "ERROR_INVALID_ACCEL_HANDLE", + "ERROR_INVALID_HOOK_HANDLE", + "ERROR_INVALID_DWP_HANDLE", + "ERROR_TLW_WITH_WSCHILD", + "ERROR_CANNOT_FIND_WND_CLASS", + "ERROR_WINDOW_OF_OTHER_THREAD", + "ERROR_HOTKEY_ALREADY_REGISTERED", + "ERROR_CLASS_ALREADY_EXISTS", + "ERROR_CLASS_DOES_NOT_EXIST", + "ERROR_CLASS_HAS_WINDOWS", + "ERROR_INVALID_INDEX", + "ERROR_INVALID_ICON_HANDLE", + "ERROR_PRIVATE_DIALOG_INDEX", + "ERROR_LISTBOX_ID_NOT_FOUND", + "ERROR_NO_WILDCARD_CHARACTERS", + "ERROR_CLIPBOARD_NOT_OPEN", + "ERROR_HOTKEY_NOT_REGISTERED", + "ERROR_WINDOW_NOT_DIALOG", + "ERROR_CONTROL_ID_NOT_FOUND", + "ERROR_INVALID_COMBOBOX_MESSAGE", + "ERROR_WINDOW_NOT_COMBOBOX", + "ERROR_INVALID_EDIT_HEIGHT", + "ERROR_DC_NOT_FOUND", + "ERROR_INVALID_HOOK_FILTER", + "ERROR_INVALID_FILTER_PROC", + "ERROR_HOOK_NEEDS_HMOD", + "ERROR_GLOBAL_ONLY_HOOK", + "ERROR_JOURNAL_HOOK_SET", + "ERROR_HOOK_NOT_INSTALLED", + "ERROR_INVALID_LB_MESSAGE", + "ERROR_SETCOUNT_ON_BAD_LB", + "ERROR_LB_WITHOUT_TABSTOPS", + "ERROR_DESTROY_OBJECT_OF_OTHER_THREAD", + "ERROR_CHILD_WINDOW_MENU", + "ERROR_NO_SYSTEM_MENU", + "ERROR_INVALID_MSGBOX_STYLE", + "ERROR_INVALID_SPI_VALUE", + "ERROR_SCREEN_ALREADY_LOCKED", + "ERROR_HWNDS_HAVE_DIFF_PARENT", + "ERROR_NOT_CHILD_WINDOW", + "ERROR_INVALID_GW_COMMAND", + "ERROR_INVALID_THREAD_ID", + "ERROR_NON_MDICHILD_WINDOW", + "ERROR_POPUP_ALREADY_ACTIVE", + "ERROR_NO_SCROLLBARS", + "ERROR_INVALID_SCROLLBAR_RANGE", + "ERROR_INVALID_SHOWWIN_COMMAND", + "ERROR_NO_SYSTEM_RESOURCES", + "ERROR_NONPAGED_SYSTEM_RESOURCES", + "ERROR_PAGED_SYSTEM_RESOURCES", + "ERROR_WORKING_SET_QUOTA", + "ERROR_PAGEFILE_QUOTA", + "ERROR_COMMITMENT_LIMIT", + "ERROR_MENU_ITEM_NOT_FOUND", + "ERROR_INVALID_KEYBOARD_HANDLE", + "ERROR_HOOK_TYPE_NOT_ALLOWED", + "ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION", + "ERROR_TIMEOUT", + "ERROR_INVALID_MONITOR_HANDLE", + "ERROR_INCORRECT_SIZE", + "ERROR_SYMLINK_CLASS_DISABLED", + "ERROR_SYMLINK_NOT_SUPPORTED", + "ERROR_XML_PARSE_ERROR", + "ERROR_XMLDSIG_ERROR", + "ERROR_RESTART_APPLICATION", + "ERROR_WRONG_COMPARTMENT", + "ERROR_AUTHIP_FAILURE", + "ERROR_NO_NVRAM_RESOURCES", + "ERROR_NOT_GUI_PROCESS", + "ERROR_EVENTLOG_FILE_CORRUPT", + "ERROR_EVENTLOG_CANT_START", + "ERROR_LOG_FILE_FULL", + "ERROR_EVENTLOG_FILE_CHANGED", + "ERROR_CONTAINER_ASSIGNED", + "ERROR_JOB_NO_CONTAINER", + "ERROR_INVALID_TASK_NAME", + "ERROR_INVALID_TASK_INDEX", + "ERROR_THREAD_ALREADY_IN_TASK", + "ERROR_INSTALL_SERVICE_FAILURE", + "ERROR_INSTALL_USEREXIT", + "ERROR_INSTALL_FAILURE", + "ERROR_INSTALL_SUSPEND", + "ERROR_UNKNOWN_PRODUCT", + "ERROR_UNKNOWN_FEATURE", + "ERROR_UNKNOWN_COMPONENT", + "ERROR_UNKNOWN_PROPERTY", + "ERROR_INVALID_HANDLE_STATE", + "ERROR_BAD_CONFIGURATION", + "ERROR_INDEX_ABSENT", + "ERROR_INSTALL_SOURCE_ABSENT", + "ERROR_INSTALL_PACKAGE_VERSION", + "ERROR_PRODUCT_UNINSTALLED", + "ERROR_BAD_QUERY_SYNTAX", + "ERROR_INVALID_FIELD", + "ERROR_DEVICE_REMOVED", + "ERROR_INSTALL_ALREADY_RUNNING", + "ERROR_INSTALL_PACKAGE_OPEN_FAILED", + "ERROR_INSTALL_PACKAGE_INVALID", + "ERROR_INSTALL_UI_FAILURE", + "ERROR_INSTALL_LOG_FAILURE", + "ERROR_INSTALL_LANGUAGE_UNSUPPORTED", + "ERROR_INSTALL_TRANSFORM_FAILURE", + "ERROR_INSTALL_PACKAGE_REJECTED", + "ERROR_FUNCTION_NOT_CALLED", + "ERROR_FUNCTION_FAILED", + "ERROR_INVALID_TABLE", + "ERROR_DATATYPE_MISMATCH", + "ERROR_UNSUPPORTED_TYPE", + "ERROR_CREATE_FAILED", + "ERROR_INSTALL_TEMP_UNWRITABLE", + "ERROR_INSTALL_PLATFORM_UNSUPPORTED", + "ERROR_INSTALL_NOTUSED", + "ERROR_PATCH_PACKAGE_OPEN_FAILED", + "ERROR_PATCH_PACKAGE_INVALID", + "ERROR_PATCH_PACKAGE_UNSUPPORTED", + "ERROR_PRODUCT_VERSION", + "ERROR_INVALID_COMMAND_LINE", + "ERROR_INSTALL_REMOTE_DISALLOWED", + "ERROR_SUCCESS_REBOOT_INITIATED", + "ERROR_PATCH_TARGET_NOT_FOUND", + "ERROR_PATCH_PACKAGE_REJECTED", + "ERROR_INSTALL_TRANSFORM_REJECTED", + "ERROR_INSTALL_REMOTE_PROHIBITED", + "ERROR_PATCH_REMOVAL_UNSUPPORTED", + "ERROR_UNKNOWN_PATCH", + "ERROR_PATCH_NO_SEQUENCE", + "ERROR_PATCH_REMOVAL_DISALLOWED", + "ERROR_INVALID_PATCH_XML", + "ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT", + "ERROR_INSTALL_SERVICE_SAFEBOOT", + "ERROR_FAIL_FAST_EXCEPTION", + "ERROR_INSTALL_REJECTED", + "ERROR_DYNAMIC_CODE_BLOCKED", + "ERROR_NOT_SAME_OBJECT", + "ERROR_STRICT_CFG_VIOLATION", + "ERROR_SET_CONTEXT_DENIED", + "ERROR_CROSS_PARTITION_VIOLATION", + "ERROR_RETURN_ADDRESS_HIJACK_ATTEMPT", + "ERROR_INVALID_USER_BUFFER", + "ERROR_UNRECOGNIZED_MEDIA", + "ERROR_NO_TRUST_LSA_SECRET", + "ERROR_NO_TRUST_SAM_ACCOUNT", + "ERROR_TRUSTED_DOMAIN_FAILURE", + "ERROR_TRUSTED_RELATIONSHIP_FAILURE", + "ERROR_TRUST_FAILURE", + "ERROR_NETLOGON_NOT_STARTED", + "ERROR_ACCOUNT_EXPIRED", + "ERROR_REDIRECTOR_HAS_OPEN_HANDLES", + "ERROR_PRINTER_DRIVER_ALREADY_INSTALLED", + "ERROR_UNKNOWN_PORT", + "ERROR_UNKNOWN_PRINTER_DRIVER", + "ERROR_UNKNOWN_PRINTPROCESSOR", + "ERROR_INVALID_SEPARATOR_FILE", + "ERROR_INVALID_PRIORITY", + "ERROR_INVALID_PRINTER_NAME", + "ERROR_PRINTER_ALREADY_EXISTS", + "ERROR_INVALID_PRINTER_COMMAND", + "ERROR_INVALID_DATATYPE", + "ERROR_INVALID_ENVIRONMENT", + "ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", + "ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT", + "ERROR_NOLOGON_SERVER_TRUST_ACCOUNT", + "ERROR_DOMAIN_TRUST_INCONSISTENT", + "ERROR_SERVER_HAS_OPEN_HANDLES", + "ERROR_RESOURCE_DATA_NOT_FOUND", + "ERROR_RESOURCE_TYPE_NOT_FOUND", + "ERROR_RESOURCE_NAME_NOT_FOUND", + "ERROR_RESOURCE_LANG_NOT_FOUND", + "ERROR_NOT_ENOUGH_QUOTA", + "ERROR_INVALID_TIME", + "ERROR_INVALID_FORM_NAME", + "ERROR_INVALID_FORM_SIZE", + "ERROR_ALREADY_WAITING", + "ERROR_PRINTER_DELETED", + "ERROR_INVALID_PRINTER_STATE", + "ERROR_PASSWORD_MUST_CHANGE", + "ERROR_DOMAIN_CONTROLLER_NOT_FOUND", + "ERROR_ACCOUNT_LOCKED_OUT", + "ERROR_NO_SITENAME", + "ERROR_CANT_ACCESS_FILE", + "ERROR_CANT_RESOLVE_FILENAME", + "ERROR_KM_DRIVER_BLOCKED", + "ERROR_CONTEXT_EXPIRED", + "ERROR_PER_USER_TRUST_QUOTA_EXCEEDED", + "ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED", + "ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED", + "ERROR_AUTHENTICATION_FIREWALL_FAILED", + "ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED", + "ERROR_NTLM_BLOCKED", + "ERROR_PASSWORD_CHANGE_REQUIRED", + "ERROR_LOST_MODE_LOGON_RESTRICTION", + "ERROR_INVALID_PIXEL_FORMAT", + "ERROR_BAD_DRIVER", + "ERROR_INVALID_WINDOW_STYLE", + "ERROR_METAFILE_NOT_SUPPORTED", + "ERROR_TRANSFORM_NOT_SUPPORTED", + "ERROR_CLIPPING_NOT_SUPPORTED", + "ERROR_INVALID_CMM", + "ERROR_INVALID_PROFILE", + "ERROR_TAG_NOT_FOUND", + "ERROR_TAG_NOT_PRESENT", + "ERROR_DUPLICATE_TAG", + "ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE", + "ERROR_PROFILE_NOT_FOUND", + "ERROR_INVALID_COLORSPACE", + "ERROR_ICM_NOT_ENABLED", + "ERROR_DELETING_ICM_XFORM", + "ERROR_INVALID_TRANSFORM", + "ERROR_COLORSPACE_MISMATCH", + "ERROR_INVALID_COLORINDEX", + "ERROR_PROFILE_DOES_NOT_MATCH_DEVICE", + "ERROR_CONNECTED_OTHER_PASSWORD", + "ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT", + "ERROR_BAD_USERNAME", + "ERROR_NOT_CONNECTED", + "ERROR_OPEN_FILES", + "ERROR_ACTIVE_CONNECTIONS", + "ERROR_DEVICE_IN_USE", + "ERROR_UNKNOWN_PRINT_MONITOR", + "ERROR_PRINTER_DRIVER_IN_USE", + "ERROR_SPOOL_FILE_NOT_FOUND", + "ERROR_SPL_NO_STARTDOC", + "ERROR_SPL_NO_ADDJOB", + "ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED", + "ERROR_PRINT_MONITOR_ALREADY_INSTALLED", + "ERROR_INVALID_PRINT_MONITOR", + "ERROR_PRINT_MONITOR_IN_USE", + "ERROR_PRINTER_HAS_JOBS_QUEUED", + "ERROR_SUCCESS_REBOOT_REQUIRED", + "ERROR_SUCCESS_RESTART_REQUIRED", + "ERROR_PRINTER_NOT_FOUND", + "ERROR_PRINTER_DRIVER_WARNED", + "ERROR_PRINTER_DRIVER_BLOCKED", + "ERROR_PRINTER_DRIVER_PACKAGE_IN_USE", + "ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND", + "ERROR_FAIL_REBOOT_REQUIRED", + "ERROR_FAIL_REBOOT_INITIATED", + "ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED", + "ERROR_PRINT_JOB_RESTART_REQUIRED", + "ERROR_INVALID_PRINTER_DRIVER_MANIFEST", + "ERROR_PRINTER_NOT_SHAREABLE", + "ERROR_REQUEST_PAUSED", + "ERROR_APPEXEC_CONDITION_NOT_SATISFIED", + "ERROR_APPEXEC_HANDLE_INVALIDATED", + "ERROR_APPEXEC_INVALID_HOST_GENERATION", + "ERROR_APPEXEC_UNEXPECTED_PROCESS_REGISTRATION", + "ERROR_APPEXEC_INVALID_HOST_STATE", + "ERROR_APPEXEC_NO_DONOR", + "ERROR_APPEXEC_HOST_ID_MISMATCH", + "ERROR_APPEXEC_UNKNOWN_USER", + "ERROR_IO_REISSUE_AS_CACHED", + "ERROR_WINS_INTERNAL", + "ERROR_CAN_NOT_DEL_LOCAL_WINS", + "ERROR_STATIC_INIT", + "ERROR_INC_BACKUP", + "ERROR_FULL_BACKUP", + "ERROR_REC_NON_EXISTENT", + "ERROR_RPL_NOT_ALLOWED", + "ERROR_DHCP_ADDRESS_CONFLICT", + "ERROR_WMI_GUID_NOT_FOUND", + "ERROR_WMI_INSTANCE_NOT_FOUND", + "ERROR_WMI_ITEMID_NOT_FOUND", + "ERROR_WMI_TRY_AGAIN", + "ERROR_WMI_DP_NOT_FOUND", + "ERROR_WMI_UNRESOLVED_INSTANCE_REF", + "ERROR_WMI_ALREADY_ENABLED", + "ERROR_WMI_GUID_DISCONNECTED", + "ERROR_WMI_SERVER_UNAVAILABLE", + "ERROR_WMI_DP_FAILED", + "ERROR_WMI_INVALID_MOF", + "ERROR_WMI_INVALID_REGINFO", + "ERROR_WMI_ALREADY_DISABLED", + "ERROR_WMI_READ_ONLY", + "ERROR_WMI_SET_FAILURE", + "ERROR_NOT_APPCONTAINER", + "ERROR_APPCONTAINER_REQUIRED", + "ERROR_NOT_SUPPORTED_IN_APPCONTAINER", + "ERROR_INVALID_PACKAGE_SID_LENGTH", + "ERROR_INVALID_MEDIA", + "ERROR_INVALID_LIBRARY", + "ERROR_INVALID_MEDIA_POOL", + "ERROR_DRIVE_MEDIA_MISMATCH", + "ERROR_MEDIA_OFFLINE", + "ERROR_LIBRARY_OFFLINE", + "ERROR_EMPTY", + "ERROR_NOT_EMPTY", + "ERROR_MEDIA_UNAVAILABLE", + "ERROR_RESOURCE_DISABLED", + "ERROR_INVALID_CLEANER", + "ERROR_UNABLE_TO_CLEAN", + "ERROR_OBJECT_NOT_FOUND", + "ERROR_DATABASE_FAILURE", + "ERROR_DATABASE_FULL", + "ERROR_MEDIA_INCOMPATIBLE", + "ERROR_RESOURCE_NOT_PRESENT", + "ERROR_INVALID_OPERATION", + "ERROR_MEDIA_NOT_AVAILABLE", + "ERROR_DEVICE_NOT_AVAILABLE", + "ERROR_REQUEST_REFUSED", + "ERROR_INVALID_DRIVE_OBJECT", + "ERROR_LIBRARY_FULL", + "ERROR_MEDIUM_NOT_ACCESSIBLE", + "ERROR_UNABLE_TO_LOAD_MEDIUM", + "ERROR_UNABLE_TO_INVENTORY_DRIVE", + "ERROR_UNABLE_TO_INVENTORY_SLOT", + "ERROR_UNABLE_TO_INVENTORY_TRANSPORT", + "ERROR_TRANSPORT_FULL", + "ERROR_CONTROLLING_IEPORT", + "ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA", + "ERROR_CLEANER_SLOT_SET", + "ERROR_CLEANER_SLOT_NOT_SET", + "ERROR_CLEANER_CARTRIDGE_SPENT", + "ERROR_UNEXPECTED_OMID", + "ERROR_CANT_DELETE_LAST_ITEM", + "ERROR_MESSAGE_EXCEEDS_MAX_SIZE", + "ERROR_VOLUME_CONTAINS_SYS_FILES", + "ERROR_INDIGENOUS_TYPE", + "ERROR_NO_SUPPORTING_DRIVES", + "ERROR_CLEANER_CARTRIDGE_INSTALLED", + "ERROR_IEPORT_FULL", + "ERROR_FILE_OFFLINE", + "ERROR_REMOTE_STORAGE_NOT_ACTIVE", + "ERROR_REMOTE_STORAGE_MEDIA_ERROR", + "ERROR_NOT_A_REPARSE_POINT", + "ERROR_REPARSE_ATTRIBUTE_CONFLICT", + "ERROR_INVALID_REPARSE_DATA", + "ERROR_REPARSE_TAG_INVALID", + "ERROR_REPARSE_TAG_MISMATCH", + "ERROR_REPARSE_POINT_ENCOUNTERED", + "ERROR_APP_DATA_NOT_FOUND", + "ERROR_APP_DATA_EXPIRED", + "ERROR_APP_DATA_CORRUPT", + "ERROR_APP_DATA_LIMIT_EXCEEDED", + "ERROR_APP_DATA_REBOOT_REQUIRED", + "ERROR_SECUREBOOT_ROLLBACK_DETECTED", + "ERROR_SECUREBOOT_POLICY_VIOLATION", + "ERROR_SECUREBOOT_INVALID_POLICY", + "ERROR_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND", + "ERROR_SECUREBOOT_POLICY_NOT_SIGNED", + "ERROR_SECUREBOOT_NOT_ENABLED", + "ERROR_SECUREBOOT_FILE_REPLACED", + "ERROR_SECUREBOOT_POLICY_NOT_AUTHORIZED", + "ERROR_SECUREBOOT_POLICY_UNKNOWN", + "ERROR_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION", + "ERROR_SECUREBOOT_PLATFORM_ID_MISMATCH", + "ERROR_SECUREBOOT_POLICY_ROLLBACK_DETECTED", + "ERROR_SECUREBOOT_POLICY_UPGRADE_MISMATCH", + "ERROR_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING", + "ERROR_SECUREBOOT_NOT_BASE_POLICY", + "ERROR_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY", + "ERROR_OFFLOAD_READ_FLT_NOT_SUPPORTED", + "ERROR_OFFLOAD_WRITE_FLT_NOT_SUPPORTED", + "ERROR_OFFLOAD_READ_FILE_NOT_SUPPORTED", + "ERROR_OFFLOAD_WRITE_FILE_NOT_SUPPORTED", + "ERROR_ALREADY_HAS_STREAM_ID", + "ERROR_SMR_GARBAGE_COLLECTION_REQUIRED", + "ERROR_WOF_WIM_HEADER_CORRUPT", + "ERROR_WOF_WIM_RESOURCE_TABLE_CORRUPT", + "ERROR_WOF_FILE_RESOURCE_TABLE_CORRUPT", + "ERROR_VOLUME_NOT_SIS_ENABLED", + "ERROR_SYSTEM_INTEGRITY_ROLLBACK_DETECTED", + "ERROR_SYSTEM_INTEGRITY_POLICY_VIOLATION", + "ERROR_SYSTEM_INTEGRITY_INVALID_POLICY", + "ERROR_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED", + "ERROR_SYSTEM_INTEGRITY_TOO_MANY_POLICIES", + "ERROR_SYSTEM_INTEGRITY_SUPPLEMENTAL_POLICY_NOT_AUTHORIZED", + "ERROR_VSM_NOT_INITIALIZED", + "ERROR_VSM_DMA_PROTECTION_NOT_IN_USE", + "ERROR_PLATFORM_MANIFEST_NOT_AUTHORIZED", + "ERROR_PLATFORM_MANIFEST_INVALID", + "ERROR_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED", + "ERROR_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED", + "ERROR_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND", + "ERROR_PLATFORM_MANIFEST_NOT_ACTIVE", + "ERROR_PLATFORM_MANIFEST_NOT_SIGNED", + "ERROR_DEPENDENT_RESOURCE_EXISTS", + "ERROR_DEPENDENCY_NOT_FOUND", + "ERROR_DEPENDENCY_ALREADY_EXISTS", + "ERROR_RESOURCE_NOT_ONLINE", + "ERROR_HOST_NODE_NOT_AVAILABLE", + "ERROR_RESOURCE_NOT_AVAILABLE", + "ERROR_RESOURCE_NOT_FOUND", + "ERROR_SHUTDOWN_CLUSTER", + "ERROR_CANT_EVICT_ACTIVE_NODE", + "ERROR_OBJECT_ALREADY_EXISTS", + "ERROR_OBJECT_IN_LIST", + "ERROR_GROUP_NOT_AVAILABLE", + "ERROR_GROUP_NOT_FOUND", + "ERROR_GROUP_NOT_ONLINE", + "ERROR_HOST_NODE_NOT_RESOURCE_OWNER", + "ERROR_HOST_NODE_NOT_GROUP_OWNER", + "ERROR_RESMON_CREATE_FAILED", + "ERROR_RESMON_ONLINE_FAILED", + "ERROR_RESOURCE_ONLINE", + "ERROR_QUORUM_RESOURCE", + "ERROR_NOT_QUORUM_CAPABLE", + "ERROR_CLUSTER_SHUTTING_DOWN", + "ERROR_INVALID_STATE", + "ERROR_RESOURCE_PROPERTIES_STORED", + "ERROR_NOT_QUORUM_CLASS", + "ERROR_CORE_RESOURCE", + "ERROR_QUORUM_RESOURCE_ONLINE_FAILED", + "ERROR_QUORUMLOG_OPEN_FAILED", + "ERROR_CLUSTERLOG_CORRUPT", + "ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE", + "ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE", + "ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND", + "ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE", + "ERROR_QUORUM_OWNER_ALIVE", + "ERROR_NETWORK_NOT_AVAILABLE", + "ERROR_NODE_NOT_AVAILABLE", + "ERROR_ALL_NODES_NOT_AVAILABLE", + "ERROR_RESOURCE_FAILED", + "ERROR_CLUSTER_INVALID_NODE", + "ERROR_CLUSTER_NODE_EXISTS", + "ERROR_CLUSTER_JOIN_IN_PROGRESS", + "ERROR_CLUSTER_NODE_NOT_FOUND", + "ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND", + "ERROR_CLUSTER_NETWORK_EXISTS", + "ERROR_CLUSTER_NETWORK_NOT_FOUND", + "ERROR_CLUSTER_NETINTERFACE_EXISTS", + "ERROR_CLUSTER_NETINTERFACE_NOT_FOUND", + "ERROR_CLUSTER_INVALID_REQUEST", + "ERROR_CLUSTER_INVALID_NETWORK_PROVIDER", + "ERROR_CLUSTER_NODE_DOWN", + "ERROR_CLUSTER_NODE_UNREACHABLE", + "ERROR_CLUSTER_NODE_NOT_MEMBER", + "ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS", + "ERROR_CLUSTER_INVALID_NETWORK", + "ERROR_CLUSTER_NODE_UP", + "ERROR_CLUSTER_IPADDR_IN_USE", + "ERROR_CLUSTER_NODE_NOT_PAUSED", + "ERROR_CLUSTER_NO_SECURITY_CONTEXT", + "ERROR_CLUSTER_NETWORK_NOT_INTERNAL", + "ERROR_CLUSTER_NODE_ALREADY_UP", + "ERROR_CLUSTER_NODE_ALREADY_DOWN", + "ERROR_CLUSTER_NETWORK_ALREADY_ONLINE", + "ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE", + "ERROR_CLUSTER_NODE_ALREADY_MEMBER", + "ERROR_CLUSTER_LAST_INTERNAL_NETWORK", + "ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS", + "ERROR_INVALID_OPERATION_ON_QUORUM", + "ERROR_DEPENDENCY_NOT_ALLOWED", + "ERROR_CLUSTER_NODE_PAUSED", + "ERROR_NODE_CANT_HOST_RESOURCE", + "ERROR_CLUSTER_NODE_NOT_READY", + "ERROR_CLUSTER_NODE_SHUTTING_DOWN", + "ERROR_CLUSTER_JOIN_ABORTED", + "ERROR_CLUSTER_INCOMPATIBLE_VERSIONS", + "ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED", + "ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED", + "ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND", + "ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED", + "ERROR_CLUSTER_RESNAME_NOT_FOUND", + "ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED", + "ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST", + "ERROR_CLUSTER_DATABASE_SEQMISMATCH", + "ERROR_RESMON_INVALID_STATE", + "ERROR_CLUSTER_GUM_NOT_LOCKER", + "ERROR_QUORUM_DISK_NOT_FOUND", + "ERROR_DATABASE_BACKUP_CORRUPT", + "ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT", + "ERROR_RESOURCE_PROPERTY_UNCHANGEABLE", + "ERROR_NO_ADMIN_ACCESS_POINT", + "ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE", + "ERROR_CLUSTER_QUORUMLOG_NOT_FOUND", + "ERROR_CLUSTER_MEMBERSHIP_HALT", + "ERROR_CLUSTER_INSTANCE_ID_MISMATCH", + "ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP", + "ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH", + "ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP", + "ERROR_CLUSTER_PARAMETER_MISMATCH", + "ERROR_NODE_CANNOT_BE_CLUSTERED", + "ERROR_CLUSTER_WRONG_OS_VERSION", + "ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME", + "ERROR_CLUSCFG_ALREADY_COMMITTED", + "ERROR_CLUSCFG_ROLLBACK_FAILED", + "ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT", + "ERROR_CLUSTER_OLD_VERSION", + "ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME", + "ERROR_CLUSTER_NO_NET_ADAPTERS", + "ERROR_CLUSTER_POISONED", + "ERROR_CLUSTER_GROUP_MOVING", + "ERROR_CLUSTER_RESOURCE_TYPE_BUSY", + "ERROR_RESOURCE_CALL_TIMED_OUT", + "ERROR_INVALID_CLUSTER_IPV6_ADDRESS", + "ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION", + "ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS", + "ERROR_CLUSTER_PARTIAL_SEND", + "ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION", + "ERROR_CLUSTER_INVALID_STRING_TERMINATION", + "ERROR_CLUSTER_INVALID_STRING_FORMAT", + "ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS", + "ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS", + "ERROR_CLUSTER_NULL_DATA", + "ERROR_CLUSTER_PARTIAL_READ", + "ERROR_CLUSTER_PARTIAL_WRITE", + "ERROR_CLUSTER_CANT_DESERIALIZE_DATA", + "ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT", + "ERROR_CLUSTER_NO_QUORUM", + "ERROR_CLUSTER_INVALID_IPV6_NETWORK", + "ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK", + "ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP", + "ERROR_DEPENDENCY_TREE_TOO_COMPLEX", + "ERROR_EXCEPTION_IN_RESOURCE_CALL", + "ERROR_CLUSTER_RHS_FAILED_INITIALIZATION", + "ERROR_CLUSTER_NOT_INSTALLED", + "ERROR_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE", + "ERROR_CLUSTER_MAX_NODES_IN_CLUSTER", + "ERROR_CLUSTER_TOO_MANY_NODES", + "ERROR_CLUSTER_OBJECT_ALREADY_USED", + "ERROR_NONCORE_GROUPS_FOUND", + "ERROR_FILE_SHARE_RESOURCE_CONFLICT", + "ERROR_CLUSTER_EVICT_INVALID_REQUEST", + "ERROR_CLUSTER_SINGLETON_RESOURCE", + "ERROR_CLUSTER_GROUP_SINGLETON_RESOURCE", + "ERROR_CLUSTER_RESOURCE_PROVIDER_FAILED", + "ERROR_CLUSTER_RESOURCE_CONFIGURATION_ERROR", + "ERROR_CLUSTER_GROUP_BUSY", + "ERROR_CLUSTER_NOT_SHARED_VOLUME", + "ERROR_CLUSTER_INVALID_SECURITY_DESCRIPTOR", + "ERROR_CLUSTER_SHARED_VOLUMES_IN_USE", + "ERROR_CLUSTER_USE_SHARED_VOLUMES_API", + "ERROR_CLUSTER_BACKUP_IN_PROGRESS", + "ERROR_NON_CSV_PATH", + "ERROR_CSV_VOLUME_NOT_LOCAL", + "ERROR_CLUSTER_WATCHDOG_TERMINATING", + "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES", + "ERROR_CLUSTER_INVALID_NODE_WEIGHT", + "ERROR_CLUSTER_RESOURCE_VETOED_CALL", + "ERROR_RESMON_SYSTEM_RESOURCES_LACKING", + "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION", + "ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE", + "ERROR_CLUSTER_GROUP_QUEUED", + "ERROR_CLUSTER_RESOURCE_LOCKED_STATUS", + "ERROR_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED", + "ERROR_CLUSTER_NODE_DRAIN_IN_PROGRESS", + "ERROR_CLUSTER_DISK_NOT_CONNECTED", + "ERROR_DISK_NOT_CSV_CAPABLE", + "ERROR_RESOURCE_NOT_IN_AVAILABLE_STORAGE", + "ERROR_CLUSTER_SHARED_VOLUME_REDIRECTED", + "ERROR_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED", + "ERROR_CLUSTER_CANNOT_RETURN_PROPERTIES", + "ERROR_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES", + "ERROR_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE", + "ERROR_CLUSTER_AFFINITY_CONFLICT", + "ERROR_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE", + "ERROR_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS", + "ERROR_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED", + "ERROR_CLUSTER_UPGRADE_RESTART_REQUIRED", + "ERROR_CLUSTER_UPGRADE_IN_PROGRESS", + "ERROR_CLUSTER_UPGRADE_INCOMPLETE", + "ERROR_CLUSTER_NODE_IN_GRACE_PERIOD", + "ERROR_CLUSTER_CSV_IO_PAUSE_TIMEOUT", + "ERROR_NODE_NOT_ACTIVE_CLUSTER_MEMBER", + "ERROR_CLUSTER_RESOURCE_NOT_MONITORED", + "ERROR_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED", + "ERROR_CLUSTER_RESOURCE_IS_REPLICATED", + "ERROR_CLUSTER_NODE_ISOLATED", + "ERROR_CLUSTER_NODE_QUARANTINED", + "ERROR_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED", + "ERROR_CLUSTER_SPACE_DEGRADED", + "ERROR_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED", + "ERROR_CLUSTER_CSV_INVALID_HANDLE", + "ERROR_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR", + "ERROR_GROUPSET_NOT_AVAILABLE", + "ERROR_GROUPSET_NOT_FOUND", + "ERROR_GROUPSET_CANT_PROVIDE", + "ERROR_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND", + "ERROR_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY", + "ERROR_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION", + "ERROR_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS", + "ERROR_CLUSTER_INVALID_INFRASTRUCTURE_FILESERVER_NAME", + "ERROR_CLUSTERSET_MANAGEMENT_CLUSTER_UNREACHABLE", + "ERROR_ENCRYPTION_FAILED", + "ERROR_DECRYPTION_FAILED", + "ERROR_FILE_ENCRYPTED", + "ERROR_NO_RECOVERY_POLICY", + "ERROR_NO_EFS", + "ERROR_WRONG_EFS", + "ERROR_NO_USER_KEYS", + "ERROR_FILE_NOT_ENCRYPTED", + "ERROR_NOT_EXPORT_FORMAT", + "ERROR_FILE_READ_ONLY", + "ERROR_DIR_EFS_DISALLOWED", + "ERROR_EFS_SERVER_NOT_TRUSTED", + "ERROR_BAD_RECOVERY_POLICY", + "ERROR_EFS_ALG_BLOB_TOO_BIG", + "ERROR_VOLUME_NOT_SUPPORT_EFS", + "ERROR_EFS_DISABLED", + "ERROR_EFS_VERSION_NOT_SUPPORT", + "ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE", + "ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER", + "ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE", + "ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE", + "ERROR_CS_ENCRYPTION_FILE_NOT_CSE", + "ERROR_ENCRYPTION_POLICY_DENIES_OPERATION", + "ERROR_WIP_ENCRYPTION_FAILED", + "ERROR_NO_BROWSER_SERVERS_FOUND", + "ERROR_CLUSTER_OBJECT_IS_CLUSTER_SET_VM", + "ERROR_LOG_SECTOR_INVALID", + "ERROR_LOG_SECTOR_PARITY_INVALID", + "ERROR_LOG_SECTOR_REMAPPED", + "ERROR_LOG_BLOCK_INCOMPLETE", + "ERROR_LOG_INVALID_RANGE", + "ERROR_LOG_BLOCKS_EXHAUSTED", + "ERROR_LOG_READ_CONTEXT_INVALID", + "ERROR_LOG_RESTART_INVALID", + "ERROR_LOG_BLOCK_VERSION", + "ERROR_LOG_BLOCK_INVALID", + "ERROR_LOG_READ_MODE_INVALID", + "ERROR_LOG_NO_RESTART", + "ERROR_LOG_METADATA_CORRUPT", + "ERROR_LOG_METADATA_INVALID", + "ERROR_LOG_METADATA_INCONSISTENT", + "ERROR_LOG_RESERVATION_INVALID", + "ERROR_LOG_CANT_DELETE", + "ERROR_LOG_CONTAINER_LIMIT_EXCEEDED", + "ERROR_LOG_START_OF_LOG", + "ERROR_LOG_POLICY_ALREADY_INSTALLED", + "ERROR_LOG_POLICY_NOT_INSTALLED", + "ERROR_LOG_POLICY_INVALID", + "ERROR_LOG_POLICY_CONFLICT", + "ERROR_LOG_PINNED_ARCHIVE_TAIL", + "ERROR_LOG_RECORD_NONEXISTENT", + "ERROR_LOG_RECORDS_RESERVED_INVALID", + "ERROR_LOG_SPACE_RESERVED_INVALID", + "ERROR_LOG_TAIL_INVALID", + "ERROR_LOG_FULL", + "ERROR_COULD_NOT_RESIZE_LOG", + "ERROR_LOG_MULTIPLEXED", + "ERROR_LOG_DEDICATED", + "ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS", + "ERROR_LOG_ARCHIVE_IN_PROGRESS", + "ERROR_LOG_EPHEMERAL", + "ERROR_LOG_NOT_ENOUGH_CONTAINERS", + "ERROR_LOG_CLIENT_ALREADY_REGISTERED", + "ERROR_LOG_CLIENT_NOT_REGISTERED", + "ERROR_LOG_FULL_HANDLER_IN_PROGRESS", + "ERROR_LOG_CONTAINER_READ_FAILED", + "ERROR_LOG_CONTAINER_WRITE_FAILED", + "ERROR_LOG_CONTAINER_OPEN_FAILED", + "ERROR_LOG_CONTAINER_STATE_INVALID", + "ERROR_LOG_STATE_INVALID", + "ERROR_LOG_PINNED", + "ERROR_LOG_METADATA_FLUSH_FAILED", + "ERROR_LOG_INCONSISTENT_SECURITY", + "ERROR_LOG_APPENDED_FLUSH_FAILED", + "ERROR_LOG_PINNED_RESERVATION", + "ERROR_INVALID_TRANSACTION", + "ERROR_TRANSACTION_NOT_ACTIVE", + "ERROR_TRANSACTION_REQUEST_NOT_VALID", + "ERROR_TRANSACTION_NOT_REQUESTED", + "ERROR_TRANSACTION_ALREADY_ABORTED", + "ERROR_TRANSACTION_ALREADY_COMMITTED", + "ERROR_TM_INITIALIZATION_FAILED", + "ERROR_RESOURCEMANAGER_READ_ONLY", + "ERROR_TRANSACTION_NOT_JOINED", + "ERROR_TRANSACTION_SUPERIOR_EXISTS", + "ERROR_CRM_PROTOCOL_ALREADY_EXISTS", + "ERROR_TRANSACTION_PROPAGATION_FAILED", + "ERROR_CRM_PROTOCOL_NOT_FOUND", + "ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER", + "ERROR_CURRENT_TRANSACTION_NOT_VALID", + "ERROR_TRANSACTION_NOT_FOUND", + "ERROR_RESOURCEMANAGER_NOT_FOUND", + "ERROR_ENLISTMENT_NOT_FOUND", + "ERROR_TRANSACTIONMANAGER_NOT_FOUND", + "ERROR_TRANSACTIONMANAGER_NOT_ONLINE", + "ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION", + "ERROR_TRANSACTION_NOT_ROOT", + "ERROR_TRANSACTION_OBJECT_EXPIRED", + "ERROR_TRANSACTION_RESPONSE_NOT_ENLISTED", + "ERROR_TRANSACTION_RECORD_TOO_LONG", + "ERROR_IMPLICIT_TRANSACTION_NOT_SUPPORTED", + "ERROR_TRANSACTION_INTEGRITY_VIOLATED", + "ERROR_TRANSACTIONMANAGER_IDENTITY_MISMATCH", + "ERROR_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT", + "ERROR_TRANSACTION_MUST_WRITETHROUGH", + "ERROR_TRANSACTION_NO_SUPERIOR", + "ERROR_HEURISTIC_DAMAGE_POSSIBLE", + "ERROR_TRANSACTIONAL_CONFLICT", + "ERROR_RM_NOT_ACTIVE", + "ERROR_RM_METADATA_CORRUPT", + "ERROR_DIRECTORY_NOT_RM", + "ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE", + "ERROR_LOG_RESIZE_INVALID_SIZE", + "ERROR_OBJECT_NO_LONGER_EXISTS", + "ERROR_STREAM_MINIVERSION_NOT_FOUND", + "ERROR_STREAM_MINIVERSION_NOT_VALID", + "ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION", + "ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT", + "ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS", + "ERROR_REMOTE_FILE_VERSION_MISMATCH", + "ERROR_HANDLE_NO_LONGER_VALID", + "ERROR_NO_TXF_METADATA", + "ERROR_LOG_CORRUPTION_DETECTED", + "ERROR_CANT_RECOVER_WITH_HANDLE_OPEN", + "ERROR_RM_DISCONNECTED", + "ERROR_ENLISTMENT_NOT_SUPERIOR", + "ERROR_RECOVERY_NOT_NEEDED", + "ERROR_RM_ALREADY_STARTED", + "ERROR_FILE_IDENTITY_NOT_PERSISTENT", + "ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY", + "ERROR_CANT_CROSS_RM_BOUNDARY", + "ERROR_TXF_DIR_NOT_EMPTY", + "ERROR_INDOUBT_TRANSACTIONS_EXIST", + "ERROR_TM_VOLATILE", + "ERROR_ROLLBACK_TIMER_EXPIRED", + "ERROR_TXF_ATTRIBUTE_CORRUPT", + "ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION", + "ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED", + "ERROR_LOG_GROWTH_FAILED", + "ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE", + "ERROR_TXF_METADATA_ALREADY_PRESENT", + "ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET", + "ERROR_TRANSACTION_REQUIRED_PROMOTION", + "ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION", + "ERROR_TRANSACTIONS_NOT_FROZEN", + "ERROR_TRANSACTION_FREEZE_IN_PROGRESS", + "ERROR_NOT_SNAPSHOT_VOLUME", + "ERROR_NO_SAVEPOINT_WITH_OPEN_FILES", + "ERROR_DATA_LOST_REPAIR", + "ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION", + "ERROR_TM_IDENTITY_MISMATCH", + "ERROR_FLOATED_SECTION", + "ERROR_CANNOT_ACCEPT_TRANSACTED_WORK", + "ERROR_CANNOT_ABORT_TRANSACTIONS", + "ERROR_BAD_CLUSTERS", + "ERROR_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION", + "ERROR_VOLUME_DIRTY", + "ERROR_NO_LINK_TRACKING_IN_TRANSACTION", + "ERROR_OPERATION_NOT_SUPPORTED_IN_TRANSACTION", + "ERROR_EXPIRED_HANDLE", + "ERROR_TRANSACTION_NOT_ENLISTED", + "ERROR_CTX_WINSTATION_NAME_INVALID", + "ERROR_CTX_INVALID_PD", + "ERROR_CTX_PD_NOT_FOUND", + "ERROR_CTX_WD_NOT_FOUND", + "ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY", + "ERROR_CTX_SERVICE_NAME_COLLISION", + "ERROR_CTX_CLOSE_PENDING", + "ERROR_CTX_NO_OUTBUF", + "ERROR_CTX_MODEM_INF_NOT_FOUND", + "ERROR_CTX_INVALID_MODEMNAME", + "ERROR_CTX_MODEM_RESPONSE_ERROR", + "ERROR_CTX_MODEM_RESPONSE_TIMEOUT", + "ERROR_CTX_MODEM_RESPONSE_NO_CARRIER", + "ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE", + "ERROR_CTX_MODEM_RESPONSE_BUSY", + "ERROR_CTX_MODEM_RESPONSE_VOICE", + "ERROR_CTX_TD_ERROR", + "ERROR_CTX_WINSTATION_NOT_FOUND", + "ERROR_CTX_WINSTATION_ALREADY_EXISTS", + "ERROR_CTX_WINSTATION_BUSY", + "ERROR_CTX_BAD_VIDEO_MODE", + "ERROR_CTX_GRAPHICS_INVALID", + "ERROR_CTX_LOGON_DISABLED", + "ERROR_CTX_NOT_CONSOLE", + "ERROR_CTX_CLIENT_QUERY_TIMEOUT", + "ERROR_CTX_CONSOLE_DISCONNECT", + "ERROR_CTX_CONSOLE_CONNECT", + "ERROR_CTX_SHADOW_DENIED", + "ERROR_CTX_WINSTATION_ACCESS_DENIED", + "ERROR_CTX_INVALID_WD", + "ERROR_CTX_SHADOW_INVALID", + "ERROR_CTX_SHADOW_DISABLED", + "ERROR_CTX_CLIENT_LICENSE_IN_USE", + "ERROR_CTX_CLIENT_LICENSE_NOT_SET", + "ERROR_CTX_LICENSE_NOT_AVAILABLE", + "ERROR_CTX_LICENSE_CLIENT_INVALID", + "ERROR_CTX_LICENSE_EXPIRED", + "ERROR_CTX_SHADOW_NOT_RUNNING", + "ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE", + "ERROR_ACTIVATION_COUNT_EXCEEDED", + "ERROR_CTX_WINSTATIONS_DISABLED", + "ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED", + "ERROR_CTX_SESSION_IN_USE", + "ERROR_CTX_NO_FORCE_LOGOFF", + "ERROR_CTX_ACCOUNT_RESTRICTION", + "ERROR_RDP_PROTOCOL_ERROR", + "ERROR_CTX_CDM_CONNECT", + "ERROR_CTX_CDM_DISCONNECT", + "ERROR_CTX_SECURITY_LAYER_ERROR", + "ERROR_TS_INCOMPATIBLE_SESSIONS", + "ERROR_TS_VIDEO_SUBSYSTEM_ERROR", + "ERROR_DS_NOT_INSTALLED", + "ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY", + "ERROR_DS_NO_ATTRIBUTE_OR_VALUE", + "ERROR_DS_INVALID_ATTRIBUTE_SYNTAX", + "ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED", + "ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS", + "ERROR_DS_BUSY", + "ERROR_DS_UNAVAILABLE", + "ERROR_DS_NO_RIDS_ALLOCATED", + "ERROR_DS_NO_MORE_RIDS", + "ERROR_DS_INCORRECT_ROLE_OWNER", + "ERROR_DS_RIDMGR_INIT_ERROR", + "ERROR_DS_OBJ_CLASS_VIOLATION", + "ERROR_DS_CANT_ON_NON_LEAF", + "ERROR_DS_CANT_ON_RDN", + "ERROR_DS_CANT_MOD_OBJ_CLASS", + "ERROR_DS_CROSS_DOM_MOVE_ERROR", + "ERROR_DS_GC_NOT_AVAILABLE", + "ERROR_SHARED_POLICY", + "ERROR_POLICY_OBJECT_NOT_FOUND", + "ERROR_POLICY_ONLY_IN_DS", + "ERROR_PROMOTION_ACTIVE", + "ERROR_NO_PROMOTION_ACTIVE", + "ERROR_DS_OPERATIONS_ERROR", + "ERROR_DS_PROTOCOL_ERROR", + "ERROR_DS_TIMELIMIT_EXCEEDED", + "ERROR_DS_SIZELIMIT_EXCEEDED", + "ERROR_DS_ADMIN_LIMIT_EXCEEDED", + "ERROR_DS_COMPARE_FALSE", + "ERROR_DS_COMPARE_TRUE", + "ERROR_DS_AUTH_METHOD_NOT_SUPPORTED", + "ERROR_DS_STRONG_AUTH_REQUIRED", + "ERROR_DS_INAPPROPRIATE_AUTH", + "ERROR_DS_AUTH_UNKNOWN", + "ERROR_DS_REFERRAL", + "ERROR_DS_UNAVAILABLE_CRIT_EXTENSION", + "ERROR_DS_CONFIDENTIALITY_REQUIRED", + "ERROR_DS_INAPPROPRIATE_MATCHING", + "ERROR_DS_CONSTRAINT_VIOLATION", + "ERROR_DS_NO_SUCH_OBJECT", + "ERROR_DS_ALIAS_PROBLEM", + "ERROR_DS_INVALID_DN_SYNTAX", + "ERROR_DS_IS_LEAF", + "ERROR_DS_ALIAS_DEREF_PROBLEM", + "ERROR_DS_UNWILLING_TO_PERFORM", + "ERROR_DS_LOOP_DETECT", + "ERROR_DS_NAMING_VIOLATION", + "ERROR_DS_OBJECT_RESULTS_TOO_LARGE", + "ERROR_DS_AFFECTS_MULTIPLE_DSAS", + "ERROR_DS_SERVER_DOWN", + "ERROR_DS_LOCAL_ERROR", + "ERROR_DS_ENCODING_ERROR", + "ERROR_DS_DECODING_ERROR", + "ERROR_DS_FILTER_UNKNOWN", + "ERROR_DS_PARAM_ERROR", + "ERROR_DS_NOT_SUPPORTED", + "ERROR_DS_NO_RESULTS_RETURNED", + "ERROR_DS_CONTROL_NOT_FOUND", + "ERROR_DS_CLIENT_LOOP", + "ERROR_DS_REFERRAL_LIMIT_EXCEEDED", + "ERROR_DS_SORT_CONTROL_MISSING", + "ERROR_DS_OFFSET_RANGE_ERROR", + "ERROR_DS_RIDMGR_DISABLED", + "ERROR_DS_ROOT_MUST_BE_NC", + "ERROR_DS_ADD_REPLICA_INHIBITED", + "ERROR_DS_ATT_NOT_DEF_IN_SCHEMA", + "ERROR_DS_MAX_OBJ_SIZE_EXCEEDED", + "ERROR_DS_OBJ_STRING_NAME_EXISTS", + "ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA", + "ERROR_DS_RDN_DOESNT_MATCH_SCHEMA", + "ERROR_DS_NO_REQUESTED_ATTS_FOUND", + "ERROR_DS_USER_BUFFER_TO_SMALL", + "ERROR_DS_ATT_IS_NOT_ON_OBJ", + "ERROR_DS_ILLEGAL_MOD_OPERATION", + "ERROR_DS_OBJ_TOO_LARGE", + "ERROR_DS_BAD_INSTANCE_TYPE", + "ERROR_DS_MASTERDSA_REQUIRED", + "ERROR_DS_OBJECT_CLASS_REQUIRED", + "ERROR_DS_MISSING_REQUIRED_ATT", + "ERROR_DS_ATT_NOT_DEF_FOR_CLASS", + "ERROR_DS_ATT_ALREADY_EXISTS", + "ERROR_DS_CANT_ADD_ATT_VALUES", + "ERROR_DS_SINGLE_VALUE_CONSTRAINT", + "ERROR_DS_RANGE_CONSTRAINT", + "ERROR_DS_ATT_VAL_ALREADY_EXISTS", + "ERROR_DS_CANT_REM_MISSING_ATT", + "ERROR_DS_CANT_REM_MISSING_ATT_VAL", + "ERROR_DS_ROOT_CANT_BE_SUBREF", + "ERROR_DS_NO_CHAINING", + "ERROR_DS_NO_CHAINED_EVAL", + "ERROR_DS_NO_PARENT_OBJECT", + "ERROR_DS_PARENT_IS_AN_ALIAS", + "ERROR_DS_CANT_MIX_MASTER_AND_REPS", + "ERROR_DS_CHILDREN_EXIST", + "ERROR_DS_OBJ_NOT_FOUND", + "ERROR_DS_ALIASED_OBJ_MISSING", + "ERROR_DS_BAD_NAME_SYNTAX", + "ERROR_DS_ALIAS_POINTS_TO_ALIAS", + "ERROR_DS_CANT_DEREF_ALIAS", + "ERROR_DS_OUT_OF_SCOPE", + "ERROR_DS_OBJECT_BEING_REMOVED", + "ERROR_DS_CANT_DELETE_DSA_OBJ", + "ERROR_DS_GENERIC_ERROR", + "ERROR_DS_DSA_MUST_BE_INT_MASTER", + "ERROR_DS_CLASS_NOT_DSA", + "ERROR_DS_INSUFF_ACCESS_RIGHTS", + "ERROR_DS_ILLEGAL_SUPERIOR", + "ERROR_DS_ATTRIBUTE_OWNED_BY_SAM", + "ERROR_DS_NAME_TOO_MANY_PARTS", + "ERROR_DS_NAME_TOO_LONG", + "ERROR_DS_NAME_VALUE_TOO_LONG", + "ERROR_DS_NAME_UNPARSEABLE", + "ERROR_DS_NAME_TYPE_UNKNOWN", + "ERROR_DS_NOT_AN_OBJECT", + "ERROR_DS_SEC_DESC_TOO_SHORT", + "ERROR_DS_SEC_DESC_INVALID", + "ERROR_DS_NO_DELETED_NAME", + "ERROR_DS_SUBREF_MUST_HAVE_PARENT", + "ERROR_DS_NCNAME_MUST_BE_NC", + "ERROR_DS_CANT_ADD_SYSTEM_ONLY", + "ERROR_DS_CLASS_MUST_BE_CONCRETE", + "ERROR_DS_INVALID_DMD", + "ERROR_DS_OBJ_GUID_EXISTS", + "ERROR_DS_NOT_ON_BACKLINK", + "ERROR_DS_NO_CROSSREF_FOR_NC", + "ERROR_DS_SHUTTING_DOWN", + "ERROR_DS_UNKNOWN_OPERATION", + "ERROR_DS_INVALID_ROLE_OWNER", + "ERROR_DS_COULDNT_CONTACT_FSMO", + "ERROR_DS_CROSS_NC_DN_RENAME", + "ERROR_DS_CANT_MOD_SYSTEM_ONLY", + "ERROR_DS_REPLICATOR_ONLY", + "ERROR_DS_OBJ_CLASS_NOT_DEFINED", + "ERROR_DS_OBJ_CLASS_NOT_SUBCLASS", + "ERROR_DS_NAME_REFERENCE_INVALID", + "ERROR_DS_CROSS_REF_EXISTS", + "ERROR_DS_CANT_DEL_MASTER_CROSSREF", + "ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD", + "ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX", + "ERROR_DS_DUP_RDN", + "ERROR_DS_DUP_OID", + "ERROR_DS_DUP_MAPI_ID", + "ERROR_DS_DUP_SCHEMA_ID_GUID", + "ERROR_DS_DUP_LDAP_DISPLAY_NAME", + "ERROR_DS_SEMANTIC_ATT_TEST", + "ERROR_DS_SYNTAX_MISMATCH", + "ERROR_DS_EXISTS_IN_MUST_HAVE", + "ERROR_DS_EXISTS_IN_MAY_HAVE", + "ERROR_DS_NONEXISTENT_MAY_HAVE", + "ERROR_DS_NONEXISTENT_MUST_HAVE", + "ERROR_DS_AUX_CLS_TEST_FAIL", + "ERROR_DS_NONEXISTENT_POSS_SUP", + "ERROR_DS_SUB_CLS_TEST_FAIL", + "ERROR_DS_BAD_RDN_ATT_ID_SYNTAX", + "ERROR_DS_EXISTS_IN_AUX_CLS", + "ERROR_DS_EXISTS_IN_SUB_CLS", + "ERROR_DS_EXISTS_IN_POSS_SUP", + "ERROR_DS_RECALCSCHEMA_FAILED", + "ERROR_DS_TREE_DELETE_NOT_FINISHED", + "ERROR_DS_CANT_DELETE", + "ERROR_DS_ATT_SCHEMA_REQ_ID", + "ERROR_DS_BAD_ATT_SCHEMA_SYNTAX", + "ERROR_DS_CANT_CACHE_ATT", + "ERROR_DS_CANT_CACHE_CLASS", + "ERROR_DS_CANT_REMOVE_ATT_CACHE", + "ERROR_DS_CANT_REMOVE_CLASS_CACHE", + "ERROR_DS_CANT_RETRIEVE_DN", + "ERROR_DS_MISSING_SUPREF", + "ERROR_DS_CANT_RETRIEVE_INSTANCE", + "ERROR_DS_CODE_INCONSISTENCY", + "ERROR_DS_DATABASE_ERROR", + "ERROR_DS_GOVERNSID_MISSING", + "ERROR_DS_MISSING_EXPECTED_ATT", + "ERROR_DS_NCNAME_MISSING_CR_REF", + "ERROR_DS_SECURITY_CHECKING_ERROR", + "ERROR_DS_SCHEMA_NOT_LOADED", + "ERROR_DS_SCHEMA_ALLOC_FAILED", + "ERROR_DS_ATT_SCHEMA_REQ_SYNTAX", + "ERROR_DS_GCVERIFY_ERROR", + "ERROR_DS_DRA_SCHEMA_MISMATCH", + "ERROR_DS_CANT_FIND_DSA_OBJ", + "ERROR_DS_CANT_FIND_EXPECTED_NC", + "ERROR_DS_CANT_FIND_NC_IN_CACHE", + "ERROR_DS_CANT_RETRIEVE_CHILD", + "ERROR_DS_SECURITY_ILLEGAL_MODIFY", + "ERROR_DS_CANT_REPLACE_HIDDEN_REC", + "ERROR_DS_BAD_HIERARCHY_FILE", + "ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED", + "ERROR_DS_CONFIG_PARAM_MISSING", + "ERROR_DS_COUNTING_AB_INDICES_FAILED", + "ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED", + "ERROR_DS_INTERNAL_FAILURE", + "ERROR_DS_UNKNOWN_ERROR", + "ERROR_DS_ROOT_REQUIRES_CLASS_TOP", + "ERROR_DS_REFUSING_FSMO_ROLES", + "ERROR_DS_MISSING_FSMO_SETTINGS", + "ERROR_DS_UNABLE_TO_SURRENDER_ROLES", + "ERROR_DS_DRA_GENERIC", + "ERROR_DS_DRA_INVALID_PARAMETER", + "ERROR_DS_DRA_BUSY", + "ERROR_DS_DRA_BAD_DN", + "ERROR_DS_DRA_BAD_NC", + "ERROR_DS_DRA_DN_EXISTS", + "ERROR_DS_DRA_INTERNAL_ERROR", + "ERROR_DS_DRA_INCONSISTENT_DIT", + "ERROR_DS_DRA_CONNECTION_FAILED", + "ERROR_DS_DRA_BAD_INSTANCE_TYPE", + "ERROR_DS_DRA_OUT_OF_MEM", + "ERROR_DS_DRA_MAIL_PROBLEM", + "ERROR_DS_DRA_REF_ALREADY_EXISTS", + "ERROR_DS_DRA_REF_NOT_FOUND", + "ERROR_DS_DRA_OBJ_IS_REP_SOURCE", + "ERROR_DS_DRA_DB_ERROR", + "ERROR_DS_DRA_NO_REPLICA", + "ERROR_DS_DRA_ACCESS_DENIED", + "ERROR_DS_DRA_NOT_SUPPORTED", + "ERROR_DS_DRA_RPC_CANCELLED", + "ERROR_DS_DRA_SOURCE_DISABLED", + "ERROR_DS_DRA_SINK_DISABLED", + "ERROR_DS_DRA_NAME_COLLISION", + "ERROR_DS_DRA_SOURCE_REINSTALLED", + "ERROR_DS_DRA_MISSING_PARENT", + "ERROR_DS_DRA_PREEMPTED", + "ERROR_DS_DRA_ABANDON_SYNC", + "ERROR_DS_DRA_SHUTDOWN", + "ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET", + "ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA", + "ERROR_DS_DRA_EXTN_CONNECTION_FAILED", + "ERROR_DS_INSTALL_SCHEMA_MISMATCH", + "ERROR_DS_DUP_LINK_ID", + "ERROR_DS_NAME_ERROR_RESOLVING", + "ERROR_DS_NAME_ERROR_NOT_FOUND", + "ERROR_DS_NAME_ERROR_NOT_UNIQUE", + "ERROR_DS_NAME_ERROR_NO_MAPPING", + "ERROR_DS_NAME_ERROR_DOMAIN_ONLY", + "ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING", + "ERROR_DS_CONSTRUCTED_ATT_MOD", + "ERROR_DS_WRONG_OM_OBJ_CLASS", + "ERROR_DS_DRA_REPL_PENDING", + "ERROR_DS_DS_REQUIRED", + "ERROR_DS_INVALID_LDAP_DISPLAY_NAME", + "ERROR_DS_NON_BASE_SEARCH", + "ERROR_DS_CANT_RETRIEVE_ATTS", + "ERROR_DS_BACKLINK_WITHOUT_LINK", + "ERROR_DS_EPOCH_MISMATCH", + "ERROR_DS_SRC_NAME_MISMATCH", + "ERROR_DS_SRC_AND_DST_NC_IDENTICAL", + "ERROR_DS_DST_NC_MISMATCH", + "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC", + "ERROR_DS_SRC_GUID_MISMATCH", + "ERROR_DS_CANT_MOVE_DELETED_OBJECT", + "ERROR_DS_PDC_OPERATION_IN_PROGRESS", + "ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD", + "ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION", + "ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS", + "ERROR_DS_NC_MUST_HAVE_NC_PARENT", + "ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE", + "ERROR_DS_DST_DOMAIN_NOT_NATIVE", + "ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER", + "ERROR_DS_CANT_MOVE_ACCOUNT_GROUP", + "ERROR_DS_CANT_MOVE_RESOURCE_GROUP", + "ERROR_DS_INVALID_SEARCH_FLAG", + "ERROR_DS_NO_TREE_DELETE_ABOVE_NC", + "ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE", + "ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE", + "ERROR_DS_SAM_INIT_FAILURE", + "ERROR_DS_SENSITIVE_GROUP_VIOLATION", + "ERROR_DS_CANT_MOD_PRIMARYGROUPID", + "ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD", + "ERROR_DS_NONSAFE_SCHEMA_CHANGE", + "ERROR_DS_SCHEMA_UPDATE_DISALLOWED", + "ERROR_DS_CANT_CREATE_UNDER_SCHEMA", + "ERROR_DS_INSTALL_NO_SRC_SCH_VERSION", + "ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE", + "ERROR_DS_INVALID_GROUP_TYPE", + "ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN", + "ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN", + "ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER", + "ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER", + "ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER", + "ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER", + "ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER", + "ERROR_DS_HAVE_PRIMARY_MEMBERS", + "ERROR_DS_STRING_SD_CONVERSION_FAILED", + "ERROR_DS_NAMING_MASTER_GC", + "ERROR_DS_DNS_LOOKUP_FAILURE", + "ERROR_DS_COULDNT_UPDATE_SPNS", + "ERROR_DS_CANT_RETRIEVE_SD", + "ERROR_DS_KEY_NOT_UNIQUE", + "ERROR_DS_WRONG_LINKED_ATT_SYNTAX", + "ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD", + "ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY", + "ERROR_DS_CANT_START", + "ERROR_DS_INIT_FAILURE", + "ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION", + "ERROR_DS_SOURCE_DOMAIN_IN_FOREST", + "ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST", + "ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED", + "ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN", + "ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER", + "ERROR_DS_SRC_SID_EXISTS_IN_FOREST", + "ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH", + "ERROR_SAM_INIT_FAILURE", + "ERROR_DS_DRA_SCHEMA_INFO_SHIP", + "ERROR_DS_DRA_SCHEMA_CONFLICT", + "ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT", + "ERROR_DS_DRA_OBJ_NC_MISMATCH", + "ERROR_DS_NC_STILL_HAS_DSAS", + "ERROR_DS_GC_REQUIRED", + "ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY", + "ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS", + "ERROR_DS_CANT_ADD_TO_GC", + "ERROR_DS_NO_CHECKPOINT_WITH_PDC", + "ERROR_DS_SOURCE_AUDITING_NOT_ENABLED", + "ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC", + "ERROR_DS_INVALID_NAME_FOR_SPN", + "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS", + "ERROR_DS_UNICODEPWD_NOT_IN_QUOTES", + "ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED", + "ERROR_DS_MUST_BE_RUN_ON_DST_DC", + "ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER", + "ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ", + "ERROR_DS_INIT_FAILURE_CONSOLE", + "ERROR_DS_SAM_INIT_FAILURE_CONSOLE", + "ERROR_DS_FOREST_VERSION_TOO_HIGH", + "ERROR_DS_DOMAIN_VERSION_TOO_HIGH", + "ERROR_DS_FOREST_VERSION_TOO_LOW", + "ERROR_DS_DOMAIN_VERSION_TOO_LOW", + "ERROR_DS_INCOMPATIBLE_VERSION", + "ERROR_DS_LOW_DSA_VERSION", + "ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN", + "ERROR_DS_NOT_SUPPORTED_SORT_ORDER", + "ERROR_DS_NAME_NOT_UNIQUE", + "ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4", + "ERROR_DS_OUT_OF_VERSION_STORE", + "ERROR_DS_INCOMPATIBLE_CONTROLS_USED", + "ERROR_DS_NO_REF_DOMAIN", + "ERROR_DS_RESERVED_LINK_ID", + "ERROR_DS_LINK_ID_NOT_AVAILABLE", + "ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER", + "ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE", + "ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC", + "ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG", + "ERROR_DS_MODIFYDN_WRONG_GRANDPARENT", + "ERROR_DS_NAME_ERROR_TRUST_REFERRAL", + "ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER", + "ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD", + "ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2", + "ERROR_DS_THREAD_LIMIT_EXCEEDED", + "ERROR_DS_NOT_CLOSEST", + "ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF", + "ERROR_DS_SINGLE_USER_MODE_FAILED", + "ERROR_DS_NTDSCRIPT_SYNTAX_ERROR", + "ERROR_DS_NTDSCRIPT_PROCESS_ERROR", + "ERROR_DS_DIFFERENT_REPL_EPOCHS", + "ERROR_DS_DRS_EXTENSIONS_CHANGED", + "ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR", + "ERROR_DS_NO_MSDS_INTID", + "ERROR_DS_DUP_MSDS_INTID", + "ERROR_DS_EXISTS_IN_RDNATTID", + "ERROR_DS_AUTHORIZATION_FAILED", + "ERROR_DS_INVALID_SCRIPT", + "ERROR_DS_REMOTE_CROSSREF_OP_FAILED", + "ERROR_DS_CROSS_REF_BUSY", + "ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN", + "ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC", + "ERROR_DS_DUPLICATE_ID_FOUND", + "ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT", + "ERROR_DS_GROUP_CONVERSION_ERROR", + "ERROR_DS_CANT_MOVE_APP_BASIC_GROUP", + "ERROR_DS_CANT_MOVE_APP_QUERY_GROUP", + "ERROR_DS_ROLE_NOT_VERIFIED", + "ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL", + "ERROR_DS_DOMAIN_RENAME_IN_PROGRESS", + "ERROR_DS_EXISTING_AD_CHILD_NC", + "ERROR_DS_REPL_LIFETIME_EXCEEDED", + "ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER", + "ERROR_DS_LDAP_SEND_QUEUE_FULL", + "ERROR_DS_DRA_OUT_SCHEDULE_WINDOW", + "ERROR_DS_POLICY_NOT_KNOWN", + "ERROR_NO_SITE_SETTINGS_OBJECT", + "ERROR_NO_SECRETS", + "ERROR_NO_WRITABLE_DC_FOUND", + "ERROR_DS_NO_SERVER_OBJECT", + "ERROR_DS_NO_NTDSA_OBJECT", + "ERROR_DS_NON_ASQ_SEARCH", + "ERROR_DS_AUDIT_FAILURE", + "ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE", + "ERROR_DS_INVALID_SEARCH_FLAG_TUPLE", + "ERROR_DS_HIERARCHY_TABLE_TOO_DEEP", + "ERROR_DS_DRA_CORRUPT_UTD_VECTOR", + "ERROR_DS_DRA_SECRETS_DENIED", + "ERROR_DS_RESERVED_MAPI_ID", + "ERROR_DS_MAPI_ID_NOT_AVAILABLE", + "ERROR_DS_DRA_MISSING_KRBTGT_SECRET", + "ERROR_DS_DOMAIN_NAME_EXISTS_IN_FOREST", + "ERROR_DS_FLAT_NAME_EXISTS_IN_FOREST", + "ERROR_INVALID_USER_PRINCIPAL_NAME", + "ERROR_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS", + "ERROR_DS_OID_NOT_FOUND", + "ERROR_DS_DRA_RECYCLED_TARGET", + "ERROR_DS_DISALLOWED_NC_REDIRECT", + "ERROR_DS_HIGH_ADLDS_FFL", + "ERROR_DS_HIGH_DSA_VERSION", + "ERROR_DS_LOW_ADLDS_FFL", + "ERROR_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION", + "ERROR_DS_UNDELETE_SAM_VALIDATION_FAILED", + "ERROR_INCORRECT_ACCOUNT_TYPE", + "ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST", + "ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST", + "ERROR_DS_MISSING_FOREST_TRUST", + "ERROR_DS_VALUE_KEY_NOT_UNIQUE", + "ERROR_IPSEC_QM_POLICY_EXISTS", + "ERROR_IPSEC_QM_POLICY_NOT_FOUND", + "ERROR_IPSEC_QM_POLICY_IN_USE", + "ERROR_IPSEC_MM_POLICY_EXISTS", + "ERROR_IPSEC_MM_POLICY_NOT_FOUND", + "ERROR_IPSEC_MM_POLICY_IN_USE", + "ERROR_IPSEC_MM_FILTER_EXISTS", + "ERROR_IPSEC_MM_FILTER_NOT_FOUND", + "ERROR_IPSEC_TRANSPORT_FILTER_EXISTS", + "ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND", + "ERROR_IPSEC_MM_AUTH_EXISTS", + "ERROR_IPSEC_MM_AUTH_NOT_FOUND", + "ERROR_IPSEC_MM_AUTH_IN_USE", + "ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND", + "ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND", + "ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND", + "ERROR_IPSEC_TUNNEL_FILTER_EXISTS", + "ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND", + "ERROR_IPSEC_MM_FILTER_PENDING_DELETION", + "ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION", + "ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION", + "ERROR_IPSEC_MM_POLICY_PENDING_DELETION", + "ERROR_IPSEC_MM_AUTH_PENDING_DELETION", + "ERROR_IPSEC_QM_POLICY_PENDING_DELETION", + "ERROR_IPSEC_IKE_NEG_STATUS_BEGIN", + "ERROR_IPSEC_IKE_AUTH_FAIL", + "ERROR_IPSEC_IKE_ATTRIB_FAIL", + "ERROR_IPSEC_IKE_NEGOTIATION_PENDING", + "ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR", + "ERROR_IPSEC_IKE_TIMED_OUT", + "ERROR_IPSEC_IKE_NO_CERT", + "ERROR_IPSEC_IKE_SA_DELETED", + "ERROR_IPSEC_IKE_SA_REAPED", + "ERROR_IPSEC_IKE_MM_ACQUIRE_DROP", + "ERROR_IPSEC_IKE_QM_ACQUIRE_DROP", + "ERROR_IPSEC_IKE_QUEUE_DROP_MM", + "ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM", + "ERROR_IPSEC_IKE_DROP_NO_RESPONSE", + "ERROR_IPSEC_IKE_MM_DELAY_DROP", + "ERROR_IPSEC_IKE_QM_DELAY_DROP", + "ERROR_IPSEC_IKE_ERROR", + "ERROR_IPSEC_IKE_CRL_FAILED", + "ERROR_IPSEC_IKE_INVALID_KEY_USAGE", + "ERROR_IPSEC_IKE_INVALID_CERT_TYPE", + "ERROR_IPSEC_IKE_NO_PRIVATE_KEY", + "ERROR_IPSEC_IKE_SIMULTANEOUS_REKEY", + "ERROR_IPSEC_IKE_DH_FAIL", + "ERROR_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED", + "ERROR_IPSEC_IKE_INVALID_HEADER", + "ERROR_IPSEC_IKE_NO_POLICY", + "ERROR_IPSEC_IKE_INVALID_SIGNATURE", + "ERROR_IPSEC_IKE_KERBEROS_ERROR", + "ERROR_IPSEC_IKE_NO_PUBLIC_KEY", + "ERROR_IPSEC_IKE_PROCESS_ERR", + "ERROR_IPSEC_IKE_PROCESS_ERR_SA", + "ERROR_IPSEC_IKE_PROCESS_ERR_PROP", + "ERROR_IPSEC_IKE_PROCESS_ERR_TRANS", + "ERROR_IPSEC_IKE_PROCESS_ERR_KE", + "ERROR_IPSEC_IKE_PROCESS_ERR_ID", + "ERROR_IPSEC_IKE_PROCESS_ERR_CERT", + "ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ", + "ERROR_IPSEC_IKE_PROCESS_ERR_HASH", + "ERROR_IPSEC_IKE_PROCESS_ERR_SIG", + "ERROR_IPSEC_IKE_PROCESS_ERR_NONCE", + "ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY", + "ERROR_IPSEC_IKE_PROCESS_ERR_DELETE", + "ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR", + "ERROR_IPSEC_IKE_INVALID_PAYLOAD", + "ERROR_IPSEC_IKE_LOAD_SOFT_SA", + "ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN", + "ERROR_IPSEC_IKE_INVALID_COOKIE", + "ERROR_IPSEC_IKE_NO_PEER_CERT", + "ERROR_IPSEC_IKE_PEER_CRL_FAILED", + "ERROR_IPSEC_IKE_POLICY_CHANGE", + "ERROR_IPSEC_IKE_NO_MM_POLICY", + "ERROR_IPSEC_IKE_NOTCBPRIV", + "ERROR_IPSEC_IKE_SECLOADFAIL", + "ERROR_IPSEC_IKE_FAILSSPINIT", + "ERROR_IPSEC_IKE_FAILQUERYSSP", + "ERROR_IPSEC_IKE_SRVACQFAIL", + "ERROR_IPSEC_IKE_SRVQUERYCRED", + "ERROR_IPSEC_IKE_GETSPIFAIL", + "ERROR_IPSEC_IKE_INVALID_FILTER", + "ERROR_IPSEC_IKE_OUT_OF_MEMORY", + "ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED", + "ERROR_IPSEC_IKE_INVALID_POLICY", + "ERROR_IPSEC_IKE_UNKNOWN_DOI", + "ERROR_IPSEC_IKE_INVALID_SITUATION", + "ERROR_IPSEC_IKE_DH_FAILURE", + "ERROR_IPSEC_IKE_INVALID_GROUP", + "ERROR_IPSEC_IKE_ENCRYPT", + "ERROR_IPSEC_IKE_DECRYPT", + "ERROR_IPSEC_IKE_POLICY_MATCH", + "ERROR_IPSEC_IKE_UNSUPPORTED_ID", + "ERROR_IPSEC_IKE_INVALID_HASH", + "ERROR_IPSEC_IKE_INVALID_HASH_ALG", + "ERROR_IPSEC_IKE_INVALID_HASH_SIZE", + "ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG", + "ERROR_IPSEC_IKE_INVALID_AUTH_ALG", + "ERROR_IPSEC_IKE_INVALID_SIG", + "ERROR_IPSEC_IKE_LOAD_FAILED", + "ERROR_IPSEC_IKE_RPC_DELETE", + "ERROR_IPSEC_IKE_BENIGN_REINIT", + "ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY", + "ERROR_IPSEC_IKE_INVALID_MAJOR_VERSION", + "ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN", + "ERROR_IPSEC_IKE_MM_LIMIT", + "ERROR_IPSEC_IKE_NEGOTIATION_DISABLED", + "ERROR_IPSEC_IKE_QM_LIMIT", + "ERROR_IPSEC_IKE_MM_EXPIRED", + "ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID", + "ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH", + "ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID", + "ERROR_IPSEC_IKE_INVALID_AUTH_PAYLOAD", + "ERROR_IPSEC_IKE_DOS_COOKIE_SENT", + "ERROR_IPSEC_IKE_SHUTTING_DOWN", + "ERROR_IPSEC_IKE_CGA_AUTH_FAILED", + "ERROR_IPSEC_IKE_PROCESS_ERR_NATOA", + "ERROR_IPSEC_IKE_INVALID_MM_FOR_QM", + "ERROR_IPSEC_IKE_QM_EXPIRED", + "ERROR_IPSEC_IKE_TOO_MANY_FILTERS", + "ERROR_IPSEC_IKE_NEG_STATUS_END", + "ERROR_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL", + "ERROR_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE", + "ERROR_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING", + "ERROR_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING", + "ERROR_IPSEC_IKE_COEXISTENCE_SUPPRESS", + "ERROR_IPSEC_IKE_RATELIMIT_DROP", + "ERROR_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE", + "ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE", + "ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE", + "ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY", + "ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE", + "ERROR_IPSEC_IKE_NEG_STATUS_EXTENDED_END", + "ERROR_IPSEC_BAD_SPI", + "ERROR_IPSEC_SA_LIFETIME_EXPIRED", + "ERROR_IPSEC_WRONG_SA", + "ERROR_IPSEC_REPLAY_CHECK_FAILED", + "ERROR_IPSEC_INVALID_PACKET", + "ERROR_IPSEC_INTEGRITY_CHECK_FAILED", + "ERROR_IPSEC_CLEAR_TEXT_DROP", + "ERROR_IPSEC_AUTH_FIREWALL_DROP", + "ERROR_IPSEC_THROTTLE_DROP", + "ERROR_IPSEC_DOSP_BLOCK", + "ERROR_IPSEC_DOSP_RECEIVED_MULTICAST", + "ERROR_IPSEC_DOSP_INVALID_PACKET", + "ERROR_IPSEC_DOSP_STATE_LOOKUP_FAILED", + "ERROR_IPSEC_DOSP_MAX_ENTRIES", + "ERROR_IPSEC_DOSP_KEYMOD_NOT_ALLOWED", + "ERROR_IPSEC_DOSP_NOT_INSTALLED", + "ERROR_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES", + "ERROR_SXS_SECTION_NOT_FOUND", + "ERROR_SXS_CANT_GEN_ACTCTX", + "ERROR_SXS_INVALID_ACTCTXDATA_FORMAT", + "ERROR_SXS_ASSEMBLY_NOT_FOUND", + "ERROR_SXS_MANIFEST_FORMAT_ERROR", + "ERROR_SXS_MANIFEST_PARSE_ERROR", + "ERROR_SXS_ACTIVATION_CONTEXT_DISABLED", + "ERROR_SXS_KEY_NOT_FOUND", + "ERROR_SXS_VERSION_CONFLICT", + "ERROR_SXS_WRONG_SECTION_TYPE", + "ERROR_SXS_THREAD_QUERIES_DISABLED", + "ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET", + "ERROR_SXS_UNKNOWN_ENCODING_GROUP", + "ERROR_SXS_UNKNOWN_ENCODING", + "ERROR_SXS_INVALID_XML_NAMESPACE_URI", + "ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED", + "ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED", + "ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE", + "ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE", + "ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE", + "ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT", + "ERROR_SXS_DUPLICATE_DLL_NAME", + "ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME", + "ERROR_SXS_DUPLICATE_CLSID", + "ERROR_SXS_DUPLICATE_IID", + "ERROR_SXS_DUPLICATE_TLBID", + "ERROR_SXS_DUPLICATE_PROGID", + "ERROR_SXS_DUPLICATE_ASSEMBLY_NAME", + "ERROR_SXS_FILE_HASH_MISMATCH", + "ERROR_SXS_POLICY_PARSE_ERROR", + "ERROR_SXS_XML_E_MISSINGQUOTE", + "ERROR_SXS_XML_E_COMMENTSYNTAX", + "ERROR_SXS_XML_E_BADSTARTNAMECHAR", + "ERROR_SXS_XML_E_BADNAMECHAR", + "ERROR_SXS_XML_E_BADCHARINSTRING", + "ERROR_SXS_XML_E_XMLDECLSYNTAX", + "ERROR_SXS_XML_E_BADCHARDATA", + "ERROR_SXS_XML_E_MISSINGWHITESPACE", + "ERROR_SXS_XML_E_EXPECTINGTAGEND", + "ERROR_SXS_XML_E_MISSINGSEMICOLON", + "ERROR_SXS_XML_E_UNBALANCEDPAREN", + "ERROR_SXS_XML_E_INTERNALERROR", + "ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE", + "ERROR_SXS_XML_E_INCOMPLETE_ENCODING", + "ERROR_SXS_XML_E_MISSING_PAREN", + "ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE", + "ERROR_SXS_XML_E_MULTIPLE_COLONS", + "ERROR_SXS_XML_E_INVALID_DECIMAL", + "ERROR_SXS_XML_E_INVALID_HEXIDECIMAL", + "ERROR_SXS_XML_E_INVALID_UNICODE", + "ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK", + "ERROR_SXS_XML_E_UNEXPECTEDENDTAG", + "ERROR_SXS_XML_E_UNCLOSEDTAG", + "ERROR_SXS_XML_E_DUPLICATEATTRIBUTE", + "ERROR_SXS_XML_E_MULTIPLEROOTS", + "ERROR_SXS_XML_E_INVALIDATROOTLEVEL", + "ERROR_SXS_XML_E_BADXMLDECL", + "ERROR_SXS_XML_E_MISSINGROOT", + "ERROR_SXS_XML_E_UNEXPECTEDEOF", + "ERROR_SXS_XML_E_BADPEREFINSUBSET", + "ERROR_SXS_XML_E_UNCLOSEDSTARTTAG", + "ERROR_SXS_XML_E_UNCLOSEDENDTAG", + "ERROR_SXS_XML_E_UNCLOSEDSTRING", + "ERROR_SXS_XML_E_UNCLOSEDCOMMENT", + "ERROR_SXS_XML_E_UNCLOSEDDECL", + "ERROR_SXS_XML_E_UNCLOSEDCDATA", + "ERROR_SXS_XML_E_RESERVEDNAMESPACE", + "ERROR_SXS_XML_E_INVALIDENCODING", + "ERROR_SXS_XML_E_INVALIDSWITCH", + "ERROR_SXS_XML_E_BADXMLCASE", + "ERROR_SXS_XML_E_INVALID_STANDALONE", + "ERROR_SXS_XML_E_UNEXPECTED_STANDALONE", + "ERROR_SXS_XML_E_INVALID_VERSION", + "ERROR_SXS_XML_E_MISSINGEQUALS", + "ERROR_SXS_PROTECTION_RECOVERY_FAILED", + "ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT", + "ERROR_SXS_PROTECTION_CATALOG_NOT_VALID", + "ERROR_SXS_UNTRANSLATABLE_HRESULT", + "ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING", + "ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE", + "ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME", + "ERROR_SXS_ASSEMBLY_MISSING", + "ERROR_SXS_CORRUPT_ACTIVATION_STACK", + "ERROR_SXS_CORRUPTION", + "ERROR_SXS_EARLY_DEACTIVATION", + "ERROR_SXS_INVALID_DEACTIVATION", + "ERROR_SXS_MULTIPLE_DEACTIVATION", + "ERROR_SXS_PROCESS_TERMINATION_REQUESTED", + "ERROR_SXS_RELEASE_ACTIVATION_CONTEXT", + "ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY", + "ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE", + "ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME", + "ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE", + "ERROR_SXS_IDENTITY_PARSE_ERROR", + "ERROR_MALFORMED_SUBSTITUTION_STRING", + "ERROR_SXS_INCORRECT_PUBLIC_KEY_TOKEN", + "ERROR_UNMAPPED_SUBSTITUTION_STRING", + "ERROR_SXS_ASSEMBLY_NOT_LOCKED", + "ERROR_SXS_COMPONENT_STORE_CORRUPT", + "ERROR_ADVANCED_INSTALLER_FAILED", + "ERROR_XML_ENCODING_MISMATCH", + "ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT", + "ERROR_SXS_IDENTITIES_DIFFERENT", + "ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT", + "ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY", + "ERROR_SXS_MANIFEST_TOO_BIG", + "ERROR_SXS_SETTING_NOT_REGISTERED", + "ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE", + "ERROR_SMI_PRIMITIVE_INSTALLER_FAILED", + "ERROR_GENERIC_COMMAND_FAILED", + "ERROR_SXS_FILE_HASH_MISSING", + "ERROR_SXS_DUPLICATE_ACTIVATABLE_CLASS", + "ERROR_EVT_INVALID_CHANNEL_PATH", + "ERROR_EVT_INVALID_QUERY", + "ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND", + "ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND", + "ERROR_EVT_INVALID_PUBLISHER_NAME", + "ERROR_EVT_INVALID_EVENT_DATA", + "ERROR_EVT_CHANNEL_NOT_FOUND", + "ERROR_EVT_MALFORMED_XML_TEXT", + "ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL", + "ERROR_EVT_CONFIGURATION_ERROR", + "ERROR_EVT_QUERY_RESULT_STALE", + "ERROR_EVT_QUERY_RESULT_INVALID_POSITION", + "ERROR_EVT_NON_VALIDATING_MSXML", + "ERROR_EVT_FILTER_ALREADYSCOPED", + "ERROR_EVT_FILTER_NOTELTSET", + "ERROR_EVT_FILTER_INVARG", + "ERROR_EVT_FILTER_INVTEST", + "ERROR_EVT_FILTER_INVTYPE", + "ERROR_EVT_FILTER_PARSEERR", + "ERROR_EVT_FILTER_UNSUPPORTEDOP", + "ERROR_EVT_FILTER_UNEXPECTEDTOKEN", + "ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL", + "ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE", + "ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE", + "ERROR_EVT_CHANNEL_CANNOT_ACTIVATE", + "ERROR_EVT_FILTER_TOO_COMPLEX", + "ERROR_EVT_MESSAGE_NOT_FOUND", + "ERROR_EVT_MESSAGE_ID_NOT_FOUND", + "ERROR_EVT_UNRESOLVED_VALUE_INSERT", + "ERROR_EVT_UNRESOLVED_PARAMETER_INSERT", + "ERROR_EVT_MAX_INSERTS_REACHED", + "ERROR_EVT_EVENT_DEFINITION_NOT_FOUND", + "ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND", + "ERROR_EVT_VERSION_TOO_OLD", + "ERROR_EVT_VERSION_TOO_NEW", + "ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY", + "ERROR_EVT_PUBLISHER_DISABLED", + "ERROR_EVT_FILTER_OUT_OF_RANGE", + "ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE", + "ERROR_EC_LOG_DISABLED", + "ERROR_EC_CIRCULAR_FORWARDING", + "ERROR_EC_CREDSTORE_FULL", + "ERROR_EC_CRED_NOT_FOUND", + "ERROR_EC_NO_ACTIVE_CHANNEL", + "ERROR_MUI_FILE_NOT_FOUND", + "ERROR_MUI_INVALID_FILE", + "ERROR_MUI_INVALID_RC_CONFIG", + "ERROR_MUI_INVALID_LOCALE_NAME", + "ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME", + "ERROR_MUI_FILE_NOT_LOADED", + "ERROR_RESOURCE_ENUM_USER_STOP", + "ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED", + "ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME", + "ERROR_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE", + "ERROR_MRM_INVALID_PRICONFIG", + "ERROR_MRM_INVALID_FILE_TYPE", + "ERROR_MRM_UNKNOWN_QUALIFIER", + "ERROR_MRM_INVALID_QUALIFIER_VALUE", + "ERROR_MRM_NO_CANDIDATE", + "ERROR_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE", + "ERROR_MRM_RESOURCE_TYPE_MISMATCH", + "ERROR_MRM_DUPLICATE_MAP_NAME", + "ERROR_MRM_DUPLICATE_ENTRY", + "ERROR_MRM_INVALID_RESOURCE_IDENTIFIER", + "ERROR_MRM_FILEPATH_TOO_LONG", + "ERROR_MRM_UNSUPPORTED_DIRECTORY_TYPE", + "ERROR_MRM_INVALID_PRI_FILE", + "ERROR_MRM_NAMED_RESOURCE_NOT_FOUND", + "ERROR_MRM_MAP_NOT_FOUND", + "ERROR_MRM_UNSUPPORTED_PROFILE_TYPE", + "ERROR_MRM_INVALID_QUALIFIER_OPERATOR", + "ERROR_MRM_INDETERMINATE_QUALIFIER_VALUE", + "ERROR_MRM_AUTOMERGE_ENABLED", + "ERROR_MRM_TOO_MANY_RESOURCES", + "ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE", + "ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE", + "ERROR_MRM_NO_CURRENT_VIEW_ON_THREAD", + "ERROR_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST", + "ERROR_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT", + "ERROR_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE", + "ERROR_MRM_GENERATION_COUNT_MISMATCH", + "ERROR_PRI_MERGE_VERSION_MISMATCH", + "ERROR_PRI_MERGE_MISSING_SCHEMA", + "ERROR_PRI_MERGE_LOAD_FILE_FAILED", + "ERROR_PRI_MERGE_ADD_FILE_FAILED", + "ERROR_PRI_MERGE_WRITE_FILE_FAILED", + "ERROR_PRI_MERGE_MULTIPLE_PACKAGE_FAMILIES_NOT_ALLOWED", + "ERROR_PRI_MERGE_MULTIPLE_MAIN_PACKAGES_NOT_ALLOWED", + "ERROR_PRI_MERGE_BUNDLE_PACKAGES_NOT_ALLOWED", + "ERROR_PRI_MERGE_MAIN_PACKAGE_REQUIRED", + "ERROR_PRI_MERGE_RESOURCE_PACKAGE_REQUIRED", + "ERROR_PRI_MERGE_INVALID_FILE_NAME", + "ERROR_MRM_PACKAGE_NOT_FOUND", + "ERROR_MRM_MISSING_DEFAULT_LANGUAGE", + "ERROR_MCA_INVALID_CAPABILITIES_STRING", + "ERROR_MCA_INVALID_VCP_VERSION", + "ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION", + "ERROR_MCA_MCCS_VERSION_MISMATCH", + "ERROR_MCA_UNSUPPORTED_MCCS_VERSION", + "ERROR_MCA_INTERNAL_ERROR", + "ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED", + "ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE", + "ERROR_AMBIGUOUS_SYSTEM_DEVICE", + "ERROR_SYSTEM_DEVICE_NOT_FOUND", + "ERROR_HASH_NOT_SUPPORTED", + "ERROR_HASH_NOT_PRESENT", + "ERROR_SECONDARY_IC_PROVIDER_NOT_REGISTERED", + "ERROR_GPIO_CLIENT_INFORMATION_INVALID", + "ERROR_GPIO_VERSION_NOT_SUPPORTED", + "ERROR_GPIO_INVALID_REGISTRATION_PACKET", + "ERROR_GPIO_OPERATION_DENIED", + "ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE", + "ERROR_GPIO_INTERRUPT_ALREADY_UNMASKED", + "ERROR_CANNOT_SWITCH_RUNLEVEL", + "ERROR_INVALID_RUNLEVEL_SETTING", + "ERROR_RUNLEVEL_SWITCH_TIMEOUT", + "ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT", + "ERROR_RUNLEVEL_SWITCH_IN_PROGRESS", + "ERROR_SERVICES_FAILED_AUTOSTART", + "ERROR_COM_TASK_STOP_PENDING", + "ERROR_INSTALL_OPEN_PACKAGE_FAILED", + "ERROR_INSTALL_PACKAGE_NOT_FOUND", + "ERROR_INSTALL_INVALID_PACKAGE", + "ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED", + "ERROR_INSTALL_OUT_OF_DISK_SPACE", + "ERROR_INSTALL_NETWORK_FAILURE", + "ERROR_INSTALL_REGISTRATION_FAILURE", + "ERROR_INSTALL_DEREGISTRATION_FAILURE", + "ERROR_INSTALL_CANCEL", + "ERROR_INSTALL_FAILED", + "ERROR_REMOVE_FAILED", + "ERROR_PACKAGE_ALREADY_EXISTS", + "ERROR_NEEDS_REMEDIATION", + "ERROR_INSTALL_PREREQUISITE_FAILED", + "ERROR_PACKAGE_REPOSITORY_CORRUPTED", + "ERROR_INSTALL_POLICY_FAILURE", + "ERROR_PACKAGE_UPDATING", + "ERROR_DEPLOYMENT_BLOCKED_BY_POLICY", + "ERROR_PACKAGES_IN_USE", + "ERROR_RECOVERY_FILE_CORRUPT", + "ERROR_INVALID_STAGED_SIGNATURE", + "ERROR_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED", + "ERROR_INSTALL_PACKAGE_DOWNGRADE", + "ERROR_SYSTEM_NEEDS_REMEDIATION", + "ERROR_APPX_INTEGRITY_FAILURE_CLR_NGEN", + "ERROR_RESILIENCY_FILE_CORRUPT", + "ERROR_INSTALL_FIREWALL_SERVICE_NOT_RUNNING", + "ERROR_PACKAGE_MOVE_FAILED", + "ERROR_INSTALL_VOLUME_NOT_EMPTY", + "ERROR_INSTALL_VOLUME_OFFLINE", + "ERROR_INSTALL_VOLUME_CORRUPT", + "ERROR_NEEDS_REGISTRATION", + "ERROR_INSTALL_WRONG_PROCESSOR_ARCHITECTURE", + "ERROR_DEV_SIDELOAD_LIMIT_EXCEEDED", + "ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE", + "ERROR_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM", + "ERROR_PACKAGE_MOVE_BLOCKED_BY_STREAMING", + "ERROR_INSTALL_OPTIONAL_PACKAGE_APPLICATIONID_NOT_UNIQUE", + "ERROR_PACKAGE_STAGING_ONHOLD", + "ERROR_INSTALL_INVALID_RELATED_SET_UPDATE", + "ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY", + "ERROR_DEPLOYMENT_BLOCKED_BY_USER_LOG_OFF", + "ERROR_PROVISION_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE_PROVISIONED", + "ERROR_PACKAGES_REPUTATION_CHECK_FAILED", + "ERROR_PACKAGES_REPUTATION_CHECK_TIMEDOUT", + "ERROR_DEPLOYMENT_OPTION_NOT_SUPPORTED", + "ERROR_APPINSTALLER_ACTIVATION_BLOCKED", + "ERROR_REGISTRATION_FROM_REMOTE_DRIVE_NOT_SUPPORTED", + "ERROR_APPX_RAW_DATA_WRITE_FAILED", + "ERROR_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_PACKAGE", + "ERROR_DEPLOYMENT_BLOCKED_BY_VOLUME_POLICY_MACHINE", + "ERROR_DEPLOYMENT_BLOCKED_BY_PROFILE_POLICY", + "ERROR_DEPLOYMENT_FAILED_CONFLICTING_MUTABLE_PACKAGE_DIRECTORY", + "ERROR_SINGLETON_RESOURCE_INSTALLED_IN_ACTIVE_USER", + "ERROR_DIFFERENT_VERSION_OF_PACKAGED_SERVICE_INSTALLED", + "ERROR_SERVICE_EXISTS_AS_NON_PACKAGED_SERVICE", + "ERROR_PACKAGED_SERVICE_REQUIRES_ADMIN_PRIVILEGES", + "ERROR_REDIRECTION_TO_DEFAULT_ACCOUNT_NOT_ALLOWED", + "ERROR_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST", + "ERROR_UNSIGNED_PACKAGE_INVALID_CONTENT", + "ERROR_UNSIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE", + "ERROR_SIGNED_PACKAGE_INVALID_PUBLISHER_NAMESPACE", + "ERROR_PACKAGE_EXTERNAL_LOCATION_NOT_ALLOWED", + "ERROR_INSTALL_FULLTRUST_HOSTRUNTIME_REQUIRES_MAIN_PACKAGE_FULLTRUST_CAPABILITY", + "ERROR_STATE_LOAD_STORE_FAILED", + "ERROR_STATE_GET_VERSION_FAILED", + "ERROR_STATE_SET_VERSION_FAILED", + "ERROR_STATE_STRUCTURED_RESET_FAILED", + "ERROR_STATE_OPEN_CONTAINER_FAILED", + "ERROR_STATE_CREATE_CONTAINER_FAILED", + "ERROR_STATE_DELETE_CONTAINER_FAILED", + "ERROR_STATE_READ_SETTING_FAILED", + "ERROR_STATE_WRITE_SETTING_FAILED", + "ERROR_STATE_DELETE_SETTING_FAILED", + "ERROR_STATE_QUERY_SETTING_FAILED", + "ERROR_STATE_READ_COMPOSITE_SETTING_FAILED", + "ERROR_STATE_WRITE_COMPOSITE_SETTING_FAILED", + "ERROR_STATE_ENUMERATE_CONTAINER_FAILED", + "ERROR_STATE_ENUMERATE_SETTINGS_FAILED", + "ERROR_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED", + "ERROR_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED", + "ERROR_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED", + "ERROR_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED", + "ERROR_API_UNAVAILABLE", +}; + +const char* WinErrorToString(uint16_t error) { + auto itr = std::find(std::begin(kWinErrorValues), + std::end(kWinErrorValues), + error); + if (itr == std::end(kWinErrorValues)) { + return nullptr; + } + + return kWinErrorStrings[itr - std::begin(kWinErrorValues)]; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.h b/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.h new file mode 100644 index 0000000000..5b7152679b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/symbolic_constants_win.h @@ -0,0 +1,61 @@ +// Copyright (c) 2015 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. + +// ntstatus_reason_win.h: Windows NTSTATUS code to string. +// +// Provides a means to convert NTSTATUS codes to strings. +// +// Author: Ben Wagner + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +/* Converts an NTSTATUS code to its string representation. Returns nullptr if + * no entry corresponds to the code. */ +const char* NTStatusToString(uint32_t ntstatus); + +/* Converts a FAST_FAIL code to its string representation. Returns nullptr if + * no entry corresponds to the code. */ +const char* FastFailToString(uint32_t fast_fail_code); + +/* Converts an ERROR code to its string representation. Returns nullptr if + * no entry corresponds to the code. */ +const char* WinErrorToString(uint16_t error); + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOLIC_CONSTANTS_WIN_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.cc b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.cc new file mode 100644 index 0000000000..aa86d248ae --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.cc @@ -0,0 +1,421 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// synth_minidump.cc: Implementation of SynthMinidump. See synth_minidump.h + +#include "processor/synth_minidump.h" + +namespace google_breakpad { + +namespace SynthMinidump { + +Section::Section(const Dump &dump) + : test_assembler::Section(dump.endianness()) { } + +void Section::CiteLocationIn(test_assembler::Section *section) const { + (*section).D32(size_).D32(file_offset_); +} + +void Stream::CiteStreamIn(test_assembler::Section *section) const { + section->D32(type_); + CiteLocationIn(section); +} + +SystemInfo::SystemInfo(const Dump &dump, + const MDRawSystemInfo &system_info, + const String &csd_version) + : Stream(dump, MD_SYSTEM_INFO_STREAM) { + D16(system_info.processor_architecture); + D16(system_info.processor_level); + D16(system_info.processor_revision); + D8(system_info.number_of_processors); + D8(system_info.product_type); + D32(system_info.major_version); + D32(system_info.minor_version); + D32(system_info.build_number); + D32(system_info.platform_id); + csd_version.CiteStringIn(this); + D16(system_info.suite_mask); + D16(system_info.reserved2); // Well, why not? + + // MDCPUInformation cpu; + if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_X86) { + D32(system_info.cpu.x86_cpu_info.vendor_id[0]); + D32(system_info.cpu.x86_cpu_info.vendor_id[1]); + D32(system_info.cpu.x86_cpu_info.vendor_id[2]); + D32(system_info.cpu.x86_cpu_info.version_information); + D32(system_info.cpu.x86_cpu_info.feature_information); + D32(system_info.cpu.x86_cpu_info.amd_extended_cpu_features); + } else if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_ARM) { + D32(system_info.cpu.arm_cpu_info.cpuid); + D32(system_info.cpu.arm_cpu_info.elf_hwcaps); + } else { + D64(system_info.cpu.other_cpu_info.processor_features[0]); + D64(system_info.cpu.other_cpu_info.processor_features[1]); + } +} + +const MDRawSystemInfo SystemInfo::windows_x86 = { + MD_CPU_ARCHITECTURE_X86, // processor_architecture + 6, // processor_level + 0xd08, // processor_revision + 1, // number_of_processors + 1, // product_type + 5, // major_version + 1, // minor_version + 2600, // build_number + 2, // platform_id + 0xdeadbeef, // csd_version_rva + 0x100, // suite_mask + 0, // reserved2 + { // cpu + { // x86_cpu_info + { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id + 0x6d8, // version_information + 0xafe9fbff, // feature_information + 0xffffffff // amd_extended_cpu_features + } + } +}; + +const string SystemInfo::windows_x86_csd_version = "Service Pack 2"; + +String::String(const Dump &dump, const string &contents) : Section(dump) { + D32(contents.size() * 2); + for (string::const_iterator i = contents.begin(); i != contents.end(); i++) + D16(*i); +} + +void String::CiteStringIn(test_assembler::Section *section) const { + section->D32(file_offset_); +} + +void Memory::CiteMemoryIn(test_assembler::Section *section) const { + section->D64(address_); + CiteLocationIn(section); +} + +Context::Context(const Dump &dump, const MDRawContextX86 &context) + : Section(dump) { + // The caller should have properly set the CPU type flag. + // The high 24 bits identify the CPU. Note that context records with no CPU + // type information can be valid (e.g. produced by ::RtlCaptureContext). + assert(((context.context_flags & MD_CONTEXT_CPU_MASK) == 0) || + (context.context_flags & MD_CONTEXT_X86)); + // It doesn't make sense to store x86 registers in big-endian form. + assert(dump.endianness() == kLittleEndian); + D32(context.context_flags); + D32(context.dr0); + D32(context.dr1); + D32(context.dr2); + D32(context.dr3); + D32(context.dr6); + D32(context.dr7); + D32(context.float_save.control_word); + D32(context.float_save.status_word); + D32(context.float_save.tag_word); + D32(context.float_save.error_offset); + D32(context.float_save.error_selector); + D32(context.float_save.data_offset); + D32(context.float_save.data_selector); + // context.float_save.register_area[] contains 8-bit quantities and + // does not need to be swapped. + Append(context.float_save.register_area, + sizeof(context.float_save.register_area)); + D32(context.float_save.cr0_npx_state); + D32(context.gs); + D32(context.fs); + D32(context.es); + D32(context.ds); + D32(context.edi); + D32(context.esi); + D32(context.ebx); + D32(context.edx); + D32(context.ecx); + D32(context.eax); + D32(context.ebp); + D32(context.eip); + D32(context.cs); + D32(context.eflags); + D32(context.esp); + D32(context.ss); + // context.extended_registers[] contains 8-bit quantities and does + // not need to be swapped. + Append(context.extended_registers, sizeof(context.extended_registers)); + assert(Size() == sizeof(MDRawContextX86)); +} + +Context::Context(const Dump &dump, const MDRawContextARM &context) + : Section(dump) { + // The caller should have properly set the CPU type flag. + assert((context.context_flags & MD_CONTEXT_ARM) || + (context.context_flags & MD_CONTEXT_ARM_OLD)); + // It doesn't make sense to store ARM registers in big-endian form. + assert(dump.endianness() == kLittleEndian); + D32(context.context_flags); + for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) + D32(context.iregs[i]); + D32(context.cpsr); + D64(context.float_save.fpscr); + for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i) + D64(context.float_save.regs[i]); + for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i) + D32(context.float_save.extra[i]); + assert(Size() == sizeof(MDRawContextARM)); +} + +Context::Context(const Dump &dump, const MDRawContextMIPS &context) + : Section(dump) { + // The caller should have properly set the CPU type flag. + assert(context.context_flags & MD_CONTEXT_MIPS); + D32(context.context_flags); + D32(context._pad0); + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + D64(context.iregs[i]); + + D64(context.mdhi); + D64(context.mdlo); + + for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) + D32(context.hi[i]); + + for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i) + D32(context.lo[i]); + + D32(context.dsp_control); + D32(context._pad1); + + D64(context.epc); + D64(context.badvaddr); + D32(context.status); + D32(context.cause); + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + D64(context.float_save.regs[i]); + + D32(context.float_save.fpcsr); + D32(context.float_save.fir); + + assert(Size() == sizeof(MDRawContextMIPS)); +} + +Thread::Thread(const Dump &dump, + uint32_t thread_id, const Memory &stack, const Context &context, + uint32_t suspend_count, uint32_t priority_class, + uint32_t priority, uint64_t teb) : Section(dump) { + D32(thread_id); + D32(suspend_count); + D32(priority_class); + D32(priority); + D64(teb); + stack.CiteMemoryIn(this); + context.CiteLocationIn(this); + assert(Size() == sizeof(MDRawThread)); +} + +Module::Module(const Dump &dump, + uint64_t base_of_image, + uint32_t size_of_image, + const String &name, + uint32_t time_date_stamp, + uint32_t checksum, + const MDVSFixedFileInfo &version_info, + const Section *cv_record, + const Section *misc_record) : Section(dump) { + D64(base_of_image); + D32(size_of_image); + D32(checksum); + D32(time_date_stamp); + name.CiteStringIn(this); + D32(version_info.signature); + D32(version_info.struct_version); + D32(version_info.file_version_hi); + D32(version_info.file_version_lo); + D32(version_info.product_version_hi); + D32(version_info.product_version_lo); + D32(version_info.file_flags_mask); + D32(version_info.file_flags); + D32(version_info.file_os); + D32(version_info.file_type); + D32(version_info.file_subtype); + D32(version_info.file_date_hi); + D32(version_info.file_date_lo); + if (cv_record) + cv_record->CiteLocationIn(this); + else + D32(0).D32(0); + if (misc_record) + misc_record->CiteLocationIn(this); + else + D32(0).D32(0); + D64(0).D64(0); +} + +const MDVSFixedFileInfo Module::stock_version_info = { + MD_VSFIXEDFILEINFO_SIGNATURE, // signature + MD_VSFIXEDFILEINFO_VERSION, // struct_version + 0x11111111, // file_version_hi + 0x22222222, // file_version_lo + 0x33333333, // product_version_hi + 0x44444444, // product_version_lo + MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags_mask + MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags + MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32, + // file_os + MD_VSFIXEDFILEINFO_FILE_TYPE_APP, // file_type + MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype + 0, // file_date_hi + 0 // file_date_lo +}; + +UnloadedModule::UnloadedModule(const Dump &dump, + uint64_t base_of_image, + uint32_t size_of_image, + const String &name, + uint32_t checksum, + uint32_t time_date_stamp) : Section(dump) { + D64(base_of_image); + D32(size_of_image); + D32(checksum); + D32(time_date_stamp); + name.CiteStringIn(this); +} + +UnloadedModuleList::UnloadedModuleList(const Dump &dump, uint32_t type) + : List(dump, type, false) { + D32(sizeof(MDRawUnloadedModuleList)); + D32(sizeof(MDRawUnloadedModule)); + D32(count_label_); +} + +Exception::Exception(const Dump &dump, + const Context &context, + uint32_t thread_id, + uint32_t exception_code, + uint32_t exception_flags, + uint64_t exception_address) + : Stream(dump, MD_EXCEPTION_STREAM) { + D32(thread_id); + D32(0); // __align + D32(exception_code); + D32(exception_flags); + D64(0); // exception_record + D64(exception_address); + D32(0); // number_parameters + D32(0); // __align + for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i) + D64(0); // exception_information + context.CiteLocationIn(this); + assert(Size() == sizeof(MDRawExceptionStream)); +} + +Dump::Dump(uint64_t flags, + Endianness endianness, + uint32_t version, + uint32_t date_time_stamp) + : test_assembler::Section(endianness), + file_start_(0), + stream_directory_(*this), + stream_count_(0), + thread_list_(*this, MD_THREAD_LIST_STREAM), + module_list_(*this, MD_MODULE_LIST_STREAM), + unloaded_module_list_(*this, MD_UNLOADED_MODULE_LIST_STREAM), + memory_list_(*this, MD_MEMORY_LIST_STREAM) + { + D32(MD_HEADER_SIGNATURE); + D32(version); + D32(stream_count_label_); + D32(stream_directory_rva_); + D32(0); + D32(date_time_stamp); + D64(flags); + assert(Size() == sizeof(MDRawHeader)); +} + +Dump &Dump::Add(SynthMinidump::Section *section) { + section->Finish(file_start_ + Size()); + Append(*section); + return *this; +} + +Dump &Dump::Add(Stream *stream) { + Add(static_cast(stream)); + stream->CiteStreamIn(&stream_directory_); + stream_count_++; + return *this; +} + +Dump &Dump::Add(Memory *memory) { + // Add the memory contents themselves to the file. + Add(static_cast(memory)); + + // The memory list is a list of MDMemoryDescriptors, not of actual + // memory elements. Produce a descriptor, and add that to the list. + SynthMinidump::Section descriptor(*this); + memory->CiteMemoryIn(&descriptor); + memory_list_.Add(&descriptor); + return *this; +} + +Dump &Dump::Add(Thread *thread) { + thread_list_.Add(thread); + return *this; +} + +Dump &Dump::Add(Module *module) { + module_list_.Add(module); + return *this; +} + +Dump &Dump::Add(UnloadedModule *unloaded_module) { + unloaded_module_list_.Add(unloaded_module); + return *this; +} + +void Dump::Finish() { + if (!thread_list_.Empty()) Add(&thread_list_); + if (!module_list_.Empty()) Add(&module_list_); + if (!unloaded_module_list_.Empty()) Add(&unloaded_module_list_); + if (!memory_list_.Empty()) Add(&memory_list_); + + // Create the stream directory. We don't use + // stream_directory_.Finish here, because the stream directory isn't + // cited using a location descriptor; rather, the Minidump header + // has the stream count and MDRVA. + stream_count_label_ = stream_count_; + stream_directory_rva_ = file_start_ + Size(); + Append(static_cast(stream_directory_)); +} + +} // namespace SynthMinidump + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.h b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.h new file mode 100644 index 0000000000..8f49cfff22 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump.h @@ -0,0 +1,398 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// synth_minidump.h: Interface to SynthMinidump: fake minidump generator. +// +// We treat a minidump file as the concatenation of a bunch of +// test_assembler::Sections. The file header, stream directory, +// streams, memory regions, strings, and so on --- each is a Section +// that eventually gets appended to the minidump. Dump, Memory, +// Context, Thread, and so on all inherit from test_assembler::Section. +// For example: +// +// using google_breakpad::test_assembler::kLittleEndian; +// using google_breakpad::SynthMinidump::Context; +// using google_breakpad::SynthMinidump::Dump; +// using google_breakpad::SynthMinidump::Memory; +// using google_breakpad::SynthMinidump::Thread; +// +// Dump minidump(MD_NORMAL, kLittleEndian); +// +// Memory stack1(minidump, 0x569eb0a9); +// ... build contents of stack1 with test_assembler::Section functions ... +// +// MDRawContextX86 x86_context1; +// x86_context1.context_flags = MD_CONTEXT_X86; +// x86_context1.eip = 0x7c90eb94; +// x86_context1.esp = 0x569eb0a9; +// x86_context1.ebp = x86_context1.esp + something appropriate; +// Context context1(minidump, x86_context1); +// +// Thread thread1(minidump, 0xe4a4821d, stack1, context1); +// +// minidump.Add(&stack1); +// minidump.Add(&context1); +// minidump.Add(&thread1); +// minidump.Finish(); +// +// string contents; +// EXPECT_TRUE(minidump.GetContents(&contents)); +// // contents now holds the bytes of a minidump file +// +// Because the test_assembler classes let us write Label references to +// sections before the Labels' values are known, this gives us +// flexibility in how we put the dump together: minidump pieces can +// hold the file offsets of other minidump pieces before the +// referents' positions have been decided. As long as everything has +// been placed by the time we call dump.GetContents to obtain the +// bytes, all the Labels' values will be known, and everything will +// get patched up appropriately. +// +// The dump.Add(thing) functions append THINGS's contents to the +// minidump, but they also do two other things: +// +// - dump.Add(thing) invokes thing->Finish, which tells *thing the +// offset within the file at which it was placed, and allows *thing +// to do any final content generation. +// +// - If THING is something which should receive an entry in some sort +// of list or directory, then dump.Add(THING) automatically creates +// the appropriate directory or list entry. Streams must appear in +// the stream directory; memory ranges should be listed in the +// memory list; threads should be placed in the thread list; and so +// on. +// +// By convention, Section subclass constructors that take references +// to other Sections do not take care of 'Add'ing their arguments to +// the dump. For example, although the Thread constructor takes +// references to a Memory and a Context, it does not add them to the +// dump on the caller's behalf. Rather, the caller is responsible for +// 'Add'ing every section they create. This allows Sections to be +// cited from more than one place; for example, Memory ranges are +// cited both from Thread objects (as their stack contents) and by the +// memory list stream. +// +// If you forget to Add some Section, the Dump::GetContents call will +// fail, as the test_assembler::Labels used to cite the Section's +// contents from elsewhere will still be undefined. +#ifndef PROCESSOR_SYNTH_MINIDUMP_H_ +#define PROCESSOR_SYNTH_MINIDUMP_H_ + +#include + +#include +#include + +#include "common/test_assembler.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +namespace SynthMinidump { + +using test_assembler::Endianness; +using test_assembler::kBigEndian; +using test_assembler::kLittleEndian; +using test_assembler::kUnsetEndian; +using test_assembler::Label; + +class Dump; +class Memory; +class String; + +// A test_assembler::Section which will be appended to a minidump. +class Section: public test_assembler::Section { + public: + explicit Section(const Dump &dump); + + // Append an MDLocationDescriptor referring to this section to SECTION. + // If 'this' is NULL, append a descriptor with a zero length and MDRVA. + // + // (I couldn't find the language in the C++ standard that says that + // invoking member functions of a NULL pointer to a class type is + // bad, if such language exists. Having this function handle NULL + // 'this' is convenient, but if it causes trouble, it's not hard to + // do differently.) + void CiteLocationIn(test_assembler::Section *section) const; + + // Note that this section's contents are complete, and that it has + // been placed in the minidump file at OFFSET. The 'Add' member + // functions call the Finish member function of the object being + // added for you; if you are 'Add'ing this section, you needn't Finish it. + virtual void Finish(const Label &offset) { + file_offset_ = offset; size_ = Size(); + } + + protected: + // This section's size and offset within the minidump file. + Label file_offset_, size_; +}; + +// A stream within a minidump file. 'Add'ing a stream to a minidump +// creates an entry for it in the minidump's stream directory. +class Stream: public Section { + public: + // Create a stream of type TYPE. You can append whatever contents + // you like to this stream using the test_assembler::Section methods. + Stream(const Dump &dump, uint32_t type) : Section(dump), type_(type) { } + + // Append an MDRawDirectory referring to this stream to SECTION. + void CiteStreamIn(test_assembler::Section *section) const; + + private: + // The type of this stream. + uint32_t type_; +}; + +class SystemInfo: public Stream { + public: + // Create an MD_SYSTEM_INFO_STREAM stream belonging to DUMP holding + // an MDRawSystem info structure initialized with the values from + // SYSTEM_INFO, except that the csd_version field is replaced with + // the file offset of the string CSD_VERSION, which can be 'Add'ed + // to the dump at the desired location. + // + // Remember that you are still responsible for 'Add'ing CSD_VERSION + // to the dump yourself. + SystemInfo(const Dump &dump, + const MDRawSystemInfo &system_info, + const String &csd_version); + + // Stock MDRawSystemInfo information and associated strings, for + // writing tests. + static const MDRawSystemInfo windows_x86; + static const string windows_x86_csd_version; +}; + +// An MDString: a string preceded by a 32-bit length. +class String: public Section { + public: + String(const Dump &dump, const string &value); + + // Append an MDRVA referring to this string to SECTION. + void CiteStringIn(test_assembler::Section *section) const; +}; + +// A range of memory contents. 'Add'ing a memory range to a minidump +// creates n entry for it in the minidump's memory list. By +// convention, the 'start', 'Here', and 'Mark' member functions refer +// to memory addresses. +class Memory: public Section { + public: + Memory(const Dump &dump, uint64_t address) + : Section(dump), address_(address) { start() = address; } + + // Append an MDMemoryDescriptor referring to this memory range to SECTION. + void CiteMemoryIn(test_assembler::Section *section) const; + + private: + // The process address from which these memory contents were taken. + // Shouldn't this be a Label? + uint64_t address_; +}; + +class Context: public Section { + public: + // Create a context belonging to DUMP whose contents are a copy of CONTEXT. + Context(const Dump &dump, const MDRawContextX86 &context); + Context(const Dump &dump, const MDRawContextARM &context); + Context(const Dump &dump, const MDRawContextMIPS &context); + // Add an empty context to the dump. + Context(const Dump &dump) : Section(dump) {} + // Add constructors for other architectures here. Remember to byteswap. +}; + +class Thread: public Section { + public: + // Create a thread belonging to DUMP with the given values, citing + // STACK and CONTEXT (which you must Add to the dump separately). + Thread(const Dump &dump, + uint32_t thread_id, + const Memory &stack, + const Context &context, + uint32_t suspend_count = 0, + uint32_t priority_class = 0, + uint32_t priority = 0, + uint64_t teb = 0); +}; + +class Module: public Section { + public: + // Create a module with the given values. Note that CV_RECORD and + // MISC_RECORD can be NULL, in which case the corresponding location + // descriptior in the minidump will have a length of zero. + Module(const Dump &dump, + uint64_t base_of_image, + uint32_t size_of_image, + const String &name, + uint32_t time_date_stamp = 1262805309, + uint32_t checksum = 0, + const MDVSFixedFileInfo &version_info = Module::stock_version_info, + const Section *cv_record = NULL, + const Section *misc_record = NULL); + + private: + // A standard MDVSFixedFileInfo structure to use as a default for + // minidumps. There's no reason to make users write out all this crap + // over and over. + static const MDVSFixedFileInfo stock_version_info; +}; + +class UnloadedModule: public Section { + public: + UnloadedModule(const Dump &dump, + uint64_t base_of_image, + uint32_t size_of_image, + const String &name, + uint32_t checksum = 0, + uint32_t time_date_stamp = 1262805309); +}; + +class Exception : public Stream { +public: + Exception(const Dump &dump, + const Context &context, + uint32_t thread_id = 0, + uint32_t exception_code = 0, + uint32_t exception_flags = 0, + uint64_t exception_address = 0); +}; + +// A list of entries starting with a 32-bit count, like a memory list +// or a thread list. +template +class List: public Stream { + public: + List(const Dump &dump, uint32_t type) : Stream(dump, type), count_(0) { + D32(count_label_); + } + + // Add ELEMENT to this list. + void Add(Element *element) { + element->Finish(file_offset_ + Size()); + Append(*element); + count_++; + } + + // Return true if this List is empty, false otherwise. + bool Empty() { return count_ == 0; } + + // Finish up the contents of this section, mark it as having been + // placed at OFFSET. + virtual void Finish(const Label &offset) { + Stream::Finish(offset); + count_label_ = count_; + } + + private: + size_t count_; + + protected: + // This constructor allows derived lists to specify their own layout + // rather than starting with count as specified in the public constructor. + List(const Dump &dump, uint32_t type, bool) : Stream(dump, type), count_(0) {} + + Label count_label_; +}; + +class UnloadedModuleList : public List { + public: + UnloadedModuleList(const Dump &dump, uint32_t type); +}; + +class Dump: public test_assembler::Section { + public: + + // Create a test_assembler::Section containing a minidump file whose + // header uses the given values. ENDIANNESS determines the + // endianness of the signature; we set this section's default + // endianness by this. + Dump(uint64_t flags, + Endianness endianness = kLittleEndian, + uint32_t version = MD_HEADER_VERSION, + uint32_t date_time_stamp = 1262805309); + + // The following functions call OBJECT->Finish(), and append the + // contents of OBJECT to this minidump. They also record OBJECT in + // whatever directory or list is appropriate for its type. The + // stream directory, memory list, thread list, and module list are + // accumulated this way. + Dump &Add(SynthMinidump::Section *object); // simply append data + Dump &Add(Stream *object); // append, record in stream directory + Dump &Add(Memory *object); // append, record in memory list + Dump &Add(Thread *object); // append, record in thread list + Dump &Add(Module *object); // append, record in module list + Dump &Add(UnloadedModule *object); // append, record in unloaded module list + + // Complete the construction of the minidump, given the Add calls + // we've seen up to this point. After this call, this Dump's + // contents are complete, all labels should be defined if everything + // Cited has been Added, and you may call GetContents on it. + void Finish(); + + private: + // A label representing the start of the minidump file. + Label file_start_; + + // The stream directory. We construct this incrementally from + // Add(Stream *) calls. + SynthMinidump::Section stream_directory_; // The directory's contents. + size_t stream_count_; // The number of streams so far. + Label stream_count_label_; // Cited in file header. + Label stream_directory_rva_; // The directory's file offset. + + // This minidump's thread list. We construct this incrementally from + // Add(Thread *) calls. + List thread_list_; + + // This minidump's module list. We construct this incrementally from + // Add(Module *) calls. + List module_list_; + + // This minidump's unloaded module list. We construct this incrementally from + // Add(UnloadedModule *) calls. + UnloadedModuleList unloaded_module_list_; + + // This minidump's memory list. We construct this incrementally from + // Add(Memory *) calls. This is actually a list of MDMemoryDescriptors, + // not memory ranges --- thus the odd type. + List memory_list_; +}; + +} // namespace SynthMinidump + +} // namespace google_breakpad + +#endif // PROCESSOR_SYNTH_MINIDUMP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest.cc b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest.cc new file mode 100644 index 0000000000..8835b44933 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest.cc @@ -0,0 +1,336 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// synth_minidump_unittest.cc: Unit tests for google_breakpad::SynthMinidump +// classes. + +#include +#include + +#include "breakpad_googletest_includes.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" +#include "processor/synth_minidump.h" +#include "processor/synth_minidump_unittest_data.h" + +using google_breakpad::SynthMinidump::Context; +using google_breakpad::SynthMinidump::Dump; +using google_breakpad::SynthMinidump::Exception; +using google_breakpad::SynthMinidump::List; +using google_breakpad::SynthMinidump::Memory; +using google_breakpad::SynthMinidump::Module; +using google_breakpad::SynthMinidump::Section; +using google_breakpad::SynthMinidump::Stream; +using google_breakpad::SynthMinidump::String; +using google_breakpad::SynthMinidump::SystemInfo; +using google_breakpad::test_assembler::kBigEndian; +using google_breakpad::test_assembler::kLittleEndian; +using google_breakpad::test_assembler::Label; + +TEST(Section, Simple) { + Dump dump(0); + Section section(dump); + section.L32(0x12345678); + section.Finish(0); + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("\x78\x56\x34\x12", 4), contents); +} + +TEST(Section, CiteLocationIn) { + Dump dump(0, kBigEndian); + Section section1(dump), section2(dump); + section1.Append("order"); + section2.Append("mayhem"); + section2.Finish(0x32287ec2); + section2.CiteLocationIn(§ion1); + string contents; + ASSERT_TRUE(section1.GetContents(&contents)); + string expected("order\0\0\0\x06\x32\x28\x7e\xc2", 13); + EXPECT_EQ(expected, contents); +} + +TEST(Stream, CiteStreamIn) { + Dump dump(0, kLittleEndian); + Stream stream(dump, 0x40cae2b3); + Section section(dump); + stream.Append("stream contents"); + section.Append("section contents"); + stream.Finish(0x41424344); + stream.CiteStreamIn(§ion); + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + string expected("section contents" + "\xb3\xe2\xca\x40" + "\x0f\0\0\0" + "\x44\x43\x42\x41", + 16 + 4 + 4 + 4); + EXPECT_EQ(expected, contents); +} + +TEST(Memory, CiteMemoryIn) { + Dump dump(0, kBigEndian); + Memory memory(dump, 0x76d010874ab019f9ULL); + Section section(dump); + memory.Append("memory contents"); + section.Append("section contents"); + memory.Finish(0x51525354); + memory.CiteMemoryIn(§ion); + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + string expected("section contents" + "\x76\xd0\x10\x87\x4a\xb0\x19\xf9" + "\0\0\0\x0f" + "\x51\x52\x53\x54", + 16 + 8 + 4 + 4); + EXPECT_EQ(contents, expected); +} + +TEST(Memory, Here) { + Dump dump(0, kBigEndian); + Memory memory(dump, 0x89979731eb060ed4ULL); + memory.Append(1729, 42); + Label l = memory.Here(); + ASSERT_EQ(0x89979731eb060ed4ULL + 1729, l.Value()); +} + +TEST(Context, X86) { + Dump dump(0, kLittleEndian); + assert(x86_raw_context.context_flags & MD_CONTEXT_X86); + Context context(dump, x86_raw_context); + string contents; + ASSERT_TRUE(context.GetContents(&contents)); + EXPECT_EQ(sizeof(x86_expected_contents), contents.size()); + EXPECT_TRUE(memcmp(contents.data(), x86_expected_contents, contents.size()) + == 0); +} + +TEST(Context, ARM) { + Dump dump(0, kLittleEndian); + assert(arm_raw_context.context_flags & MD_CONTEXT_ARM); + Context context(dump, arm_raw_context); + string contents; + ASSERT_TRUE(context.GetContents(&contents)); + EXPECT_EQ(sizeof(arm_expected_contents), contents.size()); + EXPECT_TRUE(memcmp(contents.data(), arm_expected_contents, contents.size()) + == 0); +} + +TEST(ContextDeathTest, X86BadFlags) { + Dump dump(0, kLittleEndian); + MDRawContextX86 raw; + raw.context_flags = MD_CONTEXT_AMD64; + ASSERT_DEATH(Context context(dump, raw);, + "context\\.context_flags & (0x[0-9a-f]+|MD_CONTEXT_X86)"); +} + +TEST(ContextDeathTest, X86BadEndianness) { + Dump dump(0, kBigEndian); + MDRawContextX86 raw; + raw.context_flags = MD_CONTEXT_X86; + ASSERT_DEATH(Context context(dump, raw);, + "dump\\.endianness\\(\\) == kLittleEndian"); +} + +TEST(Thread, Simple) { + Dump dump(0, kLittleEndian); + Context context(dump, x86_raw_context); + context.Finish(0x8665da0c); + Memory stack(dump, 0xaad55a93cc3c0efcULL); + stack.Append("stack contents"); + stack.Finish(0xe08cdbd1); + google_breakpad::SynthMinidump::Thread thread( + dump, 0x3d7ec360, stack, context, + 0x3593f44d, // suspend count + 0xab352b82, // priority class + 0x2753d838, // priority + 0xeb2de4be3f29e3e9ULL); // thread environment block + string contents; + ASSERT_TRUE(thread.GetContents(&contents)); + static const uint8_t expected_bytes[] = { + 0x60, 0xc3, 0x7e, 0x3d, // thread id + 0x4d, 0xf4, 0x93, 0x35, // suspend count + 0x82, 0x2b, 0x35, 0xab, // priority class + 0x38, 0xd8, 0x53, 0x27, // priority + 0xe9, 0xe3, 0x29, 0x3f, 0xbe, 0xe4, 0x2d, 0xeb, // thread environment block + 0xfc, 0x0e, 0x3c, 0xcc, 0x93, 0x5a, 0xd5, 0xaa, // stack address + 0x0e, 0x00, 0x00, 0x00, // stack size + 0xd1, 0xdb, 0x8c, 0xe0, // stack MDRVA + 0xcc, 0x02, 0x00, 0x00, // context size + 0x0c, 0xda, 0x65, 0x86 // context MDRVA + }; + EXPECT_EQ(sizeof(expected_bytes), contents.size()); + EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0); +} + +TEST(Exception, Simple) { + Dump dump(0, kLittleEndian); + Context context(dump, x86_raw_context); + context.Finish(0x8665da0c); + + Exception exception(dump, context, + 0x1234abcd, // thread id + 0xdcba4321, // exception code + 0xf0e0d0c0, // exception flags + 0x0919a9b9c9d9e9f9ULL); // exception address + string contents; + ASSERT_TRUE(exception.GetContents(&contents)); + static const uint8_t expected_bytes[] = { + 0xcd, 0xab, 0x34, 0x12, // thread id + 0x00, 0x00, 0x00, 0x00, // __align + 0x21, 0x43, 0xba, 0xdc, // exception code + 0xc0, 0xd0, 0xe0, 0xf0, // exception flags + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception record + 0xf9, 0xe9, 0xd9, 0xc9, 0xb9, 0xa9, 0x19, 0x09, // exception address + 0x00, 0x00, 0x00, 0x00, // number parameters + 0x00, 0x00, 0x00, 0x00, // __align + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information + 0xcc, 0x02, 0x00, 0x00, // context size + 0x0c, 0xda, 0x65, 0x86 // context MDRVA + }; + EXPECT_EQ(sizeof(expected_bytes), contents.size()); + EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0); +} + +TEST(String, Simple) { + Dump dump(0, kBigEndian); + String s(dump, "All mimsy were the borogoves"); + string contents; + ASSERT_TRUE(s.GetContents(&contents)); + static const char expected[] = + "\x00\x00\x00\x38\0A\0l\0l\0 \0m\0i\0m\0s\0y\0 \0w\0e\0r\0e" + "\0 \0t\0h\0e\0 \0b\0o\0r\0o\0g\0o\0v\0e\0s"; + string expected_string(expected, sizeof(expected) - 1); + EXPECT_EQ(expected_string, contents); +} + +TEST(String, CiteStringIn) { + Dump dump(0, kLittleEndian); + String s(dump, "and the mome wraths outgrabe"); + Section section(dump); + section.Append("initial"); + s.CiteStringIn(§ion); + s.Finish(0xdc2bb469); + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + EXPECT_EQ(string("initial\x69\xb4\x2b\xdc", 7 + 4), contents); +} + +TEST(List, Empty) { + Dump dump(0, kBigEndian); + List
list(dump, 0x2442779c); + EXPECT_TRUE(list.Empty()); + list.Finish(0x84e09808); + string contents; + ASSERT_TRUE(list.GetContents(&contents)); + EXPECT_EQ(string("\0\0\0\0", 4), contents); +} + +TEST(List, Two) { + Dump dump(0, kBigEndian); + List
list(dump, 0x26c9f498); + Section section1(dump); + section1.Append("section one contents"); + EXPECT_TRUE(list.Empty()); + list.Add(§ion1); + EXPECT_FALSE(list.Empty()); + Section section2(dump); + section2.Append("section two contents"); + list.Add(§ion2); + list.Finish(0x1e5bb60e); + string contents; + ASSERT_TRUE(list.GetContents(&contents)); + EXPECT_EQ(string("\0\0\0\x02section one contentssection two contents", 44), + contents); +} + +TEST(Dump, Header) { + Dump dump(0x9f738b33685cc84cULL, kLittleEndian, 0xb3817faf, 0x2c741c0a); + dump.Finish(); + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + ASSERT_EQ(string("\x4d\x44\x4d\x50" // signature + "\xaf\x7f\x81\xb3" // version + "\0\0\0\0" // stream count + "\x20\0\0\0" // directory RVA (could be anything) + "\0\0\0\0" // checksum + "\x0a\x1c\x74\x2c" // time_date_stamp + "\x4c\xc8\x5c\x68\x33\x8b\x73\x9f", // flags + 32), + contents); +} + +TEST(Dump, HeaderBigEndian) { + Dump dump(0x206ce3cc6fb8e0f0ULL, kBigEndian, 0x161693e2, 0x35667744); + dump.Finish(); + string contents; + ASSERT_TRUE(dump.GetContents(&contents)); + ASSERT_EQ(string("\x50\x4d\x44\x4d" // signature + "\x16\x16\x93\xe2" // version + "\0\0\0\0" // stream count + "\0\0\0\x20" // directory RVA (could be anything) + "\0\0\0\0" // checksum + "\x35\x66\x77\x44" // time_date_stamp + "\x20\x6c\xe3\xcc\x6f\xb8\xe0\xf0", // flags + 32), + contents); +} + +TEST(Dump, OneSection) { + Dump dump(0, kLittleEndian); + Section section(dump); + section.Append("section contents"); + dump.Add(§ion); + dump.Finish(); + string dump_contents; + // Just check for undefined labels; don't worry about the contents. + ASSERT_TRUE(dump.GetContents(&dump_contents)); + + Section referencing_section(dump); + section.CiteLocationIn(&referencing_section); + string contents; + ASSERT_TRUE(referencing_section.GetContents(&contents)); + ASSERT_EQ(string("\x10\0\0\0\x20\0\0\0", 8), contents); +} diff --git a/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest_data.h b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest_data.h new file mode 100644 index 0000000000..3403372e6c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/synth_minidump_unittest_data.h @@ -0,0 +1,418 @@ +// -*- mode: C++ -*- + +// Not copyrightable: random test data. +// synth_minidump_unittest_data.h: verbose test data for SynthMinidump tests. + +#ifndef PROCESSOR_SYNTH_MINIDUMP_UNITTEST_DATA_H_ +#define PROCESSOR_SYNTH_MINIDUMP_UNITTEST_DATA_H_ + +#include "google_breakpad/common/minidump_format.h" + +static const MDRawContextX86 x86_raw_context = { + 0xded5d71b, // context_flags + 0x9fdb432e, // dr0 + 0x26b7a81a, // dr1 + 0xcac7e348, // dr2 + 0xcf99ec09, // dr3 + 0x7dc8c2cd, // dr6 + 0x21deb880, // dr7 + + // float_save + { + 0x8a5d2bb0, // control_word + 0x0286c4c9, // status_word + 0xf1feea21, // tag_word + 0xb2d40576, // error_offset + 0x48146cde, // error_selector + 0x983f9b21, // data_offset + 0x475be12c, // data_selector + + // register_area + { + 0xd9, 0x04, 0x20, 0x6b, 0x88, 0x3a, 0x3f, 0xd5, + 0x59, 0x7a, 0xa9, 0xeb, 0xd0, 0x5c, 0xdf, 0xfe, + 0xad, 0xdd, 0x4a, 0x8b, 0x10, 0xcc, 0x9a, 0x33, + 0xcb, 0xb6, 0xf7, 0x86, 0xcd, 0x69, 0x25, 0xae, + 0x25, 0xe5, 0x7a, 0xa1, 0x8f, 0xb2, 0x84, 0xd9, + 0xf7, 0x2d, 0x8a, 0xa1, 0x80, 0x81, 0x7f, 0x67, + 0x07, 0xa8, 0x23, 0xf1, 0x8c, 0xdc, 0xd8, 0x04, + 0x8b, 0x9d, 0xb1, 0xcd, 0x61, 0x0c, 0x9c, 0x69, + 0xc7, 0x8d, 0x17, 0xb6, 0xe5, 0x0b, 0x94, 0xf7, + 0x78, 0x9b, 0x63, 0x49, 0xba, 0xfc, 0x08, 0x4d + }, + + 0x84c53a90, // cr0_npx_state + }, + + 0x79f71e76, // gs + 0x8107bd25, // fs + 0x452d2921, // es + 0x87ec2875, // ds + 0xf8bb73f5, // edi + 0xa63ebb88, // esi + 0x95d35ebe, // ebx + 0x17aa2456, // edx + 0x135fa208, // ecx + 0x500615e6, // eax + 0x66d14205, // ebp + 0x000719a5, // eip + 0x477b481b, // cs + 0x8684dfba, // eflags + 0xe33ccddf, // esp + 0xc0e65d33, // ss + + // extended_registers + { + 0x68, 0x63, 0xdf, 0x50, 0xf7, 0x3b, 0xe8, 0xe5, + 0xcb, 0xd6, 0x66, 0x60, 0xe5, 0xa3, 0x58, 0xb3, + 0x6f, 0x34, 0xca, 0x02, 0x9b, 0x5f, 0xd0, 0x41, + 0xbd, 0xc5, 0x2d, 0xf8, 0xff, 0x15, 0xa2, 0xd0, + 0xe3, 0x2b, 0x3b, 0x8a, 0x9f, 0xc3, 0x9e, 0x28, + 0x0a, 0xc2, 0xac, 0x3b, 0x67, 0x37, 0x01, 0xfd, + 0xc3, 0xaf, 0x60, 0xf6, 0x2c, 0x4f, 0xa9, 0x52, + 0x92, 0xe5, 0x28, 0xde, 0x34, 0xb6, 0x2e, 0x44, + 0x15, 0xa4, 0xb6, 0xe4, 0xc9, 0x1a, 0x14, 0xb9, + 0x51, 0x33, 0x3c, 0xe0, 0xc7, 0x94, 0xf0, 0xf7, + 0x78, 0xdd, 0xe5, 0xca, 0xb7, 0xa6, 0xe0, 0x14, + 0xa6, 0x03, 0xab, 0x77, 0xad, 0xbd, 0xd2, 0x53, + 0x3d, 0x07, 0xe7, 0xaf, 0x90, 0x44, 0x71, 0xbe, + 0x0c, 0xdf, 0x2b, 0x97, 0x40, 0x48, 0xd5, 0xf9, + 0x62, 0x03, 0x91, 0x84, 0xd6, 0xdd, 0x29, 0x97, + 0x35, 0x02, 0xfb, 0x59, 0x97, 0xb0, 0xec, 0xa9, + 0x39, 0x6f, 0x81, 0x71, 0x2a, 0xf0, 0xe7, 0x2c, + 0x4e, 0x93, 0x90, 0xcb, 0x67, 0x69, 0xde, 0xd7, + 0x68, 0x3b, 0x0f, 0x69, 0xa8, 0xf4, 0xa8, 0x83, + 0x42, 0x80, 0x47, 0x65, 0x7a, 0xc9, 0x19, 0x5d, + 0xcb, 0x43, 0xa5, 0xff, 0xf8, 0x9e, 0x62, 0xf4, + 0xe2, 0x6c, 0xcc, 0x17, 0x55, 0x7c, 0x0d, 0x5c, + 0x8d, 0x16, 0x01, 0xd7, 0x3a, 0x0c, 0xf4, 0x7f, + 0x71, 0xdc, 0x48, 0xe9, 0x4b, 0xfe, 0x1a, 0xd0, + 0x04, 0x15, 0x33, 0xec, 0x78, 0xc6, 0x7e, 0xde, + 0x7c, 0x23, 0x18, 0x8d, 0x8f, 0xc2, 0x74, 0xc1, + 0x48, 0xcd, 0x5d, 0xee, 0xee, 0x81, 0x9e, 0x49, + 0x47, 0x8a, 0xf8, 0x61, 0xa3, 0x9c, 0x81, 0x96, + 0xbe, 0x2b, 0x5e, 0xbc, 0xcd, 0x34, 0x0a, 0x2a, + 0x3b, 0x8b, 0x7d, 0xa1, 0xf2, 0x8d, 0xb4, 0x51, + 0x9e, 0x14, 0x78, 0xa3, 0x58, 0x65, 0x2d, 0xd6, + 0x50, 0x40, 0x36, 0x32, 0x31, 0xd4, 0x3e, 0xc2, + 0xe0, 0x87, 0x1c, 0x05, 0x95, 0x80, 0x84, 0x24, + 0x08, 0x6f, 0x5b, 0xc7, 0xe1, 0x1d, 0xd5, 0xa3, + 0x94, 0x44, 0xa1, 0x7c, 0xd8, 0x4b, 0x86, 0xd2, + 0xc6, 0xa9, 0xf3, 0xe2, 0x4d, 0x6e, 0x1f, 0x0e, + 0xf2, 0xf5, 0x71, 0xf9, 0x71, 0x05, 0x24, 0xc9, + 0xc1, 0xe8, 0x91, 0x42, 0x61, 0x86, 0x57, 0x68, + 0xd9, 0xc9, 0x1d, 0xd5, 0x5a, 0xe9, 0xba, 0xe6, + 0x15, 0x8f, 0x87, 0xbd, 0x62, 0x56, 0xed, 0xda, + 0xc2, 0xa5, 0xd5, 0x39, 0xac, 0x05, 0x10, 0x14, + 0x4a, 0xe7, 0xe7, 0x3c, 0x3f, 0xb7, 0xbb, 0xed, + 0x01, 0x6e, 0xcd, 0xee, 0x81, 0xb4, 0x62, 0xf4, + 0x62, 0x16, 0xff, 0x20, 0xb4, 0xf0, 0xbc, 0xff, + 0x7d, 0xd9, 0xcf, 0x95, 0x30, 0x27, 0xe0, 0x2f, + 0x98, 0x53, 0x80, 0x15, 0x13, 0xef, 0x44, 0x58, + 0x12, 0x16, 0xdb, 0x11, 0xef, 0x73, 0x51, 0xcd, + 0x42, 0x3f, 0x98, 0x6c, 0xc9, 0x68, 0xc3, 0xf4, + 0x5b, 0x0f, 0x5d, 0x77, 0xed, 0xdf, 0x0f, 0xff, + 0xb8, 0x69, 0x98, 0x50, 0x77, 0x7a, 0xe8, 0x90, + 0x27, 0x46, 0x10, 0xd2, 0xb5, 0x00, 0x3b, 0x36, + 0x43, 0x6d, 0x67, 0x41, 0x20, 0x3a, 0x32, 0xe0, + 0x2e, 0x5a, 0xfb, 0x4e, 0x4f, 0xa4, 0xf7, 0xc2, + 0xe6, 0x81, 0x1a, 0x51, 0xa8, 0x7c, 0xd4, 0x60, + 0x7c, 0x45, 0xe2, 0xba, 0x5b, 0x42, 0xf3, 0xbf, + 0x28, 0xaa, 0xf2, 0x90, 0xe4, 0x94, 0xdd, 0xaa, + 0x22, 0xd3, 0x71, 0x33, 0xa1, 0x01, 0x43, 0x0e, + 0xfa, 0x46, 0xd2, 0x6e, 0x55, 0x5e, 0x49, 0xeb, + 0x94, 0xf0, 0xb0, 0xb1, 0x2e, 0xf2, 0x3d, 0x6c, + 0x00, 0x5e, 0x01, 0x56, 0x3b, 0xfd, 0x5b, 0xa1, + 0x2f, 0x63, 0x1d, 0xbf, 0xf9, 0xd8, 0x13, 0xf7, + 0x4d, 0xb7, 0x1e, 0x3d, 0x98, 0xd2, 0xee, 0xb8, + 0x48, 0xc8, 0x5b, 0x91, 0x0f, 0x54, 0x9e, 0x26, + 0xb2, 0xc7, 0x3a, 0x6c, 0x8a, 0x35, 0xe1, 0xba + } +}; + +static const uint8_t x86_expected_contents[] = { + 0x1b, 0xd7, 0xd5, 0xde, + 0x2e, 0x43, 0xdb, 0x9f, + 0x1a, 0xa8, 0xb7, 0x26, + 0x48, 0xe3, 0xc7, 0xca, + 0x09, 0xec, 0x99, 0xcf, + 0xcd, 0xc2, 0xc8, 0x7d, + 0x80, 0xb8, 0xde, 0x21, + 0xb0, 0x2b, 0x5d, 0x8a, + 0xc9, 0xc4, 0x86, 0x02, + 0x21, 0xea, 0xfe, 0xf1, + 0x76, 0x05, 0xd4, 0xb2, + 0xde, 0x6c, 0x14, 0x48, + 0x21, 0x9b, 0x3f, 0x98, + 0x2c, 0xe1, 0x5b, 0x47, + + // float_save.register_area --- unswapped + 0xd9, 0x04, 0x20, 0x6b, 0x88, 0x3a, 0x3f, 0xd5, + 0x59, 0x7a, 0xa9, 0xeb, 0xd0, 0x5c, 0xdf, 0xfe, + 0xad, 0xdd, 0x4a, 0x8b, 0x10, 0xcc, 0x9a, 0x33, + 0xcb, 0xb6, 0xf7, 0x86, 0xcd, 0x69, 0x25, 0xae, + 0x25, 0xe5, 0x7a, 0xa1, 0x8f, 0xb2, 0x84, 0xd9, + 0xf7, 0x2d, 0x8a, 0xa1, 0x80, 0x81, 0x7f, 0x67, + 0x07, 0xa8, 0x23, 0xf1, 0x8c, 0xdc, 0xd8, 0x04, + 0x8b, 0x9d, 0xb1, 0xcd, 0x61, 0x0c, 0x9c, 0x69, + 0xc7, 0x8d, 0x17, 0xb6, 0xe5, 0x0b, 0x94, 0xf7, + 0x78, 0x9b, 0x63, 0x49, 0xba, 0xfc, 0x08, 0x4d, + + 0x90, 0x3a, 0xc5, 0x84, + 0x76, 0x1e, 0xf7, 0x79, + 0x25, 0xbd, 0x07, 0x81, + 0x21, 0x29, 0x2d, 0x45, + 0x75, 0x28, 0xec, 0x87, + 0xf5, 0x73, 0xbb, 0xf8, + 0x88, 0xbb, 0x3e, 0xa6, + 0xbe, 0x5e, 0xd3, 0x95, + 0x56, 0x24, 0xaa, 0x17, + 0x08, 0xa2, 0x5f, 0x13, + 0xe6, 0x15, 0x06, 0x50, + 0x05, 0x42, 0xd1, 0x66, + 0xa5, 0x19, 0x07, 0x00, + 0x1b, 0x48, 0x7b, 0x47, + 0xba, 0xdf, 0x84, 0x86, + 0xdf, 0xcd, 0x3c, 0xe3, + 0x33, 0x5d, 0xe6, 0xc0, + + // extended_registers --- unswapped + 0x68, 0x63, 0xdf, 0x50, 0xf7, 0x3b, 0xe8, 0xe5, + 0xcb, 0xd6, 0x66, 0x60, 0xe5, 0xa3, 0x58, 0xb3, + 0x6f, 0x34, 0xca, 0x02, 0x9b, 0x5f, 0xd0, 0x41, + 0xbd, 0xc5, 0x2d, 0xf8, 0xff, 0x15, 0xa2, 0xd0, + 0xe3, 0x2b, 0x3b, 0x8a, 0x9f, 0xc3, 0x9e, 0x28, + 0x0a, 0xc2, 0xac, 0x3b, 0x67, 0x37, 0x01, 0xfd, + 0xc3, 0xaf, 0x60, 0xf6, 0x2c, 0x4f, 0xa9, 0x52, + 0x92, 0xe5, 0x28, 0xde, 0x34, 0xb6, 0x2e, 0x44, + 0x15, 0xa4, 0xb6, 0xe4, 0xc9, 0x1a, 0x14, 0xb9, + 0x51, 0x33, 0x3c, 0xe0, 0xc7, 0x94, 0xf0, 0xf7, + 0x78, 0xdd, 0xe5, 0xca, 0xb7, 0xa6, 0xe0, 0x14, + 0xa6, 0x03, 0xab, 0x77, 0xad, 0xbd, 0xd2, 0x53, + 0x3d, 0x07, 0xe7, 0xaf, 0x90, 0x44, 0x71, 0xbe, + 0x0c, 0xdf, 0x2b, 0x97, 0x40, 0x48, 0xd5, 0xf9, + 0x62, 0x03, 0x91, 0x84, 0xd6, 0xdd, 0x29, 0x97, + 0x35, 0x02, 0xfb, 0x59, 0x97, 0xb0, 0xec, 0xa9, + 0x39, 0x6f, 0x81, 0x71, 0x2a, 0xf0, 0xe7, 0x2c, + 0x4e, 0x93, 0x90, 0xcb, 0x67, 0x69, 0xde, 0xd7, + 0x68, 0x3b, 0x0f, 0x69, 0xa8, 0xf4, 0xa8, 0x83, + 0x42, 0x80, 0x47, 0x65, 0x7a, 0xc9, 0x19, 0x5d, + 0xcb, 0x43, 0xa5, 0xff, 0xf8, 0x9e, 0x62, 0xf4, + 0xe2, 0x6c, 0xcc, 0x17, 0x55, 0x7c, 0x0d, 0x5c, + 0x8d, 0x16, 0x01, 0xd7, 0x3a, 0x0c, 0xf4, 0x7f, + 0x71, 0xdc, 0x48, 0xe9, 0x4b, 0xfe, 0x1a, 0xd0, + 0x04, 0x15, 0x33, 0xec, 0x78, 0xc6, 0x7e, 0xde, + 0x7c, 0x23, 0x18, 0x8d, 0x8f, 0xc2, 0x74, 0xc1, + 0x48, 0xcd, 0x5d, 0xee, 0xee, 0x81, 0x9e, 0x49, + 0x47, 0x8a, 0xf8, 0x61, 0xa3, 0x9c, 0x81, 0x96, + 0xbe, 0x2b, 0x5e, 0xbc, 0xcd, 0x34, 0x0a, 0x2a, + 0x3b, 0x8b, 0x7d, 0xa1, 0xf2, 0x8d, 0xb4, 0x51, + 0x9e, 0x14, 0x78, 0xa3, 0x58, 0x65, 0x2d, 0xd6, + 0x50, 0x40, 0x36, 0x32, 0x31, 0xd4, 0x3e, 0xc2, + 0xe0, 0x87, 0x1c, 0x05, 0x95, 0x80, 0x84, 0x24, + 0x08, 0x6f, 0x5b, 0xc7, 0xe1, 0x1d, 0xd5, 0xa3, + 0x94, 0x44, 0xa1, 0x7c, 0xd8, 0x4b, 0x86, 0xd2, + 0xc6, 0xa9, 0xf3, 0xe2, 0x4d, 0x6e, 0x1f, 0x0e, + 0xf2, 0xf5, 0x71, 0xf9, 0x71, 0x05, 0x24, 0xc9, + 0xc1, 0xe8, 0x91, 0x42, 0x61, 0x86, 0x57, 0x68, + 0xd9, 0xc9, 0x1d, 0xd5, 0x5a, 0xe9, 0xba, 0xe6, + 0x15, 0x8f, 0x87, 0xbd, 0x62, 0x56, 0xed, 0xda, + 0xc2, 0xa5, 0xd5, 0x39, 0xac, 0x05, 0x10, 0x14, + 0x4a, 0xe7, 0xe7, 0x3c, 0x3f, 0xb7, 0xbb, 0xed, + 0x01, 0x6e, 0xcd, 0xee, 0x81, 0xb4, 0x62, 0xf4, + 0x62, 0x16, 0xff, 0x20, 0xb4, 0xf0, 0xbc, 0xff, + 0x7d, 0xd9, 0xcf, 0x95, 0x30, 0x27, 0xe0, 0x2f, + 0x98, 0x53, 0x80, 0x15, 0x13, 0xef, 0x44, 0x58, + 0x12, 0x16, 0xdb, 0x11, 0xef, 0x73, 0x51, 0xcd, + 0x42, 0x3f, 0x98, 0x6c, 0xc9, 0x68, 0xc3, 0xf4, + 0x5b, 0x0f, 0x5d, 0x77, 0xed, 0xdf, 0x0f, 0xff, + 0xb8, 0x69, 0x98, 0x50, 0x77, 0x7a, 0xe8, 0x90, + 0x27, 0x46, 0x10, 0xd2, 0xb5, 0x00, 0x3b, 0x36, + 0x43, 0x6d, 0x67, 0x41, 0x20, 0x3a, 0x32, 0xe0, + 0x2e, 0x5a, 0xfb, 0x4e, 0x4f, 0xa4, 0xf7, 0xc2, + 0xe6, 0x81, 0x1a, 0x51, 0xa8, 0x7c, 0xd4, 0x60, + 0x7c, 0x45, 0xe2, 0xba, 0x5b, 0x42, 0xf3, 0xbf, + 0x28, 0xaa, 0xf2, 0x90, 0xe4, 0x94, 0xdd, 0xaa, + 0x22, 0xd3, 0x71, 0x33, 0xa1, 0x01, 0x43, 0x0e, + 0xfa, 0x46, 0xd2, 0x6e, 0x55, 0x5e, 0x49, 0xeb, + 0x94, 0xf0, 0xb0, 0xb1, 0x2e, 0xf2, 0x3d, 0x6c, + 0x00, 0x5e, 0x01, 0x56, 0x3b, 0xfd, 0x5b, 0xa1, + 0x2f, 0x63, 0x1d, 0xbf, 0xf9, 0xd8, 0x13, 0xf7, + 0x4d, 0xb7, 0x1e, 0x3d, 0x98, 0xd2, 0xee, 0xb8, + 0x48, 0xc8, 0x5b, 0x91, 0x0f, 0x54, 0x9e, 0x26, + 0xb2, 0xc7, 0x3a, 0x6c, 0x8a, 0x35, 0xe1, 0xba +}; + +static const MDRawContextARM arm_raw_context = { + // context_flags + 0x591b9e6a, + // iregs + { + 0xa21594de, + 0x820d8a25, + 0xc4e133b2, + 0x173a1c02, + 0x105fb175, + 0xe871793f, + 0x5def70b3, + 0xcee3a623, + 0x7b3aa9b8, + 0x52518537, + 0x627012c5, + 0x22723dcc, + 0x16fcc971, + 0x20988bcb, + 0xf1ab806b, + 0x99d5fc03, + }, + // cpsr + 0xb70df511, + // float_save + { + // fpscr + 0xa1e1f7ce1077e6b5ULL, + // regs + { + 0xbcb8d002eed7fbdeULL, + 0x4dd26a43b96ae97fULL, + 0x8eec22db8b31741cULL, + 0xfd634bd7c5ad66a0ULL, + 0x1681da0daeb3debeULL, + 0x474a32bdf72d0b71ULL, + 0xcaf464f8b1044834ULL, + 0xcaa6592ae5c7582aULL, + 0x4ee46889d877c3dbULL, + 0xf8930cf301645cf5ULL, + 0x4da7e9ebba27f7c7ULL, + 0x69a7b02761944da3ULL, + 0x2cda2b2e78195c06ULL, + 0x66b227ab9b460a42ULL, + 0x7e77e49e52ee0849ULL, + 0xd62cd9663e76f255ULL, + 0xe9370f082451514bULL, + 0x50a1c674dd1b6029ULL, + 0x405db4575829eac4ULL, + 0x67b948764649eee7ULL, + 0x93731885419229d4ULL, + 0xdb0338bad72a4ce7ULL, + 0xa0a451f996fca4c8ULL, + 0xb4508ea668400a45ULL, + 0xbff28c5c7a142423ULL, + 0x4f31b42b96f3a431ULL, + 0x2ce6789d4ea1ff37ULL, + 0xfa150b52e4f82a3cULL, + 0xe9ec40449e6ed4f3ULL, + 0x5ceca87836fe2251ULL, + 0x66f50de463ee238cULL, + 0x42823efcd59ab511ULL, + }, + // extra + { + 0xe9e14cd2, + 0x865bb640, + 0x9f3f0b3e, + 0x94a71c52, + 0x3c012f19, + 0x6436637c, + 0x46ccedcb, + 0x7b341be7, + } + } +}; + +static const uint8_t arm_expected_contents[] = { + 0x6a, 0x9e, 0x1b, 0x59, + 0xde, 0x94, 0x15, 0xa2, + 0x25, 0x8a, 0x0d, 0x82, + 0xb2, 0x33, 0xe1, 0xc4, + 0x02, 0x1c, 0x3a, 0x17, + 0x75, 0xb1, 0x5f, 0x10, + 0x3f, 0x79, 0x71, 0xe8, + 0xb3, 0x70, 0xef, 0x5d, + 0x23, 0xa6, 0xe3, 0xce, + 0xb8, 0xa9, 0x3a, 0x7b, + 0x37, 0x85, 0x51, 0x52, + 0xc5, 0x12, 0x70, 0x62, + 0xcc, 0x3d, 0x72, 0x22, + 0x71, 0xc9, 0xfc, 0x16, + 0xcb, 0x8b, 0x98, 0x20, + 0x6b, 0x80, 0xab, 0xf1, + 0x03, 0xfc, 0xd5, 0x99, + 0x11, 0xf5, 0x0d, 0xb7, + 0xb5, 0xe6, 0x77, 0x10, + 0xce, 0xf7, 0xe1, 0xa1, + 0xde, 0xfb, 0xd7, 0xee, + 0x02, 0xd0, 0xb8, 0xbc, + 0x7f, 0xe9, 0x6a, 0xb9, + 0x43, 0x6a, 0xd2, 0x4d, + 0x1c, 0x74, 0x31, 0x8b, + 0xdb, 0x22, 0xec, 0x8e, + 0xa0, 0x66, 0xad, 0xc5, + 0xd7, 0x4b, 0x63, 0xfd, + 0xbe, 0xde, 0xb3, 0xae, + 0x0d, 0xda, 0x81, 0x16, + 0x71, 0x0b, 0x2d, 0xf7, + 0xbd, 0x32, 0x4a, 0x47, + 0x34, 0x48, 0x04, 0xb1, + 0xf8, 0x64, 0xf4, 0xca, + 0x2a, 0x58, 0xc7, 0xe5, + 0x2a, 0x59, 0xa6, 0xca, + 0xdb, 0xc3, 0x77, 0xd8, + 0x89, 0x68, 0xe4, 0x4e, + 0xf5, 0x5c, 0x64, 0x01, + 0xf3, 0x0c, 0x93, 0xf8, + 0xc7, 0xf7, 0x27, 0xba, + 0xeb, 0xe9, 0xa7, 0x4d, + 0xa3, 0x4d, 0x94, 0x61, + 0x27, 0xb0, 0xa7, 0x69, + 0x06, 0x5c, 0x19, 0x78, + 0x2e, 0x2b, 0xda, 0x2c, + 0x42, 0x0a, 0x46, 0x9b, + 0xab, 0x27, 0xb2, 0x66, + 0x49, 0x08, 0xee, 0x52, + 0x9e, 0xe4, 0x77, 0x7e, + 0x55, 0xf2, 0x76, 0x3e, + 0x66, 0xd9, 0x2c, 0xd6, + 0x4b, 0x51, 0x51, 0x24, + 0x08, 0x0f, 0x37, 0xe9, + 0x29, 0x60, 0x1b, 0xdd, + 0x74, 0xc6, 0xa1, 0x50, + 0xc4, 0xea, 0x29, 0x58, + 0x57, 0xb4, 0x5d, 0x40, + 0xe7, 0xee, 0x49, 0x46, + 0x76, 0x48, 0xb9, 0x67, + 0xd4, 0x29, 0x92, 0x41, + 0x85, 0x18, 0x73, 0x93, + 0xe7, 0x4c, 0x2a, 0xd7, + 0xba, 0x38, 0x03, 0xdb, + 0xc8, 0xa4, 0xfc, 0x96, + 0xf9, 0x51, 0xa4, 0xa0, + 0x45, 0x0a, 0x40, 0x68, + 0xa6, 0x8e, 0x50, 0xb4, + 0x23, 0x24, 0x14, 0x7a, + 0x5c, 0x8c, 0xf2, 0xbf, + 0x31, 0xa4, 0xf3, 0x96, + 0x2b, 0xb4, 0x31, 0x4f, + 0x37, 0xff, 0xa1, 0x4e, + 0x9d, 0x78, 0xe6, 0x2c, + 0x3c, 0x2a, 0xf8, 0xe4, + 0x52, 0x0b, 0x15, 0xfa, + 0xf3, 0xd4, 0x6e, 0x9e, + 0x44, 0x40, 0xec, 0xe9, + 0x51, 0x22, 0xfe, 0x36, + 0x78, 0xa8, 0xec, 0x5c, + 0x8c, 0x23, 0xee, 0x63, + 0xe4, 0x0d, 0xf5, 0x66, + 0x11, 0xb5, 0x9a, 0xd5, + 0xfc, 0x3e, 0x82, 0x42, + 0xd2, 0x4c, 0xe1, 0xe9, + 0x40, 0xb6, 0x5b, 0x86, + 0x3e, 0x0b, 0x3f, 0x9f, + 0x52, 0x1c, 0xa7, 0x94, + 0x19, 0x2f, 0x01, 0x3c, + 0x7c, 0x63, 0x36, 0x64, + 0xcb, 0xed, 0xcc, 0x46, + 0xe7, 0x1b, 0x34, 0x7b +}; + +#endif // PROCESSOR_SYNTH_MINIDUMP_UNITTEST_DATA_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/tokenize.cc b/toolkit/crashreporter/google-breakpad/src/processor/tokenize.cc new file mode 100644 index 0000000000..8fce87a224 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/tokenize.cc @@ -0,0 +1,79 @@ +// Copyright (c) 2010, 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 + +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +#ifdef _MSC_VER +#define strtok_r strtok_s +#endif + +using std::vector; + +bool Tokenize(char *line, + const char *separators, + int max_tokens, + vector *tokens) { + tokens->clear(); + tokens->reserve(max_tokens); + + int remaining = max_tokens; + + // Split tokens on the separator character. + // strip them out before exhausting max_tokens. + char *save_ptr; + char *token = strtok_r(line, separators, &save_ptr); + while (token && --remaining > 0) { + tokens->push_back(token); + if (remaining > 1) + token = strtok_r(NULL, separators, &save_ptr); + } + + // If there's anything left, just add it as a single token. + if (remaining == 0 && (token = strtok_r(NULL, "\r\n", &save_ptr))) { + tokens->push_back(token); + } + + return tokens->size() == static_cast(max_tokens); +} + +void StringToVector(const string &str, vector &vec) { + vec.resize(str.length() + 1); + std::copy(str.begin(), str.end(), + vec.begin()); + vec[str.length()] = '\0'; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/processor/tokenize.h b/toolkit/crashreporter/google-breakpad/src/processor/tokenize.h new file mode 100644 index 0000000000..9ff571d5c5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/tokenize.h @@ -0,0 +1,63 @@ +// Copyright (c) 2010, 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. +// +// Implements a Tokenize function for splitting up strings. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_TOKENIZE_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_TOKENIZE_H_ + +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// Splits line into at most max_tokens tokens, separated by any of the +// characters in separators and placing them in the tokens vector. +// line is a 0-terminated string that optionally ends with a newline +// character or combination, which will be removed. +// If more tokens than max_tokens are present, the final token is placed +// into the vector without splitting it up at all. This modifies line as +// a side effect. Returns true if exactly max_tokens tokens are returned, +// and false if fewer are returned. This is not considered a failure of +// Tokenize, but may be treated as a failure if the caller expects an +// exact, as opposed to maximum, number of tokens. + +bool Tokenize(char *line, + const char *separators, + int max_tokens, + std::vector *tokens); +// For convenience, since you need a char* to pass to Tokenize. +// You can call StringToVector on a string, and use &vec[0]. +void StringToVector(const string &str, std::vector &vec); + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_TOKENIZE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/processor/windows_frame_info.h b/toolkit/crashreporter/google-breakpad/src/processor/windows_frame_info.h new file mode 100644 index 0000000000..f96e0a438c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/processor/windows_frame_info.h @@ -0,0 +1,209 @@ +// 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. + +// windows_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_WINDOWS_FRAME_INFO_H__ +#define PROCESSOR_WINDOWS_FRAME_INFO_H__ + +#include +#include + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "processor/logging.h" +#include "processor/tokenize.h" + +namespace google_breakpad { + +#ifdef _WIN32 +#define strtoull _strtoui64 +#endif + +struct WindowsFrameInfo { + public: + enum Validity { + VALID_NONE = 0, + VALID_PARAMETER_SIZE = 1, + VALID_ALL = -1 + }; + + // The types for stack_info_. This is equivalent to MS DIA's + // StackFrameTypeEnum. Each identifies a different type of frame + // information, although all are represented in the symbol file in the + // same format. These are used as indices to the stack_info_ array. + enum StackInfoTypes { + STACK_INFO_FPO = 0, + STACK_INFO_TRAP, // not used here + STACK_INFO_TSS, // not used here + STACK_INFO_STANDARD, + STACK_INFO_FRAME_DATA, + STACK_INFO_LAST, // must be the last sequentially-numbered item + STACK_INFO_UNKNOWN = -1 + }; + + WindowsFrameInfo() : type_(STACK_INFO_UNKNOWN), + 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() {} + + WindowsFrameInfo(StackInfoTypes type, + uint32_t set_prolog_size, + uint32_t set_epilog_size, + uint32_t set_parameter_size, + uint32_t set_saved_register_size, + uint32_t set_local_size, + uint32_t set_max_stack_size, + int set_allocates_base_pointer, + const string set_program_string) + : type_(type), + 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) {} + + // Parse a textual serialization of a WindowsFrameInfo object from + // a string. Returns NULL if parsing fails, or a new object + // otherwise. type, rva and code_size are present in the STACK line, + // but not the StackFrameInfo structure, so return them as outparams. + static WindowsFrameInfo *ParseFromString(const string string, + int &type, + uint64_t &rva, + uint64_t &code_size) { + // The format of a STACK WIN record is documented at: + // + // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md + + std::vector buffer; + StringToVector(string, buffer); + std::vector tokens; + if (!Tokenize(&buffer[0], " \r\n", 11, &tokens)) + return NULL; + + type = strtol(tokens[0], NULL, 16); + if (type < 0 || type > STACK_INFO_LAST - 1) + return NULL; + + rva = strtoull(tokens[1], NULL, 16); + code_size = strtoull(tokens[2], NULL, 16); + uint32_t prolog_size = strtoul(tokens[3], NULL, 16); + uint32_t epilog_size = strtoul(tokens[4], NULL, 16); + uint32_t parameter_size = strtoul(tokens[5], NULL, 16); + uint32_t saved_register_size = strtoul(tokens[6], NULL, 16); + uint32_t local_size = strtoul(tokens[7], NULL, 16); + uint32_t max_stack_size = strtoul(tokens[8], NULL, 16); + int has_program_string = strtoul(tokens[9], NULL, 16); + + const char *program_string = ""; + int allocates_base_pointer = 0; + if (has_program_string) { + program_string = tokens[10]; + } else { + allocates_base_pointer = strtoul(tokens[10], NULL, 16); + } + + return new WindowsFrameInfo(static_cast(type), + prolog_size, + epilog_size, + parameter_size, + saved_register_size, + local_size, + max_stack_size, + allocates_base_pointer, + program_string); + } + + // CopyFrom makes "this" WindowsFrameInfo object identical to "that". + void CopyFrom(const WindowsFrameInfo &that) { + type_ = that.type_; + 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 WindowsFrameInfo object so that users will see it as though + // it contains no information. + void Clear() { + type_ = STACK_INFO_UNKNOWN; + valid = VALID_NONE; + program_string.erase(); + } + + StackInfoTypes type_; + + // 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. + uint32_t prolog_size; + uint32_t epilog_size; + uint32_t parameter_size; + uint32_t saved_register_size; + uint32_t local_size; + uint32_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; + string program_string; +}; + +} // namespace google_breakpad + + +#endif // PROCESSOR_WINDOWS_FRAME_INFO_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/COPYING b/toolkit/crashreporter/google-breakpad/src/third_party/curl/COPYING new file mode 100644 index 0000000000..3528bd7566 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/COPYING @@ -0,0 +1,22 @@ +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2019, Daniel Stenberg, , and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/curl.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/curl.h new file mode 100644 index 0000000000..86a24184aa --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/curl.h @@ -0,0 +1,2864 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "system.h" /* determine things run-time */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +/* Compatibility for non-Clang compilers */ +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(x) 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) || \ + (__has_declspec_attribute(dllexport) && \ + __has_declspec_attribute(dllimport)) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_SECURETRANSPORT = 9, + CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ + CURLSSLBACKEND_MBEDTLS = 11, + CURLSSLBACKEND_MESALINK = 12 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL + +/* deprecated names: */ +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL +#define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + +/* This callback will be called when a new resolver request is made */ +typedef int (*curl_resolver_start_callback)(void *resolver_state, + void *reserved, void *userdata); + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +/* Return code for when the trailing headers' callback has terminated + without any errors*/ +#define CURL_TRAILERFUNC_OK 0 +/* Return code for when was an error in the trailing header's list and we + want to abort the request */ +#define CURL_TRAILERFUNC_ABORT 1 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef int (*curl_trailer_callback)(struct curl_slist **list, + void *userdata); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_OBSOLETE51, /* 51 - NOT USED */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from + inside a callback */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.62.0 */ +#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_BEARER - HTTP Bearer token authentication + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_BEARER (((unsigned long)1)<<6) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS, + CURLKHTYPE_ECDSA, + CURLKHTYPE_ED25519 +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +/* The default connection attempt delay in milliseconds for happy eyeballs. + CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document + this value, keep them in sync. */ +#define CURL_HET_DEFAULT 200L + +/* The default connection upkeep interval in milliseconds. */ +#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ +#define CURLALTSVC_IMMEDIATELY (1<<0) +#define CURLALTSVC_ALTUSED (1<<1) +#define CURLALTSVC_READONLYFILE (1<<2) +#define CURLALTSVC_H1 (1<<3) +#define CURLALTSVC_H2 (1<<4) +#define CURLALTSVC_H3 (1<<5) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of milliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv6 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + + /* The request target, instead of extracted from the URL */ + CINIT(REQUEST_TARGET, STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CINIT(SOCKS5_AUTH, LONG, 267), + + /* Enable/disable SSH compression */ + CINIT(SSH_COMPRESSION, LONG, 268), + + /* Post MIME data. */ + CINIT(MIMEPOST, OBJECTPOINT, 269), + + /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of + seconds since 1 Jan 1970. */ + CINIT(TIMEVALUE_LARGE, OFF_T, 270), + + /* Head start in milliseconds to give happy eyeballs. */ + CINIT(HAPPY_EYEBALLS_TIMEOUT_MS, LONG, 271), + + /* Function that will be called before a resolver request is made */ + CINIT(RESOLVER_START_FUNCTION, FUNCTIONPOINT, 272), + + /* User data to pass to the resolver start callback. */ + CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273), + + /* send HAProxy PROXY protocol header? */ + CINIT(HAPROXYPROTOCOL, LONG, 274), + + /* shuffle addresses before use when DNS returns multiple */ + CINIT(DNS_SHUFFLE_ADDRESSES, LONG, 275), + + /* Specify which TLS 1.3 ciphers suites to use */ + CINIT(TLS13_CIPHERS, STRINGPOINT, 276), + CINIT(PROXY_TLS13_CIPHERS, STRINGPOINT, 277), + + /* Disallow specifying username/login in URL. */ + CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278), + + /* DNS-over-HTTPS URL */ + CINIT(DOH_URL, STRINGPOINT, 279), + + /* Preferred buffer size to use for uploads */ + CINIT(UPLOAD_BUFFERSIZE, LONG, 280), + + /* Time in ms between connection upkeep calls for long-lived connections. */ + CINIT(UPKEEP_INTERVAL_MS, LONG, 281), + + /* Specify URL using CURL URL API. */ + CINIT(CURLU, OBJECTPOINT, 282), + + /* add trailing data just after no more data is available */ + CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 283), + + /* pointer to be passed to HTTP_TRAILER_FUNCTION */ + CINIT(TRAILERDATA, OBJECTPOINT, 284), + + /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ + CINIT(HTTP09_ALLOWED, LONG, 285), + + /* alt-svc control bitmask */ + CINIT(ALTSVC_CTRL, LONG, 286), + + /* alt-svc cache file name to possibly read from/write to */ + CINIT(ALTSVC, STRINGPOINT, 287), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +/* Special size_t value signaling a zero-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + release */ +CURL_EXTERN int curl_strequal(const char *s1, const char *s2); +CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); + +/* Mime/form handling support. */ +typedef struct curl_mime_s curl_mime; /* Mime context. */ +typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); + +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); + +/* Old form API. */ +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_PTR 0x400000 /* same as SLIST */ +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + /* Preferably these would be defined conditionally based on the + sizeof curl_off_t being 64-bits */ + CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, + CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, + CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, + CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, + CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, + CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, + CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, + + CURLINFO_LASTONE = 56 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_PSL, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_FIFTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FIFTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + + /* These fields were added in CURLVERSION_FIFTH */ + + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is supported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ +#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ +#define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" +#include "urlapi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/curlver.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/curlver.h new file mode 100644 index 0000000000..479cd8e6cd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2019 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.64.1-DEV" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 64 +#define LIBCURL_VERSION_PATCH 1 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x074001 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date follows this template: + * + * "2007-11-23" + */ +#define LIBCURL_TIMESTAMP "[unreleased]" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/easy.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/easy.h new file mode 100644 index 0000000000..f42a8a9692 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/easy.h @@ -0,0 +1,112 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + + +/* + * NAME curl_easy_upkeep() + * + * DESCRIPTION + * + * Performs connection upkeep for the given session handle. + */ +CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/multi.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/multi.h new file mode 100644 index 0000000000..b19dbaf791 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/multi.h @@ -0,0 +1,441 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a + callback */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on individual transfers even when + * this returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/system.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/system.h new file mode 100644 index 0000000000..1e555ec19e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/system.h @@ -0,0 +1,493 @@ +#ifndef __CURL_SYSTEM_H +#define __CURL_SYSTEM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Try to keep one section per platform, compiler and architecture, otherwise, + * if an existing section is reused for a different one and later on the + * original is adjusted, probably the piggybacking one can be adversely + * changed. + * + * In order to differentiate between platforms/compilers/architectures use + * only compiler built in predefined preprocessor symbols. + * + * curl_off_t + * ---------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit + * wide signed integral data type. The width of this data type must remain + * constant and independent of any possible large file support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit + * wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall + * only be violated if off_t is the only 64-bit data type available and the + * size of off_t is independent of large file support settings. Keep your + * build on the safe side avoiding an off_t gating. If you have a 64-bit + * off_t then take for sure that another 64-bit data type exists, dig deeper + * and you will find it. + * + */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SALFORDC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TURBOC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__LCC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__MWERKS__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(_WIN32_WCE) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__MINGW32__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_WS2TCPIP_H 1 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TINYC__) /* also known as tcc */ + +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || \ + defined(__sparcv8) || \ + defined(__sparcv8plus)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__xlc__) /* IBM xlc compiler */ +# if !defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) && !defined(_SCO_DS) +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +/* generic "safe guess" on old 32 bit style */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +#endif + +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + + +/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ +/* ws2tcpip.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_WS2TCPIP_H +# include +# include +# include +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* __CURL_SYSTEM_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/typecheck-gcc.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/typecheck-gcc.h new file mode 100644 index 0000000000..8018ea37fe --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/typecheck-gcc.h @@ -0,0 +1,700 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ + if(!_curl_is_resolver_start_callback(value)) \ + _curl_easy_setopt_err_resolver_start_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!_curl_is_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + if(_curl_is_tlssessioninfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ + _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + if(_curl_is_certinfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_certinfo *)) \ + _curl_easy_getinfo_err_curl_certinfo(); \ + if(_curl_is_socket_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_socket_t)) \ + _curl_easy_getinfo_err_curl_socket(); \ + if(_curl_is_off_t_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_resolver_start_callback, + "curl_easy_setopt expects a " + "curl_resolver_start_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_tlssessioninfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_certinfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, + "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_ALTSVC || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DOH_URL || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_CAINFO || \ + (option) == CURLOPT_PROXY_CAPATH || \ + (option) == CURLOPT_PROXY_CRLFILE || \ + (option) == CURLOPT_PROXY_KEYPASSWD || \ + (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSLCERT || \ + (option) == CURLOPT_PROXY_SSLCERTTYPE || \ + (option) == CURLOPT_PROXY_SSLKEY || \ + (option) == CURLOPT_PROXY_SSLKEYTYPE || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ + (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + (option) == CURLOPT_RESOLVER_START_DATA || \ + (option) == CURLOPT_CURLU || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) + +/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ +#define _curl_is_tlssessioninfo_info(info) \ + (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) + +/* true if info expects a pointer to struct curl_certinfo * argument */ +#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) + +/* true if info expects a pointer to struct curl_socket_t argument */ +#define _curl_is_socket_info(info) \ + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define _curl_is_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true if expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (_curl_is_NULL(expr) || \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char) || \ + _curl_is_arr((expr), unsigned char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func) *, type)) + +/* evaluates to true if expr is of type curl_resolver_start_callback */ +#define _curl_is_resolver_start_callback(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_resolver_start_callback)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), __typeof__(fread) *) || \ + _curl_callback_compatible((expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ + _curl_callback_compatible((expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_opensocket_callback) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (*_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (*_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/curl/urlapi.h b/toolkit/crashreporter/google-breakpad/src/third_party/curl/urlapi.h new file mode 100644 index 0000000000..850faa97a5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/curl/urlapi.h @@ -0,0 +1,122 @@ +#ifndef __CURL_URLAPI_H +#define __CURL_URLAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* the error codes for the URL API */ +typedef enum { + CURLUE_OK, + CURLUE_BAD_HANDLE, /* 1 */ + CURLUE_BAD_PARTPOINTER, /* 2 */ + CURLUE_MALFORMED_INPUT, /* 3 */ + CURLUE_BAD_PORT_NUMBER, /* 4 */ + CURLUE_UNSUPPORTED_SCHEME, /* 5 */ + CURLUE_URLDECODE, /* 6 */ + CURLUE_OUT_OF_MEMORY, /* 7 */ + CURLUE_USER_NOT_ALLOWED, /* 8 */ + CURLUE_UNKNOWN_PART, /* 9 */ + CURLUE_NO_SCHEME, /* 10 */ + CURLUE_NO_USER, /* 11 */ + CURLUE_NO_PASSWORD, /* 12 */ + CURLUE_NO_OPTIONS, /* 13 */ + CURLUE_NO_HOST, /* 14 */ + CURLUE_NO_PORT, /* 15 */ + CURLUE_NO_QUERY, /* 16 */ + CURLUE_NO_FRAGMENT /* 17 */ +} CURLUcode; + +typedef enum { + CURLUPART_URL, + CURLUPART_SCHEME, + CURLUPART_USER, + CURLUPART_PASSWORD, + CURLUPART_OPTIONS, + CURLUPART_HOST, + CURLUPART_PORT, + CURLUPART_PATH, + CURLUPART_QUERY, + CURLUPART_FRAGMENT +} CURLUPart; + +#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ +#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, + if the port number matches the + default for the scheme */ +#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if + missing */ +#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ +#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ +#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ +#define CURLU_URLDECODE (1<<6) /* URL decode on get */ +#define CURLU_URLENCODE (1<<7) /* URL encode on set */ +#define CURLU_APPENDQUERY (1<<8) /* append a form style part */ +#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ + +typedef struct Curl_URL CURLU; + +/* + * curl_url() creates a new CURLU handle and returns a pointer to it. + * Must be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url(void); + +/* + * curl_url_cleanup() frees the CURLU handle and related resources used for + * the URL parsing. It will not free strings previously returned with the URL + * API. + */ +CURL_EXTERN void curl_url_cleanup(CURLU *handle); + +/* + * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new + * handle must also be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url_dup(CURLU *in); + +/* + * curl_url_get() extracts a specific part of the URL from a CURLU + * handle. Returns error code. The returned pointer MUST be freed with + * curl_free() afterwards. + */ +CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, + char **part, unsigned int flags); + +/* + * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns + * error code. The passed in string will be copied. Passing a NULL instead of + * a part string, clears that part. + */ +CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, + const char *part, unsigned int flags); + + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/glog/Makefile.in b/toolkit/crashreporter/google-breakpad/src/third_party/glog/Makefile.in new file mode 100644 index 0000000000..731e82f995 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/glog/Makefile.in @@ -0,0 +1,1553 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ + +# These are good warnings to turn on by default +@GCC_TRUE@am__append_1 = -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare + +# These are x86-specific, having to do with frame-pointers +@ENABLE_FRAME_POINTERS_TRUE@@X86_64_TRUE@am__append_2 = -fno-omit-frame-pointer +@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@am__append_3 = -DNO_FRAME_POINTER +TESTS = logging_unittest$(EXEEXT) demangle_unittest$(EXEEXT) \ + stacktrace_unittest$(EXEEXT) symbolize_unittest$(EXEEXT) \ + stl_logging_unittest$(EXEEXT) utilities_unittest$(EXEEXT) \ + $(am__EXEEXT_1) +@HAVE_GMOCK_TRUE@am__append_4 = mock_log_test +noinst_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) +subdir = . +DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \ + $(gloginclude_HEADERS) $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/libglog.pc.in \ + $(top_srcdir)/configure $(top_srcdir)/src/config.h.in \ + $(top_srcdir)/src/glog/logging.h.in \ + $(top_srcdir)/src/glog/raw_logging.h.in \ + $(top_srcdir)/src/glog/stl_logging.h.in \ + $(top_srcdir)/src/glog/vlog_is_on.h.in AUTHORS COPYING \ + ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ + install-sh ltmain.sh missing mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_have_attribute.m4 \ + $(top_srcdir)/m4/ac_have_builtin_expect.m4 \ + $(top_srcdir)/m4/ac_have_sync_val_compare_and_swap.m4 \ + $(top_srcdir)/m4/ac_rwlock.m4 $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/google_namespace.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/namespaces.m4 \ + $(top_srcdir)/m4/pc_from_ucontext.m4 \ + $(top_srcdir)/m4/stl_namespace.m4 \ + $(top_srcdir)/m4/using_operator.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/src/config.h +CONFIG_CLEAN_FILES = src/glog/logging.h src/glog/raw_logging.h \ + src/glog/vlog_is_on.h src/glog/stl_logging.h libglog.pc +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" \ + "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(glogincludedir)" \ + "$(DESTDIR)$(glogincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +libglog_la_DEPENDENCIES = $(am__DEPENDENCIES_2) +am__objects_1 = +am_libglog_la_OBJECTS = $(am__objects_1) libglog_la-logging.lo \ + libglog_la-raw_logging.lo libglog_la-vlog_is_on.lo \ + libglog_la-utilities.lo libglog_la-demangle.lo \ + libglog_la-symbolize.lo libglog_la-signalhandler.lo +nodist_libglog_la_OBJECTS = $(am__objects_1) +libglog_la_OBJECTS = $(am_libglog_la_OBJECTS) \ + $(nodist_libglog_la_OBJECTS) +libglog_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libglog_la_CXXFLAGS) \ + $(CXXFLAGS) $(libglog_la_LDFLAGS) $(LDFLAGS) -o $@ +@HAVE_GMOCK_TRUE@am__EXEEXT_1 = mock_log_test$(EXEEXT) +am__EXEEXT_2 = logging_unittest$(EXEEXT) demangle_unittest$(EXEEXT) \ + stacktrace_unittest$(EXEEXT) symbolize_unittest$(EXEEXT) \ + stl_logging_unittest$(EXEEXT) utilities_unittest$(EXEEXT) \ + $(am__EXEEXT_1) +am__EXEEXT_3 = logging_striptest0$(EXEEXT) logging_striptest2$(EXEEXT) \ + logging_striptest10$(EXEEXT) signalhandler_unittest$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am_demangle_unittest_OBJECTS = $(am__objects_1) \ + demangle_unittest-demangle_unittest.$(OBJEXT) +nodist_demangle_unittest_OBJECTS = $(am__objects_1) +demangle_unittest_OBJECTS = $(am_demangle_unittest_OBJECTS) \ + $(nodist_demangle_unittest_OBJECTS) +demangle_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +demangle_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(demangle_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(demangle_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am_logging_striptest0_OBJECTS = $(am__objects_1) \ + logging_striptest0-logging_striptest_main.$(OBJEXT) +nodist_logging_striptest0_OBJECTS = $(am__objects_1) +logging_striptest0_OBJECTS = $(am_logging_striptest0_OBJECTS) \ + $(nodist_logging_striptest0_OBJECTS) +logging_striptest0_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) +logging_striptest0_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(logging_striptest0_CXXFLAGS) $(CXXFLAGS) \ + $(logging_striptest0_LDFLAGS) $(LDFLAGS) -o $@ +am_logging_striptest10_OBJECTS = $(am__objects_1) \ + logging_striptest10-logging_striptest10.$(OBJEXT) +nodist_logging_striptest10_OBJECTS = $(am__objects_1) +logging_striptest10_OBJECTS = $(am_logging_striptest10_OBJECTS) \ + $(nodist_logging_striptest10_OBJECTS) +logging_striptest10_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) +logging_striptest10_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(logging_striptest10_CXXFLAGS) $(CXXFLAGS) \ + $(logging_striptest10_LDFLAGS) $(LDFLAGS) -o $@ +am_logging_striptest2_OBJECTS = $(am__objects_1) \ + logging_striptest2-logging_striptest2.$(OBJEXT) +nodist_logging_striptest2_OBJECTS = $(am__objects_1) +logging_striptest2_OBJECTS = $(am_logging_striptest2_OBJECTS) \ + $(nodist_logging_striptest2_OBJECTS) +logging_striptest2_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) +logging_striptest2_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(logging_striptest2_CXXFLAGS) $(CXXFLAGS) \ + $(logging_striptest2_LDFLAGS) $(LDFLAGS) -o $@ +am_logging_unittest_OBJECTS = $(am__objects_1) \ + logging_unittest-logging_unittest.$(OBJEXT) +nodist_logging_unittest_OBJECTS = $(am__objects_1) +logging_unittest_OBJECTS = $(am_logging_unittest_OBJECTS) \ + $(nodist_logging_unittest_OBJECTS) +logging_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +logging_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(logging_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(logging_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am__mock_log_test_SOURCES_DIST = src/glog/log_severity.h \ + src/mock-log_test.cc +@HAVE_GMOCK_TRUE@am_mock_log_test_OBJECTS = $(am__objects_1) \ +@HAVE_GMOCK_TRUE@ mock_log_test-mock-log_test.$(OBJEXT) +@HAVE_GMOCK_TRUE@nodist_mock_log_test_OBJECTS = $(am__objects_1) +mock_log_test_OBJECTS = $(am_mock_log_test_OBJECTS) \ + $(nodist_mock_log_test_OBJECTS) +@HAVE_GMOCK_TRUE@mock_log_test_DEPENDENCIES = libglog.la \ +@HAVE_GMOCK_TRUE@ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +mock_log_test_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(mock_log_test_CXXFLAGS) \ + $(CXXFLAGS) $(mock_log_test_LDFLAGS) $(LDFLAGS) -o $@ +am_signalhandler_unittest_OBJECTS = $(am__objects_1) \ + signalhandler_unittest-signalhandler_unittest.$(OBJEXT) +nodist_signalhandler_unittest_OBJECTS = $(am__objects_1) +signalhandler_unittest_OBJECTS = $(am_signalhandler_unittest_OBJECTS) \ + $(nodist_signalhandler_unittest_OBJECTS) +signalhandler_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +signalhandler_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(signalhandler_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(signalhandler_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am_stacktrace_unittest_OBJECTS = $(am__objects_1) \ + stacktrace_unittest-stacktrace_unittest.$(OBJEXT) +nodist_stacktrace_unittest_OBJECTS = $(am__objects_1) +stacktrace_unittest_OBJECTS = $(am_stacktrace_unittest_OBJECTS) \ + $(nodist_stacktrace_unittest_OBJECTS) +stacktrace_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) +stacktrace_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(stacktrace_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(stacktrace_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am_stl_logging_unittest_OBJECTS = $(am__objects_1) \ + stl_logging_unittest-stl_logging_unittest.$(OBJEXT) +nodist_stl_logging_unittest_OBJECTS = $(am__objects_1) +stl_logging_unittest_OBJECTS = $(am_stl_logging_unittest_OBJECTS) \ + $(nodist_stl_logging_unittest_OBJECTS) +stl_logging_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +stl_logging_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(stl_logging_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(stl_logging_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am_symbolize_unittest_OBJECTS = $(am__objects_1) \ + symbolize_unittest-symbolize_unittest.$(OBJEXT) +nodist_symbolize_unittest_OBJECTS = $(am__objects_1) +symbolize_unittest_OBJECTS = $(am_symbolize_unittest_OBJECTS) \ + $(nodist_symbolize_unittest_OBJECTS) +symbolize_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +symbolize_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(symbolize_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(symbolize_unittest_LDFLAGS) $(LDFLAGS) -o $@ +am_utilities_unittest_OBJECTS = $(am__objects_1) \ + utilities_unittest-utilities_unittest.$(OBJEXT) +nodist_utilities_unittest_OBJECTS = $(am__objects_1) +utilities_unittest_OBJECTS = $(am_utilities_unittest_OBJECTS) \ + $(nodist_utilities_unittest_OBJECTS) +utilities_unittest_DEPENDENCIES = libglog.la $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +utilities_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(utilities_unittest_CXXFLAGS) $(CXXFLAGS) \ + $(utilities_unittest_LDFLAGS) $(LDFLAGS) -o $@ +SCRIPTS = $(noinst_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libglog_la_SOURCES) $(nodist_libglog_la_SOURCES) \ + $(demangle_unittest_SOURCES) \ + $(nodist_demangle_unittest_SOURCES) \ + $(logging_striptest0_SOURCES) \ + $(nodist_logging_striptest0_SOURCES) \ + $(logging_striptest10_SOURCES) \ + $(nodist_logging_striptest10_SOURCES) \ + $(logging_striptest2_SOURCES) \ + $(nodist_logging_striptest2_SOURCES) \ + $(logging_unittest_SOURCES) $(nodist_logging_unittest_SOURCES) \ + $(mock_log_test_SOURCES) $(nodist_mock_log_test_SOURCES) \ + $(signalhandler_unittest_SOURCES) \ + $(nodist_signalhandler_unittest_SOURCES) \ + $(stacktrace_unittest_SOURCES) \ + $(nodist_stacktrace_unittest_SOURCES) \ + $(stl_logging_unittest_SOURCES) \ + $(nodist_stl_logging_unittest_SOURCES) \ + $(symbolize_unittest_SOURCES) \ + $(nodist_symbolize_unittest_SOURCES) \ + $(utilities_unittest_SOURCES) \ + $(nodist_utilities_unittest_SOURCES) +DIST_SOURCES = $(libglog_la_SOURCES) $(demangle_unittest_SOURCES) \ + $(logging_striptest0_SOURCES) $(logging_striptest10_SOURCES) \ + $(logging_striptest2_SOURCES) $(logging_unittest_SOURCES) \ + $(am__mock_log_test_SOURCES_DIST) \ + $(signalhandler_unittest_SOURCES) \ + $(stacktrace_unittest_SOURCES) $(stl_logging_unittest_SOURCES) \ + $(symbolize_unittest_SOURCES) $(utilities_unittest_SOURCES) +DATA = $(dist_doc_DATA) $(pkgconfig_DATA) +HEADERS = $(gloginclude_HEADERS) $(nodist_gloginclude_HEADERS) \ + $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GFLAGS_CFLAGS = @GFLAGS_CFLAGS@ +GFLAGS_LIBS = @GFLAGS_LIBS@ +GMOCK_CFLAGS = @GMOCK_CFLAGS@ +GMOCK_CONFIG = @GMOCK_CONFIG@ +GMOCK_LIBS = @GMOCK_LIBS@ +GREP = @GREP@ +GTEST_CFLAGS = @GTEST_CFLAGS@ +GTEST_CONFIG = @GTEST_CONFIG@ +GTEST_LIBS = @GTEST_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +UNWIND_LIBS = @UNWIND_LIBS@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv___attribute___noreturn = @ac_cv___attribute___noreturn@ +ac_cv___attribute___printf_4_5 = @ac_cv___attribute___printf_4_5@ +ac_cv_cxx_using_operator = @ac_cv_cxx_using_operator@ +ac_cv_have___builtin_expect = @ac_cv_have___builtin_expect@ +ac_cv_have___uint16 = @ac_cv_have___uint16@ +ac_cv_have_inttypes_h = @ac_cv_have_inttypes_h@ +ac_cv_have_libgflags = @ac_cv_have_libgflags@ +ac_cv_have_stdint_h = @ac_cv_have_stdint_h@ +ac_cv_have_systypes_h = @ac_cv_have_systypes_h@ +ac_cv_have_u_int16_t = @ac_cv_have_u_int16_t@ +ac_cv_have_uint16_t = @ac_cv_have_uint16_t@ +ac_cv_have_unistd_h = @ac_cv_have_unistd_h@ +ac_google_end_namespace = @ac_google_end_namespace@ +ac_google_namespace = @ac_google_namespace@ +ac_google_start_namespace = @ac_google_start_namespace@ +acx_pthread_config = @acx_pthread_config@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Make sure that when we re-make ./configure, we get the macros we need +ACLOCAL_AMFLAGS = -I m4 + +# This is so we can #include +AM_CPPFLAGS = -I$(top_srcdir)/src + +# This is mostly based on configure options +AM_CXXFLAGS = $(am__append_1) $(am__append_2) $(am__append_3) +glogincludedir = $(includedir)/glog +gloginclude_HEADERS = src/glog/log_severity.h +nodist_gloginclude_HEADERS = src/glog/logging.h src/glog/raw_logging.h src/glog/vlog_is_on.h src/glog/stl_logging.h +noinst_HEADERS = src/glog/logging.h.in src/glog/raw_logging.h.in src/glog/vlog_is_on.h.in src/glog/stl_logging.h.in +dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README README.windows \ + doc/designstyle.css doc/glog.html + +lib_LTLIBRARIES = libglog.la + +# The libraries libglog depends on. +COMMON_LIBS = $(PTHREAD_LIBS) $(GFLAGS_LIBS) $(UNWIND_LIBS) +# Compile switches for our unittest. +TEST_CFLAGS = $(GTEST_CFLAGS) $(GMOCK_CFLAGS) $(GFLAGS_CFLAGS) $(AM_CXXFLAGS) +# Libraries for our unittest. +TEST_LIBS = $(GTEST_LIBS) $(GMOCK_LIBS) $(GFLAGS_LIBS) +TESTS_ENVIRONMENT = +check_SCRIPTS = logging_striplog_test_sh demangle_unittest_sh \ + signalhandler_unittest_sh +# Every time you add a unittest to check_SCRIPTS, add it here too +noinst_SCRIPTS = src/logging_striplog_test.sh src/demangle_unittest.sh \ + src/signalhandler_unittest.sh +# Binaries used for script-based unittests. +TEST_BINARIES = logging_striptest0 logging_striptest2 \ + logging_striptest10 signalhandler_unittest +logging_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/logging_unittest.cc \ + src/config_for_unittests.h \ + src/mock-log.h + +nodist_logging_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +logging_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +logging_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +logging_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +logging_striptest0_SOURCES = $(gloginclude_HEADERS) \ + src/logging_striptest_main.cc + +nodist_logging_striptest0_SOURCES = $(nodist_gloginclude_HEADERS) +logging_striptest0_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +logging_striptest0_LDFLAGS = $(PTHREAD_CFLAGS) +logging_striptest0_LDADD = libglog.la $(COMMON_LIBS) +logging_striptest2_SOURCES = $(gloginclude_HEADERS) \ + src/logging_striptest2.cc + +nodist_logging_striptest2_SOURCES = $(nodist_gloginclude_HEADERS) +logging_striptest2_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +logging_striptest2_LDFLAGS = $(PTHREAD_CFLAGS) +logging_striptest2_LDADD = libglog.la $(COMMON_LIBS) +logging_striptest10_SOURCES = $(gloginclude_HEADERS) \ + src/logging_striptest10.cc + +nodist_logging_striptest10_SOURCES = $(nodist_gloginclude_HEADERS) +logging_striptest10_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +logging_striptest10_LDFLAGS = $(PTHREAD_CFLAGS) +logging_striptest10_LDADD = libglog.la $(COMMON_LIBS) +demangle_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/demangle_unittest.cc + +nodist_demangle_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +demangle_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +demangle_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +demangle_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +stacktrace_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/stacktrace_unittest.cc + +nodist_stacktrace_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +stacktrace_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +stacktrace_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +stacktrace_unittest_LDADD = libglog.la $(COMMON_LIBS) +symbolize_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/symbolize_unittest.cc + +nodist_symbolize_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +symbolize_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +symbolize_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +symbolize_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +stl_logging_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/stl_logging_unittest.cc + +nodist_stl_logging_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +stl_logging_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +stl_logging_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +stl_logging_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +signalhandler_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/signalhandler_unittest.cc + +nodist_signalhandler_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +signalhandler_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +signalhandler_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +signalhandler_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +utilities_unittest_SOURCES = $(gloginclude_HEADERS) \ + src/utilities_unittest.cc + +nodist_utilities_unittest_SOURCES = $(nodist_gloginclude_HEADERS) +utilities_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +utilities_unittest_LDFLAGS = $(PTHREAD_CFLAGS) +utilities_unittest_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +@HAVE_GMOCK_TRUE@mock_log_test_SOURCES = $(gloginclude_HEADERS) \ +@HAVE_GMOCK_TRUE@ src/mock-log_test.cc + +@HAVE_GMOCK_TRUE@nodist_mock_log_test_SOURCES = $(nodist_gloginclude_HEADERS) +@HAVE_GMOCK_TRUE@mock_log_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(TEST_CFLAGS) +@HAVE_GMOCK_TRUE@mock_log_test_LDFLAGS = $(PTHREAD_CFLAGS) +@HAVE_GMOCK_TRUE@mock_log_test_LDADD = libglog.la $(COMMON_LIBS) $(TEST_LIBS) +libglog_la_SOURCES = $(gloginclude_HEADERS) \ + src/logging.cc src/raw_logging.cc src/vlog_is_on.cc \ + src/utilities.cc src/utilities.h \ + src/demangle.cc src/demangle.h \ + src/stacktrace.h \ + src/stacktrace_generic-inl.h \ + src/stacktrace_libunwind-inl.h \ + src/stacktrace_powerpc-inl.h \ + src/stacktrace_x86-inl.h \ + src/stacktrace_x86_64-inl.h \ + src/symbolize.cc src/symbolize.h \ + src/signalhandler.cc \ + src/base/mutex.h src/base/googleinit.h \ + src/base/commandlineflags.h src/googletest.h + +nodist_libglog_la_SOURCES = $(nodist_gloginclude_HEADERS) +libglog_la_CXXFLAGS = $(PTRHEAD_CFLAGS) $(GFLAGS_CFLAGS) $(AM_CXXFLAGS) -DNDEBUG +libglog_la_LDFLAGS = $(PTRHEAD_CFLAGS) $(GFLAGS_LDFLAGS) +libglog_la_LIBADD = $(COMMON_LIBS) +WINDOWS_PROJECTS = google-glog.sln vsprojects/libglog/libglog.vcproj \ + vsprojects/logging_unittest/logging_unittest.vcproj \ + vsprojects/libglog_static/libglog_static.vcproj \ + vsprojects/logging_unittest_static/logging_unittest_static.vcproj +EXTRA_DIST = packages/rpm.sh packages/rpm/rpm.spec packages/deb.sh packages/deb \ + $(SCRIPTS) src/logging_unittest.err src/demangle_unittest.txt \ + src/windows/config.h src/windows/port.h src/windows/port.cc \ + src/windows/preprocess.sh \ + src/windows/glog/log_severity.h src/windows/glog/logging.h \ + src/windows/glog/raw_logging.h src/windows/glog/stl_logging.h \ + src/windows/glog/vlog_is_on.h \ + $(WINDOWS_PROJECTS) + +CLEANFILES = core demangle.dm demangle.nm signalhandler.out* \ + signalhandler_unittest.*.log.INFO.* + + +# Add pkgconfig file +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libglog.pc +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +src/config.h: src/stamp-h1 + @if test ! -f $@; then \ + rm -f src/stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) src/stamp-h1; \ + else :; fi + +src/stamp-h1: $(top_srcdir)/src/config.h.in $(top_builddir)/config.status + @rm -f src/stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status src/config.h +$(top_srcdir)/src/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f src/stamp-h1 + touch $@ + +distclean-hdr: + -rm -f src/config.h src/stamp-h1 +src/glog/logging.h: $(top_builddir)/config.status $(top_srcdir)/src/glog/logging.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/glog/raw_logging.h: $(top_builddir)/config.status $(top_srcdir)/src/glog/raw_logging.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/glog/vlog_is_on.h: $(top_builddir)/config.status $(top_srcdir)/src/glog/vlog_is_on.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/glog/stl_logging.h: $(top_builddir)/config.status $(top_srcdir)/src/glog/stl_logging.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +libglog.pc: $(top_builddir)/config.status $(srcdir)/libglog.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libglog.la: $(libglog_la_OBJECTS) $(libglog_la_DEPENDENCIES) + $(libglog_la_LINK) -rpath $(libdir) $(libglog_la_OBJECTS) $(libglog_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +demangle_unittest$(EXEEXT): $(demangle_unittest_OBJECTS) $(demangle_unittest_DEPENDENCIES) + @rm -f demangle_unittest$(EXEEXT) + $(demangle_unittest_LINK) $(demangle_unittest_OBJECTS) $(demangle_unittest_LDADD) $(LIBS) +logging_striptest0$(EXEEXT): $(logging_striptest0_OBJECTS) $(logging_striptest0_DEPENDENCIES) + @rm -f logging_striptest0$(EXEEXT) + $(logging_striptest0_LINK) $(logging_striptest0_OBJECTS) $(logging_striptest0_LDADD) $(LIBS) +logging_striptest10$(EXEEXT): $(logging_striptest10_OBJECTS) $(logging_striptest10_DEPENDENCIES) + @rm -f logging_striptest10$(EXEEXT) + $(logging_striptest10_LINK) $(logging_striptest10_OBJECTS) $(logging_striptest10_LDADD) $(LIBS) +logging_striptest2$(EXEEXT): $(logging_striptest2_OBJECTS) $(logging_striptest2_DEPENDENCIES) + @rm -f logging_striptest2$(EXEEXT) + $(logging_striptest2_LINK) $(logging_striptest2_OBJECTS) $(logging_striptest2_LDADD) $(LIBS) +logging_unittest$(EXEEXT): $(logging_unittest_OBJECTS) $(logging_unittest_DEPENDENCIES) + @rm -f logging_unittest$(EXEEXT) + $(logging_unittest_LINK) $(logging_unittest_OBJECTS) $(logging_unittest_LDADD) $(LIBS) +mock_log_test$(EXEEXT): $(mock_log_test_OBJECTS) $(mock_log_test_DEPENDENCIES) + @rm -f mock_log_test$(EXEEXT) + $(mock_log_test_LINK) $(mock_log_test_OBJECTS) $(mock_log_test_LDADD) $(LIBS) +signalhandler_unittest$(EXEEXT): $(signalhandler_unittest_OBJECTS) $(signalhandler_unittest_DEPENDENCIES) + @rm -f signalhandler_unittest$(EXEEXT) + $(signalhandler_unittest_LINK) $(signalhandler_unittest_OBJECTS) $(signalhandler_unittest_LDADD) $(LIBS) +stacktrace_unittest$(EXEEXT): $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_DEPENDENCIES) + @rm -f stacktrace_unittest$(EXEEXT) + $(stacktrace_unittest_LINK) $(stacktrace_unittest_OBJECTS) $(stacktrace_unittest_LDADD) $(LIBS) +stl_logging_unittest$(EXEEXT): $(stl_logging_unittest_OBJECTS) $(stl_logging_unittest_DEPENDENCIES) + @rm -f stl_logging_unittest$(EXEEXT) + $(stl_logging_unittest_LINK) $(stl_logging_unittest_OBJECTS) $(stl_logging_unittest_LDADD) $(LIBS) +symbolize_unittest$(EXEEXT): $(symbolize_unittest_OBJECTS) $(symbolize_unittest_DEPENDENCIES) + @rm -f symbolize_unittest$(EXEEXT) + $(symbolize_unittest_LINK) $(symbolize_unittest_OBJECTS) $(symbolize_unittest_LDADD) $(LIBS) +utilities_unittest$(EXEEXT): $(utilities_unittest_OBJECTS) $(utilities_unittest_DEPENDENCIES) + @rm -f utilities_unittest$(EXEEXT) + $(utilities_unittest_LINK) $(utilities_unittest_OBJECTS) $(utilities_unittest_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/demangle_unittest-demangle_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-demangle.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-raw_logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-signalhandler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-symbolize.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-utilities.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglog_la-vlog_is_on.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging_striptest0-logging_striptest_main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging_striptest10-logging_striptest10.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging_striptest2-logging_striptest2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logging_unittest-logging_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mock_log_test-mock-log_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbolize_unittest-symbolize_unittest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utilities_unittest-utilities_unittest.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +libglog_la-logging.lo: src/logging.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-logging.lo -MD -MP -MF $(DEPDIR)/libglog_la-logging.Tpo -c -o libglog_la-logging.lo `test -f 'src/logging.cc' || echo '$(srcdir)/'`src/logging.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-logging.Tpo $(DEPDIR)/libglog_la-logging.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging.cc' object='libglog_la-logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-logging.lo `test -f 'src/logging.cc' || echo '$(srcdir)/'`src/logging.cc + +libglog_la-raw_logging.lo: src/raw_logging.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-raw_logging.lo -MD -MP -MF $(DEPDIR)/libglog_la-raw_logging.Tpo -c -o libglog_la-raw_logging.lo `test -f 'src/raw_logging.cc' || echo '$(srcdir)/'`src/raw_logging.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-raw_logging.Tpo $(DEPDIR)/libglog_la-raw_logging.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/raw_logging.cc' object='libglog_la-raw_logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-raw_logging.lo `test -f 'src/raw_logging.cc' || echo '$(srcdir)/'`src/raw_logging.cc + +libglog_la-vlog_is_on.lo: src/vlog_is_on.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-vlog_is_on.lo -MD -MP -MF $(DEPDIR)/libglog_la-vlog_is_on.Tpo -c -o libglog_la-vlog_is_on.lo `test -f 'src/vlog_is_on.cc' || echo '$(srcdir)/'`src/vlog_is_on.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-vlog_is_on.Tpo $(DEPDIR)/libglog_la-vlog_is_on.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/vlog_is_on.cc' object='libglog_la-vlog_is_on.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-vlog_is_on.lo `test -f 'src/vlog_is_on.cc' || echo '$(srcdir)/'`src/vlog_is_on.cc + +libglog_la-utilities.lo: src/utilities.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-utilities.lo -MD -MP -MF $(DEPDIR)/libglog_la-utilities.Tpo -c -o libglog_la-utilities.lo `test -f 'src/utilities.cc' || echo '$(srcdir)/'`src/utilities.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-utilities.Tpo $(DEPDIR)/libglog_la-utilities.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utilities.cc' object='libglog_la-utilities.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-utilities.lo `test -f 'src/utilities.cc' || echo '$(srcdir)/'`src/utilities.cc + +libglog_la-demangle.lo: src/demangle.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-demangle.lo -MD -MP -MF $(DEPDIR)/libglog_la-demangle.Tpo -c -o libglog_la-demangle.lo `test -f 'src/demangle.cc' || echo '$(srcdir)/'`src/demangle.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-demangle.Tpo $(DEPDIR)/libglog_la-demangle.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/demangle.cc' object='libglog_la-demangle.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-demangle.lo `test -f 'src/demangle.cc' || echo '$(srcdir)/'`src/demangle.cc + +libglog_la-symbolize.lo: src/symbolize.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-symbolize.lo -MD -MP -MF $(DEPDIR)/libglog_la-symbolize.Tpo -c -o libglog_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-symbolize.Tpo $(DEPDIR)/libglog_la-symbolize.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/symbolize.cc' object='libglog_la-symbolize.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-symbolize.lo `test -f 'src/symbolize.cc' || echo '$(srcdir)/'`src/symbolize.cc + +libglog_la-signalhandler.lo: src/signalhandler.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -MT libglog_la-signalhandler.lo -MD -MP -MF $(DEPDIR)/libglog_la-signalhandler.Tpo -c -o libglog_la-signalhandler.lo `test -f 'src/signalhandler.cc' || echo '$(srcdir)/'`src/signalhandler.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libglog_la-signalhandler.Tpo $(DEPDIR)/libglog_la-signalhandler.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/signalhandler.cc' object='libglog_la-signalhandler.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglog_la_CXXFLAGS) $(CXXFLAGS) -c -o libglog_la-signalhandler.lo `test -f 'src/signalhandler.cc' || echo '$(srcdir)/'`src/signalhandler.cc + +demangle_unittest-demangle_unittest.o: src/demangle_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(demangle_unittest_CXXFLAGS) $(CXXFLAGS) -MT demangle_unittest-demangle_unittest.o -MD -MP -MF $(DEPDIR)/demangle_unittest-demangle_unittest.Tpo -c -o demangle_unittest-demangle_unittest.o `test -f 'src/demangle_unittest.cc' || echo '$(srcdir)/'`src/demangle_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/demangle_unittest-demangle_unittest.Tpo $(DEPDIR)/demangle_unittest-demangle_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/demangle_unittest.cc' object='demangle_unittest-demangle_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(demangle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o demangle_unittest-demangle_unittest.o `test -f 'src/demangle_unittest.cc' || echo '$(srcdir)/'`src/demangle_unittest.cc + +demangle_unittest-demangle_unittest.obj: src/demangle_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(demangle_unittest_CXXFLAGS) $(CXXFLAGS) -MT demangle_unittest-demangle_unittest.obj -MD -MP -MF $(DEPDIR)/demangle_unittest-demangle_unittest.Tpo -c -o demangle_unittest-demangle_unittest.obj `if test -f 'src/demangle_unittest.cc'; then $(CYGPATH_W) 'src/demangle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/demangle_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/demangle_unittest-demangle_unittest.Tpo $(DEPDIR)/demangle_unittest-demangle_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/demangle_unittest.cc' object='demangle_unittest-demangle_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(demangle_unittest_CXXFLAGS) $(CXXFLAGS) -c -o demangle_unittest-demangle_unittest.obj `if test -f 'src/demangle_unittest.cc'; then $(CYGPATH_W) 'src/demangle_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/demangle_unittest.cc'; fi` + +logging_striptest0-logging_striptest_main.o: src/logging_striptest_main.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest0_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest0-logging_striptest_main.o -MD -MP -MF $(DEPDIR)/logging_striptest0-logging_striptest_main.Tpo -c -o logging_striptest0-logging_striptest_main.o `test -f 'src/logging_striptest_main.cc' || echo '$(srcdir)/'`src/logging_striptest_main.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest0-logging_striptest_main.Tpo $(DEPDIR)/logging_striptest0-logging_striptest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest_main.cc' object='logging_striptest0-logging_striptest_main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest0_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest0-logging_striptest_main.o `test -f 'src/logging_striptest_main.cc' || echo '$(srcdir)/'`src/logging_striptest_main.cc + +logging_striptest0-logging_striptest_main.obj: src/logging_striptest_main.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest0_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest0-logging_striptest_main.obj -MD -MP -MF $(DEPDIR)/logging_striptest0-logging_striptest_main.Tpo -c -o logging_striptest0-logging_striptest_main.obj `if test -f 'src/logging_striptest_main.cc'; then $(CYGPATH_W) 'src/logging_striptest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest_main.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest0-logging_striptest_main.Tpo $(DEPDIR)/logging_striptest0-logging_striptest_main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest_main.cc' object='logging_striptest0-logging_striptest_main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest0_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest0-logging_striptest_main.obj `if test -f 'src/logging_striptest_main.cc'; then $(CYGPATH_W) 'src/logging_striptest_main.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest_main.cc'; fi` + +logging_striptest10-logging_striptest10.o: src/logging_striptest10.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest10_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest10-logging_striptest10.o -MD -MP -MF $(DEPDIR)/logging_striptest10-logging_striptest10.Tpo -c -o logging_striptest10-logging_striptest10.o `test -f 'src/logging_striptest10.cc' || echo '$(srcdir)/'`src/logging_striptest10.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest10-logging_striptest10.Tpo $(DEPDIR)/logging_striptest10-logging_striptest10.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest10.cc' object='logging_striptest10-logging_striptest10.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest10_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest10-logging_striptest10.o `test -f 'src/logging_striptest10.cc' || echo '$(srcdir)/'`src/logging_striptest10.cc + +logging_striptest10-logging_striptest10.obj: src/logging_striptest10.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest10_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest10-logging_striptest10.obj -MD -MP -MF $(DEPDIR)/logging_striptest10-logging_striptest10.Tpo -c -o logging_striptest10-logging_striptest10.obj `if test -f 'src/logging_striptest10.cc'; then $(CYGPATH_W) 'src/logging_striptest10.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest10.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest10-logging_striptest10.Tpo $(DEPDIR)/logging_striptest10-logging_striptest10.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest10.cc' object='logging_striptest10-logging_striptest10.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest10_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest10-logging_striptest10.obj `if test -f 'src/logging_striptest10.cc'; then $(CYGPATH_W) 'src/logging_striptest10.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest10.cc'; fi` + +logging_striptest2-logging_striptest2.o: src/logging_striptest2.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest2_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest2-logging_striptest2.o -MD -MP -MF $(DEPDIR)/logging_striptest2-logging_striptest2.Tpo -c -o logging_striptest2-logging_striptest2.o `test -f 'src/logging_striptest2.cc' || echo '$(srcdir)/'`src/logging_striptest2.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest2-logging_striptest2.Tpo $(DEPDIR)/logging_striptest2-logging_striptest2.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest2.cc' object='logging_striptest2-logging_striptest2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest2_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest2-logging_striptest2.o `test -f 'src/logging_striptest2.cc' || echo '$(srcdir)/'`src/logging_striptest2.cc + +logging_striptest2-logging_striptest2.obj: src/logging_striptest2.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest2_CXXFLAGS) $(CXXFLAGS) -MT logging_striptest2-logging_striptest2.obj -MD -MP -MF $(DEPDIR)/logging_striptest2-logging_striptest2.Tpo -c -o logging_striptest2-logging_striptest2.obj `if test -f 'src/logging_striptest2.cc'; then $(CYGPATH_W) 'src/logging_striptest2.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest2.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_striptest2-logging_striptest2.Tpo $(DEPDIR)/logging_striptest2-logging_striptest2.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_striptest2.cc' object='logging_striptest2-logging_striptest2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_striptest2_CXXFLAGS) $(CXXFLAGS) -c -o logging_striptest2-logging_striptest2.obj `if test -f 'src/logging_striptest2.cc'; then $(CYGPATH_W) 'src/logging_striptest2.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_striptest2.cc'; fi` + +logging_unittest-logging_unittest.o: src/logging_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_unittest_CXXFLAGS) $(CXXFLAGS) -MT logging_unittest-logging_unittest.o -MD -MP -MF $(DEPDIR)/logging_unittest-logging_unittest.Tpo -c -o logging_unittest-logging_unittest.o `test -f 'src/logging_unittest.cc' || echo '$(srcdir)/'`src/logging_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_unittest-logging_unittest.Tpo $(DEPDIR)/logging_unittest-logging_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_unittest.cc' object='logging_unittest-logging_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_unittest_CXXFLAGS) $(CXXFLAGS) -c -o logging_unittest-logging_unittest.o `test -f 'src/logging_unittest.cc' || echo '$(srcdir)/'`src/logging_unittest.cc + +logging_unittest-logging_unittest.obj: src/logging_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_unittest_CXXFLAGS) $(CXXFLAGS) -MT logging_unittest-logging_unittest.obj -MD -MP -MF $(DEPDIR)/logging_unittest-logging_unittest.Tpo -c -o logging_unittest-logging_unittest.obj `if test -f 'src/logging_unittest.cc'; then $(CYGPATH_W) 'src/logging_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/logging_unittest-logging_unittest.Tpo $(DEPDIR)/logging_unittest-logging_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/logging_unittest.cc' object='logging_unittest-logging_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(logging_unittest_CXXFLAGS) $(CXXFLAGS) -c -o logging_unittest-logging_unittest.obj `if test -f 'src/logging_unittest.cc'; then $(CYGPATH_W) 'src/logging_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/logging_unittest.cc'; fi` + +mock_log_test-mock-log_test.o: src/mock-log_test.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mock_log_test_CXXFLAGS) $(CXXFLAGS) -MT mock_log_test-mock-log_test.o -MD -MP -MF $(DEPDIR)/mock_log_test-mock-log_test.Tpo -c -o mock_log_test-mock-log_test.o `test -f 'src/mock-log_test.cc' || echo '$(srcdir)/'`src/mock-log_test.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/mock_log_test-mock-log_test.Tpo $(DEPDIR)/mock_log_test-mock-log_test.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mock-log_test.cc' object='mock_log_test-mock-log_test.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mock_log_test_CXXFLAGS) $(CXXFLAGS) -c -o mock_log_test-mock-log_test.o `test -f 'src/mock-log_test.cc' || echo '$(srcdir)/'`src/mock-log_test.cc + +mock_log_test-mock-log_test.obj: src/mock-log_test.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mock_log_test_CXXFLAGS) $(CXXFLAGS) -MT mock_log_test-mock-log_test.obj -MD -MP -MF $(DEPDIR)/mock_log_test-mock-log_test.Tpo -c -o mock_log_test-mock-log_test.obj `if test -f 'src/mock-log_test.cc'; then $(CYGPATH_W) 'src/mock-log_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/mock-log_test.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/mock_log_test-mock-log_test.Tpo $(DEPDIR)/mock_log_test-mock-log_test.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/mock-log_test.cc' object='mock_log_test-mock-log_test.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mock_log_test_CXXFLAGS) $(CXXFLAGS) -c -o mock_log_test-mock-log_test.obj `if test -f 'src/mock-log_test.cc'; then $(CYGPATH_W) 'src/mock-log_test.cc'; else $(CYGPATH_W) '$(srcdir)/src/mock-log_test.cc'; fi` + +signalhandler_unittest-signalhandler_unittest.o: src/signalhandler_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(signalhandler_unittest_CXXFLAGS) $(CXXFLAGS) -MT signalhandler_unittest-signalhandler_unittest.o -MD -MP -MF $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Tpo -c -o signalhandler_unittest-signalhandler_unittest.o `test -f 'src/signalhandler_unittest.cc' || echo '$(srcdir)/'`src/signalhandler_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Tpo $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/signalhandler_unittest.cc' object='signalhandler_unittest-signalhandler_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(signalhandler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o signalhandler_unittest-signalhandler_unittest.o `test -f 'src/signalhandler_unittest.cc' || echo '$(srcdir)/'`src/signalhandler_unittest.cc + +signalhandler_unittest-signalhandler_unittest.obj: src/signalhandler_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(signalhandler_unittest_CXXFLAGS) $(CXXFLAGS) -MT signalhandler_unittest-signalhandler_unittest.obj -MD -MP -MF $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Tpo -c -o signalhandler_unittest-signalhandler_unittest.obj `if test -f 'src/signalhandler_unittest.cc'; then $(CYGPATH_W) 'src/signalhandler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/signalhandler_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Tpo $(DEPDIR)/signalhandler_unittest-signalhandler_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/signalhandler_unittest.cc' object='signalhandler_unittest-signalhandler_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(signalhandler_unittest_CXXFLAGS) $(CXXFLAGS) -c -o signalhandler_unittest-signalhandler_unittest.obj `if test -f 'src/signalhandler_unittest.cc'; then $(CYGPATH_W) 'src/signalhandler_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/signalhandler_unittest.cc'; fi` + +stacktrace_unittest-stacktrace_unittest.o: src/stacktrace_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stacktrace_unittest_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_unittest-stacktrace_unittest.o -MD -MP -MF $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Tpo -c -o stacktrace_unittest-stacktrace_unittest.o `test -f 'src/stacktrace_unittest.cc' || echo '$(srcdir)/'`src/stacktrace_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Tpo $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stacktrace_unittest.cc' object='stacktrace_unittest-stacktrace_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stacktrace_unittest_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace_unittest-stacktrace_unittest.o `test -f 'src/stacktrace_unittest.cc' || echo '$(srcdir)/'`src/stacktrace_unittest.cc + +stacktrace_unittest-stacktrace_unittest.obj: src/stacktrace_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stacktrace_unittest_CXXFLAGS) $(CXXFLAGS) -MT stacktrace_unittest-stacktrace_unittest.obj -MD -MP -MF $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Tpo -c -o stacktrace_unittest-stacktrace_unittest.obj `if test -f 'src/stacktrace_unittest.cc'; then $(CYGPATH_W) 'src/stacktrace_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/stacktrace_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Tpo $(DEPDIR)/stacktrace_unittest-stacktrace_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stacktrace_unittest.cc' object='stacktrace_unittest-stacktrace_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stacktrace_unittest_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace_unittest-stacktrace_unittest.obj `if test -f 'src/stacktrace_unittest.cc'; then $(CYGPATH_W) 'src/stacktrace_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/stacktrace_unittest.cc'; fi` + +stl_logging_unittest-stl_logging_unittest.o: src/stl_logging_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stl_logging_unittest_CXXFLAGS) $(CXXFLAGS) -MT stl_logging_unittest-stl_logging_unittest.o -MD -MP -MF $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Tpo -c -o stl_logging_unittest-stl_logging_unittest.o `test -f 'src/stl_logging_unittest.cc' || echo '$(srcdir)/'`src/stl_logging_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Tpo $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stl_logging_unittest.cc' object='stl_logging_unittest-stl_logging_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stl_logging_unittest_CXXFLAGS) $(CXXFLAGS) -c -o stl_logging_unittest-stl_logging_unittest.o `test -f 'src/stl_logging_unittest.cc' || echo '$(srcdir)/'`src/stl_logging_unittest.cc + +stl_logging_unittest-stl_logging_unittest.obj: src/stl_logging_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stl_logging_unittest_CXXFLAGS) $(CXXFLAGS) -MT stl_logging_unittest-stl_logging_unittest.obj -MD -MP -MF $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Tpo -c -o stl_logging_unittest-stl_logging_unittest.obj `if test -f 'src/stl_logging_unittest.cc'; then $(CYGPATH_W) 'src/stl_logging_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/stl_logging_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Tpo $(DEPDIR)/stl_logging_unittest-stl_logging_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/stl_logging_unittest.cc' object='stl_logging_unittest-stl_logging_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stl_logging_unittest_CXXFLAGS) $(CXXFLAGS) -c -o stl_logging_unittest-stl_logging_unittest.obj `if test -f 'src/stl_logging_unittest.cc'; then $(CYGPATH_W) 'src/stl_logging_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/stl_logging_unittest.cc'; fi` + +symbolize_unittest-symbolize_unittest.o: src/symbolize_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(symbolize_unittest_CXXFLAGS) $(CXXFLAGS) -MT symbolize_unittest-symbolize_unittest.o -MD -MP -MF $(DEPDIR)/symbolize_unittest-symbolize_unittest.Tpo -c -o symbolize_unittest-symbolize_unittest.o `test -f 'src/symbolize_unittest.cc' || echo '$(srcdir)/'`src/symbolize_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/symbolize_unittest-symbolize_unittest.Tpo $(DEPDIR)/symbolize_unittest-symbolize_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/symbolize_unittest.cc' object='symbolize_unittest-symbolize_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(symbolize_unittest_CXXFLAGS) $(CXXFLAGS) -c -o symbolize_unittest-symbolize_unittest.o `test -f 'src/symbolize_unittest.cc' || echo '$(srcdir)/'`src/symbolize_unittest.cc + +symbolize_unittest-symbolize_unittest.obj: src/symbolize_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(symbolize_unittest_CXXFLAGS) $(CXXFLAGS) -MT symbolize_unittest-symbolize_unittest.obj -MD -MP -MF $(DEPDIR)/symbolize_unittest-symbolize_unittest.Tpo -c -o symbolize_unittest-symbolize_unittest.obj `if test -f 'src/symbolize_unittest.cc'; then $(CYGPATH_W) 'src/symbolize_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/symbolize_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/symbolize_unittest-symbolize_unittest.Tpo $(DEPDIR)/symbolize_unittest-symbolize_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/symbolize_unittest.cc' object='symbolize_unittest-symbolize_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(symbolize_unittest_CXXFLAGS) $(CXXFLAGS) -c -o symbolize_unittest-symbolize_unittest.obj `if test -f 'src/symbolize_unittest.cc'; then $(CYGPATH_W) 'src/symbolize_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/symbolize_unittest.cc'; fi` + +utilities_unittest-utilities_unittest.o: src/utilities_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(utilities_unittest_CXXFLAGS) $(CXXFLAGS) -MT utilities_unittest-utilities_unittest.o -MD -MP -MF $(DEPDIR)/utilities_unittest-utilities_unittest.Tpo -c -o utilities_unittest-utilities_unittest.o `test -f 'src/utilities_unittest.cc' || echo '$(srcdir)/'`src/utilities_unittest.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/utilities_unittest-utilities_unittest.Tpo $(DEPDIR)/utilities_unittest-utilities_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utilities_unittest.cc' object='utilities_unittest-utilities_unittest.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(utilities_unittest_CXXFLAGS) $(CXXFLAGS) -c -o utilities_unittest-utilities_unittest.o `test -f 'src/utilities_unittest.cc' || echo '$(srcdir)/'`src/utilities_unittest.cc + +utilities_unittest-utilities_unittest.obj: src/utilities_unittest.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(utilities_unittest_CXXFLAGS) $(CXXFLAGS) -MT utilities_unittest-utilities_unittest.obj -MD -MP -MF $(DEPDIR)/utilities_unittest-utilities_unittest.Tpo -c -o utilities_unittest-utilities_unittest.obj `if test -f 'src/utilities_unittest.cc'; then $(CYGPATH_W) 'src/utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/utilities_unittest.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/utilities_unittest-utilities_unittest.Tpo $(DEPDIR)/utilities_unittest-utilities_unittest.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/utilities_unittest.cc' object='utilities_unittest-utilities_unittest.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(utilities_unittest_CXXFLAGS) $(CXXFLAGS) -c -o utilities_unittest-utilities_unittest.obj `if test -f 'src/utilities_unittest.cc'; then $(CYGPATH_W) 'src/utilities_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/utilities_unittest.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-dist_docDATA: $(dist_doc_DATA) + @$(NORMAL_INSTALL) + test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)" + @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ + done + +uninstall-dist_docDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(docdir)" && rm -f $$files +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files +install-glogincludeHEADERS: $(gloginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(glogincludedir)" || $(MKDIR_P) "$(DESTDIR)$(glogincludedir)" + @list='$(gloginclude_HEADERS)'; test -n "$(glogincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(glogincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(glogincludedir)" || exit $$?; \ + done + +uninstall-glogincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(gloginclude_HEADERS)'; test -n "$(glogincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(glogincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(glogincludedir)" && rm -f $$files +install-nodist_glogincludeHEADERS: $(nodist_gloginclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(glogincludedir)" || $(MKDIR_P) "$(DESTDIR)$(glogincludedir)" + @list='$(nodist_gloginclude_HEADERS)'; test -n "$(glogincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(glogincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(glogincludedir)" || exit $$?; \ + done + +uninstall-nodist_glogincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_gloginclude_HEADERS)'; test -n "$(glogincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(glogincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(glogincludedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(DATA) \ + $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(glogincludedir)" "$(DESTDIR)$(glogincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_docDATA install-glogincludeHEADERS \ + install-nodist_glogincludeHEADERS install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_docDATA uninstall-glogincludeHEADERS \ + uninstall-libLTLIBRARIES uninstall-nodist_glogincludeHEADERS \ + uninstall-pkgconfigDATA + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ + clean clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstPROGRAMS ctags dist dist-all dist-bzip2 dist-gzip \ + dist-hook dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-dist_docDATA install-dvi install-dvi-am install-exec \ + install-exec-am install-glogincludeHEADERS install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man \ + install-nodist_glogincludeHEADERS install-pdf install-pdf-am \ + install-pkgconfigDATA install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-dist_docDATA \ + uninstall-glogincludeHEADERS uninstall-libLTLIBRARIES \ + uninstall-nodist_glogincludeHEADERS uninstall-pkgconfigDATA + +@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@ # TODO(csilvers): check if -fomit-frame-pointer might be in $(CXXFLAGS), +@ENABLE_FRAME_POINTERS_FALSE@@X86_64_TRUE@ # before setting this. +logging_striplog_test_sh: logging_striptest0 logging_striptest2 logging_striptest10 + $(top_srcdir)/src/logging_striplog_test.sh +demangle_unittest_sh: demangle_unittest + $(builddir)/demangle_unittest # force to create lt-demangle_unittest + $(top_srcdir)/src/demangle_unittest.sh +signalhandler_unittest_sh: signalhandler_unittest + $(builddir)/signalhandler_unittest # force to create lt-signalhandler_unittest + $(top_srcdir)/src/signalhandler_unittest.sh + +rpm: dist-gzip packages/rpm.sh packages/rpm/rpm.spec + @cd packages && ./rpm.sh ${PACKAGE} ${VERSION} + +deb: dist-gzip packages/deb.sh packages/deb/* + @cd packages && ./deb.sh ${PACKAGE} ${VERSION} + +# Windows wants write permission to .vcproj files and maybe even sln files. +dist-hook: + test -e "$(distdir)/vsprojects" \ + && chmod -R u+w $(distdir)/*.sln $(distdir)/vsprojects/ + +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/LICENSE b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/LICENSE new file mode 100644 index 0000000000..c5638285a9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/LICENSE @@ -0,0 +1,137 @@ + + + + + The "Clarified Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Distribution fee" is a fee you charge for providing a copy of this + Package to another party. + + "Freely Available" means that no fee is charged for the right to use + the item, though there may be fees involved in handling the item. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain, or those made Freely Available, or from +the Copyright Holder. A Package modified in such a way shall still be +considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site allowing unrestricted access to them, or by allowing the Copyright + Holder to include your modifications in the Standard Version of the + Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) permit and encourge anyone who receives a copy of the modified Package + permission to make your modifications Freely Available in some specific + way. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + + e) offer the machine-readable source of the Package, with your + modifications, by mail order. + +5. You may charge a distribution fee for any distribution of this Package. +If you offer support for this Package, you may charge any fee you choose +for that support. You may not charge a license fee for the right to use +this Package itself. You may distribute this Package in aggregate with +other (possibly commercial and possibly nonfree) programs as part of a +larger (possibly commercial and possibly nonfree) software distribution, +and charge license fees for other parts of that software distribution, +provided that you do not advertise this Package as a product of your own. +If the Package includes an interpreter, You may embed this Package's +interpreter within an executable of yours (by linking); this shall be +construed as a mere form of aggregation, provided that the complete +Standard Version of the interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of the Standard Version of the Package with a commercial +distribution is always permitted provided that the use of this Package is +embedded; that is, when no overt attempt is made to make this Package's +interfaces visible to the end user of the commercial distribution. +Such use shall not be construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/Makefile.am b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/Makefile.am new file mode 100644 index 0000000000..bd3129e1ad --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/Makefile.am @@ -0,0 +1,43 @@ +include_HEADERS = libdis.h +lib_LTLIBRARIES = libdisasm.la +libdisasm_la_SOURCES = \ + ia32_implicit.c \ + ia32_implicit.h \ + ia32_insn.c \ + ia32_insn.h \ + ia32_invariant.c \ + ia32_invariant.h \ + ia32_modrm.c \ + ia32_modrm.h \ + ia32_opcode_tables.c \ + ia32_opcode_tables.h \ + ia32_operand.c \ + ia32_operand.h \ + ia32_reg.c \ + ia32_reg.h \ + ia32_settings.c \ + ia32_settings.h \ + libdis.h \ + qword.h \ + x86_disasm.c \ + x86_format.c \ + x86_imm.c \ + x86_imm.h \ + x86_insn.c \ + x86_misc.c \ + x86_operand_list.c \ + x86_operand_list.h + +# Cheat to get non-autoconf swig into tarball, +# even if it doesn't build by default. +EXTRA_DIST = \ +swig/Makefile \ +swig/libdisasm.i \ +swig/libdisasm_oop.i \ +swig/python/Makefile-swig \ +swig/perl/Makefile-swig \ +swig/perl/Makefile.PL \ +swig/ruby/Makefile-swig \ +swig/ruby/extconf.rb \ +swig/tcl/Makefile-swig \ +swig/README diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/README.breakpad b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/README.breakpad new file mode 100644 index 0000000000..a345411401 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/README.breakpad @@ -0,0 +1,9 @@ +Name: libdisasm +URL: https://sourceforge.net/projects/bastard/files/libdisasm/0.23/libdisasm-0.23.tar.gz/download +Version: 0.23 +License: Clarified-Artistic +License File: LICENSE + +Description: +This contains a copy of libdisasm. It is no longer under development upstream, +so we keep a copy here to maintain fixes ourselves. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/TODO b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/TODO new file mode 100644 index 0000000000..148addf9b8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/TODO @@ -0,0 +1,43 @@ +x86_format.c +------------ +intel: jmpf -> jmp, callf -> call +att: jmpf -> ljmp, callf -> lcall + +opcode table +------------ +finish typing instructions +fix flag clear/set/toggle types + +ix64 stuff +---------- +document output file formats in web page +features doc: register aliases, implicit operands, stack mods, +ring0 flags, eflags, cpu model/isa + +ia32_handle_* implementation + +fix operand 0F C2 +CMPPS + +* sysenter, sysexit as CALL types -- preceded by MSR writes +* SYSENTER/SYSEXIT stack : overwrites SS, ESP +* stos, cmps, scas, movs, ins, outs, lods -> OP_PTR +* OP_SIZE in implicit operands +* use OP_SIZE to choose reg sizes! + +DONE?? : +implicit operands: provide action ? +e.g. add/inc for stach, write, etc +replace table numbers in opcodes.dat with +#defines for table names + +replace 0 with INSN_INVALID [or maybe FF for imnvalid and 00 for Not Applicable */ +no wait that is only for prefix tables -- n/p + +if ( prefx) only use if insn != invalid + +these should cover all the wacky disasm exceptions + +for the rep one we can chet, match only a 0x90 + +todo: privilege | ring diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.c new file mode 100644 index 0000000000..8b075d2ee0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.c @@ -0,0 +1,422 @@ +#include + +#include "ia32_implicit.h" +#include "ia32_insn.h" +#include "ia32_reg.h" +#include "x86_operand_list.h" + +/* Conventions: Register operands which are aliases of another register + * operand (e.g. AX in one operand and AL in another) assume that the + * operands are different registers and that alias tracking will resolve + * data flow. This means that something like + * mov ax, al + * would have 'write only' access for AX and 'read only' access for AL, + * even though both AL and AX are read and written */ +typedef struct { + uint32_t type; + uint32_t operand; +} op_implicit_list_t; + +static op_implicit_list_t list_aaa[] = + /* 37 : AAA : rw AL */ + /* 3F : AAS : rw AL */ + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* aaa */ + +static op_implicit_list_t list_aad[] = + /* D5 0A, D5 (ib) : AAD : rw AX */ + /* D4 0A, D4 (ib) : AAM : rw AX */ + {{ OP_R | OP_W, REG_WORD_OFFSET }, {0}}; /* aad */ + +static op_implicit_list_t list_call[] = + /* E8, FF, 9A, FF : CALL : rw ESP, rw EIP */ + /* C2, C3, CA, CB : RET : rw ESP, rw EIP */ + {{ OP_R | OP_W, REG_EIP_INDEX }, + { OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* call, ret */ + +static op_implicit_list_t list_cbw[] = + /* 98 : CBW : r AL, rw AX */ + {{ OP_R | OP_W, REG_WORD_OFFSET }, + { OP_R, REG_BYTE_OFFSET}, {0}}; /* cbw */ + +static op_implicit_list_t list_cwde[] = + /* 98 : CWDE : r AX, rw EAX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, + { OP_R, REG_WORD_OFFSET }, {0}}; /* cwde */ + +static op_implicit_list_t list_clts[] = + /* 0F 06 : CLTS : rw CR0 */ + {{ OP_R | OP_W, REG_CTRL_OFFSET}, {0}}; /* clts */ + +static op_implicit_list_t list_cmpxchg[] = + /* 0F B0 : CMPXCHG : rw AL */ + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* cmpxchg */ + +static op_implicit_list_t list_cmpxchgb[] = + /* 0F B1 : CMPXCHG : rw EAX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* cmpxchg */ + +static op_implicit_list_t list_cmpxchg8b[] = + /* 0F C7 : CMPXCHG8B : rw EDX, rw EAX, r ECX, r EBX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, + { OP_R | OP_W, REG_DWORD_OFFSET + 2 }, + { OP_R, REG_DWORD_OFFSET + 1 }, + { OP_R, REG_DWORD_OFFSET + 3 }, {0}}; /* cmpxchg8b */ + +static op_implicit_list_t list_cpuid[] = + /* 0F A2 : CPUID : rw EAX, w EBX, w ECX, w EDX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, + { OP_W, REG_DWORD_OFFSET + 1 }, + { OP_W, REG_DWORD_OFFSET + 2 }, + { OP_W, REG_DWORD_OFFSET + 3 }, {0}}; /* cpuid */ + +static op_implicit_list_t list_cwd[] = + /* 99 : CWD/CWQ : rw EAX, w EDX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, + { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* cwd */ + +static op_implicit_list_t list_daa[] = + /* 27 : DAA : rw AL */ + /* 2F : DAS : rw AL */ + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* daa */ + +static op_implicit_list_t list_idiv[] = + /* F6 : DIV, IDIV : r AX, w AL, w AH */ + /* FIXED: first op was EAX, not Aw. TODO: verify! */ + {{ OP_R, REG_WORD_OFFSET }, + { OP_W, REG_BYTE_OFFSET }, + { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* div */ + +static op_implicit_list_t list_div[] = + /* F7 : DIV, IDIV : rw EDX, rw EAX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, + { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* div */ + +static op_implicit_list_t list_enter[] = + /* C8 : ENTER : rw ESP w EBP */ + {{ OP_R | OP_W, REG_DWORD_OFFSET + 4 }, + { OP_R, REG_DWORD_OFFSET + 5 }, {0}}; /* enter */ + +static op_implicit_list_t list_f2xm1[] = + /* D9 F0 : F2XM1 : rw ST(0) */ + /* D9 E1 : FABS : rw ST(0) */ + /* D9 E0 : FCHS : rw ST(0) */ + /* D9 FF : FCOS : rw ST(0)*/ + /* D8, DA : FDIV : rw ST(0) */ + /* D8, DA : FDIVR : rw ST(0) */ + /* D9 F2 : FPTAN : rw ST(0) */ + /* D9 FC : FRNDINT : rw ST(0) */ + /* D9 FB : FSINCOS : rw ST(0) */ + /* D9 FE : FSIN : rw ST(0) */ + /* D9 FA : FSQRT : rw ST(0) */ + /* D9 F4 : FXTRACT : rw ST(0) */ + {{ OP_R | OP_W, REG_FPU_OFFSET }, {0}}; /* f2xm1 */ + +static op_implicit_list_t list_fcom[] = + /* D8, DC, DE D9 : FCOM : r ST(0) */ + /* DE, DA : FICOM : r ST(0) */ + /* DF, D8 : FIST : r ST(0) */ + /* D9 E4 : FTST : r ST(0) */ + /* D9 E5 : FXAM : r ST(0) */ + {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fcom */ + +static op_implicit_list_t list_fpatan[] = + /* D9 F3 : FPATAN : r ST(0), rw ST(1) */ + {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fpatan */ + +static op_implicit_list_t list_fprem[] = + /* D9 F8, D9 F5 : FPREM : rw ST(0) r ST(1) */ + /* D9 FD : FSCALE : rw ST(0), r ST(1) */ + {{ OP_R | OP_W, REG_FPU_OFFSET }, + { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fprem */ + +static op_implicit_list_t list_faddp[] = + /* DE C1 : FADDP : r ST(0), rw ST(1) */ + /* DE E9 : FSUBP : r ST(0), rw ST(1) */ + /* D9 F1 : FYL2X : r ST(0), rw ST(1) */ + /* D9 F9 : FYL2XP1 : r ST(0), rw ST(1) */ + {{ OP_R, REG_FPU_OFFSET }, + { OP_R | OP_W, REG_FPU_OFFSET + 1 }, {0}}; /* faddp */ + +static op_implicit_list_t list_fucompp[] = + /* DA E9 : FUCOMPP : r ST(0), r ST(1) */ + {{ OP_R, REG_FPU_OFFSET }, + { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fucompp */ + +static op_implicit_list_t list_imul[] = + /* F6 : IMUL : r AL, w AX */ + /* F6 : MUL : r AL, w AX */ + {{ OP_R, REG_BYTE_OFFSET }, + { OP_W, REG_WORD_OFFSET }, {0}}; /* imul */ + +static op_implicit_list_t list_mul[] = + /* F7 : IMUL : rw EAX, w EDX */ + /* F7 : MUL : rw EAX, w EDX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET }, + { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* imul */ + +static op_implicit_list_t list_lahf[] = + /* 9F : LAHF : r EFLAGS, w AH */ + {{ OP_R, REG_FLAGS_INDEX }, + { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* lahf */ + +static op_implicit_list_t list_ldmxcsr[] = + /* 0F AE : LDMXCSR : w MXCSR SSE Control Status Reg */ + {{ OP_W, REG_MXCSG_INDEX }, {0}}; /* ldmxcsr */ + +static op_implicit_list_t list_leave[] = + /* C9 : LEAVE : rw ESP, w EBP */ + {{ OP_R | OP_W, REG_ESP_INDEX }, + { OP_W, REG_DWORD_OFFSET + 5 }, {0}}; /* leave */ + +static op_implicit_list_t list_lgdt[] = + /* 0F 01 : LGDT : w GDTR */ + {{ OP_W, REG_GDTR_INDEX }, {0}}; /* lgdt */ + +static op_implicit_list_t list_lidt[] = + /* 0F 01 : LIDT : w IDTR */ + {{ OP_W, REG_IDTR_INDEX }, {0}}; /* lidt */ + +static op_implicit_list_t list_lldt[] = + /* 0F 00 : LLDT : w LDTR */ + {{ OP_W, REG_LDTR_INDEX }, {0}}; /* lldt */ + +static op_implicit_list_t list_lmsw[] = + /* 0F 01 : LMSW : w CR0 */ + {{ OP_W, REG_CTRL_OFFSET }, {0}}; /* lmsw */ + +static op_implicit_list_t list_loop[] = + /* E0, E1, E2 : LOOP : rw ECX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* loop */ + +static op_implicit_list_t list_ltr[] = + /* 0F 00 : LTR : w Task Register */ + {{ OP_W, REG_TR_INDEX }, {0}}; /* ltr */ + +static op_implicit_list_t list_pop[] = + /* 8F, 58, 1F, 07, 17, 0F A1, 0F A9 : POP : rw ESP */ + /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ + {{ OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* pop, push */ + +static op_implicit_list_t list_popad[] = + /* 61 : POPAD : rw esp, w edi esi ebp ebx edx ecx eax */ + {{ OP_R | OP_W, REG_ESP_INDEX }, + { OP_W, REG_DWORD_OFFSET + 7 }, + { OP_W, REG_DWORD_OFFSET + 6 }, + { OP_W, REG_DWORD_OFFSET + 5 }, + { OP_W, REG_DWORD_OFFSET + 3 }, + { OP_W, REG_DWORD_OFFSET + 2 }, + { OP_W, REG_DWORD_OFFSET + 1 }, + { OP_W, REG_DWORD_OFFSET }, {0}}; /* popad */ + +static op_implicit_list_t list_popfd[] = + /* 9D : POPFD : rw esp, w eflags */ + {{ OP_R | OP_W, REG_ESP_INDEX }, + { OP_W, REG_FLAGS_INDEX }, {0}}; /* popfd */ + +static op_implicit_list_t list_pushad[] = + /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ + /* 60 : PUSHAD : rw esp, r eax ecx edx ebx esp ebp esi edi */ + {{ OP_R | OP_W, REG_ESP_INDEX }, + { OP_R, REG_DWORD_OFFSET }, + { OP_R, REG_DWORD_OFFSET + 1 }, + { OP_R, REG_DWORD_OFFSET + 2 }, + { OP_R, REG_DWORD_OFFSET + 3 }, + { OP_R, REG_DWORD_OFFSET + 5 }, + { OP_R, REG_DWORD_OFFSET + 6 }, + { OP_R, REG_DWORD_OFFSET + 7 }, {0}}; /* pushad */ + +static op_implicit_list_t list_pushfd[] = + /* 9C : PUSHFD : rw esp, r eflags */ + {{ OP_R | OP_W, REG_ESP_INDEX }, + { OP_R, REG_FLAGS_INDEX }, {0}}; /* pushfd */ + +static op_implicit_list_t list_rdmsr[] = + /* 0F 32 : RDMSR : r ECX, w EDX, w EAX */ + {{ OP_R, REG_DWORD_OFFSET + 1 }, + { OP_W, REG_DWORD_OFFSET + 2 }, + { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdmsr */ + +static op_implicit_list_t list_rdpmc[] = + /* 0F 33 : RDPMC : r ECX, w EDX, w EAX */ + {{ OP_R, REG_DWORD_OFFSET + 1 }, + { OP_W, REG_DWORD_OFFSET + 2 }, + { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdpmc */ + +static op_implicit_list_t list_rdtsc[] = + /* 0F 31 : RDTSC : rw EDX, rw EAX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, + { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* rdtsc */ + +static op_implicit_list_t list_rep[] = + /* F3, F2 ... : REP : rw ECX */ + {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* rep */ + +static op_implicit_list_t list_rsm[] = + /* 0F AA : RSM : r CR4, r CR0 */ + {{ OP_R, REG_CTRL_OFFSET + 4 }, + { OP_R, REG_CTRL_OFFSET }, {0}}; /* rsm */ + +static op_implicit_list_t list_sahf[] = + /* 9E : SAHF : r ah, rw eflags (set SF ZF AF PF CF) */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sahf */ + +static op_implicit_list_t list_sgdt[] = + /* 0F : SGDT : r gdtr */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sgdt */ + +static op_implicit_list_t list_sidt[] = + /* 0F : SIDT : r idtr */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sidt */ + +static op_implicit_list_t list_sldt[] = + /* 0F : SLDT : r ldtr */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sldt */ + +static op_implicit_list_t list_smsw[] = + /* 0F : SMSW : r CR0 */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* smsw */ + +static op_implicit_list_t list_stmxcsr[] = + /* 0F AE : STMXCSR : r MXCSR */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* stmxcsr */ + +static op_implicit_list_t list_str[] = + /* 0F 00 : STR : r TR (task register) */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* str */ + +static op_implicit_list_t list_sysenter[] = + /* 0F 34 : SYSENTER : w cs, w eip, w ss, w esp, r CR0, w eflags + * r sysenter_cs_msr, sysenter_esp_msr, sysenter_eip_msr */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysenter */ + +static op_implicit_list_t list_sysexit[] = + /* 0F 35 : SYSEXIT : r edx, r ecx, w cs, w eip, w ss, w esp + * r sysenter_cs_msr */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysexit */ + +static op_implicit_list_t list_wrmsr[] = + /* 0F 30 : WRMST : r edx, r eax, r ecx */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* wrmsr */ + +static op_implicit_list_t list_xlat[] = + /* D7 : XLAT : rw al r ebx (ptr) */ + /* TODO: finish this! */ + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* xlat */ +/* TODO: + * monitor 0f 01 c8 eax OP_R ecx OP_R edx OP_R + * mwait 0f 01 c9 eax OP_R ecx OP_R + */ +static op_implicit_list_t list_monitor[] = + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* monitor */ +static op_implicit_list_t list_mwait[] = + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* mwait */ + +op_implicit_list_t *op_implicit_list[] = { + /* This is a list of implicit operands which are read/written by + * various x86 instructions. Note that modifications to the stack + * register are mentioned here, but that additional information on + * the effect an instruction has on the stack is contained in the + * x86_insn_t 'stack_mod' and 'stack_mod_val' fields. Use of the + * eflags register, i.e. setting, clearing, and testing flags, is + * not recorded here but rather in the flags_set and flags_tested + * fields of the x86_insn_t.*/ + NULL, + list_aaa, list_aad, list_call, list_cbw, /* 1 - 4 */ + list_cwde, list_clts, list_cmpxchg, list_cmpxchgb, /* 5 - 8 */ + list_cmpxchg8b, list_cpuid, list_cwd, list_daa, /* 9 - 12 */ + list_idiv, list_div, list_enter, list_f2xm1, /* 13 - 16 */ + list_fcom, list_fpatan, list_fprem, list_faddp, /* 17 - 20 */ + list_fucompp, list_imul, list_mul, list_lahf, /* 21 - 24 */ + list_ldmxcsr, list_leave, list_lgdt, list_lidt, /* 25 - 28 */ + list_lldt, list_lmsw, list_loop, list_ltr, /* 29 - 32 */ + list_pop, list_popad, list_popfd, list_pushad, /* 33 - 36 */ + list_pushfd, list_rdmsr, list_rdpmc, list_rdtsc, /* 37 - 40 */ + /* NOTE: 'REP' is a hack since it is a prefix: if its position + * in the table changes, then change IDX_IMPLICIT_REP in the .h */ + list_rep, list_rsm, list_sahf, list_sgdt, /* 41 - 44 */ + list_sidt, list_sldt, list_smsw, list_stmxcsr, /* 45 - 48 */ + list_str, list_sysenter, list_sysexit, list_wrmsr, /* 49 - 52 */ + list_xlat, list_monitor, list_mwait, /* 53 - 55*/ + NULL /* end of list */ + }; + +#define LAST_IMPL_IDX 55 + +static void handle_impl_reg( x86_op_t *op, uint32_t val ) { + x86_reg_t *reg = &op->data.reg; + op->type = op_register; + ia32_handle_register( reg, (unsigned int) val ); + switch (reg->size) { + case 1: + op->datatype = op_byte; break; + case 2: + op->datatype = op_word; break; + case 4: + op->datatype = op_dword; break; + case 8: + op->datatype = op_qword; break; + case 10: + op->datatype = op_extreal; break; + case 16: + op->datatype = op_dqword; break; + } + return; +} + +/* 'impl_idx' is the value from the opcode table: between 1 and LAST_IMPL_IDX */ +/* returns number of operands added */ +unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx ) { + op_implicit_list_t *list; + x86_op_t *op; + unsigned int num = 0; + + if (! impl_idx || impl_idx > LAST_IMPL_IDX ) { + return 0; + } + + for ( list = op_implicit_list[impl_idx]; list->type; list++, num++ ) { + enum x86_op_access access = (enum x86_op_access) OP_PERM(list->type); + enum x86_op_flags flags = (enum x86_op_flags) (OP_FLAGS(list->type) >> 12); + + op = NULL; + /* In some cases (MUL), EAX is an implicit operand hardcoded in + * the instruction without being explicitly listed in assembly. + * For this situation, find the hardcoded operand and add the + * implied flag rather than adding a new implicit operand. */ + x86_oplist_t * existing; + if (ia32_true_register_id(list->operand) == REG_DWORD_OFFSET) { + for ( existing = insn->operands; existing; existing = existing->next ) { + if (existing->op.type == op_register && + existing->op.data.reg.id == list->operand) { + op = &existing->op; + break; + } + } + } + if (!op) { + op = x86_operand_new( insn ); + /* all implicit operands are registers */ + handle_impl_reg( op, list->operand ); + /* decrement the 'explicit count' incremented by default in + * x86_operand_new */ + insn->explicit_count = insn->explicit_count -1; + } + if (!op) { + return num; /* gah! return early */ + } + op->access |= access; + op->flags |= flags; + op->flags |= op_implied; + } + + return num; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.h new file mode 100644 index 0000000000..0002b28b9b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.h @@ -0,0 +1,13 @@ +#ifndef IA32_IMPLICIT_H +#define IA32_IMPLICIT_H + +#include "libdis.h" + +/* OK, this is a hack to deal with prefixes having implicit operands... + * thought I had removed all the old hackishness ;( */ + +#define IDX_IMPLICIT_REP 41 /* change this if the table changes! */ + +unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx ); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.c new file mode 100644 index 0000000000..cc277608bf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.c @@ -0,0 +1,623 @@ +#include +#include +#include +#include "qword.h" + +#include "ia32_insn.h" +#include "ia32_opcode_tables.h" + +#include "ia32_reg.h" +#include "ia32_operand.h" +#include "ia32_implicit.h" +#include "ia32_settings.h" + +#include "libdis.h" + +extern ia32_table_desc_t ia32_tables[]; +extern ia32_settings_t ia32_settings; + +#define IS_SP( op ) (op->type == op_register && \ + (op->data.reg.id == REG_ESP_INDEX || \ + op->data.reg.alias == REG_ESP_INDEX) ) +#define IS_IMM( op ) (op->type == op_immediate ) + +#ifdef WIN32 +# define INLINE +#else +# define INLINE inline +#endif + +/* for calculating stack modification based on an operand */ +static INLINE int32_t long_from_operand( x86_op_t *op ) { + + if (! IS_IMM(op) ) { + return 0L; + } + + switch ( op->datatype ) { + case op_byte: + return (int32_t) op->data.sbyte; + case op_word: + return (int32_t) op->data.sword; + case op_qword: + return (int32_t) op->data.sqword; + case op_dword: + return op->data.sdword; + default: + /* these are not used in stack insn */ + break; + } + + return 0L; +} + + +/* determine what this insn does to the stack */ +static void ia32_stack_mod(x86_insn_t *insn) { + x86_op_t *dest, *src = NULL; + + if (! insn || ! insn->operands ) { + return; + } + + dest = &insn->operands->op; + if ( dest ) { + src = &insn->operands->next->op; + } + + insn->stack_mod = 0; + insn->stack_mod_val = 0; + + switch ( insn->type ) { + case insn_call: + case insn_callcc: + insn->stack_mod = 1; + insn->stack_mod_val = insn->addr_size * -1; + break; + case insn_push: + insn->stack_mod = 1; + insn->stack_mod_val = insn->addr_size * -1; + break; + case insn_return: + insn->stack_mod = 1; + insn->stack_mod_val = insn->addr_size; + case insn_int: case insn_intcc: + case insn_iret: + break; + case insn_pop: + insn->stack_mod = 1; + if (! IS_SP( dest ) ) { + insn->stack_mod_val = insn->op_size; + } /* else we don't know the stack change in a pop esp */ + break; + case insn_enter: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_leave: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_pushregs: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_popregs: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_pushflags: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_popflags: + insn->stack_mod = 1; + insn->stack_mod_val = 0; /* TODO : FIX */ + break; + case insn_add: + if ( IS_SP( dest ) ) { + insn->stack_mod = 1; + insn->stack_mod_val = long_from_operand( src ); + } + break; + case insn_sub: + if ( IS_SP( dest ) ) { + insn->stack_mod = 1; + insn->stack_mod_val = long_from_operand( src ); + insn->stack_mod_val *= -1; + } + break; + case insn_inc: + if ( IS_SP( dest ) ) { + insn->stack_mod = 1; + insn->stack_mod_val = 1; + } + break; + case insn_dec: + if ( IS_SP( dest ) ) { + insn->stack_mod = 1; + insn->stack_mod_val = 1; + } + break; + case insn_mov: case insn_movcc: + case insn_xchg: case insn_xchgcc: + case insn_mul: case insn_div: + case insn_shl: case insn_shr: + case insn_rol: case insn_ror: + case insn_and: case insn_or: + case insn_not: case insn_neg: + case insn_xor: + if ( IS_SP( dest ) ) { + insn->stack_mod = 1; + } + break; + default: + break; + } + if (! strcmp("enter", insn->mnemonic) ) { + insn->stack_mod = 1; + } else if (! strcmp("leave", insn->mnemonic) ) { + insn->stack_mod = 1; + } + + /* for mov, etc we return 0 -- unknown stack mod */ + + return; +} + +/* get the cpu details for this insn from cpu flags int */ +static void ia32_handle_cpu( x86_insn_t *insn, unsigned int cpu ) { + insn->cpu = (enum x86_insn_cpu) CPU_MODEL(cpu); + insn->isa = (enum x86_insn_isa) (ISA_SUBSET(cpu)) >> 16; + return; +} + +/* handle mnemonic type and group */ +static void ia32_handle_mnemtype(x86_insn_t *insn, unsigned int mnemtype) { + unsigned int type = mnemtype & ~INS_FLAG_MASK; + insn->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12; + insn->type = (enum x86_insn_type) INS_TYPE(type); + + return; +} + +static void ia32_handle_notes(x86_insn_t *insn, unsigned int notes) { + insn->note = (enum x86_insn_note) notes; + return; +} + +static void ia32_handle_eflags( x86_insn_t *insn, unsigned int eflags) { + unsigned int flags; + + /* handle flags effected */ + flags = INS_FLAGS_TEST(eflags); + /* handle weird OR cases */ + /* these are either JLE (ZF | SF<>OF) or JBE (CF | ZF) */ + if (flags & INS_TEST_OR) { + flags &= ~INS_TEST_OR; + if ( flags & INS_TEST_ZERO ) { + flags &= ~INS_TEST_ZERO; + if ( flags & INS_TEST_CARRY ) { + flags &= ~INS_TEST_CARRY ; + flags |= (int)insn_carry_or_zero_set; + } else if ( flags & INS_TEST_SFNEOF ) { + flags &= ~INS_TEST_SFNEOF; + flags |= (int)insn_zero_set_or_sign_ne_oflow; + } + } + } + insn->flags_tested = (enum x86_flag_status) flags; + + insn->flags_set = (enum x86_flag_status) INS_FLAGS_SET(eflags) >> 16; + + return; +} + +static void ia32_handle_prefix( x86_insn_t *insn, unsigned int prefixes ) { + + insn->prefix = (enum x86_insn_prefix) prefixes & PREFIX_MASK; // >> 20; + if (! (insn->prefix & PREFIX_PRINT_MASK) ) { + /* no printable prefixes */ + insn->prefix = insn_no_prefix; + } + + /* concat all prefix strings */ + if ( (unsigned int)insn->prefix & PREFIX_LOCK ) { + strncat(insn->prefix_string, "lock ", 32 - + strlen(insn->prefix_string)); + } + + if ( (unsigned int)insn->prefix & PREFIX_REPNZ ) { + strncat(insn->prefix_string, "repnz ", 32 - + strlen(insn->prefix_string)); + } else if ( (unsigned int)insn->prefix & PREFIX_REPZ ) { + strncat(insn->prefix_string, "repz ", 32 - + strlen(insn->prefix_string)); + } + + return; +} + + +static void reg_32_to_16( x86_op_t *op, x86_insn_t *insn, void *arg ) { + + /* if this is a 32-bit register and it is a general register ... */ + if ( op->type == op_register && op->data.reg.size == 4 && + (op->data.reg.type & reg_gen) ) { + /* WORD registers are 8 indices off from DWORD registers */ + ia32_handle_register( &(op->data.reg), + op->data.reg.id + 8 ); + } +} + +static void handle_insn_metadata( x86_insn_t *insn, ia32_insn_t *raw_insn ) { + ia32_handle_mnemtype( insn, raw_insn->mnem_flag ); + ia32_handle_notes( insn, raw_insn->notes ); + ia32_handle_eflags( insn, raw_insn->flags_effected ); + ia32_handle_cpu( insn, raw_insn->cpu ); + ia32_stack_mod( insn ); +} + +static size_t ia32_decode_insn( unsigned char *buf, size_t buf_len, + ia32_insn_t *raw_insn, x86_insn_t *insn, + unsigned int prefixes ) { + size_t size, op_size; + unsigned char modrm; + + /* this should never happen, but just in case... */ + if ( raw_insn->mnem_flag == INS_INVALID ) { + return 0; + } + + if (ia32_settings.options & opt_16_bit) { + insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2; + insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2; + } else { + insn->op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4; + insn->addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4; + } + + + /* ++++ 1. Copy mnemonic and mnemonic-flags to CODE struct */ + if ((ia32_settings.options & opt_att_mnemonics) && raw_insn->mnemonic_att[0]) { + strncpy( insn->mnemonic, raw_insn->mnemonic_att, 16 ); + } + else { + strncpy( insn->mnemonic, raw_insn->mnemonic, 16 ); + } + ia32_handle_prefix( insn, prefixes ); + + handle_insn_metadata( insn, raw_insn ); + + /* prefetch the next byte in case it is a modr/m byte -- saves + * worrying about whether the 'mod/rm' operand or the 'reg' operand + * occurs first */ + modrm = GET_BYTE( buf, buf_len ); + + /* ++++ 2. Decode Explicit Operands */ + /* Intel uses up to 3 explicit operands in its instructions; + * the first is 'dest', the second is 'src', and the third + * is an additional source value (usually an immediate value, + * e.g. in the MUL instructions). These three explicit operands + * are encoded in the opcode tables, even if they are not used + * by the instruction. Additional implicit operands are stored + * in a supplemental table and are handled later. */ + + op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->dest, + raw_insn->dest_flag, prefixes, modrm ); + /* advance buffer, increase size if necessary */ + buf += op_size; + buf_len -= op_size; + size = op_size; + + op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->src, + raw_insn->src_flag, prefixes, modrm ); + buf += op_size; + buf_len -= op_size; + size += op_size; + + op_size = ia32_decode_operand( buf, buf_len, insn, raw_insn->aux, + raw_insn->aux_flag, prefixes, modrm ); + size += op_size; + + + /* ++++ 3. Decode Implicit Operands */ + /* apply implicit operands */ + ia32_insn_implicit_ops( insn, raw_insn->implicit_ops ); + /* we have one small inelegant hack here, to deal with + * the two prefixes that have implicit operands. If Intel + * adds more, we'll change the algorithm to suit :) */ + if ( (prefixes & PREFIX_REPZ) || (prefixes & PREFIX_REPNZ) ) { + ia32_insn_implicit_ops( insn, IDX_IMPLICIT_REP ); + } + + + /* 16-bit hack: foreach operand, if 32-bit reg, make 16-bit reg */ + if ( insn->op_size == 2 ) { + x86_operand_foreach( insn, reg_32_to_16, NULL, op_any ); + } + + return size; +} + + +/* convenience routine */ +#define USES_MOD_RM(flag) \ + (flag == ADDRMETH_E || flag == ADDRMETH_M || flag == ADDRMETH_Q || \ + flag == ADDRMETH_W || flag == ADDRMETH_R) + +static int uses_modrm_flag( unsigned int flag ) { + unsigned int meth; + if ( flag == ARG_NONE ) { + return 0; + } + meth = (flag & ADDRMETH_MASK); + if ( USES_MOD_RM(meth) ) { + return 1; + } + + return 0; +} + +/* This routine performs the actual byte-by-byte opcode table lookup. + * Originally it was pretty simple: get a byte, adjust it to a proper + * index into the table, then check the table row at that index to + * determine what to do next. But is anything that simple with Intel? + * This is now a huge, convoluted mess, mostly of bitter comments. */ +/* buf: pointer to next byte to read from stream + * buf_len: length of buf + * table: index of table to use for lookups + * raw_insn: output pointer that receives opcode definition + * prefixes: output integer that is encoded with prefixes in insn + * returns : number of bytes consumed from stream during lookup */ +size_t ia32_table_lookup( unsigned char *buf, size_t buf_len, + unsigned int table, ia32_insn_t **raw_insn, + unsigned int *prefixes ) { + unsigned char *next, op = buf[0]; /* byte value -- 'opcode' */ + size_t size = 1, sub_size = 0, next_len; + ia32_table_desc_t *table_desc; + unsigned int subtable, prefix = 0, recurse_table = 0; + + table_desc = &ia32_tables[table]; + + op = GET_BYTE( buf, buf_len ); + + if ( table_desc->type == tbl_fpu && op > table_desc->maxlim) { + /* one of the fucking FPU tables out of the 00-BH range */ + /* OK,. this is a bit of a hack -- the proper way would + * have been to use subtables in the 00-BF FPU opcode tables, + * but that is rather wasteful of space... */ + table_desc = &ia32_tables[table +1]; + } + + /* PERFORM TABLE LOOKUP */ + + /* ModR/M trick: shift extension bits into lowest bits of byte */ + /* Note: non-ModR/M tables have a shift value of 0 */ + op >>= table_desc->shift; + + /* ModR/M trick: mask out high bits to turn extension into an index */ + /* Note: non-ModR/M tables have a mask value of 0xFF */ + op &= table_desc->mask; + + + /* Sparse table trick: check that byte is <= max value */ + /* Note: full (256-entry) tables have a maxlim of 155 */ + if ( op > table_desc->maxlim ) { + /* this is a partial table, truncated at the tail, + and op is out of range! */ + return INVALID_INSN; + } + + /* Sparse table trick: check that byte is >= min value */ + /* Note: full (256-entry) tables have a minlim of 0 */ + if ( table_desc->minlim > op ) { + /* this is a partial table, truncated at the head, + and op is out of range! */ + return INVALID_INSN; + } + /* adjust op to be an offset from table index 0 */ + op -= table_desc->minlim; + + /* Yay! 'op' is now fully adjusted to be an index into 'table' */ + *raw_insn = &(table_desc->table[op]); + //printf("BYTE %X TABLE %d OP %X\n", buf[0], table, op ); + + if ( (*raw_insn)->mnem_flag & INS_FLAG_PREFIX ) { + prefix = (*raw_insn)->mnem_flag & PREFIX_MASK; + } + + + /* handle escape to a multibyte/coproc/extension/etc table */ + /* NOTE: if insn is a prefix and has a subtable, then we + * only recurse if this is the first prefix byte -- + * that is, if *prefixes is 0. + * NOTE also that suffix tables are handled later */ + subtable = (*raw_insn)->table; + + if ( subtable && ia32_tables[subtable].type != tbl_suffix && + (! prefix || ! *prefixes) ) { + + if ( ia32_tables[subtable].type == tbl_ext_ext || + ia32_tables[subtable].type == tbl_fpu_ext ) { + /* opcode extension: reuse current byte in buffer */ + next = buf; + next_len = buf_len; + } else { + /* "normal" opcode: advance to next byte in buffer */ + if ( buf_len > 1 ) { + next = &buf[1]; + next_len = buf_len - 1; + } + else { + // buffer is truncated + return INVALID_INSN; + } + } + /* we encountered a multibyte opcode: recurse using the + * table specified in the opcode definition */ + sub_size = ia32_table_lookup( next, next_len, subtable, + raw_insn, prefixes ); + + /* SSE/prefix hack: if the original opcode def was a + * prefix that specified a subtable, and the subtable + * lookup returned a valid insn, then we have encountered + * an SSE opcode definition; otherwise, we pretend we + * never did the subtable lookup, and deal with the + * prefix normally later */ + if ( prefix && ( sub_size == INVALID_INSN || + INS_TYPE((*raw_insn)->mnem_flag) == INS_INVALID ) ) { + /* this is a prefix, not an SSE insn : + * lookup next byte in main table, + * subsize will be reset during the + * main table lookup */ + recurse_table = 1; + } else { + /* this is either a subtable (two-byte) insn + * or an invalid insn: either way, set prefix + * to NULL and end the opcode lookup */ + prefix = 0; + // short-circuit lookup on invalid insn + if (sub_size == INVALID_INSN) return INVALID_INSN; + } + } else if ( prefix ) { + recurse_table = 1; + } + + /* by default, we assume that we have the opcode definition, + * and there is no need to recurse on the same table, but + * if we do then a prefix was encountered... */ + if ( recurse_table ) { + /* this must have been a prefix: use the same table for + * lookup of the next byte */ + sub_size = ia32_table_lookup( &buf[1], buf_len - 1, table, + raw_insn, prefixes ); + + // short-circuit lookup on invalid insn + if (sub_size == INVALID_INSN) return INVALID_INSN; + + /* a bit of a hack for branch hints */ + if ( prefix & BRANCH_HINT_MASK ) { + if ( INS_GROUP((*raw_insn)->mnem_flag) == INS_EXEC ) { + /* segment override prefixes are invalid for + * all branch instructions, so delete them */ + prefix &= ~PREFIX_REG_MASK; + } else { + prefix &= ~BRANCH_HINT_MASK; + } + } + + /* apply prefix to instruction */ + + /* TODO: implement something enforcing prefix groups */ + (*prefixes) |= prefix; + } + + /* if this lookup was in a ModR/M table, then an opcode byte is + * NOT consumed: subtract accordingly. NOTE that if none of the + * operands used the ModR/M, then we need to consume the byte + * here, but ONLY in the 'top-level' opcode extension table */ + + if ( table_desc->type == tbl_ext_ext ) { + /* extensions-to-extensions never consume a byte */ + --size; + } else if ( (table_desc->type == tbl_extension || + table_desc->type == tbl_fpu || + table_desc->type == tbl_fpu_ext ) && + /* extensions that have an operand encoded in ModR/M + * never consume a byte */ + (uses_modrm_flag((*raw_insn)->dest_flag) || + uses_modrm_flag((*raw_insn)->src_flag) ) ) { + --size; + } + + size += sub_size; + + return size; +} + +static size_t handle_insn_suffix( unsigned char *buf, size_t buf_len, + ia32_insn_t *raw_insn, x86_insn_t * insn ) { + ia32_insn_t *sfx_insn; + size_t size; + unsigned int prefixes = 0; + + size = ia32_table_lookup( buf, buf_len, raw_insn->table, &sfx_insn, + &prefixes ); + if (size == INVALID_INSN || sfx_insn->mnem_flag == INS_INVALID ) { + return 0; + } + + strncpy( insn->mnemonic, sfx_insn->mnemonic, 16 ); + handle_insn_metadata( insn, sfx_insn ); + + return 1; +} + +/* invalid instructions are handled by returning 0 [error] from the + * function, setting the size of the insn to 1 byte, and copying + * the byte at the start of the invalid insn into the x86_insn_t. + * if the caller is saving the x86_insn_t for invalid instructions, + * instead of discarding them, this will maintain a consistent + * address space in the x86_insn_ts */ + +/* this function is called by the controlling disassembler, so its name and + * calling convention cannot be changed */ +/* buf points to the loc of the current opcode (start of the + * instruction) in the instruction stream. The instruction + * stream is assumed to be a buffer of bytes read directly + * from the file for the purpose of disassembly; a mem-mapped + * file is ideal for * this. + * insn points to a code structure to be filled by instr_decode + * returns the size of the decoded instruction in bytes */ +size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len, + x86_insn_t *insn ) { + ia32_insn_t *raw_insn = NULL; + unsigned int prefixes = 0; + size_t size, sfx_size; + + if ( (ia32_settings.options & opt_ignore_nulls) && buf_len > 3 && + !buf[0] && !buf[1] && !buf[2] && !buf[3]) { + /* IF IGNORE_NULLS is set AND + * first 4 bytes in the intruction stream are NULL + * THEN return 0 (END_OF_DISASSEMBLY) */ + /* TODO: set errno */ + MAKE_INVALID( insn, buf ); + return 0; /* 4 00 bytes in a row? This isn't code! */ + } + + /* Perform recursive table lookup starting with main table (0) */ + size = ia32_table_lookup(buf, buf_len, idx_Main, &raw_insn, &prefixes); + if ( size == INVALID_INSN || size > buf_len || raw_insn->mnem_flag == INS_INVALID ) { + MAKE_INVALID( insn, buf ); + /* TODO: set errno */ + return 0; + } + + /* We now have the opcode itself figured out: we can decode + * the rest of the instruction. */ + size += ia32_decode_insn( &buf[size], buf_len - size, raw_insn, insn, + prefixes ); + if ( raw_insn->mnem_flag & INS_FLAG_SUFFIX ) { + /* AMD 3DNow! suffix -- get proper operand type here */ + sfx_size = handle_insn_suffix( &buf[size], buf_len - size, + raw_insn, insn ); + if (! sfx_size ) { + /* TODO: set errno */ + MAKE_INVALID( insn, buf ); + return 0; + } + + size += sfx_size; + } + + if (! size ) { + /* invalid insn */ + MAKE_INVALID( insn, buf ); + return 0; + } + + + insn->size = size; + return size; /* return size of instruction in bytes */ +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.h new file mode 100644 index 0000000000..d3f36c3b20 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_insn.h @@ -0,0 +1,506 @@ +#ifndef IA32_INSN_H +#define IA32_INSN_H +/* this file contains the structure of opcode definitions and the + * constants they use */ + +#include +#include "libdis.h" + + +#define GET_BYTE( buf, buf_len ) buf_len ? *buf : 0 + +#define OP_SIZE_16 1 +#define OP_SIZE_32 2 +#define ADDR_SIZE_16 4 +#define ADDR_SIZE_32 8 + +#define MAX_INSTRUCTION_SIZE 20 + +/* invalid instructions are handled by returning 0 [error] from the + * function, setting the size of the insn to 1 byte, and copying + * the byte at the start of the invalid insn into the x86_insn_t. + * if the caller is saving the x86_insn_t for invalid instructions, + * instead of discarding them, this will maintain a consistent + * address space in the x86_insn_ts */ + +#define INVALID_INSN ((size_t) -1) /* return value for invalid insn */ +#define MAKE_INVALID( i, buf ) \ + strcpy( i->mnemonic, "invalid" ); \ + x86_oplist_free( i ); \ + i->size = 1; \ + i->group = insn_none; \ + i->type = insn_invalid; \ + memcpy( i->bytes, buf, 1 ); + + +size_t ia32_disasm_addr( unsigned char * buf, size_t buf_len, + x86_insn_t *insn); + + +/* --------------------------------------------------------- Table Lookup */ +/* IA32 Instruction defintion for ia32_opcodes.c */ +typedef struct { + unsigned int table; /* escape to this sub-table */ + unsigned int mnem_flag; /* Flags referring to mnemonic */ + unsigned int notes; /* Notes for this instruction */ + unsigned int dest_flag, src_flag, aux_flag; /* and for specific operands */ + unsigned int cpu; /* minimumCPU [AND with clocks?? */ + char mnemonic[16]; /* buffers for building instruction */ + char mnemonic_att[16]; /* at&t style mnemonic name */ + int32_t dest; + int32_t src; + int32_t aux; + unsigned int flags_effected; + unsigned int implicit_ops; /* implicit operands */ +} ia32_insn_t; + + + +/* --------------------------------------------------------- Prefixes */ +/* Prefix Flags */ +/* Prefixes, same order as in the manual */ +/* had to reverse the values of the first three as they were entered into + * libdis.h incorrectly. */ +#define PREFIX_LOCK 0x0004 +#define PREFIX_REPNZ 0x0002 +#define PREFIX_REPZ 0x0001 +#define PREFIX_OP_SIZE 0x0010 +#define PREFIX_ADDR_SIZE 0x0020 +#define PREFIX_CS 0x0100 +#define PREFIX_SS 0x0200 +#define PREFIX_DS 0x0300 +#define PREFIX_ES 0x0400 +#define PREFIX_FS 0x0500 +#define PREFIX_GS 0x0600 +#define PREFIX_TAKEN 0x1000 /* branch taken */ +#define PREFIX_NOTTAKEN 0x2000 /* branch not taken */ +#define PREFIX_REG_MASK 0x0F00 +#define BRANCH_HINT_MASK 0x3000 +#define PREFIX_PRINT_MASK 0x000F /* printable prefixes */ +#define PREFIX_MASK 0xFFFF + +/* ---------------------------------------------------------- CPU Type */ + +#define cpu_8086 0x0001 +#define cpu_80286 0x0002 +#define cpu_80386 0x0003 +#define cpu_80387 0x0004 /* originally these were a co-proc */ +#define cpu_80486 0x0005 +#define cpu_PENTIUM 0x0006 +#define cpu_PENTPRO 0x0007 +#define cpu_PENTIUM2 0x0008 +#define cpu_PENTIUM3 0x0009 +#define cpu_PENTIUM4 0x000A +#define cpu_K6 0x0010 +#define cpu_K7 0x0020 +#define cpu_ATHLON 0x0030 +#define CPU_MODEL_MASK 0xFFFF +#define CPU_MODEL(cpu) (cpu & CPU_MODEL_MASK) +/* intel instruction subsets */ +#define isa_GP 0x10000 /* General Purpose Instructions */ +#define isa_FPU 0x20000 /* FPU instructions */ +#define isa_FPUMGT 0x30000 /* FPU/SIMD Management */ +#define isa_MMX 0x40000 /* MMX */ +#define isa_SSE1 0x50000 /* SSE */ +#define isa_SSE2 0x60000 /* SSE 2 */ +#define isa_SSE3 0x70000 /* SSE 3 */ +#define isa_3DNOW 0x80000 /* AMD 3d Now */ +#define isa_SYS 0x90000 /* System Instructions */ +#define ISA_SUBSET_MASK 0xFFFF0000 +#define ISA_SUBSET(isa) (isa & ISA_SUBSET_MASK) + + +/* ------------------------------------------------------ Operand Decoding */ +#define ARG_NONE 0 + +/* Using a mask allows us to store info such as OP_SIGNED in the + * operand flags field */ +#define OPFLAGS_MASK 0x0000FFFF + +/* Operand Addressing Methods, per intel manual */ +#define ADDRMETH_MASK 0x00FF0000 + +/* note: for instructions with implied operands, use no ADDRMETH */ +#define ADDRMETH_A 0x00010000 +#define ADDRMETH_C 0x00020000 +#define ADDRMETH_D 0x00030000 +#define ADDRMETH_E 0x00040000 +#define ADDRMETH_F 0x00050000 +#define ADDRMETH_G 0x00060000 +#define ADDRMETH_I 0x00070000 +#define ADDRMETH_J 0x00080000 +#define ADDRMETH_M 0x00090000 +#define ADDRMETH_O 0x000A0000 +#define ADDRMETH_P 0x000B0000 +#define ADDRMETH_Q 0x000C0000 +#define ADDRMETH_R 0x000D0000 +#define ADDRMETH_S 0x000E0000 +#define ADDRMETH_T 0x000F0000 +#define ADDRMETH_V 0x00100000 +#define ADDRMETH_W 0x00110000 +#define ADDRMETH_X 0x00120000 +#define ADDRMETH_Y 0x00130000 +#define ADDRMETH_RR 0x00140000 /* gen reg hard-coded in opcode */ +#define ADDRMETH_RS 0x00150000 /* seg reg hard-coded in opcode */ +#define ADDRMETH_RT 0x00160000 /* test reg hard-coded in opcode */ +#define ADDRMETH_RF 0x00170000 /* fpu reg hard-coded in opcode */ +#define ADDRMETH_II 0x00180000 /* immediate hard-coded in opcode */ +#define ADDRMETH_PP 0x00190000 /* mm reg ONLY in modr/m field */ +#define ADDRMETH_VV 0x001A0000 /* xmm reg ONLY in mod/rm field */ + +/* Operand Types, per intel manual */ +#define OPTYPE_MASK 0xFF000000 + +#define OPTYPE_a 0x01000000 /* BOUND: h:h or w:w */ +#define OPTYPE_b 0x02000000 /* byte */ +#define OPTYPE_c 0x03000000 /* byte or word */ +#define OPTYPE_d 0x04000000 /* word */ +#define OPTYPE_dq 0x05000000 /* qword */ +#define OPTYPE_p 0x06000000 /* 16:16 or 16:32 pointer */ +#define OPTYPE_pi 0x07000000 /* dword MMX reg */ +#define OPTYPE_ps 0x08000000 /* 128-bit single fp */ +#define OPTYPE_q 0x09000000 /* dword */ +#define OPTYPE_s 0x0A000000 /* 6-byte descriptor */ +#define OPTYPE_ss 0x0B000000 /* scalar of 128-bit single fp */ +#define OPTYPE_si 0x0C000000 /* word general register */ +#define OPTYPE_v 0x0D000000 /* hword or word */ +#define OPTYPE_w 0x0E000000 /* hword */ +#define OPTYPE_m 0x0F000000 /* to handle LEA */ +#define OPTYPE_none 0xFF000000 /* no valid operand size, INVLPG */ + +/* custom ones for FPU instructions */ +#define OPTYPE_fs 0x10000000 /* pointer to single-real*/ +#define OPTYPE_fd 0x20000000 /* pointer to double real */ +#define OPTYPE_fe 0x30000000 /* pointer to extended real */ +#define OPTYPE_fb 0x40000000 /* pointer to packed BCD */ +#define OPTYPE_fv 0x50000000 /* pointer to FPU env: 14|28-bytes */ +#define OPTYPE_ft 0x60000000 /* pointer to FPU state: 94|108-bytes */ +#define OPTYPE_fx 0x70000000 /* pointer to FPU regs: 512 bites */ +#define OPTYPE_fp 0x80000000 /* general fpu register: dbl ext */ + +/* SSE2 operand types */ +#define OPTYPE_sd 0x90000000 /* scalar of 128-bit double fp */ +#define OPTYPE_pd 0xA0000000 /* 128-bit double fp */ + + + +/* ---------------------------------------------- Opcode Table Descriptions */ +/* the table type describes how to handle byte/size increments before + * and after lookup. Some tables re-use the current byte, others + * consume a byte only if the ModR/M encodes no operands, etc */ +enum ia32_tbl_type_id { + tbl_opcode = 0, /* standard opcode table: no surprises */ + tbl_prefix, /* Prefix Override, e.g. 66/F2/F3 */ + tbl_suffix, /* 3D Now style */ + tbl_extension, /* ModR/M extension: 00-FF -> 00-07 */ + tbl_ext_ext, /* extension of modr/m using R/M field */ + tbl_fpu, /* fpu table: 00-BF -> 00-0F */ + tbl_fpu_ext /* fpu extension : C0-FF -> 00-1F */ + }; + +/* How it works: + * Bytes are 'consumed' if the next table lookup requires that the byte + * pointer be advanced in the instruction stream. 'Does not consume' means + * that, when the lookup function recurses, the same byte it re-used in the + * new table. It also means that size is not decremented, for example when + * a ModR/M byte is used. Note that tbl_extension (ModR/M) instructions that + * do not increase the size of an insn with their operands have a forced + 3 size increase in the lookup algo. Weird, yes, confusing, yes, welcome + * to the Intel ISA. Another note: tbl_prefix is used as an override, so an + * empty insn in a prefix table causes the instruction in the original table + * to be used, rather than an invalid insn being generated. + * tbl_opcode uses current byte and consumes it + * tbl_prefix uses current byte but does not consume it + * tbl_suffix uses and consumes last byte in insn + * tbl_extension uses current byte but does not consume it + * tbl_ext_ext uses current byte but does not consume it + * tbl_fpu uses current byte and consumes it + * tbl_fpu_ext uses current byte but does not consume it + */ + +/* Convenience struct for opcode tables : these will be stored in a + * 'table of tables' so we can use a table index instead of a pointer */ +typedef struct { /* Assembly instruction tables */ + ia32_insn_t *table; /* Pointer to table of instruction encodings */ + enum ia32_tbl_type_id type; + unsigned char shift; /* amount to shift modrm byte */ + unsigned char mask; /* bit mask for look up */ + unsigned char minlim,maxlim; /* limits on min/max entries. */ +} ia32_table_desc_t; + + +/* ---------------------------------------------- 'Cooked' Operand Type Info */ +/* Permissions: */ +#define OP_R 0x001 /* operand is READ */ +#define OP_W 0x002 /* operand is WRITTEN */ +#define OP_RW 0x003 /* (OP_R|OP_W): convenience macro */ +#define OP_X 0x004 /* operand is EXECUTED */ + +#define OP_PERM_MASK 0x0000007 /* perms are NOT mutually exclusive */ +#define OP_PERM( type ) (type & OP_PERM_MASK) + +/* Flags */ +#define OP_SIGNED 0x010 /* operand is signed */ + +#define OP_FLAG_MASK 0x0F0 /* mods are NOT mutually exclusive */ +#define OP_FLAGS( type ) (type & OP_FLAG_MASK) + +#define OP_REG_MASK 0x0000FFFF /* lower WORD is register ID */ +#define OP_REGTBL_MASK 0xFFFF0000 /* higher word is register type [gen/dbg] */ +#define OP_REGID( type ) (type & OP_REG_MASK) +#define OP_REGTYPE( type ) (type & OP_REGTBL_MASK) + +/* ------------------------------------------'Cooked' Instruction Type Info */ +/* high-bit opcode types/insn meta-types */ +#define INS_FLAG_PREFIX 0x10000000 /* insn is a prefix */ +#define INS_FLAG_SUFFIX 0x20000000 /* followed by a suffix byte */ +#define INS_FLAG_MASK 0xFF000000 + +/* insn notes */ +#define INS_NOTE_RING0 0x00000001 /* insn is privileged */ +#define INS_NOTE_SMM 0x00000002 /* Sys Mgt Mode only */ +#define INS_NOTE_SERIAL 0x00000004 /* serializes */ +#define INS_NOTE_NONSWAP 0x00000008 /* insn is not swapped in att format */ // could be separate field? +#define INS_NOTE_NOSUFFIX 0x00000010 /* insn has no size suffix in att format */ // could be separate field? +//#define INS_NOTE_NMI + +#define INS_INVALID 0 + +/* instruction groups */ +#define INS_EXEC 0x1000 +#define INS_ARITH 0x2000 +#define INS_LOGIC 0x3000 +#define INS_STACK 0x4000 +#define INS_COND 0x5000 +#define INS_LOAD 0x6000 +#define INS_ARRAY 0x7000 +#define INS_BIT 0x8000 +#define INS_FLAG 0x9000 +#define INS_FPU 0xA000 +#define INS_TRAPS 0xD000 +#define INS_SYSTEM 0xE000 +#define INS_OTHER 0xF000 + +#define INS_GROUP_MASK 0xF000 +#define INS_GROUP( type ) ( type & INS_GROUP_MASK ) + +/* INS_EXEC group */ +#define INS_BRANCH (INS_EXEC | 0x01) /* Unconditional branch */ +#define INS_BRANCHCC (INS_EXEC | 0x02) /* Conditional branch */ +#define INS_CALL (INS_EXEC | 0x03) /* Jump to subroutine */ +#define INS_CALLCC (INS_EXEC | 0x04) /* Jump to subroutine */ +#define INS_RET (INS_EXEC | 0x05) /* Return from subroutine */ + +/* INS_ARITH group */ +#define INS_ADD (INS_ARITH | 0x01) +#define INS_SUB (INS_ARITH | 0x02) +#define INS_MUL (INS_ARITH | 0x03) +#define INS_DIV (INS_ARITH | 0x04) +#define INS_INC (INS_ARITH | 0x05) /* increment */ +#define INS_DEC (INS_ARITH | 0x06) /* decrement */ +#define INS_SHL (INS_ARITH | 0x07) /* shift right */ +#define INS_SHR (INS_ARITH | 0x08) /* shift left */ +#define INS_ROL (INS_ARITH | 0x09) /* rotate left */ +#define INS_ROR (INS_ARITH | 0x0A) /* rotate right */ +#define INS_MIN (INS_ARITH | 0x0B) /* min func */ +#define INS_MAX (INS_ARITH | 0x0C) /* max func */ +#define INS_AVG (INS_ARITH | 0x0D) /* avg func */ +#define INS_FLR (INS_ARITH | 0x0E) /* floor func */ +#define INS_CEIL (INS_ARITH | 0x0F) /* ceiling func */ + +/* INS_LOGIC group */ +#define INS_AND (INS_LOGIC | 0x01) +#define INS_OR (INS_LOGIC | 0x02) +#define INS_XOR (INS_LOGIC | 0x03) +#define INS_NOT (INS_LOGIC | 0x04) +#define INS_NEG (INS_LOGIC | 0x05) +#define INS_NAND (INS_LOGIC | 0x06) + +/* INS_STACK group */ +#define INS_PUSH (INS_STACK | 0x01) +#define INS_POP (INS_STACK | 0x02) +#define INS_PUSHREGS (INS_STACK | 0x03) /* push register context */ +#define INS_POPREGS (INS_STACK | 0x04) /* pop register context */ +#define INS_PUSHFLAGS (INS_STACK | 0x05) /* push all flags */ +#define INS_POPFLAGS (INS_STACK | 0x06) /* pop all flags */ +#define INS_ENTER (INS_STACK | 0x07) /* enter stack frame */ +#define INS_LEAVE (INS_STACK | 0x08) /* leave stack frame */ + +/* INS_COND group */ +#define INS_TEST (INS_COND | 0x01) +#define INS_CMP (INS_COND | 0x02) + +/* INS_LOAD group */ +#define INS_MOV (INS_LOAD | 0x01) +#define INS_MOVCC (INS_LOAD | 0x02) +#define INS_XCHG (INS_LOAD | 0x03) +#define INS_XCHGCC (INS_LOAD | 0x04) +#define INS_CONV (INS_LOAD | 0x05) /* move and convert type */ + +/* INS_ARRAY group */ +#define INS_STRCMP (INS_ARRAY | 0x01) +#define INS_STRLOAD (INS_ARRAY | 0x02) +#define INS_STRMOV (INS_ARRAY | 0x03) +#define INS_STRSTOR (INS_ARRAY | 0x04) +#define INS_XLAT (INS_ARRAY | 0x05) + +/* INS_BIT group */ +#define INS_BITTEST (INS_BIT | 0x01) +#define INS_BITSET (INS_BIT | 0x02) +#define INS_BITCLR (INS_BIT | 0x03) + +/* INS_FLAG group */ +#define INS_CLEARCF (INS_FLAG | 0x01) /* clear Carry flag */ +#define INS_CLEARZF (INS_FLAG | 0x02) /* clear Zero flag */ +#define INS_CLEAROF (INS_FLAG | 0x03) /* clear Overflow flag */ +#define INS_CLEARDF (INS_FLAG | 0x04) /* clear Direction flag */ +#define INS_CLEARSF (INS_FLAG | 0x05) /* clear Sign flag */ +#define INS_CLEARPF (INS_FLAG | 0x06) /* clear Parity flag */ +#define INS_SETCF (INS_FLAG | 0x07) +#define INS_SETZF (INS_FLAG | 0x08) +#define INS_SETOF (INS_FLAG | 0x09) +#define INS_SETDF (INS_FLAG | 0x0A) +#define INS_SETSF (INS_FLAG | 0x0B) +#define INS_SETPF (INS_FLAG | 0x0C) +#define INS_TOGCF (INS_FLAG | 0x10) /* toggle */ +#define INS_TOGZF (INS_FLAG | 0x20) +#define INS_TOGOF (INS_FLAG | 0x30) +#define INS_TOGDF (INS_FLAG | 0x40) +#define INS_TOGSF (INS_FLAG | 0x50) +#define INS_TOGPF (INS_FLAG | 0x60) + +/* INS_FPU */ +#define INS_FMOV (INS_FPU | 0x1) +#define INS_FMOVCC (INS_FPU | 0x2) +#define INS_FNEG (INS_FPU | 0x3) +#define INS_FABS (INS_FPU | 0x4) +#define INS_FADD (INS_FPU | 0x5) +#define INS_FSUB (INS_FPU | 0x6) +#define INS_FMUL (INS_FPU | 0x7) +#define INS_FDIV (INS_FPU | 0x8) +#define INS_FSQRT (INS_FPU | 0x9) +#define INS_FCMP (INS_FPU | 0xA) +#define INS_FCOS (INS_FPU | 0xC) /* cosine */ +#define INS_FLDPI (INS_FPU | 0xD) /* load pi */ +#define INS_FLDZ (INS_FPU | 0xE) /* load 0 */ +#define INS_FTAN (INS_FPU | 0xF) /* tanget */ +#define INS_FSINE (INS_FPU | 0x10) /* sine */ +#define INS_FSYS (INS_FPU | 0x20) /* misc */ + +/* INS_TRAP */ +#define INS_TRAP (INS_TRAPS | 0x01) /* generate trap */ +#define INS_TRAPCC (INS_TRAPS | 0x02) /* conditional trap gen */ +#define INS_TRET (INS_TRAPS | 0x03) /* return from trap */ +#define INS_BOUNDS (INS_TRAPS | 0x04) /* gen bounds trap */ +#define INS_DEBUG (INS_TRAPS | 0x05) /* gen breakpoint trap */ +#define INS_TRACE (INS_TRAPS | 0x06) /* gen single step trap */ +#define INS_INVALIDOP (INS_TRAPS | 0x07) /* gen invalid insn */ +#define INS_OFLOW (INS_TRAPS | 0x08) /* gen overflow trap */ +#define INS_ICEBP (INS_TRAPS | 0x09) /* ICE breakpoint */ + +/* INS_SYSTEM */ +#define INS_HALT (INS_SYSTEM | 0x01) /* halt machine */ +#define INS_IN (INS_SYSTEM | 0x02) /* input form port */ +#define INS_OUT (INS_SYSTEM | 0x03) /* output to port */ +#define INS_CPUID (INS_SYSTEM | 0x04) /* identify cpu */ + +/* INS_OTHER */ +#define INS_NOP (INS_OTHER | 0x01) +#define INS_BCDCONV (INS_OTHER | 0x02) /* convert to/from BCD */ +#define INS_SZCONV (INS_OTHER | 0x03) /* convert size of operand */ +#define INS_SALC (INS_OTHER | 0x04) /* set %al on carry */ +#define INS_UNKNOWN (INS_OTHER | 0x05) + + +#define INS_TYPE_MASK 0xFFFF +#define INS_TYPE( type ) ( type & INS_TYPE_MASK ) + + /* flags effected by instruction */ +#define INS_TEST_CARRY 0x01 /* carry */ +#define INS_TEST_ZERO 0x02 /* zero/equal */ +#define INS_TEST_OFLOW 0x04 /* overflow */ +#define INS_TEST_DIR 0x08 /* direction */ +#define INS_TEST_SIGN 0x10 /* negative */ +#define INS_TEST_PARITY 0x20 /* parity */ +#define INS_TEST_OR 0x40 /* used in jle */ +#define INS_TEST_NCARRY 0x100 /* ! carry */ +#define INS_TEST_NZERO 0x200 /* ! zero */ +#define INS_TEST_NOFLOW 0x400 /* ! oflow */ +#define INS_TEST_NDIR 0x800 /* ! dir */ +#define INS_TEST_NSIGN 0x100 /* ! sign */ +#define INS_TEST_NPARITY 0x2000 /* ! parity */ +/* SF == OF */ +#define INS_TEST_SFEQOF 0x4000 +/* SF != OF */ +#define INS_TEST_SFNEOF 0x8000 + +#define INS_TEST_ALL INS_TEST_CARRY | INS_TEST_ZERO | \ + INS_TEST_OFLOW | INS_TEST_SIGN | \ + INS_TEST_PARITY + +#define INS_SET_CARRY 0x010000 /* carry */ +#define INS_SET_ZERO 0x020000 /* zero/equal */ +#define INS_SET_OFLOW 0x040000 /* overflow */ +#define INS_SET_DIR 0x080000 /* direction */ +#define INS_SET_SIGN 0x100000 /* negative */ +#define INS_SET_PARITY 0x200000 /* parity */ +#define INS_SET_NCARRY 0x1000000 +#define INS_SET_NZERO 0x2000000 +#define INS_SET_NOFLOW 0x4000000 +#define INS_SET_NDIR 0x8000000 +#define INS_SET_NSIGN 0x10000000 +#define INS_SET_NPARITY 0x20000000 +#define INS_SET_SFEQOF 0x40000000 +#define INS_SET_SFNEOF 0x80000000 + +#define INS_SET_ALL INS_SET_CARRY | INS_SET_ZERO | \ + INS_SET_OFLOW | INS_SET_SIGN | \ + INS_SET_PARITY + +#define INS_TEST_MASK 0x0000FFFF +#define INS_FLAGS_TEST(x) (x & INS_TEST_MASK) +#define INS_SET_MASK 0xFFFF0000 +#define INS_FLAGS_SET(x) (x & INS_SET_MASK) + +#if 0 +/* TODO: actually start using these */ +#define X86_PAIR_NP 1 /* not pairable; execs in U */ +#define X86_PAIR_PU 2 /* pairable in U pipe */ +#define X86_PAIR_PV 3 /* pairable in V pipe */ +#define X86_PAIR_UV 4 /* pairable in UV pipe */ +#define X86_PAIR_FX 5 /* pairable with FXCH */ + +#define X86_EXEC_PORT_0 1 +#define X86_EXEC_PORT_1 2 +#define X86_EXEC_PORT_2 4 +#define X86_EXEC_PORT_3 8 +#define X86_EXEC_PORT_4 16 + +#define X86_EXEC_UNITS + +typedef struct { /* representation of an insn during decoding */ + uint32_t flags; /* runtime settings */ + /* instruction prefixes and other foolishness */ + uint32_t prefix; /* encoding of prefix */ + char prefix_str[16]; /* mnemonics for prefix */ + uint32_t branch_hint; /* gah! */ + unsigned int cpu_ver; /* TODO: cpu version */ + unsigned int clocks; /* TODO: clock cycles: min/max */ + unsigned char last_prefix; + /* runtime intruction decoding helpers */ + unsigned char mode; /* 16, 32, 64 */ + unsigned char gen_regs; /* offset of default general reg set */ + unsigned char sz_operand; /* operand size for insn */ + unsigned char sz_address; /* address size for insn */ + unsigned char uops; /* uops per insn */ + unsigned char pairing; /* np,pu,pv.lv */ + unsigned char exec_unit; + unsigned char exec_port; + unsigned char latency; +} ia32_info_t; +#define MODE_32 0 /* default */ +#define MODE_16 1 +#define MODE_64 2 +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c new file mode 100644 index 0000000000..68ec153d27 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.c @@ -0,0 +1,313 @@ +#include +#include + +#include "ia32_invariant.h" +#include "ia32_insn.h" +#include "ia32_settings.h" + +extern ia32_table_desc_t *ia32_tables; +extern ia32_settings_t ia32_settings; + +extern size_t ia32_table_lookup( unsigned char *buf, size_t buf_len, + unsigned int table, ia32_insn_t **raw_insn, + unsigned int *prefixes ); + + +/* -------------------------------- ModR/M, SIB */ +/* Convenience flags */ +#define MODRM_EA 1 /* ModR/M is an effective addr */ +#define MODRM_reg 2 /* ModR/M is a register */ + +/* ModR/M flags */ +#define MODRM_RM_SIB 0x04 /* R/M == 100 */ +#define MODRM_RM_NOREG 0x05 /* R/B == 101 */ +/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */ +#define MODRM_MOD_NODISP 0x00 /* mod == 00 */ +#define MODRM_MOD_DISP8 0x01 /* mod == 01 */ +#define MODRM_MOD_DISP32 0x02 /* mod == 10 */ +#define MODRM_MOD_NOEA 0x03 /* mod == 11 */ +/* 16-bit modrm flags */ +#define MOD16_MOD_NODISP 0 +#define MOD16_MOD_DISP8 1 +#define MOD16_MOD_DISP16 2 +#define MOD16_MOD_REG 3 + +#define MOD16_RM_BXSI 0 +#define MOD16_RM_BXDI 1 +#define MOD16_RM_BPSI 2 +#define MOD16_RM_BPDI 3 +#define MOD16_RM_SI 4 +#define MOD16_RM_DI 5 +#define MOD16_RM_BP 6 +#define MOD16_RM_BX 7 + +/* SIB flags */ +#define SIB_INDEX_NONE 0x04 +#define SIB_BASE_EBP 0x05 +#define SIB_SCALE_NOBASE 0x00 + +/* Convenience struct for modR/M bitfield */ +struct modRM_byte { + unsigned int mod : 2; + unsigned int reg : 3; + unsigned int rm : 3; +}; + +/* Convenience struct for SIB bitfield */ +struct SIB_byte { + unsigned int scale : 2; + unsigned int index : 3; + unsigned int base : 3; +}; + +#ifdef WIN32 +static void byte_decode(unsigned char b, struct modRM_byte *modrm) { +#else +static inline void byte_decode(unsigned char b, struct modRM_byte *modrm) { +#endif + /* generic bitfield-packing routine */ + + modrm->mod = b >> 6; /* top 2 bits */ + modrm->reg = (b & 56) >> 3; /* middle 3 bits */ + modrm->rm = b & 7; /* bottom 3 bits */ +} +static int ia32_invariant_modrm( unsigned char *in, unsigned char *out, + unsigned int mode_16, x86_invariant_op_t *op) { + struct modRM_byte modrm; + struct SIB_byte sib; + unsigned char *c, *cin; + unsigned short *s; + unsigned int *i; + int size = 0; /* modrm byte is already counted */ + + + byte_decode(*in, &modrm); /* get bitfields */ + + out[0] = in[0]; /* save modrm byte */ + cin = &in[1]; + c = &out[1]; + s = (unsigned short *)&out[1]; + i = (unsigned int *)&out[1]; + + op->type = op_expression; + op->flags |= op_pointer; + if ( ! mode_16 && modrm.rm == MODRM_RM_SIB && + modrm.mod != MODRM_MOD_NOEA ) { + size ++; + byte_decode(*cin, (struct modRM_byte *)(void*)&sib); + + out[1] = in[1]; /* save sib byte */ + cin = &in[2]; + c = &out[2]; + s = (unsigned short *)&out[2]; + i = (unsigned int *)&out[2]; + + if ( sib.base == SIB_BASE_EBP && ! modrm.mod ) { + /* disp 32 is variant! */ + memset( i, X86_WILDCARD_BYTE, 4 ); + size += 4; + } + } + + if (! modrm.mod && modrm.rm == 101) { + if ( mode_16 ) { /* straight RVA in disp */ + memset( s, X86_WILDCARD_BYTE, 2 ); + size += 2; + } else { + memset( i, X86_WILDCARD_BYTE, 2 ); + size += 4; + } + } else if (modrm.mod && modrm.mod < 3) { + if (modrm.mod == MODRM_MOD_DISP8) { /* offset in disp */ + *c = *cin; + size += 1; + } else if ( mode_16 ) { + *s = (* ((unsigned short *) cin)); + size += 2; + } else { + *i = (*((unsigned int *) cin)); + size += 4; + } + } else if ( modrm.mod == 3 ) { + op->type = op_register; + op->flags &= ~op_pointer; + } + + return (size); +} + + +static int ia32_decode_invariant( unsigned char *buf, size_t buf_len, + ia32_insn_t *t, unsigned char *out, + unsigned int prefixes, x86_invariant_t *inv) { + + unsigned int addr_size, op_size, mode_16; + unsigned int op_flags[3] = { t->dest_flag, t->src_flag, t->aux_flag }; + int x, type, bytes = 0, size = 0, modrm = 0; + + /* set addressing mode */ + if (ia32_settings.options & opt_16_bit) { + op_size = ( prefixes & PREFIX_OP_SIZE ) ? 4 : 2; + addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 4 : 2; + mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 0 : 1; + } else { + op_size = ( prefixes & PREFIX_OP_SIZE ) ? 2 : 4; + addr_size = ( prefixes & PREFIX_ADDR_SIZE ) ? 2 : 4; + mode_16 = ( prefixes & PREFIX_ADDR_SIZE ) ? 1 : 0; + } + + for (x = 0; x < 3; x++) { + inv->operands[x].access = (enum x86_op_access) + OP_PERM(op_flags[x]); + inv->operands[x].flags = (enum x86_op_flags) + (OP_FLAGS(op_flags[x]) >> 12); + + switch (op_flags[x] & OPTYPE_MASK) { + case OPTYPE_c: + size = (op_size == 4) ? 2 : 1; + break; + case OPTYPE_a: case OPTYPE_v: + size = (op_size == 4) ? 4 : 2; + break; + case OPTYPE_p: + size = (op_size == 4) ? 6 : 4; + break; + case OPTYPE_b: + size = 1; + break; + case OPTYPE_w: + size = 2; + break; + case OPTYPE_d: case OPTYPE_fs: case OPTYPE_fd: + case OPTYPE_fe: case OPTYPE_fb: case OPTYPE_fv: + case OPTYPE_si: case OPTYPE_fx: + size = 4; + break; + case OPTYPE_s: + size = 6; + break; + case OPTYPE_q: case OPTYPE_pi: + size = 8; + break; + case OPTYPE_dq: case OPTYPE_ps: case OPTYPE_ss: + case OPTYPE_pd: case OPTYPE_sd: + size = 16; + break; + case OPTYPE_m: + size = (addr_size == 4) ? 4 : 2; + break; + default: + break; + } + + type = op_flags[x] & ADDRMETH_MASK; + switch (type) { + case ADDRMETH_E: case ADDRMETH_M: case ADDRMETH_Q: + case ADDRMETH_R: case ADDRMETH_W: + modrm = 1; + bytes += ia32_invariant_modrm( buf, out, + mode_16, &inv->operands[x]); + break; + case ADDRMETH_C: case ADDRMETH_D: case ADDRMETH_G: + case ADDRMETH_P: case ADDRMETH_S: case ADDRMETH_T: + case ADDRMETH_V: + inv->operands[x].type = op_register; + modrm = 1; + break; + case ADDRMETH_A: case ADDRMETH_O: + /* pad with xF4's */ + memset( &out[bytes + modrm], X86_WILDCARD_BYTE, + size ); + bytes += size; + inv->operands[x].type = op_offset; + if ( type == ADDRMETH_O ) { + inv->operands[x].flags |= op_signed | + op_pointer; + } + break; + case ADDRMETH_I: case ADDRMETH_J: + /* grab imm value */ + if ((op_flags[x] & OPTYPE_MASK) == OPTYPE_v) { + /* assume this is an address */ + memset( &out[bytes + modrm], + X86_WILDCARD_BYTE, size ); + } else { + memcpy( &out[bytes + modrm], + &buf[bytes + modrm], size ); + } + + bytes += size; + if ( type == ADDRMETH_J ) { + if ( size == 1 ) { + inv->operands[x].type = + op_relative_near; + } else { + inv->operands[x].type = + op_relative_far; + } + inv->operands[x].flags |= op_signed; + } else { + inv->operands[x].type = op_immediate; + } + break; + case ADDRMETH_F: + inv->operands[x].type = op_register; + break; + case ADDRMETH_X: + inv->operands[x].flags |= op_signed | + op_pointer | op_ds_seg | op_string; + break; + case ADDRMETH_Y: + inv->operands[x].flags |= op_signed | + op_pointer | op_es_seg | op_string; + break; + case ADDRMETH_RR: + inv->operands[x].type = op_register; + break; + case ADDRMETH_II: + inv->operands[x].type = op_immediate; + break; + default: + inv->operands[x].type = op_unused; + break; + } + } + + return (bytes + modrm); +} + +size_t ia32_disasm_invariant( unsigned char * buf, size_t buf_len, + x86_invariant_t *inv ) { + ia32_insn_t *raw_insn = NULL; + unsigned int prefixes; + unsigned int type; + size_t size; + + /* Perform recursive table lookup starting with main table (0) */ + size = ia32_table_lookup( buf, buf_len, 0, &raw_insn, &prefixes ); + if ( size == INVALID_INSN || size > buf_len ) { + /* TODO: set errno */ + return 0; + } + + /* copy opcode bytes to buffer */ + memcpy( inv->bytes, buf, size ); + + /* set mnemonic type and group */ + type = raw_insn->mnem_flag & ~INS_FLAG_MASK; + inv->group = (enum x86_insn_group) (INS_GROUP(type)) >> 12; + inv->type = (enum x86_insn_type) INS_TYPE(type); + + /* handle operands */ + size += ia32_decode_invariant( buf + size, buf_len - size, raw_insn, + &buf[size - 1], prefixes, inv ); + + inv->size = size; + + return size; /* return size of instruction in bytes */ +} + +size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ) { + x86_invariant_t inv = { {0} }; + return( ia32_disasm_invariant( buf, buf_len, &inv ) ); +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.h new file mode 100644 index 0000000000..e1cea60e9d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_invariant.h @@ -0,0 +1,11 @@ +#ifndef IA32_INVARIANT_H +#define IA32_INVARIANT_H + +#include "libdis.h" + +size_t ia32_disasm_invariant( unsigned char *buf, size_t buf_len, + x86_invariant_t *inv); + +size_t ia32_disasm_size( unsigned char *buf, size_t buf_len ); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.c new file mode 100644 index 0000000000..b0fe2ed3d3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.c @@ -0,0 +1,310 @@ +#include "ia32_modrm.h" +#include "ia32_reg.h" +#include "x86_imm.h" + +/* NOTE: when decoding ModR/M and SIB, we have to add 1 to all register + * values obtained from decoding the ModR/M or SIB byte, since they + * are encoded with eAX = 0 and the tables in ia32_reg.c use eAX = 1. + * ADDENDUM: this is only the case when the register value is used + * directly as an index into the register table, not when it is added to + * a genregs offset. */ + +/* -------------------------------- ModR/M, SIB */ +/* ModR/M flags */ +#define MODRM_RM_SIB 0x04 /* R/M == 100 */ +#define MODRM_RM_NOREG 0x05 /* R/B == 101 */ + +/* if (MODRM.MOD_NODISP && MODRM.RM_NOREG) then just disp32 */ +#define MODRM_MOD_NODISP 0x00 /* mod == 00 */ +#define MODRM_MOD_DISP8 0x01 /* mod == 01 */ +#define MODRM_MOD_DISP32 0x02 /* mod == 10 */ +#define MODRM_MOD_NOEA 0x03 /* mod == 11 */ + +/* 16-bit modrm flags */ +#define MOD16_MOD_NODISP 0 +#define MOD16_MOD_DISP8 1 +#define MOD16_MOD_DISP16 2 +#define MOD16_MOD_REG 3 + +#define MOD16_RM_BXSI 0 +#define MOD16_RM_BXDI 1 +#define MOD16_RM_BPSI 2 +#define MOD16_RM_BPDI 3 +#define MOD16_RM_SI 4 +#define MOD16_RM_DI 5 +#define MOD16_RM_BP 6 +#define MOD16_RM_BX 7 + +/* SIB flags */ +#define SIB_INDEX_NONE 0x04 +#define SIB_BASE_EBP 0x05 +#define SIB_SCALE_NOBASE 0x00 + +/* Convenience struct for modR/M bitfield */ +struct modRM_byte { + unsigned int mod : 2; + unsigned int reg : 3; + unsigned int rm : 3; +}; + +/* Convenience struct for SIB bitfield */ +struct SIB_byte { + unsigned int scale : 2; + unsigned int index : 3; + unsigned int base : 3; +}; + + +#if 0 +int modrm_rm[] = {0,1,2,3,MODRM_RM_SIB,MODRM_MOD_DISP32,6,7}; +int modrm_reg[] = {0, 1, 2, 3, 4, 5, 6, 7}; +int modrm_mod[] = {0, MODRM_MOD_DISP8, MODRM_MOD_DISP32, MODRM_MOD_NOEA}; +int sib_scl[] = {0, 2, 4, 8}; +int sib_idx[] = {0, 1, 2, 3, SIB_INDEX_NONE, 5, 6, 7 }; +int sib_bas[] = {0, 1, 2, 3, 4, SIB_SCALE_NOBASE, 6, 7 }; +#endif + +/* this is needed to replace x86_imm_signsized() which does not sign-extend + * to dest */ +static unsigned int imm32_signsized( unsigned char *buf, size_t buf_len, + int32_t *dest, unsigned int size ) { + if ( size > buf_len ) { + return 0; + } + + switch (size) { + case 1: + *dest = *((signed char *) buf); + break; + case 2: + *dest = *((signed short *) buf); + break; + case 4: + default: + *dest = *((signed int *) buf); + break; + } + + return size; +} + + + +static void byte_decode(unsigned char b, struct modRM_byte *modrm) { + /* generic bitfield-packing routine */ + + modrm->mod = b >> 6; /* top 2 bits */ + modrm->reg = (b & 56) >> 3; /* middle 3 bits */ + modrm->rm = b & 7; /* bottom 3 bits */ +} + + +static size_t sib_decode( unsigned char *buf, size_t buf_len, x86_ea_t *ea, + unsigned int mod ) { + /* set Address Expression fields (scale, index, base, disp) + * according to the contents of the SIB byte. + * b points to the SIB byte in the instruction-stream buffer; the + * byte after b[0] is therefore the byte after the SIB + * returns number of bytes 'used', including the SIB byte */ + size_t size = 1; /* start at 1 for SIB byte */ + struct SIB_byte sib; + + if ( buf_len < 1 ) { + return 0; + } + + byte_decode( *buf, (struct modRM_byte *)(void*)&sib ); /* get bit-fields */ + + if ( sib.base == SIB_BASE_EBP && ! mod ) { /* if base == 101 (ebp) */ + /* IF BASE == EBP, deal with exception */ + /* IF (ModR/M did not create a Disp */ + /* ... create a 32-bit Displacement */ + imm32_signsized( &buf[1], buf_len, &ea->disp, sizeof(int32_t)); + ea->disp_size = sizeof(int32_t); + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + size += 4; /* add sizeof disp to count */ + + } else { + /* ELSE BASE refers to a General Register */ + ia32_handle_register( &ea->base, sib.base + 1 ); + } + + /* set scale to 1, 2, 4, 8 */ + ea->scale = 1 << sib.scale; + + if (sib.index != SIB_INDEX_NONE) { + /* IF INDEX is not 'ESP' (100) */ + ia32_handle_register( &ea->index, sib.index + 1 ); + } + + return (size); /* return number of bytes processed */ +} + +static size_t modrm_decode16( unsigned char *buf, unsigned int buf_len, + x86_op_t *op, struct modRM_byte *modrm ) { + /* 16-bit mode: hackish, but not as hackish as 32-bit mode ;) */ + size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ + x86_ea_t * ea = &op->data.expression; + + switch( modrm->rm ) { + case MOD16_RM_BXSI: + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); + ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); + break; + case MOD16_RM_BXDI: + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); + ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); + case MOD16_RM_BPSI: + op->flags |= op_ss_seg; + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); + ia32_handle_register(&ea->index, REG_WORD_OFFSET + 6); + break; + case MOD16_RM_BPDI: + op->flags |= op_ss_seg; + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 5); + ia32_handle_register(&ea->index, REG_WORD_OFFSET + 7); + break; + case MOD16_RM_SI: + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 6); + break; + case MOD16_RM_DI: + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 7); + break; + case MOD16_RM_BP: + if ( modrm->mod != MOD16_MOD_NODISP ) { + op->flags |= op_ss_seg; + ia32_handle_register(&ea->base, + REG_WORD_OFFSET + 5); + } + break; + case MOD16_RM_BX: + ia32_handle_register(&ea->base, REG_WORD_OFFSET + 3); + break; + } + + /* move to byte after ModR/M */ + ++buf; + --buf_len; + + if ( modrm->mod == MOD16_MOD_DISP8 ) { + imm32_signsized( buf, buf_len, &ea->disp, sizeof(char) ); + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + ea->disp_size = sizeof(char); + size += sizeof(char); + } else if ( modrm->mod == MOD16_MOD_DISP16 ) { + imm32_signsized( buf, buf_len, &ea->disp, sizeof(short) ); + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + ea->disp_size = sizeof(short); + size += sizeof(short); + } + + return size; +} + +/* TODO : Mark index modes + Use addressing mode flags to imply arrays (index), structure (disp), + two-dimensional arrays [disp + index], classes [ea reg], and so on. +*/ +size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len, + x86_op_t *op, x86_insn_t *insn, size_t gen_regs ) { + /* create address expression and/or fill operand based on value of + * ModR/M byte. Calls sib_decode as appropriate. + * flags specifies whether Reg or mod+R/M fields are being decoded + * returns the number of bytes in the instruction, including modR/M */ + struct modRM_byte modrm; + size_t size = 1; /* # of bytes decoded [1 for modR/M byte] */ + x86_ea_t * ea; + + + byte_decode(*buf, &modrm); /* get bitfields */ + + /* first, handle the case where the mod field is a register only */ + if ( modrm.mod == MODRM_MOD_NOEA ) { + op->type = op_register; + ia32_handle_register(&op->data.reg, modrm.rm + gen_regs); + /* increase insn size by 1 for modrm byte */ + return 1; + } + + /* then deal with cases where there is an effective address */ + ea = &op->data.expression; + op->type = op_expression; + op->flags |= op_pointer; + + if ( insn->addr_size == 2 ) { + /* gah! 16 bit mode! */ + return modrm_decode16( buf, buf_len, op, &modrm); + } + + /* move to byte after ModR/M */ + ++buf; + --buf_len; + + if (modrm.mod == MODRM_MOD_NODISP) { /* if mod == 00 */ + + /* IF MOD == No displacement, just Indirect Register */ + if (modrm.rm == MODRM_RM_NOREG) { /* if r/m == 101 */ + /* IF RM == No Register, just Displacement */ + /* This is an Intel Moronic Exception TM */ + imm32_signsized( buf, buf_len, &ea->disp, + sizeof(int32_t) ); + ea->disp_size = sizeof(int32_t); + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + size += 4; /* add sizeof disp to count */ + + } else if (modrm.rm == MODRM_RM_SIB) { /* if r/m == 100 */ + /* ELSE IF an SIB byte is present */ + /* TODO: check for 0 retval */ + size += sib_decode( buf, buf_len, ea, modrm.mod); + /* move to byte after SIB for displacement */ + ++buf; + --buf_len; + } else { /* modR/M specifies base register */ + /* ELSE RM encodes a general register */ + ia32_handle_register( &ea->base, modrm.rm + 1 ); + } + } else { /* mod is 01 or 10 */ + if (modrm.rm == MODRM_RM_SIB) { /* rm == 100 */ + /* IF base is an AddrExpr specified by an SIB byte */ + /* TODO: check for 0 retval */ + size += sib_decode( buf, buf_len, ea, modrm.mod); + /* move to byte after SIB for displacement */ + ++buf; + --buf_len; + } else { + /* ELSE base is a general register */ + ia32_handle_register( &ea->base, modrm.rm + 1 ); + } + + /* ELSE mod + r/m specify a disp##[base] or disp##(SIB) */ + if (modrm.mod == MODRM_MOD_DISP8) { /* mod == 01 */ + /* If this is an 8-bit displacement */ + imm32_signsized( buf, buf_len, &ea->disp, + sizeof(char)); + ea->disp_size = sizeof(char); + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + size += 1; /* add sizeof disp to count */ + + } else { + /* Displacement is dependent on address size */ + imm32_signsized( buf, buf_len, &ea->disp, + insn->addr_size); + ea->disp_size = insn->addr_size; + ea->disp_sign = (ea->disp < 0) ? 1 : 0; + size += 4; + } + } + + return size; /* number of bytes found in instruction */ +} + +void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ) { + struct modRM_byte modrm; + byte_decode( byte, &modrm ); /* get bitfields */ + + /* set operand to register ID */ + op->type = op_register; + ia32_handle_register(&op->data.reg, modrm.reg + gen_regs); + + return; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.h new file mode 100644 index 0000000000..765cb0833b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_modrm.h @@ -0,0 +1,13 @@ +#ifndef IA32_MODRM_H +#define IA32_MODRM_H + +#include "libdis.h" +#include "ia32_insn.h" + +size_t ia32_modrm_decode( unsigned char *buf, unsigned int buf_len, + x86_op_t *op, x86_insn_t *insn, + size_t gen_regs ); + +void ia32_reg_decode( unsigned char byte, x86_op_t *op, size_t gen_regs ); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.c new file mode 100644 index 0000000000..ef97c7a351 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.c @@ -0,0 +1,2939 @@ +#include "ia32_insn.h" + +#include "ia32_reg.h" + +#include "ia32_opcode_tables.h" + +static ia32_insn_t tbl_Main[] = { /* One-byte Opcodes */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 0, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RS | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 0, 0, 0, 0 , 33 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 1, 0, 0, 0 , 33 }, + { idx_0F, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, +/* 0x10 */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_ADD, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_ADD, 0, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_ADD, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_ADD, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 2, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RS | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 2, 0, 0, 0 , 33 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_SIGNED | OP_R, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_RR | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_RR | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 3, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RS | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 3, 0, 0, 0 , 33 }, +/* 0x20 */ + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_AND, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_AND, 0, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_AND, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_AND, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_ES, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BCDCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "daa", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_CARRY|INS_SET_PARITY|INS_TEST_CARRY, 12 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_G | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_RR | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_RR | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_CS | PREFIX_NOTTAKEN, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BCDCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "das", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_CARRY|INS_SET_PARITY|INS_TEST_CARRY, 0 }, +/* 0x30 */ + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_SS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BCDCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "aaa", "", 0, 0, 0, INS_SET_CARRY, 1 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_G | OPTYPE_b | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_RR | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_DS | PREFIX_TAKEN, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BCDCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "aas", "", 0, 0, 0, INS_SET_CARRY, 0 }, +/* 0x40 */ + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 1, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 2, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 3, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 4, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 5, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 6, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_INC, 0, ADDRMETH_RR | OPTYPE_v | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 7, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 1, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 2, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 3, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 4, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 5, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 6, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 7, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, +/* 0x50 */ + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 0, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 1, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 2, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 3, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 4, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 5, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 6, 0, 0, 0 , 33 }, + { 0, INS_PUSH, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 7, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 0, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 1, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 2, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 3, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 4, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 5, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 6, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 7, 0, 0, 0 , 33 }, +/* 0x60 */ + { 0, INS_PUSHREGS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pusha", "", 0, 0, 0, 0 , 36 }, + { 0, INS_POPREGS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "popa", "", 0, 0, 0, 0 , 34 }, + { 0, INS_BOUNDS, INS_NOTE_NONSWAP, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_M | OPTYPE_a | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bound", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_R | OP_W, ADDRMETH_G | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "arpl", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_FS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_GS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_66, INS_FLAG_PREFIX | PREFIX_OP_SIZE, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_FLAG_PREFIX | PREFIX_ADDR_SIZE, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_PUSH, 0, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 0, 0, 0, 0 , 33 }, + { 0, INS_MUL, 0, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, cpu_80386 | isa_GP, "imul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 0, 0, 0, 0 , 33 }, + { 0, INS_MUL, 0, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, cpu_80386 | isa_GP, "imul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 0 }, + { 0, INS_IN, 0, ADDRMETH_Y | OPTYPE_b | OP_W, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ins", "", 0, 2, 0, 0 , 0 }, + { 0, INS_IN, 0, ADDRMETH_Y | OPTYPE_v | OP_W, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ins", "", 0, 2, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_RR | OPTYPE_b | OP_R, ADDRMETH_X | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "outs", "", 2, 0, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ADDRMETH_X | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "outs", "", 2, 0, 0, 0 , 0 }, +/* 0x70 */ + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jo", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jno", "", 0, 0, 0, INS_TEST_NOFLOW, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jc", "", 0, 0, 0, INS_TEST_CARRY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jnc", "", 0, 0, 0, INS_TEST_NCARRY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jz", "", 0, 0, 0, INS_TEST_ZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jnz", "", 0, 0, 0, INS_TEST_NZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jbe", "", 0, 0, 0, INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ja", "", 0, 0, 0, INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "js", "", 0, 0, 0, INS_TEST_SIGN, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jns", "", 0, 0, 0, INS_TEST_NSIGN, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jpe", "", 0, 0, 0, INS_TEST_PARITY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jpo", "", 0, 0, 0, INS_TEST_NPARITY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jl", "", 0, 0, 0, INS_TEST_SFNEOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jge", "", 0, 0, 0, INS_TEST_SFEQOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jle", "", 0, 0, 0, INS_TEST_ZERO|INS_TEST_OR|INS_TEST_SFNEOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jg", "", 0, 0, 0, INS_TEST_NZERO|INS_TEST_SFEQOF, 0 }, +/* 0x80 */ + { idx_80, 0, 0, ADDRMETH_E | OPTYPE_b, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_81, 0, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_v, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_82, 0, 0, ADDRMETH_E | OPTYPE_b, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_83, 0, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XCHG, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_G | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_b | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_w | OP_W, ADDRMETH_S | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_m | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lea", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_S | OPTYPE_w | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_POP, 0, ADDRMETH_E | OPTYPE_v | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 0, 0, 0, 0 , 33 }, +/* 0x90 */ + { 0, INS_NOP, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "nop", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 1, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 2, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 3, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 4, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 5, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 6, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xchg", "", 0, 7, 0, 0 , 0 }, + { 0, INS_SZCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "cwde", "", 0, 0, 0, 0 , 5 }, + { 0, INS_SZCONV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "cdq", "", 0, 0, 0, 0 , 11 }, + { 0, INS_CALL, 0, ADDRMETH_A | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "callf", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "wait", "", 0, 0, 0, 0 , 0 }, + { 0, INS_PUSHFLAGS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pushf", "", 0, 0, 0, 0 , 37 }, + { 0, INS_POPFLAGS, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "popf", "", 0, 0, 0, 0 , 35 }, + { 0, INS_MOV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sahf", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 43 }, + { 0, INS_MOV, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lahf", "", 0, 0, 0, 0 , 24 }, +/* 0xa0 */ + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_O | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_O | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_O | OPTYPE_b | OP_W, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_O | OPTYPE_v | OP_W, ADDRMETH_RR | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRMOV, 0, ADDRMETH_Y | OPTYPE_b | OP_W, ADDRMETH_X | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movs", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRMOV, 0, ADDRMETH_Y | OPTYPE_v | OP_W, ADDRMETH_X | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movs", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRCMP, 0, ADDRMETH_Y | OPTYPE_b | OP_R, ADDRMETH_X | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRCMP, 0, ADDRMETH_X | OPTYPE_v | OP_R, ADDRMETH_Y | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_TEST, 0, ADDRMETH_RR | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_TEST, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_STRSTOR, 0, ADDRMETH_Y | OPTYPE_b | OP_W, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "stos", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRSTOR, 0, ADDRMETH_Y | OPTYPE_v | OP_W, ADDRMETH_RR | OPTYPE_v |OP_R, ARG_NONE, cpu_80386 | isa_GP, "stos", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRLOAD, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_X| OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lods", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRLOAD, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_X| OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lods", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRCMP, 0, ADDRMETH_RR | OPTYPE_b | OP_R, ADDRMETH_Y | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "scas", "", 0, 0, 0, 0 , 0 }, + { 0, INS_STRCMP, 0, ADDRMETH_RR | OPTYPE_v | OP_R, ADDRMETH_Y | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "scas", "", 0, 0, 0, 0 , 0 }, +/* 0xb0 */ + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 1, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 2, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 3, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 4, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 5, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 6, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 7, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 1, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 2, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 3, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 4, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 5, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 6, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 7, 0, 0, 0 , 0 }, +/* 0xc0 */ + { idx_C0, 0, 0, ADDRMETH_E | OPTYPE_b, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_C1, 0, 0, ADDRMETH_E | OPTYPE_v, ADDRMETH_I | OPTYPE_b, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_RET, 0, ADDRMETH_I | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ret", "", 0, 0, 0, 0 , 3 }, + { 0, INS_RET, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ret", "", 0, 0, 0, 0 , 3 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_R, ARG_NONE, cpu_80386 | isa_GP, "les", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lds", "", 0, 0, 0, 0 , 0 }, + { idx_C6, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_C7, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ENTER, INS_NOTE_NONSWAP, ADDRMETH_I | OPTYPE_w | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "enter", "", 0, 0, 0, 0 , 15 }, + { 0, INS_LEAVE, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "leave", "", 0, 0, 0, 0 , 26 }, + { 0, INS_RET, 0, ADDRMETH_I | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "retf", "lret", 0, 0, 0, 0 , 3 }, + { 0, INS_RET, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "retf", "lret", 0, 0, 0, 0 , 3 }, + { 0, INS_DEBUG, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "int3", "", 0, 0, 0, 0 , 0 }, + { 0, INS_TRAP, 0, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "int", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OFLOW, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "into", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_TRET, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "iret", "", 0, 0, 0, INS_SET_ALL|INS_SET_DIR, 0 }, +/* 0xd0 */ + { idx_D0, 0, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 1, 0, 0 , 0 }, + { idx_D1, 0, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 1, 0, 0 , 0 }, + { idx_D2, 0, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 1, 0, 0 , 0 }, + { idx_D3, 0, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 1, 0, 0 , 0 }, + { 0, INS_BCDCONV, 0, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "aam", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_BCDCONV, 0, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "aad", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 2 }, + { 0, INS_SALC, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "salc", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XLAT, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "xlat", "", 0, 0, 0, 0 , 53 }, + { idx_D8, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_D9, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DA, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DB, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DC, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DD, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DE, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_DF, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, +/* 0xe0 */ + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "loopnz", "", 0, 0, 0, INS_TEST_NZERO, 31 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "loopz", "", 0, 0, 0, INS_TEST_ZERO, 31 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "loop", "", 0, 0, 0, 0 , 31 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_b | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jcxz", "", 0, 0, 0, 0 , 31 }, + { 0, INS_IN, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "in", "", 0, 0, 0, 0 , 0 }, + { 0, INS_IN, 0, ADDRMETH_RR | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "in", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_I | OPTYPE_b | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "out", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_I | OPTYPE_b | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "out", "", 0, 0, 0, 0 , 0 }, + { 0, INS_CALL, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "call", "", 0, 0, 0, 0 , 3 }, + { 0, INS_BRANCH, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jmp", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BRANCH, 0, ADDRMETH_A | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jmp", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BRANCH, 0, ADDRMETH_J | OPTYPE_b | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jmp", "", 0, 0, 0, 0 , 0 }, + { 0, INS_IN, 0, ADDRMETH_RR | OPTYPE_b| OP_W, ADDRMETH_RR | OPTYPE_w| OP_R, ARG_NONE, cpu_80386 | isa_GP, "in", "", 0, 2, 0, 0 , 0 }, + { 0, INS_IN, 0, ADDRMETH_RR | OPTYPE_v | OP_W, ADDRMETH_RR | OPTYPE_w| OP_R, ARG_NONE, cpu_80386 | isa_GP, "in", "", 0, 2, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_RR | OPTYPE_w| OP_R, ADDRMETH_RR | OPTYPE_b| OP_R, ARG_NONE, cpu_80386 | isa_GP, "out", "", 2, 0, 0, 0 , 0 }, + { 0, INS_OUT, 0, ADDRMETH_RR | OPTYPE_w| OP_R, ADDRMETH_RR | OPTYPE_v| OP_R, ARG_NONE, cpu_80386 | isa_GP, "out", "", 2, 0, 0, 0 , 0 }, +/* 0xf0 */ + { 0, INS_FLAG_PREFIX | PREFIX_LOCK, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ICEBP, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "icebp", "", 0, 0, 0, 0 , 0 }, + { idx_F2, INS_FLAG_PREFIX | PREFIX_REPNZ, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_F3, INS_FLAG_PREFIX | PREFIX_REPZ, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_HALT, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "hlt", "", 0, 0, 0, 0 , 0 }, + { 0, INS_TOGCF, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "cmc", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { idx_F6, 0, 0, ADDRMETH_E | OPTYPE_b, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_F7, 0, 0, ADDRMETH_E | OPTYPE_v, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_CLEARCF, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "clc", "", 0, 0, 0, INS_SET_NCARRY, 0 }, + { 0, INS_SETCF, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "stc", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "cli", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sti", "", 0, 0, 0, 0 , 0 }, + { 0, INS_CLEARDF, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "cld", "", 0, 0, 0, INS_SET_NDIR, 0 }, + { 0, INS_SETDF, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "std", "", 0, 0, 0, INS_SET_DIR, 0 }, + { idx_FE, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_FF, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_66[] = { /* SIMD 66 one-byte Opcodes */ + { idx_660F, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_F2[] = { /* SIMD F2 one-byte Opcodes */ + { idx_F20F, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_F3[] = { /* SIMD F3 one-byte Opcodes */ + { idx_F30F, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pause", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_0F[] = { /* Two-byte Opcodes */ + { idx_0F00, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { idx_0F01, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lar", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "lsl", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "clts", "", 0, 0, 0, 0 , 6 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "invd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "wbinvd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_UNKNOWN, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTPRO | isa_GP, "ud2", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "prefetch", "", 0, 0, 0, 0, 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "femms", "", 0, 0, 0, 0, 0 }, + { idx_0F0F, INS_FLAG_SUFFIX, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movups", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movups", "", 0, 0, 0, 0 , 0 }, + { idx_0F12, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movlps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "unpcklps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "unpckhps", "", 0, 0, 0, 0 , 0 }, + { idx_0F16, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_q | OP_W, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movhps", "", 0, 0, 0, 0 , 0 }, + { idx_0F18, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_R | OPTYPE_d | OP_W, ADDRMETH_C | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_R | OPTYPE_d | OP_W, ADDRMETH_D | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_C | OPTYPE_d | OP_W, ADDRMETH_R | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_D | OPTYPE_d | OP_W, ADDRMETH_R | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_R | OPTYPE_d | OP_W, ADDRMETH_T | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_T | OPTYPE_d | OP_W, ADDRMETH_R | OPTYPE_d | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movaps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movaps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "cvtpi2ps", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_W | OPTYPE_ps | OP_W, ADDRMETH_V | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movntps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "cvttps2pi", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_q | OP_W , ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "cvtps2pi", "", 0, 0, 0, 0, 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ss | OP_W, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "ucomiss", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ss | OP_W, ARG_NONE, cpu_PENTIUM2 | isa_GP, "comiss", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "wrmsr", "", 0, 0, 0, 0 , 52 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "rdtsc", "", 0, 0, 0, 0 , 40 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "rdmsr", "", 0, 0, 0, 0 , 38 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTPRO | isa_GP, "rdpmc", "", 0, 0, 0, 0 , 39 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "sysenter", "", 0, 0, 0, 0 , 50 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "sysexit", "", 0, 0, 0, 0 , 51 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovo", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovno", "", 0, 0, 0, INS_TEST_NOFLOW, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovc", "", 0, 0, 0, INS_TEST_CARRY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovnc", "", 0, 0, 0, INS_TEST_NCARRY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovz", "", 0, 0, 0, INS_TEST_ZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovnz", "", 0, 0, 0, INS_TEST_NZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovbe", "", 0, 0, 0, INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmova", "", 0, 0, 0, INS_TEST_NZERO|INS_TEST_NCARRY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovs", "", 0, 0, 0, INS_TEST_SIGN, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovns", "", 0, 0, 0, INS_TEST_NSIGN, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovp", "", 0, 0, 0, INS_TEST_PARITY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovnp", "", 0, 0, 0, INS_TEST_NPARITY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovl", "", 0, 0, 0, INS_TEST_SFNEOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovge", "", 0, 0, 0, INS_TEST_SFEQOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovle", "", 0, 0, 0, INS_TEST_ZERO|INS_TEST_OR|INS_TEST_SFNEOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "cmovg", "", 0, 0, 0, INS_TEST_NZERO|INS_TEST_SFEQOF, 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_d | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movmskps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "sqrtps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "rsqrtps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "rcpps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_AND, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "andps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_AND, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "andnps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OR, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "orps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XOR, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "xorps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "addps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MUL, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "mulps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_pd, ADDRMETH_W | OPTYPE_q, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtps2pd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtdq2ps", "", 0, 0, 0, 0, 0 }, + { 0, INS_SUB, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "subps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "minps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_DIV, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "divps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "maxps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpcklbw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpcklwd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpckldq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "packsswb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpgtb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpgtw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpgtd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "packuswb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpckhbw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpckhwd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "punpckhdq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "packssdw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_d | OP_W, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "movd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "movq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2 | isa_GP, "pshufw", "", 0, 0, 0, 0, 0 }, + { idx_0F71, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "", "", 0, 0, 0, 0 , 0 }, + { idx_0F72, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "", "", 0, 0, 0, 0 , 0 }, + { idx_0F73, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpeqb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_CMP, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpeqw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_CMP, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pcmpeqd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "emms", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_d | OP_W, ADDRMETH_P | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "movd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_Q | OPTYPE_q | OP_W, ADDRMETH_P | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "movq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jo", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jno", "", 0, 0, 0, INS_TEST_NOFLOW, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jc", "", 0, 0, 0, INS_TEST_CARRY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jnc", "", 0, 0, 0, INS_TEST_NCARRY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jz", "", 0, 0, 0, INS_TEST_ZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jnz", "", 0, 0, 0, INS_TEST_NZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jbe", "", 0, 0, 0, INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ja", "", 0, 0, 0, INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "js", "", 0, 0, 0, INS_TEST_SIGN, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jns", "", 0, 0, 0, INS_TEST_NSIGN, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jpe", "", 0, 0, 0, INS_TEST_PARITY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jpo", "", 0, 0, 0, INS_TEST_NPARITY, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jl", "", 0, 0, 0, INS_TEST_SFNEOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jge", "", 0, 0, 0, INS_TEST_SFEQOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jle", "", 0, 0, 0, INS_TEST_ZERO|INS_TEST_OR|INS_TEST_SFNEOF, 0 }, + { 0, INS_BRANCHCC, 0, ADDRMETH_J | OPTYPE_v | OP_X | OP_SIGNED, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jg", "", 0, 0, 0, INS_TEST_NZERO|INS_TEST_SFEQOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "seto", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setno", "", 0, 0, 0, INS_TEST_OFLOW, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setc", "", 0, 0, 0, INS_TEST_CARRY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setnc", "", 0, 0, 0, INS_TEST_NCARRY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setz", "", 0, 0, 0, INS_TEST_ZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setnz", "", 0, 0, 0, INS_TEST_NZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setbe", "", 0, 0, 0, INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "seta", "", 0, 0, 0, INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sets", "", 0, 0, 0, INS_TEST_SIGN, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setns", "", 0, 0, 0, INS_TEST_NSIGN, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setpe", "", 0, 0, 0, INS_TEST_PARITY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setpo", "", 0, 0, 0, INS_TEST_NPARITY, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setl", "", 0, 0, 0, INS_TEST_SFNEOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setge", "", 0, 0, 0, INS_TEST_SFEQOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setle", "", 0, 0, 0, INS_TEST_ZERO|INS_TEST_OR|INS_TEST_SFNEOF, 0 }, + { 0, INS_MOVCC, 0, ADDRMETH_E | OPTYPE_b | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "setg", "", 0, 0, 0, INS_TEST_NZERO|INS_TEST_SFEQOF, 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 4, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RS | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 4, 0, 0, 0 , 33 }, + { 0, INS_CPUID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "cpuid", "", 0, 0, 0, 0 , 10 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bt", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_80386 | isa_GP, "shld", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + //{ 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OP_R | OPTYPE_b | ADDRMETH_RR, cpu_80386 | isa_GP, "shld", "", 0, 0, 1, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_RR | OP_R | OPTYPE_b, cpu_80386 | isa_GP, "shld", "", 0, 0, 1, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_PUSH, 0, ADDRMETH_RS | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 5, 0, 0, 0 , 33 }, + { 0, INS_POP, 0, ADDRMETH_RS | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "pop", "", 5, 0, 0, 0 , 33 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "rsm", "", 0, 0, 0, INS_SET_ALL|INS_SET_DIR, 42 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bts", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_80386 | isa_GP, "shrd", "", 0, 0, 0, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ADDRMETH_RR | OP_R | OPTYPE_b , cpu_80386 | isa_GP, "shrd", "", 0, 0, 1, INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { idx_0FAE, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MUL, 0, ADDRMETH_G | OPTYPE_v | OP_SIGNED | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "imul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, }, + { 0, INS_XCHGCC, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_W, ARG_NONE, cpu_80486 | isa_GP, "cmpxchg", "", 0, 0, 0, INS_SET_ALL, 8 }, + { 0, INS_XCHGCC, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_W, ARG_NONE, cpu_80486 | isa_GP, "cmpxchg", "", 0, 0, 0, INS_SET_ALL, 7 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_W, ARG_NONE, cpu_80386 | isa_GP, "lss", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "btr", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_W, ARG_NONE, cpu_80386 | isa_GP, "lfs", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_M | OPTYPE_p | OP_W, ARG_NONE, cpu_80386 | isa_GP, "lgs", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movzx", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movzx", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_UNKNOWN, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ud1", "", 0, 0, 0, 0 , 0 }, + { idx_0FBA, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_G | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "btc", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_G | OPTYPE_v | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bsf", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_G | OPTYPE_v | OP_R | OP_W, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bsr", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movsx", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_G | OPTYPE_v | OP_W, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, cpu_80386 | isa_GP, "movsx", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_G | OPTYPE_b | OP_W, ARG_NONE, cpu_80486 | isa_GP, "xadd", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_G | OPTYPE_v | OP_W, ARG_NONE, cpu_80486 | isa_GP, "xadd", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "cmpps", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_M | OPTYPE_d | OP_W, ADDRMETH_G | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movnti", "", 0, 0, 0, 0, 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_E | OPTYPE_d | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2 | isa_GP, "pinsrw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_G | OPTYPE_d | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2 | isa_GP, "pextrw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_ps | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM2 | isa_GP, "shufps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHGCC, 0, ADDRMETH_M | OPTYPE_q | OP_R | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "cmpxchg8b", "", 0, 0, 0, 0, 9 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 1, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 2, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 3, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 4, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 5, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 6, 0, 0, 0 , 0 }, + { 0, INS_XCHG, 0, ADDRMETH_RR | OPTYPE_d | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "bswap", "", 7, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddq", "", 0, 0, 0, 0, 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pmullw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_G | OPTYPE_d | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pmovmskb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubusb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubusw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pminub", "", 0, 0, 0, 0 , 0 }, + { 0, INS_AND, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pand", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddusb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddusw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pmaxub", "", 0, 0, 0, 0 , 0 }, + { 0, INS_AND, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pandn", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pavgb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psraw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrad", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pavgw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MUL, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pmulhuw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MUL, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pmulhw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_W | OPTYPE_q | OP_W, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movntq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubsb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubsw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pminsw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OR, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "por", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddsb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddsw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "pmaxsw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XOR, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pxor", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pslld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MUL, 0, ADDRMETH_P | OPTYPE_q | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmuludq", "", 0, 0, 0, 0, 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pmaddwd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "psadbw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_P | OPTYPE_pi | OP_W, ADDRMETH_Q | OPTYPE_pi | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "maskmovq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psubd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_q | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubq", "", 0, 0, 0, 0, 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddb", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "paddd", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_660F[] = { /* SIMD 66 Two-byte Opcodes */ + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movupd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_W | OPTYPE_pd | OP_R, ADDRMETH_V | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movupd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_R, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movlpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_M | OPTYPE_q | OP_R, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movlpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "unpcklpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "unpckhpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_R, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movhpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_M | OPTYPE_q | OP_R, ADDRMETH_V | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movhpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movapd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MOV, 0, ADDRMETH_W | OPTYPE_pd | OP_R, ADDRMETH_V | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movapd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtpi2pd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_M | OPTYPE_pd | OP_R, ADDRMETH_V | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movntpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_P | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvttpd2pi", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_P | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtpd2pi", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "ucomisd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "comisd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movmskpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_FSQRT, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "sqrtpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_AND, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "andpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_AND, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "andnpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_OR, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "orpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_XOR, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "xorpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_ADD, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "addpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_MUL, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "mulpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtpd2ps", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtps2dq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "subpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "minpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "divpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "maxpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpcklbw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpcklwd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpckldq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "packsswb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpgtb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpgtw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpgtd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "packuswb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpckhbw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpckhwd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpckhdq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "packssdw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpcklqdq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "punpckhqdq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_d | OP_R, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movdqa", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "pshufd", "", 0, 0, 0, 0, 0 }, + { idx_660F71, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { idx_660F72, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { idx_660F73, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpeqb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpeqw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pcmpeqd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "haddpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "hsubpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_E | OPTYPE_d | OP_R, ADDRMETH_V | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_W | OPTYPE_dq | OP_R, ADDRMETH_V | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movdqa", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "cmppd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_w | OP_R, ADDRMETH_E | OPTYPE_d | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "pinsrw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_w | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "pextrw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "shufpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "addsubpd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psrlw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psrld", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psrlq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmullw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_W | OPTYPE_q | OP_R, ADDRMETH_V | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmovmskb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubusb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubusw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pminub", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pand", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddusb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddusw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmaxub", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pandn", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pavgb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psraw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psrad", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pavgw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmulhuw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmulhw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvttpd2dq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_M | OPTYPE_dq | OP_R, ADDRMETH_V | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movntdq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubsb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubsw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pminsw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "por", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddsb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddsw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmaxsw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pxor", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psllw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pslld", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psllq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmuludq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "pmaddwd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psadbw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "maskmovdqu", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "psubq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddb", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddw", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "paddd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_F20F[] = { /* SIMD F2 Two-byte Opcodes */ + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_W | OPTYPE_sd | OP_R, ADDRMETH_V | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movddup", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtsi2sd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvttsd2si", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtsd2si", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "sqrtsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "addsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "mulsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtsd2ss", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "subsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "minsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "divsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "maxsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "pshuflw", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "haddps", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "hsubps", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_sd | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "cmpsd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "addsubps", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_P | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movdq2q", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_pd | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtpd2dq", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_M | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "lddqu", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_F30F[] = { /* SIMD F3 Two-byte Opcodes */ + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_W | OPTYPE_ss | OP_R, ADDRMETH_V | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movsldup", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ps | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movshdup", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtsi2ss", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvttss2si", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_G | OPTYPE_d | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtss2si", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "sqrtss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "rsqrtss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "rcpss", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "addss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "mulss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_sd | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtss2sd", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_ps | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvttps2dq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "subss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "minss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "divss", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "maxss", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movdqu", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_W | OPTYPE_dq | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "pshufhw", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_q | OP_R, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movq", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_W | OPTYPE_dq | OP_R, ADDRMETH_V | OPTYPE_dq | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movdqu", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_ss | OP_R, ADDRMETH_W | OPTYPE_ss | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, cpu_PENTIUM4 | isa_GP, "cmpss", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_dq | OP_R, ADDRMETH_Q | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "movq2dq", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_UNKNOWN, 0, ADDRMETH_V | OPTYPE_pd | OP_R, ADDRMETH_W | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM4 | isa_GP, "cvtdq2pd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_0F00[] = { /* Group 6 */ + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sldt", "", 0, 0, 0, 0 , 46 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "str", "", 0, 0, 0, 0 , 49 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lldt", "", 0, 0, 0, 0 , 29 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "ltr", "", 0, 0, 0, 0 , 32 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "verr", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "verw", "", 0, 0, 0, INS_SET_ZERO, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0F01[] = { /* Group 7 */ + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sgdt", "", 0, 0, 0, 0 , 44 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sidt", "", 0, 0, 0, 0 , 45 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lgdt", "", 0, 0, 0, 0 , 27 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lidt", "", 0, 0, 0, 0 , 28 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "smsw", "", 0, 0, 0, 0 , 47 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lmsw", "", 0, 0, 0, 0 , 30 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_none | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "invlpg", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sgdt", "", 0, 0, 0, 0 , 44 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sidt", "", 0, 0, 0, 0 , 45 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lgdt", "", 0, 0, 0, 0 , 27 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lidt", "", 0, 0, 0, 0 , 28 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "smsw", "", 0, 0, 0, 0 , 47 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lmsw", "", 0, 0, 0, 0 , 30 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_none | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "invlpg", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sgdt", "", 0, 0, 0, 0 , 44 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "sidt", "", 0, 0, 0, 0 , 45 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lgdt", "", 0, 0, 0, 0 , 27 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_s | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lidt", "", 0, 0, 0, 0 , 28 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "smsw", "", 0, 0, 0, 0 , 47 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lmsw", "", 0, 0, 0, 0 , 30 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_none | OP_R, ARG_NONE, ARG_NONE, cpu_80486 | isa_GP, "invlpg", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { idx_0F0111, 0, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "smsw", "", 0, 0, 0, 0 , 47 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_w | OP_W, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "lmsw", "", 0, 0, 0, 0 , 30 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0F0111[] = { /* Monitor/MWait opcode */ + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "monitor", "", 0, 0, 0, 0, 54 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "mwait", "", 0, 0, 0, 0, 55 } +}; + + +static ia32_insn_t tbl_0F12[] = { /* Movlps Opcode */ + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movlps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movlps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, INS_NOTE_NOSUFFIX, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movlps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_R | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R , ARG_NONE, cpu_PENTIUM4 | isa_GP, "movhlps", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_0F16[] = { /* Movhps Opcode */ + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movhps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movhps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_V | OPTYPE_q | OP_W, ADDRMETH_M | OPTYPE_q | OP_R, ARG_NONE, cpu_PENTIUM2 | isa_GP, "movhps", "", 0, 0, 0, 0 , 0 }, + { 0, INS_MOV, 0, ADDRMETH_V | OPTYPE_ps | OP_R | OP_W, ADDRMETH_W | OPTYPE_ps | OP_R , ARG_NONE, cpu_PENTIUM4 | isa_GP, "movlhps", "", 0, 0, 0, 0, 0 } +}; + + +static ia32_insn_t tbl_0F18[] = { /* Group 16 */ + { 0, INS_SYSTEM, 0, OP_W | OPTYPE_b | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetchnta", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht0", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht1", "", 1, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht2", "", 2, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, OP_W | OPTYPE_b | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetchnta", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht0", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht1", "", 1, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht2", "", 2, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, OP_W | OPTYPE_b | ADDRMETH_M, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetchnta", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht0", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht1", "", 1, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_RT | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2 | isa_GP, "prefetcht2", "", 2, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0F71[] = { /* Group 12 */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psraw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_660F71[] = { /* Group 12 SSE */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psraw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllw", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0F72[] = { /* Group 13 */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrad", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pslld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_660F72[] = { /* Group 13 SSE */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrad", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pslld", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0F73[] = { /* Group 14 */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_P | OPTYPE_q | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_660F73[] = { /* Group 14 SSE */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrlq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psrldq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "psllq", "", 0, 0, 0, 0 , 0 }, + { 0, INS_OTHER, 0, ADDRMETH_W | OPTYPE_dq | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_PENTIUM | isa_MMX, "pslldq", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0FAE[] = { /* Group 15 */ + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxsave", "", 0, 0, 0, 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxrstor", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "ldmxcsr", "", 0, 0, 0, 0 , 25 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "stmxcsr", "", 0, 0, 0 , 0, 48 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "clflush", "", 0, 0, 0, 0, 0 }, + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxsave", "", 0, 0, 0, 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxrstor", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "ldmxcsr", "", 0, 0, 0, 0 , 25 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "stmxcsr", "", 0, 0, 0 , 0, 48 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "clflush", "", 0, 0, 0, 0, 0 }, + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxsave", "", 0, 0, 0, 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_E | OPTYPE_fx | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_MMX, "fxrstor", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "ldmxcsr", "", 0, 0, 0, 0 , 25 }, + { 0, INS_SYSTEM, 0, ADDRMETH_E | OPTYPE_d | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM2, "stmxcsr", "", 0, 0, 0 , 0, 48 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ADDRMETH_M | OPTYPE_b | OP_R, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "clflush", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "lfence", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "mfence", "", 0, 0, 0, 0 , 0 }, + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "sfence", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_0FBA[] = { /* Group 8 */ + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bt", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "bts", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "btr", "", 0, 0, 0, INS_SET_CARRY, 0 }, + { 0, INS_BITTEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "btc", "", 0, 0, 0 , INS_SET_CARRY, 0 } +}; + + +static ia32_insn_t tbl_0FC7[] = { /* Group 9 */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHGCC, 0, ADDRMETH_M | OPTYPE_q | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "cmpxch8b", "", 0, 0, 0 , 0 , 9 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHGCC, 0, ADDRMETH_M | OPTYPE_q | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "cmpxch8b", "", 0, 0, 0 , 0 , 9 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "", "", 0, 0, 0, 0 , 0 }, + { 0, INS_XCHGCC, 0, ADDRMETH_M | OPTYPE_q | OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM | isa_GP, "cmpxch8b", "", 0, 0, 0 , 0 , 9 } +}; + + +static ia32_insn_t tbl_0FB9[] = { /* Group 10 */ + { 0, INS_SYSTEM, 0, ARG_NONE, ARG_NONE, ARG_NONE, 0, "fxsave", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_C6[] = { /* Group 11a */ + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_b | OP_W, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_C7[] = { /* Group 11b */ + { 0, INS_MOV, 0, ADDRMETH_E | OPTYPE_v | OP_W, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mov", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_80[] = { /* Group 1a */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_81[] = { /* Group 1b */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_82[] = { /* Group 1c */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_83[] = { /* Group 1d */ + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "add", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_OR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "or", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_ADD, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "adc", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sbb", "", 0, 0, 0, INS_SET_ALL|INS_TEST_CARRY, 0 }, + { 0, INS_AND, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "and", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SUB, 0, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sub", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_XOR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "xor", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_CMP, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "cmp", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_C0[] = { /* Group 2a */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_C1[] = { /* Group 2b */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 0, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_I | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 0, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_D0[] = { /* Group 2c */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_II | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 1, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_D1[] = { /* Group 2d */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_II | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 1, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_D2[] = { /* Group 2e */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 1, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_D3[] = { /* Group 2f */ + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rol", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "ror", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW, 0 }, + { 0, INS_ROL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcl", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_ROR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "rcr", "", 0, 1, 0, INS_SET_CARRY|INS_SET_OFLOW|INS_TEST_CARRY, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shl", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "shr", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHL, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sal", "", 0, 1, 0, INS_SET_ALL, 0 }, + { 0, INS_SHR, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ADDRMETH_RR | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "sar", "", 0, 1, 0 , INS_SET_ALL, 0 } +}; + + +static ia32_insn_t tbl_F6[] = { /* Group 3a */ + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_b | OP_R, ADDRMETH_I | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_NOT, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "not", "", 0, 0, 0, 0 , 0 }, + { 0, INS_NEG, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "neg", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_MUL, 0, OPTYPE_b | ADDRMETH_RR | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 22 }, + { 0, INS_MUL, 0, OPTYPE_b | ADDRMETH_RR | OP_W | OP_SIGNED | OP_R, ADDRMETH_E | OPTYPE_b | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "imul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 22 }, + { 0, INS_DIV, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "div", "", 0, 0, 0, 0 , 13 }, + { 0, INS_DIV, 0, ADDRMETH_RR | OPTYPE_b | OP_W | OP_R, ADDRMETH_E | OPTYPE_b | OP_R, ARG_NONE, cpu_80386 | isa_GP, "idiv", "", 0, 0, 0 , 0 , 13 } +}; + + +static ia32_insn_t tbl_F7[] = { /* Group 3b */ + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_TEST, 0, ADDRMETH_E | OPTYPE_v | OP_R, ADDRMETH_I | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "test", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_NOT, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "not", "", 0, 0, 0, 0 , 0 }, + { 0, INS_NEG, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "neg", "", 0, 0, 0, INS_SET_ALL, 0 }, + { 0, INS_MUL, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "mul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 23 }, + { 0, INS_MUL, 0, ADDRMETH_RR | OPTYPE_v | OP_SIGNED | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_SIGNED | OP_R, ARG_NONE, cpu_80386 | isa_GP, "imul", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_CARRY, 23 }, + { 0, INS_DIV, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "div", "", 0, 0, 0, 0 , 14 }, + { 0, INS_DIV, 0, ADDRMETH_RR | OPTYPE_v | OP_W | OP_R, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, cpu_80386 | isa_GP, "idiv", "", 0, 0, 0, 0 , 14 } +}; + + +static ia32_insn_t tbl_FE[] = { /* Group 4 */ + { 0, INS_INC, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_E | OPTYPE_b | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 0, 0, 0 , INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 } +}; + + +static ia32_insn_t tbl_FF[] = { /* Group 5 */ + { 0, INS_INC, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "inc", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_DEC, 0, ADDRMETH_E | OPTYPE_v | OP_W | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "dec", "", 0, 0, 0, INS_SET_OFLOW|INS_SET_SIGN|INS_SET_ZERO|INS_SET_PARITY, 0 }, + { 0, INS_CALL, 0, ADDRMETH_E | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "call", "", 0, 0, 0, 0 , 3 }, + { 0, INS_CALL, 0, ADDRMETH_M | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "call", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BRANCH, 0, ADDRMETH_E | OPTYPE_v | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jmp", "", 0, 0, 0, 0 , 0 }, + { 0, INS_BRANCH, 0, ADDRMETH_M | OPTYPE_p | OP_X, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "jmp", "", 0, 0, 0, 0 , 0 }, + { 0, INS_PUSH, 0, ADDRMETH_E | OPTYPE_v | OP_R, ARG_NONE, ARG_NONE, cpu_80386 | isa_GP, "push", "", 0, 0, 0, 0 , 33 } +}; + + +static ia32_insn_t tbl_D8[] = { /* FPU D8 */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_D8C0[] = { /* FPU D8 C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 1, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 2, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 3, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 4, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 5, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 6, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 7, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 1, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 2, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 3, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 4, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 5, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 6, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 7, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 7, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_D9[] = { /* FPU D9 */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fs|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fv|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldenv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldcw", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fv|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnstenv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnstcw", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_D9C0[] = { /* FPU D9 C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fxch", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnop", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fchs", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fabs", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ftst", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fxam", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fld1", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldl2t", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldl2e", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldpi", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldlg2", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldln2", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fldz", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "f2xm1", "", 0, 0, 0 , 0 , 16 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fyl2x", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fptan", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fpatan", "", 0, 0, 0 , 0 , 18 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fxtract", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fprem1", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fdecstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fincstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fprem", "", 0, 0, 0 , 0 , 19 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fyl2xp1", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsqrt", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsincos", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "frndint", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fscale", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsin", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcos", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DA[] = { /* FPU DA */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fiadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fimul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ficom", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ficomp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fisub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fisubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fidiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fidivr", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DAC0[] = { /* FPU DA C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 0, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 1, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 2, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 3, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 4, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 5, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 6, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovb", "", 0, 7, 0 , INS_TEST_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 0, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 1, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 2, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 3, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 4, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 5, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 6, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmove", "", 0, 7, 0 , INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 0, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 1, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 2, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 3, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 4, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 5, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 6, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovbe", "", 0, 7, 0 , INS_TEST_CARRY|INS_TEST_OR|INS_TEST_ZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 0, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 1, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 2, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 3, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 4, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 5, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 6, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcmovu", "", 0, 7, 0 , INS_TEST_PARITY, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fucompp", "", 0, 0, 0 , 0 , 21 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DB[] = { /* FPU DB */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fild", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "fisttp", "", 0, 0, 0, 0, 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fist", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_d|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fistp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fe|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fe|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DBC0[] = { /* FPU DB C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 0, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 1, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 2, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 3, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 4, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 5, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 6, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnb", "", 0, 7, 0 , INS_TEST_NCARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 0, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 1, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 2, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 3, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 4, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 5, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 6, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovne", "", 0, 7, 0 , INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 0, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 1, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 2, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 3, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 4, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 5, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 6, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnbe", "", 0, 7, 0 , INS_TEST_NCARRY|INS_TEST_NZERO, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 0, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 1, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 2, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 3, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 4, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 5, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 6, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcmovnu", "", 0, 7, 0 , INS_TEST_NPARITY, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnclex", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fninit", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomi", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0, }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 1, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 2, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 3, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 4, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 5, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 6, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_PENTPRO | isa_GP, "fcomi", "", 0, 7, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DC[] = { /* FPU DC */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcom", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 17 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcomp", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_DCC0[] = { /* FPU DC C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fadd", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmul", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubr", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsub", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivr", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdiv", "", 7, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DD[] = { /* FPU DD */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fld", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_q|OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "fisttp", "", 0, 0, 0, 0, 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fd|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_ft|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "frstor", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_ft|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnsave", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnstsw", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DDC0[] = { /* FPU DD C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ffree", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fst", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fstp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucom", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DE[] = { /* FPU DE */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fiadd", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fimul", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ficom", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "ficomp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fisub", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fisubr", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fidiv", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fidivr", "", 0, 0, 0, 0 , 0 } +}; + + +static ia32_insn_t tbl_DEC0[] = { /* FPU DE C0 */ + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 0, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 1, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 2, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 3, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 4, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 5, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 6, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "faddp", "", 7, 0, 0 , 0 , 20 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fmulp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fcompp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubrp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fsubp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivrp", "", 7, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 1, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 2, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 3, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 4, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 5, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 6, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fdivp", "", 7, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DF[] = { /* FPU DF */ + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fild", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_PENTIUM4 | isa_GP, "fisttp", "", 0, 0, 0, 0, 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fist", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_w|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fistp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fb|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fbld", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_q|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fild", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_fb|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fbstp", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_M|OPTYPE_q|OP_W, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fistp", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_DFC0[] = { /* FPU DF C0 */ + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RR | OPTYPE_w | OP_R, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "fnstsw", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 1, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 2, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 3, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 4, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 5, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 6, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fucomip", "", 0, 7, 0 , 0 , 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 0, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 1, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 2, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 3, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 4, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 5, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 6, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_FPU, 0, ADDRMETH_RF | OPTYPE_fp | OP_W, ADDRMETH_RF | OPTYPE_fp | OP_R, ARG_NONE, cpu_80387 | isa_FPU, "fcomip", "", 0, 7, 0 , INS_SET_ZERO|INS_SET_PARITY|INS_SET_CARRY, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_80387 | isa_FPU, "", "", 0, 0, 0 , 0 , 0 } +}; + + +static ia32_insn_t tbl_0F0F[] = { /* 3D Now! 0F Suffix */ + /* 00 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_CONV, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pi2fd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 10 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_CONV, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pf2id", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 20 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 30 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 40 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 50 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 60 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 70 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + /* 80 */ { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_CMP, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfcmpge", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_MIN, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfmin", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfrcp", "", 0, 0, 0, 0, 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfrsqrt", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfsub", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfadd", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_CMP, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfcmpgt", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_MAX, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfmax", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfrcpit1", "", 0, 0, 0, 0, 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfrsqit1", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_SUB, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfsubr", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_ADD, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfacc", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_CMP, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfcmpeq", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_MUL, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfmul", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_ARITH, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pfrcpit2", "", 0, 0, 0, 0, 0 }, + { 0, INS_MUL, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pmulhrw", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_INVALID, 0, ARG_NONE, ARG_NONE, ARG_NONE, cpu_K6 | isa_3DNOW, "", "", 0, 0, 0, 0, 0 }, + { 0, INS_AVG, 0, ADDRMETH_P | OPTYPE_pi | OP_R | OP_W, ADDRMETH_Q | OPTYPE_q |OP_R, ARG_NONE, cpu_K6 | isa_3DNOW, "pavgusb", "", 0, 0, 0, 0, 0 } +}; + + + +/* ================== Table of Opcode Tables ================== */ +ia32_table_desc_t ia32_tables[] = { + /* table, prefix table, type, shift, mask, min, max */ + { tbl_Main, tbl_opcode, 0x00, 0xFF, 0x00, 0xFF }, + { tbl_66, tbl_prefix, 0x00, 0xFF, 0x0F, 0x0F }, + { tbl_F2, tbl_prefix, 0x00, 0xFF, 0x0F, 0x0F }, + { tbl_F3, tbl_prefix, 0x00, 0xFF, 0x0F, 0x90 }, + { tbl_0F, tbl_opcode, 0x00, 0xFF, 0x00, 0xFF }, + /* 5 */ + { tbl_660F, tbl_prefix, 0x00, 0xFF, 0x10, 0xFF }, + { tbl_F20F, tbl_prefix, 0x00, 0xFF, 0x10, 0xFF }, + { tbl_F30F, tbl_prefix, 0x00, 0xFF, 0x10, 0xFF }, + { tbl_0F00, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_0F01, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + /* 10 */ + { tbl_0F0111, tbl_ext_ext, 0x00, 0x01, 0x00, 0x01 }, + { tbl_0F12, tbl_extension, 0x06, 0x03, 0x00, 0x03 }, + { tbl_0F16, tbl_extension, 0x06, 0x03, 0x00, 0x03 }, + { tbl_0F18, tbl_extension, 0x03, 0x1F, 0x00, 0x13 }, + { tbl_0F71, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + /* 15 */ + { tbl_660F71, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + { tbl_0F72, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + { tbl_660F72, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + { tbl_0F73, tbl_extension, 0x00, 0x00, 0x00, 0x00 }, + { tbl_660F73, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + /* 20 */ + { tbl_0FAE, tbl_extension, 0x03, 0x1F, 0x00, 0x1F }, + { tbl_0FBA, tbl_extension, 0x03, 0x07, 0x04, 0x07 }, + { tbl_0FC7, tbl_extension, 0x03, 0x1F, 0x00, 0x11 }, + { tbl_0FB9, tbl_extension, 0x03, 0x07, 0x00, 0x00 }, + { tbl_C6, tbl_extension, 0x03, 0x07, 0x00, 0x00 }, + /* 25 */ + { tbl_C7, tbl_extension, 0x03, 0x07, 0x00, 0x00 }, + { tbl_80, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_81, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_82, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_83, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + /* 30 */ + { tbl_C0, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_C1, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_D0, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_D1, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_D2, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + /* 35 */ + { tbl_D3, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_F6, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_F7, tbl_extension, 0x03, 0x07, 0x00, 0x07 }, + { tbl_FE, tbl_extension, 0x03, 0x07, 0x00, 0x01 }, + { tbl_FF, tbl_extension, 0x03, 0x07, 0x00, 0x06 }, + /* 40 */ + { tbl_D8, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_D8C0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_D9, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_D9C0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_DA, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + /* 45 */ + { tbl_DAC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_DB, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_DBC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_DC, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_DCC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + /* 50 */ + { tbl_DD, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_DDC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_DE, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + { tbl_DEC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_DF, tbl_fpu, 0x03, 0x07, 0x00, 0xBF }, + /* 55 */ + { tbl_DFC0, tbl_fpu_ext, 0x00, 0xFF, 0xC0, 0xFF }, + { tbl_0F0F, tbl_suffix, 0x00, 0xFF, 0x00, 0xBF } +}; +/* ia32_opcode_tables.h */ +/* Table index constants: +#define idx_Main 0 +#define idx_66 1 +#define idx_F2 2 +#define idx_F3 3 +#define idx_0F 4 +#define idx_660F 5 +#define idx_F20F 6 +#define idx_F30F 7 +#define idx_0F00 8 +#define idx_0F01 9 +#define idx_0F0111 10 +#define idx_0F12 11 +#define idx_0F16 12 +#define idx_0F18 13 +#define idx_0F71 14 +#define idx_660F71 15 +#define idx_0F72 16 +#define idx_660F72 17 +#define idx_0F73 18 +#define idx_660F73 19 +#define idx_0FAE 20 +#define idx_0FBA 21 +#define idx_0FC7 22 +#define idx_0FB9 23 +#define idx_C6 24 +#define idx_C7 25 +#define idx_80 26 +#define idx_81 27 +#define idx_82 28 +#define idx_83 29 +#define idx_C0 30 +#define idx_C1 31 +#define idx_D0 32 +#define idx_D1 33 +#define idx_D2 34 +#define idx_D3 35 +#define idx_F6 36 +#define idx_F7 37 +#define idx_FE 38 +#define idx_FF 39 +#define idx_D8 40 +#define idx_D8C0 41 +#define idx_D9 42 +#define idx_D9C0 43 +#define idx_DA 44 +#define idx_DAC0 45 +#define idx_DB 46 +#define idx_DBC0 47 +#define idx_DC 48 +#define idx_DCC0 49 +#define idx_DD 50 +#define idx_DDC0 51 +#define idx_DE 52 +#define idx_DEC0 53 +#define idx_DF 54 +#define idx_DFC0 55 +#define idx_0F0F 56 +*/ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.h new file mode 100644 index 0000000000..bbd4fae9ab --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_opcode_tables.h @@ -0,0 +1,57 @@ +#define idx_Main 0 +#define idx_66 1 +#define idx_F2 2 +#define idx_F3 3 +#define idx_0F 4 +#define idx_660F 5 +#define idx_F20F 6 +#define idx_F30F 7 +#define idx_0F00 8 +#define idx_0F01 9 +#define idx_0F0111 10 +#define idx_0F12 11 +#define idx_0F16 12 +#define idx_0F18 13 +#define idx_0F71 14 +#define idx_660F71 15 +#define idx_0F72 16 +#define idx_660F72 17 +#define idx_0F73 18 +#define idx_660F73 19 +#define idx_0FAE 20 +#define idx_0FBA 21 +#define idx_0FC7 22 +#define idx_0FB9 23 +#define idx_C6 24 +#define idx_C7 25 +#define idx_80 26 +#define idx_81 27 +#define idx_82 28 +#define idx_83 29 +#define idx_C0 30 +#define idx_C1 31 +#define idx_D0 32 +#define idx_D1 33 +#define idx_D2 34 +#define idx_D3 35 +#define idx_F6 36 +#define idx_F7 37 +#define idx_FE 38 +#define idx_FF 39 +#define idx_D8 40 +#define idx_D8C0 41 +#define idx_D9 42 +#define idx_D9C0 43 +#define idx_DA 44 +#define idx_DAC0 45 +#define idx_DB 46 +#define idx_DBC0 47 +#define idx_DC 48 +#define idx_DCC0 49 +#define idx_DD 50 +#define idx_DDC0 51 +#define idx_DE 52 +#define idx_DEC0 53 +#define idx_DF 54 +#define idx_DFC0 55 +#define idx_0F0F 56 diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.c new file mode 100644 index 0000000000..8e7f16a0c0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.c @@ -0,0 +1,425 @@ +#include +#include +#include + +#include "libdis.h" +#include "ia32_insn.h" +#include "ia32_operand.h" +#include "ia32_modrm.h" +#include "ia32_reg.h" +#include "x86_imm.h" +#include "x86_operand_list.h" + + + +/* apply segment override to memory operand in insn */ +static void apply_seg( x86_op_t *op, unsigned int prefixes ) { + if (! prefixes ) return; + + /* apply overrides from prefix */ + switch ( prefixes & PREFIX_REG_MASK ) { + case PREFIX_CS: + op->flags |= op_cs_seg; break; + case PREFIX_SS: + op->flags |= op_ss_seg; break; + case PREFIX_DS: + op->flags |= op_ds_seg; break; + case PREFIX_ES: + op->flags |= op_es_seg; break; + case PREFIX_FS: + op->flags |= op_fs_seg; break; + case PREFIX_GS: + op->flags |= op_gs_seg; break; + } + + return; +} + +static size_t decode_operand_value( unsigned char *buf, size_t buf_len, + x86_op_t *op, x86_insn_t *insn, + unsigned int addr_meth, size_t op_size, + unsigned int op_value, unsigned char modrm, + size_t gen_regs ) { + size_t size = 0; + + /* ++ Do Operand Addressing Method / Decode operand ++ */ + switch (addr_meth) { + /* This sets the operand Size based on the Intel Opcode Map + * (Vol 2, Appendix A). Letter encodings are from section + * A.1.1, 'Codes for Addressing Method' */ + + /* ---------------------- Addressing Method -------------- */ + /* Note that decoding mod ModR/M operand adjusts the size of + * the instruction, but decoding the reg operand does not. + * This should not cause any problems, as every 'reg' operand + * has an associated 'mod' operand. + * Goddamn-Intel-Note: + * Some Intel addressing methods [M, R] specify that modR/M + * byte may only refer to a memory address/may only refer to + * a register -- however Intel provides no clues on what to do + * if, say, the modR/M for an M opcode decodes to a register + * rather than a memory address ... returning 0 is out of the + * question, as this would be an Immediate or a RelOffset, so + * instead these modR/Ms are decoded with total disregard to + * the M, R constraints. */ + + /* MODRM -- mod operand. sets size to at least 1! */ + case ADDRMETH_E: /* ModR/M present, Gen reg or memory */ + size = ia32_modrm_decode( buf, buf_len, op, insn, + gen_regs ); + break; + case ADDRMETH_M: /* ModR/M only refers to memory */ + size = ia32_modrm_decode( buf, buf_len, op, insn, + gen_regs ); + break; + case ADDRMETH_Q: /* ModR/M present, MMX or Memory */ + size = ia32_modrm_decode( buf, buf_len, op, insn, + REG_MMX_OFFSET ); + break; + case ADDRMETH_R: /* ModR/M mod == gen reg */ + size = ia32_modrm_decode( buf, buf_len, op, insn, + gen_regs ); + break; + case ADDRMETH_W: /* ModR/M present, mem or SIMD reg */ + size = ia32_modrm_decode( buf, buf_len, op, insn, + REG_SIMD_OFFSET ); + break; + + /* MODRM -- reg operand. does not effect size! */ + case ADDRMETH_C: /* ModR/M reg == control reg */ + ia32_reg_decode( modrm, op, REG_CTRL_OFFSET ); + break; + case ADDRMETH_D: /* ModR/M reg == debug reg */ + ia32_reg_decode( modrm, op, REG_DEBUG_OFFSET ); + break; + case ADDRMETH_G: /* ModR/M reg == gen-purpose reg */ + ia32_reg_decode( modrm, op, gen_regs ); + break; + case ADDRMETH_P: /* ModR/M reg == qword MMX reg */ + ia32_reg_decode( modrm, op, REG_MMX_OFFSET ); + break; + case ADDRMETH_S: /* ModR/M reg == segment reg */ + ia32_reg_decode( modrm, op, REG_SEG_OFFSET ); + break; + case ADDRMETH_T: /* ModR/M reg == test reg */ + ia32_reg_decode( modrm, op, REG_TEST_OFFSET ); + break; + case ADDRMETH_V: /* ModR/M reg == SIMD reg */ + ia32_reg_decode( modrm, op, REG_SIMD_OFFSET ); + break; + + /* No MODRM : note these set operand type explicitly */ + case ADDRMETH_A: /* No modR/M -- direct addr */ + op->type = op_absolute; + + /* segment:offset address used in far calls */ + x86_imm_sized( buf, buf_len, + &op->data.absolute.segment, 2 ); + if ( insn->addr_size == 4 ) { + x86_imm_sized( buf, buf_len, + &op->data.absolute.offset.off32, 4 ); + size = 6; + } else { + x86_imm_sized( buf, buf_len, + &op->data.absolute.offset.off16, 2 ); + size = 4; + } + + break; + case ADDRMETH_I: /* Immediate val */ + op->type = op_immediate; + /* if it ever becomes legal to have imm as dest and + * there is a src ModR/M operand, we are screwed! */ + if ( op->flags & op_signed ) { + x86_imm_signsized(buf, buf_len, &op->data.byte, + op_size); + } else { + x86_imm_sized(buf, buf_len, &op->data.byte, + op_size); + } + size = op_size; + break; + case ADDRMETH_J: /* Rel offset to add to IP [jmp] */ + /* this fills op->data.near_offset or + op->data.far_offset depending on the size of + the operand */ + op->flags |= op_signed; + if ( op_size == 1 ) { + /* one-byte near offset */ + op->type = op_relative_near; + x86_imm_signsized(buf, buf_len, + &op->data.relative_near, 1); + } else { + /* far offset...is this truly signed? */ + op->type = op_relative_far; + x86_imm_signsized(buf, buf_len, + &op->data.relative_far, op_size ); + } + size = op_size; + break; + case ADDRMETH_O: /* No ModR/M; op is word/dword offset */ + /* NOTE: these are actually RVAs not offsets to seg!! */ + /* note bene: 'O' ADDR_METH uses addr_size to + determine operand size */ + op->type = op_offset; + op->flags |= op_pointer; + x86_imm_sized( buf, buf_len, &op->data.offset, + insn->addr_size ); + + size = insn->addr_size; + break; + + /* Hard-coded: these are specified in the insn definition */ + case ADDRMETH_F: /* EFLAGS register */ + op->type = op_register; + op->flags |= op_hardcode; + ia32_handle_register( &op->data.reg, REG_FLAGS_INDEX ); + break; + case ADDRMETH_X: /* Memory addressed by DS:SI [string] */ + op->type = op_expression; + op->flags |= op_hardcode; + op->flags |= op_ds_seg | op_pointer | op_string; + ia32_handle_register( &op->data.expression.base, + REG_DWORD_OFFSET + 6 ); + break; + case ADDRMETH_Y: /* Memory addressed by ES:DI [string] */ + op->type = op_expression; + op->flags |= op_hardcode; + op->flags |= op_es_seg | op_pointer | op_string; + ia32_handle_register( &op->data.expression.base, + REG_DWORD_OFFSET + 7 ); + break; + case ADDRMETH_RR: /* Gen Register hard-coded in opcode */ + op->type = op_register; + op->flags |= op_hardcode; + ia32_handle_register( &op->data.reg, + op_value + gen_regs ); + break; + case ADDRMETH_RS: /* Seg Register hard-coded in opcode */ + op->type = op_register; + op->flags |= op_hardcode; + ia32_handle_register( &op->data.reg, + op_value + REG_SEG_OFFSET ); + break; + case ADDRMETH_RF: /* FPU Register hard-coded in opcode */ + op->type = op_register; + op->flags |= op_hardcode; + ia32_handle_register( &op->data.reg, + op_value + REG_FPU_OFFSET ); + break; + case ADDRMETH_RT: /* TST Register hard-coded in opcode */ + op->type = op_register; + op->flags |= op_hardcode; + ia32_handle_register( &op->data.reg, + op_value + REG_TEST_OFFSET ); + break; + case ADDRMETH_II: /* Immediate hard-coded in opcode */ + op->type = op_immediate; + op->data.dword = op_value; + op->flags |= op_hardcode; + break; + + case 0: /* Operand is not used */ + default: + /* ignore -- operand not used in this insn */ + op->type = op_unused; /* this shouldn't happen! */ + break; + } + + return size; +} + +static size_t decode_operand_size( unsigned int op_type, x86_insn_t *insn, + x86_op_t *op ){ + size_t size; + + /* ++ Do Operand Type ++ */ + switch (op_type) { + /* This sets the operand Size based on the Intel Opcode Map + * (Vol 2, Appendix A). Letter encodings are from section + * A.1.2, 'Codes for Operand Type' */ + /* NOTE: in this routines, 'size' refers to the size + * of the operand in the raw (encoded) instruction; + * 'datatype' stores the actual size and datatype + * of the operand */ + + /* ------------------------ Operand Type ----------------- */ + case OPTYPE_c: /* byte or word [op size attr] */ + size = (insn->op_size == 4) ? 2 : 1; + op->datatype = (size == 4) ? op_word : op_byte; + break; + case OPTYPE_a: /* 2 word or 2 dword [op size attr] */ + /* pointer to a 16:16 or 32:32 BOUNDS operand */ + size = (insn->op_size == 4) ? 8 : 4; + op->datatype = (size == 4) ? op_bounds32 : op_bounds16; + break; + case OPTYPE_v: /* word or dword [op size attr] */ + size = (insn->op_size == 4) ? 4 : 2; + op->datatype = (size == 4) ? op_dword : op_word; + break; + case OPTYPE_p: /* 32/48-bit ptr [op size attr] */ + /* technically these flags are not accurate: the + * value s a 16:16 pointer or a 16:32 pointer, where + * the first '16' is a segment */ + size = (insn->addr_size == 4) ? 6 : 4; + op->datatype = (size == 4) ? op_descr32 : op_descr16; + break; + case OPTYPE_b: /* byte, ignore op-size */ + size = 1; + op->datatype = op_byte; + break; + case OPTYPE_w: /* word, ignore op-size */ + size = 2; + op->datatype = op_word; + break; + case OPTYPE_d: /* dword , ignore op-size */ + size = 4; + op->datatype = op_dword; + break; + case OPTYPE_s: /* 6-byte psuedo-descriptor */ + /* ptr to 6-byte value which is 32:16 in 32-bit + * mode, or 8:24:16 in 16-bit mode. The high byte + * is ignored in 16-bit mode. */ + size = 6; + op->datatype = (insn->addr_size == 4) ? + op_pdescr32 : op_pdescr16; + break; + case OPTYPE_q: /* qword, ignore op-size */ + size = 8; + op->datatype = op_qword; + break; + case OPTYPE_dq: /* d-qword, ignore op-size */ + size = 16; + op->datatype = op_dqword; + break; + case OPTYPE_ps: /* 128-bit FP data */ + size = 16; + /* really this is 4 packed SP FP values */ + op->datatype = op_ssimd; + break; + case OPTYPE_pd: /* 128-bit FP data */ + size = 16; + /* really this is 2 packed DP FP values */ + op->datatype = op_dsimd; + break; + case OPTYPE_ss: /* Scalar elem of 128-bit FP data */ + size = 16; + /* this only looks at the low dword (4 bytes) + * of the xmmm register passed as a param. + * This is a 16-byte register where only 4 bytes + * are used in the insn. Painful, ain't it? */ + op->datatype = op_sssimd; + break; + case OPTYPE_sd: /* Scalar elem of 128-bit FP data */ + size = 16; + /* this only looks at the low qword (8 bytes) + * of the xmmm register passed as a param. + * This is a 16-byte register where only 8 bytes + * are used in the insn. Painful, again... */ + op->datatype = op_sdsimd; + break; + case OPTYPE_pi: /* qword mmx register */ + size = 8; + op->datatype = op_qword; + break; + case OPTYPE_si: /* dword integer register */ + size = 4; + op->datatype = op_dword; + break; + case OPTYPE_fs: /* single-real */ + size = 4; + op->datatype = op_sreal; + break; + case OPTYPE_fd: /* double real */ + size = 8; + op->datatype = op_dreal; + break; + case OPTYPE_fe: /* extended real */ + size = 10; + op->datatype = op_extreal; + break; + case OPTYPE_fb: /* packed BCD */ + size = 10; + op->datatype = op_bcd; + break; + case OPTYPE_fv: /* pointer to FPU env: 14 or 28-bytes */ + size = (insn->addr_size == 4)? 28 : 14; + op->datatype = (size == 28)? op_fpuenv32: op_fpuenv16; + break; + case OPTYPE_ft: /* pointer to FPU env: 94 or 108 bytes */ + size = (insn->addr_size == 4)? 108 : 94; + op->datatype = (size == 108)? + op_fpustate32: op_fpustate16; + break; + case OPTYPE_fx: /* 512-byte register stack */ + size = 512; + op->datatype = op_fpregset; + break; + case OPTYPE_fp: /* floating point register */ + size = 10; /* double extended precision */ + op->datatype = op_fpreg; + break; + case OPTYPE_m: /* fake operand type used for "lea Gv, M" */ + size = insn->addr_size; + op->datatype = (size == 4) ? op_dword : op_word; + break; + case OPTYPE_none: /* handle weird instructions that have no encoding but use a dword datatype, like invlpg */ + size = 0; + op->datatype = op_none; + break; + case 0: + default: + size = insn->op_size; + op->datatype = (size == 4) ? op_dword : op_word; + break; + } + return size; +} + +size_t ia32_decode_operand( unsigned char *buf, size_t buf_len, + x86_insn_t *insn, unsigned int raw_op, + unsigned int raw_flags, unsigned int prefixes, + unsigned char modrm ) { + unsigned int addr_meth, op_type, op_size, gen_regs; + x86_op_t *op; + size_t size; + + /* ++ Yank optype and addr mode out of operand flags */ + addr_meth = raw_flags & ADDRMETH_MASK; + op_type = raw_flags & OPTYPE_MASK; + + if ( raw_flags == ARG_NONE ) { + /* operand is not used in this instruction */ + return 0; + } + + /* allocate a new operand */ + op = x86_operand_new( insn ); + + /* ++ Copy flags from opcode table to x86_insn_t */ + op->access = (enum x86_op_access) OP_PERM(raw_flags); + op->flags = (enum x86_op_flags) (OP_FLAGS(raw_flags) >> 12); + + /* Get size (for decoding) and datatype of operand */ + op_size = decode_operand_size(op_type, insn, op); + + /* override default register set based on Operand Type */ + /* this allows mixing of 8, 16, and 32 bit regs in insn */ + if (op_size == 1) { + gen_regs = REG_BYTE_OFFSET; + } else if (op_size == 2) { + gen_regs = REG_WORD_OFFSET; + } else { + gen_regs = REG_DWORD_OFFSET; + } + + size = decode_operand_value( buf, buf_len, op, insn, addr_meth, + op_size, raw_op, modrm, gen_regs ); + + /* if operand is an address, apply any segment override prefixes */ + if ( op->type == op_expression || op->type == op_offset ) { + apply_seg(op, prefixes); + } + + return size; /* return number of bytes in instruction */ +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.h new file mode 100644 index 0000000000..08c3074cd7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_operand.h @@ -0,0 +1,11 @@ +#ifndef IA32_OPERAND_H +#define IA32_OPERAND_H + +#include "libdis.h" +#include "ia32_insn.h" + +size_t ia32_decode_operand( unsigned char *buf, size_t buf_len, + x86_insn_t *insn, unsigned int raw_op, + unsigned int raw_flags, unsigned int prefixes, + unsigned char modrm ); +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.c new file mode 100644 index 0000000000..f270c1f346 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.c @@ -0,0 +1,234 @@ +#include +#include + +#include "ia32_reg.h" +#include "ia32_insn.h" + +#define NUM_X86_REGS 92 + +/* register sizes */ +#define REG_DWORD_SIZE 4 +#define REG_WORD_SIZE 2 +#define REG_BYTE_SIZE 1 +#define REG_MMX_SIZE 8 +#define REG_SIMD_SIZE 16 +#define REG_DEBUG_SIZE 4 +#define REG_CTRL_SIZE 4 +#define REG_TEST_SIZE 4 +#define REG_SEG_SIZE 2 +#define REG_FPU_SIZE 10 +#define REG_FLAGS_SIZE 4 +#define REG_FPCTRL_SIZE 2 +#define REG_FPSTATUS_SIZE 2 +#define REG_FPTAG_SIZE 2 +#define REG_EIP_SIZE 4 +#define REG_IP_SIZE 2 + +/* REGISTER ALIAS TABLE: + * + * NOTE: the MMX register mapping is fixed to the physical registers + * used by the FPU. The floating FP stack does not effect the location + * of the MMX registers, so this aliasing is not 100% accurate. + * */ +static struct { + unsigned char alias; /* id of register this is an alias for */ + unsigned char shift; /* # of bits register must be shifted */ +} ia32_reg_aliases[] = { + { 0,0 }, + { REG_DWORD_OFFSET, 0 }, /* al : 1 */ + { REG_DWORD_OFFSET, 8 }, /* ah : 2 */ + { REG_DWORD_OFFSET, 0 }, /* ax : 3 */ + { REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */ + { REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */ + { REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */ + { REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */ + { REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */ + { REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */ + { REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */ + { REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */ + { REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */ + { REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */ + { REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */ + { REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */ + { REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */ + { REG_EIP_INDEX, 0 }, /* ip : 17 */ + { REG_FPU_OFFSET, 0 }, /* mm0 : 18 */ + { REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */ + { REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */ + { REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */ + { REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */ + { REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */ + { REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */ + { REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */ + }; + +/* REGISTER TABLE: size, type, and name of every register in the + * CPU. Does not include MSRs since the are, after all, + * model specific. */ +static struct { + unsigned int size; + enum x86_reg_type type; + unsigned int alias; + char mnemonic[8]; +} ia32_reg_table[NUM_X86_REGS + 2] = { + { 0, 0, 0, "" }, + /* REG_DWORD_OFFSET */ + { REG_DWORD_SIZE, reg_gen | reg_ret, 0, "eax" }, + { REG_DWORD_SIZE, reg_gen | reg_count, 0, "ecx" }, + { REG_DWORD_SIZE, reg_gen, 0, "edx" }, + { REG_DWORD_SIZE, reg_gen, 0, "ebx" }, + /* REG_ESP_INDEX */ + { REG_DWORD_SIZE, reg_gen | reg_sp, 0, "esp" }, + { REG_DWORD_SIZE, reg_gen | reg_fp, 0, "ebp" }, + { REG_DWORD_SIZE, reg_gen | reg_src, 0, "esi" }, + { REG_DWORD_SIZE, reg_gen | reg_dest, 0, "edi" }, + /* REG_WORD_OFFSET */ + { REG_WORD_SIZE, reg_gen | reg_ret, 3, "ax" }, + { REG_WORD_SIZE, reg_gen | reg_count, 6, "cx" }, + { REG_WORD_SIZE, reg_gen, 9, "dx" }, + { REG_WORD_SIZE, reg_gen, 12, "bx" }, + { REG_WORD_SIZE, reg_gen | reg_sp, 13, "sp" }, + { REG_WORD_SIZE, reg_gen | reg_fp, 14, "bp" }, + { REG_WORD_SIZE, reg_gen | reg_src, 15, "si" }, + { REG_WORD_SIZE, reg_gen | reg_dest, 16, "di" }, + /* REG_BYTE_OFFSET */ + { REG_BYTE_SIZE, reg_gen, 1, "al" }, + { REG_BYTE_SIZE, reg_gen, 4, "cl" }, + { REG_BYTE_SIZE, reg_gen, 7, "dl" }, + { REG_BYTE_SIZE, reg_gen, 10, "bl" }, + { REG_BYTE_SIZE, reg_gen, 2, "ah" }, + { REG_BYTE_SIZE, reg_gen, 5, "ch" }, + { REG_BYTE_SIZE, reg_gen, 8, "dh" }, + { REG_BYTE_SIZE, reg_gen, 11, "bh" }, + /* REG_MMX_OFFSET */ + { REG_MMX_SIZE, reg_simd, 18, "mm0" }, + { REG_MMX_SIZE, reg_simd, 19, "mm1" }, + { REG_MMX_SIZE, reg_simd, 20, "mm2" }, + { REG_MMX_SIZE, reg_simd, 21, "mm3" }, + { REG_MMX_SIZE, reg_simd, 22, "mm4" }, + { REG_MMX_SIZE, reg_simd, 23, "mm5" }, + { REG_MMX_SIZE, reg_simd, 24, "mm6" }, + { REG_MMX_SIZE, reg_simd, 25, "mm7" }, + /* REG_SIMD_OFFSET */ + { REG_SIMD_SIZE, reg_simd, 0, "xmm0" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm1" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm2" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm3" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm4" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm5" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm6" }, + { REG_SIMD_SIZE, reg_simd, 0, "xmm7" }, + /* REG_DEBUG_OFFSET */ + { REG_DEBUG_SIZE, reg_sys, 0, "dr0" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr1" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr2" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr3" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr4" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr5" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr6" }, + { REG_DEBUG_SIZE, reg_sys, 0, "dr7" }, + /* REG_CTRL_OFFSET */ + { REG_CTRL_SIZE, reg_sys, 0, "cr0" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr1" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr2" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr3" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr4" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr5" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr6" }, + { REG_CTRL_SIZE, reg_sys, 0, "cr7" }, + /* REG_TEST_OFFSET */ + { REG_TEST_SIZE, reg_sys, 0, "tr0" }, + { REG_TEST_SIZE, reg_sys, 0, "tr1" }, + { REG_TEST_SIZE, reg_sys, 0, "tr2" }, + { REG_TEST_SIZE, reg_sys, 0, "tr3" }, + { REG_TEST_SIZE, reg_sys, 0, "tr4" }, + { REG_TEST_SIZE, reg_sys, 0, "tr5" }, + { REG_TEST_SIZE, reg_sys, 0, "tr6" }, + { REG_TEST_SIZE, reg_sys, 0, "tr7" }, + /* REG_SEG_OFFSET */ + { REG_SEG_SIZE, reg_seg, 0, "es" }, + { REG_SEG_SIZE, reg_seg, 0, "cs" }, + { REG_SEG_SIZE, reg_seg, 0, "ss" }, + { REG_SEG_SIZE, reg_seg, 0, "ds" }, + { REG_SEG_SIZE, reg_seg, 0, "fs" }, + { REG_SEG_SIZE, reg_seg, 0, "gs" }, + /* REG_LDTR_INDEX */ + { REG_DWORD_SIZE, reg_sys, 0, "ldtr" }, + /* REG_GDTR_INDEX */ + { REG_DWORD_SIZE, reg_sys, 0, "gdtr" }, + /* REG_FPU_OFFSET */ + { REG_FPU_SIZE, reg_fpu, 0, "st(0)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(1)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(2)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(3)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(4)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(5)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(6)" }, + { REG_FPU_SIZE, reg_fpu, 0, "st(7)" }, + /* REG_FLAGS_INDEX : 81 */ + { REG_FLAGS_SIZE, reg_cond, 0, "eflags" }, + /* REG_FPCTRL_INDEX : 82*/ + { REG_FPCTRL_SIZE, reg_fpu | reg_sys, 0, "fpctrl" }, + /* REG_FPSTATUS_INDEX : 83*/ + { REG_FPSTATUS_SIZE, reg_fpu | reg_sys, 0, "fpstat" }, + /* REG_FPTAG_INDEX : 84 */ + { REG_FPTAG_SIZE, reg_fpu | reg_sys, 0, "fptag" }, + /* REG_EIP_INDEX : 85 */ + { REG_EIP_SIZE, reg_pc, 0, "eip" }, + /* REG_IP_INDEX : 86 */ + { REG_IP_SIZE, reg_pc, 17, "ip" }, + /* REG_IDTR_INDEX : 87 */ + { REG_DWORD_SIZE, reg_sys, 0, "idtr" }, + /* REG_MXCSG_INDEX : SSE Control Reg : 88 */ + { REG_DWORD_SIZE, reg_sys | reg_simd, 0, "mxcsr" }, + /* REG_TR_INDEX : Task Register : 89 */ + { 16 + 64, reg_sys, 0, "tr" }, + /* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */ + { REG_DWORD_SIZE, reg_sys, 0, "cs_msr" }, + /* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */ + { REG_DWORD_SIZE, reg_sys, 0, "esp_msr" }, + /* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */ + { REG_DWORD_SIZE, reg_sys, 0, "eip_msr" }, + { 0 } + }; + + +static size_t sz_regtable = NUM_X86_REGS + 1; + + +void ia32_handle_register( x86_reg_t *reg, size_t id ) { + unsigned int alias; + if (! id || id > sz_regtable ) { + return; + } + + memset( reg, 0, sizeof(x86_reg_t) ); + + strncpy( reg->name, ia32_reg_table[id].mnemonic, MAX_REGNAME ); + + reg->type = ia32_reg_table[id].type; + reg->size = ia32_reg_table[id].size; + + alias = ia32_reg_table[id].alias; + if ( alias ) { + reg->alias = ia32_reg_aliases[alias].alias; + reg->shift = ia32_reg_aliases[alias].shift; + } + reg->id = id; + + return; +} + +size_t ia32_true_register_id( size_t id ) { + size_t reg; + + if (! id || id > sz_regtable ) { + return 0; + } + + reg = id; + if (ia32_reg_table[reg].alias) { + reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias; + } + return reg; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.h new file mode 100644 index 0000000000..fbbc77a178 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_reg.h @@ -0,0 +1,41 @@ +#ifndef IA32_REG_H +#define IA32_REG_H + +#include /* for size_t */ +#include "libdis.h" /* for x86_reg_t */ + +/* NOTE these are used in opcode tables for hard-coded registers */ +#define REG_DWORD_OFFSET 1 /* 0 + 1 */ +#define REG_ECX_INDEX 2 /* 0 + 1 + 1 */ +#define REG_ESP_INDEX 5 /* 0 + 4 + 1 */ +#define REG_EBP_INDEX 6 /* 0 + 5 + 1 */ +#define REG_ESI_INDEX 7 /* 0 + 6 + 1 */ +#define REG_EDI_INDEX 8 /* 0 + 7 + 1 */ +#define REG_WORD_OFFSET 9 /* 1 * 8 + 1 */ +#define REG_BYTE_OFFSET 17 /* 2 * 8 + 1 */ +#define REG_MMX_OFFSET 25 /* 3 * 8 + 1 */ +#define REG_SIMD_OFFSET 33 /* 4 * 8 + 1 */ +#define REG_DEBUG_OFFSET 41 /* 5 * 8 + 1 */ +#define REG_CTRL_OFFSET 49 /* 6 * 8 + 1 */ +#define REG_TEST_OFFSET 57 /* 7 * 8 + 1 */ +#define REG_SEG_OFFSET 65 /* 8 * 8 + 1 */ +#define REG_LDTR_INDEX 71 /* 8 * 8 + 1 + 1 */ +#define REG_GDTR_INDEX 72 /* 8 * 8 + 2 + 1 */ +#define REG_FPU_OFFSET 73 /* 9 * 8 + 1 */ +#define REG_FLAGS_INDEX 81 /* 10 * 8 + 1 */ +#define REG_FPCTRL_INDEX 82 /* 10 * 8 + 1 + 1 */ +#define REG_FPSTATUS_INDEX 83 /* 10 * 8 + 2 + 1 */ +#define REG_FPTAG_INDEX 84 /* 10 * 8 + 3 + 1 */ +#define REG_EIP_INDEX 85 /* 10 * 8 + 4 + 1 */ +#define REG_IP_INDEX 86 /* 10 * 8 + 5 + 1 */ +#define REG_IDTR_INDEX 87 /* 10 * 8 + 6 + 1 */ +#define REG_MXCSG_INDEX 88 /* 10 * 8 + 7 + 1 */ +#define REG_TR_INDEX 89 /* 10 * 8 + 8 + 1 */ +#define REG_CSMSR_INDEX 90 /* 10 * 8 + 9 + 1 */ +#define REG_ESPMSR_INDEX 91 /* 10 * 8 + 10 + 1 */ +#define REG_EIPMSR_INDEX 92 /* 10 * 8 + 11 + 1 */ + +void ia32_handle_register( x86_reg_t *reg, size_t id ); +size_t ia32_true_register_id( size_t id ); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.c new file mode 100644 index 0000000000..b578e34488 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.c @@ -0,0 +1,13 @@ +#include "libdis.h" +#include "ia32_settings.h" +#include "ia32_reg.h" +#include "ia32_insn.h" + +ia32_settings_t ia32_settings = { + 1, 0xF4, + MAX_INSTRUCTION_SIZE, + 4, 4, 8, 4, 8, + REG_ESP_INDEX, REG_EBP_INDEX, REG_EIP_INDEX, REG_FLAGS_INDEX, + REG_DWORD_OFFSET, REG_SEG_OFFSET, REG_FPU_OFFSET, + opt_none +}; diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.h new file mode 100644 index 0000000000..769c0e9fa0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_settings.h @@ -0,0 +1,27 @@ +#ifndef IA32_SETTINGS_H +#define IA32_SETTINGS_H + +#include "libdis.h" + +typedef struct { + /* options */ + unsigned char endian, /* 0 = big, 1 = little */ + wc_byte, /* wildcard byte */ + max_insn, /* max insn size */ + sz_addr, /* default address size */ + sz_oper, /* default operand size */ + sz_byte, /* # bits in byte */ + sz_word, /* # bytes in machine word */ + sz_dword; /* # bytes in machine dword */ + unsigned int id_sp_reg, /* id of stack pointer */ + id_fp_reg, /* id of frame pointer */ + id_ip_reg, /* id of instruction pointer */ + id_flag_reg, /* id of flags register */ + offset_gen_regs, /* start of general regs */ + offset_seg_regs, /* start of segment regs */ + offset_fpu_regs; /* start of floating point regs */ + /* user-controlled settings */ + enum x86_options options; +} ia32_settings_t; + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdis.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdis.h new file mode 100644 index 0000000000..83a88612a3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdis.h @@ -0,0 +1,832 @@ +#ifndef LIBDISASM_H +#define LIBDISASM_H + +#include + +/* 'NEW" types + * __________________________________________________________________________*/ +#ifndef LIBDISASM_QWORD_H /* do not interfere with qword.h */ + #define LIBDISASM_QWORD_H + #ifdef _MSC_VER + typedef __int64 qword_t; + #else + typedef int64_t qword_t; + #endif +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* 'NEW" x86 API + * __________________________________________________________________________*/ + + +/* ========================================= Error Reporting */ +/* REPORT CODES + * These are passed to a reporter function passed at initialization. + * Each code determines the type of the argument passed to the reporter; + * this allows the report to recover from errors, or just log them. + */ +enum x86_report_codes { + report_disasm_bounds, /* RVA OUT OF BOUNDS : The disassembler could + not disassemble the supplied RVA as it is + out of the range of the buffer. The + application should store the address and + attempt to determine what section of the + binary it is in, then disassemble the + address from the bytes in that section. + data: uint32_t rva */ + report_insn_bounds, /* INSTRUCTION OUT OF BOUNDS: The disassembler + could not disassemble the instruction as + the instruction would require bytes beyond + the end of the current buffer. This usually + indicated garbage bytes at the end of a + buffer, or an incorrectly-sized buffer. + data: uint32_t rva */ + report_invalid_insn, /* INVALID INSTRUCTION: The disassembler could + not disassemble the instruction as it has an + invalid combination of opcodes and operands. + This will stop automated disassembly; the + application can restart the disassembly + after the invalid instruction. + data: uint32_t rva */ + report_unknown +}; + +/* 'arg' is optional arbitrary data provided by the code passing the + * callback -- for example, it could be 'this' or 'self' in OOP code. + * 'code' is provided by libdisasm, it is one of the above + * 'data' is provided by libdisasm and is context-specific, per the enums */ +typedef void (*DISASM_REPORTER)( enum x86_report_codes code, + void *data, void *arg ); + + +/* x86_report_error : Call the register reporter to report an error */ +void x86_report_error( enum x86_report_codes code, void *data ); + +/* ========================================= Libdisasm Management Routines */ +enum x86_options { /* these can be ORed together */ + opt_none= 0, + opt_ignore_nulls=1, /* ignore sequences of > 4 NULL bytes */ + opt_16_bit=2, /* 16-bit/DOS disassembly */ + opt_att_mnemonics=4, /* use AT&T syntax names for alternate opcode mnemonics */ +}; + +/* management routines */ +/* 'arg' is caller-specific data which is passed as the first argument + * to the reporter callback routine */ +int x86_init( enum x86_options options, DISASM_REPORTER reporter, void *arg); +void x86_set_reporter( DISASM_REPORTER reporter, void *arg); +void x86_set_options( enum x86_options options ); +enum x86_options x86_get_options( void ); +int x86_cleanup(void); + + +/* ========================================= Instruction Representation */ +/* these defines are only intended for use in the array decl's */ +#define MAX_REGNAME 8 + +#define MAX_PREFIX_STR 32 +#define MAX_MNEM_STR 16 +#define MAX_INSN_SIZE 20 /* same as in i386.h */ +#define MAX_OP_STRING 32 /* max possible operand size in string form */ +#define MAX_OP_RAW_STRING 64 /* max possible operand size in raw form */ +#define MAX_OP_XML_STRING 256 /* max possible operand size in xml form */ +#define MAX_NUM_OPERANDS 8 /* max # implicit and explicit operands */ +/* in these, the '2 *' is arbitrary: the max # of operands should require + * more space than the rest of the insn */ +#define MAX_INSN_STRING 512 /* 2 * 8 * MAX_OP_STRING */ +#define MAX_INSN_RAW_STRING 1024 /* 2 * 8 * MAX_OP_RAW_STRING */ +#define MAX_INSN_XML_STRING 4096 /* 2 * 8 * MAX_OP_XML_STRING */ + +enum x86_reg_type { /* NOTE: these may be ORed together */ + reg_gen = 0x00001, /* general purpose */ + reg_in = 0x00002, /* incoming args, ala RISC */ + reg_out = 0x00004, /* args to calls, ala RISC */ + reg_local = 0x00008, /* local vars, ala RISC */ + reg_fpu = 0x00010, /* FPU data register */ + reg_seg = 0x00020, /* segment register */ + reg_simd = 0x00040, /* SIMD/MMX reg */ + reg_sys = 0x00080, /* restricted/system register */ + reg_sp = 0x00100, /* stack pointer */ + reg_fp = 0x00200, /* frame pointer */ + reg_pc = 0x00400, /* program counter */ + reg_retaddr = 0x00800, /* return addr for func */ + reg_cond = 0x01000, /* condition code / flags */ + reg_zero = 0x02000, /* zero register, ala RISC */ + reg_ret = 0x04000, /* return value */ + reg_src = 0x10000, /* array/rep source */ + reg_dest = 0x20000, /* array/rep destination */ + reg_count = 0x40000 /* array/rep/loop counter */ +}; + +/* x86_reg_t : an X86 CPU register */ +typedef struct { + char name[MAX_REGNAME]; + enum x86_reg_type type; /* what register is used for */ + unsigned int size; /* size of register in bytes */ + unsigned int id; /* register ID #, for quick compares */ + unsigned int alias; /* ID of reg this is an alias for */ + unsigned int shift; /* amount to shift aliased reg by */ +} x86_reg_t; + +/* x86_ea_t : an X86 effective address (address expression) */ +typedef struct { + unsigned int scale; /* scale factor */ + x86_reg_t index, base; /* index, base registers */ + int32_t disp; /* displacement */ + char disp_sign; /* is negative? 1/0 */ + char disp_size; /* 0, 1, 2, 4 */ +} x86_ea_t; + +/* x86_absolute_t : an X86 segment:offset address (descriptor) */ +typedef struct { + unsigned short segment; /* loaded directly into CS */ + union { + unsigned short off16; /* loaded directly into IP */ + uint32_t off32; /* loaded directly into EIP */ + } offset; +} x86_absolute_t; + +enum x86_op_type { /* mutually exclusive */ + op_unused = 0, /* empty/unused operand: should never occur */ + op_register = 1, /* CPU register */ + op_immediate = 2, /* Immediate Value */ + op_relative_near = 3, /* Relative offset from IP */ + op_relative_far = 4, /* Relative offset from IP */ + op_absolute = 5, /* Absolute address (ptr16:32) */ + op_expression = 6, /* Address expression (scale/index/base/disp) */ + op_offset = 7, /* Offset from start of segment (m32) */ + op_unknown +}; + +#define x86_optype_is_address( optype ) \ + ( optype == op_absolute || optype == op_offset ) +#define x86_optype_is_relative( optype ) \ + ( optype == op_relative_near || optype == op_relative_far ) +#define x86_optype_is_memory( optype ) \ + ( optype > op_immediate && optype < op_unknown ) + +enum x86_op_datatype { /* these use Intel's lame terminology */ + op_byte = 1, /* 1 byte integer */ + op_word = 2, /* 2 byte integer */ + op_dword = 3, /* 4 byte integer */ + op_qword = 4, /* 8 byte integer */ + op_dqword = 5, /* 16 byte integer */ + op_sreal = 6, /* 4 byte real (single real) */ + op_dreal = 7, /* 8 byte real (double real) */ + op_extreal = 8, /* 10 byte real (extended real) */ + op_bcd = 9, /* 10 byte binary-coded decimal */ + op_ssimd = 10, /* 16 byte : 4 packed single FP (SIMD, MMX) */ + op_dsimd = 11, /* 16 byte : 2 packed double FP (SIMD, MMX) */ + op_sssimd = 12, /* 4 byte : scalar single FP (SIMD, MMX) */ + op_sdsimd = 13, /* 8 byte : scalar double FP (SIMD, MMX) */ + op_descr32 = 14, /* 6 byte Intel descriptor 2:4 */ + op_descr16 = 15, /* 4 byte Intel descriptor 2:2 */ + op_pdescr32 = 16, /* 6 byte Intel pseudo-descriptor 32:16 */ + op_pdescr16 = 17, /* 6 byte Intel pseudo-descriptor 8:24:16 */ + op_bounds16 = 18, /* signed 16:16 lower:upper bounds */ + op_bounds32 = 19, /* signed 32:32 lower:upper bounds */ + op_fpuenv16 = 20, /* 14 byte FPU control/environment data */ + op_fpuenv32 = 21, /* 28 byte FPU control/environment data */ + op_fpustate16 = 22, /* 94 byte FPU state (env & reg stack) */ + op_fpustate32 = 23, /* 108 byte FPU state (env & reg stack) */ + op_fpregset = 24, /* 512 bytes: register set */ + op_fpreg = 25, /* FPU register */ + op_none = 0xFF, /* operand without a datatype (INVLPG) */ +}; + +enum x86_op_access { /* ORed together */ + op_read = 1, + op_write = 2, + op_execute = 4 +}; + +enum x86_op_flags { /* ORed together, but segs are mutually exclusive */ + op_signed = 1, /* signed integer */ + op_string = 2, /* possible string or array */ + op_constant = 4, /* symbolic constant */ + op_pointer = 8, /* operand points to a memory address */ + op_sysref = 0x010, /* operand is a syscall number */ + op_implied = 0x020, /* operand is implicit in the insn */ + op_hardcode = 0x40, /* operand is hardcoded in insn definition */ + /* NOTE: an 'implied' operand is one which can be considered a side + * effect of the insn, e.g. %esp being modified by PUSH or POP. A + * 'hard-coded' operand is one which is specified in the instruction + * definition, e.g. %es:%edi in MOVSB or 1 in ROL Eb, 1. The difference + * is that hard-coded operands are printed by disassemblers and are + * required to re-assemble, while implicit operands are invisible. */ + op_es_seg = 0x100, /* ES segment override */ + op_cs_seg = 0x200, /* CS segment override */ + op_ss_seg = 0x300, /* SS segment override */ + op_ds_seg = 0x400, /* DS segment override */ + op_fs_seg = 0x500, /* FS segment override */ + op_gs_seg = 0x600 /* GS segment override */ +}; + +/* x86_op_t : an X86 instruction operand */ +typedef struct { + enum x86_op_type type; /* operand type */ + enum x86_op_datatype datatype; /* operand size */ + enum x86_op_access access; /* operand access [RWX] */ + enum x86_op_flags flags; /* misc flags */ + union { + /* sizeof will have to work on these union members! */ + /* immediate values */ + char sbyte; + short sword; + int32_t sdword; + qword_t sqword; + unsigned char byte; + unsigned short word; + uint32_t dword; + qword_t qword; + float sreal; + double dreal; + /* misc large/non-native types */ + unsigned char extreal[10]; + unsigned char bcd[10]; + qword_t dqword[2]; + unsigned char simd[16]; + unsigned char fpuenv[28]; + /* offset from segment */ + uint32_t offset; + /* ID of CPU register */ + x86_reg_t reg; + /* offsets from current insn */ + char relative_near; + int32_t relative_far; + /* segment:offset */ + x86_absolute_t absolute; + /* effective address [expression] */ + x86_ea_t expression; + } data; + /* this is needed to make formatting operands more sane */ + void * insn; /* pointer to x86_insn_t owning operand */ +} x86_op_t; + +/* Linked list of x86_op_t; provided for manual traversal of the operand + * list in an insn. Users wishing to add operands to this list, e.g. to add + * implicit operands, should use x86_operand_new in x86_operand_list.h */ +typedef struct x86_operand_list { + x86_op_t op; + struct x86_operand_list *next; +} x86_oplist_t; + +enum x86_insn_group { + insn_none = 0, /* invalid instruction */ + insn_controlflow = 1, + insn_arithmetic = 2, + insn_logic = 3, + insn_stack = 4, + insn_comparison = 5, + insn_move = 6, + insn_string = 7, + insn_bit_manip = 8, + insn_flag_manip = 9, + insn_fpu = 10, + insn_interrupt = 13, + insn_system = 14, + insn_other = 15 +}; + +enum x86_insn_type { + insn_invalid = 0, /* invalid instruction */ + /* insn_controlflow */ + insn_jmp = 0x1001, + insn_jcc = 0x1002, + insn_call = 0x1003, + insn_callcc = 0x1004, + insn_return = 0x1005, + /* insn_arithmetic */ + insn_add = 0x2001, + insn_sub = 0x2002, + insn_mul = 0x2003, + insn_div = 0x2004, + insn_inc = 0x2005, + insn_dec = 0x2006, + insn_shl = 0x2007, + insn_shr = 0x2008, + insn_rol = 0x2009, + insn_ror = 0x200A, + /* insn_logic */ + insn_and = 0x3001, + insn_or = 0x3002, + insn_xor = 0x3003, + insn_not = 0x3004, + insn_neg = 0x3005, + /* insn_stack */ + insn_push = 0x4001, + insn_pop = 0x4002, + insn_pushregs = 0x4003, + insn_popregs = 0x4004, + insn_pushflags = 0x4005, + insn_popflags = 0x4006, + insn_enter = 0x4007, + insn_leave = 0x4008, + /* insn_comparison */ + insn_test = 0x5001, + insn_cmp = 0x5002, + /* insn_move */ + insn_mov = 0x6001, /* move */ + insn_movcc = 0x6002, /* conditional move */ + insn_xchg = 0x6003, /* exchange */ + insn_xchgcc = 0x6004, /* conditional exchange */ + /* insn_string */ + insn_strcmp = 0x7001, + insn_strload = 0x7002, + insn_strmov = 0x7003, + insn_strstore = 0x7004, + insn_translate = 0x7005, /* xlat */ + /* insn_bit_manip */ + insn_bittest = 0x8001, + insn_bitset = 0x8002, + insn_bitclear = 0x8003, + /* insn_flag_manip */ + insn_clear_carry = 0x9001, + insn_clear_zero = 0x9002, + insn_clear_oflow = 0x9003, + insn_clear_dir = 0x9004, + insn_clear_sign = 0x9005, + insn_clear_parity = 0x9006, + insn_set_carry = 0x9007, + insn_set_zero = 0x9008, + insn_set_oflow = 0x9009, + insn_set_dir = 0x900A, + insn_set_sign = 0x900B, + insn_set_parity = 0x900C, + insn_tog_carry = 0x9010, + insn_tog_zero = 0x9020, + insn_tog_oflow = 0x9030, + insn_tog_dir = 0x9040, + insn_tog_sign = 0x9050, + insn_tog_parity = 0x9060, + /* insn_fpu */ + insn_fmov = 0xA001, + insn_fmovcc = 0xA002, + insn_fneg = 0xA003, + insn_fabs = 0xA004, + insn_fadd = 0xA005, + insn_fsub = 0xA006, + insn_fmul = 0xA007, + insn_fdiv = 0xA008, + insn_fsqrt = 0xA009, + insn_fcmp = 0xA00A, + insn_fcos = 0xA00C, + insn_fldpi = 0xA00D, + insn_fldz = 0xA00E, + insn_ftan = 0xA00F, + insn_fsine = 0xA010, + insn_fsys = 0xA020, + /* insn_interrupt */ + insn_int = 0xD001, + insn_intcc = 0xD002, /* not present in x86 ISA */ + insn_iret = 0xD003, + insn_bound = 0xD004, + insn_debug = 0xD005, + insn_trace = 0xD006, + insn_invalid_op = 0xD007, + insn_oflow = 0xD008, + /* insn_system */ + insn_halt = 0xE001, + insn_in = 0xE002, /* input from port/bus */ + insn_out = 0xE003, /* output to port/bus */ + insn_cpuid = 0xE004, + /* insn_other */ + insn_nop = 0xF001, + insn_bcdconv = 0xF002, /* convert to or from BCD */ + insn_szconv = 0xF003 /* change size of operand */ +}; + +/* These flags specify special characteristics of the instruction, such as + * whether the inatruction is privileged or whether it serializes the + * pipeline. + * NOTE : These may not be accurate for all instructions; updates to the + * opcode tables have not been completed. */ +enum x86_insn_note { + insn_note_ring0 = 1, /* Only available in ring 0 */ + insn_note_smm = 2, /* "" in System Management Mode */ + insn_note_serial = 4, /* Serializing instruction */ + insn_note_nonswap = 8, /* Does not swap arguments in att-style formatting */ + insn_note_nosuffix = 16, /* Does not have size suffix in att-style formatting */ +}; + +/* This specifies what effects the instruction has on the %eflags register */ +enum x86_flag_status { + insn_carry_set = 0x1, /* CF */ + insn_zero_set = 0x2, /* ZF */ + insn_oflow_set = 0x4, /* OF */ + insn_dir_set = 0x8, /* DF */ + insn_sign_set = 0x10, /* SF */ + insn_parity_set = 0x20, /* PF */ + insn_carry_or_zero_set = 0x40, + insn_zero_set_or_sign_ne_oflow = 0x80, + insn_carry_clear = 0x100, + insn_zero_clear = 0x200, + insn_oflow_clear = 0x400, + insn_dir_clear = 0x800, + insn_sign_clear = 0x1000, + insn_parity_clear = 0x2000, + insn_sign_eq_oflow = 0x4000, + insn_sign_ne_oflow = 0x8000 +}; + +/* The CPU model in which the insturction first appeared; this can be used + * to mask out instructions appearing in earlier or later models or to + * check the portability of a binary. + * NOTE : These may not be accurate for all instructions; updates to the + * opcode tables have not been completed. */ +enum x86_insn_cpu { + cpu_8086 = 1, /* Intel */ + cpu_80286 = 2, + cpu_80386 = 3, + cpu_80387 = 4, + cpu_80486 = 5, + cpu_pentium = 6, + cpu_pentiumpro = 7, + cpu_pentium2 = 8, + cpu_pentium3 = 9, + cpu_pentium4 = 10, + cpu_k6 = 16, /* AMD */ + cpu_k7 = 32, + cpu_athlon = 48 +}; + +/* CPU ISA subsets: These are derived from the Instruction Groups in + * Intel Vol 1 Chapter 5; they represent subsets of the IA32 ISA but + * do not reflect the 'type' of the instruction in the same way that + * x86_insn_group does. In short, these are AMD/Intel's somewhat useless + * designations. + * NOTE : These may not be accurate for all instructions; updates to the + * opcode tables have not been completed. */ +enum x86_insn_isa { + isa_gp = 1, /* general purpose */ + isa_fp = 2, /* floating point */ + isa_fpumgt = 3, /* FPU/SIMD management */ + isa_mmx = 4, /* Intel MMX */ + isa_sse1 = 5, /* Intel SSE SIMD */ + isa_sse2 = 6, /* Intel SSE2 SIMD */ + isa_sse3 = 7, /* Intel SSE3 SIMD */ + isa_3dnow = 8, /* AMD 3DNow! SIMD */ + isa_sys = 9 /* system instructions */ +}; + +enum x86_insn_prefix { + insn_no_prefix = 0, + insn_rep_zero = 1, /* REPZ and REPE */ + insn_rep_notzero = 2, /* REPNZ and REPNZ */ + insn_lock = 4 /* LOCK: */ +}; + +/* TODO: maybe provide insn_new/free(), and have disasm return new insn_t */ +/* x86_insn_t : an X86 instruction */ +typedef struct { + /* information about the instruction */ + uint32_t addr; /* load address */ + uint32_t offset; /* offset into file/buffer */ + enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */ + enum x86_insn_type type; /* type, e.g. INS_BRANCH */ + enum x86_insn_note note; /* note, e.g. RING0 */ + unsigned char bytes[MAX_INSN_SIZE]; + unsigned char size; /* size of insn in bytes */ + /* 16/32-bit mode settings */ + unsigned char addr_size; /* default address size : 2 or 4 */ + unsigned char op_size; /* default operand size : 2 or 4 */ + /* CPU/instruction set */ + enum x86_insn_cpu cpu; + enum x86_insn_isa isa; + /* flags */ + enum x86_flag_status flags_set; /* flags set or tested by insn */ + enum x86_flag_status flags_tested; + /* stack */ + unsigned char stack_mod; /* 0 or 1 : is the stack modified? */ + int32_t stack_mod_val; /* val stack is modified by if known */ + + /* the instruction proper */ + enum x86_insn_prefix prefix; /* prefixes ORed together */ + char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */ + char mnemonic[MAX_MNEM_STR]; + x86_oplist_t *operands; /* list of explicit/implicit operands */ + size_t operand_count; /* total number of operands */ + size_t explicit_count; /* number of explicit operands */ + /* convenience fields for user */ + void *block; /* code block containing this insn */ + void *function; /* function containing this insn */ + int tag; /* tag the insn as seen/processed */ +} x86_insn_t; + + +/* returns 0 if an instruction is invalid, 1 if valid */ +int x86_insn_is_valid( x86_insn_t *insn ); + +/* DISASSEMBLY ROUTINES + * Canonical order of arguments is + * (buf, buf_len, buf_rva, offset, len, insn, func, arg, resolve_func) + * ...but of course all of these are not used at the same time. + */ + + +/* Function prototype for caller-supplied callback routine + * These callbacks are intended to process 'insn' further, e.g. by + * adding it to a linked list, database, etc */ +typedef void (*DISASM_CALLBACK)( x86_insn_t *insn, void * arg ); + +/* Function prototype for caller-supplied address resolver. + * This routine is used to determine the rva to disassemble next, given + * the 'dest' operand of a jump/call. This allows the caller to resolve + * jump/call targets stored in a register or on the stack, and also allows + * the caller to prevent endless loops by checking if an address has + * already been disassembled. If an address cannot be resolved from the + * operand, or if the address has already been disassembled, this routine + * should return -1; in all other cases the RVA to be disassembled next + * should be returned. */ +typedef int32_t (*DISASM_RESOLVER)( x86_op_t *op, x86_insn_t * current_insn, + void *arg ); + + +/* x86_disasm: Disassemble a single instruction from a buffer of bytes. + * Returns size of instruction in bytes. + * Caller is responsible for calling x86_oplist_free() on + * a reused "insn" to avoid leaking memory when calling this + * function repeatedly. + * buf : Buffer of bytes to disassemble + * buf_len : Length of the buffer + * buf_rva : Load address of the start of the buffer + * offset : Offset in buffer to disassemble + * insn : Structure to fill with disassembled instruction + */ +unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len, + uint32_t buf_rva, unsigned int offset, + x86_insn_t * insn ); + +/* x86_disasm_range: Sequential disassembly of a range of bytes in a buffer, + * invoking a callback function each time an instruction + * is successfully disassembled. The 'range' refers to the + * bytes between 'offset' and 'offset + len' in the buffer; + * 'len' is assumed to be less than the length of the buffer. + * Returns number of instructions processed. + * buf : Buffer of bytes to disassemble (e.g. .text section) + * buf_rva : Load address of buffer (e.g. ELF Virtual Address) + * offset : Offset in buffer to start disassembly at + * len : Number of bytes to disassemble + * func : Callback function to invoke (may be NULL) + * arg : Arbitrary data to pass to callback (may be NULL) + */ +unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva, + unsigned int offset, unsigned int len, + DISASM_CALLBACK func, void *arg ); + +/* x86_disasm_forward: Flow-of-execution disassembly of the bytes in a buffer, + * invoking a callback function each time an instruction + * is successfully disassembled. + * buf : Buffer to disassemble (e.g. .text section) + * buf_len : Number of bytes in buffer + * buf_rva : Load address of buffer (e.g. ELF Virtual Address) + * offset : Offset in buffer to start disassembly at (e.g. entry point) + * func : Callback function to invoke (may be NULL) + * arg : Arbitrary data to pass to callback (may be NULL) + * resolver: Caller-supplied address resolver. If no resolver is + * supplied, a default internal one is used -- however the + * internal resolver does NOT catch loops and could end up + * disassembling forever.. + * r_arg : Arbitrary data to pass to resolver (may be NULL) + */ +unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len, + uint32_t buf_rva, unsigned int offset, + DISASM_CALLBACK func, void *arg, + DISASM_RESOLVER resolver, void *r_arg ); + +/* Instruction operands: these are stored as a list of explicit and + * implicit operands. It is recommended that the 'foreach' routines + * be used to when examining operands for purposes of data flow analysis */ + +/* Operand FOREACH callback: 'arg' is an abritrary parameter passed to the + * foreach routine, 'insn' is the x86_insn_t whose operands are being + * iterated over, and 'op' is the current x86_op_t */ +typedef void (*x86_operand_fn)(x86_op_t *op, x86_insn_t *insn, void *arg); + +/* FOREACH types: these are used to limit the foreach results to + * operands which match a certain "type" (implicit or explicit) + * or which are accessed in certain ways (e.g. read or write). Note + * that this operates on the operand list of single instruction, so + * specifying the 'real' operand type (register, memory, etc) is not + * useful. Note also that by definition Execute Access implies Read + * Access and implies Not Write Access. + * The "type" (implicit or explicit) and the access method can + * be ORed together, e.g. op_wo | op_explicit */ +enum x86_op_foreach_type { + op_any = 0, /* ALL operands (explicit, implicit, rwx) */ + op_dest = 1, /* operands with Write access */ + op_src = 2, /* operands with Read access */ + op_ro = 3, /* operands with Read but not Write access */ + op_wo = 4, /* operands with Write but not Read access */ + op_xo = 5, /* operands with Execute access */ + op_rw = 6, /* operands with Read AND Write access */ + op_implicit = 0x10, /* operands that are implied by the opcode */ + op_explicit = 0x20 /* operands that are not side-effects */ +}; + + +/* free the operand list associated with an instruction -- useful for + * preventing memory leaks when free()ing an x86_insn_t */ +void x86_oplist_free( x86_insn_t *insn ); + +/* Operand foreach: invokes 'func' with 'insn' and 'arg' as arguments. The + * 'type' parameter is used to select only operands matching specific + * criteria. */ +int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg, + enum x86_op_foreach_type type); + +/* convenience routine: returns count of operands matching 'type' */ +size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type ); + +/* accessor functions for the operands */ +x86_op_t * x86_operand_1st( x86_insn_t *insn ); +x86_op_t * x86_operand_2nd( x86_insn_t *insn ); +x86_op_t * x86_operand_3rd( x86_insn_t *insn ); + +/* these allow libdisasm 2.0 accessor functions to still be used */ +#define x86_get_dest_operand( insn ) x86_operand_1st( insn ) +#define x86_get_src_operand( insn ) x86_operand_2nd( insn ) +#define x86_get_imm_operand( insn ) x86_operand_3rd( insn ) + +/* get size of operand data in bytes */ +unsigned int x86_operand_size( x86_op_t *op ); + +/* Operand Convenience Routines: the following three routines are common + * operations on operands, intended to ease the burden of the programmer. */ + +/* Get Address: return the value of an offset operand, or the offset of + * a segment:offset absolute address */ +uint32_t x86_get_address( x86_insn_t *insn ); + +/* Get Relative Offset: return as a sign-extended int32_t the near or far + * relative offset operand, or 0 if there is none. There can be only one + * relaive offset operand in an instruction. */ +int32_t x86_get_rel_offset( x86_insn_t *insn ); + +/* Get Branch Target: return the x86_op_t containing the target of + * a jump or call operand, or NULL if there is no branch target. + * Internally, a 'branch target' is defined as any operand with + * Execute Access set. There can be only one branch target per instruction. */ +x86_op_t * x86_get_branch_target( x86_insn_t *insn ); + +/* Get Immediate: return the x86_op_t containing the immediate operand + * for this instruction, or NULL if there is no immediate operand. There + * can be only one immediate operand per instruction */ +x86_op_t * x86_get_imm( x86_insn_t *insn ); + +/* Get Raw Immediate Data: returns a pointer to the immediate data encoded + * in the instruction. This is useful for large data types [>32 bits] currently + * not supported by libdisasm, or for determining if the disassembler + * screwed up the conversion of the immediate data. Note that 'imm' in this + * context refers to immediate data encoded at the end of an instruction as + * detailed in the Intel Manual Vol II Chapter 2; it does not refer to the + * 'op_imm' operand (the third operand in instructions like 'mul' */ +unsigned char * x86_get_raw_imm( x86_insn_t *insn ); + + +/* More accessor fuctions, this time for user-defined info... */ +/* set the address (usually RVA) of the insn */ +void x86_set_insn_addr( x86_insn_t *insn, uint32_t addr ); + +/* set the offset (usually offset into file) of the insn */ +void x86_set_insn_offset( x86_insn_t *insn, unsigned int offset ); + +/* set a pointer to the function owning the instruction. The + * type of 'func' is user-defined; libdisasm does not use the func field. */ +void x86_set_insn_function( x86_insn_t *insn, void * func ); + +/* set a pointer to the block of code owning the instruction. The + * type of 'block' is user-defined; libdisasm does not use the block field. */ +void x86_set_insn_block( x86_insn_t *insn, void * block ); + +/* instruction tagging: these routines allow the programmer to mark + * instructions as "seen" in a DFS, for example. libdisasm does not use + * the tag field.*/ +/* set insn->tag to 1 */ +void x86_tag_insn( x86_insn_t *insn ); +/* set insn->tag to 0 */ +void x86_untag_insn( x86_insn_t *insn ); +/* return insn->tag */ +int x86_insn_is_tagged( x86_insn_t *insn ); + + +/* Disassembly formats: + * AT&T is standard AS/GAS-style: "mnemonic\tsrc, dest, imm" + * Intel is standard MASM/NASM/TASM: "mnemonic\tdest,src, imm" + * Native is tab-delimited: "RVA\tbytes\tmnemonic\tdest\tsrc\timm" + * XML is your typical ... + * Raw is addr|offset|size|bytes|prefix... see libdisasm_formats.7 + */ +enum x86_asm_format { + unknown_syntax = 0, /* never use! */ + native_syntax, /* header: 35 bytes */ + intel_syntax, /* header: 23 bytes */ + att_syntax, /* header: 23 bytes */ + xml_syntax, /* header: 679 bytes */ + raw_syntax /* header: 172 bytes */ +}; + +/* format (sprintf) an operand into 'buf' using specified syntax */ +int x86_format_operand(x86_op_t *op, char *buf, int len, + enum x86_asm_format format); + +/* format (sprintf) an instruction mnemonic into 'buf' using specified syntax */ +int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len, + enum x86_asm_format format); + +/* format (sprintf) an instruction into 'buf' using specified syntax; + * this includes formatting all operands */ +int x86_format_insn(x86_insn_t *insn, char *buf, int len, enum x86_asm_format); + +/* fill 'buf' with a description of the format's syntax */ +int x86_format_header( char *buf, int len, enum x86_asm_format format); + +/* Endianness of an x86 CPU : 0 is big, 1 is little; always returns 1 */ +unsigned int x86_endian(void); + +/* Default address and operand size in bytes */ +unsigned int x86_addr_size(void); +unsigned int x86_op_size(void); + +/* Size of a machine word in bytes */ +unsigned int x86_word_size(void); + +/* maximum size of a code instruction */ +#define x86_max_inst_size(x) x86_max_insn_size(x) +unsigned int x86_max_insn_size(void); + +/* register IDs of Stack, Frame, Instruction pointer and Flags register */ +unsigned int x86_sp_reg(void); +unsigned int x86_fp_reg(void); +unsigned int x86_ip_reg(void); +unsigned int x86_flag_reg(void); + +/* fill 'reg' struct with details of register 'id' */ +void x86_reg_from_id( unsigned int id, x86_reg_t * reg ); + +/* convenience macro demonstrating how to get an aliased register; proto is + * void x86_get_aliased_reg( x86_reg_t *alias_reg, x86_reg_t *output_reg ) + * where 'alias_reg' is a reg operand and 'output_reg' is filled with the + * register that the operand is an alias for */ +#define x86_get_aliased_reg( alias_reg, output_reg ) \ + x86_reg_from_id( alias_reg->alias, output_reg ) + + +/* ================================== Invariant Instruction Representation */ +/* Invariant instructions are used for generating binary signatures; + * the instruction is modified so that all variant bytes in an instruction + * are replaced with a wildcard byte. + * + * A 'variant byte' is one that is expected to be modified by either the + * static or the dynamic linker: for example, an address encoded in an + * instruction. + * + * By comparing the invariant representation of one instruction [or of a + * sequence of instructions] with the invariant representation of another, + * one determine whether the two invariant representations are from the same + * relocatable object [.o] file. Thus one can use binary signatures [which + * are just sequences of invariant instruction representations] to look for + * library routines which have been statically-linked into a binary. + * + * The invariant routines are faster and smaller than the disassembly + * routines; they can be used to determine the size of an instruction + * without all of the overhead of a full instruction disassembly. + */ + +/* This byte is used to replace variant bytes */ +#define X86_WILDCARD_BYTE 0xF4 + +typedef struct { + enum x86_op_type type; /* operand type */ + enum x86_op_datatype datatype; /* operand size */ + enum x86_op_access access; /* operand access [RWX] */ + enum x86_op_flags flags; /* misc flags */ +} x86_invariant_op_t; + +typedef struct { + unsigned char bytes[64]; /* invariant representation */ + unsigned int size; /* number of bytes in insn */ + enum x86_insn_group group; /* meta-type, e.g. INS_EXEC */ + enum x86_insn_type type; /* type, e.g. INS_BRANCH */ + x86_invariant_op_t operands[3]; /* operands: dest, src, imm */ +} x86_invariant_t; + + +/* return a version of the instruction with the variant bytes masked out */ +size_t x86_invariant_disasm( unsigned char *buf, int buf_len, + x86_invariant_t *inv ); +/* return the size in bytes of the intruction pointed to by 'buf'; + * this used x86_invariant_disasm since it faster than x86_disasm */ +size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdisasm.gyp b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdisasm.gyp new file mode 100644 index 0000000000..5c8dc45867 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/libdisasm.gyp @@ -0,0 +1,67 @@ +# Copyright 2014 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. + +{ + 'includes': [ + '../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'libdisasm', + 'type': 'static_library', + 'sources': [ + 'ia32_implicit.c', + 'ia32_implicit.h', + 'ia32_insn.c', + 'ia32_insn.h', + 'ia32_invariant.c', + 'ia32_invariant.h', + 'ia32_modrm.c', + 'ia32_modrm.h', + 'ia32_opcode_tables.c', + 'ia32_opcode_tables.h', + 'ia32_operand.c', + 'ia32_operand.h', + 'ia32_reg.c', + 'ia32_reg.h', + 'ia32_settings.c', + 'ia32_settings.h', + 'libdis.h', + 'qword.h', + 'x86_disasm.c', + 'x86_format.c', + 'x86_imm.c', + 'x86_imm.h', + 'x86_insn.c', + 'x86_misc.c', + 'x86_operand_list.c', + 'x86_operand_list.h', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/qword.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/qword.h new file mode 100644 index 0000000000..5f0e803c93 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/qword.h @@ -0,0 +1,14 @@ +#ifndef LIBDISASM_QWORD_H +#define LIBDISASM_QWORD_H + +#include + +/* platform independent data types */ + +#ifdef _MSC_VER + typedef __int64 qword_t; +#else + typedef int64_t qword_t; +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/Makefile b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/Makefile new file mode 100644 index 0000000000..44ef486b6a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/Makefile @@ -0,0 +1,70 @@ +# change these values if you need to +SWIG = swig # apt-get install swig ! +GCC = gcc + +CC_FLAGS = -c -fPIC +LD_FLAGS = -shared -L../.. -ldisasm + +BASE_NAME = x86disasm + +export INTERFACE_FILE BASE_NAME SWIG GCC CC_FLAGS LD_FLAGS + +#==================================================== +# TARGETS + +all: swig +dummy: swig swig-python swig-ruby swig-perl swig-tcl install uninstall clean + +swig: swig-python swig-perl +# swig-rub swig-tcl + +swig-python: + cd python && make -f Makefile-swig + +swig-ruby: + cd ruby && make -f Makefile-swig + +swig-perl: + cd perl && make -f Makefile-swig + +swig-tcl: + cd tcl && make -f Makefile-swig + +# ================================================================== +install: install-python install-perl +# install-ruby install-tcl + +install-python: + cd python && sudo make -f Makefile-swig install + +install-ruby: + cd ruby && sudo make -f Makefile-swig install + +install-perl: + cd perl && sudo make -f Makefile-swig install + +install-tcl: + cd tcl && sudo make -f Makefile-swig install + +# ================================================================== +uninstall: uninstall-python +#uninstall-ruby uninstall-perl uninstall-tcl + +uninstall-python: + cd python && sudo make -f Makefile-swig uninstall + +uninstall-ruby: + cd ruby && sudo make -f Makefile-swig uninstall + +uninstall-perl: + cd perl && sudo make -f Makefile-swig uninstall + +uninstall-tcl: + cd tcl && sudo make -f Makefile-swig uninstall + +# ================================================================== +clean: + cd python && make -f Makefile-swig clean + cd ruby && make -f Makefile-swig clean + cd perl && make -f Makefile-swig clean + cd tcl && make -f Makefile-swig clean diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/README b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/README new file mode 100644 index 0000000000..a9fa79ec2c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/README @@ -0,0 +1,128 @@ + Libdisasm SWIG README + +The SWIG utility (www.swig.org) can be used to generate + + +Building SWIG Modules +--------------------- + + make + make install + +Make and Install both build Python, Perl, Ruby, and Tcl modules. If you +do not have one of these languages installed, comment out the relevant +target in the main Makefile. + +Install uses 'sudo' to put files in the correct locations; if you +do not have sudo installed, change the install targets. + +The Module API +-------------- + +The OOP API +----------- + + +The Python Module +----------------- + +To test that the module loads: + + bash# python + >>> import x86disasm + >>> x86disasm.version_string() + '0.21-pre' + >>>^D + bash# + + >>> import x86disasm + >>> import array + >>> disasm = x86disasm.X86_Disasm( ) + >>> tgt = open( "/tmp/a.out", "rb" ) + >>> tgt.seek( 0, 2 ) + >>> size = tgt.tell() + >>> tgt.seek( 0, 0 ) + >>> buf = array.array( 'B' ) + >>> buf.fromfile( tgt, size ) + >>> tgt.close() + >>> data = x86disasm.byteArray( size ) + >>> for i in range( size ): + ... data[i] = buf.pop(0) + ... + >>> del buf + >>> del tgt + >>> insn = disasm.disasm( data, size - 1, 0, 0 ) + >>> insn.format( x86disasm.att_syntax ) + 'jg\t0x00000047' + >>> insn.format( x86disasm.raw_syntax ) + '0x00000000|0x00000000|2|7F 45 |||controlflow|jcc|jg|80386|General Purpose|||zero_clear sign_eq_oflow |0|0|relative|sbyte|00000047|' + >>> ops = insn.operand_list() + >>> node = ops.first() + >>> while node is not None: + ... s = node.op.format(x86disasm.raw_syntax) + ... print s + ... node = ops.next() + ... + relative|sbyte|00000047| + + + + + + +The Perl Module +--------------- + +To test that the module loads: + + bash# perl + use x86disasm; + print x86disasm::version_string() . "\n"; + ^D + 0.21-pre + bash# + +The Ruby Module +--------------- + +To test that the module loads: + + bash# irb + irb(main):001:0> require 'x86disasm' + => true + irb(main):002:0> X86disasm.version_string() + => "0.21-pre" + irb(main):003:0> x = X86disasm::X86_Disasm.new + => # + irb(main):004:0> x.max_register_string() + => 8 + irb(main):003:0> ^D + bash# + +The Tcl Module +--------------- + +To test that the module loads: + + bash# tclsh + % load /usr/lib/tcl8.3/x86disasm.so X86disasm + % version_string + 0.21-pre + % ^D + bash# + + % x86_init 0 NULL NULL + OR + % x86disasm dis + _486b0708_p_x86disasm + % puts "[dis cget -last_error]" + 0 + + + + +The Interface Files +------------------- + + libdisasm.i -- interface file without shadow classes + libdisasm_oop.i -- interface file with shadow classes diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm.i b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm.i new file mode 100644 index 0000000000..ec12041755 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm.i @@ -0,0 +1,508 @@ +%module x86disasm +%{ +#include "../../libdis.h" +#include "../../../config.h" +%} + +%rename(version_string) x86_version_string; +%include "../../libdis.h" +#include "../../../config.h" + +%inline %{ + const char * x86_version_string( void ) { + return PACKAGE_VERSION; + } +%} + +%rename(report_codes) x86_report_codes; +%rename(report_error) x86_report_error; +%rename(options) x86_options; +%rename(init) x86_init; +%rename(set_reporter) x86_set_reporter; +%rename(set_options) x86_set_options; +%rename(options) x86_get_options; +%rename(cleanup) x86_cleanup; +%rename(reg_type) x86_reg_type; +%rename(reg) x86_reg_t; +%rename(eaddr) x86_ea_t; +%rename(op_type) x86_op_type; +%rename(optype_is_address) x86_optype_is_address; +%rename(optype_is_relative) x86_optype_is_relative; +%rename(op_datatype) x86_op_datatype; +%rename(op_access) x86_op_access; +%rename(op_flags) x86_op_flags; +%rename(operand) x86_op_t; +%rename(insn_group) x86_insn_group; +%rename(insn_type) x86_insn_type; +%rename(insn_note) x86_insn_note ; +%rename(flag_status) x86_flag_status; +%rename(insn_cpu) x86_insn_cpu ; +%rename(insn_isa) x86_insn_isa ; +%rename(insn_prefix) x86_insn_prefix ; +%rename(insn) x86_insn_t; +%rename(insn_is_valid) x86_insn_is_valid; +%rename(i_disasm) x86_disasm; +%rename(i_disasm_range) x86_disasm_range; +%rename(i_disasm_forward) x86_disasm_forward; +%rename(insn_operand_count) x86_operand_count; +%rename(insn_operand_1st) x86_operand_1st; +%rename(insn_operand_2nd) x86_operand_2nd; +%rename(insn_operand_3rd) x86_operand_3rd; +%rename(insn_dest_operand) x86_get_dest_operand; +%rename(insn_src_operand) x86_get_src_operand; +%rename(insn_imm_operand) x86_get_imm_operand; +%rename(operand_size) x86_operand_size; +%rename(insn_rel_offset) x86_get_rel_offset; +%rename(insn_branch_target) x86_get_branch_target; +%rename(insn_imm) x86_get_imm; +%rename(insn_raw_imm) x86_get_raw_imm; +%rename(insn_set_addr) x86_set_insn_addr; +%rename(insn_set_offset) x86_set_insn_offset; +%rename(insn_set_function) x86_set_insn_function; +%rename(insn_set_block) x86_set_insn_block; +%rename(insn_tag) x86_tag_insn; +%rename(insn_untag) x86_untag_insn; +%rename(insn_is_tagged) x86_insn_is_tagged; +%rename(asm_format) x86_asm_format; +%rename(operand_format) x86_format_operand; +%rename(insn_format_mnemonic) x86_format_mnemonic; +%rename(insn_format) x86_format_insn; +%rename(header_format) x86_format_header; +%rename(endian) x86_endian; +%rename(size_default_address) x86_addr_size; +%rename(size_default_operand) x86_op_size; +%rename(size_machine_word) x86_word_size; +%rename(size_max_insn) x86_max_insn_size; +%rename(reg_sp) x86_sp_reg; +%rename(reg_fp) x86_fp_reg; +%rename(reg_ip) x86_ip_reg; +%rename(reg_from_id) x86_reg_from_id; +%rename(reg_from_alias) x86_get_aliased_reg; +%rename(invariant_op) x86_invariant_op_t; +%rename(invariant) x86_invariant_t; +%rename(disasm_invariant) x86_invariant_disasm; +%rename(disasm_size) x86_size_disasm; + +%include "carrays.i" + +%array_class( unsigned char, byteArray ); + + +%apply (unsigned char *STRING, int LENGTH) { + (unsigned char *buf, size_t buf_len) +}; + + +%newobject x86_op_copy; +%inline %{ + x86_op_t * x86_op_copy( x86_op_t * src ) { + x86_op_t *op; + + if (! src ) { + return NULL; + } + + op = (x86_op_t *) calloc( sizeof(x86_op_t), 1 ); + if ( op ) { + memcpy( op, src, sizeof(x86_op_t) ); + } + + return op; + } + + typedef struct x86_op_list_node { + x86_op_t *op; + struct x86_op_list_node *next, *prev; + } x86_op_list_node; + + typedef struct x86_op_list { + size_t count; + x86_op_list_node *head, *tail, *curr; + } x86_op_list; + + x86_op_list * x86_op_list_new () { + x86_op_list *list = (x86_op_list *) + calloc( sizeof(x86_op_list), 1 ); + list->count = 0; + return list; + } + + void x86_op_list_free(x86_op_list *list) { + x86_op_list_node *node, *next; + + node = list->head; + while ( node ) { + next = node->next; + /* free( node->insn ); */ + free( node ); + node = next; + } + + free( list ); + } + + x86_op_list_node * x86_op_list_first(x86_op_list *list) { + return list->head; + } + + x86_op_list_node * x86_op_list_last(x86_op_list *list) { + return list->tail; + } + + x86_op_list_node * x86_op_list_next(x86_op_list *list) { + if (! list->curr ) { + list->curr = list->head; + return list->head; + } + + list->curr = list->curr->next; + return list->curr; + } + + x86_op_list_node * x86_op_list_prev(x86_op_list *list) { + if (! list->curr ) { + list->curr = list->tail; + return list->tail; + } + + list->curr = list->curr->prev; + return list->curr; + } + +%} + +%newobject x86_op_list_append; + +%inline %{ + void x86_op_list_append( x86_op_list * list, x86_op_t *op ) { + x86_op_list_node *node = (x86_op_list_node *) + calloc( sizeof(x86_op_list_node) , 1 ); + if (! node ) { + return; + } + + list->count++; + if ( ! list->tail ) { + list->head = list->tail = node; + } else { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } + + node->op = x86_op_copy( op ); + } + + x86_oplist_t * x86_op_list_node_copy( x86_oplist_t * list ) { + x86_oplist_t *ptr; + ptr = (x86_oplist_t *) calloc( sizeof(x86_oplist_t), 1 ); + if ( ptr ) { + memcpy( &ptr->op, &list->op, sizeof(x86_op_t) ); + } + + return ptr; + } + + x86_insn_t * x86_insn_new() { + x86_insn_t *insn = (x86_insn_t *) + calloc( sizeof(x86_insn_t), 1 ); + return insn; + } + + void x86_insn_free( x86_insn_t *insn ) { + x86_oplist_free( insn ); + free( insn ); + } +%} + +%newobject x86_insn_copy; + +%inline %{ + x86_insn_t * x86_insn_copy( x86_insn_t *src) { + x86_oplist_t *ptr, *list, *last = NULL; + x86_insn_t *insn = (x86_insn_t *) + calloc( sizeof(x86_insn_t), 1 ); + + if ( insn ) { + memcpy( insn, src, sizeof(x86_insn_t) ); + insn->operands = NULL; + insn->block = NULL; + insn->function = NULL; + + /* copy operand list */ + for ( list = src->operands; list; list = list->next ) { + ptr = x86_op_list_node_copy( list ); + + if (! ptr ) { + continue; + } + + if ( insn->operands ) { + last->next = ptr; + } else { + insn->operands = ptr; + } + last = ptr; + } + } + + return insn; + } + + x86_op_list * x86_insn_op_list( x86_insn_t *insn ) { + x86_oplist_t *list = insn->operands; + x86_op_list *op_list = x86_op_list_new(); + + for ( list = insn->operands; list; list = list->next ) { + x86_op_list_append( op_list, &list->op ); + } + + return op_list; + } + + typedef struct x86_insn_list_node { + x86_insn_t *insn; + struct x86_insn_list_node *next, *prev; + } x86_insn_list_node; + + typedef struct x86_insn_list { + size_t count; + x86_insn_list_node *head, *tail, *curr; + } x86_insn_list; + +%} + +%newobject x86_insn_list_new; + +%inline %{ + x86_insn_list * x86_insn_list_new () { + x86_insn_list *list = (x86_insn_list *) + calloc( sizeof(x86_insn_list), 1 ); + list->count = 0; + return list; + } + + void x86_insn_list_free( x86_insn_list * list ) { + x86_insn_list_node *node, *next; + + if (! list ) { + return; + } + + node = list->head; + while ( node ) { + next = node->next; + /* free( node->insn ); */ + free( node ); + node = next; + } + + free( list ); + } + + x86_insn_list_node * x86_insn_list_first( x86_insn_list *list ) { + if (! list ) { + return NULL; + } + return list->head; + } + + x86_insn_list_node * x86_insn_list_last( x86_insn_list *list ) { + if (! list ) { + return NULL; + } + return list->tail; + } + + x86_insn_list_node * x86_insn_list_next( x86_insn_list *list ) { + if (! list ) { + return NULL; + } + if (! list->curr ) { + list->curr = list->head; + return list->head; + } + + list->curr = list->curr->next; + return list->curr; + } + + x86_insn_list_node * x86_insn_list_prev( x86_insn_list *list ) { + if (! list ) { + return NULL; + } + if (! list->curr ) { + list->curr = list->tail; + return list->tail; + } + + list->curr = list->curr->prev; + return list->curr; + } + +%} + +%newobject x86_insn_list_append; + +%inline %{ + void x86_insn_list_append( x86_insn_list *list, x86_insn_t *insn ) { + x86_insn_list_node *node; + if (! list ) { + return; + } + + node = (x86_insn_list_node *) + calloc( sizeof(x86_insn_list_node) , 1 ); + + if (! node ) { + return; + } + + list->count++; + if ( ! list->tail ) { + list->head = list->tail = node; + } else { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } + + node->insn = x86_insn_copy( insn ); + } + + typedef struct { + enum x86_report_codes last_error; + void * last_error_data; + void * disasm_callback; + void * disasm_resolver; + } x86disasm; + + void x86_default_reporter( enum x86_report_codes code, + void *data, void *arg ) { + x86disasm *dis = (x86disasm *) arg; + if ( dis ) { + dis->last_error = code; + dis->last_error_data = data; + } + } + + void x86_default_callback( x86_insn_t *insn, void *arg ) { + x86_insn_list *list = (x86_insn_list *) arg; + if ( list ) { + x86_insn_list_append( list, insn ); + } + } + + /* TODO: resolver stack, maybe a callback */ + long x86_default_resolver( x86_op_t *op, x86_insn_t *insn, void *arg ) { + x86disasm *dis = (x86disasm *) arg; + if ( dis ) { + //return dis->resolver( op, insn ); + return 0; + } + + return 0; + } + + +%} + +%newobject x86disasm_new; + +%inline %{ + x86disasm * x86disasm_new ( enum x86_options options ) { + x86disasm * dis = (x86disasm *) + calloc( sizeof( x86disasm ), 1 ); + x86_init( options, x86_default_reporter, dis ); + return dis; + } + + void x86disasm_free( x86disasm * dis ) { + x86_cleanup(); + free( dis ); + } +%} + +%newobject x86_disasm; + +%inline %{ + x86_insn_t * disasm( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset ) { + x86_insn_t *insn = calloc( sizeof( x86_insn_t ), 1 ); + x86_disasm( buf, buf_len, buf_rva, offset, insn ); + return insn; + } + + int disasm_range( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset, + unsigned int len ) { + + x86_insn_list *list = x86_insn_list_new(); + + if ( len > buf_len ) { + len = buf_len; + } + + return x86_disasm_range( buf, buf_rva, offset, len, + x86_default_callback, list ); + } + + int disasm_forward( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset ) { + x86_insn_list *list = x86_insn_list_new(); + + /* use default resolver: damn SWIG callbacks! */ + return x86_disasm_forward( buf, buf_len, buf_rva, offset, + x86_default_callback, list, + x86_default_resolver, NULL ); + } + + size_t disasm_invariant( unsigned char *buf, size_t buf_len, + x86_invariant_t *inv ) { + return x86_invariant_disasm( buf, buf_len, inv ); + } + + size_t disasm_size( unsigned char *buf, size_t buf_len ) { + return x86_size_disasm( buf, buf_len ); + } + + int x86_max_operand_string( enum x86_asm_format format ) { + switch ( format ) { + case xml_syntax: + return MAX_OP_XML_STRING; + break; + case raw_syntax: + return MAX_OP_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + return MAX_OP_STRING; + break; + } + } + + + int x86_max_insn_string( enum x86_asm_format format ) { + switch ( format ) { + case xml_syntax: + return MAX_INSN_XML_STRING; + break; + case raw_syntax: + return MAX_INSN_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + return MAX_INSN_STRING; + break; + } + } + + int x86_max_num_operands( ) { return MAX_NUM_OPERANDS; } +%} + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm_oop.i b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm_oop.i new file mode 100644 index 0000000000..973a47e27b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/libdisasm_oop.i @@ -0,0 +1,1114 @@ +%module x86disasm +%{ +#ifdef _MSC_VER + typedef __int64 qword; +#else + typedef long long qword; +#endif + +#include + +#define MAX_REGNAME 8 +#define MAX_PREFIX_STR 32 +#define MAX_MNEM_STR 16 +#define MAX_INSN_SIZE 20 +#define MAX_OP_STRING 32 +#define MAX_OP_RAW_STRING 64 +#define MAX_OP_XML_STRING 256 +#define MAX_NUM_OPERANDS 8 +#define MAX_INSN_STRING 512 +#define MAX_INSN_RAW_STRING 1024 +#define MAX_INSN_XML_STRING 4096 + +#include "../../../config.h" + + +const char * version_string( void ) { + return PACKAGE_VERSION; +} + +%} + +const char * version_string( void ); + +%rename(X86_Register) x86_reg_t; +%rename(X86_EAddr) x86_ea_t; +%rename(X86_Operand) x86_op_t; +//%rename(X86_OpList) x86_oplist_t; +%rename(X86_Insn) x86_insn_t; +%rename(X86_InvOperand) x86_invariant_op_t; +%rename(X86_Invariant) x86_invariant_t; + +%include "carrays.i" + +%array_class( unsigned char, byteArray ); + + +%apply (unsigned char *STRING, int LENGTH) { + (unsigned char *buf, size_t buf_len) +}; + + +%inline %{ + + +enum x86_asm_format { + unknown_syntax = 0, /* never use! */ + native_syntax, /* header: 35 bytes */ + intel_syntax, /* header: 23 bytes */ + att_syntax, /* header: 23 bytes */ + xml_syntax, /* header: 679 bytes */ + raw_syntax /* header: 172 bytes */ +}; +%} + +/* ================================================================== */ +/* operand class */ +%inline %{ + enum x86_reg_type { + reg_gen = 0x00001, reg_in = 0x00002, + reg_out = 0x00004, reg_local = 0x00008, + reg_fpu = 0x00010, reg_seg = 0x00020, + reg_simd = 0x00040, reg_sys = 0x00080, + reg_sp = 0x00100, reg_fp = 0x00200, + reg_pc = 0x00400, reg_retaddr = 0x00800, + reg_cond = 0x01000, reg_zero = 0x02000, + reg_ret = 0x04000, reg_src = 0x10000, + reg_dest = 0x20000, reg_count = 0x40000 + }; + + typedef struct { + char name[MAX_REGNAME]; + enum x86_reg_type type; + unsigned int size; + unsigned int id; + unsigned int alias; + unsigned int shift; + } x86_reg_t; + + void x86_reg_from_id( unsigned int id, x86_reg_t * reg ); + + typedef struct { + unsigned int scale; + x86_reg_t index, base; + long disp; + char disp_sign; + char disp_size; + } x86_ea_t; + + enum x86_op_type { + op_unused = 0, + op_register = 1, + op_immediate = 2, + op_relative_near = 3, + op_relative_far = 4, + op_absolute = 5, + op_expression = 6, + op_offset = 7, + op_unknown + }; + + enum x86_op_datatype { + op_byte = 1, op_word = 2, + op_dword = 3, op_qword = 4, + op_dqword = 5, op_sreal = 6, + op_dreal = 7, op_extreal = 8, + op_bcd = 9, op_ssimd = 10, + op_dsimd = 11, op_sssimd = 12, + op_sdsimd = 13, op_descr32 = 14, + op_descr16 = 15, op_pdescr32 = 16, + op_pdescr16 = 17, op_fpuenv = 18, + op_fpregset = 19, + }; + + enum x86_op_access { + op_read = 1, + op_write = 2, + op_execute = 4 + }; + + enum x86_op_flags { + op_signed = 1, op_string = 2, + op_constant = 4, op_pointer = 8, + op_sysref = 0x010, op_implied = 0x020, + op_hardcode = 0x40, op_es_seg = 0x100, + op_cs_seg = 0x200, op_ss_seg = 0x300, + op_ds_seg = 0x400, op_fs_seg = 0x500, + op_gs_seg = 0x600 + }; + + typedef struct { + enum x86_op_type type; + enum x86_op_datatype datatype; + enum x86_op_access access; + enum x86_op_flags flags; + union { + char sbyte; + short sword; + long sdword; + qword sqword; + unsigned char byte; + unsigned short word; + unsigned long dword; + qword qword; + float sreal; + double dreal; + unsigned char extreal[10]; + unsigned char bcd[10]; + qword dqword[2]; + unsigned char simd[16]; + unsigned char fpuenv[28]; + void * address; + unsigned long offset; + x86_reg_t reg; + char relative_near; + long relative_far; + x86_ea_t expression; + } data; + void * insn; + } x86_op_t; + + unsigned int x86_operand_size( x86_op_t *op ); + + int x86_format_operand(x86_op_t *op, char *buf, int len, + enum x86_asm_format format); +%} + +%extend x86_reg_t{ + x86_reg_t * aliased_reg( ) { + x86_reg_t * reg = (x86_reg_t * ) + calloc( sizeof(x86_reg_t), 1 ); + x86_reg_from_id( self->id, reg ); + return reg; + } +} + +%extend x86_op_t{ + size_t size() { + return x86_operand_size( self ); + } + char * format( enum x86_asm_format format ) { + char *buf, *str; + size_t len; + + switch ( format ) { + case xml_syntax: + len = MAX_OP_XML_STRING; + break; + case raw_syntax: + len = MAX_OP_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + len = MAX_OP_STRING; + break; + } + + buf = (char * ) calloc( len + 1, 1 ); + x86_format_operand( self, buf, len, format ); + + /* drop buffer down to a reasonable size */ + str = strdup( buf ); + free(buf); + return str; + } + + int is_address( ) { + if ( self->type == op_absolute || + self->type == op_offset ) { + return 1; + } + + return 0; + } + + int is_relative( ) { + if ( self->type == op_relative_near || + self->type == op_relative_far ) { + return 1; + } + + return 0; + } + + %newobject copy; + x86_op_t * copy() { + x86_op_t *op = (x86_op_t *) calloc( sizeof(x86_op_t), 1 ); + + if ( op ) { + memcpy( op, self, sizeof(x86_op_t) ); + } + + return op; + } +} + +/* ================================================================== */ +/* operand list class */ +%inline %{ + typedef struct X86_OpListNode { + x86_op_t *op; + struct X86_OpListNode *next, *prev; + } X86_OpListNode; + + typedef struct X86_OpList { + size_t count; + X86_OpListNode *head, *tail, *curr; + } X86_OpList; +%} + +%extend X86_OpList { + X86_OpList () { + X86_OpList *list = (X86_OpList *) + calloc( sizeof(X86_OpList), 1 ); + list->count = 0; + return list; + } + + ~X86_OpList() { + X86_OpListNode *node, *next; + + node = self->head; + while ( node ) { + next = node->next; + /* free( node->insn ); */ + free( node ); + node = next; + } + + free( self ); + } + + X86_OpListNode * first() { + self->curr = self->head; + return self->head; + } + + X86_OpListNode * last() { + self->curr = self->tail; + return self->tail; + } + + X86_OpListNode * next() { + if (! self->curr ) { + self->curr = self->head; + return self->head; + } + + self->curr = self->curr->next; + return self->curr; + } + + X86_OpListNode * prev() { + if (! self->curr ) { + self->curr = self->tail; + return self->tail; + } + + self->curr = self->curr->prev; + return self->curr; + } + + %newobject append; + void append( x86_op_t *op ) { + X86_OpListNode *node = (X86_OpListNode *) + calloc( sizeof(X86_OpListNode) , 1 ); + if (! node ) { + return; + } + + self->count++; + if ( ! self->tail ) { + self->head = self->tail = node; + } else { + self->tail->next = node; + node->prev = self->tail; + self->tail = node; + } + + node->op = x86_op_t_copy( op ); + } +} + +%inline %{ + typedef struct x86_operand_list { + x86_op_t op; + struct x86_operand_list *next; + } x86_oplist_t; +%} + +%extend x86_oplist_t { + %newobject x86_oplist_node_copy; +} + +/* ================================================================== */ +/* instruction class */ +%inline %{ + x86_oplist_t * x86_oplist_node_copy( x86_oplist_t * list ) { + x86_oplist_t *ptr; + ptr = (x86_oplist_t *) calloc( sizeof(x86_oplist_t), 1 ); + if ( ptr ) { + memcpy( &ptr->op, &list->op, sizeof(x86_op_t) ); + } + + return ptr; + } + + enum x86_insn_group { + insn_none = 0, insn_controlflow = 1, + insn_arithmetic = 2, insn_logic = 3, + insn_stack = 4, insn_comparison = 5, + insn_move = 6, insn_string = 7, + insn_bit_manip = 8, insn_flag_manip = 9, + insn_fpu = 10, insn_interrupt = 13, + insn_system = 14, insn_other = 15 + }; + + enum x86_insn_type { + insn_invalid = 0, insn_jmp = 0x1001, + insn_jcc = 0x1002, insn_call = 0x1003, + insn_callcc = 0x1004, insn_return = 0x1005, + insn_add = 0x2001, insn_sub = 0x2002, + insn_mul = 0x2003, insn_div = 0x2004, + insn_inc = 0x2005, insn_dec = 0x2006, + insn_shl = 0x2007, insn_shr = 0x2008, + insn_rol = 0x2009, insn_ror = 0x200A, + insn_and = 0x3001, insn_or = 0x3002, + insn_xor = 0x3003, insn_not = 0x3004, + insn_neg = 0x3005, insn_push = 0x4001, + insn_pop = 0x4002, insn_pushregs = 0x4003, + insn_popregs = 0x4004, insn_pushflags = 0x4005, + insn_popflags = 0x4006, insn_enter = 0x4007, + insn_leave = 0x4008, insn_test = 0x5001, + insn_cmp = 0x5002, insn_mov = 0x6001, + insn_movcc = 0x6002, insn_xchg = 0x6003, + insn_xchgcc = 0x6004, insn_strcmp = 0x7001, + insn_strload = 0x7002, insn_strmov = 0x7003, + insn_strstore = 0x7004, insn_translate = 0x7005, + insn_bittest = 0x8001, insn_bitset = 0x8002, + insn_bitclear = 0x8003, insn_clear_carry = 0x9001, + insn_clear_zero = 0x9002, insn_clear_oflow = 0x9003, + insn_clear_dir = 0x9004, insn_clear_sign = 0x9005, + insn_clear_parity = 0x9006, insn_set_carry = 0x9007, + insn_set_zero = 0x9008, insn_set_oflow = 0x9009, + insn_set_dir = 0x900A, insn_set_sign = 0x900B, + insn_set_parity = 0x900C, insn_tog_carry = 0x9010, + insn_tog_zero = 0x9020, insn_tog_oflow = 0x9030, + insn_tog_dir = 0x9040, insn_tog_sign = 0x9050, + insn_tog_parity = 0x9060, insn_fmov = 0xA001, + insn_fmovcc = 0xA002, insn_fneg = 0xA003, + insn_fabs = 0xA004, insn_fadd = 0xA005, + insn_fsub = 0xA006, insn_fmul = 0xA007, + insn_fdiv = 0xA008, insn_fsqrt = 0xA009, + insn_fcmp = 0xA00A, insn_fcos = 0xA00C, + insn_fldpi = 0xA00D, insn_fldz = 0xA00E, + insn_ftan = 0xA00F, insn_fsine = 0xA010, + insn_fsys = 0xA020, insn_int = 0xD001, + insn_intcc = 0xD002, insn_iret = 0xD003, + insn_bound = 0xD004, insn_debug = 0xD005, + insn_trace = 0xD006, insn_invalid_op = 0xD007, + insn_oflow = 0xD008, insn_halt = 0xE001, + insn_in = 0xE002, insn_out = 0xE003, + insn_cpuid = 0xE004, insn_nop = 0xF001, + insn_bcdconv = 0xF002, insn_szconv = 0xF003 + }; + + enum x86_insn_note { + insn_note_ring0 = 1, + insn_note_smm = 2, + insn_note_serial = 4 + }; + + enum x86_flag_status { + insn_carry_set = 0x1, + insn_zero_set = 0x2, + insn_oflow_set = 0x4, + insn_dir_set = 0x8, + insn_sign_set = 0x10, + insn_parity_set = 0x20, + insn_carry_or_zero_set = 0x40, + insn_zero_set_or_sign_ne_oflow = 0x80, + insn_carry_clear = 0x100, + insn_zero_clear = 0x200, + insn_oflow_clear = 0x400, + insn_dir_clear = 0x800, + insn_sign_clear = 0x1000, + insn_parity_clear = 0x2000, + insn_sign_eq_oflow = 0x4000, + insn_sign_ne_oflow = 0x8000 + }; + + enum x86_insn_cpu { + cpu_8086 = 1, cpu_80286 = 2, + cpu_80386 = 3, cpu_80387 = 4, + cpu_80486 = 5, cpu_pentium = 6, + cpu_pentiumpro = 7, cpu_pentium2 = 8, + cpu_pentium3 = 9, cpu_pentium4 = 10, + cpu_k6 = 16, cpu_k7 = 32, + cpu_athlon = 48 + }; + + enum x86_insn_isa { + isa_gp = 1, isa_fp = 2, + isa_fpumgt = 3, isa_mmx = 4, + isa_sse1 = 5, isa_sse2 = 6, + isa_sse3 = 7, isa_3dnow = 8, + isa_sys = 9 + }; + + enum x86_insn_prefix { + insn_no_prefix = 0, + insn_rep_zero = 1, + insn_rep_notzero = 2, + insn_lock = 4 + }; + + + typedef struct { + unsigned long addr; + unsigned long offset; + enum x86_insn_group group; + enum x86_insn_type type; + enum x86_insn_note note; + unsigned char bytes[MAX_INSN_SIZE]; + unsigned char size; + unsigned char addr_size; + unsigned char op_size; + enum x86_insn_cpu cpu; + enum x86_insn_isa isa; + enum x86_flag_status flags_set; + enum x86_flag_status flags_tested; + unsigned char stack_mod; + long stack_mod_val; + enum x86_insn_prefix prefix; + char prefix_string[MAX_PREFIX_STR]; + char mnemonic[MAX_MNEM_STR]; + x86_oplist_t *operands; + size_t operand_count; + size_t explicit_count; + void *block; + void *function; + int tag; + } x86_insn_t; + + typedef void (*x86_operand_fn)(x86_op_t *op, x86_insn_t *insn, + void *arg); + + enum x86_op_foreach_type { + op_any = 0, + op_dest = 1, + op_src = 2, + op_ro = 3, + op_wo = 4, + op_xo = 5, + op_rw = 6, + op_implicit = 0x10, + op_explicit = 0x20 + }; + + size_t x86_operand_count( x86_insn_t *insn, + enum x86_op_foreach_type type ); + x86_op_t * x86_operand_1st( x86_insn_t *insn ); + x86_op_t * x86_operand_2nd( x86_insn_t *insn ); + x86_op_t * x86_operand_3rd( x86_insn_t *insn ); + long x86_get_rel_offset( x86_insn_t *insn ); + x86_op_t * x86_get_branch_target( x86_insn_t *insn ); + x86_op_t * x86_get_imm( x86_insn_t *insn ); + unsigned char * x86_get_raw_imm( x86_insn_t *insn ); + void x86_set_insn_addr( x86_insn_t *insn, unsigned long addr ); + int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len, + enum x86_asm_format format); + int x86_format_insn(x86_insn_t *insn, char *buf, int len, + enum x86_asm_format); + void x86_oplist_free( x86_insn_t *insn ); + int x86_insn_is_valid( x86_insn_t *insn ); +%} + +%extend x86_insn_t { + x86_insn_t() { + x86_insn_t *insn = (x86_insn_t *) + calloc( sizeof(x86_insn_t), 1 ); + return insn; + } + ~x86_insn_t() { + x86_oplist_free( self ); + free( self ); + } + + int is_valid( ) { + return x86_insn_is_valid( self ); + } + + x86_op_t * operand_1st() { + return x86_operand_1st( self ); + } + + x86_op_t * operand_2nd() { + return x86_operand_2nd( self ); + } + + x86_op_t * operand_3rd() { + return x86_operand_3rd( self ); + } + + x86_op_t * operand_dest() { + return x86_operand_1st( self ); + } + + x86_op_t * operand_src() { + return x86_operand_2nd( self ); + } + + size_t num_operands( enum x86_op_foreach_type type ) { + return x86_operand_count( self, type ); + } + + long rel_offset() { + return x86_get_rel_offset( self ); + } + + x86_op_t * branch_target() { + return x86_get_branch_target( self ); + } + + x86_op_t * imm() { + return x86_get_imm( self ); + } + + unsigned char * raw_imm() { + return x86_get_raw_imm( self ); + } + + %newobject format; + char * format( enum x86_asm_format format ) { + char *buf, *str; + size_t len; + + switch ( format ) { + case xml_syntax: + len = MAX_INSN_XML_STRING; + break; + case raw_syntax: + len = MAX_INSN_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + len = MAX_INSN_STRING; + break; + } + + buf = (char * ) calloc( len + 1, 1 ); + x86_format_insn( self, buf, len, format ); + + /* drop buffer down to a reasonable size */ + str = strdup( buf ); + free(buf); + return str; + } + + %newobject format_mnemonic; + char * format_mnemonic( enum x86_asm_format format ) { + char *buf, *str; + size_t len = MAX_MNEM_STR + MAX_PREFIX_STR + 4; + + buf = (char * ) calloc( len, 1 ); + x86_format_mnemonic( self, buf, len, format ); + + /* drop buffer down to a reasonable size */ + str = strdup( buf ); + free(buf); + + return str; + } + + %newobject copy; + x86_insn_t * copy() { + x86_oplist_t *ptr, *list, *last = NULL; + x86_insn_t *insn = (x86_insn_t *) + calloc( sizeof(x86_insn_t), 1 ); + + if ( insn ) { + memcpy( insn, self, sizeof(x86_insn_t) ); + insn->operands = NULL; + insn->block = NULL; + insn->function = NULL; + + /* copy operand list */ + for ( list = self->operands; list; list = list->next ) { + ptr = x86_oplist_node_copy( list ); + + if (! ptr ) { + continue; + } + + if ( insn->operands ) { + last->next = ptr; + } else { + insn->operands = ptr; + } + last = ptr; + } + } + + return insn; + } + + X86_OpList * operand_list( ) { + x86_oplist_t *list = self->operands; + X86_OpList *op_list = new_X86_OpList(); + + for ( list = self->operands; list; list = list->next ) { + X86_OpList_append( op_list, &list->op ); + } + + return op_list; + } +} + +/* ================================================================== */ +/* invariant instruction class */ +%inline %{ + #define X86_WILDCARD_BYTE 0xF4 + + typedef struct { + enum x86_op_type type; + enum x86_op_datatype datatype; + enum x86_op_access access; + enum x86_op_flags flags; + } x86_invariant_op_t; + + typedef struct { + unsigned char bytes[64]; + unsigned int size; + enum x86_insn_group group; + enum x86_insn_type type; + x86_invariant_op_t operands[3]; + } x86_invariant_t; +%} + +%extend x86_invariant_t { + + x86_invariant_t() { + x86_invariant_t *inv = (x86_invariant_t *) + calloc( sizeof(x86_invariant_t), 1 ); + return inv; + } + + ~x86_invariant_t() { + free( self ); + } +} + +/* ================================================================== */ +/* instruction list class */ +%inline %{ + typedef struct X86_InsnListNode { + x86_insn_t *insn; + struct X86_InsnListNode *next, *prev; + } X86_InsnListNode; + + typedef struct X86_InsnList { + size_t count; + X86_InsnListNode *head, *tail, *curr; + } X86_InsnList; +%} + +%extend X86_InsnList { + X86_InsnList () { + X86_InsnList *list = (X86_InsnList *) + calloc( sizeof(X86_InsnList), 1 ); + list->count = 0; + return list; + } + + ~X86_InsnList() { + X86_InsnListNode *node, *next; + + node = self->head; + while ( node ) { + next = node->next; + /* free( node->insn ); */ + free( node ); + node = next; + } + + free( self ); + } + + X86_InsnListNode * first() { return self->head; } + + X86_InsnListNode * last() { return self->tail; } + + X86_InsnListNode * next() { + if (! self->curr ) { + self->curr = self->head; + return self->head; + } + + self->curr = self->curr->next; + return self->curr; + } + + X86_InsnListNode * prev() { + if (! self->curr ) { + self->curr = self->tail; + return self->tail; + } + + self->curr = self->curr->prev; + return self->curr; + } + + %newobject append; + void append( x86_insn_t *insn ) { + X86_InsnListNode *node = (X86_InsnListNode *) + calloc( sizeof(X86_InsnListNode) , 1 ); + if (! node ) { + return; + } + + self->count++; + if ( ! self->tail ) { + self->head = self->tail = node; + } else { + self->tail->next = node; + node->prev = self->tail; + self->tail = node; + } + + node->insn = x86_insn_t_copy( insn ); + } +} + +/* ================================================================== */ +/* address table class */ +/* slight TODO */ + +/* ================================================================== */ +/* Main disassembler class */ +%inline %{ + + enum x86_options { + opt_none= 0, + opt_ignore_nulls=1, + opt_16_bit=2 + }; + enum x86_report_codes { + report_disasm_bounds, + report_insn_bounds, + report_invalid_insn, + report_unknown + }; + + + typedef struct { + enum x86_report_codes last_error; + void * last_error_data; + void * disasm_callback; + void * disasm_resolver; + } X86_Disasm; + + typedef void (*DISASM_REPORTER)( enum x86_report_codes code, + void *data, void *arg ); + typedef void (*DISASM_CALLBACK)( x86_insn_t *insn, void * arg ); + typedef long (*DISASM_RESOLVER)( x86_op_t *op, + x86_insn_t * current_insn, + void *arg ); + + void x86_report_error( enum x86_report_codes code, void *data ); + int x86_init( enum x86_options options, DISASM_REPORTER reporter, + void *arg); + void x86_set_reporter( DISASM_REPORTER reporter, void *arg); + void x86_set_options( enum x86_options options ); + enum x86_options x86_get_options( void ); + int x86_cleanup(void); + int x86_format_header( char *buf, int len, enum x86_asm_format format); + unsigned int x86_endian(void); + unsigned int x86_addr_size(void); + unsigned int x86_op_size(void); + unsigned int x86_word_size(void); + unsigned int x86_max_insn_size(void); + unsigned int x86_sp_reg(void); + unsigned int x86_fp_reg(void); + unsigned int x86_ip_reg(void); + size_t x86_invariant_disasm( unsigned char *buf, int buf_len, + x86_invariant_t *inv ); + size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ); + int x86_disasm( unsigned char *buf, unsigned int buf_len, + unsigned long buf_rva, unsigned int offset, + x86_insn_t * insn ); + int x86_disasm_range( unsigned char *buf, unsigned long buf_rva, + unsigned int offset, unsigned int len, + DISASM_CALLBACK func, void *arg ); + int x86_disasm_forward( unsigned char *buf, unsigned int buf_len, + unsigned long buf_rva, unsigned int offset, + DISASM_CALLBACK func, void *arg, + DISASM_RESOLVER resolver, void *r_arg ); + + void x86_default_reporter( enum x86_report_codes code, + void *data, void *arg ) { + X86_Disasm *dis = (X86_Disasm *) arg; + if ( dis ) { + dis->last_error = code; + dis->last_error_data = data; + } + } + + void x86_default_callback( x86_insn_t *insn, void *arg ) { + X86_InsnList *list = (X86_InsnList *) arg; + if ( list ) { + X86_InsnList_append( list, insn ); + } + } + + /* TODO: resolver stack, maybe a callback */ + long x86_default_resolver( x86_op_t *op, x86_insn_t *insn, void *arg ) { + X86_Disasm *dis = (X86_Disasm *) arg; + if ( dis ) { + //return dis->resolver( op, insn ); + return 0; + } + + return 0; + } + +%} + +%extend X86_Disasm { + + X86_Disasm( ) { + X86_Disasm * dis = (X86_Disasm *) + calloc( sizeof( X86_Disasm ), 1 ); + x86_init( opt_none, x86_default_reporter, dis ); + return dis; + } + + X86_Disasm( enum x86_options options ) { + X86_Disasm * dis = (X86_Disasm *) + calloc( sizeof( X86_Disasm ), 1 ); + x86_init( options, x86_default_reporter, dis ); + return dis; + } + + X86_Disasm( enum x86_options options, DISASM_REPORTER reporter ) { + X86_Disasm * dis = (X86_Disasm *) + calloc( sizeof( X86_Disasm ), 1 ); + x86_init( options, reporter, NULL ); + return dis; + } + + X86_Disasm( enum x86_options options, DISASM_REPORTER reporter, + void * arg ) { + X86_Disasm * dis = (X86_Disasm *) + calloc( sizeof( X86_Disasm ), 1 ); + x86_init( options, reporter, arg ); + return dis; + } + + ~X86_Disasm() { + x86_cleanup(); + free( self ); + } + + void set_options( enum x86_options options ) { + return x86_set_options( options ); + } + + enum x86_options options() { + return x86_get_options(); + } + + void set_callback( void * callback ) { + self->disasm_callback = callback; + } + + void set_resolver( void * callback ) { + self->disasm_resolver = callback; + } + + void report_error( enum x86_report_codes code ) { + x86_report_error( code, NULL ); + } + + %newobject disasm; + x86_insn_t * disasm( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset ) { + x86_insn_t *insn = calloc( sizeof( x86_insn_t ), 1 ); + x86_disasm( buf, buf_len, buf_rva, offset, insn ); + return insn; + } + + int disasm_range( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset, + unsigned int len ) { + + X86_InsnList *list = new_X86_InsnList(); + + if ( len > buf_len ) { + len = buf_len; + } + + return x86_disasm_range( buf, buf_rva, offset, len, + x86_default_callback, list ); + } + + int disasm_forward( unsigned char *buf, size_t buf_len, + unsigned long buf_rva, unsigned int offset ) { + X86_InsnList *list = new_X86_InsnList(); + + /* use default resolver: damn SWIG callbacks! */ + return x86_disasm_forward( buf, buf_len, buf_rva, offset, + x86_default_callback, list, + x86_default_resolver, NULL ); + } + + size_t disasm_invariant( unsigned char *buf, size_t buf_len, + x86_invariant_t *inv ) { + return x86_invariant_disasm( buf, buf_len, inv ); + } + + size_t disasm_size( unsigned char *buf, size_t buf_len ) { + return x86_size_disasm( buf, buf_len ); + } + + %newobject format_header; + char * format_header( enum x86_asm_format format) { + char *buf, *str; + size_t len; + + switch ( format ) { + /* these were obtained from x86_format.c */ + case xml_syntax: + len = 679; break; + case raw_syntax: + len = 172; break; + case native_syntax: + len = 35; break; + case intel_syntax: + len = 23; break; + case att_syntax: + len = 23; break; + case unknown_syntax: + default: + len = 23; break; + } + + buf = (char * ) calloc( len + 1, 1 ); + x86_format_header( buf, len, format ); + + return buf; + } + + unsigned int endian() { + return x86_endian(); + } + + unsigned int addr_size() { + return x86_addr_size(); + } + + unsigned int op_size() { + return x86_op_size(); + } + + unsigned int word_size() { + return x86_word_size(); + } + + unsigned int max_insn_size() { + return x86_max_insn_size(); + } + + unsigned int sp_reg() { + return x86_sp_reg(); + } + + unsigned int fp_reg() { + return x86_fp_reg(); + } + + unsigned int ip_reg() { + return x86_ip_reg(); + } + + %newobject reg_from_id; + x86_reg_t * reg_from_id( unsigned int id ) { + x86_reg_t * reg = calloc( sizeof(x86_reg_t), 1 ); + x86_reg_from_id( id, reg ); + return reg; + } + + unsigned char wildcard_byte() { return X86_WILDCARD_BYTE; } + + int max_register_string() { return MAX_REGNAME; } + + int max_prefix_string() { return MAX_PREFIX_STR; } + + int max_mnemonic_string() { return MAX_MNEM_STR; } + + int max_operand_string( enum x86_asm_format format ) { + switch ( format ) { + case xml_syntax: + return MAX_OP_XML_STRING; + break; + case raw_syntax: + return MAX_OP_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + return MAX_OP_STRING; + break; + } + } + + + int max_insn_string( enum x86_asm_format format ) { + switch ( format ) { + case xml_syntax: + return MAX_INSN_XML_STRING; + break; + case raw_syntax: + return MAX_INSN_RAW_STRING; + break; + case native_syntax: + case intel_syntax: + case att_syntax: + case unknown_syntax: + default: + return MAX_INSN_STRING; + break; + } + } + + int max_num_operands( ) { return MAX_NUM_OPERANDS; } +} + +/* python callback, per the manual */ +/*%typemap(python,in) PyObject *pyfunc { + if (!PyCallable_Check($source)) { + PyErr_SetString(PyExc_TypeError, "Need a callable object!"); + return NULL; + } + $target = $source; +}*/ + +/* python FILE * callback, per the manual */ +/* +%typemap(python,in) FILE * { + if (!PyFile_Check($source)) { + PyErr_SetString(PyExc_TypeError, "Need a file!"); + return NULL; + } + $target = PyFile_AsFile($source); +}*/ + + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile-swig b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile-swig new file mode 100644 index 0000000000..9f3a645733 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile-swig @@ -0,0 +1,65 @@ +ifndef BASE_NAME +BASE_NAME = x86disasm +endif + +ifndef SWIG +SWIG = swig # apt-get install swig ! +endif + +ifndef GCC +GCC = gcc +endif + +ifndef CC_FLAGS +CC_FLAGS = -c -fPIC +endif + +ifndef LD_FLAGS +LD_FLAGS = -shared -L.. -ldisasm +endif + +INTERFACE_FILE = libdisasm_oop.i + +SWIG_INTERFACE = ../$(INTERFACE_FILE) + +# PERL rules +PERL_MOD = blib/arch/auto/$(BASE_NAME)/$(BASE_NAME).so +PERL_SHADOW = $(BASE_NAME)_wrap.c +PERL_SWIG = $(BASE_NAME).pl +PERL_OBJ = $(BASE_NAME)_wrap.o +PERL_INC = `perl -e 'use Config; print $$Config{archlib};'`/CORE +PERL_CC_FLAGS = `perl -e 'use Config; print $$Config{ccflags};'` + +#==================================================== +# TARGETS + +all: swig-perl + +dummy: swig-perl install uninstall clean + +swig-perl: $(PERL_MOD) + +$(PERL_MOD): $(PERL_OBJ) + perl Makefile.PL + make + #$(GCC) $(LD_FLAGS) $(PERL_OBJ) -o $@ + +$(PERL_OBJ): $(PERL_SHADOW) + $(GCC) $(CC_FLAGS) $(PERL_CC_FLAGS) -I$(PERL_INC) -o $@ $< + +$(PERL_SHADOW): $(SWIG_INTERFACE) + swig -perl -shadow -o $(PERL_SHADOW) -outdir . $< + +# ================================================================== +install: $(PERL_MOD) + make install + +# ================================================================== +uninstall: + +# ================================================================== +clean: + rm $(PERL_MOD) $(PERL_OBJ) + rm $(PERL_SHADOW) + rm -rf Makefile blib pm_to_blib + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile.PL b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile.PL new file mode 100644 index 0000000000..6e625df182 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/perl/Makefile.PL @@ -0,0 +1,7 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + 'NAME' => 'x86disasm', + 'LIBS' => ['-ldisasm'], + 'OBJECT' => 'x86disasm_wrap.o' +); diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/python/Makefile-swig b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/python/Makefile-swig new file mode 100644 index 0000000000..544681a13a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/python/Makefile-swig @@ -0,0 +1,64 @@ +ifndef BASE_NAME +BASE_NAME = x86disasm +endif + +ifndef SWIG +SWIG = swig # apt-get install swig ! +endif + +ifndef GCC +GCC = gcc +endif + +ifndef CC_FLAGS +CC_FLAGS = -c -fPIC +endif + +ifndef LD_FLAGS +LD_FLAGS = -shared -L.. -ldisasm +endif + +INTERFACE_FILE = libdisasm_oop.i + +SWIG_INTERFACE = ../$(INTERFACE_FILE) + +# PYTHON rules +PYTHON_MOD = $(BASE_NAME)-python.so +PYTHON_SHADOW = $(BASE_NAME)_wrap.c +PYTHON_SWIG = $(BASE_NAME).py +PYTHON_OBJ = $(BASE_NAME)_wrap.o +PYTHON_INC = `/bin/echo -e 'import sys\nprint sys.prefix + "/include/python" + sys.version[:3]' | python` +PYTHON_LIB = `/bin/echo -e 'import sys\nprint sys.prefix + "/lib/python" + sys.version[:3]' | python` +PYTHON_DEST = $(PYTHON_LIB)/lib-dynload/_$(BASE_NAME).so + +#==================================================== +# TARGETS + +all: swig-python + +dummy: swig-python install uninstall clean + +swig-python: $(PYTHON_MOD) + +$(PYTHON_MOD): $(PYTHON_OBJ) + $(GCC) $(LD_FLAGS) $(PYTHON_OBJ) -o $@ + +$(PYTHON_OBJ): $(PYTHON_SHADOW) + $(GCC) $(CC_FLAGS) -I$(PYTHON_INC) -I.. -o $@ $< + +$(PYTHON_SHADOW): $(SWIG_INTERFACE) + swig -python -shadow -o $(PYTHON_SHADOW) -outdir . $< + +# ================================================================== +install: $(PYTHON_MOD) + sudo cp $(PYTHON_MOD) $(PYTHON_DEST) + sudo cp $(PYTHON_SWIG) $(PYTHON_LIB) + +# ================================================================== +uninstall: + +# ================================================================== +clean: + rm $(PYTHON_MOD) $(PYTHON_SWIG) $(PYTHON_OBJ) + rm $(PYTHON_SHADOW) + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/Makefile-swig b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/Makefile-swig new file mode 100644 index 0000000000..ee4800232c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/Makefile-swig @@ -0,0 +1,68 @@ +ifndef BASE_NAME +BASE_NAME = x86disasm +endif + +ifndef SWIG +SWIG = swig # apt-get install swig ! +endif + +ifndef GCC +GCC = gcc +endif + +ifndef CC_FLAGS +CC_FLAGS = -c -fPIC +endif + +ifndef LD_FLAGS +LD_FLAGS = -shared -L../.. -ldisasm +endif + +LIBDISASM_DIR = ../.. + +INTERFACE_FILE = libdisasm_oop.i + +SWIG_INTERFACE = ../$(INTERFACE_FILE) + +# RUBY rules +RUBY_MAKEFILE = Makefile +RUBY_MOD = $(BASE_NAME).so +RUBY_SHADOW = $(BASE_NAME)_wrap.c +#RUBY_SWIG = $(BASE_NAME).rb +RUBY_OBJ = $(BASE_NAME)_wrap.o +RUBY_INC = `ruby -e 'puts $$:.join("\n")' | tail -2 | head -1` +#RUBY_LIB = +#RUBY_DEST = + +#==================================================== +# TARGETS + +all: swig-ruby + +dummy: swig-ruby install uninstall clean + +swig-ruby: $(RUBY_MOD) + +$(RUBY_MOD): $(RUBY_MAKEFILE) + make + +$(RUBY_MAKEFILE): $(RUBY_OBJ) + ruby extconf.rb + +$(RUBY_OBJ):$(RUBY_SHADOW) + $(GCC) $(CC_FLAGS) -I$(RUBY_INC) -I.. -o $@ $< + +$(RUBY_SHADOW): $(SWIG_INTERFACE) + swig -ruby -o $(RUBY_SHADOW) -outdir . $< + +# ================================================================== +install: $(RUBY_MOD) + make install + +# ================================================================== +uninstall: + +# ================================================================== +clean: + make clean || true + rm $(RUBY_SHADOW) $(RUBY_MAKEFILE) $(RUBY_MOD) $(RUBY_OBJ) diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/extconf.rb b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/extconf.rb new file mode 100644 index 0000000000..4e74326435 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/ruby/extconf.rb @@ -0,0 +1,4 @@ +require 'mkmf' +find_library('disasm', 'x86_init', "/usr/local/lib", "../..") +create_makefile('x86disasm') + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/tcl/Makefile-swig b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/tcl/Makefile-swig new file mode 100644 index 0000000000..5145a82935 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/swig/tcl/Makefile-swig @@ -0,0 +1,63 @@ +ifndef BASE_NAME +BASE_NAME = x86disasm +endif + +ifndef SWIG +SWIG = swig # apt-get install swig ! +endif + +ifndef GCC +GCC = gcc +endif + +ifndef CC_FLAGS +CC_FLAGS = -c -fPIC +endif + +ifndef LD_FLAGS +LD_FLAGS = -shared -L../.. -ldisasm +endif + +INTERFACE_FILE = libdisasm.i + +SWIG_INTERFACE = ../$(INTERFACE_FILE) + +# TCL rules +TCL_VERSION = 8.3 +TCL_MOD = $(BASE_NAME)-tcl.so +TCL_SHADOW = $(BASE_NAME)_wrap.c +TCL_OBJ = $(BASE_NAME)_wrap.o +TCL_INC = /usr/include/tcl$(TCL_VERSION) +TCL_LIB = /usr/lib/tcl$(TCL_VERSION) +TCL_DEST = $(TCL_LIB)/$(BASE_NAME).so + +#==================================================== +# TARGETS + +all: swig-tcl + +dummy: swig-tcl install uninstall clean + +swig-tcl: $(TCL_MOD) + +$(TCL_MOD): $(TCL_OBJ) + $(GCC) $(LD_FLAGS) $(TCL_OBJ) -o $@ + +$(TCL_OBJ): $(TCL_SHADOW) + $(GCC) $(CC_FLAGS) -I$(TCL_INC) -I.. -o $@ $< + +$(TCL_SHADOW): $(SWIG_INTERFACE) + swig -tcl -o $(TCL_SHADOW) -outdir . $< + +# ================================================================== +install: $(TCL_MOD) + sudo cp $(TCL_MOD) $(TCL_DEST) + +# ================================================================== +uninstall: + +# ================================================================== +clean: + rm $(TCL_MOD) $(TCL_SWIG) $(TCL_OBJ) + rm $(TCL_SHADOW) + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_disasm.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_disasm.c new file mode 100644 index 0000000000..1b82f4e667 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_disasm.c @@ -0,0 +1,210 @@ +#include +#include +#include + +#include "libdis.h" +#include "ia32_insn.h" +#include "ia32_invariant.h" +#include "x86_operand_list.h" + + +#ifdef _MSC_VER + #define snprintf _snprintf + #define inline __inline +#endif + +unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len, + uint32_t buf_rva, unsigned int offset, + x86_insn_t *insn ){ + int len, size; + unsigned char bytes[MAX_INSTRUCTION_SIZE]; + + if ( ! buf || ! insn || ! buf_len ) { + /* caller screwed up somehow */ + return 0; + } + + + /* ensure we are all NULLed up */ + memset( insn, 0, sizeof(x86_insn_t) ); + insn->addr = buf_rva + offset; + insn->offset = offset; + /* default to invalid insn */ + insn->type = insn_invalid; + insn->group = insn_none; + + if ( offset >= buf_len ) { + /* another caller screwup ;) */ + x86_report_error(report_disasm_bounds, (void*)(long)(buf_rva+offset)); + return 0; + } + + len = buf_len - offset; + + /* copy enough bytes for disassembly into buffer : this + * helps prevent buffer overruns at the end of a file */ + memset( bytes, 0, MAX_INSTRUCTION_SIZE ); + memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len : + MAX_INSTRUCTION_SIZE ); + + /* actually do the disassembly */ + /* TODO: allow switching when more disassemblers are added */ + size = ia32_disasm_addr( bytes, len, insn); + + /* check and see if we had an invalid instruction */ + if (! size ) { + x86_report_error(report_invalid_insn, (void*)(long)(buf_rva+offset)); + return 0; + } + + /* check if we overran the end of the buffer */ + if ( size > len ) { + x86_report_error( report_insn_bounds, (void*)(long)(buf_rva + offset)); + MAKE_INVALID( insn, bytes ); + return 0; + } + + /* fill bytes field of insn */ + memcpy( insn->bytes, bytes, size ); + + return size; +} + +unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva, + unsigned int offset, unsigned int len, + DISASM_CALLBACK func, void *arg ) { + x86_insn_t insn; + unsigned int buf_len, size, count = 0, bytes = 0; + + /* buf_len is implied by the arguments */ + buf_len = len + offset; + + while ( bytes < len ) { + size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, + &insn ); + if ( size ) { + /* invoke callback if it exists */ + if ( func ) { + (*func)( &insn, arg ); + } + bytes += size; + count ++; + } else { + /* error */ + bytes++; /* try next byte */ + } + + x86_oplist_free( &insn ); + } + + return( count ); +} + +static inline int follow_insn_dest( x86_insn_t *insn ) { + if ( insn->type == insn_jmp || insn->type == insn_jcc || + insn->type == insn_call || insn->type == insn_callcc ) { + return(1); + } + return(0); +} + +static inline int insn_doesnt_return( x86_insn_t *insn ) { + return( (insn->type == insn_jmp || insn->type == insn_return) ? 1: 0 ); +} + +static int32_t internal_resolver( x86_op_t *op, x86_insn_t *insn ){ + int32_t next_addr = -1; + if ( x86_optype_is_address(op->type) ) { + next_addr = op->data.sdword; + } else if ( op->type == op_relative_near ) { + next_addr = insn->addr + insn->size + op->data.relative_near; + } else if ( op->type == op_relative_far ) { + next_addr = insn->addr + insn->size + op->data.relative_far; + } + return( next_addr ); +} + +unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len, + uint32_t buf_rva, unsigned int offset, + DISASM_CALLBACK func, void *arg, + DISASM_RESOLVER resolver, void *r_arg ){ + x86_insn_t insn; + x86_op_t *op; + int32_t next_addr; + uint32_t next_offset; + unsigned int size, count = 0, bytes = 0, cont = 1; + + while ( cont && bytes < buf_len ) { + size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, + &insn ); + + if ( size ) { + /* invoke callback if it exists */ + if ( func ) { + (*func)( &insn, arg ); + } + bytes += size; + count ++; + } else { + /* error */ + bytes++; /* try next byte */ + } + + if ( follow_insn_dest(&insn) ) { + op = x86_get_dest_operand( &insn ); + next_addr = -1; + + /* if caller supplied a resolver, use it to determine + * the address to disassemble */ + if ( resolver ) { + next_addr = resolver(op, &insn, r_arg); + } else { + next_addr = internal_resolver(op, &insn); + } + + if (next_addr != -1 ) { + next_offset = next_addr - buf_rva; + /* if offset is in this buffer... */ + if ( (uint32_t)next_addr >= buf_rva && + next_offset < buf_len ) { + /* go ahead and disassemble */ + count += x86_disasm_forward( buf, + buf_len, + buf_rva, + next_offset, + func, arg, + resolver, r_arg ); + } else { + /* report unresolved address */ + x86_report_error( report_disasm_bounds, + (void*)(long)next_addr ); + } + } + } /* end follow_insn */ + + if ( insn_doesnt_return(&insn) ) { + /* stop disassembling */ + cont = 0; + } + + x86_oplist_free( &insn ); + } + return( count ); +} + +/* invariant instruction representation */ +size_t x86_invariant_disasm( unsigned char *buf, int buf_len, + x86_invariant_t *inv ){ + if (! buf || ! buf_len || ! inv ) { + return(0); + } + + return ia32_disasm_invariant(buf, buf_len, inv); +} +size_t x86_size_disasm( unsigned char *buf, unsigned int buf_len ) { + if (! buf || ! buf_len ) { + return(0); + } + + return ia32_disasm_size(buf, buf_len); +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_format.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_format.c new file mode 100644 index 0000000000..0ec960dc8f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_format.c @@ -0,0 +1,1430 @@ +#include +#include +#include + +#include "libdis.h" +#include + +#ifdef _MSC_VER + #define snprintf _snprintf + #define inline __inline +#endif + + +/* + * concatenation macros. STRNCATF concatenates a format string, buf + * only with one argument. + */ +#define STRNCAT( buf, str, len ) do { \ + int _i = strlen(str), _blen = strlen(buf), _len = len - 1; \ + if ( len ) { \ + strncat( buf, str, _len ); \ + if ( _len <= _i ) { \ + buf[_blen+_len] = '\0'; \ + len = 0; \ + } else { \ + len -= _i; \ + } \ + } \ +} while( 0 ) + +#define STRNCATF( buf, fmt, data, len ) do { \ + char _tmp[MAX_OP_STRING]; \ + \ + snprintf( _tmp, sizeof _tmp, fmt, data ); \ + STRNCAT( buf, _tmp, len ); \ +} while( 0 ) + + +#define PRINT_DISPLACEMENT( ea ) do { \ + if ( ea->disp_size && ea->disp ) { \ + if ( ea->disp_sign ) { \ + STRNCATF( buf, "-0x%" PRIX32, -ea->disp, len ); \ + } else { \ + STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); \ + } \ + } \ +} while( 0 ) + +static const char *prefix_strings[] = { + "", /* no prefix */ + "repz ", /* the trailing spaces make it easy to prepend to mnemonic */ + "repnz ", + "lock ", + "branch delay " /* unused in x86 */ +}; + +static int format_insn_prefix_str( enum x86_insn_prefix prefix, char *buf, + int len ) { + + int len_orig = len; + + /* concat all prefix strings */ + if ( prefix & 1 ) { STRNCAT( buf, prefix_strings[1], len ); } + if ( prefix & 2 ) { STRNCAT( buf, prefix_strings[2], len ); } + if ( prefix & 4 ) { STRNCAT( buf, prefix_strings[3], len ); } + if ( prefix & 8 ) { STRNCAT( buf, prefix_strings[4], len ); } + + /* return the number of characters added */ + return (len_orig - len); +} + +/* + * sprint's an operand's data to string str. + */ +static void get_operand_data_str( x86_op_t *op, char *str, int len ){ + + if ( op->flags & op_signed ) { + switch ( op->datatype ) { + case op_byte: + snprintf( str, len, "%" PRId8, op->data.sbyte ); + return; + case op_word: + snprintf( str, len, "%" PRId16, op->data.sword ); + return; + case op_qword: + snprintf( str, len, "%" PRId64, op->data.sqword ); + return; + default: + snprintf( str, len, "%" PRId32, op->data.sdword ); + return; + } + } + + //else + switch ( op->datatype ) { + case op_byte: + snprintf( str, len, "0x%02" PRIX8, op->data.byte ); + return; + case op_word: + snprintf( str, len, "0x%04" PRIX16, op->data.word ); + return; + case op_qword: + snprintf( str, len, "0x%08" PRIX64,op->data.sqword ); + return; + default: + snprintf( str, len, "0x%08" PRIX32, op->data.dword ); + return; + } +} + +/* + * sprints register types to a string. the register types can be ORed + * together. + */ +static void get_operand_regtype_str( int regtype, char *str, int len ) +{ + static struct { + const char *name; + int value; + } operand_regtypes[] = { + {"reg_gen" , 0x00001}, + {"reg_in" , 0x00002}, + {"reg_out" , 0x00004}, + {"reg_local" , 0x00008}, + {"reg_fpu" , 0x00010}, + {"reg_seg" , 0x00020}, + {"reg_simd" , 0x00040}, + {"reg_sys" , 0x00080}, + {"reg_sp" , 0x00100}, + {"reg_fp" , 0x00200}, + {"reg_pc" , 0x00400}, + {"reg_retaddr", 0x00800}, + {"reg_cond" , 0x01000}, + {"reg_zero" , 0x02000}, + {"reg_ret" , 0x04000}, + {"reg_src" , 0x10000}, + {"reg_dest" , 0x20000}, + {"reg_count" , 0x40000}, + {NULL, 0}, //end + }; + + unsigned int i; + + memset( str, 0, len ); + + //go thru every type in the enum + for ( i = 0; operand_regtypes[i].name; i++ ) { + //skip if type is not set + if(! (regtype & operand_regtypes[i].value) ) + continue; + + //not the first time around + if( str[0] ) { + STRNCAT( str, " ", len ); + } + + STRNCAT(str, operand_regtypes[i].name, len ); + } +} + +static int format_expr( x86_ea_t *ea, char *buf, int len, + enum x86_asm_format format ) { + char str[MAX_OP_STRING]; + + if ( format == att_syntax ) { + if (ea->base.name[0] || ea->index.name[0] || ea->scale) { + PRINT_DISPLACEMENT(ea); + STRNCAT( buf, "(", len ); + + if ( ea->base.name[0]) { + STRNCATF( buf, "%%%s", ea->base.name, len ); + } + if ( ea->index.name[0]) { + STRNCATF( buf, ",%%%s", ea->index.name, len ); + if ( ea->scale > 1 ) { + STRNCATF( buf, ",%d", ea->scale, len ); + } + } + /* handle the syntactic exception */ + if ( ! ea->base.name[0] && + ! ea->index.name[0] ) { + STRNCATF( buf, ",%d", ea->scale, len ); + } + + STRNCAT( buf, ")", len ); + } else + STRNCATF( buf, "0x%" PRIX32, ea->disp, len ); + + } else if ( format == xml_syntax ){ + + if ( ea->base.name[0]) { + STRNCAT (buf, "\t\t\t\n", len); + + get_operand_regtype_str (ea->base.type, str, + sizeof str); + STRNCAT (buf, "\t\t\t\tbase.name, len); + STRNCATF (buf, "type=\"%s\" ", str, len); + STRNCATF (buf, "size=%d/>\n", ea->base.size, len); + + STRNCAT (buf, "\t\t\t\n", len); + } + + if ( ea->index.name[0]) { + STRNCAT (buf, "\t\t\t\n", len); + + get_operand_regtype_str (ea->index.type, str, + sizeof str); + + STRNCAT (buf, "\t\t\t\tindex.name, len); + STRNCATF (buf, "type=\"%s\" ", str, len); + STRNCATF (buf, "size=%d/>\n", ea->index.size, len); + + STRNCAT (buf, "\t\t\t\n", len); + } + + //scale + STRNCAT (buf, "\t\t\t\n", len); + STRNCAT (buf, "\t\t\t\t\n", ea->scale, len); + STRNCAT (buf, "\t\t\t\n", len); + + if ( ea->disp_size ) { + + STRNCAT (buf, "\t\t\t\n", len); + + if ( ea->disp_size > 1 && ! ea->disp_sign ) { + STRNCAT (buf, "\t\t\t\t
\n", ea->disp, + len); + } else { + STRNCAT (buf, "\t\t\t\t\n", ea->disp, len); + } + + STRNCAT (buf, "\t\t\t\n", len); + } + + } else if ( format == raw_syntax ) { + + PRINT_DISPLACEMENT(ea); + STRNCAT( buf, "(", len ); + + STRNCATF( buf, "%s,", ea->base.name, len ); + STRNCATF( buf, "%s,", ea->index.name, len ); + STRNCATF( buf, "%d", ea->scale, len ); + STRNCAT( buf, ")", len ); + + } else { + + STRNCAT( buf, "[", len ); + + if ( ea->base.name[0] ) { + STRNCAT( buf, ea->base.name, len ); + if ( ea->index.name[0] || + (ea->disp_size && ! ea->disp_sign) ) { + STRNCAT( buf, "+", len ); + } + } + if ( ea->index.name[0] ) { + STRNCAT( buf, ea->index.name, len ); + if ( ea->scale > 1 ) + { + STRNCATF( buf, "*%" PRId32, ea->scale, len ); + } + if ( ea->disp_size && ! ea->disp_sign ) + { + STRNCAT( buf, "+", len ); + } + } + + if ( ea->disp_size || (! ea->index.name[0] && + ! ea->base.name[0] ) ) + { + PRINT_DISPLACEMENT(ea); + } + + STRNCAT( buf, "]", len ); + } + + return( strlen(buf) ); +} + +static int format_seg( x86_op_t *op, char *buf, int len, + enum x86_asm_format format ) { + int len_orig = len; + const char *reg = ""; + + if (! op || ! buf || ! len || ! op->flags) { + return(0); + } + if ( op->type != op_offset && op->type != op_expression ){ + return(0); + } + if (! ((int) op->flags & 0xF00) ) { + return(0); + } + + switch (op->flags & 0xF00) { + case op_es_seg: reg = "es"; break; + case op_cs_seg: reg = "cs"; break; + case op_ss_seg: reg = "ss"; break; + case op_ds_seg: reg = "ds"; break; + case op_fs_seg: reg = "fs"; break; + case op_gs_seg: reg = "gs"; break; + default: + break; + } + + if (! reg[0] ) { + return( 0 ); + } + + switch( format ) { + case xml_syntax: + STRNCAT( buf, "\t\t\t\n", reg, len ); + break; + case att_syntax: + STRNCATF( buf, "%%%s:", reg, len ); + break; + + default: + STRNCATF( buf, "%s:", reg, len ); + break; + } + + return( len_orig - len ); /* return length of appended string */ +} + +static const char *get_operand_datatype_str( x86_op_t *op ){ + + static const char *types[] = { + "sbyte", /* 0 */ + "sword", + "sqword", + "sdword", + "sdqword", /* 4 */ + "byte", + "word", + "qword", + "dword", /* 8 */ + "dqword", + "sreal", + "dreal", + "extreal", /* 12 */ + "bcd", + "ssimd", + "dsimd", + "sssimd", /* 16 */ + "sdsimd", + "descr32", + "descr16", + "pdescr32", /* 20 */ + "pdescr16", + "bounds16", + "bounds32", + "fpu_env16", + "fpu_env32", /* 25 */ + "fpu_state16", + "fpu_state32", + "fp_reg_set" + }; + + /* handle signed values first */ + if ( op->flags & op_signed ) { + switch (op->datatype) { + case op_byte: return types[0]; + case op_word: return types[1]; + case op_qword: return types[2]; + case op_dqword: return types[4]; + default: return types[3]; + } + } + + switch (op->datatype) { + case op_byte: return types[5]; + case op_word: return types[6]; + case op_qword: return types[7]; + case op_dqword: return types[9]; + case op_sreal: return types[10]; + case op_dreal: return types[11]; + case op_extreal: return types[12]; + case op_bcd: return types[13]; + case op_ssimd: return types[14]; + case op_dsimd: return types[15]; + case op_sssimd: return types[16]; + case op_sdsimd: return types[17]; + case op_descr32: return types[18]; + case op_descr16: return types[19]; + case op_pdescr32: return types[20]; + case op_pdescr16: return types[21]; + case op_bounds16: return types[22]; + case op_bounds32: return types[23]; + case op_fpustate16: return types[24]; + case op_fpustate32: return types[25]; + case op_fpuenv16: return types[26]; + case op_fpuenv32: return types[27]; + case op_fpregset: return types[28]; + default: return types[8]; + } +} + +static int format_insn_eflags_str( enum x86_flag_status flags, char *buf, + int len) { + + static struct { + const char *name; + int value; + } insn_flags[] = { + { "carry_set ", 0x0001 }, + { "zero_set ", 0x0002 }, + { "oflow_set ", 0x0004 }, + { "dir_set ", 0x0008 }, + { "sign_set ", 0x0010 }, + { "parity_set ", 0x0020 }, + { "carry_or_zero_set ", 0x0040 }, + { "zero_set_or_sign_ne_oflow ", 0x0080 }, + { "carry_clear ", 0x0100 }, + { "zero_clear ", 0x0200 }, + { "oflow_clear ", 0x0400 }, + { "dir_clear ", 0x0800 }, + { "sign_clear ", 0x1000 }, + { "parity_clear ", 0x2000 }, + { "sign_eq_oflow ", 0x4000 }, + { "sign_ne_oflow ", 0x8000 }, + { NULL, 0x0000 }, //end + }; + + unsigned int i; + int len_orig = len; + + for (i = 0; insn_flags[i].name; i++) { + if (! (flags & insn_flags[i].value) ) + continue; + + STRNCAT( buf, insn_flags[i].name, len ); + } + + return( len_orig - len ); +} + +static const char *get_insn_group_str( enum x86_insn_group gp ) { + + static const char *types[] = { + "", // 0 + "controlflow",// 1 + "arithmetic", // 2 + "logic", // 3 + "stack", // 4 + "comparison", // 5 + "move", // 6 + "string", // 7 + "bit_manip", // 8 + "flag_manip", // 9 + "fpu", // 10 + "", // 11 + "", // 12 + "interrupt", // 13 + "system", // 14 + "other", // 15 + }; + + if ( gp > sizeof (types)/sizeof(types[0]) ) + return ""; + + return types[gp]; +} + +static const char *get_insn_type_str( enum x86_insn_type type ) { + + static struct { + const char *name; + int value; + } types[] = { + /* insn_controlflow */ + { "jmp", 0x1001 }, + { "jcc", 0x1002 }, + { "call", 0x1003 }, + { "callcc", 0x1004 }, + { "return", 0x1005 }, + { "loop", 0x1006 }, + /* insn_arithmetic */ + { "add", 0x2001 }, + { "sub", 0x2002 }, + { "mul", 0x2003 }, + { "div", 0x2004 }, + { "inc", 0x2005 }, + { "dec", 0x2006 }, + { "shl", 0x2007 }, + { "shr", 0x2008 }, + { "rol", 0x2009 }, + { "ror", 0x200A }, + /* insn_logic */ + { "and", 0x3001 }, + { "or", 0x3002 }, + { "xor", 0x3003 }, + { "not", 0x3004 }, + { "neg", 0x3005 }, + /* insn_stack */ + { "push", 0x4001 }, + { "pop", 0x4002 }, + { "pushregs", 0x4003 }, + { "popregs", 0x4004 }, + { "pushflags", 0x4005 }, + { "popflags", 0x4006 }, + { "enter", 0x4007 }, + { "leave", 0x4008 }, + /* insn_comparison */ + { "test", 0x5001 }, + { "cmp", 0x5002 }, + /* insn_move */ + { "mov", 0x6001 }, /* move */ + { "movcc", 0x6002 }, /* conditional move */ + { "xchg", 0x6003 }, /* exchange */ + { "xchgcc", 0x6004 }, /* conditional exchange */ + /* insn_string */ + { "strcmp", 0x7001 }, + { "strload", 0x7002 }, + { "strmov", 0x7003 }, + { "strstore", 0x7004 }, + { "translate", 0x7005 }, /* xlat */ + /* insn_bit_manip */ + { "bittest", 0x8001 }, + { "bitset", 0x8002 }, + { "bitclear", 0x8003 }, + /* insn_flag_manip */ + { "clear_carry", 0x9001 }, + { "clear_zero", 0x9002 }, + { "clear_oflow", 0x9003 }, + { "clear_dir", 0x9004 }, + { "clear_sign", 0x9005 }, + { "clear_parity", 0x9006 }, + { "set_carry", 0x9007 }, + { "set_zero", 0x9008 }, + { "set_oflow", 0x9009 }, + { "set_dir", 0x900A }, + { "set_sign", 0x900B }, + { "set_parity", 0x900C }, + { "tog_carry", 0x9010 }, + { "tog_zero", 0x9020 }, + { "tog_oflow", 0x9030 }, + { "tog_dir", 0x9040 }, + { "tog_sign", 0x9050 }, + { "tog_parity", 0x9060 }, + /* insn_fpu */ + { "fmov", 0xA001 }, + { "fmovcc", 0xA002 }, + { "fneg", 0xA003 }, + { "fabs", 0xA004 }, + { "fadd", 0xA005 }, + { "fsub", 0xA006 }, + { "fmul", 0xA007 }, + { "fdiv", 0xA008 }, + { "fsqrt", 0xA009 }, + { "fcmp", 0xA00A }, + { "fcos", 0xA00C }, + { "fldpi", 0xA00D }, + { "fldz", 0xA00E }, + { "ftan", 0xA00F }, + { "fsine", 0xA010 }, + { "fsys", 0xA020 }, + /* insn_interrupt */ + { "int", 0xD001 }, + { "intcc", 0xD002 }, /* not present in x86 ISA */ + { "iret", 0xD003 }, + { "bound", 0xD004 }, + { "debug", 0xD005 }, + { "trace", 0xD006 }, + { "invalid_op", 0xD007 }, + { "oflow", 0xD008 }, + /* insn_system */ + { "halt", 0xE001 }, + { "in", 0xE002 }, /* input from port/bus */ + { "out", 0xE003 }, /* output to port/bus */ + { "cpuid", 0xE004 }, + /* insn_other */ + { "nop", 0xF001 }, + { "bcdconv", 0xF002 }, /* convert to or from BCD */ + { "szconv", 0xF003 }, /* change size of operand */ + { NULL, 0 }, //end + }; + + unsigned int i; + + //go thru every type in the enum + for ( i = 0; types[i].name; i++ ) { + if ( types[i].value == type ) + return types[i].name; + } + + return ""; +} + +static const char *get_insn_cpu_str( enum x86_insn_cpu cpu ) { + static const char *intel[] = { + "", // 0 + "8086", // 1 + "80286", // 2 + "80386", // 3 + "80387", // 4 + "80486", // 5 + "Pentium", // 6 + "Pentium Pro", // 7 + "Pentium 2", // 8 + "Pentium 3", // 9 + "Pentium 4" // 10 + }; + + if ( cpu < sizeof(intel)/sizeof(intel[0]) ) { + return intel[cpu]; + } else if ( cpu == 16 ) { + return "K6"; + } else if ( cpu == 32 ) { + return "K7"; + } else if ( cpu == 48 ) { + return "Athlon"; + } + + return ""; +} + +static const char *get_insn_isa_str( enum x86_insn_isa isa ) { + static const char *subset[] = { + NULL, // 0 + "General Purpose", // 1 + "Floating Point", // 2 + "FPU Management", // 3 + "MMX", // 4 + "SSE", // 5 + "SSE2", // 6 + "SSE3", // 7 + "3DNow!", // 8 + "System" // 9 + }; + + if ( isa > sizeof (subset)/sizeof(subset[0]) ) { + return ""; + } + + return subset[isa]; +} + +static int format_operand_att( x86_op_t *op, x86_insn_t *insn, char *buf, + int len){ + + char str[MAX_OP_STRING]; + + memset (str, 0, sizeof str); + + switch ( op->type ) { + case op_register: + STRNCATF( buf, "%%%s", op->data.reg.name, len ); + break; + + case op_immediate: + get_operand_data_str( op, str, sizeof str ); + STRNCATF( buf, "$%s", str, len ); + break; + + case op_relative_near: + STRNCATF( buf, "0x%08X", + (unsigned int)(op->data.sbyte + + insn->addr + insn->size), len ); + break; + + case op_relative_far: + if (op->datatype == op_word) { + STRNCATF( buf, "0x%08X", + (unsigned int)(op->data.sword + + insn->addr + insn->size), len ); + } else { + STRNCATF( buf, "0x%08X", + (unsigned int)(op->data.sdword + + insn->addr + insn->size), len ); + } + break; + + case op_absolute: + /* ATT uses the syntax $section, $offset */ + STRNCATF( buf, "$0x%04" PRIX16 ", ", op->data.absolute.segment, + len ); + if (op->datatype == op_descr16) { + STRNCATF( buf, "$0x%04" PRIX16, + op->data.absolute.offset.off16, len ); + } else { + STRNCATF( buf, "$0x%08" PRIX32, + op->data.absolute.offset.off32, len ); + } + break; + case op_offset: + /* ATT requires a '*' before JMP/CALL ops */ + if (insn->type == insn_jmp || insn->type == insn_call) + STRNCAT( buf, "*", len ); + + len -= format_seg( op, buf, len, att_syntax ); + STRNCATF( buf, "0x%08" PRIX32, op->data.sdword, len ); + break; + + case op_expression: + /* ATT requires a '*' before JMP/CALL ops */ + if (insn->type == insn_jmp || insn->type == insn_call) + STRNCAT( buf, "*", len ); + + len -= format_seg( op, buf, len, att_syntax ); + len -= format_expr( &op->data.expression, buf, len, + att_syntax ); + break; + case op_unused: + case op_unknown: + /* return 0-truncated buffer */ + break; + } + + return ( strlen( buf ) ); +} + +static int format_operand_native( x86_op_t *op, x86_insn_t *insn, char *buf, + int len){ + + char str[MAX_OP_STRING]; + + switch (op->type) { + case op_register: + STRNCAT( buf, op->data.reg.name, len ); + break; + + case op_immediate: + get_operand_data_str( op, str, sizeof str ); + STRNCAT( buf, str, len ); + break; + + case op_relative_near: + STRNCATF( buf, "0x%08" PRIX32, + (unsigned int)(op->data.sbyte + + insn->addr + insn->size), len ); + break; + + case op_relative_far: + if ( op->datatype == op_word ) { + STRNCATF( buf, "0x%08" PRIX32, + (unsigned int)(op->data.sword + + insn->addr + insn->size), len ); + break; + } else { + STRNCATF( buf, "0x%08" PRIX32, op->data.sdword + + insn->addr + insn->size, len ); + } + break; + + case op_absolute: + STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment, + len ); + if (op->datatype == op_descr16) { + STRNCATF( buf, "0x%04" PRIX16, + op->data.absolute.offset.off16, len ); + } else { + STRNCATF( buf, "0x%08" PRIX32, + op->data.absolute.offset.off32, len ); + } + break; + + case op_offset: + len -= format_seg( op, buf, len, native_syntax ); + STRNCATF( buf, "[0x%08" PRIX32 "]", op->data.sdword, len ); + break; + + case op_expression: + len -= format_seg( op, buf, len, native_syntax ); + len -= format_expr( &op->data.expression, buf, len, + native_syntax ); + break; + case op_unused: + case op_unknown: + /* return 0-truncated buffer */ + break; + } + + return( strlen( buf ) ); +} + +static int format_operand_xml( x86_op_t *op, x86_insn_t *insn, char *buf, + int len){ + + char str[MAX_OP_STRING] = "\0"; + + switch (op->type) { + case op_register: + + get_operand_regtype_str( op->data.reg.type, str, + sizeof str ); + + STRNCAT( buf, "\t\tdata.reg.name, len ); + STRNCATF( buf, "type=\"%s\" ", str, len ); + STRNCATF( buf, "size=%d/>\n", op->data.reg.size, len ); + break; + + case op_immediate: + + get_operand_data_str( op, str, sizeof str ); + + STRNCAT( buf, "\t\t\n", str, len ); + break; + + case op_relative_near: + STRNCAT( buf, "\t\t\n", + (unsigned int)(op->data.sbyte + + insn->addr + insn->size), len ); + break; + + case op_relative_far: + STRNCAT( buf, "\t\tdatatype == op_word) { + STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n", + (unsigned int)(op->data.sword + + insn->addr + insn->size), len); + break; + } else { + + STRNCATF( buf, "value=\"0x%08" PRIX32 "\"/>\n", + op->data.sdword + insn->addr + insn->size, + len ); + } + break; + + case op_absolute: + + STRNCATF( buf, + "\t\tdata.absolute.segment, len ); + + if (op->datatype == op_descr16) { + STRNCATF( buf, "offset=\"0x%04" PRIX16 "\">", + op->data.absolute.offset.off16, len ); + } else { + STRNCATF( buf, "offset=\"0x%08" PRIX32 "\">", + op->data.absolute.offset.off32, len ); + } + + STRNCAT( buf, "\t\t\n", len ); + break; + + case op_expression: + + + STRNCAT( buf, "\t\t\n", len ); + + len -= format_seg( op, buf, len, xml_syntax ); + len -= format_expr( &op->data.expression, buf, len, + xml_syntax ); + + STRNCAT( buf, "\t\t\n", len ); + break; + + case op_offset: + + STRNCAT( buf, "\t\t\n", len ); + + len -= format_seg( op, buf, len, xml_syntax ); + + STRNCAT( buf, "\t\t\t
\n", + op->data.sdword, len ); + STRNCAT( buf, "\t\t\n", len ); + break; + + case op_unused: + case op_unknown: + /* return 0-truncated buffer */ + break; + } + + return( strlen( buf ) ); +} + +static int format_operand_raw( x86_op_t *op, x86_insn_t *insn, char *buf, + int len){ + + char str[MAX_OP_RAW_STRING]; + const char *datatype = get_operand_datatype_str(op); + + switch (op->type) { + case op_register: + + get_operand_regtype_str( op->data.reg.type, str, + sizeof str ); + + STRNCAT( buf, "reg|", len ); + STRNCATF( buf, "%s|", datatype, len ); + STRNCATF( buf, "%s:", op->data.reg.name, len ); + STRNCATF( buf, "%s:", str, len ); + STRNCATF( buf, "%d|", op->data.reg.size, len ); + break; + + case op_immediate: + + get_operand_data_str( op, str, sizeof str ); + + STRNCAT( buf, "immediate|", len ); + STRNCATF( buf, "%s|", datatype, len ); + STRNCATF( buf, "%s|", str, len ); + break; + + case op_relative_near: + /* NOTE: in raw format, we print the + * relative offset, not the actual + * address of the jump target */ + + STRNCAT( buf, "relative|", len ); + STRNCATF( buf, "%s|", datatype, len ); + STRNCATF( buf, "%" PRId8 "|", op->data.sbyte, len ); + break; + + case op_relative_far: + + STRNCAT( buf, "relative|", len ); + STRNCATF( buf, "%s|", datatype, len ); + + if (op->datatype == op_word) { + STRNCATF( buf, "%" PRId16 "|", op->data.sword, len); + break; + } else { + STRNCATF( buf, "%" PRId32 "|", op->data.sdword, len ); + } + break; + + case op_absolute: + + STRNCAT( buf, "absolute_address|", len ); + STRNCATF( buf, "%s|", datatype, len ); + + STRNCATF( buf, "$0x%04" PRIX16 ":", op->data.absolute.segment, + len ); + if (op->datatype == op_descr16) { + STRNCATF( buf, "0x%04" PRIX16 "|", + op->data.absolute.offset.off16, len ); + } else { + STRNCATF( buf, "0x%08" PRIX32 "|", + op->data.absolute.offset.off32, len ); + } + + break; + + case op_expression: + + STRNCAT( buf, "address_expression|", len ); + STRNCATF( buf, "%s|", datatype, len ); + + len -= format_seg( op, buf, len, native_syntax ); + len -= format_expr( &op->data.expression, buf, len, + raw_syntax ); + + STRNCAT( buf, "|", len ); + break; + + case op_offset: + + STRNCAT( buf, "segment_offset|", len ); + STRNCATF( buf, "%s|", datatype, len ); + + len -= format_seg( op, buf, len, xml_syntax ); + + STRNCATF( buf, "%08" PRIX32 "|", op->data.sdword, len ); + break; + + case op_unused: + case op_unknown: + /* return 0-truncated buffer */ + break; + } + + return( strlen( buf ) ); +} + +int x86_format_operand( x86_op_t *op, char *buf, int len, + enum x86_asm_format format ){ + x86_insn_t *insn; + + if ( ! op || ! buf || len < 1 ) { + return(0); + } + + /* insn is stored in x86_op_t since .21-pre3 */ + insn = (x86_insn_t *) op->insn; + + memset( buf, 0, len ); + + switch ( format ) { + case att_syntax: + return format_operand_att( op, insn, buf, len ); + case xml_syntax: + return format_operand_xml( op, insn, buf, len ); + case raw_syntax: + return format_operand_raw( op, insn, buf, len ); + case native_syntax: + case intel_syntax: + default: + return format_operand_native( op, insn, buf, len ); + } +} + +#define is_imm_jmp(op) (op->type == op_absolute || \ + op->type == op_immediate || \ + op->type == op_offset) +#define is_memory_op(op) (op->type == op_absolute || \ + op->type == op_expression || \ + op->type == op_offset) + +static int format_att_mnemonic( x86_insn_t *insn, char *buf, int len) { + int size = 0; + const char *suffix; + + if (! insn || ! buf || ! len ) + return(0); + + memset( buf, 0, len ); + + /* do long jump/call prefix */ + if ( insn->type == insn_jmp || insn->type == insn_call ) { + if (! is_imm_jmp( x86_operand_1st(insn) ) || + (x86_operand_1st(insn))->datatype != op_byte ) { + /* far jump/call, use "l" prefix */ + STRNCAT( buf, "l", len ); + } + STRNCAT( buf, insn->mnemonic, len ); + + return ( strlen( buf ) ); + } + + /* do mnemonic */ + STRNCAT( buf, insn->mnemonic, len ); + + /* do suffixes for memory operands */ + if (!(insn->note & insn_note_nosuffix) && + (insn->group == insn_arithmetic || + insn->group == insn_logic || + insn->group == insn_move || + insn->group == insn_stack || + insn->group == insn_string || + insn->group == insn_comparison || + insn->type == insn_in || + insn->type == insn_out + )) { + if ( x86_operand_count( insn, op_explicit ) > 0 && + is_memory_op( x86_operand_1st(insn) ) ){ + size = x86_operand_size( x86_operand_1st( insn ) ); + } else if ( x86_operand_count( insn, op_explicit ) > 1 && + is_memory_op( x86_operand_2nd(insn) ) ){ + size = x86_operand_size( x86_operand_2nd( insn ) ); + } + } + + if ( size == 1 ) suffix = "b"; + else if ( size == 2 ) suffix = "w"; + else if ( size == 4 ) suffix = "l"; + else if ( size == 8 ) suffix = "q"; + else suffix = ""; + + STRNCAT( buf, suffix, len ); + return ( strlen( buf ) ); +} + +int x86_format_mnemonic(x86_insn_t *insn, char *buf, int len, + enum x86_asm_format format){ + char str[MAX_OP_STRING]; + + memset( buf, 0, len ); + STRNCAT( buf, insn->prefix_string, len ); + if ( format == att_syntax ) { + format_att_mnemonic( insn, str, sizeof str ); + STRNCAT( buf, str, len ); + } else { + STRNCAT( buf, insn->mnemonic, len ); + } + + return( strlen( buf ) ); +} + +struct op_string { char *buf; size_t len; }; + +static void format_op_raw( x86_op_t *op, x86_insn_t *insn, void *arg ) { + struct op_string * opstr = (struct op_string *) arg; + + format_operand_raw(op, insn, opstr->buf, opstr->len); +} + +static int format_insn_note(x86_insn_t *insn, char *buf, int len){ + char note[32] = {0}; + int len_orig = len, note_len = 32; + + if ( insn->note & insn_note_ring0 ) { + STRNCATF( note, "%s", "Ring0 ", note_len ); + } + if ( insn->note & insn_note_smm ) { + STRNCATF( note, "%s", "SMM ", note_len ); + } + if ( insn->note & insn_note_serial ) { + STRNCATF(note, "%s", "Serialize ", note_len ); + } + STRNCATF( buf, "%s|", note, len ); + + return( len_orig - len ); +} + +static int format_raw_insn( x86_insn_t *insn, char *buf, int len ){ + struct op_string opstr = { buf, len }; + int i; + + /* RAW style: + * ADDRESS|OFFSET|SIZE|BYTES| + * PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES| + * MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED| + * STACK_MOD|STACK_MOD_VAL + * [|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]* + * + * Register values are encoded as: + * NAME:TYPE:SIZE + * + * Effective addresses are encoded as: + * disp(base_reg,index_reg,scale) + */ + STRNCATF( buf, "0x%08" PRIX32 "|", insn->addr , len ); + STRNCATF( buf, "0x%08" PRIX32 "|", insn->offset, len ); + STRNCATF( buf, "%d|" , insn->size , len ); + + /* print bytes */ + for ( i = 0; i < insn->size; i++ ) { + STRNCATF( buf, "%02X ", insn->bytes[i], len ); + } + STRNCAT( buf, "|", len ); + + len -= format_insn_prefix_str( insn->prefix, buf, len ); + STRNCATF( buf, "|%s|", insn->prefix_string , len ); + STRNCATF( buf, "%s|", get_insn_group_str( insn->group ), len ); + STRNCATF( buf, "%s|", get_insn_type_str( insn->type ) , len ); + STRNCATF( buf, "%s|", insn->mnemonic , len ); + STRNCATF( buf, "%s|", get_insn_cpu_str( insn->cpu ) , len ); + STRNCATF( buf, "%s|", get_insn_isa_str( insn->isa ) , len ); + + /* insn note */ + len -= format_insn_note( insn, buf, len ); + + len -= format_insn_eflags_str( insn->flags_set, buf, len ); + STRNCAT( buf, "|", len ); + len -= format_insn_eflags_str( insn->flags_tested, buf, len ); + STRNCAT( buf, "|", len ); + STRNCATF( buf, "%d|", insn->stack_mod, len ); + STRNCATF( buf, "%" PRId32 "|", insn->stack_mod_val, len ); + + opstr.len = len; + x86_operand_foreach( insn, format_op_raw, &opstr, op_any ); + + return( strlen (buf) ); +} + +static int format_xml_insn( x86_insn_t *insn, char *buf, int len ) { + char str[MAX_OP_XML_STRING]; + int i; + + STRNCAT( buf, "\n", len ); + + STRNCATF( buf, "\t
addr, len ); + STRNCATF( buf, "offset=\"0x%08" PRIX32 "\" ", insn->offset, len ); + STRNCATF( buf, "size=%d bytes=\"", insn->size, len ); + + for ( i = 0; i < insn->size; i++ ) { + STRNCATF( buf, "%02X ", insn->bytes[i], len ); + } + STRNCAT( buf, "\"/>\n", len ); + + STRNCAT( buf, "\tprefix, buf, len ); + STRNCATF( buf, "\" string=\"%s\"/>\n", insn->prefix_string, len ); + + STRNCATF( buf, "\tgroup), len ); + STRNCATF( buf, "type=\"%s\" ", get_insn_type_str (insn->type), len ); + STRNCATF( buf, "string=\"%s\"/>\n", insn->mnemonic, len ); + + STRNCAT( buf, "\t\n", len ); + STRNCAT( buf, "\t\tflags_set, buf, len ); + STRNCAT( buf, "\"/>\n\t\n", len ); + + + STRNCAT( buf, "\t\n", len ); + STRNCAT( buf, "\t\tflags_tested, buf, len ); + STRNCAT( buf, "\"/>\n\t\n", len ); + + if ( x86_operand_1st( insn ) ) { + x86_format_operand( x86_operand_1st(insn), str, + sizeof str, xml_syntax); + STRNCAT( buf, "\t\n", len ); + STRNCAT( buf, str, len ); + STRNCAT( buf, "\t\n", len ); + } + + if ( x86_operand_2nd( insn ) ) { + x86_format_operand( x86_operand_2nd( insn ), str, + sizeof str, xml_syntax); + STRNCAT( buf, "\t\n", len ); + STRNCAT( buf, str, len ); + STRNCAT( buf, "\t\n", len ); + } + + if ( x86_operand_3rd( insn ) ) { + x86_format_operand( x86_operand_3rd(insn), str, + sizeof str, xml_syntax); + STRNCAT( buf, "\t\n", len ); + STRNCAT( buf, str, len ); + STRNCAT( buf, "\t\n", len ); + } + + STRNCAT( buf, "\n", len ); + + return strlen (buf); +} + +int x86_format_header( char *buf, int len, enum x86_asm_format format ) { + switch (format) { + case att_syntax: + snprintf( buf, len, "MNEMONIC\tSRC, DEST, IMM" ); + break; + case intel_syntax: + snprintf( buf, len, "MNEMONIC\tDEST, SRC, IMM" ); + break; + case native_syntax: + snprintf( buf, len, "ADDRESS\tBYTES\tMNEMONIC\t" + "DEST\tSRC\tIMM" ); + break; + case raw_syntax: + snprintf( buf, len, "ADDRESS|OFFSET|SIZE|BYTES|" + "PREFIX|PREFIX_STRING|GROUP|TYPE|NOTES|" + "MNEMONIC|CPU|ISA|FLAGS_SET|FLAGS_TESTED|" + "STACK_MOD|STACK_MOD_VAL" + "[|OP_TYPE|OP_DATATYPE|OP_ACCESS|OP_FLAGS|OP]*" + ); + break; + case xml_syntax: + snprintf( buf, len, + "" + "
" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
" + "" + "" + "" + "
" + "" + "" + "" + ); + break; + case unknown_syntax: + if ( len ) { + buf[0] = '\0'; + } + break; + } + + return( strlen(buf) ); +} + +int x86_format_insn( x86_insn_t *insn, char *buf, int len, + enum x86_asm_format format ){ + char str[MAX_OP_STRING]; + x86_op_t *src, *dst; + int i; + + memset(buf, 0, len); + if ( format == intel_syntax ) { + /* INTEL STYLE: mnemonic dest, src, imm */ + STRNCAT( buf, insn->prefix_string, len ); + STRNCAT( buf, insn->mnemonic, len ); + STRNCAT( buf, "\t", len ); + + /* dest */ + if ( (dst = x86_operand_1st( insn )) && !(dst->flags & op_implied) ) { + x86_format_operand( dst, str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + } + + /* src */ + if ( (src = x86_operand_2nd( insn )) ) { + if ( !(dst->flags & op_implied) ) { + STRNCAT( buf, ", ", len ); + } + x86_format_operand( src, str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + } + + /* imm */ + if ( x86_operand_3rd( insn )) { + STRNCAT( buf, ", ", len ); + x86_format_operand( x86_operand_3rd( insn ), + str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + } + + } else if ( format == att_syntax ) { + /* ATT STYLE: mnemonic src, dest, imm */ + STRNCAT( buf, insn->prefix_string, len ); + format_att_mnemonic(insn, str, MAX_OP_STRING); + STRNCATF( buf, "%s\t", str, len); + + + /* not sure which is correct? sometimes GNU as requires + * an imm as the first operand, sometimes as the third... */ + /* imm */ + if ( x86_operand_3rd( insn ) ) { + x86_format_operand(x86_operand_3rd( insn ), + str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + /* there is always 'dest' operand if there is 'src' */ + STRNCAT( buf, ", ", len ); + } + + if ( (insn->note & insn_note_nonswap ) == 0 ) { + /* regular AT&T style swap */ + src = x86_operand_2nd( insn ); + dst = x86_operand_1st( insn ); + } + else { + /* special-case instructions */ + src = x86_operand_1st( insn ); + dst = x86_operand_2nd( insn ); + } + + /* src */ + if ( src ) { + x86_format_operand(src, str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + /* there is always 'dest' operand if there is 'src' */ + if ( dst && !(dst->flags & op_implied) ) { + STRNCAT( buf, ", ", len ); + } + } + + /* dest */ + if ( dst && !(dst->flags & op_implied) ) { + x86_format_operand( dst, str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + } + + + } else if ( format == raw_syntax ) { + format_raw_insn( insn, buf, len ); + } else if ( format == xml_syntax ) { + format_xml_insn( insn, buf, len ); + } else { /* default to native */ + /* NATIVE style: RVA\tBYTES\tMNEMONIC\tOPERANDS */ + /* print address */ + STRNCATF( buf, "%08" PRIX32 "\t", insn->addr, len ); + + /* print bytes */ + for ( i = 0; i < insn->size; i++ ) { + STRNCATF( buf, "%02X ", insn->bytes[i], len ); + } + + STRNCAT( buf, "\t", len ); + + /* print mnemonic */ + STRNCAT( buf, insn->prefix_string, len ); + STRNCAT( buf, insn->mnemonic, len ); + STRNCAT( buf, "\t", len ); + + /* print operands */ + /* dest */ + if ( x86_operand_1st( insn ) ) { + x86_format_operand( x86_operand_1st( insn ), + str, MAX_OP_STRING, format); + STRNCATF( buf, "%s\t", str, len ); + } + + /* src */ + if ( x86_operand_2nd( insn ) ) { + x86_format_operand(x86_operand_2nd( insn ), + str, MAX_OP_STRING, format); + STRNCATF( buf, "%s\t", str, len ); + } + + /* imm */ + if ( x86_operand_3rd( insn )) { + x86_format_operand( x86_operand_3rd( insn ), + str, MAX_OP_STRING, format); + STRNCAT( buf, str, len ); + } + } + + return( strlen( buf ) ); +} + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.c new file mode 100644 index 0000000000..cd59bfc9ab --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.c @@ -0,0 +1,70 @@ +#include "qword.h" +#include "x86_imm.h" + +#include + +unsigned int x86_imm_signsized( unsigned char * buf, size_t buf_len, + void *dest, unsigned int size ) { + signed char *cp = (signed char *) dest; + signed short *sp = (signed short *) dest; + int32_t *lp = (int32_t *) dest; + qword_t *qp = (qword_t *) dest; + + if ( size > buf_len ) { + return 0; + } + + /* Copy 'size' bytes from *buf to *op + * return number of bytes copied */ + switch (size) { + case 1: /* BYTE */ + *cp = *((signed char *) buf); + break; + case 2: /* WORD */ + *sp = *((signed short *) buf); + break; + case 6: + case 8: /* QWORD */ + *qp = *((qword_t *) buf); + break; + case 4: /* DWORD */ + default: + *lp = *((int32_t *) buf); + break; + } + return (size); +} + +unsigned int x86_imm_sized( unsigned char * buf, size_t buf_len, void *dest, + unsigned int size ) { + unsigned char *cp = (unsigned char *) dest; + unsigned short *sp = (unsigned short *) dest; + uint32_t *lp = (uint32_t *) dest; + qword_t *qp = (qword_t *) dest; + + if ( size > buf_len ) { + return 0; + } + + /* Copy 'size' bytes from *buf to *op + * return number of bytes copied */ + switch (size) { + case 1: /* BYTE */ + *cp = *((unsigned char *) buf); + break; + case 2: /* WORD */ + *sp = *((unsigned short *) buf); + break; + case 6: + case 8: /* QWORD */ + *qp = *((qword_t *) buf); + break; + case 4: /* DWORD */ + default: + *lp = *((uint32_t *) buf); + break; + } + + return (size); +} + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.h new file mode 100644 index 0000000000..fa35ff2de4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_imm.h @@ -0,0 +1,18 @@ +#ifndef x86_IMM_H +#define x86_IMM_H + +#include "./qword.h" +#include + +#ifdef WIN32 +#include +#endif + +/* these are in the global x86 namespace but are not a part of the + * official API */ +unsigned int x86_imm_sized( unsigned char *buf, size_t buf_len, void *dest, + unsigned int size ); + +unsigned int x86_imm_signsized( unsigned char *buf, size_t buf_len, void *dest, + unsigned int size ); +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_insn.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_insn.c new file mode 100644 index 0000000000..5649b89fb8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_insn.c @@ -0,0 +1,182 @@ +#include +#include + +#include "libdis.h" + +#ifdef _MSC_VER + #define snprintf _snprintf + #define inline __inline +#endif + +int x86_insn_is_valid( x86_insn_t *insn ) { + if ( insn && insn->type != insn_invalid && insn->size > 0 ) { + return 1; + } + + return 0; +} + +uint32_t x86_get_address( x86_insn_t *insn ) { + x86_oplist_t *op_lst; + if (! insn || ! insn->operands ) { + return 0; + } + + for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) { + if ( op_lst->op.type == op_offset ) { + return op_lst->op.data.offset; + } else if ( op_lst->op.type == op_absolute ) { + if ( op_lst->op.datatype == op_descr16 ) { + return (uint32_t) + op_lst->op.data.absolute.offset.off16; + } + return op_lst->op.data.absolute.offset.off32; + } + } + + return 0; +} + +int32_t x86_get_rel_offset( x86_insn_t *insn ) { + x86_oplist_t *op_lst; + if (! insn || ! insn->operands ) { + return 0; + } + + for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) { + if ( op_lst->op.type == op_relative_near ) { + return (int32_t) op_lst->op.data.relative_near; + } else if ( op_lst->op.type == op_relative_far ) { + return op_lst->op.data.relative_far; + } + } + + return 0; +} + +x86_op_t * x86_get_branch_target( x86_insn_t *insn ) { + x86_oplist_t *op_lst; + if (! insn || ! insn->operands ) { + return NULL; + } + + for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) { + if ( op_lst->op.access & op_execute ) { + return &(op_lst->op); + } + } + + return NULL; +} +x86_op_t * x86_get_imm( x86_insn_t *insn ) { + x86_oplist_t *op_lst; + if (! insn || ! insn->operands ) { + return NULL; + } + + for (op_lst = insn->operands; op_lst; op_lst = op_lst->next ) { + if ( op_lst->op.type == op_immediate ) { + return &(op_lst->op); + } + } + + return NULL; +} + +#define IS_PROPER_IMM( x ) \ + x->op.type == op_immediate && ! (x->op.flags & op_hardcode) + + +/* if there is an immediate value in the instruction, return a pointer to + * it */ +unsigned char * x86_get_raw_imm( x86_insn_t *insn ) { + int size, offset; + x86_op_t *op = NULL; + + if (! insn || ! insn->operands ) { + return(NULL); + } + + /* a bit inelegant, but oh well... */ + if ( IS_PROPER_IMM( insn->operands ) ) { + op = &insn->operands->op; + } else if ( insn->operands->next ) { + if ( IS_PROPER_IMM( insn->operands->next ) ) { + op = &insn->operands->next->op; + } else if ( insn->operands->next->next && + IS_PROPER_IMM( insn->operands->next->next ) ) { + op = &insn->operands->next->next->op; + } + } + + if (! op ) { + return( NULL ); + } + + /* immediate data is at the end of the insn */ + size = x86_operand_size( op ); + offset = insn->size - size; + return( &insn->bytes[offset] ); +} + + +unsigned int x86_operand_size( x86_op_t *op ) { + switch (op->datatype ) { + case op_byte: return 1; + case op_word: return 2; + case op_dword: return 4; + case op_qword: return 8; + case op_dqword: return 16; + case op_sreal: return 4; + case op_dreal: return 8; + case op_extreal: return 10; + case op_bcd: return 10; + case op_ssimd: return 16; + case op_dsimd: return 16; + case op_sssimd: return 4; + case op_sdsimd: return 8; + case op_descr32: return 6; + case op_descr16: return 4; + case op_pdescr32: return 6; + case op_pdescr16: return 6; + case op_bounds16: return 4; + case op_bounds32: return 8; + case op_fpuenv16: return 14; + case op_fpuenv32: return 28; + case op_fpustate16: return 94; + case op_fpustate32: return 108; + case op_fpregset: return 512; + case op_fpreg: return 10; + case op_none: return 0; + } + return(4); /* default size */ +} + +void x86_set_insn_addr( x86_insn_t *insn, uint32_t addr ) { + if ( insn ) insn->addr = addr; +} + +void x86_set_insn_offset( x86_insn_t *insn, unsigned int offset ){ + if ( insn ) insn->offset = offset; +} + +void x86_set_insn_function( x86_insn_t *insn, void * func ){ + if ( insn ) insn->function = func; +} + +void x86_set_insn_block( x86_insn_t *insn, void * block ){ + if ( insn ) insn->block = block; +} + +void x86_tag_insn( x86_insn_t *insn ){ + if ( insn ) insn->tag = 1; +} + +void x86_untag_insn( x86_insn_t *insn ){ + if ( insn ) insn->tag = 0; +} + +int x86_insn_is_tagged( x86_insn_t *insn ){ + return insn->tag; +} + diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_misc.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_misc.c new file mode 100644 index 0000000000..3d2dd0ae8b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_misc.c @@ -0,0 +1,71 @@ +#include +#include +#include + +#include "libdis.h" +#include "ia32_insn.h" +#include "ia32_reg.h" /* for ia32_reg wrapper */ +#include "ia32_settings.h" +extern ia32_settings_t ia32_settings; + +#ifdef _MSC_VER + #define snprintf _snprintf + #define inline __inline +#endif + + +/* =========================================================== INIT/TERM */ +static DISASM_REPORTER __x86_reporter_func = NULL; +static void * __x86_reporter_arg = NULL; + +int x86_init( enum x86_options options, DISASM_REPORTER reporter, void * arg ) +{ + ia32_settings.options = options; + __x86_reporter_func = reporter; + __x86_reporter_arg = arg; + + return 1; +} + +void x86_set_reporter( DISASM_REPORTER reporter, void * arg ) { + __x86_reporter_func = reporter; + __x86_reporter_arg = arg; +} + +void x86_set_options( enum x86_options options ){ + ia32_settings.options = options; +} + +enum x86_options x86_get_options( void ) { + return ia32_settings.options; +} + +int x86_cleanup( void ) +{ + return 1; +} + +/* =========================================================== ERRORS */ +void x86_report_error( enum x86_report_codes code, void *data ) { + if ( __x86_reporter_func ) { + (*__x86_reporter_func)(code, data, __x86_reporter_arg); + } +} + + +/* =========================================================== MISC */ +unsigned int x86_endian(void) { return ia32_settings.endian; } +unsigned int x86_addr_size(void) { return ia32_settings.sz_addr; } +unsigned int x86_op_size(void) { return ia32_settings.sz_oper; } +unsigned int x86_word_size(void) { return ia32_settings.sz_word; } +unsigned int x86_max_insn_size(void) { return ia32_settings.max_insn; } +unsigned int x86_sp_reg(void) { return ia32_settings.id_sp_reg; } +unsigned int x86_fp_reg(void) { return ia32_settings.id_fp_reg; } +unsigned int x86_ip_reg(void) { return ia32_settings.id_ip_reg; } +unsigned int x86_flag_reg(void) { return ia32_settings.id_flag_reg; } + +/* wrapper function to hide the IA32 register fn */ +void x86_reg_from_id( unsigned int id, x86_reg_t * reg ) { + ia32_handle_register( reg, id ); + return; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.c b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.c new file mode 100644 index 0000000000..95409e0698 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.c @@ -0,0 +1,191 @@ +#include +#include "libdis.h" + + +static void x86_oplist_append( x86_insn_t *insn, x86_oplist_t *op ) { + x86_oplist_t *list; + + if (! insn ) { + return; + } + + list = insn->operands; + if (! list ) { + insn->operand_count = 1; + /* Note that we have no way of knowing if this is an + * exlicit operand or not, since the caller fills + * the x86_op_t after we return. We increase the + * explicit count automatically, and ia32_insn_implicit_ops + * decrements it */ + insn->explicit_count = 1; + insn->operands = op; + return; + } + + /* get to end of list */ + for ( ; list->next; list = list->next ) + ; + + insn->operand_count = insn->operand_count + 1; + insn->explicit_count = insn->explicit_count + 1; + list->next = op; + + return; +} + +x86_op_t * x86_operand_new( x86_insn_t *insn ) { + x86_oplist_t *op; + + if (! insn ) { + return(NULL); + } + op = calloc( sizeof(x86_oplist_t), 1 ); + op->op.insn = insn; + x86_oplist_append( insn, op ); + return( &(op->op) ); +} + +void x86_oplist_free( x86_insn_t *insn ) { + x86_oplist_t *op, *list; + + if (! insn ) { + return; + } + + for ( list = insn->operands; list; ) { + op = list; + list = list->next; + free(op); + } + + insn->operands = NULL; + insn->operand_count = 0; + insn->explicit_count = 0; + + return; +} + +/* ================================================== LIBDISASM API */ +/* these could probably just be #defines, but that means exposing the + enum... yet one more confusing thing in the API */ +int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg, + enum x86_op_foreach_type type ){ + x86_oplist_t *list; + char explicit = 1, implicit = 1; + + if (! insn || ! func ) { + return 0; + } + + /* note: explicit and implicit can be ORed together to + * allow an "all" limited by access type, even though the + * user is stupid to do this since it is default behavior :) */ + if ( (type & op_explicit) && ! (type & op_implicit) ) { + implicit = 0; + } + if ( (type & op_implicit) && ! (type & op_explicit) ) { + explicit = 0; + } + + type = type & 0x0F; /* mask out explicit/implicit operands */ + + for ( list = insn->operands; list; list = list->next ) { + if (! implicit && (list->op.flags & op_implied) ) { + /* operand is implicit */ + continue; + } + + if (! explicit && ! (list->op.flags & op_implied) ) { + /* operand is not implicit */ + continue; + } + + switch ( type ) { + case op_any: + break; + case op_dest: + if (! (list->op.access & op_write) ) { + continue; + } + break; + case op_src: + if (! (list->op.access & op_read) ) { + continue; + } + break; + case op_ro: + if (! (list->op.access & op_read) || + (list->op.access & op_write ) ) { + continue; + } + break; + case op_wo: + if (! (list->op.access & op_write) || + (list->op.access & op_read ) ) { + continue; + } + break; + case op_xo: + if (! (list->op.access & op_execute) ) { + continue; + } + break; + case op_rw: + if (! (list->op.access & op_write) || + ! (list->op.access & op_read ) ) { + continue; + } + break; + case op_implicit: case op_explicit: /* make gcc happy */ + break; + } + /* any non-continue ends up here: invoke the callback */ + (*func)( &list->op, insn, arg ); + } + + return 1; +} + +static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) { + size_t * count = (size_t *) arg; + *count = *count + 1; +} + +size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type ) { + size_t count = 0; + + /* save us a list traversal for common counts... */ + if ( type == op_any ) { + return insn->operand_count; + } else if ( type == op_explicit ) { + return insn->explicit_count; + } + + x86_operand_foreach( insn, count_operand, &count, type ); + return count; +} + +/* accessor functions */ +x86_op_t * x86_operand_1st( x86_insn_t *insn ) { + if (! insn->explicit_count ) { + return NULL; + } + + return &(insn->operands->op); +} + +x86_op_t * x86_operand_2nd( x86_insn_t *insn ) { + if ( insn->explicit_count < 2 ) { + return NULL; + } + + return &(insn->operands->next->op); +} + +x86_op_t * x86_operand_3rd( x86_insn_t *insn ) { + if ( insn->explicit_count < 3 ) { + return NULL; + } + + return &(insn->operands->next->next->op); +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.h b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.h new file mode 100644 index 0000000000..53668658ec --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/x86_operand_list.h @@ -0,0 +1,8 @@ +#ifndef X86_OPERAND_LIST_H +#define X86_OPERAND_LIST_H +#include "libdis.h" + + +x86_op_t * x86_operand_new( x86_insn_t *insn ); + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/.gitignore b/toolkit/crashreporter/google-breakpad/src/third_party/lss/.gitignore new file mode 100644 index 0000000000..4032eb05cb --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/.gitignore @@ -0,0 +1,3 @@ +*.o + +core diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/README.md b/toolkit/crashreporter/google-breakpad/src/third_party/lss/README.md new file mode 100644 index 0000000000..70cbc85311 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/README.md @@ -0,0 +1,137 @@ +# Linux Syscall Support (LSS) + +Every so often, projects need to directly embed Linux system calls instead of +calling the implementations in the system runtime library. + +This project provides a header file that can be included into your application +whenever you need to make direct system calls. + +The goal is to provide an API that generally mirrors the standard C library +while still making direct syscalls. We try to hide some of the differences +between arches when reasonably feasible. e.g. Newer architectures no longer +provide an `open` syscall, but do provide `openat`. We will still expose a +`sys_open` helper by default that calls into `openat` instead. + +We explicitly do not expose the raw syscall ABI including all of its historical +warts to the user. We want people to be able to easily make a syscall, not have +to worry that on some arches size args are swapped or they are shifted. + +Please be sure to review the Caveats section below however. + +## How to include linux\_syscall\_support.h in your project + +You can either copy the file into your project, or preferably, you can set up +Git submodules to automatically pull from our source repository. + +## Supported targets + +The following architectures/ABIs have been tested (at some point) and should +generally work. If you don't see your combo listed here, please double check +the header itself as this list might be out of date. + +* x86 32-bit (i.e. i386, i486, i586, i686, Intel, AMD, etc...) +* [x86_64 64-bit](https://en.wikipedia.org/wiki/X86-64) (i.e. x86-64, amd64, etc...) +* [x32 32-bit](https://sites.google.com/site/x32abi/) +* [ARM 32-bit](https://en.wikipedia.org/wiki/ARM_architecture) OABI +* [ARM 32-bit](https://en.wikipedia.org/wiki/ARM_architecture) EABI (i.e. armv6, armv7, etc...) +* AARCH64 64-bit (i.e. arm64, armv8, etc...) +* PowerPC 32-bit (i.e. ppc, ppc32, etc...) +* MIPS 32-bit o32 ABI +* MIPS 32-bit n32 ABI +* MIPS 64-bit n64 ABI + +## API + +By default, you can just add a `sys_` prefix to any function you want to call. +So if you want to call `open(...)`, use `sys_open(...)` instead. + +### Knobs + +The linux\_syscall\_support.h header provides many knobs for you to control +the exported API. These are all documented in the top of the header in a big +comment block, so refer to that instead. + +## Caveats + +### ABI differences + +Some functions that the standard C library exposes use a different ABI than +what the Linux kernel uses. Care must be taken when making syscalls directly +that you use the right structure and flags. e.g. Most C libraries define a +`struct stat` (commonly in `sys/stat.h` or `bits/stat.h`) that is different +from the `struct stat` the kernel uses (commonly in `asm/stat.h`). If you use +the wrong structure layout, then you can see errors like memory corruption or +weird/shifted values. If you plan on making syscalls directly, you should +focus on headers that are available under the `linux/` and `asm/` namespaces. + +Note: LSS provides structs for most of these cases. For `sys_stat()`, it +provides `struct kernel_stat` for you to use. + +### Transparent backwards compatibility with older kernels + +While some C libraries (notably, glibc) take care to fallback to older syscalls +when running on older kernels, there is no such support in LSS. If you plan on +trying to run on older kernels, you will need to handle errors yourself (e.g. +`ENOSYS` when using a too new syscall). + +Remember that this can happen with new flag bits too. e.g. The `O_CLOEXEC` +flag was added to many syscalls, but if you try to run use it on older kernels, +it will fail with `EINVAL`. In that case, you must handle the fallback logic +yourself. + +### Variable arguments (varargs) + +We do not support vararg type functions. e.g. While the standard `open()` +function can accept 2 or 3 arguments (with the mode field being optional), +the `sys_open()` function always requires 3 arguments. + +## Bug reports & feature requests + +If you wish to report a problem or request a feature, please file them in our +[bug tracker](https://bugs.chromium.org/p/linux-syscall-support/issues/). + +Please do not post patches to the tracker. Instead, see below for how to send +patches to us directly. + +While we welcome feature requests, please keep in mind that it is unlikely that +anyone will find time to implement them for you. Sending patches is strongly +preferred and will often move things much faster. + +## Projects that use LSS + +* [Chromium](https://www.chromium.org/) +* [Breakpad](https://chromium.googlesource.com/breakpad/breakpad) +* [Native Client](https://developer.chrome.com/native-client), in nacl\_bootstrap.c + +## How to get an LSS change committed + +### Review + +You get your change reviewed, you can upload it to +[Gerrit](https://chromium-review.googlesource.com/q/project:linux-syscall-support+status:open) +using `git cl upload` from +[Chromium's depot-tools](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html). + +### Testing + +Tests are found in the [tests/](./tests/) subdirectory. It does not (yet) offer +100% coverage, but should grow over time. + +New commits that update/change/add syscall wrappers should include tests for +them too. Consult the [test documentation](./tests/README.md) for more details. + +To run, just run `make` inside the tests directory. It will compile & execute +the tests locally. + +There is some limited cross-compile coverage available if you run `make cross`. +It only compiles things (does not execute at all). + +### Rolling into Chromium + +If you commit a change to LSS, please also commit a Chromium change to update +`lss_revision` in +[Chromium's DEPS](https://chromium.googlesource.com/chromium/src/+/master/DEPS) +file. + +This ensures that the LSS change gets tested, so that people who commit later +LSS changes don't run into problems with updating `lss_revision`. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/codereview.settings b/toolkit/crashreporter/google-breakpad/src/third_party/lss/codereview.settings new file mode 100644 index 0000000000..b5082e8d30 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/codereview.settings @@ -0,0 +1,5 @@ +# This file is used by git cl to get repository specific information. +CC_LIST: chromium-reviews@chromium.org,mseaborn@chromium.org +CODE_REVIEW_SERVER: codereview.chromium.org +GERRIT_HOST: True +VIEW_VC: https://chromium.googlesource.com/linux-syscall-support/+/ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h b/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h new file mode 100644 index 0000000000..1abe0ba5b0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h @@ -0,0 +1,4553 @@ +/* Copyright (c) 2005-2011, 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. + * + * --- + * Author: Markus Gutschke + */ + +/* This file includes Linux-specific support functions common to the + * coredumper and the thread lister; primarily, this is a collection + * of direct system calls, and a couple of symbols missing from + * standard header files. + * There are a few options that the including file can set to control + * the behavior of this file: + * + * SYS_CPLUSPLUS: + * The entire header file will normally be wrapped in 'extern "C" { }", + * making it suitable for compilation as both C and C++ source. If you + * do not want to do this, you can set the SYS_CPLUSPLUS macro to inhibit + * the wrapping. N.B. doing so will suppress inclusion of all prerequisite + * system header files, too. It is the caller's responsibility to provide + * the necessary definitions. + * + * SYS_ERRNO: + * All system calls will update "errno" unless overriden by setting the + * SYS_ERRNO macro prior to including this file. SYS_ERRNO should be + * an l-value. + * + * SYS_INLINE: + * New symbols will be defined "static inline", unless overridden by + * the SYS_INLINE macro. + * + * SYS_LINUX_SYSCALL_SUPPORT_H + * This macro is used to avoid multiple inclusions of this header file. + * If you need to include this file more than once, make sure to + * unset SYS_LINUX_SYSCALL_SUPPORT_H before each inclusion. + * + * SYS_PREFIX: + * New system calls will have a prefix of "sys_" unless overridden by + * the SYS_PREFIX macro. Valid values for this macro are [0..9] which + * results in prefixes "sys[0..9]_". It is also possible to set this + * macro to -1, which avoids all prefixes. + * + * SYS_SYSCALL_ENTRYPOINT: + * Some applications (such as sandboxes that filter system calls), need + * to be able to run custom-code each time a system call is made. If this + * macro is defined, it expands to the name of a "common" symbol. If + * this symbol is assigned a non-NULL pointer value, it is used as the + * address of the system call entrypoint. + * A pointer to this symbol can be obtained by calling + * get_syscall_entrypoint() + * + * This file defines a few internal symbols that all start with "LSS_". + * Do not access these symbols from outside this file. They are not part + * of the supported API. + */ +#ifndef SYS_LINUX_SYSCALL_SUPPORT_H +#define SYS_LINUX_SYSCALL_SUPPORT_H + +/* We currently only support x86-32, x86-64, ARM, MIPS, PPC, s390 and s390x + * on Linux. + * Porting to other related platforms should not be difficult. + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ + defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ + defined(__aarch64__) || defined(__s390__)) \ + && (defined(__linux) || defined(__ANDROID__)) + +#ifndef SYS_CPLUSPLUS +#ifdef __cplusplus +/* Some system header files in older versions of gcc neglect to properly + * handle being included from C++. As it appears to be harmless to have + * multiple nested 'extern "C"' blocks, just add another one here. + */ +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __mips__ +/* Include definitions of the ABI currently in use. */ +#ifdef __ANDROID__ +/* Android doesn't have sgidefs.h, but does have asm/sgidefs.h, + * which has the definitions we need. + */ +#include +#else +#include +#endif +#endif +#endif + +/* Some libcs, for example Android NDK and musl, #define these + * macros as aliases to their non-64 counterparts. To avoid naming + * conflict, remove them. + * + * These are restored by the corresponding #pragma pop_macro near + * the end of this file. + */ +#pragma push_macro("stat64") +#pragma push_macro("fstat64") +#pragma push_macro("lstat64") +#pragma push_macro("pread64") +#pragma push_macro("pwrite64") +#pragma push_macro("getdents64") +#undef stat64 +#undef fstat64 +#undef lstat64 +#undef pread64 +#undef pwrite64 +#undef getdents64 + +#if defined(__ANDROID__) && defined(__x86_64__) +// A number of x86_64 syscalls are blocked by seccomp on recent Android; +// undefine them so that modern alternatives will be used instead where +// possible. +// The alternative syscalls have been sanity checked against linux-3.4+; +// older versions might not work. +# undef __NR_getdents +# undef __NR_dup2 +# undef __NR_fork +# undef __NR_getpgrp +# undef __NR_open +# undef __NR_poll +# undef __NR_readlink +# undef __NR_stat +# undef __NR_unlink +# undef __NR_pipe +#endif + +#if defined(__ANDROID__) +// waitpid is blocked by seccomp on all architectures on recent Android. +# undef __NR_waitpid +#endif + +/* As glibc often provides subtly incompatible data structures (and implicit + * wrapper functions that convert them), we provide our own kernel data + * structures for use by the system calls. + * These structures have been developed by using Linux 2.6.23 headers for + * reference. Note though, we do not care about exact API compatibility + * with the kernel, and in fact the kernel often does not have a single + * API that works across architectures. Instead, we try to mimic the glibc + * API where reasonable, and only guarantee ABI compatibility with the + * kernel headers. + * Most notably, here are a few changes that were made to the structures + * defined by kernel headers: + * + * - we only define structures, but not symbolic names for kernel data + * types. For the latter, we directly use the native C datatype + * (i.e. "unsigned" instead of "mode_t"). + * - in a few cases, it is possible to define identical structures for + * both 32bit (e.g. i386) and 64bit (e.g. x86-64) platforms by + * standardizing on the 64bit version of the data types. In particular, + * this means that we use "unsigned" where the 32bit headers say + * "unsigned long". + * - overall, we try to minimize the number of cases where we need to + * conditionally define different structures. + * - the "struct kernel_sigaction" class of structures have been + * modified to more closely mimic glibc's API by introducing an + * anonymous union for the function pointer. + * - a small number of field names had to have an underscore appended to + * them, because glibc defines a global macro by the same name. + */ + +/* include/linux/dirent.h */ +struct kernel_dirent64 { + unsigned long long d_ino; + long long d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +/* include/linux/dirent.h */ +#if !defined(__NR_getdents) +// when getdents is not available, getdents64 is used for both. +#define kernel_dirent kernel_dirent64 +#else +struct kernel_dirent { + long d_ino; + long d_off; + unsigned short d_reclen; + char d_name[256]; +}; +#endif + +/* include/linux/uio.h */ +struct kernel_iovec { + void *iov_base; + unsigned long iov_len; +}; + +/* include/linux/socket.h */ +struct kernel_msghdr { + void *msg_name; + int msg_namelen; + struct kernel_iovec*msg_iov; + unsigned long msg_iovlen; + void *msg_control; + unsigned long msg_controllen; + unsigned msg_flags; +}; + +/* include/asm-generic/poll.h */ +struct kernel_pollfd { + int fd; + short events; + short revents; +}; + +/* include/linux/resource.h */ +struct kernel_rlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; + +/* include/linux/time.h */ +struct kernel_timespec { + long tv_sec; + long tv_nsec; +}; + +/* include/linux/time.h */ +struct kernel_timeval { + long tv_sec; + long tv_usec; +}; + +/* include/linux/resource.h */ +struct kernel_rusage { + struct kernel_timeval ru_utime; + struct kernel_timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ + || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) + +/* include/asm-{arm,i386,mips,ppc}/signal.h */ +struct kernel_old_sigaction { + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + unsigned long sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +} __attribute__((packed,aligned(4))); +#elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) + #define kernel_old_sigaction kernel_sigaction +#elif defined(__aarch64__) + // No kernel_old_sigaction defined for arm64. +#endif + +/* Some kernel functions (e.g. sigaction() in 2.6.23) require that the + * exactly match the size of the signal set, even though the API was + * intended to be extensible. We define our own KERNEL_NSIG to deal with + * this. + * Please note that glibc provides signals [1.._NSIG-1], whereas the + * kernel (and this header) provides the range [1..KERNEL_NSIG]. The + * actual number of signals is obviously the same, but the constants + * differ by one. + */ +#ifdef __mips__ +#define KERNEL_NSIG 128 +#else +#define KERNEL_NSIG 64 +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64}/signal.h */ +struct kernel_sigset_t { + unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/ + (8*sizeof(unsigned long))]; +}; + +/* include/asm-{arm,i386,mips,x86_64,ppc}/signal.h */ +struct kernel_sigaction { +#ifdef __mips__ + unsigned long sa_flags; + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + struct kernel_sigset_t sa_mask; +#else + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + struct kernel_sigset_t sa_mask; +#endif +}; + +/* include/linux/socket.h */ +struct kernel_sockaddr { + unsigned short sa_family; + char sa_data[14]; +}; + +/* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */ +#ifdef __mips__ +#if _MIPS_SIM == _MIPS_SIM_ABI64 +struct kernel_stat { +#else +struct kernel_stat64 { +#endif + unsigned st_dev; + unsigned __pad0[3]; + unsigned long long st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + unsigned __pad1[3]; + long long st_size; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned st_blksize; + unsigned __pad2; + unsigned long long st_blocks; +}; +#elif defined __PPC__ +struct kernel_stat64 { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned long long st_rdev; + unsigned short int __pad2; + long long st_size; + long st_blksize; + long long st_blocks; + long st_atime_; + unsigned long st_atime_nsec_; + long st_mtime_; + unsigned long st_mtime_nsec_; + long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; +#else +struct kernel_stat64 { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned __st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned st_blksize; + unsigned long long st_blocks; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned long long st_ino; +}; +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */ +#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +struct kernel_stat { + /* The kernel headers suggest that st_dev and st_rdev should be 32bit + * quantities encoding 12bit major and 20bit minor numbers in an interleaved + * format. In reality, we do not see useful data in the top bits. So, + * we'll leave the padding in here, until we find a better solution. + */ + unsigned short st_dev; + short pad1; + unsigned st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + short pad2; + unsigned st_size; + unsigned st_blksize; + unsigned st_blocks; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned __unused4; + unsigned __unused5; +}; +#elif defined(__x86_64__) +struct kernel_stat { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_nlink; + unsigned st_mode; + unsigned st_uid; + unsigned st_gid; + unsigned __pad0; + uint64_t st_rdev; + int64_t st_size; + int64_t st_blksize; + int64_t st_blocks; + uint64_t st_atime_; + uint64_t st_atime_nsec_; + uint64_t st_mtime_; + uint64_t st_mtime_nsec_; + uint64_t st_ctime_; + uint64_t st_ctime_nsec_; + int64_t __unused4[3]; +}; +#elif defined(__PPC__) +struct kernel_stat { + unsigned st_dev; + unsigned long st_ino; // ino_t + unsigned long st_mode; // mode_t + unsigned short st_nlink; // nlink_t + unsigned st_uid; // uid_t + unsigned st_gid; // gid_t + unsigned st_rdev; + long st_size; // off_t + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; +#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) +struct kernel_stat { + unsigned st_dev; + int st_pad1[3]; + unsigned st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + int st_pad2[2]; + long st_size; + int st_pad3; + long st_atime_; + long st_atime_nsec_; + long st_mtime_; + long st_mtime_nsec_; + long st_ctime_; + long st_ctime_nsec_; + int st_blksize; + int st_blocks; + int st_pad4[14]; +}; +#elif defined(__aarch64__) +struct kernel_stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + unsigned long __pad1; + long st_size; + int st_blksize; + int __pad2; + long st_blocks; + long st_atime_; + unsigned long st_atime_nsec_; + long st_mtime_; + unsigned long st_mtime_nsec_; + long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned int __unused4; + unsigned int __unused5; +}; +#elif defined(__s390x__) +struct kernel_stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad1; + unsigned long st_rdev; + unsigned long st_size; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long st_blksize; + long st_blocks; + unsigned long __unused[3]; +}; +#elif defined(__s390__) +struct kernel_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */ +#ifdef __mips__ +#if _MIPS_SIM != _MIPS_SIM_ABI64 +struct kernel_statfs64 { + unsigned long f_type; + unsigned long f_bsize; + unsigned long f_frsize; + unsigned long __pad; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_files; + unsigned long long f_ffree; + unsigned long long f_bavail; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_spare[6]; +}; +#endif +#elif defined(__s390__) +/* See also arch/s390/include/asm/compat.h */ +struct kernel_statfs64 { + unsigned int f_type; + unsigned int f_bsize; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; + struct { int val[2]; } f_fsid; + unsigned int f_namelen; + unsigned int f_frsize; + unsigned int f_flags; + unsigned int f_spare[4]; +}; +#elif !defined(__x86_64__) +struct kernel_statfs64 { + unsigned long f_type; + unsigned long f_bsize; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_spare[5]; +}; +#endif + +/* include/asm-{arm,i386,mips,x86_64,ppc,generic,s390}/statfs.h */ +#ifdef __mips__ +struct kernel_statfs { + long f_type; + long f_bsize; + long f_frsize; + long f_blocks; + long f_bfree; + long f_files; + long f_ffree; + long f_bavail; + struct { int val[2]; } f_fsid; + long f_namelen; + long f_spare[6]; +}; +#elif defined(__x86_64__) +struct kernel_statfs { + /* x86_64 actually defines all these fields as signed, whereas all other */ + /* platforms define them as unsigned. Leaving them at unsigned should not */ + /* cause any problems. Make sure these are 64-bit even on x32. */ + uint64_t f_type; + uint64_t f_bsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + struct { int val[2]; } f_fsid; + uint64_t f_namelen; + uint64_t f_frsize; + uint64_t f_spare[5]; +}; +#elif defined(__s390__) +struct kernel_statfs { + unsigned int f_type; + unsigned int f_bsize; + unsigned long f_blocks; + unsigned long f_bfree; + unsigned long f_bavail; + unsigned long f_files; + unsigned long f_ffree; + struct { int val[2]; } f_fsid; + unsigned int f_namelen; + unsigned int f_frsize; + unsigned int f_flags; + unsigned int f_spare[4]; +}; +#else +struct kernel_statfs { + unsigned long f_type; + unsigned long f_bsize; + unsigned long f_blocks; + unsigned long f_bfree; + unsigned long f_bavail; + unsigned long f_files; + unsigned long f_ffree; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_spare[5]; +}; +#endif + + +/* Definitions missing from the standard header files */ +#ifndef O_DIRECTORY +#if defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || defined(__aarch64__) +#define O_DIRECTORY 0040000 +#else +#define O_DIRECTORY 0200000 +#endif +#endif +#ifndef NT_PRXFPREG +#define NT_PRXFPREG 0x46e62b7f +#endif +#ifndef PTRACE_GETFPXREGS +#define PTRACE_GETFPXREGS ((enum __ptrace_request)18) +#endif +#ifndef PR_GET_DUMPABLE +#define PR_GET_DUMPABLE 3 +#endif +#ifndef PR_SET_DUMPABLE +#define PR_SET_DUMPABLE 4 +#endif +#ifndef PR_GET_SECCOMP +#define PR_GET_SECCOMP 21 +#endif +#ifndef PR_SET_SECCOMP +#define PR_SET_SECCOMP 22 +#endif +#ifndef AT_FDCWD +#define AT_FDCWD (-100) +#endif +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif +#ifndef AT_REMOVEDIR +#define AT_REMOVEDIR 0x200 +#endif +#ifndef MREMAP_FIXED +#define MREMAP_FIXED 2 +#endif +#ifndef SA_RESTORER +#define SA_RESTORER 0x04000000 +#endif +#ifndef CPUCLOCK_PROF +#define CPUCLOCK_PROF 0 +#endif +#ifndef CPUCLOCK_VIRT +#define CPUCLOCK_VIRT 1 +#endif +#ifndef CPUCLOCK_SCHED +#define CPUCLOCK_SCHED 2 +#endif +#ifndef CPUCLOCK_PERTHREAD_MASK +#define CPUCLOCK_PERTHREAD_MASK 4 +#endif +#ifndef MAKE_PROCESS_CPUCLOCK +#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ + ((int)(~(unsigned)(pid) << 3) | (int)(clock)) +#endif +#ifndef MAKE_THREAD_CPUCLOCK +#define MAKE_THREAD_CPUCLOCK(tid, clock) \ + ((int)(~(unsigned)(tid) << 3) | \ + (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) +#endif + +#ifndef FUTEX_WAIT +#define FUTEX_WAIT 0 +#endif +#ifndef FUTEX_WAKE +#define FUTEX_WAKE 1 +#endif +#ifndef FUTEX_FD +#define FUTEX_FD 2 +#endif +#ifndef FUTEX_REQUEUE +#define FUTEX_REQUEUE 3 +#endif +#ifndef FUTEX_CMP_REQUEUE +#define FUTEX_CMP_REQUEUE 4 +#endif +#ifndef FUTEX_WAKE_OP +#define FUTEX_WAKE_OP 5 +#endif +#ifndef FUTEX_LOCK_PI +#define FUTEX_LOCK_PI 6 +#endif +#ifndef FUTEX_UNLOCK_PI +#define FUTEX_UNLOCK_PI 7 +#endif +#ifndef FUTEX_TRYLOCK_PI +#define FUTEX_TRYLOCK_PI 8 +#endif +#ifndef FUTEX_PRIVATE_FLAG +#define FUTEX_PRIVATE_FLAG 128 +#endif +#ifndef FUTEX_CMD_MASK +#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG +#endif +#ifndef FUTEX_WAIT_PRIVATE +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_WAKE_PRIVATE +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_REQUEUE_PRIVATE +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_CMP_REQUEUE_PRIVATE +#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_WAKE_OP_PRIVATE +#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_LOCK_PI_PRIVATE +#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_UNLOCK_PI_PRIVATE +#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_TRYLOCK_PI_PRIVATE +#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) +#endif + + +#if defined(__x86_64__) +#ifndef ARCH_SET_GS +#define ARCH_SET_GS 0x1001 +#endif +#ifndef ARCH_GET_GS +#define ARCH_GET_GS 0x1004 +#endif +#endif + +#if defined(__i386__) +#ifndef __NR_quotactl +#define __NR_quotactl 131 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigsuspend 179 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 180 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 181 +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit 191 +#endif +#ifndef __NR_stat64 +#define __NR_stat64 195 +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 197 +#endif +#ifndef __NR_setresuid32 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#endif +#ifndef __NR_setfsuid32 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 220 +#endif +#ifndef __NR_gettid +#define __NR_gettid 224 +#endif +#ifndef __NR_readahead +#define __NR_readahead 225 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 226 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 227 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 229 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 230 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 232 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 233 +#endif +#ifndef __NR_tkill +#define __NR_tkill 238 +#endif +#ifndef __NR_futex +#define __NR_futex 240 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 258 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 265 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 266 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 268 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 269 +#endif +#ifndef __NR_fadvise64_64 +#define __NR_fadvise64_64 272 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 289 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 290 +#endif +#ifndef __NR_openat +#define __NR_openat 295 +#endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 300 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 301 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 317 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 318 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 324 +#endif +/* End of i386 definitions */ +#elif defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_SYSCALL_BASE + 164) +#define __NR_getresuid (__NR_SYSCALL_BASE + 165) +#define __NR_setresgid (__NR_SYSCALL_BASE + 170) +#define __NR_getresgid (__NR_SYSCALL_BASE + 171) +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn (__NR_SYSCALL_BASE + 173) +#define __NR_rt_sigaction (__NR_SYSCALL_BASE + 174) +#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE + 175) +#define __NR_rt_sigpending (__NR_SYSCALL_BASE + 176) +#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE + 179) +#endif +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_SYSCALL_BASE + 180) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_SYSCALL_BASE + 181) +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit (__NR_SYSCALL_BASE + 191) +#endif +#ifndef __NR_stat64 +#define __NR_stat64 (__NR_SYSCALL_BASE + 195) +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 (__NR_SYSCALL_BASE + 197) +#endif +#ifndef __NR_setresuid32 +#define __NR_setresuid32 (__NR_SYSCALL_BASE + 208) +#define __NR_getresuid32 (__NR_SYSCALL_BASE + 209) +#define __NR_setresgid32 (__NR_SYSCALL_BASE + 210) +#define __NR_getresgid32 (__NR_SYSCALL_BASE + 211) +#endif +#ifndef __NR_setfsuid32 +#define __NR_setfsuid32 (__NR_SYSCALL_BASE + 215) +#define __NR_setfsgid32 (__NR_SYSCALL_BASE + 216) +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 (__NR_SYSCALL_BASE + 217) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_SYSCALL_BASE + 224) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_SYSCALL_BASE + 225) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_SYSCALL_BASE + 226) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_SYSCALL_BASE + 227) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_SYSCALL_BASE + 229) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_SYSCALL_BASE + 230) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_SYSCALL_BASE + 232) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_SYSCALL_BASE + 233) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_SYSCALL_BASE + 238) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_SYSCALL_BASE + 240) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_SYSCALL_BASE + 241) +#define __NR_sched_getaffinity (__NR_SYSCALL_BASE + 242) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_SYSCALL_BASE + 256) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_SYSCALL_BASE + 263) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_SYSCALL_BASE + 264) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_SYSCALL_BASE + 266) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_SYSCALL_BASE + 314) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_SYSCALL_BASE + 344) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_SYSCALL_BASE + 345) +#endif +/* End of ARM 3/EABI definitions */ +#elif defined(__aarch64__) +#ifndef __NR_setxattr +#define __NR_setxattr 5 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 6 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 8 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 9 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 11 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 12 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 30 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 31 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 35 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 47 +#endif +#ifndef __NR_openat +#define __NR_openat 56 +#endif +#ifndef __NR_quotactl +#define __NR_quotactl 60 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 61 +#endif +#ifndef __NR_getdents +// when getdents is not available, getdents64 is used for both. +#define __NR_getdents __NR_getdents64 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 67 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 68 +#endif +#ifndef __NR_ppoll +#define __NR_ppoll 73 +#endif +#ifndef __NR_readlinkat +#define __NR_readlinkat 78 +#endif +#ifndef __NR_newfstatat +#define __NR_newfstatat 79 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 96 +#endif +#ifndef __NR_futex +#define __NR_futex 98 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 113 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 114 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#endif +#ifndef __NR_tkill +#define __NR_tkill 130 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#endif +#ifndef __NR_gettid +#define __NR_gettid 178 +#endif +#ifndef __NR_readahead +#define __NR_readahead 213 +#endif +#ifndef __NR_fadvise64 +#define __NR_fadvise64 223 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 239 +#endif +/* End of aarch64 definitions */ +#elif defined(__x86_64__) +#ifndef __NR_pread64 +#define __NR_pread64 17 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 18 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#endif +#ifndef __NR_quotactl +#define __NR_quotactl 179 +#endif +#ifndef __NR_gettid +#define __NR_gettid 186 +#endif +#ifndef __NR_readahead +#define __NR_readahead 187 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 188 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 189 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 191 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 192 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 194 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 195 +#endif +#ifndef __NR_tkill +#define __NR_tkill 200 +#endif +#ifndef __NR_futex +#define __NR_futex 202 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 217 +#endif +#ifndef __NR_getdents +// when getdents is not available, getdents64 is used for both. +#define __NR_getdents __NR_getdents64 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 218 +#endif +#ifndef __NR_fadvise64 +#define __NR_fadvise64 221 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 228 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 229 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 251 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 252 +#endif +#ifndef __NR_openat +#define __NR_openat 257 +#endif +#ifndef __NR_newfstatat +#define __NR_newfstatat 262 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 263 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 279 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 285 +#endif +/* End of x86-64 definitions */ +#elif defined(__mips__) +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 185) +#define __NR_getresuid (__NR_Linux + 186) +#define __NR_setresgid (__NR_Linux + 190) +#define __NR_getresgid (__NR_Linux + 191) +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn (__NR_Linux + 193) +#define __NR_rt_sigaction (__NR_Linux + 194) +#define __NR_rt_sigprocmask (__NR_Linux + 195) +#define __NR_rt_sigpending (__NR_Linux + 196) +#define __NR_rt_sigsuspend (__NR_Linux + 199) +#endif +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_Linux + 200) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_Linux + 201) +#endif +#ifndef __NR_stat64 +#define __NR_stat64 (__NR_Linux + 213) +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 (__NR_Linux + 215) +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 (__NR_Linux + 219) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 222) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 223) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 224) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 225) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 227) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 228) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 230) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 231) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 236) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 238) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 239) +#define __NR_sched_getaffinity (__NR_Linux + 240) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 252) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_Linux + 255) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_Linux + 256) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 263) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 264) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 288) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 293) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 294) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 308) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 312) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 314) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 315) +#endif +/* End of MIPS (old 32bit API) definitions */ +#elif _MIPS_SIM == _MIPS_SIM_ABI64 +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_Linux + 16) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_Linux + 17) +#endif +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 115) +#define __NR_getresuid (__NR_Linux + 116) +#define __NR_setresgid (__NR_Linux + 117) +#define __NR_getresgid (__NR_Linux + 118) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 178) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 179) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 180) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 181) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 183) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 184) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 186) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 187) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 192) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 194) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 195) +#define __NR_sched_getaffinity (__NR_Linux + 196) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 212) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 222) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 223) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 247) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 252) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 253) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 267) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 271) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 273) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 274) +#endif +/* End of MIPS (64bit API) definitions */ +#else +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 115) +#define __NR_getresuid (__NR_Linux + 116) +#define __NR_setresgid (__NR_Linux + 117) +#define __NR_getresgid (__NR_Linux + 118) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 178) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 179) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 180) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 181) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 183) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 184) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 186) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 187) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 192) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 194) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 195) +#define __NR_sched_getaffinity (__NR_Linux + 196) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 213) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_Linux + 217) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_Linux + 218) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 226) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 227) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 251) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 256) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 257) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 271) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 275) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 277) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 278) +#endif +/* End of MIPS (new 32bit API) definitions */ +#endif +/* End of MIPS definitions */ +#elif defined(__PPC__) +#ifndef __NR_setfsuid +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_setresgid 169 +#define __NR_getresgid 170 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn 172 +#define __NR_rt_sigaction 173 +#define __NR_rt_sigprocmask 174 +#define __NR_rt_sigpending 175 +#define __NR_rt_sigsuspend 178 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 179 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 180 +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit 190 +#endif +#ifndef __NR_readahead +#define __NR_readahead 191 +#endif +#ifndef __NR_stat64 +#define __NR_stat64 195 +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 197 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 202 +#endif +#ifndef __NR_gettid +#define __NR_gettid 207 +#endif +#ifndef __NR_tkill +#define __NR_tkill 208 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 209 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 210 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 212 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 213 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 215 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 216 +#endif +#ifndef __NR_futex +#define __NR_futex 221 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 222 +#define __NR_sched_getaffinity 223 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 232 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 246 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 247 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 252 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 253 +#endif +#ifndef __NR_fadvise64_64 +#define __NR_fadvise64_64 254 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 273 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 274 +#endif +#ifndef __NR_openat +#define __NR_openat 286 +#endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 291 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 292 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 301 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 302 +#endif +/* End of powerpc defininitions */ +#elif defined(__s390__) +#ifndef __NR_quotactl +#define __NR_quotactl 131 +#endif +#ifndef __NR_rt_sigreturn +#define __NR_rt_sigreturn 173 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigaction 174 +#endif +#ifndef __NR_rt_sigprocmask +#define __NR_rt_sigprocmask 175 +#endif +#ifndef __NR_rt_sigpending +#define __NR_rt_sigpending 176 +#endif +#ifndef __NR_rt_sigsuspend +#define __NR_rt_sigsuspend 179 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 180 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 181 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 220 +#endif +#ifndef __NR_readahead +#define __NR_readahead 222 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 224 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 225 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 227 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 228 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 230 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 231 +#endif +#ifndef __NR_gettid +#define __NR_gettid 236 +#endif +#ifndef __NR_tkill +#define __NR_tkill 237 +#endif +#ifndef __NR_futex +#define __NR_futex 238 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 239 +#endif +#ifndef __NR_sched_getaffinity +#define __NR_sched_getaffinity 240 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 252 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 260 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 261 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 265 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 266 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 282 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 283 +#endif +#ifndef __NR_openat +#define __NR_openat 288 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 294 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 310 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 311 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 314 +#endif +/* Some syscalls are named/numbered differently between s390 and s390x. */ +#ifdef __s390x__ +# ifndef __NR_getrlimit +# define __NR_getrlimit 191 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 208 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 209 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 210 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 211 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 215 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 216 +# endif +# ifndef __NR_fadvise64 +# define __NR_fadvise64 253 +# endif +# ifndef __NR_newfstatat +# define __NR_newfstatat 293 +# endif +#else /* __s390x__ */ +# ifndef __NR_getrlimit +# define __NR_getrlimit 76 +# endif +# ifndef __NR_setfsuid +# define __NR_setfsuid 138 +# endif +# ifndef __NR_setfsgid +# define __NR_setfsgid 139 +# endif +# ifndef __NR_setresuid +# define __NR_setresuid 164 +# endif +# ifndef __NR_getresuid +# define __NR_getresuid 165 +# endif +# ifndef __NR_setresgid +# define __NR_setresgid 170 +# endif +# ifndef __NR_getresgid +# define __NR_getresgid 171 +# endif +# ifndef __NR_ugetrlimit +# define __NR_ugetrlimit 191 +# endif +# ifndef __NR_mmap2 +# define __NR_mmap2 192 +# endif +# ifndef __NR_setresuid32 +# define __NR_setresuid32 208 +# endif +# ifndef __NR_getresuid32 +# define __NR_getresuid32 209 +# endif +# ifndef __NR_setresgid32 +# define __NR_setresgid32 210 +# endif +# ifndef __NR_getresgid32 +# define __NR_getresgid32 211 +# endif +# ifndef __NR_setfsuid32 +# define __NR_setfsuid32 215 +# endif +# ifndef __NR_setfsgid32 +# define __NR_setfsgid32 216 +# endif +# ifndef __NR_fadvise64_64 +# define __NR_fadvise64_64 264 +# endif +# ifndef __NR_fstatat64 +# define __NR_fstatat64 293 +# endif +#endif /* __s390__ */ +/* End of s390/s390x definitions */ +#endif + + +/* After forking, we must make sure to only call system calls. */ +#if defined(__BOUNDED_POINTERS__) + #error "Need to port invocations of syscalls for bounded ptrs" +#else + /* The core dumper and the thread lister get executed after threads + * have been suspended. As a consequence, we cannot call any functions + * that acquire locks. Unfortunately, libc wraps most system calls + * (e.g. in order to implement pthread_atfork, and to make calls + * cancellable), which means we cannot call these functions. Instead, + * we have to call syscall() directly. + */ + #undef LSS_ERRNO + #ifdef SYS_ERRNO + /* Allow the including file to override the location of errno. This can + * be useful when using clone() with the CLONE_VM option. + */ + #define LSS_ERRNO SYS_ERRNO + #else + #define LSS_ERRNO errno + #endif + + #undef LSS_INLINE + #ifdef SYS_INLINE + #define LSS_INLINE SYS_INLINE + #else + #define LSS_INLINE static inline + #endif + + /* Allow the including file to override the prefix used for all new + * system calls. By default, it will be set to "sys_". + */ + #undef LSS_NAME + #ifndef SYS_PREFIX + #define LSS_NAME(name) sys_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX < 0 + #define LSS_NAME(name) name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 0 + #define LSS_NAME(name) sys0_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 1 + #define LSS_NAME(name) sys1_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 2 + #define LSS_NAME(name) sys2_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 3 + #define LSS_NAME(name) sys3_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 4 + #define LSS_NAME(name) sys4_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 5 + #define LSS_NAME(name) sys5_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 6 + #define LSS_NAME(name) sys6_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 7 + #define LSS_NAME(name) sys7_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 8 + #define LSS_NAME(name) sys8_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 9 + #define LSS_NAME(name) sys9_##name + #endif + + #undef LSS_RETURN + #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ + || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__)) + /* Failing system calls return a negative result in the range of + * -1..-4095. These are "errno" values with the sign inverted. + */ + #define LSS_RETURN(type, res) \ + do { \ + if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ + LSS_ERRNO = -(res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #elif defined(__mips__) + /* On MIPS, failing system calls return -1, and set errno in a + * separate CPU register. + */ + #define LSS_RETURN(type, res, err) \ + do { \ + if (err) { \ + unsigned long __errnovalue = (res); \ + LSS_ERRNO = __errnovalue; \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #elif defined(__PPC__) + /* On PPC, failing system calls return -1, and set errno in a + * separate CPU register. See linux/unistd.h. + */ + #define LSS_RETURN(type, res, err) \ + do { \ + if (err & 0x10000000 ) { \ + LSS_ERRNO = (res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #endif + #if defined(__i386__) + /* In PIC mode (e.g. when building shared libraries), gcc for i386 + * reserves ebx. Unfortunately, most distribution ship with implementations + * of _syscallX() which clobber ebx. + * Also, most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_ENTRYPOINT + #ifdef SYS_SYSCALL_ENTRYPOINT + static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { + void (**entrypoint)(void); + asm volatile(".bss\n" + ".align 8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" + ".previous\n" + /* This logically does 'lea "SYS_SYSCALL_ENTRYPOINT", %0' */ + "call 0f\n" + "0:pop %0\n" + "add $_GLOBAL_OFFSET_TABLE_+[.-0b], %0\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOT(%0), %0\n" + : "=r"(entrypoint)); + return entrypoint; + } + + #define LSS_ENTRYPOINT ".bss\n" \ + ".align 8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ + ".previous\n" \ + /* Check the SYS_SYSCALL_ENTRYPOINT vector */ \ + "push %%eax\n" \ + "call 10000f\n" \ + "10000:pop %%eax\n" \ + "add $_GLOBAL_OFFSET_TABLE_+[.-10000b], %%eax\n" \ + "mov " SYS_SYSCALL_ENTRYPOINT \ + "@GOT(%%eax), %%eax\n" \ + "mov 0(%%eax), %%eax\n" \ + "test %%eax, %%eax\n" \ + "jz 10002f\n" \ + "push %%eax\n" \ + "call 10001f\n" \ + "10001:pop %%eax\n" \ + "add $(10003f-10001b), %%eax\n" \ + "xchg 4(%%esp), %%eax\n" \ + "ret\n" \ + "10002:pop %%eax\n" \ + "int $0x80\n" \ + "10003:\n" + #else + #define LSS_ENTRYPOINT "int $0x80\n" + #endif + #undef LSS_BODY + #define LSS_BODY(type,args...) \ + long __res; \ + __asm__ __volatile__("push %%ebx\n" \ + "movl %2,%%ebx\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx" \ + args \ + : "esp", "memory"); \ + LSS_RETURN(type,__res) + #undef _syscall0 + #define _syscall0(type,name) \ + type LSS_NAME(name)(void) { \ + long __res; \ + __asm__ volatile(LSS_ENTRYPOINT \ + : "=a" (__res) \ + : "0" (__NR_##name) \ + : "memory"); \ + LSS_RETURN(type,__res); \ + } + #undef _syscall1 + #define _syscall1(type,name,type1,arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1))); \ + } + #undef _syscall2 + #define _syscall2(type,name,type1,arg1,type2,arg2) \ + type LSS_NAME(name)(type1 arg1,type2 arg2) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)), "c" ((long)(arg2))); \ + } + #undef _syscall3 + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type LSS_NAME(name)(type1 arg1,type2 arg2,type3 arg3) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ + "d" ((long)(arg3))); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4))); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + long __res; \ + __asm__ __volatile__("push %%ebx\n" \ + "movl %2,%%ebx\n" \ + "movl %1,%%eax\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx" \ + : "=a" (__res) \ + : "i" (__NR_##name), "ri" ((long)(arg1)), \ + "c" ((long)(arg2)), "d" ((long)(arg3)), \ + "S" ((long)(arg4)), "D" ((long)(arg5)) \ + : "esp", "memory"); \ + LSS_RETURN(type,__res); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + long __res; \ + struct { long __a1; long __a6; } __s = { (long)arg1, (long) arg6 }; \ + __asm__ __volatile__("push %%ebp\n" \ + "push %%ebx\n" \ + "movl 4(%2),%%ebp\n" \ + "movl 0(%2), %%ebx\n" \ + "movl %1,%%eax\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx\n" \ + "pop %%ebp" \ + : "=a" (__res) \ + : "i" (__NR_##name), "0" ((long)(&__s)), \ + "c" ((long)(arg2)), "d" ((long)(arg3)), \ + "S" ((long)(arg4)), "D" ((long)(arg5)) \ + : "esp", "memory"); \ + LSS_RETURN(type,__res); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + __asm__ __volatile__(/* if (fn == NULL) + * return -EINVAL; + */ + "movl %3,%%ecx\n" + "jecxz 1f\n" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "movl %4,%%ecx\n" + "jecxz 1f\n" + + /* Set up alignment of the child stack: + * child_stack = (child_stack & ~0xF) - 20; + */ + "andl $-16,%%ecx\n" + "subl $20,%%ecx\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "movl %6,%%eax\n" + "movl %%eax,4(%%ecx)\n" + "movl %3,%%eax\n" + "movl %%eax,(%%ecx)\n" + + /* %eax = syscall(%eax = __NR_clone, + * %ebx = flags, + * %ecx = child_stack, + * %edx = parent_tidptr, + * %esi = newtls, + * %edi = child_tidptr) + * Also, make sure that %ebx gets preserved as it is + * used in PIC mode. + */ + "movl %8,%%esi\n" + "movl %7,%%edx\n" + "movl %5,%%eax\n" + "movl %9,%%edi\n" + "pushl %%ebx\n" + "movl %%eax,%%ebx\n" + "movl %2,%%eax\n" + LSS_ENTRYPOINT + + /* In the parent: restore %ebx + * In the child: move "fn" into %ebx + */ + "popl %%ebx\n" + + /* if (%eax != 0) + * return %eax; + */ + "test %%eax,%%eax\n" + "jnz 1f\n" + + /* In the child, now. Terminate frame pointer chain. + */ + "movl $0,%%ebp\n" + + /* Call "fn". "arg" is already on the stack. + */ + "call *%%ebx\n" + + /* Call _exit(%ebx). Unfortunately older versions + * of gcc restrict the number of arguments that can + * be passed to asm(). So, we need to hard-code the + * system call number. + */ + "movl %%eax,%%ebx\n" + "movl $1,%%eax\n" + LSS_ENTRYPOINT + + /* Return to parent. + */ + "1:\n" + : "=a" (__res) + : "0"(-EINVAL), "i"(__NR_clone), + "m"(fn), "m"(child_stack), "m"(flags), "m"(arg), + "m"(parent_tidptr), "m"(newtls), "m"(child_tidptr) + : "esp", "memory", "ecx", "edx", "esi", "edi"); + LSS_RETURN(int, __res); + } + + LSS_INLINE _syscall1(int, set_thread_area, void *, u) + LSS_INLINE _syscall1(int, get_thread_area, void *, u) + + LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { + /* On i386, the kernel does not know how to return from a signal + * handler. Instead, it relies on user space to provide a + * restorer function that calls the {rt_,}sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + void (*res)(void); + __asm__ __volatile__("call 2f\n" + "0:.align 16\n" + "1:movl %1,%%eax\n" + LSS_ENTRYPOINT + "2:popl %0\n" + "addl $(1b-0b),%0\n" + : "=a" (res) + : "i" (__NR_rt_sigreturn)); + return res; + } + LSS_INLINE void (*LSS_NAME(restore)(void))(void) { + /* On i386, the kernel does not know how to return from a signal + * handler. Instead, it relies on user space to provide a + * restorer function that calls the {rt_,}sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + void (*res)(void); + __asm__ __volatile__("call 2f\n" + "0:.align 16\n" + "1:pop %%eax\n" + "movl %1,%%eax\n" + LSS_ENTRYPOINT + "2:popl %0\n" + "addl $(1b-0b),%0\n" + : "=a" (res) + : "i" (__NR_sigreturn)); + return res; + } + #elif defined(__x86_64__) + /* There are no known problems with any of the _syscallX() macros + * currently shipping for x86_64, but we still need to be able to define + * our own version so that we can override the location of the errno + * location (e.g. when using the clone() system call with the CLONE_VM + * option). + */ + #undef LSS_ENTRYPOINT + #ifdef SYS_SYSCALL_ENTRYPOINT + static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { + void (**entrypoint)(void); + asm volatile(".bss\n" + ".align 8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" + ".previous\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %0\n" + : "=r"(entrypoint)); + return entrypoint; + } + + #define LSS_ENTRYPOINT \ + ".bss\n" \ + ".align 8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ + ".previous\n" \ + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %%rcx\n" \ + "mov 0(%%rcx), %%rcx\n" \ + "test %%rcx, %%rcx\n" \ + "jz 10001f\n" \ + "call *%%rcx\n" \ + "jmp 10002f\n" \ + "10001:syscall\n" \ + "10002:\n" + + #else + #define LSS_ENTRYPOINT "syscall\n" + #endif + + /* The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. + * We need to explicitly cast to an unsigned 64 bit type to avoid implicit + * sign extension. We can't cast pointers directly because those are + * 32 bits, and gcc will dump ugly warnings about casting from a pointer + * to an integer of a different size. + */ + #undef LSS_SYSCALL_ARG + #define LSS_SYSCALL_ARG(a) ((uint64_t)(uintptr_t)(a)) + #undef _LSS_RETURN + #define _LSS_RETURN(type, res, cast) \ + do { \ + if ((uint64_t)(res) >= (uint64_t)(-4095)) { \ + LSS_ERRNO = -(res); \ + res = -1; \ + } \ + return (type)(cast)(res); \ + } while (0) + #undef LSS_RETURN + #define LSS_RETURN(type, res) _LSS_RETURN(type, res, uintptr_t) + + #undef _LSS_BODY + #define _LSS_BODY(nr, type, name, cast, ...) \ + long long __res; \ + __asm__ __volatile__(LSS_BODY_ASM##nr LSS_ENTRYPOINT \ + : "=a" (__res) \ + : "0" (__NR_##name) LSS_BODY_ARG##nr(__VA_ARGS__) \ + : LSS_BODY_CLOBBER##nr "r11", "rcx", "memory"); \ + _LSS_RETURN(type, __res, cast) + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + _LSS_BODY(nr, type, name, uintptr_t, ## args) + + #undef LSS_BODY_ASM0 + #undef LSS_BODY_ASM1 + #undef LSS_BODY_ASM2 + #undef LSS_BODY_ASM3 + #undef LSS_BODY_ASM4 + #undef LSS_BODY_ASM5 + #undef LSS_BODY_ASM6 + #define LSS_BODY_ASM0 + #define LSS_BODY_ASM1 LSS_BODY_ASM0 + #define LSS_BODY_ASM2 LSS_BODY_ASM1 + #define LSS_BODY_ASM3 LSS_BODY_ASM2 + #define LSS_BODY_ASM4 LSS_BODY_ASM3 "movq %5,%%r10;" + #define LSS_BODY_ASM5 LSS_BODY_ASM4 "movq %6,%%r8;" + #define LSS_BODY_ASM6 LSS_BODY_ASM5 "movq %7,%%r9;" + + #undef LSS_BODY_CLOBBER0 + #undef LSS_BODY_CLOBBER1 + #undef LSS_BODY_CLOBBER2 + #undef LSS_BODY_CLOBBER3 + #undef LSS_BODY_CLOBBER4 + #undef LSS_BODY_CLOBBER5 + #undef LSS_BODY_CLOBBER6 + #define LSS_BODY_CLOBBER0 + #define LSS_BODY_CLOBBER1 LSS_BODY_CLOBBER0 + #define LSS_BODY_CLOBBER2 LSS_BODY_CLOBBER1 + #define LSS_BODY_CLOBBER3 LSS_BODY_CLOBBER2 + #define LSS_BODY_CLOBBER4 LSS_BODY_CLOBBER3 "r10", + #define LSS_BODY_CLOBBER5 LSS_BODY_CLOBBER4 "r8", + #define LSS_BODY_CLOBBER6 LSS_BODY_CLOBBER5 "r9", + + #undef LSS_BODY_ARG0 + #undef LSS_BODY_ARG1 + #undef LSS_BODY_ARG2 + #undef LSS_BODY_ARG3 + #undef LSS_BODY_ARG4 + #undef LSS_BODY_ARG5 + #undef LSS_BODY_ARG6 + #define LSS_BODY_ARG0() + #define LSS_BODY_ARG1(arg1) \ + LSS_BODY_ARG0(), "D" (arg1) + #define LSS_BODY_ARG2(arg1, arg2) \ + LSS_BODY_ARG1(arg1), "S" (arg2) + #define LSS_BODY_ARG3(arg1, arg2, arg3) \ + LSS_BODY_ARG2(arg1, arg2), "d" (arg3) + #define LSS_BODY_ARG4(arg1, arg2, arg3, arg4) \ + LSS_BODY_ARG3(arg1, arg2, arg3), "r" (arg4) + #define LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5) \ + LSS_BODY_ARG4(arg1, arg2, arg3, arg4), "r" (arg5) + #define LSS_BODY_ARG6(arg1, arg2, arg3, arg4, arg5, arg6) \ + LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5), "r" (arg6) + + #undef _syscall0 + #define _syscall0(type,name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + #undef _syscall1 + #define _syscall1(type,name,type1,arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, LSS_SYSCALL_ARG(arg1)); \ + } + #undef _syscall2 + #define _syscall2(type,name,type1,arg1,type2,arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2));\ + } + #undef _syscall3 + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4));\ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ + LSS_SYSCALL_ARG(arg5)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ + LSS_SYSCALL_ARG(arg5), LSS_SYSCALL_ARG(arg6));\ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long long __res; + { + __asm__ __volatile__(/* if (fn == NULL) + * return -EINVAL; + */ + "testq %4,%4\n" + "jz 1f\n" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "testq %5,%5\n" + "jz 1f\n" + + /* childstack -= 2*sizeof(void *); + */ + "subq $16,%5\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "movq %7,8(%5)\n" + "movq %4,0(%5)\n" + + /* %rax = syscall(%rax = __NR_clone, + * %rdi = flags, + * %rsi = child_stack, + * %rdx = parent_tidptr, + * %r8 = new_tls, + * %r10 = child_tidptr) + */ + "movq %2,%%rax\n" + "movq %9,%%r8\n" + "movq %10,%%r10\n" + LSS_ENTRYPOINT + + /* if (%rax != 0) + * return; + */ + "testq %%rax,%%rax\n" + "jnz 1f\n" + + /* In the child. Terminate frame pointer chain. + */ + "xorq %%rbp,%%rbp\n" + + /* Call "fn(arg)". + */ + "popq %%rax\n" + "popq %%rdi\n" + "call *%%rax\n" + + /* Call _exit(%ebx). + */ + "movq %%rax,%%rdi\n" + "movq %3,%%rax\n" + LSS_ENTRYPOINT + + /* Return to parent. + */ + "1:\n" + : "=a" (__res) + : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), + "r"(LSS_SYSCALL_ARG(fn)), + "S"(LSS_SYSCALL_ARG(child_stack)), + "D"(LSS_SYSCALL_ARG(flags)), + "r"(LSS_SYSCALL_ARG(arg)), + "d"(LSS_SYSCALL_ARG(parent_tidptr)), + "r"(LSS_SYSCALL_ARG(newtls)), + "r"(LSS_SYSCALL_ARG(child_tidptr)) + : "memory", "r8", "r10", "r11", "rcx"); + } + LSS_RETURN(int, __res); + } + LSS_INLINE _syscall2(int, arch_prctl, int, c, void *, a) + + LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { + /* On x86-64, the kernel does not know how to return from + * a signal handler. Instead, it relies on user space to provide a + * restorer function that calls the rt_sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + long long res; + __asm__ __volatile__("jmp 2f\n" + ".align 16\n" + "1:movq %1,%%rax\n" + LSS_ENTRYPOINT + "2:leaq 1b(%%rip),%0\n" + : "=r" (res) + : "i" (__NR_rt_sigreturn)); + return (void (*)(void))(uintptr_t)res; + } + #elif defined(__ARM_ARCH_3__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ (__syscall(name) \ + : "=r"(__res_r0) : args : "lr", "memory"); \ + __res = __res_r0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + { + register int __flags __asm__("r0") = flags; + register void *__stack __asm__("r1") = child_stack; + register void *__ptid __asm__("r2") = parent_tidptr; + register void *__tls __asm__("r3") = newtls; + register int *__ctid __asm__("r4") = child_tidptr; + __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) + * return -EINVAL; + */ + "cmp %2,#0\n" + "cmpne %3,#0\n" + "moveq %0,%1\n" + "beq 1f\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "str %5,[%3,#-4]!\n" + "str %2,[%3,#-4]!\n" + + /* %r0 = syscall(%r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = newtls, + * %r4 = child_tidptr) + */ + __syscall(clone)"\n" + + /* if (%r0 != 0) + * return %r0; + */ + "movs %0,r0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldr r0,[sp, #4]\n" + "mov lr,pc\n" + "ldr pc,[sp]\n" + + /* Call _exit(%r0). + */ + __syscall(exit)"\n" + "1:\n" + : "=r" (__res) + : "i"(-EINVAL), + "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid) + : "cc", "lr", "memory"); + } + LSS_RETURN(int, __res); + } + #elif defined(__ARM_EABI__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all fo the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ ("push {r7}\n" \ + "mov r7, %1\n" \ + "swi 0x0\n" \ + "pop {r7}\n" \ + : "=r"(__res_r0) \ + : "i"(__NR_##name) , ## args \ + : "lr", "memory"); \ + __res = __res_r0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + if (fn == NULL || child_stack == NULL) { + __res = -EINVAL; + LSS_RETURN(int, __res); + } + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + { + uintptr_t* cstack = (uintptr_t*)child_stack - 2; + cstack[0] = (uintptr_t)fn; + cstack[1] = (uintptr_t)arg; + child_stack = cstack; + } + { + register int __flags __asm__("r0") = flags; + register void *__stack __asm__("r1") = child_stack; + register void *__ptid __asm__("r2") = parent_tidptr; + register void *__tls __asm__("r3") = newtls; + register int *__ctid __asm__("r4") = child_tidptr; + __asm__ __volatile__( +#ifdef __thumb2__ + "push {r7}\n" +#endif + /* %r0 = syscall(%r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = newtls, + * %r4 = child_tidptr) + */ + "mov r7, %6\n" + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp r0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldr r0,[sp, #4]\n" + + "ldr lr,[sp]\n" + "blx lr\n" + + /* Call _exit(%r0). + */ + "mov r7, %7\n" + "swi 0x0\n" + /* Unreachable */ + "bkpt #0\n" + "1:\n" +#ifdef __thumb2__ + "pop {r7}\n" +#endif + "movs %0,r0\n" + : "=r"(__res) + : "r"(__stack), "r"(__flags), "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "lr", "memory" +#ifndef __thumb2__ + , "r7" +#endif + ); + } + LSS_RETURN(int, __res); + } + #elif defined(__aarch64__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register int64_t __r##r __asm__("x"#r) = (int64_t)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_x0 __asm__("x0"); \ + int64_t __res; \ + __asm__ __volatile__ ("mov x8, %1\n" \ + "svc 0x0\n" \ + : "=r"(__res_x0) \ + : "i"(__NR_##name) , ## args \ + : "x8", "memory"); \ + __res = __res_x0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register uint64_t __flags __asm__("x0") = flags; + register void *__stack __asm__("x1") = child_stack; + register void *__ptid __asm__("x2") = parent_tidptr; + register void *__tls __asm__("x3") = newtls; + register int *__ctid __asm__("x4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "stp %1, %4, [%2, #-16]!\n" + + /* %x0 = syscall(%x0 = flags, + * %x1 = child_stack, + * %x2 = parent_tidptr, + * %x3 = newtls, + * %x4 = child_tidptr) + */ + "mov x8, %8\n" + "svc 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "mov %0, x0\n" + "cbnz x0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldp x1, x0, [sp], #16\n" + "blr x1\n" + + /* Call _exit(%r0). + */ + "mov x8, %9\n" + "svc 0x0\n" + "1:\n" + : "=r" (__res) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "x8", "memory"); + } + LSS_RETURN(int, __res); + } + #elif defined(__mips__) + #undef LSS_REG + #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \ + (unsigned long)(a) + #undef LSS_BODY + #undef LSS_SYSCALL_CLOBBERS + #if _MIPS_SIM == _MIPS_SIM_ABI32 + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", \ + "$11", "$12", "$13", "$14", "$15", \ + "$24", "$25", "hi", "lo", "memory" + #else + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "hi", "lo", "memory" + #endif + #define LSS_BODY(type,name,r7,...) \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ ("syscall\n" \ + : "=r"(__v0), r7 (__r7) \ + : "0"(__v0), ##__VA_ARGS__ \ + : LSS_SYSCALL_CLOBBERS); \ + LSS_RETURN(type, __v0, __r7) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_BODY(type, name, "=r"); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_BODY(type, name, "=r", "r"(__r4)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_REG(5, arg2); \ + LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5), "r"(__r6)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6)); \ + } + #undef _syscall5 + #if _MIPS_SIM == _MIPS_SIM_ABI32 + /* The old 32bit MIPS system call API passes the fifth and sixth argument + * on the stack, whereas the new APIs use registers "r8" and "r9". + */ + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ (".set noreorder\n" \ + "subu $29, 32\n" \ + "sw %5, 16($29)\n" \ + "syscall\n" \ + "addiu $29, 32\n" \ + ".set reorder\n" \ + : "+r"(__v0), "+r" (__r7) \ + : "r"(__r4), "r"(__r5), \ + "r"(__r6), "r" ((unsigned long)arg5) \ + : "$8", "$9", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "memory"); \ + LSS_RETURN(type, __v0, __r7); \ + } + #else + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); LSS_REG(8, arg5); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ + "r"(__r8)); \ + } + #endif + #undef _syscall6 + #if _MIPS_SIM == _MIPS_SIM_ABI32 + /* The old 32bit MIPS system call API passes the fifth and sixth argument + * on the stack, whereas the new APIs use registers "r8" and "r9". + */ + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ (".set noreorder\n" \ + "subu $29, 32\n" \ + "sw %5, 16($29)\n" \ + "sw %6, 20($29)\n" \ + "syscall\n" \ + "addiu $29, 32\n" \ + ".set reorder\n" \ + : "+r"(__v0), "+r" (__r7) \ + : "r"(__r4), "r"(__r5), \ + "r"(__r6), "r" ((unsigned long)arg5), \ + "r" ((unsigned long)arg6) \ + : "$8", "$9", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "memory"); \ + LSS_RETURN(type, __v0, __r7); \ + } + #else + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5,type6 arg6) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); LSS_REG(8, arg5); LSS_REG(9, arg6); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ + "r"(__r8), "r"(__r9)); \ + } + #endif + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + register unsigned long __v0 __asm__("$2") = -EINVAL; + register unsigned long __r7 __asm__("$7") = (unsigned long)newtls; + { + register int __flags __asm__("$4") = flags; + register void *__stack __asm__("$5") = child_stack; + register void *__ptid __asm__("$6") = parent_tidptr; + register int *__ctid __asm__("$8") = child_tidptr; + __asm__ __volatile__( + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "subu $29,24\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "sub $29,16\n" + #else + "dsubu $29,16\n" + #endif + + /* if (fn == NULL || child_stack == NULL) + * return -EINVAL; + */ + "beqz %4,1f\n" + "beqz %5,1f\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "subu %5,32\n" + "sw %4,0(%5)\n" + "sw %7,4(%5)\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "sub %5,32\n" + "sw %4,0(%5)\n" + "sw %7,8(%5)\n" + #else + "dsubu %5,32\n" + "sd %4,0(%5)\n" + "sd %7,8(%5)\n" + #endif + + /* $7 = syscall($4 = flags, + * $5 = child_stack, + * $6 = parent_tidptr, + * $7 = newtls, + * $8 = child_tidptr) + */ + "li $2,%2\n" + "syscall\n" + + /* if ($7 != 0) + * return $2; + */ + "bnez $7,1f\n" + "bnez $2,1f\n" + + /* In the child, now. Call "fn(arg)". + */ + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "lw $25,0($29)\n" + "lw $4,4($29)\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "lw $25,0($29)\n" + "lw $4,8($29)\n" + #else + "ld $25,0($29)\n" + "ld $4,8($29)\n" + #endif + "jalr $25\n" + + /* Call _exit($2) + */ + "move $4,$2\n" + "li $2,%3\n" + "syscall\n" + + "1:\n" + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "addu $29, 24\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "add $29, 16\n" + #else + "daddu $29,16\n" + #endif + : "+r" (__v0), "+r" (__r7) + : "i"(__NR_clone), "i"(__NR_exit), "r"(fn), + "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__ctid) + : "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$24", "$25", "memory"); + } + LSS_RETURN(int, __v0, __r7); + } + #elif defined (__PPC__) + #undef LSS_LOADARGS_0 + #define LSS_LOADARGS_0(name, dummy...) \ + __sc_0 = __NR_##name + #undef LSS_LOADARGS_1 + #define LSS_LOADARGS_1(name, arg1) \ + LSS_LOADARGS_0(name); \ + __sc_3 = (unsigned long) (arg1) + #undef LSS_LOADARGS_2 + #define LSS_LOADARGS_2(name, arg1, arg2) \ + LSS_LOADARGS_1(name, arg1); \ + __sc_4 = (unsigned long) (arg2) + #undef LSS_LOADARGS_3 + #define LSS_LOADARGS_3(name, arg1, arg2, arg3) \ + LSS_LOADARGS_2(name, arg1, arg2); \ + __sc_5 = (unsigned long) (arg3) + #undef LSS_LOADARGS_4 + #define LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4) \ + LSS_LOADARGS_3(name, arg1, arg2, arg3); \ + __sc_6 = (unsigned long) (arg4) + #undef LSS_LOADARGS_5 + #define LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5) \ + LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4); \ + __sc_7 = (unsigned long) (arg5) + #undef LSS_LOADARGS_6 + #define LSS_LOADARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ + LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5); \ + __sc_8 = (unsigned long) (arg6) + #undef LSS_ASMINPUT_0 + #define LSS_ASMINPUT_0 "0" (__sc_0) + #undef LSS_ASMINPUT_1 + #define LSS_ASMINPUT_1 LSS_ASMINPUT_0, "1" (__sc_3) + #undef LSS_ASMINPUT_2 + #define LSS_ASMINPUT_2 LSS_ASMINPUT_1, "2" (__sc_4) + #undef LSS_ASMINPUT_3 + #define LSS_ASMINPUT_3 LSS_ASMINPUT_2, "3" (__sc_5) + #undef LSS_ASMINPUT_4 + #define LSS_ASMINPUT_4 LSS_ASMINPUT_3, "4" (__sc_6) + #undef LSS_ASMINPUT_5 + #define LSS_ASMINPUT_5 LSS_ASMINPUT_4, "5" (__sc_7) + #undef LSS_ASMINPUT_6 + #define LSS_ASMINPUT_6 LSS_ASMINPUT_5, "6" (__sc_8) + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0"); \ + register unsigned long __sc_3 __asm__ ("r3"); \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + register unsigned long __sc_8 __asm__ ("r8"); \ + \ + LSS_LOADARGS_##nr(name, args); \ + __asm__ __volatile__ \ + ("sc\n\t" \ + "mfcr %0" \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7), "=&r" (__sc_8) \ + : LSS_ASMINPUT_##nr \ + : "cr0", "ctr", "memory", \ + "r9", "r10", "r11", "r12"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + LSS_RETURN(type, __sc_ret, __sc_err) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, arg1); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, arg1, arg2); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, arg1, arg2, arg3); \ + } + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, arg1, arg2, arg3, arg4); \ + } + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5); \ + } + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ + } + /* clone function adapted from glibc 2.3.6 clone.S */ + /* TODO(csilvers): consider wrapping some args up in a struct, like we + * do for i386's _syscall6, so we can compile successfully on gcc 2.95 + */ + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __ret, __err; + { + register int (*__fn)(void *) __asm__ ("r8") = fn; + register void *__cstack __asm__ ("r4") = child_stack; + register int __flags __asm__ ("r3") = flags; + register void * __arg __asm__ ("r9") = arg; + register int * __ptidptr __asm__ ("r5") = parent_tidptr; + register void * __newtls __asm__ ("r6") = newtls; + register int * __ctidptr __asm__ ("r7") = child_tidptr; + __asm__ __volatile__( + /* check for fn == NULL + * and child_stack == NULL + */ + "cmpwi cr0, %6, 0\n\t" + "cmpwi cr1, %7, 0\n\t" + "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t" + "beq- cr0, 1f\n\t" + + /* set up stack frame for child */ + "clrrwi %7, %7, 4\n\t" + "li 0, 0\n\t" + "stwu 0, -16(%7)\n\t" + + /* fn, arg, child_stack are saved across the syscall: r28-30 */ + "mr 28, %6\n\t" + "mr 29, %7\n\t" + "mr 27, %9\n\t" + + /* syscall */ + "li 0, %4\n\t" + /* flags already in r3 + * child_stack already in r4 + * ptidptr already in r5 + * newtls already in r6 + * ctidptr already in r7 + */ + "sc\n\t" + + /* Test if syscall was successful */ + "cmpwi cr1, 3, 0\n\t" + "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" + "bne- cr1, 1f\n\t" + + /* Do the function call */ + "mtctr 28\n\t" + "mr 3, 27\n\t" + "bctrl\n\t" + + /* Call _exit(r3) */ + "li 0, %5\n\t" + "sc\n\t" + + /* Return to parent */ + "1:\n" + "mfcr %1\n\t" + "mr %0, 3\n\t" + : "=r" (__ret), "=r" (__err) + : "0" (-1), "1" (EINVAL), + "i" (__NR_clone), "i" (__NR_exit), + "r" (__fn), "r" (__cstack), "r" (__flags), + "r" (__arg), "r" (__ptidptr), "r" (__newtls), + "r" (__ctidptr) + : "cr0", "cr1", "memory", "ctr", + "r0", "r29", "r27", "r28"); + } + LSS_RETURN(int, __ret, __err); + } + #elif defined(__s390__) + #undef LSS_REG + #define LSS_REG(r, a) register unsigned long __r##r __asm__("r"#r) = (unsigned long) a + #undef LSS_BODY + #define LSS_BODY(type, name, args...) \ + register unsigned long __nr __asm__("r1") \ + = (unsigned long)(__NR_##name); \ + register long __res_r2 __asm__("r2"); \ + long __res; \ + __asm__ __volatile__ \ + ("svc 0\n\t" \ + : "=d"(__res_r2) \ + : "d"(__nr), ## args \ + : "memory"); \ + __res = __res_r2; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(2, arg1); \ + LSS_BODY(type, name, "0"(__r2)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4)); \ + } + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5)); \ + } + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4, type5 arg5) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); LSS_REG(6, arg5); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6)); \ + } + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ + type4 arg4, type5 arg5, type6 arg6) { \ + LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ + LSS_REG(5, arg4); LSS_REG(6, arg5); LSS_REG(7, arg6); \ + LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ + "d"(__r5), "d"(__r6), "d"(__r7)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __ret; + { + register int (*__fn)(void *) __asm__ ("r1") = fn; + register void *__cstack __asm__ ("r2") = child_stack; + register int __flags __asm__ ("r3") = flags; + register void *__arg __asm__ ("r0") = arg; + register int *__ptidptr __asm__ ("r4") = parent_tidptr; + register void *__newtls __asm__ ("r6") = newtls; + register int *__ctidptr __asm__ ("r5") = child_tidptr; + __asm__ __volatile__ ( + #ifndef __s390x__ + /* arg already in r0 */ + "ltr %4, %4\n\t" /* check fn, which is already in r1 */ + "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ + "ltr %5, %5\n\t" /* check child_stack, which is already in r2 */ + "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ + /* flags already in r3 */ + /* parent_tidptr already in r4 */ + /* child_tidptr already in r5 */ + /* newtls already in r6 */ + "svc %2\n\t" /* invoke clone syscall */ + "ltr %0,%%r2\n\t" /* load return code into __ret and test */ + "jnz 1f\n\t" /* return to parent if non-zero */ + /* start child thread */ + "lr %%r2, %7\n\t" /* set first parameter to void *arg */ + "ahi %%r15, -96\n\t" /* make room on the stack for the save area */ + "xc 0(4,%%r15), 0(%%r15)\n\t" + "basr %%r14, %4\n\t" /* jump to fn */ + "svc %3\n" /* invoke exit syscall */ + "1:\n" + #else + /* arg already in r0 */ + "ltgr %4, %4\n\t" /* check fn, which is already in r1 */ + "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ + "ltgr %5, %5\n\t" /* check child_stack, which is already in r2 */ + "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ + /* flags already in r3 */ + /* parent_tidptr already in r4 */ + /* child_tidptr already in r5 */ + /* newtls already in r6 */ + "svc %2\n\t" /* invoke clone syscall */ + "ltgr %0, %%r2\n\t" /* load return code into __ret and test */ + "jnz 1f\n\t" /* return to parent if non-zero */ + /* start child thread */ + "lgr %%r2, %7\n\t" /* set first parameter to void *arg */ + "aghi %%r15, -160\n\t" /* make room on the stack for the save area */ + "xc 0(8,%%r15), 0(%%r15)\n\t" + "basr %%r14, %4\n\t" /* jump to fn */ + "svc %3\n" /* invoke exit syscall */ + "1:\n" + #endif + : "=r" (__ret) + : "0" (-EINVAL), "i" (__NR_clone), "i" (__NR_exit), + "d" (__fn), "d" (__cstack), "d" (__flags), "d" (__arg), + "d" (__ptidptr), "d" (__newtls), "d" (__ctidptr) + : "cc", "r14", "memory" + ); + } + LSS_RETURN(int, __ret); + } + #endif + #define __NR__exit __NR_exit + #define __NR__gettid __NR_gettid + #define __NR__mremap __NR_mremap + LSS_INLINE _syscall1(void *, brk, void *, e) + LSS_INLINE _syscall1(int, chdir, const char *,p) + LSS_INLINE _syscall1(int, close, int, f) + LSS_INLINE _syscall2(int, clock_getres, int, c, + struct kernel_timespec*, t) + LSS_INLINE _syscall2(int, clock_gettime, int, c, + struct kernel_timespec*, t) + LSS_INLINE _syscall1(int, dup, int, f) + #if defined(__NR_dup2) + // dup2 is polyfilled below when not available. + LSS_INLINE _syscall2(int, dup2, int, s, + int, d) + #endif + #if defined(__NR_dup3) + LSS_INLINE _syscall3(int, dup3, int, s, int, d, int, f) + #endif + LSS_INLINE _syscall3(int, execve, const char*, f, + const char*const*,a,const char*const*, e) + LSS_INLINE _syscall1(int, _exit, int, e) + LSS_INLINE _syscall1(int, exit_group, int, e) + LSS_INLINE _syscall3(int, fcntl, int, f, + int, c, long, a) + #if defined(__NR_fork) + // fork is polyfilled below when not available. + LSS_INLINE _syscall0(pid_t, fork) + #endif + LSS_INLINE _syscall2(int, fstat, int, f, + struct kernel_stat*, b) + LSS_INLINE _syscall2(int, fstatfs, int, f, + struct kernel_statfs*, b) + #if defined(__x86_64__) + /* Need to make sure off_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(ftruncate)(int f, off_t l) { + LSS_BODY(2, int, ftruncate, LSS_SYSCALL_ARG(f), (uint64_t)(l)); + } + #else + LSS_INLINE _syscall2(int, ftruncate, int, f, + off_t, l) + #endif + LSS_INLINE _syscall6(int, futex, int*, u, + int, o, int, v, + struct kernel_timespec*, t, + int*, u2, int, v2) + LSS_INLINE _syscall3(int, getdents, int, f, + struct kernel_dirent*, d, int, c) + LSS_INLINE _syscall3(int, getdents64, int, f, + struct kernel_dirent64*, d, int, c) + LSS_INLINE _syscall0(gid_t, getegid) + LSS_INLINE _syscall0(uid_t, geteuid) + #if defined(__NR_getpgrp) + LSS_INLINE _syscall0(pid_t, getpgrp) + #endif + LSS_INLINE _syscall0(pid_t, getpid) + LSS_INLINE _syscall0(pid_t, getppid) + LSS_INLINE _syscall2(int, getpriority, int, a, + int, b) + LSS_INLINE _syscall3(int, getresgid, gid_t *, r, + gid_t *, e, gid_t *, s) + LSS_INLINE _syscall3(int, getresuid, uid_t *, r, + uid_t *, e, uid_t *, s) +#if !defined(__ARM_EABI__) + LSS_INLINE _syscall2(int, getrlimit, int, r, + struct kernel_rlimit*, l) +#endif + LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) + LSS_INLINE _syscall0(pid_t, _gettid) + LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t, + void*, tz) + LSS_INLINE _syscall5(int, setxattr, const char *,p, + const char *, n, const void *,v, + size_t, s, int, f) + LSS_INLINE _syscall5(int, lsetxattr, const char *,p, + const char *, n, const void *,v, + size_t, s, int, f) + LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p, + const char *, n, void *, v, size_t, s) + LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p, + const char *, n, void *, v, size_t, s) + LSS_INLINE _syscall3(ssize_t, listxattr, const char *,p, + char *, l, size_t, s) + LSS_INLINE _syscall3(ssize_t, llistxattr, const char *,p, + char *, l, size_t, s) + LSS_INLINE _syscall3(int, ioctl, int, d, + int, r, void *, a) + LSS_INLINE _syscall2(int, ioprio_get, int, which, + int, who) + LSS_INLINE _syscall3(int, ioprio_set, int, which, + int, who, int, ioprio) + LSS_INLINE _syscall2(int, kill, pid_t, p, + int, s) + #if defined(__x86_64__) + /* Need to make sure off_t isn't truncated to 32-bits under x32. */ + LSS_INLINE off_t LSS_NAME(lseek)(int f, off_t o, int w) { + _LSS_BODY(3, off_t, lseek, off_t, LSS_SYSCALL_ARG(f), (uint64_t)(o), + LSS_SYSCALL_ARG(w)); + } + #else + LSS_INLINE _syscall3(off_t, lseek, int, f, + off_t, o, int, w) + #endif + LSS_INLINE _syscall2(int, munmap, void*, s, + size_t, l) + LSS_INLINE _syscall6(long, move_pages, pid_t, p, + unsigned long, n, void **,g, int *, d, + int *, s, int, f) + LSS_INLINE _syscall3(int, mprotect, const void *,a, + size_t, l, int, p) + LSS_INLINE _syscall5(void*, _mremap, void*, o, + size_t, os, size_t, ns, + unsigned long, f, void *, a) + #if defined(__NR_open) + // open is polyfilled below when not available. + LSS_INLINE _syscall3(int, open, const char*, p, + int, f, int, m) + #endif + #if defined(__NR_poll) + // poll is polyfilled below when not available. + LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, + unsigned int, n, int, t) + #endif + #if defined(__NR_ppoll) + LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u, + unsigned int, n, const struct kernel_timespec *, t, + const struct kernel_sigset_t *, sigmask, size_t, s) + #endif + LSS_INLINE _syscall5(int, prctl, int, option, + unsigned long, arg2, + unsigned long, arg3, + unsigned long, arg4, + unsigned long, arg5) + LSS_INLINE _syscall4(long, ptrace, int, r, + pid_t, p, void *, a, void *, d) + #if defined(__NR_quotactl) + // Defined on x86_64 / i386 only + LSS_INLINE _syscall4(int, quotactl, int, cmd, const char *, special, + int, id, caddr_t, addr) + #endif + LSS_INLINE _syscall3(ssize_t, read, int, f, + void *, b, size_t, c) + #if defined(__NR_readlink) + // readlink is polyfilled below when not available. + LSS_INLINE _syscall3(int, readlink, const char*, p, + char*, b, size_t, s) + #endif + #if defined(__NR_readlinkat) + LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b, + size_t, s) + #endif + LSS_INLINE _syscall4(int, rt_sigaction, int, s, + const struct kernel_sigaction*, a, + struct kernel_sigaction*, o, size_t, c) + LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s, + size_t, c) + LSS_INLINE _syscall4(int, rt_sigprocmask, int, h, + const struct kernel_sigset_t*, s, + struct kernel_sigset_t*, o, size_t, c) + LSS_INLINE _syscall2(int, rt_sigsuspend, + const struct kernel_sigset_t*, s, size_t, c) + LSS_INLINE _syscall4(int, rt_sigtimedwait, const struct kernel_sigset_t*, s, + siginfo_t*, i, const struct timespec*, t, size_t, c) + LSS_INLINE _syscall3(int, sched_getaffinity,pid_t, p, + unsigned int, l, unsigned long *, m) + LSS_INLINE _syscall3(int, sched_setaffinity,pid_t, p, + unsigned int, l, unsigned long *, m) + LSS_INLINE _syscall0(int, sched_yield) + LSS_INLINE _syscall1(long, set_tid_address, int *, t) + LSS_INLINE _syscall1(int, setfsgid, gid_t, g) + LSS_INLINE _syscall1(int, setfsuid, uid_t, u) + LSS_INLINE _syscall1(int, setuid, uid_t, u) + LSS_INLINE _syscall1(int, setgid, gid_t, g) + LSS_INLINE _syscall2(int, setpgid, pid_t, p, + pid_t, g) + LSS_INLINE _syscall3(int, setpriority, int, a, + int, b, int, p) + LSS_INLINE _syscall3(int, setresgid, gid_t, r, + gid_t, e, gid_t, s) + LSS_INLINE _syscall3(int, setresuid, uid_t, r, + uid_t, e, uid_t, s) + LSS_INLINE _syscall2(int, setrlimit, int, r, + const struct kernel_rlimit*, l) + LSS_INLINE _syscall0(pid_t, setsid) + LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, + const stack_t*, o) + #if defined(__NR_sigreturn) + LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) + #endif + #if defined(__NR_stat) + // stat is polyfilled below when not available. + LSS_INLINE _syscall2(int, stat, const char*, f, + struct kernel_stat*, b) + #endif + LSS_INLINE _syscall2(int, statfs, const char*, f, + struct kernel_statfs*, b) + LSS_INLINE _syscall3(int, tgkill, pid_t, p, + pid_t, t, int, s) + LSS_INLINE _syscall2(int, tkill, pid_t, p, + int, s) + #if defined(__NR_unlink) + // unlink is polyfilled below when not available. + LSS_INLINE _syscall1(int, unlink, const char*, f) + #endif + LSS_INLINE _syscall3(ssize_t, write, int, f, + const void *, b, size_t, c) + LSS_INLINE _syscall3(ssize_t, writev, int, f, + const struct kernel_iovec*, v, size_t, c) + #if defined(__NR_getcpu) + LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, + unsigned *, node, void *, unused) + #endif + #if defined(__x86_64__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) + LSS_INLINE _syscall3(int, recvmsg, int, s, + struct kernel_msghdr*, m, int, f) + LSS_INLINE _syscall3(int, sendmsg, int, s, + const struct kernel_msghdr*, m, int, f) + LSS_INLINE _syscall6(int, sendto, int, s, + const void*, m, size_t, l, + int, f, + const struct kernel_sockaddr*, a, int, t) + LSS_INLINE _syscall2(int, shutdown, int, s, + int, h) + LSS_INLINE _syscall3(int, socket, int, d, + int, t, int, p) + LSS_INLINE _syscall4(int, socketpair, int, d, + int, t, int, p, int*, s) + #endif + #if defined(__NR_fadvise64) + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, + int advice) { + LSS_BODY(4, int, fadvise64, LSS_SYSCALL_ARG(fd), (uint64_t)(offset), + (uint64_t)(len), LSS_SYSCALL_ARG(advice)); + } + #else + LSS_INLINE _syscall4(int, fadvise64, + int, fd, loff_t, offset, loff_t, len, int, advice) + #endif + #elif defined(__i386__) + #define __NR__fadvise64_64 __NR_fadvise64_64 + LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi, + int, advice) + + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, + loff_t len, int advice) { + return LSS_NAME(_fadvise64_64)(fd, + (unsigned)offset, (unsigned)(offset >>32), + (unsigned)len, (unsigned)(len >> 32), + advice); + } + + #elif defined(__s390__) && !defined(__s390x__) + #define __NR__fadvise64_64 __NR_fadvise64_64 + struct kernel_fadvise64_64_args { + int fd; + long long offset; + long long len; + int advice; + }; + + LSS_INLINE _syscall1(int, _fadvise64_64, + struct kernel_fadvise64_64_args *args) + + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, + loff_t len, int advice) { + struct kernel_fadvise64_64_args args = { fd, offset, len, advice }; + return LSS_NAME(_fadvise64_64)(&args); + } + #endif + #if defined(__NR_fallocate) + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(fallocate)(int f, int mode, loff_t offset, + loff_t len) { + LSS_BODY(4, int, fallocate, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(mode), + (uint64_t)(offset), (uint64_t)(len)); + } + #elif (defined(__i386__) || (defined(__s390__) && !defined(__s390x__)) \ + || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) \ + || (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) \ + || defined(__PPC__)) + #define __NR__fallocate __NR_fallocate + LSS_INLINE _syscall6(int, _fallocate, int, fd, + int, mode, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi) + + LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, + loff_t offset, loff_t len) { + union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; + return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); + } + #else + LSS_INLINE _syscall4(int, fallocate, + int, f, int, mode, loff_t, offset, loff_t, len) + #endif + #endif + #if defined(__NR_newfstatat) + LSS_INLINE _syscall4(int, newfstatat, int, d, + const char *, p, + struct kernel_stat*, b, int, f) + #endif + #if defined(__x86_64__) || defined(__s390x__) + LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, + gid_t *egid, + gid_t *sgid) { + return LSS_NAME(getresgid)(rgid, egid, sgid); + } + + LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, + uid_t *euid, + uid_t *suid) { + return LSS_NAME(getresuid)(ruid, euid, suid); + } + + LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { + return LSS_NAME(setfsgid)(gid); + } + + LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { + return LSS_NAME(setfsuid)(uid); + } + + LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { + return LSS_NAME(setresgid)(rgid, egid, sgid); + } + + LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { + return LSS_NAME(setresuid)(ruid, euid, suid); + } + + LSS_INLINE int LSS_NAME(sigaction)(int signum, + const struct kernel_sigaction *act, + struct kernel_sigaction *oldact) { + #if defined(__x86_64__) + /* On x86_64, the kernel requires us to always set our own + * SA_RESTORER in order to be able to return from a signal handler. + * This function must have a "magic" signature that the "gdb" + * (and maybe the kernel?) can recognize. + */ + if (act != NULL && !(act->sa_flags & SA_RESTORER)) { + struct kernel_sigaction a = *act; + a.sa_flags |= SA_RESTORER; + a.sa_restorer = LSS_NAME(restore_rt)(); + return LSS_NAME(rt_sigaction)(signum, &a, oldact, + (KERNEL_NSIG+7)/8); + } else + #endif + return LSS_NAME(rt_sigaction)(signum, act, oldact, + (KERNEL_NSIG+7)/8); + } + + LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { + return LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); + } + + LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { + return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); + } + #endif + #if defined(__NR_rt_sigprocmask) + LSS_INLINE int LSS_NAME(sigprocmask)(int how, + const struct kernel_sigset_t *set, + struct kernel_sigset_t *oldset) { + return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); + } + #endif + #if defined(__NR_rt_sigtimedwait) + LSS_INLINE int LSS_NAME(sigtimedwait)(const struct kernel_sigset_t *set, + siginfo_t *info, + const struct timespec *timeout) { + return LSS_NAME(rt_sigtimedwait)(set, info, timeout, (KERNEL_NSIG+7)/8); + } + #endif + #if defined(__NR_wait4) + LSS_INLINE _syscall4(pid_t, wait4, pid_t, p, + int*, s, int, o, + struct kernel_rusage*, r) + #endif + #if defined(__NR_openat) + LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m) + #endif + #if defined(__NR_unlinkat) + LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f) + #endif + #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__s390__) && !defined(__s390x__)) + #define __NR__getresgid32 __NR_getresgid32 + #define __NR__getresuid32 __NR_getresuid32 + #define __NR__setfsgid32 __NR_setfsgid32 + #define __NR__setfsuid32 __NR_setfsuid32 + #define __NR__setresgid32 __NR_setresgid32 + #define __NR__setresuid32 __NR_setresuid32 +#if defined(__ARM_EABI__) + LSS_INLINE _syscall2(int, ugetrlimit, int, r, + struct kernel_rlimit*, l) +#endif + LSS_INLINE _syscall3(int, _getresgid32, gid_t *, r, + gid_t *, e, gid_t *, s) + LSS_INLINE _syscall3(int, _getresuid32, uid_t *, r, + uid_t *, e, uid_t *, s) + LSS_INLINE _syscall1(int, _setfsgid32, gid_t, f) + LSS_INLINE _syscall1(int, _setfsuid32, uid_t, f) + LSS_INLINE _syscall3(int, _setresgid32, gid_t, r, + gid_t, e, gid_t, s) + LSS_INLINE _syscall3(int, _setresuid32, uid_t, r, + uid_t, e, uid_t, s) + + LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, + gid_t *egid, + gid_t *sgid) { + int rc; + if ((rc = LSS_NAME(_getresgid32)(rgid, egid, sgid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((rgid == NULL) || (egid == NULL) || (sgid == NULL)) { + return EFAULT; + } + // Clear the high bits first, since getresgid only sets 16 bits + *rgid = *egid = *sgid = 0; + rc = LSS_NAME(getresgid)(rgid, egid, sgid); + } + return rc; + } + + LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, + uid_t *euid, + uid_t *suid) { + int rc; + if ((rc = LSS_NAME(_getresuid32)(ruid, euid, suid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((ruid == NULL) || (euid == NULL) || (suid == NULL)) { + return EFAULT; + } + // Clear the high bits first, since getresuid only sets 16 bits + *ruid = *euid = *suid = 0; + rc = LSS_NAME(getresuid)(ruid, euid, suid); + } + return rc; + } + + LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { + int rc; + if ((rc = LSS_NAME(_setfsgid32)(gid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)gid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setfsgid)(gid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { + int rc; + if ((rc = LSS_NAME(_setfsuid32)(uid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)uid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setfsuid)(uid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { + int rc; + if ((rc = LSS_NAME(_setresgid32)(rgid, egid, sgid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)rgid & ~0xFFFFu || + (unsigned int)egid & ~0xFFFFu || + (unsigned int)sgid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setresgid)(rgid, egid, sgid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { + int rc; + if ((rc = LSS_NAME(_setresuid32)(ruid, euid, suid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)ruid & ~0xFFFFu || + (unsigned int)euid & ~0xFFFFu || + (unsigned int)suid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setresuid)(ruid, euid, suid); + } + } + return rc; + } + #endif + LSS_INLINE int LSS_NAME(sigemptyset)(struct kernel_sigset_t *set) { + memset(&set->sig, 0, sizeof(set->sig)); + return 0; + } + + LSS_INLINE int LSS_NAME(sigfillset)(struct kernel_sigset_t *set) { + memset(&set->sig, -1, sizeof(set->sig)); + return 0; + } + + LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] + |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0]))); + return 0; + } + } + + LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] + &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0])))); + return 0; + } + } + + LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] & + (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); + } + } + #if defined(__i386__) || \ + defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__PPC__) || \ + (defined(__s390__) && !defined(__s390x__)) + #define __NR__sigaction __NR_sigaction + #define __NR__sigpending __NR_sigpending + #define __NR__sigsuspend __NR_sigsuspend + #define __NR__socketcall __NR_socketcall + LSS_INLINE _syscall2(int, fstat64, int, f, + struct kernel_stat64 *, b) + LSS_INLINE _syscall5(int, _llseek, uint, fd, + unsigned long, hi, unsigned long, lo, + loff_t *, res, uint, wh) +#if defined(__s390__) && !defined(__s390x__) + /* On s390, mmap2() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(_mmap2)(void *s, size_t l, int p, int f, int d, + off_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap2, "0"(__r2)); + } +#else + #define __NR__mmap2 __NR_mmap2 + LSS_INLINE _syscall6(void*, _mmap2, void*, s, + size_t, l, int, p, + int, f, int, d, + off_t, o) +#endif + LSS_INLINE _syscall3(int, _sigaction, int, s, + const struct kernel_old_sigaction*, a, + struct kernel_old_sigaction*, o) + LSS_INLINE _syscall1(int, _sigpending, unsigned long*, s) + #ifdef __PPC__ + LSS_INLINE _syscall1(int, _sigsuspend, unsigned long, s) + #else + LSS_INLINE _syscall3(int, _sigsuspend, const void*, a, + int, b, + unsigned long, s) + #endif + LSS_INLINE _syscall2(int, stat64, const char *, p, + struct kernel_stat64 *, b) + + LSS_INLINE int LSS_NAME(sigaction)(int signum, + const struct kernel_sigaction *act, + struct kernel_sigaction *oldact) { + int old_errno = LSS_ERRNO; + int rc; + struct kernel_sigaction a; + if (act != NULL) { + a = *act; + #ifdef __i386__ + /* On i386, the kernel requires us to always set our own + * SA_RESTORER when using realtime signals. Otherwise, it does not + * know how to return from a signal handler. This function must have + * a "magic" signature that the "gdb" (and maybe the kernel?) can + * recognize. + * Apparently, a SA_RESTORER is implicitly set by the kernel, when + * using non-realtime signals. + * + * TODO: Test whether ARM needs a restorer + */ + if (!(a.sa_flags & SA_RESTORER)) { + a.sa_flags |= SA_RESTORER; + a.sa_restorer = (a.sa_flags & SA_SIGINFO) + ? LSS_NAME(restore_rt)() : LSS_NAME(restore)(); + } + #endif + } + rc = LSS_NAME(rt_sigaction)(signum, act ? &a : act, oldact, + (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + struct kernel_old_sigaction oa, ooa, *ptr_a = &oa, *ptr_oa = &ooa; + if (!act) { + ptr_a = NULL; + } else { + oa.sa_handler_ = act->sa_handler_; + memcpy(&oa.sa_mask, &act->sa_mask, sizeof(oa.sa_mask)); + #ifndef __mips__ + oa.sa_restorer = act->sa_restorer; + #endif + oa.sa_flags = act->sa_flags; + } + if (!oldact) { + ptr_oa = NULL; + } + LSS_ERRNO = old_errno; + rc = LSS_NAME(_sigaction)(signum, ptr_a, ptr_oa); + if (rc == 0 && oldact) { + if (act) { + memcpy(oldact, act, sizeof(*act)); + } else { + memset(oldact, 0, sizeof(*oldact)); + } + oldact->sa_handler_ = ptr_oa->sa_handler_; + oldact->sa_flags = ptr_oa->sa_flags; + memcpy(&oldact->sa_mask, &ptr_oa->sa_mask, sizeof(ptr_oa->sa_mask)); + #ifndef __mips__ + oldact->sa_restorer = ptr_oa->sa_restorer; + #endif + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { + int old_errno = LSS_ERRNO; + int rc = LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + LSS_ERRNO = old_errno; + LSS_NAME(sigemptyset)(set); + rc = LSS_NAME(_sigpending)(&set->sig[0]); + } + return rc; + } + + LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { + int olderrno = LSS_ERRNO; + int rc = LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + LSS_ERRNO = olderrno; + rc = LSS_NAME(_sigsuspend)( + #ifndef __PPC__ + set, 0, + #endif + set->sig[0]); + } + return rc; + } + #endif + #if defined(__i386__) || \ + defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__PPC__) || \ + (defined(__s390__) && !defined(__s390x__)) + /* On these architectures, implement mmap() with mmap2(). */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + if (o % 4096) { + LSS_ERRNO = EINVAL; + return (void *) -1; + } + return LSS_NAME(_mmap2)(s, l, p, f, d, (o / 4096)); + } + #elif defined(__s390x__) + /* On s390x, mmap() arguments are passed in memory. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, + (unsigned long) p, (unsigned long) f, + (unsigned long) d, (unsigned long) o }; + LSS_REG(2, buf); + LSS_BODY(void*, mmap, "0"(__r2)); + } + #elif defined(__x86_64__) + /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), + LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), + LSS_SYSCALL_ARG(d), (uint64_t)(o)); + } + #else + /* Remaining 64-bit architectures. */ + LSS_INLINE _syscall6(void*, mmap, void*, addr, size_t, length, int, prot, + int, flags, int, fd, int64_t, offset) + #endif + #if defined(__PPC__) + #undef LSS_SC_LOADARGS_0 + #define LSS_SC_LOADARGS_0(dummy...) + #undef LSS_SC_LOADARGS_1 + #define LSS_SC_LOADARGS_1(arg1) \ + __sc_4 = (unsigned long) (arg1) + #undef LSS_SC_LOADARGS_2 + #define LSS_SC_LOADARGS_2(arg1, arg2) \ + LSS_SC_LOADARGS_1(arg1); \ + __sc_5 = (unsigned long) (arg2) + #undef LSS_SC_LOADARGS_3 + #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \ + LSS_SC_LOADARGS_2(arg1, arg2); \ + __sc_6 = (unsigned long) (arg3) + #undef LSS_SC_LOADARGS_4 + #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \ + LSS_SC_LOADARGS_3(arg1, arg2, arg3); \ + __sc_7 = (unsigned long) (arg4) + #undef LSS_SC_LOADARGS_5 + #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \ + LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \ + __sc_8 = (unsigned long) (arg5) + #undef LSS_SC_BODY + #define LSS_SC_BODY(nr, type, opt, args...) \ + long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \ + register unsigned long __sc_3 __asm__ ("r3") = opt; \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + register unsigned long __sc_8 __asm__ ("r8"); \ + LSS_SC_LOADARGS_##nr(args); \ + __asm__ __volatile__ \ + ("stwu 1, -48(1)\n\t" \ + "stw 4, 20(1)\n\t" \ + "stw 5, 24(1)\n\t" \ + "stw 6, 28(1)\n\t" \ + "stw 7, 32(1)\n\t" \ + "stw 8, 36(1)\n\t" \ + "addi 4, 1, 20\n\t" \ + "sc\n\t" \ + "mfcr %0" \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7), "=&r" (__sc_8) \ + : LSS_ASMINPUT_##nr \ + : "cr0", "ctr", "memory"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + LSS_RETURN(type, __sc_ret, __sc_err) + + LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, + int flags){ + LSS_SC_BODY(3, ssize_t, 17, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, + const struct kernel_msghdr *msg, + int flags) { + LSS_SC_BODY(3, ssize_t, 16, s, msg, flags); + } + + // TODO(csilvers): why is this ifdef'ed out? +#if 0 + LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, + int flags, + const struct kernel_sockaddr *to, + unsigned int tolen) { + LSS_BODY(6, ssize_t, 11, s, buf, len, flags, to, tolen); + } +#endif + + LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { + LSS_SC_BODY(2, int, 13, s, how); + } + + LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { + LSS_SC_BODY(3, int, 1, domain, type, protocol); + } + + LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, + int sv[2]) { + LSS_SC_BODY(4, int, 8, d, type, protocol, sv); + } + #endif + #if defined(__ARM_EABI__) || defined (__aarch64__) + LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, + int, flags) + LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, + msg, int, flags) + LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len, + int, flags, const struct kernel_sockaddr*, to, + unsigned int, tolen) + LSS_INLINE _syscall2(int, shutdown, int, s, int, how) + LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol) + LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol, + int*, sv) + #endif + #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ + defined(__s390__) + #define __NR__socketcall __NR_socketcall + LSS_INLINE _syscall2(int, _socketcall, int, c, + va_list, a) + LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { + int rc; + va_list ap; + va_start(ap, op); + rc = LSS_NAME(_socketcall)(op, ap); + va_end(ap); + return rc; + } + + LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, + int flags){ + return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, + const struct kernel_msghdr *msg, + int flags) { + return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, + int flags, + const struct kernel_sockaddr *to, + unsigned int tolen) { + return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); + } + + LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { + return LSS_NAME(socketcall)(13, s, how); + } + + LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { + return LSS_NAME(socketcall)(1, domain, type, protocol); + } + + LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, + int sv[2]) { + return LSS_NAME(socketcall)(8, d, type, protocol, sv); + } + #endif + #if defined(__NR_fstatat64) + LSS_INLINE _syscall4(int, fstatat64, int, d, + const char *, p, + struct kernel_stat64 *, b, int, f) + #endif + #if defined(__NR_waitpid) + // waitpid is polyfilled below when not available. + LSS_INLINE _syscall3(pid_t, waitpid, pid_t, p, + int*, s, int, o) + #endif + #if defined(__mips__) + /* sys_pipe() on MIPS has non-standard calling conventions, as it returns + * both file handles through CPU registers. + */ + LSS_INLINE int LSS_NAME(pipe)(int *p) { + register unsigned long __v0 __asm__("$2") = __NR_pipe; + register unsigned long __v1 __asm__("$3"); + register unsigned long __r7 __asm__("$7"); + __asm__ __volatile__ ("syscall\n" + : "=r"(__v0), "=r"(__v1), "=r" (__r7) + : "0"(__v0) + : "$8", "$9", "$10", "$11", "$12", + "$13", "$14", "$15", "$24", "$25", "memory"); + if (__r7) { + unsigned long __errnovalue = __v0; + LSS_ERRNO = __errnovalue; + return -1; + } else { + p[0] = __v0; + p[1] = __v1; + return 0; + } + } + #elif defined(__NR_pipe) + // pipe is polyfilled below when not available. + LSS_INLINE _syscall1(int, pipe, int *, p) + #endif + #if defined(__NR_pipe2) + LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags) + #endif + /* TODO(csilvers): see if ppc can/should support this as well */ + #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ + defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) || \ + (defined(__s390__) && !defined(__s390x__)) + #define __NR__statfs64 __NR_statfs64 + #define __NR__fstatfs64 __NR_fstatfs64 + LSS_INLINE _syscall3(int, _statfs64, const char*, p, + size_t, s,struct kernel_statfs64*, b) + LSS_INLINE _syscall3(int, _fstatfs64, int, f, + size_t, s,struct kernel_statfs64*, b) + LSS_INLINE int LSS_NAME(statfs64)(const char *p, + struct kernel_statfs64 *b) { + return LSS_NAME(_statfs64)(p, sizeof(*b), b); + } + LSS_INLINE int LSS_NAME(fstatfs64)(int f,struct kernel_statfs64 *b) { + return LSS_NAME(_fstatfs64)(f, sizeof(*b), b); + } + #endif + + LSS_INLINE int LSS_NAME(execv)(const char *path, const char *const argv[]) { + extern char **environ; + return LSS_NAME(execve)(path, argv, (const char *const *)environ); + } + + LSS_INLINE pid_t LSS_NAME(gettid)(void) { + pid_t tid = LSS_NAME(_gettid)(); + if (tid != -1) { + return tid; + } + return LSS_NAME(getpid)(); + } + + LSS_INLINE void *LSS_NAME(mremap)(void *old_address, size_t old_size, + size_t new_size, int flags, ...) { + va_list ap; + void *new_address, *rc; + va_start(ap, flags); + new_address = va_arg(ap, void *); + rc = LSS_NAME(_mremap)(old_address, old_size, new_size, + flags, new_address); + va_end(ap); + return rc; + } + + LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) { + /* PTRACE_DETACH can sometimes forget to wake up the tracee and it + * then sends job control signals to the real parent, rather than to + * the tracer. We reduce the risk of this happening by starting a + * whole new time slice, and then quickly sending a SIGCONT signal + * right after detaching from the tracee. + * + * We use tkill to ensure that we only issue a wakeup for the thread being + * detached. Large multi threaded apps can take a long time in the kernel + * processing SIGCONT. + */ + int rc, err; + LSS_NAME(sched_yield)(); + rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); + err = LSS_ERRNO; + LSS_NAME(tkill)(pid, SIGCONT); + /* Old systems don't have tkill */ + if (LSS_ERRNO == ENOSYS) + LSS_NAME(kill)(pid, SIGCONT); + LSS_ERRNO = err; + return rc; + } + + LSS_INLINE int LSS_NAME(raise)(int sig) { + return LSS_NAME(kill)(LSS_NAME(getpid)(), sig); + } + + LSS_INLINE int LSS_NAME(setpgrp)(void) { + return LSS_NAME(setpgid)(0, 0); + } + + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE ssize_t LSS_NAME(pread64)(int f, void *b, size_t c, loff_t o) { + LSS_BODY(4, ssize_t, pread64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), + LSS_SYSCALL_ARG(c), (uint64_t)(o)); + } + + LSS_INLINE ssize_t LSS_NAME(pwrite64)(int f, const void *b, size_t c, + loff_t o) { + LSS_BODY(4, ssize_t, pwrite64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), + LSS_SYSCALL_ARG(c), (uint64_t)(o)); + } + + LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, unsigned c) { + LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o), + LSS_SYSCALL_ARG(c)); + } + #elif defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64 + LSS_INLINE _syscall4(ssize_t, pread64, int, f, + void *, b, size_t, c, + loff_t, o) + LSS_INLINE _syscall4(ssize_t, pwrite64, int, f, + const void *, b, size_t, c, + loff_t, o) + LSS_INLINE _syscall3(int, readahead, int, f, + loff_t, o, unsigned, c) + #else + #define __NR__pread64 __NR_pread64 + #define __NR__pwrite64 __NR_pwrite64 + #define __NR__readahead __NR_readahead + #if defined(__ARM_EABI__) || defined(__mips__) + /* On ARM and MIPS, a 64-bit parameter has to be in an even-odd register + * pair. Hence these calls ignore their fourth argument (r3) so that their + * fifth and sixth make such a pair (r4,r5). + */ + #define LSS_LLARG_PAD 0, + LSS_INLINE _syscall6(ssize_t, _pread64, int, f, + void *, b, size_t, c, + unsigned, skip, unsigned, o1, unsigned, o2) + LSS_INLINE _syscall6(ssize_t, _pwrite64, int, f, + const void *, b, size_t, c, + unsigned, skip, unsigned, o1, unsigned, o2) + LSS_INLINE _syscall5(int, _readahead, int, f, + unsigned, skip, + unsigned, o1, unsigned, o2, size_t, c) + #else + #define LSS_LLARG_PAD + LSS_INLINE _syscall5(ssize_t, _pread64, int, f, + void *, b, size_t, c, unsigned, o1, + unsigned, o2) + LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, + const void *, b, size_t, c, unsigned, o1, + long, o2) + LSS_INLINE _syscall4(int, _readahead, int, f, + unsigned, o1, unsigned, o2, size_t, c) + #endif + /* We force 64bit-wide parameters onto the stack, then access each + * 32-bit component individually. This guarantees that we build the + * correct parameters independent of the native byte-order of the + * underlying architecture. + */ + LSS_INLINE ssize_t LSS_NAME(pread64)(int fd, void *buf, size_t count, + loff_t off) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_pread64)(fd, buf, count, + LSS_LLARG_PAD o.arg[0], o.arg[1]); + } + LSS_INLINE ssize_t LSS_NAME(pwrite64)(int fd, const void *buf, + size_t count, loff_t off) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_pwrite64)(fd, buf, count, + LSS_LLARG_PAD o.arg[0], o.arg[1]); + } + LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len); + } + #endif +#endif + +/* + * Polyfills for deprecated syscalls. + */ + +#if !defined(__NR_dup2) + LSS_INLINE int LSS_NAME(dup2)(int s, int d) { + return LSS_NAME(dup3)(s, d, 0); + } +#endif + +#if !defined(__NR_open) + LSS_INLINE int LSS_NAME(open)(const char *pathname, int flags, int mode) { + return LSS_NAME(openat)(AT_FDCWD, pathname, flags, mode); + } +#endif + +#if !defined(__NR_unlink) + LSS_INLINE int LSS_NAME(unlink)(const char *pathname) { + return LSS_NAME(unlinkat)(AT_FDCWD, pathname, 0); + } +#endif + +#if !defined(__NR_readlink) + LSS_INLINE int LSS_NAME(readlink)(const char *pathname, char *buffer, + size_t size) { + return LSS_NAME(readlinkat)(AT_FDCWD, pathname, buffer, size); + } +#endif + +#if !defined(__NR_pipe) + LSS_INLINE int LSS_NAME(pipe)(int *pipefd) { + return LSS_NAME(pipe2)(pipefd, 0); + } +#endif + +#if !defined(__NR_poll) + LSS_INLINE int LSS_NAME(poll)(struct kernel_pollfd *fds, unsigned int nfds, + int timeout) { + struct kernel_timespec timeout_ts; + struct kernel_timespec *timeout_ts_p = NULL; + + if (timeout >= 0) { + timeout_ts.tv_sec = timeout / 1000; + timeout_ts.tv_nsec = (timeout % 1000) * 1000000; + timeout_ts_p = &timeout_ts; + } + return LSS_NAME(ppoll)(fds, nfds, timeout_ts_p, NULL, 0); + } +#endif + +#if !defined(__NR_stat) + LSS_INLINE int LSS_NAME(stat)(const char *pathname, + struct kernel_stat *buf) { + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + } +#endif + +#if !defined(__NR_waitpid) + LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options) { + return LSS_NAME(wait4)(pid, status, options, 0); + } +#endif + +#if !defined(__NR_fork) +// TODO: define this in an arch-independant way instead of inlining the clone +// syscall body. + +# if defined(__aarch64__) + LSS_INLINE pid_t LSS_NAME(fork)(void) { + // No fork syscall on aarch64 - implement by means of the clone syscall. + // Note that this does not reset glibc's cached view of the PID/TID, so + // some glibc interfaces might go wrong in the forked subprocess. + int flags = SIGCHLD; + void *child_stack = NULL; + void *parent_tidptr = NULL; + void *newtls = NULL; + void *child_tidptr = NULL; + + LSS_REG(0, flags); + LSS_REG(1, child_stack); + LSS_REG(2, parent_tidptr); + LSS_REG(3, newtls); + LSS_REG(4, child_tidptr); + LSS_BODY(pid_t, clone, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), + "r"(__r4)); + } +# elif defined(__x86_64__) + LSS_INLINE pid_t LSS_NAME(fork)(void) { + // Android disallows the fork syscall on x86_64 - implement by means of the + // clone syscall as above for aarch64. + int flags = SIGCHLD; + void *child_stack = NULL; + void *parent_tidptr = NULL; + void *newtls = NULL; + void *child_tidptr = NULL; + + LSS_BODY(5, pid_t, clone, LSS_SYSCALL_ARG(flags), + LSS_SYSCALL_ARG(child_stack), LSS_SYSCALL_ARG(parent_tidptr), + LSS_SYSCALL_ARG(newtls), LSS_SYSCALL_ARG(child_tidptr)); + } +# else +# error missing fork polyfill for this architecture +# endif +#endif + +/* These restore the original values of these macros saved by the + * corresponding #pragma push_macro near the top of this file. */ +#pragma pop_macro("stat64") +#pragma pop_macro("fstat64") +#pragma pop_macro("lstat64") +#pragma pop_macro("pread64") +#pragma pop_macro("pwrite64") +#pragma pop_macro("getdents64") + +#if defined(__cplusplus) && !defined(SYS_CPLUSPLUS) +} +#endif + +#elif defined(__FreeBSD__) + +#include +#include + +#define sys_readlink readlink + +#define sys_open open +#define sys_close close +#define sys_fstat fstat +#define sys_fstat64 fstat +#define kernel_stat stat +#define kernel_stat64 stat +#define sys_mmap mmap +#define sys_munmap munmap + +#endif + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/.gitignore b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/.gitignore new file mode 100644 index 0000000000..89c5d3c934 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/.gitignore @@ -0,0 +1,4 @@ +/*_test + +# Some tests create temp files. +/tempfile.* diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/Makefile b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/Makefile new file mode 100644 index 0000000000..5e37345f15 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/Makefile @@ -0,0 +1,131 @@ +# Copyright 2018, 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. + +top_srcdir ?= .. + +DEF_FLAGS = -g -pipe +DEF_WFLAGS = -Wall +CFLAGS ?= $(DEF_FLAGS) +CXXFLAGS ?= $(DEF_FLAGS) +CFLAGS += $(DEF_WFLAGS) -Wstrict-prototypes +CXXFLAGS += $(DEF_WFLAGS) +CPPFLAGS += -I$(top_srcdir) +# We use static linking here so that if people run through qemu/etc... by hand, +# it's a lot easier to run/debug. Same for strace output. +LDFLAGS += -static + +TESTS = \ + fallocate \ + sigtimedwait \ + unlink \ + +all: check + +%_test: %.c test_skel.h $(top_srcdir)/linux_syscall_support.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< + +%_test: %.cc test_skel.h $(top_srcdir)/linux_syscall_support.h + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< + +%_run: %_test + @t=$(@:_run=_test); \ + echo "./$$t"; \ + if ! env -i ./$$t; then \ + env -i strace -f -v ./$$t; \ + echo "TRY: gdb -q -ex r -ex bt ./$$t"; \ + exit 1; \ + fi + +ALL_TEST_TARGETS = $(TESTS:=_test) +compile_tests: $(ALL_TEST_TARGETS) + +ALL_RUN_TARGETS = $(TESTS:=_run) +check: $(ALL_RUN_TARGETS) + +# The "tempfile" targets are the names we use with temp files. +# Clean them out in case some tests crashed in the middle. +clean: + rm -f *~ *.o tempfile.* a.out core $(ALL_TEST_TARGETS) + +.SUFFIXES: +.PHONY: all check clean compile_tests +.SECONDARY: $(ALL_TEST_TARGETS) + +# Try to cross-compile the tests for all our supported arches. We test with +# both gcc and clang. We don't support execution (yet?), but just compiling +# & linking helps catch common bugs. +.PHONY: cross compile_cross +cross_compile: + @echo "Running: $(MAKE) $@ CC='$(CC)' CXX='$(CXX)'"; \ + if (echo '#include ' | $(CC) -x c -c -o /dev/null -) 2>/dev/null; then \ + $(MAKE) -s clean; \ + $(MAKE) -k --no-print-directory compile_tests; \ + else \ + echo "Skipping $(CC) test: not installed"; \ + fi; \ + echo + +# The names here are a best effort. Not easy to probe for. +cross: + @for cc in \ + "x86_64-pc-linux-gnu-gcc" \ + "i686-pc-linux-gnu-gcc" \ + "x86_64-pc-linux-gnu-gcc -mx32" \ + "armv7a-unknown-linux-gnueabi-gcc -marm -mhard-float" \ + "armv7a-unknown-linux-gnueabi-gcc -mthumb -mhard-float" \ + "powerpc-unknown-linux-gnu-gcc" \ + "aarch64-unknown-linux-gnu-gcc" \ + "mips64-unknown-linux-gnu-gcc -mabi=64" \ + "mips64-unknown-linux-gnu-gcc -mabi=32" \ + "mips64-unknown-linux-gnu-gcc -mabi=n32" \ + "s390-ibm-linux-gnu-gcc" \ + "s390x-ibm-linux-gnu-gcc" \ + ; do \ + cxx=`echo "$$cc" | sed 's:-gcc:-g++:'`; \ + $(MAKE) --no-print-directory CC="$$cc" CXX="$$cxx" cross_compile; \ + \ + sysroot=`$$cc --print-sysroot 2>/dev/null`; \ + gccdir=`$$cc -print-file-name=libgcc.a 2>/dev/null`; \ + gccdir=`dirname "$$gccdir"`; \ + : Skip building for clang for mips/o32 and s390/31-bit until it works.; \ + case $$cc in \ + mips64*-mabi=32) continue;; \ + s390-*) continue;; \ + esac; \ + set -- $$cc; \ + tuple=$${1%-gcc}; \ + shift; \ + cc="clang -target $$tuple $$*"; \ + : Assume the build system is x86_64 based, so ignore the sysroot.; \ + case $$tuple in \ + x86_64*) ;; \ + *) cc="$$cc --sysroot $$sysroot -B$$gccdir -L$$gccdir";; \ + esac; \ + cxx=`echo "$$cc" | sed 's:^clang:clang++:'`; \ + $(MAKE) --no-print-directory CC="$$cc" CXX="$$cxx" cross_compile; \ + done diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/README.md b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/README.md new file mode 100644 index 0000000000..45af3c37ed --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/README.md @@ -0,0 +1,52 @@ +# LSS Tests + +## Source Layout + +The general layout of the tests: +* [test_skel.h]: Test helpers for common checks/etc... +* xxx.c: Unittest for the xxx syscall (e.g. `open.c`). +* [Makefile]: New tests should be registered in the `TESTS` variable. + +## Test Guidelines + +The unittest itself generally follows the conventions: +* Written in C (unless a very specific language behavior is needed). +* You should only need to `#include "test_skel.h"`. For new system headers, try + to add them here rather than copying to exact unittest (if possible). + It might slow compilation down slightly, but makes the code easier to manage. + Make sure it is included first. +* Use `assert()` on everything to check return values. +* Use `sys_xxx()` to access the syscall via LSS (compared to `xxx()` which tends + to come from the C library). +* If you need a tempfile, use `tempfile.XXXXXX` for templates with helpers like + `mkstemp`. Try to clean them up when you're done with them. + These will be created in the cwd, but that's fine. +* Don't worry about trying to verify the kernel/C library API and various edge + cases. The goal of LSS is to make sure that we pass args along correctly to + the syscall only. +* Make sure to leave comments in the test so it's clear what behavior you're + trying to verify (and how). + +Feel free to extend [test_skel.h] with more helpers if they're useful to more +than one test. + +If you're looking for a simple example, start with [unlink.c](./unlink.c). +You should be able to copy this over and replace the content of `main()`. + +## Running The Tests + +Simply run `make`. This will compile & execute all the tests on your local +system. A standard `make clean` will clean up all the objects. + +If you need to debug something, then the programs are simply named `xxx_test` +and can easily be thrown into `gdb ./xxx_test`. + +We have rudimentary cross-compile testing via gcc and clang. Try running +`make cross` -- for any toolchains you don't have available, it should skip +things automatically. This only verifies the compilation & linking stages +though. + +The cross-compilers can be created using . + +[Makefile]: ./Makefile +[test_skel.h]: ./test_skel.h diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/fallocate.c b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/fallocate.c new file mode 100644 index 0000000000..c156e58986 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/fallocate.c @@ -0,0 +1,67 @@ +/* Copyright 2019, 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 "test_skel.h" + +int main(int argc, char *argv[]) { + int fd = 0, mode = 0; + loff_t offset = 0, len = 0; + + // Bad file descriptor. + fd = -1; + assert(sys_fallocate(fd, mode, offset, len) == -1); + assert(errno == EBADF); + + char filename[] = "tempfile.XXXXXX"; + fd = mkstemp(filename); + assert(fd >= 0); + + // Invalid len. + assert(sys_fallocate(fd, mode, offset, len) == -1); + assert(errno == EINVAL); + + // Small offset and length succeeds. + len = 4096; + assert(sys_fallocate(fd, mode, offset, len) == 0); + + // Large offset succeeds and isn't truncated. + offset = 1llu + UINT32_MAX; + assert(sys_fallocate(fd, mode , offset, len) == 0); + +#if defined(__NR_fstat64) + struct kernel_stat64 st; + assert(sys_fstat64(fd, &st) == 0); +#else + struct kernel_stat st; + assert(sys_fstat(fd, &st) == 0); +#endif + assert(st.st_size == offset + len); + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/sigtimedwait.c b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/sigtimedwait.c new file mode 100644 index 0000000000..ee2f740fe4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/sigtimedwait.c @@ -0,0 +1,58 @@ +/* Copyright 2019, 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 "test_skel.h" + +int main(int argc, char *argv[]) { + + struct kernel_sigset_t sigset = {}; + siginfo_t siginfo = {}; + struct timespec timeout = {}; + + // Invalid timeouts. + timeout.tv_sec = -1; + assert(sys_sigtimedwait(&sigset, &siginfo, &timeout) == -1); + assert(errno == EINVAL); + + // Expired timeouts. + timeout.tv_sec = 0; + assert(sys_sigtimedwait(&sigset, &siginfo, &timeout) == -1); + assert(errno == EAGAIN); + + // Success. + const int kTestSignal = SIGCONT; + assert(sys_sigemptyset(&sigset) == 0); + assert(sys_sigaddset(&sigset, kTestSignal) == 0); + assert(sys_sigprocmask(SIG_BLOCK, &sigset, NULL) == 0); + assert(raise(kTestSignal) == 0); + assert(sys_sigtimedwait(&sigset, &siginfo, &timeout) == kTestSignal); + assert(siginfo.si_signo == kTestSignal); + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/test_skel.h b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/test_skel.h new file mode 100644 index 0000000000..9ff0eb3711 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/test_skel.h @@ -0,0 +1,70 @@ +/* Copyright 2018, 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. + */ + +/* + * Make sure it's defined before including anything else. A number of syscalls + * are GNU extensions and rely on being exported by glibc. + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* + * Make sure the assert checks aren't removed as all the unittests are based + * on them. + */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "linux_syscall_support.h" + +void assert_buffers_eq_len(const void *buf1, const void *buf2, size_t len) { + const uint8_t *u8_1 = (const uint8_t *)buf1; + const uint8_t *u8_2 = (const uint8_t *)buf2; + size_t i; + + for (i = 0; i < len; ++i) { + if (u8_1[i] != u8_2[i]) + printf("offset %zu: %02x != %02x\n", i, u8_1[i], u8_2[i]); + } +} +#define assert_buffers_eq(obj1, obj2) assert_buffers_eq_len(obj1, obj2, sizeof(*obj1)) diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/unlink.c b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/unlink.c new file mode 100644 index 0000000000..70c8bc9a5e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/tests/unlink.c @@ -0,0 +1,48 @@ +/* Copyright 2018, 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 "test_skel.h" + +int main(int argc, char *argv[]) { + // Get a unique path to play with. + char foo[] = "tempfile.XXXXXX"; + int fd = mkstemp(foo); + assert(fd != -1); + + // Make sure it exists. + assert(access(foo, F_OK) == 0); + + // Then delete it. + assert(sys_unlink(foo) == 0); + + // Make sure it's gone. + assert(access(foo, F_OK) != 0); + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/README b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/README new file mode 100644 index 0000000000..c681bb3d65 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/README @@ -0,0 +1,2 @@ +These headers were copied from the Mac OS X 10.7 SDK to enable building +the Mac dump_syms code that processes Mach-O files on Linux. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/architecture/byte_order.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/architecture/byte_order.h new file mode 100644 index 0000000000..b772d9f38e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/architecture/byte_order.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1999-2008 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) 1992 NeXT Computer, Inc. + * + * Byte ordering conversion. + * + */ +/* This file mostly left blank */ + +#ifndef _ARCHITECTURE_BYTE_ORDER_H_ +#define _ARCHITECTURE_BYTE_ORDER_H_ + +/* + * Identify the byte order + * of the current host. + */ + +enum NXByteOrder { + NX_UnknownByteOrder, + NX_LittleEndian, + NX_BigEndian +}; + +#endif /* _ARCHITECTURE_BYTE_ORDER_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/i386/_types.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/i386/_types.h new file mode 100644 index 0000000000..2ed7fd6759 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/i386/_types.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +#ifndef _BSD_I386__TYPES_H_ +#define _BSD_I386__TYPES_H_ + +typedef long __darwin_intptr_t; +typedef unsigned int __darwin_natural_t; + +#endif /* _BSD_I386__TYPES_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/arch.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/arch.h new file mode 100644 index 0000000000..526c10fc84 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/arch.h @@ -0,0 +1,105 @@ +/* + * 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@ + */ +#ifndef _MACH_O_ARCH_H_ +#define _MACH_O_ARCH_H_ +/* + * Copyright (c) 1997 Apple Computer, Inc. + * + * Functions that deal with information about architectures. + * + */ + +#include +#include +#include + +/* The NXArchInfo structs contain the architectures symbolic name + * (such as "ppc"), its CPU type and CPU subtype as defined in + * mach/machine.h, the byte order for the architecture, and a + * describing string (such as "PowerPC"). + * There will both be entries for specific CPUs (such as ppc604e) as + * well as generic "family" entries (such as ppc). + */ +typedef struct { + const char *name; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + enum NXByteOrder byteorder; + const char *description; +} NXArchInfo; + +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* NXGetAllArchInfos() returns a pointer to an array of all known + * NXArchInfo structures. The last NXArchInfo is marked by a NULL name. + */ +extern const NXArchInfo *NXGetAllArchInfos(void); + +/* NXGetLocalArchInfo() returns the NXArchInfo for the local host, or NULL + * if none is known. + */ +extern const NXArchInfo *NXGetLocalArchInfo(void); + +/* NXGetArchInfoFromName() and NXGetArchInfoFromCpuType() return the + * NXArchInfo from the architecture's name or cputype/cpusubtype + * combination. A cpusubtype of CPU_SUBTYPE_MULTIPLE can be used + * to request the most general NXArchInfo known for the given cputype. + * NULL is returned if no matching NXArchInfo can be found. + */ +extern const NXArchInfo *NXGetArchInfoFromName(const char *name); +extern const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, + cpu_subtype_t cpusubtype); + +/* NXFindBestFatArch() is passed a cputype and cpusubtype and a set of + * fat_arch structs and selects the best one that matches (if any) and returns + * a pointer to that fat_arch struct (or NULL). The fat_arch structs must be + * in the host byte order and correct such that the fat_archs really points to + * enough memory for nfat_arch structs. It is possible that this routine could + * fail if new cputypes or cpusubtypes are added and an old version of this + * routine is used. But if there is an exact match between the cputype and + * cpusubtype and one of the fat_arch structs this routine will always succeed. + */ +extern struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, + cpu_subtype_t cpusubtype, + struct fat_arch *fat_archs, + uint32_t nfat_archs); + +/* NXCombineCpuSubtypes() returns the resulting cpusubtype when combining two + * different cpusubtypes for the specified cputype. If the two cpusubtypes + * can't be combined (the specific subtypes are mutually exclusive) -1 is + * returned indicating it is an error to combine them. This can also fail and + * return -1 if new cputypes or cpusubtypes are added and an old version of + * this routine is used. But if the cpusubtypes are the same they can always + * be combined and this routine will return the cpusubtype pass in. + */ +extern cpu_subtype_t NXCombineCpuSubtypes(cpu_type_t cputype, + cpu_subtype_t cpusubtype1, + cpu_subtype_t cpusubtype2); + +#if __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _MACH_O_ARCH_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/fat.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/fat.h new file mode 100644 index 0000000000..e2bcf433d5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/fat.h @@ -0,0 +1,64 @@ +/* + * 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@ + */ +#ifndef _MACH_O_FAT_H_ +#define _MACH_O_FAT_H_ +/* + * This header file describes the structures of the file format for "fat" + * architecture specific file (wrapper design). At the begining of the file + * there is one fat_header structure followed by a number of fat_arch + * structures. For each architecture in the file, specified by a pair of + * cputype and cpusubtype, the fat_header describes the file offset, file + * size and alignment in the file of the architecture specific member. + * The padded bytes in the file to place each member on it's specific alignment + * are defined to be read as zeros and can be left as "holes" if the file system + * can support them as long as they read as zeros. + * + * All structures defined here are always written and read to/from disk + * in big-endian order. + */ + +/* + * is needed here for the cpu_type_t and cpu_subtype_t types + * and contains the constants for the possible values of these types. + */ +#include +#include +#include + +#define FAT_MAGIC 0xcafebabe +#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */ + +struct fat_header { + uint32_t magic; /* FAT_MAGIC */ + uint32_t nfat_arch; /* number of structs that follow */ +}; + +struct fat_arch { + cpu_type_t cputype; /* cpu specifier (int) */ + cpu_subtype_t cpusubtype; /* machine specifier (int) */ + uint32_t offset; /* file offset to this object file */ + uint32_t size; /* size of this object file */ + uint32_t align; /* alignment as a power of 2 */ +}; + +#endif /* _MACH_O_FAT_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/loader.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/loader.h new file mode 100644 index 0000000000..ff18e29c73 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/loader.h @@ -0,0 +1,1402 @@ +/* + * Copyright (c) 1999-2010 Apple 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@ + */ +#ifndef _MACHO_LOADER_H_ +#define _MACHO_LOADER_H_ + +/* + * This file describes the format of mach object files. + */ +#include + +/* + * is needed here for the cpu_type_t and cpu_subtype_t types + * and contains the constants for the possible values of these types. + */ +#include + +/* + * is needed here for the vm_prot_t type and contains the + * constants that are or'ed together for the possible values of this type. + */ +#include + +/* + * is expected to define the flavors of the thread + * states and the structures of those flavors for each machine. + */ +#include +#include + +/* + * The 32-bit mach header appears at the very beginning of the object file for + * 32-bit architectures. + */ +struct mach_header { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ +}; + +/* Constant for the magic field of the mach_header (32-bit architectures) */ +#define MH_MAGIC 0xfeedface /* the mach magic number */ +#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ + +/* + * The 64-bit mach header appears at the very beginning of object files for + * 64-bit architectures. + */ +struct mach_header_64 { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ + uint32_t reserved; /* reserved */ +}; + +/* Constant for the magic field of the mach_header_64 (64-bit architectures) */ +#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ +#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ + +/* + * The layout of the file depends on the filetype. For all but the MH_OBJECT + * file type the segments are padded out and aligned on a segment alignment + * boundary for efficient demand pageing. The MH_EXECUTE, MH_FVMLIB, MH_DYLIB, + * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part + * of their first segment. + * + * The file type MH_OBJECT is a compact format intended as output of the + * assembler and input (and possibly output) of the link editor (the .o + * format). All sections are in one unnamed segment with no segment padding. + * This format is used as an executable format when the file is so small the + * segment padding greatly increases its size. + * + * The file type MH_PRELOAD is an executable format intended for things that + * are not executed under the kernel (proms, stand alones, kernels, etc). The + * format can be executed under the kernel but may demand paged it and not + * preload it before execution. + * + * A core file is in MH_CORE format and can be any in an arbritray legal + * Mach-O file. + * + * Constants for the filetype field of the mach_header + */ +#define MH_OBJECT 0x1 /* relocatable object file */ +#define MH_EXECUTE 0x2 /* demand paged executable file */ +#define MH_FVMLIB 0x3 /* fixed VM shared library file */ +#define MH_CORE 0x4 /* core file */ +#define MH_PRELOAD 0x5 /* preloaded executable file */ +#define MH_DYLIB 0x6 /* dynamically bound shared library */ +#define MH_DYLINKER 0x7 /* dynamic link editor */ +#define MH_BUNDLE 0x8 /* dynamically bound bundle file */ +#define MH_DYLIB_STUB 0x9 /* shared library stub for static */ + /* linking only, no section contents */ +#define MH_DSYM 0xa /* companion file with only debug */ + /* sections */ +#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */ + +/* Constants for the flags field of the mach_header */ +#define MH_NOUNDEFS 0x1 /* the object file has no undefined + references */ +#define MH_INCRLINK 0x2 /* the object file is the output of an + incremental link against a base file + and can't be link edited again */ +#define MH_DYLDLINK 0x4 /* the object file is input for the + dynamic linker and can't be staticly + link edited again */ +#define MH_BINDATLOAD 0x8 /* the object file's undefined + references are bound by the dynamic + linker when loaded. */ +#define MH_PREBOUND 0x10 /* the file has its dynamic undefined + references prebound. */ +#define MH_SPLIT_SEGS 0x20 /* the file has its read-only and + read-write segments split */ +#define MH_LAZY_INIT 0x40 /* the shared library init routine is + to be run lazily via catching memory + faults to its writeable segments + (obsolete) */ +#define MH_TWOLEVEL 0x80 /* the image is using two-level name + space bindings */ +#define MH_FORCE_FLAT 0x100 /* the executable is forcing all images + to use flat name space bindings */ +#define MH_NOMULTIDEFS 0x200 /* this umbrella guarantees no multiple + defintions of symbols in its + sub-images so the two-level namespace + hints can always be used. */ +#define MH_NOFIXPREBINDING 0x400 /* do not have dyld notify the + prebinding agent about this + executable */ +#define MH_PREBINDABLE 0x800 /* the binary is not prebound but can + have its prebinding redone. only used + when MH_PREBOUND is not set. */ +#define MH_ALLMODSBOUND 0x1000 /* indicates that this binary binds to + all two-level namespace modules of + its dependent libraries. only used + when MH_PREBINDABLE and MH_TWOLEVEL + are both set. */ +#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000/* safe to divide up the sections into + sub-sections via symbols for dead + code stripping */ +#define MH_CANONICAL 0x4000 /* the binary has been canonicalized + via the unprebind operation */ +#define MH_WEAK_DEFINES 0x8000 /* the final linked image contains + external weak symbols */ +#define MH_BINDS_TO_WEAK 0x10000 /* the final linked image uses + weak symbols */ + +#define MH_ALLOW_STACK_EXECUTION 0x20000/* When this bit is set, all stacks + in the task will be given stack + execution privilege. Only used in + MH_EXECUTE filetypes. */ +#define MH_ROOT_SAFE 0x40000 /* When this bit is set, the binary + declares it is safe for use in + processes with uid zero */ + +#define MH_SETUID_SAFE 0x80000 /* When this bit is set, the binary + declares it is safe for use in + processes when issetugid() is true */ + +#define MH_NO_REEXPORTED_DYLIBS 0x100000 /* When this bit is set on a dylib, + the static linker does not need to + examine dependent dylibs to see + if any are re-exported */ +#define MH_PIE 0x200000 /* When this bit is set, the OS will + load the main executable at a + random address. Only used in + MH_EXECUTE filetypes. */ +#define MH_DEAD_STRIPPABLE_DYLIB 0x400000 /* Only for use on dylibs. When + linking against a dylib that + has this bit set, the static linker + will automatically not create a + LC_LOAD_DYLIB load command to the + dylib if no symbols are being + referenced from the dylib. */ +#define MH_HAS_TLV_DESCRIPTORS 0x800000 /* Contains a section of type + S_THREAD_LOCAL_VARIABLES */ + +#define MH_NO_HEAP_EXECUTION 0x1000000 /* When this bit is set, the OS will + run the main executable with + a non-executable heap even on + platforms (e.g. i386) that don't + require it. Only used in MH_EXECUTE + filetypes. */ + +/* + * The load commands directly follow the mach_header. The total size of all + * of the commands is given by the sizeofcmds field in the mach_header. All + * load commands must have as their first two fields cmd and cmdsize. The cmd + * field is filled in with a constant for that command type. Each command type + * has a structure specifically for it. The cmdsize field is the size in bytes + * of the particular load command structure plus anything that follows it that + * is a part of the load command (i.e. section structures, strings, etc.). To + * advance to the next load command the cmdsize can be added to the offset or + * pointer of the current load command. The cmdsize for 32-bit architectures + * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple + * of 8 bytes (these are forever the maximum alignment of any load commands). + * The padded bytes must be zero. All tables in the object file must also + * follow these rules so the file can be memory mapped. Otherwise the pointers + * to these tables will not work well or at all on some machines. With all + * padding zeroed like objects will compare byte for byte. + */ +struct load_command { + uint32_t cmd; /* type of load command */ + uint32_t cmdsize; /* total size of command in bytes */ +}; + +/* + * After MacOS X 10.1 when a new load command is added that is required to be + * understood by the dynamic linker for the image to execute properly the + * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic + * linker sees such a load command it it does not understand will issue a + * "unknown load command required for execution" error and refuse to use the + * image. Other load commands without this bit that are not understood will + * simply be ignored. + */ +#define LC_REQ_DYLD 0x80000000 + +/* Constants for the cmd field of all load commands, the type */ +#define LC_SEGMENT 0x1 /* segment of this file to be mapped */ +#define LC_SYMTAB 0x2 /* link-edit stab symbol table info */ +#define LC_SYMSEG 0x3 /* link-edit gdb symbol table info (obsolete) */ +#define LC_THREAD 0x4 /* thread */ +#define LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */ +#define LC_LOADFVMLIB 0x6 /* load a specified fixed VM shared library */ +#define LC_IDFVMLIB 0x7 /* fixed VM shared library identification */ +#define LC_IDENT 0x8 /* object identification info (obsolete) */ +#define LC_FVMFILE 0x9 /* fixed VM file inclusion (internal use) */ +#define LC_PREPAGE 0xa /* prepage command (internal use) */ +#define LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */ +#define LC_LOAD_DYLIB 0xc /* load a dynamically linked shared library */ +#define LC_ID_DYLIB 0xd /* dynamically linked shared lib ident */ +#define LC_LOAD_DYLINKER 0xe /* load a dynamic linker */ +#define LC_ID_DYLINKER 0xf /* dynamic linker identification */ +#define LC_PREBOUND_DYLIB 0x10 /* modules prebound for a dynamically */ + /* linked shared library */ +#define LC_ROUTINES 0x11 /* image routines */ +#define LC_SUB_FRAMEWORK 0x12 /* sub framework */ +#define LC_SUB_UMBRELLA 0x13 /* sub umbrella */ +#define LC_SUB_CLIENT 0x14 /* sub client */ +#define LC_SUB_LIBRARY 0x15 /* sub library */ +#define LC_TWOLEVEL_HINTS 0x16 /* two-level namespace lookup hints */ +#define LC_PREBIND_CKSUM 0x17 /* prebind checksum */ + +/* + * load a dynamically linked shared library that is allowed to be missing + * (all symbols are weak imported). + */ +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) + +#define LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be + mapped */ +#define LC_ROUTINES_64 0x1a /* 64-bit image routines */ +#define LC_UUID 0x1b /* the uuid */ +#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ +#define LC_CODE_SIGNATURE 0x1d /* local of code signature */ +#define LC_SEGMENT_SPLIT_INFO 0x1e /* local of info to split segments */ +#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */ +#define LC_LAZY_LOAD_DYLIB 0x20 /* delay load of dylib until first use */ +#define LC_ENCRYPTION_INFO 0x21 /* encrypted segment information */ +#define LC_DYLD_INFO 0x22 /* compressed dyld information */ +#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) /* compressed dyld information only */ +#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */ +#define LC_VERSION_MIN_MACOSX 0x24 /* build for MacOSX min OS version */ +#define LC_VERSION_MIN_IPHONEOS 0x25 /* build for iPhoneOS min OS version */ +#define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */ +#define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat + like environment variable */ + +/* + * A variable length string in a load command is represented by an lc_str + * union. The strings are stored just after the load command structure and + * the offset is from the start of the load command structure. The size + * of the string is reflected in the cmdsize field of the load command. + * Once again any padded bytes to bring the cmdsize field to a multiple + * of 4 bytes must be zero. + */ +union lc_str { + uint32_t offset; /* offset to the string */ +#ifndef __LP64__ + char *ptr; /* pointer to the string */ +#endif +}; + +/* + * The segment load command indicates that a part of this file is to be + * mapped into the task's address space. The size of this segment in memory, + * vmsize, maybe equal to or larger than the amount to map from this file, + * filesize. The file is mapped starting at fileoff to the beginning of + * the segment in memory, vmaddr. The rest of the memory of the segment, + * if any, is allocated zero fill on demand. The segment's maximum virtual + * memory protection and initial virtual memory protection are specified + * by the maxprot and initprot fields. If the segment has sections then the + * section structures directly follow the segment command and their size is + * reflected in cmdsize. + */ +struct segment_command { /* for 32-bit architectures */ + uint32_t cmd; /* LC_SEGMENT */ + uint32_t cmdsize; /* includes sizeof section structs */ + char segname[16]; /* segment name */ + uint32_t vmaddr; /* memory address of this segment */ + uint32_t vmsize; /* memory size of this segment */ + uint32_t fileoff; /* file offset of this segment */ + uint32_t filesize; /* amount to map from the file */ + vm_prot_t maxprot; /* maximum VM protection */ + vm_prot_t initprot; /* initial VM protection */ + uint32_t nsects; /* number of sections in segment */ + uint32_t flags; /* flags */ +}; + +/* + * The 64-bit segment load command indicates that a part of this file is to be + * mapped into a 64-bit task's address space. If the 64-bit segment has + * sections then section_64 structures directly follow the 64-bit segment + * command and their size is reflected in cmdsize. + */ +struct segment_command_64 { /* for 64-bit architectures */ + uint32_t cmd; /* LC_SEGMENT_64 */ + uint32_t cmdsize; /* includes sizeof section_64 structs */ + char segname[16]; /* segment name */ + uint64_t vmaddr; /* memory address of this segment */ + uint64_t vmsize; /* memory size of this segment */ + uint64_t fileoff; /* file offset of this segment */ + uint64_t filesize; /* amount to map from the file */ + vm_prot_t maxprot; /* maximum VM protection */ + vm_prot_t initprot; /* initial VM protection */ + uint32_t nsects; /* number of sections in segment */ + uint32_t flags; /* flags */ +}; + +/* Constants for the flags field of the segment_command */ +#define SG_HIGHVM 0x1 /* the file contents for this segment is for + the high part of the VM space, the low part + is zero filled (for stacks in core files) */ +#define SG_FVMLIB 0x2 /* this segment is the VM that is allocated by + a fixed VM library, for overlap checking in + the link editor */ +#define SG_NORELOC 0x4 /* this segment has nothing that was relocated + in it and nothing relocated to it, that is + it maybe safely replaced without relocation*/ +#define SG_PROTECTED_VERSION_1 0x8 /* This segment is protected. If the + segment starts at file offset 0, the + first page of the segment is not + protected. All other pages of the + segment are protected. */ + +/* + * A segment is made up of zero or more sections. Non-MH_OBJECT files have + * all of their segments with the proper sections in each, and padded to the + * specified segment alignment when produced by the link editor. The first + * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header + * and load commands of the object file before its first section. The zero + * fill sections are always last in their segment (in all formats). This + * allows the zeroed segment padding to be mapped into memory where zero fill + * sections might be. The gigabyte zero fill sections, those with the section + * type S_GB_ZEROFILL, can only be in a segment with sections of this type. + * These segments are then placed after all other segments. + * + * The MH_OBJECT format has all of its sections in one segment for + * compactness. There is no padding to a specified segment boundary and the + * mach_header and load commands are not part of the segment. + * + * Sections with the same section name, sectname, going into the same segment, + * segname, are combined by the link editor. The resulting section is aligned + * to the maximum alignment of the combined sections and is the new section's + * alignment. The combined sections are aligned to their original alignment in + * the combined section. Any padded bytes to get the specified alignment are + * zeroed. + * + * The format of the relocation entries referenced by the reloff and nreloc + * fields of the section structure for mach object files is described in the + * header file . + */ +struct section { /* for 32-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + uint32_t addr; /* memory address of this section */ + uint32_t size; /* size in bytes of this section */ + uint32_t offset; /* file offset of this section */ + uint32_t align; /* section alignment (power of 2) */ + uint32_t reloff; /* file offset of relocation entries */ + uint32_t nreloc; /* number of relocation entries */ + uint32_t flags; /* flags (section type and attributes)*/ + uint32_t reserved1; /* reserved (for offset or index) */ + uint32_t reserved2; /* reserved (for count or sizeof) */ +}; + +struct section_64 { /* for 64-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + uint64_t addr; /* memory address of this section */ + uint64_t size; /* size in bytes of this section */ + uint32_t offset; /* file offset of this section */ + uint32_t align; /* section alignment (power of 2) */ + uint32_t reloff; /* file offset of relocation entries */ + uint32_t nreloc; /* number of relocation entries */ + uint32_t flags; /* flags (section type and attributes)*/ + uint32_t reserved1; /* reserved (for offset or index) */ + uint32_t reserved2; /* reserved (for count or sizeof) */ + uint32_t reserved3; /* reserved */ +}; + +/* + * The flags field of a section structure is separated into two parts a section + * type and section attributes. The section types are mutually exclusive (it + * can only have one type) but the section attributes are not (it may have more + * than one attribute). + */ +#define SECTION_TYPE 0x000000ff /* 256 section types */ +#define SECTION_ATTRIBUTES 0xffffff00 /* 24 section attributes */ + +/* Constants for the type of a section */ +#define S_REGULAR 0x0 /* regular section */ +#define S_ZEROFILL 0x1 /* zero fill on demand section */ +#define S_CSTRING_LITERALS 0x2 /* section with only literal C strings*/ +#define S_4BYTE_LITERALS 0x3 /* section with only 4 byte literals */ +#define S_8BYTE_LITERALS 0x4 /* section with only 8 byte literals */ +#define S_LITERAL_POINTERS 0x5 /* section with only pointers to */ + /* literals */ +/* + * For the two types of symbol pointers sections and the symbol stubs section + * they have indirect symbol table entries. For each of the entries in the + * section the indirect symbol table entries, in corresponding order in the + * indirect symbol table, start at the index stored in the reserved1 field + * of the section structure. Since the indirect symbol table entries + * correspond to the entries in the section the number of indirect symbol table + * entries is inferred from the size of the section divided by the size of the + * entries in the section. For symbol pointers sections the size of the entries + * in the section is 4 bytes and for symbol stubs sections the byte size of the + * stubs is stored in the reserved2 field of the section structure. + */ +#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* section with only non-lazy + symbol pointers */ +#define S_LAZY_SYMBOL_POINTERS 0x7 /* section with only lazy symbol + pointers */ +#define S_SYMBOL_STUBS 0x8 /* section with only symbol + stubs, byte size of stub in + the reserved2 field */ +#define S_MOD_INIT_FUNC_POINTERS 0x9 /* section with only function + pointers for initialization*/ +#define S_MOD_TERM_FUNC_POINTERS 0xa /* section with only function + pointers for termination */ +#define S_COALESCED 0xb /* section contains symbols that + are to be coalesced */ +#define S_GB_ZEROFILL 0xc /* zero fill on demand section + (that can be larger than 4 + gigabytes) */ +#define S_INTERPOSING 0xd /* section with only pairs of + function pointers for + interposing */ +#define S_16BYTE_LITERALS 0xe /* section with only 16 byte + literals */ +#define S_DTRACE_DOF 0xf /* section contains + DTrace Object Format */ +#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 /* section with only lazy + symbol pointers to lazy + loaded dylibs */ +/* + * Section types to support thread local variables + */ +#define S_THREAD_LOCAL_REGULAR 0x11 /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_ZEROFILL 0x12 /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_VARIABLES 0x13 /* TLV descriptors */ +#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 /* pointers to TLV + descriptors */ +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 /* functions to call + to initialize TLV + values */ + +/* + * Constants for the section attributes part of the flags field of a section + * structure. + */ +#define SECTION_ATTRIBUTES_USR 0xff000000 /* User setable attributes */ +#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 /* section contains only true + machine instructions */ +#define S_ATTR_NO_TOC 0x40000000 /* section contains coalesced + symbols that are not to be + in a ranlib table of + contents */ +#define S_ATTR_STRIP_STATIC_SYMS 0x20000000 /* ok to strip static symbols + in this section in files + with the MH_DYLDLINK flag */ +#define S_ATTR_NO_DEAD_STRIP 0x10000000 /* no dead stripping */ +#define S_ATTR_LIVE_SUPPORT 0x08000000 /* blocks are live if they + reference live blocks */ +#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 /* Used with i386 code stubs + written on by dyld */ +/* + * If a segment contains any sections marked with S_ATTR_DEBUG then all + * sections in that segment must have this attribute. No section other than + * a section marked with this attribute may reference the contents of this + * section. A section with this attribute may contain no symbols and must have + * a section type S_REGULAR. The static linker will not copy section contents + * from sections with this attribute into its output file. These sections + * generally contain DWARF debugging info. + */ +#define S_ATTR_DEBUG 0x02000000 /* a debug section */ +#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */ +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some + machine instructions */ +#define S_ATTR_EXT_RELOC 0x00000200 /* section has external + relocation entries */ +#define S_ATTR_LOC_RELOC 0x00000100 /* section has local + relocation entries */ + + +/* + * The names of segments and sections in them are mostly meaningless to the + * link-editor. But there are few things to support traditional UNIX + * executables that require the link-editor and assembler to use some names + * agreed upon by convention. + * + * The initial protection of the "__TEXT" segment has write protection turned + * off (not writeable). + * + * The link-editor will allocate common symbols at the end of the "__common" + * section in the "__DATA" segment. It will create the section and segment + * if needed. + */ + +/* The currently known segment names and the section names in those segments */ + +#define SEG_PAGEZERO "__PAGEZERO" /* the pagezero segment which has no */ + /* protections and catches NULL */ + /* references for MH_EXECUTE files */ + + +#define SEG_TEXT "__TEXT" /* the tradition UNIX text segment */ +#define SECT_TEXT "__text" /* the real text part of the text */ + /* section no headers, and no padding */ +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" /* the fvmlib initialization */ + /* section */ +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" /* the section following the */ + /* fvmlib initialization */ + /* section */ + +#define SEG_DATA "__DATA" /* the tradition UNIX data segment */ +#define SECT_DATA "__data" /* the real initialized data section */ + /* no padding, no bss overlap */ +#define SECT_BSS "__bss" /* the real uninitialized data section*/ + /* no padding */ +#define SECT_COMMON "__common" /* the section common symbols are */ + /* allocated in by the link editor */ + +#define SEG_OBJC "__OBJC" /* objective-C runtime segment */ +#define SECT_OBJC_SYMBOLS "__symbol_table" /* symbol table */ +#define SECT_OBJC_MODULES "__module_info" /* module information */ +#define SECT_OBJC_STRINGS "__selector_strs" /* string table */ +#define SECT_OBJC_REFS "__selector_refs" /* string table */ + +#define SEG_ICON "__ICON" /* the icon segment */ +#define SECT_ICON_HEADER "__header" /* the icon headers */ +#define SECT_ICON_TIFF "__tiff" /* the icons in tiff format */ + +#define SEG_LINKEDIT "__LINKEDIT" /* the segment containing all structs */ + /* created and maintained by the link */ + /* editor. Created with -seglinkedit */ + /* option to ld(1) for MH_EXECUTE and */ + /* FVMLIB file types only */ + +#define SEG_UNIXSTACK "__UNIXSTACK" /* the unix stack segment */ + +#define SEG_IMPORT "__IMPORT" /* the segment for the self (dyld) */ + /* modifing code stubs that has read, */ + /* write and execute permissions */ + +/* + * Fixed virtual memory shared libraries are identified by two things. The + * target pathname (the name of the library as found for execution), and the + * minor version number. The address of where the headers are loaded is in + * header_addr. (THIS IS OBSOLETE and no longer supported). + */ +struct fvmlib { + union lc_str name; /* library's target pathname */ + uint32_t minor_version; /* library's minor version number */ + uint32_t header_addr; /* library's header address */ +}; + +/* + * A fixed virtual shared library (filetype == MH_FVMLIB in the mach header) + * contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library. + * An object that uses a fixed virtual shared library also contains a + * fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses. + * (THIS IS OBSOLETE and no longer supported). + */ +struct fvmlib_command { + uint32_t cmd; /* LC_IDFVMLIB or LC_LOADFVMLIB */ + uint32_t cmdsize; /* includes pathname string */ + struct fvmlib fvmlib; /* the library identification */ +}; + +/* + * Dynamicly linked shared libraries are identified by two things. The + * pathname (the name of the library as found for execution), and the + * compatibility version number. The pathname must match and the compatibility + * number in the user of the library must be greater than or equal to the + * library being used. The time stamp is used to record the time a library was + * built and copied into user so it can be use to determined if the library used + * at runtime is exactly the same as used to built the program. + */ +struct dylib { + union lc_str name; /* library's path name */ + uint32_t timestamp; /* library's build time stamp */ + uint32_t current_version; /* library's current version number */ + uint32_t compatibility_version; /* library's compatibility vers number*/ +}; + +/* + * A dynamically linked shared library (filetype == MH_DYLIB in the mach header) + * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library. + * An object that uses a dynamically linked shared library also contains a + * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or + * LC_REEXPORT_DYLIB) for each library it uses. + */ +struct dylib_command { + uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, + LC_REEXPORT_DYLIB */ + uint32_t cmdsize; /* includes pathname string */ + struct dylib dylib; /* the library identification */ +}; + +/* + * A dynamically linked shared library may be a subframework of an umbrella + * framework. If so it will be linked with "-umbrella umbrella_name" where + * Where "umbrella_name" is the name of the umbrella framework. A subframework + * can only be linked against by its umbrella framework or other subframeworks + * that are part of the same umbrella framework. Otherwise the static link + * editor produces an error and states to link against the umbrella framework. + * The name of the umbrella framework for subframeworks is recorded in the + * following structure. + */ +struct sub_framework_command { + uint32_t cmd; /* LC_SUB_FRAMEWORK */ + uint32_t cmdsize; /* includes umbrella string */ + union lc_str umbrella; /* the umbrella framework name */ +}; + +/* + * For dynamically linked shared libraries that are subframework of an umbrella + * framework they can allow clients other than the umbrella framework or other + * subframeworks in the same umbrella framework. To do this the subframework + * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load + * command is created for each -allowable_client flag. The client_name is + * usually a framework name. It can also be a name used for bundles clients + * where the bundle is built with "-client_name client_name". + */ +struct sub_client_command { + uint32_t cmd; /* LC_SUB_CLIENT */ + uint32_t cmdsize; /* includes client string */ + union lc_str client; /* the client name */ +}; + +/* + * A dynamically linked shared library may be a sub_umbrella of an umbrella + * framework. If so it will be linked with "-sub_umbrella umbrella_name" where + * Where "umbrella_name" is the name of the sub_umbrella framework. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * umbrella framework will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks to be implicited linked in. Any other + * dependent dynamic libraries will not be linked it when -twolevel_namespace + * is in effect. The primary library recorded by the static linker when + * resolving a symbol in these libraries will be the umbrella framework. + * Zero or more sub_umbrella frameworks may be use by an umbrella framework. + * The name of a sub_umbrella framework is recorded in the following structure. + */ +struct sub_umbrella_command { + uint32_t cmd; /* LC_SUB_UMBRELLA */ + uint32_t cmdsize; /* includes sub_umbrella string */ + union lc_str sub_umbrella; /* the sub_umbrella framework name */ +}; + +/* + * A dynamically linked shared library may be a sub_library of another shared + * library. If so it will be linked with "-sub_library library_name" where + * Where "library_name" is the name of the sub_library shared library. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * shared library will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks and libraries listed as sub_libraries to + * be implicited linked in. Any other dependent dynamic libraries will not be + * linked it when -twolevel_namespace is in effect. The primary library + * recorded by the static linker when resolving a symbol in these libraries + * will be the umbrella framework (or dynamic library). Zero or more sub_library + * shared libraries may be use by an umbrella framework or (or dynamic library). + * The name of a sub_library framework is recorded in the following structure. + * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc". + */ +struct sub_library_command { + uint32_t cmd; /* LC_SUB_LIBRARY */ + uint32_t cmdsize; /* includes sub_library string */ + union lc_str sub_library; /* the sub_library name */ +}; + +/* + * A program (filetype == MH_EXECUTE) that is + * prebound to its dynamic libraries has one of these for each library that + * the static linker used in prebinding. It contains a bit vector for the + * modules in the library. The bits indicate which modules are bound (1) and + * which are not (0) from the library. The bit for module 0 is the low bit + * of the first byte. So the bit for the Nth module is: + * (linked_modules[N/8] >> N%8) & 1 + */ +struct prebound_dylib_command { + uint32_t cmd; /* LC_PREBOUND_DYLIB */ + uint32_t cmdsize; /* includes strings */ + union lc_str name; /* library's path name */ + uint32_t nmodules; /* number of modules in library */ + union lc_str linked_modules; /* bit vector of linked modules */ +}; + +/* + * A program that uses a dynamic linker contains a dylinker_command to identify + * the name of the dynamic linker (LC_LOAD_DYLINKER). And a dynamic linker + * contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER). + * A file can have at most one of these. + * This struct is also used for the LC_DYLD_ENVIRONMENT load command and + * contains string for dyld to treat like environment variable. + */ +struct dylinker_command { + uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or + LC_DYLD_ENVIRONMENT */ + uint32_t cmdsize; /* includes pathname string */ + union lc_str name; /* dynamic linker's path name */ +}; + +/* + * Thread commands contain machine-specific data structures suitable for + * use in the thread state primitives. The machine specific data structures + * follow the struct thread_command as follows. + * Each flavor of machine specific data structure is preceded by an unsigned + * long constant for the flavor of that data structure, an uint32_t + * that is the count of longs of the size of the state data structure and then + * the state data structure follows. This triple may be repeated for many + * flavors. The constants for the flavors, counts and state data structure + * definitions are expected to be in the header file . + * These machine specific data structures sizes must be multiples of + * 4 bytes The cmdsize reflects the total size of the thread_command + * and all of the sizes of the constants for the flavors, counts and state + * data structures. + * + * For executable objects that are unix processes there will be one + * thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor. + * This is the same as a LC_THREAD, except that a stack is automatically + * created (based on the shell's limit for the stack size). Command arguments + * and environment variables are copied onto that stack. + */ +struct thread_command { + uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */ + uint32_t cmdsize; /* total size of this command */ + /* uint32_t flavor flavor of thread state */ + /* uint32_t count count of longs in thread state */ + /* struct XXX_thread_state state thread state for this flavor */ + /* ... */ +}; + +/* + * The routines command contains the address of the dynamic shared library + * initialization routine and an index into the module table for the module + * that defines the routine. Before any modules are used from the library the + * dynamic linker fully binds the module that defines the initialization routine + * and then calls it. This gets called before any module initialization + * routines (used for C++ static constructors) in the library. + */ +struct routines_command { /* for 32-bit architectures */ + uint32_t cmd; /* LC_ROUTINES */ + uint32_t cmdsize; /* total size of this command */ + uint32_t init_address; /* address of initialization routine */ + uint32_t init_module; /* index into the module table that */ + /* the init routine is defined in */ + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + uint32_t reserved6; +}; + +/* + * The 64-bit routines command. Same use as above. + */ +struct routines_command_64 { /* for 64-bit architectures */ + uint32_t cmd; /* LC_ROUTINES_64 */ + uint32_t cmdsize; /* total size of this command */ + uint64_t init_address; /* address of initialization routine */ + uint64_t init_module; /* index into the module table that */ + /* the init routine is defined in */ + uint64_t reserved1; + uint64_t reserved2; + uint64_t reserved3; + uint64_t reserved4; + uint64_t reserved5; + uint64_t reserved6; +}; + +/* + * The symtab_command contains the offsets and sizes of the link-edit 4.3BSD + * "stab" style symbol table information as described in the header files + * and . + */ +struct symtab_command { + uint32_t cmd; /* LC_SYMTAB */ + uint32_t cmdsize; /* sizeof(struct symtab_command) */ + uint32_t symoff; /* symbol table offset */ + uint32_t nsyms; /* number of symbol table entries */ + uint32_t stroff; /* string table offset */ + uint32_t strsize; /* string table size in bytes */ +}; + +/* + * This is the second set of the symbolic information which is used to support + * the data structures for the dynamically link editor. + * + * The original set of symbolic information in the symtab_command which contains + * the symbol and string tables must also be present when this load command is + * present. When this load command is present the symbol table is organized + * into three groups of symbols: + * local symbols (static and debugging symbols) - grouped by module + * defined external symbols - grouped by module (sorted by name if not lib) + * undefined external symbols (sorted by name if MH_BINDATLOAD is not set, + * and in order the were seen by the static + * linker if MH_BINDATLOAD is set) + * In this load command there are offsets and counts to each of the three groups + * of symbols. + * + * This load command contains a the offsets and sizes of the following new + * symbolic information tables: + * table of contents + * module table + * reference symbol table + * indirect symbol table + * The first three tables above (the table of contents, module table and + * reference symbol table) are only present if the file is a dynamically linked + * shared library. For executable and object modules, which are files + * containing only one module, the information that would be in these three + * tables is determined as follows: + * table of contents - the defined external symbols are sorted by name + * module table - the file contains only one module so everything in the + * file is part of the module. + * reference symbol table - is the defined and undefined external symbols + * + * For dynamically linked shared library files this load command also contains + * offsets and sizes to the pool of relocation entries for all sections + * separated into two groups: + * external relocation entries + * local relocation entries + * For executable and object modules the relocation entries continue to hang + * off the section structures. + */ +struct dysymtab_command { + uint32_t cmd; /* LC_DYSYMTAB */ + uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ + + /* + * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command + * are grouped into the following three groups: + * local symbols (further grouped by the module they are from) + * defined external symbols (further grouped by the module they are from) + * undefined symbols + * + * The local symbols are used only for debugging. The dynamic binding + * process may have to use them to indicate to the debugger the local + * symbols for a module that is being bound. + * + * The last two groups are used by the dynamic binding process to do the + * binding (indirectly through the module table and the reference symbol + * table when this is a dynamically linked shared library file). + */ + uint32_t ilocalsym; /* index to local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextdefsym;/* index to externally defined symbols */ + uint32_t nextdefsym;/* number of externally defined symbols */ + + uint32_t iundefsym; /* index to undefined symbols */ + uint32_t nundefsym; /* number of undefined symbols */ + + /* + * For the for the dynamic binding process to find which module a symbol + * is defined in the table of contents is used (analogous to the ranlib + * structure in an archive) which maps defined external symbols to modules + * they are defined in. This exists only in a dynamically linked shared + * library file. For executable and object modules the defined external + * symbols are sorted by name and is use as the table of contents. + */ + uint32_t tocoff; /* file offset to table of contents */ + uint32_t ntoc; /* number of entries in table of contents */ + + /* + * To support dynamic binding of "modules" (whole object files) the symbol + * table must reflect the modules that the file was created from. This is + * done by having a module table that has indexes and counts into the merged + * tables for each module. The module structure that these two entries + * refer to is described below. This exists only in a dynamically linked + * shared library file. For executable and object modules the file only + * contains one module so everything in the file belongs to the module. + */ + uint32_t modtaboff; /* file offset to module table */ + uint32_t nmodtab; /* number of module table entries */ + + /* + * To support dynamic module binding the module structure for each module + * indicates the external references (defined and undefined) each module + * makes. For each module there is an offset and a count into the + * reference symbol table for the symbols that the module references. + * This exists only in a dynamically linked shared library file. For + * executable and object modules the defined external symbols and the + * undefined external symbols indicates the external references. + */ + uint32_t extrefsymoff; /* offset to referenced symbol table */ + uint32_t nextrefsyms; /* number of referenced symbol table entries */ + + /* + * The sections that contain "symbol pointers" and "routine stubs" have + * indexes and (implied counts based on the size of the section and fixed + * size of the entry) into the "indirect symbol" table for each pointer + * and stub. For every section of these two types the index into the + * indirect symbol table is stored in the section header in the field + * reserved1. An indirect symbol table entry is simply a 32bit index into + * the symbol table to the symbol that the pointer or stub is referring to. + * The indirect symbol table is ordered to match the entries in the section. + */ + uint32_t indirectsymoff; /* file offset to the indirect symbol table */ + uint32_t nindirectsyms; /* number of indirect symbol table entries */ + + /* + * To support relocating an individual module in a library file quickly the + * external relocation entries for each module in the library need to be + * accessed efficiently. Since the relocation entries can't be accessed + * through the section headers for a library file they are separated into + * groups of local and external entries further grouped by module. In this + * case the presents of this load command who's extreloff, nextrel, + * locreloff and nlocrel fields are non-zero indicates that the relocation + * entries of non-merged sections are not referenced through the section + * structures (and the reloff and nreloc fields in the section headers are + * set to zero). + * + * Since the relocation entries are not accessed through the section headers + * this requires the r_address field to be something other than a section + * offset to identify the item to be relocated. In this case r_address is + * set to the offset from the vmaddr of the first LC_SEGMENT command. + * For MH_SPLIT_SEGS images r_address is set to the the offset from the + * vmaddr of the first read-write LC_SEGMENT command. + * + * The relocation entries are grouped by module and the module table + * entries have indexes and counts into them for the group of external + * relocation entries for that the module. + * + * For sections that are merged across modules there must not be any + * remaining external relocation entries for them (for merged sections + * remaining relocation entries must be local). + */ + uint32_t extreloff; /* offset to external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + /* + * All the local relocation entries are grouped together (they are not + * grouped by their module since they are only used if the object is moved + * from it staticly link edited address). + */ + uint32_t locreloff; /* offset to local relocation entries */ + uint32_t nlocrel; /* number of local relocation entries */ + +}; + +/* + * An indirect symbol table entry is simply a 32bit index into the symbol table + * to the symbol that the pointer or stub is refering to. Unless it is for a + * non-lazy symbol pointer section for a defined symbol which strip(1) as + * removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the + * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that. + */ +#define INDIRECT_SYMBOL_LOCAL 0x80000000 +#define INDIRECT_SYMBOL_ABS 0x40000000 + + +/* a table of contents entry */ +struct dylib_table_of_contents { + uint32_t symbol_index; /* the defined external symbol + (index into the symbol table) */ + uint32_t module_index; /* index into the module table this symbol + is defined in */ +}; + +/* a module table entry */ +struct dylib_module { + uint32_t module_name; /* the module name (index into string table) */ + + uint32_t iextdefsym; /* index into externally defined symbols */ + uint32_t nextdefsym; /* number of externally defined symbols */ + uint32_t irefsym; /* index into reference symbol table */ + uint32_t nrefsym; /* number of reference symbol table entries */ + uint32_t ilocalsym; /* index into symbols for local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextrel; /* index into external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + uint32_t iinit_iterm; /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + uint32_t ninit_nterm; /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + uint32_t /* for this module address of the start of */ + objc_module_info_addr; /* the (__OBJC,__module_info) section */ + uint32_t /* for this module size of */ + objc_module_info_size; /* the (__OBJC,__module_info) section */ +}; + +/* a 64-bit module table entry */ +struct dylib_module_64 { + uint32_t module_name; /* the module name (index into string table) */ + + uint32_t iextdefsym; /* index into externally defined symbols */ + uint32_t nextdefsym; /* number of externally defined symbols */ + uint32_t irefsym; /* index into reference symbol table */ + uint32_t nrefsym; /* number of reference symbol table entries */ + uint32_t ilocalsym; /* index into symbols for local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextrel; /* index into external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + uint32_t iinit_iterm; /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + uint32_t ninit_nterm; /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + uint32_t /* for this module size of */ + objc_module_info_size; /* the (__OBJC,__module_info) section */ + uint64_t /* for this module address of the start of */ + objc_module_info_addr; /* the (__OBJC,__module_info) section */ +}; + +/* + * The entries in the reference symbol table are used when loading the module + * (both by the static and dynamic link editors) and if the module is unloaded + * or replaced. Therefore all external symbols (defined and undefined) are + * listed in the module's reference table. The flags describe the type of + * reference that is being made. The constants for the flags are defined in + * as they are also used for symbol table entries. + */ +struct dylib_reference { + uint32_t isym:24, /* index into the symbol table */ + flags:8; /* flags to indicate the type of reference */ +}; + +/* + * The twolevel_hints_command contains the offset and number of hints in the + * two-level namespace lookup hints table. + */ +struct twolevel_hints_command { + uint32_t cmd; /* LC_TWOLEVEL_HINTS */ + uint32_t cmdsize; /* sizeof(struct twolevel_hints_command) */ + uint32_t offset; /* offset to the hint table */ + uint32_t nhints; /* number of hints in the hint table */ +}; + +/* + * The entries in the two-level namespace lookup hints table are twolevel_hint + * structs. These provide hints to the dynamic link editor where to start + * looking for an undefined symbol in a two-level namespace image. The + * isub_image field is an index into the sub-images (sub-frameworks and + * sub-umbrellas list) that made up the two-level image that the undefined + * symbol was found in when it was built by the static link editor. If + * isub-image is 0 the the symbol is expected to be defined in library and not + * in the sub-images. If isub-image is non-zero it is an index into the array + * of sub-images for the umbrella with the first index in the sub-images being + * 1. The array of sub-images is the ordered list of sub-images of the umbrella + * that would be searched for a symbol that has the umbrella recorded as its + * primary library. The table of contents index is an index into the + * library's table of contents. This is used as the starting point of the + * binary search or a directed linear search. + */ +struct twolevel_hint { + uint32_t + isub_image:8, /* index into the sub images */ + itoc:24; /* index into the table of contents */ +}; + +/* + * The prebind_cksum_command contains the value of the original check sum for + * prebound files or zero. When a prebound file is first created or modified + * for other than updating its prebinding information the value of the check sum + * is set to zero. When the file has it prebinding re-done and if the value of + * the check sum is zero the original check sum is calculated and stored in + * cksum field of this load command in the output file. If when the prebinding + * is re-done and the cksum field is non-zero it is left unchanged from the + * input file. + */ +struct prebind_cksum_command { + uint32_t cmd; /* LC_PREBIND_CKSUM */ + uint32_t cmdsize; /* sizeof(struct prebind_cksum_command) */ + uint32_t cksum; /* the check sum or zero */ +}; + +/* + * The uuid load command contains a single 128-bit unique random number that + * identifies an object produced by the static link editor. + */ +struct uuid_command { + uint32_t cmd; /* LC_UUID */ + uint32_t cmdsize; /* sizeof(struct uuid_command) */ + uint8_t uuid[16]; /* the 128-bit uuid */ +}; + +/* + * The rpath_command contains a path which at runtime should be added to + * the current run path used to find @rpath prefixed dylibs. + */ +struct rpath_command { + uint32_t cmd; /* LC_RPATH */ + uint32_t cmdsize; /* includes string */ + union lc_str path; /* path to add to run path */ +}; + +/* + * The linkedit_data_command contains the offsets and sizes of a blob + * of data in the __LINKEDIT segment. + */ +struct linkedit_data_command { + uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, + or LC_FUNCTION_STARTS */ + uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ + uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ + uint32_t datasize; /* file size of data in __LINKEDIT segment */ +}; + +/* + * The encryption_info_command contains the file offset and size of an + * of an encrypted segment. + */ +struct encryption_info_command { + uint32_t cmd; /* LC_ENCRYPTION_INFO */ + uint32_t cmdsize; /* sizeof(struct encryption_info_command) */ + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, + 0 means not-encrypted yet */ +}; + +/* + * The version_min_command contains the min OS version on which this + * binary was built to run. + */ +struct version_min_command { + uint32_t cmd; /* LC_VERSION_MIN_MACOSX or + LC_VERSION_MIN_IPHONEOS */ + uint32_t cmdsize; /* sizeof(struct min_version_command) */ + uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t reserved; /* zero */ +}; + +/* + * The dyld_info_command contains the file offsets and sizes of + * the new compressed form of the information dyld needs to + * load the image. This information is used by dyld on Mac OS X + * 10.6 and later. All information pointed to by this command + * is encoded using byte streams, so no endian swapping is needed + * to interpret it. + */ +struct dyld_info_command { + uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ + uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ + + /* + * Dyld rebases an image whenever dyld loads it at an address different + * from its preferred address. The rebase information is a stream + * of byte sized opcodes whose symbolic names start with REBASE_OPCODE_. + * Conceptually the rebase information is a table of tuples: + * + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like "every n'th offset for m times" can be encoded in a few + * bytes. + */ + uint32_t rebase_off; /* file offset to rebase info */ + uint32_t rebase_size; /* size of rebase info */ + + /* + * Dyld binds an image during the loading process, if the image + * requires any pointers to be initialized to symbols in other images. + * The bind information is a stream of byte sized + * opcodes whose symbolic names start with BIND_OPCODE_. + * Conceptually the bind information is a table of tuples: + * + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like for runs of pointers initialzed to the same value can be + * encoded in a few bytes. + */ + uint32_t bind_off; /* file offset to binding info */ + uint32_t bind_size; /* size of binding info */ + + /* + * Some C++ programs require dyld to unique symbols so that all + * images in the process use the same copy of some code/data. + * This step is done after binding. The content of the weak_bind + * info is an opcode stream like the bind_info. But it is sorted + * alphabetically by symbol name. This enable dyld to walk + * all images with weak binding information in order and look + * for collisions. If there are no collisions, dyld does + * no updating. That means that some fixups are also encoded + * in the bind_info. For instance, all calls to "operator new" + * are first bound to libstdc++.dylib using the information + * in bind_info. Then if some image overrides operator new + * that is detected when the weak_bind information is processed + * and the call to operator new is then rebound. + */ + uint32_t weak_bind_off; /* file offset to weak binding info */ + uint32_t weak_bind_size; /* size of weak binding info */ + + /* + * Some uses of external symbols do not need to be bound immediately. + * Instead they can be lazily bound on first use. The lazy_bind + * are contains a stream of BIND opcodes to bind all lazy symbols. + * Normal use is that dyld ignores the lazy_bind section when + * loading an image. Instead the static linker arranged for the + * lazy pointer to initially point to a helper function which + * pushes the offset into the lazy_bind area for the symbol + * needing to be bound, then jumps to dyld which simply adds + * the offset to lazy_bind_off to get the information on what + * to bind. + */ + uint32_t lazy_bind_off; /* file offset to lazy binding info */ + uint32_t lazy_bind_size; /* size of lazy binding infs */ + + /* + * The symbols exported by a dylib are encoded in a trie. This + * is a compact representation that factors out common prefixes. + * It also reduces LINKEDIT pages in RAM because it encodes all + * information (name, address, flags) in one small, contiguous range. + * The export area is a stream of nodes. The first node sequentially + * is the start node for the trie. + * + * Nodes for a symbol start with a uleb128 that is the length of + * the exported symbol information for the string so far. + * If there is no exported symbol, the node starts with a zero byte. + * If there is exported info, it follows the length. First is + * a uleb128 containing flags. Normally, it is followed by a + * uleb128 encoded offset which is location of the content named + * by the symbol from the mach_header for the image. If the flags + * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is + * a uleb128 encoded library ordinal, then a zero terminated + * UTF8 string. If the string is zero length, then the symbol + * is re-export from the specified dylib with the same name. + * + * After the optional exported symbol information is a byte of + * how many edges (0-255) that this node has leaving it, + * followed by each edge. + * Each edge is a zero terminated UTF8 of the addition chars + * in the symbol, followed by a uleb128 offset for the node that + * edge points to. + * + */ + uint32_t export_off; /* file offset to lazy binding info */ + uint32_t export_size; /* size of lazy binding infs */ +}; + +/* + * The following are used to encode rebasing information + */ +#define REBASE_TYPE_POINTER 1 +#define REBASE_TYPE_TEXT_ABSOLUTE32 2 +#define REBASE_TYPE_TEXT_PCREL32 3 + +#define REBASE_OPCODE_MASK 0xF0 +#define REBASE_IMMEDIATE_MASK 0x0F +#define REBASE_OPCODE_DONE 0x00 +#define REBASE_OPCODE_SET_TYPE_IMM 0x10 +#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 +#define REBASE_OPCODE_ADD_ADDR_ULEB 0x30 +#define REBASE_OPCODE_ADD_ADDR_IMM_SCALED 0x40 +#define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES 0x60 +#define REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB 0x70 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB 0x80 + + +/* + * The following are used to encode binding information + */ +#define BIND_TYPE_POINTER 1 +#define BIND_TYPE_TEXT_ABSOLUTE32 2 +#define BIND_TYPE_TEXT_PCREL32 3 + +#define BIND_SPECIAL_DYLIB_SELF 0 +#define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1 +#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 + +#define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 +#define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8 + +#define BIND_OPCODE_MASK 0xF0 +#define BIND_IMMEDIATE_MASK 0x0F +#define BIND_OPCODE_DONE 0x00 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20 +#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 +#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 +#define BIND_OPCODE_SET_TYPE_IMM 0x50 +#define BIND_OPCODE_SET_ADDEND_SLEB 0x60 +#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 +#define BIND_OPCODE_ADD_ADDR_ULEB 0x80 +#define BIND_OPCODE_DO_BIND 0x90 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0 +#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0 + + +/* + * The following are used on the flags byte of a terminal node + * in the export information. + */ +#define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03 +#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 +#define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01 +#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 +#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 +#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 + +/* + * The symseg_command contains the offset and size of the GNU style + * symbol table information as described in the header file . + * The symbol roots of the symbol segments must also be aligned properly + * in the file. So the requirement of keeping the offsets aligned to a + * multiple of a 4 bytes translates to the length field of the symbol + * roots also being a multiple of a long. Also the padding must again be + * zeroed. (THIS IS OBSOLETE and no longer supported). + */ +struct symseg_command { + uint32_t cmd; /* LC_SYMSEG */ + uint32_t cmdsize; /* sizeof(struct symseg_command) */ + uint32_t offset; /* symbol segment offset */ + uint32_t size; /* symbol segment size in bytes */ +}; + +/* + * The ident_command contains a free format string table following the + * ident_command structure. The strings are null terminated and the size of + * the command is padded out with zero bytes to a multiple of 4 bytes/ + * (THIS IS OBSOLETE and no longer supported). + */ +struct ident_command { + uint32_t cmd; /* LC_IDENT */ + uint32_t cmdsize; /* strings that follow this command */ +}; + +/* + * The fvmfile_command contains a reference to a file to be loaded at the + * specified virtual address. (Presently, this command is reserved for + * internal use. The kernel ignores this command when loading a program into + * memory). + */ +struct fvmfile_command { + uint32_t cmd; /* LC_FVMFILE */ + uint32_t cmdsize; /* includes pathname string */ + union lc_str name; /* files pathname */ + uint32_t header_addr; /* files virtual address */ +}; + +/* + * Sections of type S_THREAD_LOCAL_VARIABLES contain an array + * of tlv_descriptor structures. + */ +struct tlv_descriptor +{ + void* (*thunk)(struct tlv_descriptor*); + unsigned long key; + unsigned long offset; +}; + +#endif /* _MACHO_LOADER_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/nlist.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/nlist.h new file mode 100644 index 0000000000..1c1941012e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach-o/nlist.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 1999-2003 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@ + */ +#ifndef _MACHO_NLIST_H_ +#define _MACHO_NLIST_H_ +/* $NetBSD: nlist.h,v 1.5 1994/10/26 00:56:11 cgd Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * + * @(#)nlist.h 8.2 (Berkeley) 1/21/94 + */ +#include + +/* + * Format of a symbol table entry of a Mach-O file for 32-bit architectures. + * Modified from the BSD format. The modifications from the original format + * were changing n_other (an unused field) to n_sect and the addition of the + * N_SECT type. These modifications are required to support symbols in a larger + * number of sections not just the three sections (text, data and bss) in a BSD + * file. + */ +struct nlist { + union { +#ifndef __LP64__ + char *n_name; /* for use when in-core */ +#endif + int32_t n_strx; /* index into the string table */ + } n_un; + uint8_t n_type; /* type flag, see below */ + uint8_t n_sect; /* section number or NO_SECT */ + int16_t n_desc; /* see */ + uint32_t n_value; /* value of this symbol (or stab offset) */ +}; + +/* + * This is the symbol table entry structure for 64-bit architectures. + */ +struct nlist_64 { + union { + uint32_t n_strx; /* index into the string table */ + } n_un; + uint8_t n_type; /* type flag, see below */ + uint8_t n_sect; /* section number or NO_SECT */ + uint16_t n_desc; /* see */ + uint64_t n_value; /* value of this symbol (or stab offset) */ +}; + +/* + * Symbols with a index into the string table of zero (n_un.n_strx == 0) are + * defined to have a null, "", name. Therefore all string indexes to non null + * names must not have a zero string index. This is bit historical information + * that has never been well documented. + */ + +/* + * The n_type field really contains four fields: + * unsigned char N_STAB:3, + * N_PEXT:1, + * N_TYPE:3, + * N_EXT:1; + * which are used via the following masks. + */ +#define N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */ +#define N_PEXT 0x10 /* private external symbol bit */ +#define N_TYPE 0x0e /* mask for the type bits */ +#define N_EXT 0x01 /* external symbol bit, set for external symbols */ + +/* + * Only symbolic debugging entries have some of the N_STAB bits set and if any + * of these bits are set then it is a symbolic debugging entry (a stab). In + * which case then the values of the n_type field (the entire field) are given + * in + */ + +/* + * Values for N_TYPE bits of the n_type field. + */ +#define N_UNDF 0x0 /* undefined, n_sect == NO_SECT */ +#define N_ABS 0x2 /* absolute, n_sect == NO_SECT */ +#define N_SECT 0xe /* defined in section number n_sect */ +#define N_PBUD 0xc /* prebound undefined (defined in a dylib) */ +#define N_INDR 0xa /* indirect */ + +/* + * If the type is N_INDR then the symbol is defined to be the same as another + * symbol. In this case the n_value field is an index into the string table + * of the other symbol's name. When the other symbol is defined then they both + * take on the defined type and value. + */ + +/* + * If the type is N_SECT then the n_sect field contains an ordinal of the + * section the symbol is defined in. The sections are numbered from 1 and + * refer to sections in order they appear in the load commands for the file + * they are in. This means the same ordinal may very well refer to different + * sections in different files. + * + * The n_value field for all symbol table entries (including N_STAB's) gets + * updated by the link editor based on the value of it's n_sect field and where + * the section n_sect references gets relocated. If the value of the n_sect + * field is NO_SECT then it's n_value field is not changed by the link editor. + */ +#define NO_SECT 0 /* symbol is not in any section */ +#define MAX_SECT 255 /* 1 thru 255 inclusive */ + +/* + * Common symbols are represented by undefined (N_UNDF) external (N_EXT) types + * who's values (n_value) are non-zero. In which case the value of the n_value + * field is the size (in bytes) of the common symbol. The n_sect field is set + * to NO_SECT. The alignment of a common symbol may be set as a power of 2 + * between 2^1 and 2^15 as part of the n_desc field using the macros below. If + * the alignment is not set (a value of zero) then natural alignment based on + * the size is used. + */ +#define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f) +#define SET_COMM_ALIGN(n_desc,align) \ + (n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8)) + +/* + * To support the lazy binding of undefined symbols in the dynamic link-editor, + * the undefined symbols in the symbol table (the nlist structures) are marked + * with the indication if the undefined reference is a lazy reference or + * non-lazy reference. If both a non-lazy reference and a lazy reference is + * made to the same symbol the non-lazy reference takes precedence. A reference + * is lazy only when all references to that symbol are made through a symbol + * pointer in a lazy symbol pointer section. + * + * The implementation of marking nlist structures in the symbol table for + * undefined symbols will be to use some of the bits of the n_desc field as a + * reference type. The mask REFERENCE_TYPE will be applied to the n_desc field + * of an nlist structure for an undefined symbol to determine the type of + * undefined reference (lazy or non-lazy). + * + * The constants for the REFERENCE FLAGS are propagated to the reference table + * in a shared library file. In that case the constant for a defined symbol, + * REFERENCE_FLAG_DEFINED, is also used. + */ +/* Reference type bits of the n_desc field of undefined symbols */ +#define REFERENCE_TYPE 0x7 +/* types of references */ +#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0 +#define REFERENCE_FLAG_UNDEFINED_LAZY 1 +#define REFERENCE_FLAG_DEFINED 2 +#define REFERENCE_FLAG_PRIVATE_DEFINED 3 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4 +#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5 + +/* + * To simplify stripping of objects that use are used with the dynamic link + * editor, the static link editor marks the symbols defined an object that are + * referenced by a dynamicly bound object (dynamic shared libraries, bundles). + * With this marking strip knows not to strip these symbols. + */ +#define REFERENCED_DYNAMICALLY 0x0010 + +/* + * For images created by the static link editor with the -twolevel_namespace + * option in effect the flags field of the mach header is marked with + * MH_TWOLEVEL. And the binding of the undefined references of the image are + * determined by the static link editor. Which library an undefined symbol is + * bound to is recorded by the static linker in the high 8 bits of the n_desc + * field using the SET_LIBRARY_ORDINAL macro below. The ordinal recorded + * references the libraries listed in the Mach-O's LC_LOAD_DYLIB, + * LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB, and + * LC_LAZY_LOAD_DYLIB, etc. load commands in the order they appear in the + * headers. The library ordinals start from 1. + * For a dynamic library that is built as a two-level namespace image the + * undefined references from module defined in another use the same nlist struct + * an in that case SELF_LIBRARY_ORDINAL is used as the library ordinal. For + * defined symbols in all images they also must have the library ordinal set to + * SELF_LIBRARY_ORDINAL. The EXECUTABLE_ORDINAL refers to the executable + * image for references from plugins that refer to the executable that loads + * them. + * + * The DYNAMIC_LOOKUP_ORDINAL is for undefined symbols in a two-level namespace + * image that are looked up by the dynamic linker with flat namespace semantics. + * This ordinal was added as a feature in Mac OS X 10.3 by reducing the + * value of MAX_LIBRARY_ORDINAL by one. So it is legal for existing binaries + * or binaries built with older tools to have 0xfe (254) dynamic libraries. In + * this case the ordinal value 0xfe (254) must be treated as a library ordinal + * for compatibility. + */ +#define GET_LIBRARY_ORDINAL(n_desc) (((n_desc) >> 8) & 0xff) +#define SET_LIBRARY_ORDINAL(n_desc,ordinal) \ + (n_desc) = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8)) +#define SELF_LIBRARY_ORDINAL 0x0 +#define MAX_LIBRARY_ORDINAL 0xfd +#define DYNAMIC_LOOKUP_ORDINAL 0xfe +#define EXECUTABLE_ORDINAL 0xff + +/* + * The bit 0x0020 of the n_desc field is used for two non-overlapping purposes + * and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED. + */ + +/* + * The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a + * relocatable .o file (MH_OBJECT filetype). And is used to indicate to the + * static link editor it is never to dead strip the symbol. + */ +#define N_NO_DEAD_STRIP 0x0020 /* symbol is not to be dead stripped */ + +/* + * The N_DESC_DISCARDED bit of the n_desc field never appears in linked image. + * But is used in very rare cases by the dynamic link editor to mark an in + * memory symbol as discared and longer used for linking. + */ +#define N_DESC_DISCARDED 0x0020 /* symbol is discarded */ + +/* + * The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that + * the undefined symbol is allowed to be missing and is to have the address of + * zero when missing. + */ +#define N_WEAK_REF 0x0040 /* symbol is weak referenced */ + +/* + * The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic + * linkers that the symbol definition is weak, allowing a non-weak symbol to + * also be used which causes the weak definition to be discared. Currently this + * is only supported for symbols in coalesed sections. + */ +#define N_WEAK_DEF 0x0080 /* coalesed symbol is a weak definition */ + +/* + * The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker + * that the undefined symbol should be resolved using flat namespace searching. + */ +#define N_REF_TO_WEAK 0x0080 /* reference to a weak symbol */ + +/* + * The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is + * a defintion of a Thumb function. + */ +#define N_ARM_THUMB_DEF 0x0008 /* symbol is a Thumb function (ARM) */ + +/* + * The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the + * that the function is actually a resolver function and should + * be called to get the address of the real function to use. + * This bit is only available in .o files (MH_OBJECT filetype) + */ +#define N_SYMBOL_RESOLVER 0x0100 + +#ifndef __STRICT_BSD__ +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +/* + * The function nlist(3) from the C library. + */ +extern int nlist (const char *filename, struct nlist *list); +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __STRICT_BSD__ */ + +#endif /* _MACHO_LIST_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/boolean.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/boolean.h new file mode 100644 index 0000000000..641c3962d9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/boolean.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * File: mach/boolean.h + * + * Boolean data type. + * + */ + +#ifndef _MACH_BOOLEAN_H_ +#define _MACH_BOOLEAN_H_ + +/* + * Pick up "boolean_t" type definition + */ + +#ifndef ASSEMBLER +#include +#endif /* ASSEMBLER */ + +/* + * Define TRUE and FALSE if not defined. + */ + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#endif /* _MACH_BOOLEAN_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/boolean.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/boolean.h new file mode 100644 index 0000000000..100f7e7b51 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/boolean.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ + +/* + * File: boolean.h + * + * Boolean type, for I386. + */ + +#ifndef _MACH_I386_BOOLEAN_H_ +#define _MACH_I386_BOOLEAN_H_ + +#if defined(__x86_64__) && !defined(KERNEL) +typedef unsigned int boolean_t; +#else +typedef int boolean_t; +#endif + +#endif /* _MACH_I386_BOOLEAN_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_param.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_param.h new file mode 100644 index 0000000000..edcb83496b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_param.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/* + * Copyright (c) 1994 The University of Utah and + * the Computer Systems Laboratory at the University of Utah (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software is hereby + * granted provided that (1) source code retains these copyright, permission, + * and disclaimer notices, and (2) redistributions including binaries + * reproduce the notices in supporting documentation, and (3) all advertising + * materials mentioning features or use of this software display the following + * acknowledgement: ``This product includes software developed by the + * Computer Systems Laboratory at the University of Utah.'' + * + * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS + * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF + * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * CSL requests users of this software to return to csl-dist@cs.utah.edu any + * improvements that they make and grant CSL redistribution rights. + * + */ + +/* + * File: vm_param.h + * Author: Avadis Tevanian, Jr. + * Date: 1985 + * + * I386 machine dependent virtual memory parameters. + * Most of the declarations are preceeded by I386_ (or i386_) + * which is OK because only I386 specific code will be using + * them. + */ + +#ifndef _MACH_I386_VM_PARAM_H_ +#define _MACH_I386_VM_PARAM_H_ + +#define BYTE_SIZE 8 /* byte size in bits */ + +#define I386_PGBYTES 4096 /* bytes per 80386 page */ +#define I386_PGSHIFT 12 /* bitshift for pages */ + +#define PAGE_SIZE I386_PGBYTES +#define PAGE_SHIFT I386_PGSHIFT +#define PAGE_MASK (PAGE_SIZE - 1) + +#define I386_LPGBYTES 2*1024*1024 /* bytes per large page */ +#define I386_LPGSHIFT 21 /* bitshift for large pages */ +#define I386_LPGMASK (I386_LPGBYTES-1) + +/* + * Convert bytes to pages and convert pages to bytes. + * No rounding is used. + */ + +#define i386_btop(x) ((ppnum_t)((x) >> I386_PGSHIFT)) +#define machine_btop(x) i386_btop(x) +#define i386_ptob(x) (((pmap_paddr_t)(x)) << I386_PGSHIFT) + +/* + * Round off or truncate to the nearest page. These will work + * for either addresses or counts. (i.e. 1 byte rounds to 1 page + * bytes. + */ + +#define i386_round_page(x) ((((pmap_paddr_t)(x)) + I386_PGBYTES - 1) & \ + ~(I386_PGBYTES-1)) +#define i386_trunc_page(x) (((pmap_paddr_t)(x)) & ~(I386_PGBYTES-1)) + + + +#define VM_MIN_ADDRESS64 ((user_addr_t) 0x0000000000000000ULL) +/* + * default top of user stack... it grows down from here + */ +#define VM_USRSTACK64 ((user_addr_t) 0x00007FFF5FC00000ULL) +#define VM_DYLD64 ((user_addr_t) 0x00007FFF5FC00000ULL) +#define VM_LIB64_SHR_DATA ((user_addr_t) 0x00007FFF60000000ULL) +#define VM_LIB64_SHR_TEXT ((user_addr_t) 0x00007FFF80000000ULL) +/* + * the end of the usable user address space , for now about 47 bits. + * the 64 bit commpage is past the end of this + */ +#define VM_MAX_PAGE_ADDRESS ((user_addr_t) 0x00007FFFFFE00000ULL) +/* + * canonical end of user address space for limits checking + */ +#define VM_MAX_USER_PAGE_ADDRESS ((user_addr_t)0x00007FFFFFFFF000ULL) + + +/* system-wide values */ +#define MACH_VM_MIN_ADDRESS ((mach_vm_offset_t) 0) +#define MACH_VM_MAX_ADDRESS ((mach_vm_offset_t) VM_MAX_PAGE_ADDRESS) + +/* process-relative values (all 32-bit legacy only for now) */ +#define VM_MIN_ADDRESS ((vm_offset_t) 0) +#define VM_USRSTACK32 ((vm_offset_t) 0xC0000000) +#define VM_MAX_ADDRESS ((vm_offset_t) 0xFFE00000) + + + +#endif /* _MACH_I386_VM_PARAM_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_types.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_types.h new file mode 100644 index 0000000000..2c38fa2d70 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/i386/vm_types.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ + +/* + * File: vm_types.h + * Author: Avadis Tevanian, Jr. + * Date: 1985 + * + * Header file for VM data types. I386 version. + */ + +#ifndef _MACH_I386_VM_TYPES_H_ +#define _MACH_I386_VM_TYPES_H_ + +#ifndef ASSEMBLER + +#include +#include +#include + +/* + * natural_t and integer_t are Mach's legacy types for machine- + * independent integer types (unsigned, and signed, respectively). + * Their original purpose was to define other types in a machine/ + * compiler independent way. + * + * They also had an implicit "same size as pointer" characteristic + * to them (i.e. Mach's traditional types are very ILP32 or ILP64 + * centric). We support x86 ABIs that do not follow either of + * these models (specifically LP64). Therefore, we had to make a + * choice between making these types scale with pointers or stay + * tied to integers. Because their use is predominantly tied to + * to the size of an integer, we are keeping that association and + * breaking free from pointer size guarantees. + * + * New use of these types is discouraged. + */ +typedef __darwin_natural_t natural_t; +typedef int integer_t; + +/* + * A vm_offset_t is a type-neutral pointer, + * e.g. an offset into a virtual memory space. + */ +#ifdef __LP64__ +typedef uintptr_t vm_offset_t; +#else /* __LP64__ */ +typedef natural_t vm_offset_t; +#endif /* __LP64__ */ + +/* + * A vm_size_t is the proper type for e.g. + * expressing the difference between two + * vm_offset_t entities. + */ +#ifdef __LP64__ +typedef uintptr_t vm_size_t; +#else /* __LP64__ */ +typedef natural_t vm_size_t; +#endif /* __LP64__ */ + +/* + * This new type is independent of a particular vm map's + * implementation size - and represents appropriate types + * for all possible maps. This is used for interfaces + * where the size of the map is not known - or we don't + * want to have to distinguish. + */ +typedef uint64_t mach_vm_address_t; +typedef uint64_t mach_vm_offset_t; +typedef uint64_t mach_vm_size_t; + +typedef uint64_t vm_map_offset_t; +typedef uint64_t vm_map_address_t; +typedef uint64_t vm_map_size_t; + + +#endif /* ASSEMBLER */ + +/* + * If composing messages by hand (please do not) + */ +#define MACH_MSG_TYPE_INTEGER_T MACH_MSG_TYPE_INTEGER_32 + +#endif /* _MACH_I386_VM_TYPES_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine.h new file mode 100644 index 0000000000..5bb21e48be --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine.h @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* File: machine.h + * Author: Avadis Tevanian, Jr. + * Date: 1986 + * + * Machine independent machine abstraction. + */ + +#ifndef _MACH_MACHINE_H_ +#define _MACH_MACHINE_H_ + +#include +#include +#include + +typedef integer_t cpu_type_t; +typedef integer_t cpu_subtype_t; +typedef integer_t cpu_threadtype_t; + +#define CPU_STATE_MAX 4 + +#define CPU_STATE_USER 0 +#define CPU_STATE_SYSTEM 1 +#define CPU_STATE_IDLE 2 +#define CPU_STATE_NICE 3 + + + +/* + * Capability bits used in the definition of cpu_type. + */ +#define CPU_ARCH_MASK 0xff000000 /* mask for architecture bits */ +#define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */ + +/* + * Machine types known by all. + */ + +#define CPU_TYPE_ANY ((cpu_type_t) -1) + +#define CPU_TYPE_VAX ((cpu_type_t) 1) +/* skip ((cpu_type_t) 2) */ +/* skip ((cpu_type_t) 3) */ +/* skip ((cpu_type_t) 4) */ +/* skip ((cpu_type_t) 5) */ +#define CPU_TYPE_MC680x0 ((cpu_type_t) 6) +#define CPU_TYPE_X86 ((cpu_type_t) 7) +#define CPU_TYPE_I386 CPU_TYPE_X86 /* compatibility */ +#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) + +/* skip CPU_TYPE_MIPS ((cpu_type_t) 8) */ +/* skip ((cpu_type_t) 9) */ +#define CPU_TYPE_MC98000 ((cpu_type_t) 10) +#define CPU_TYPE_HPPA ((cpu_type_t) 11) +#define CPU_TYPE_ARM ((cpu_type_t) 12) +#define CPU_TYPE_MC88000 ((cpu_type_t) 13) +#define CPU_TYPE_SPARC ((cpu_type_t) 14) +#define CPU_TYPE_I860 ((cpu_type_t) 15) +/* skip CPU_TYPE_ALPHA ((cpu_type_t) 16) */ +/* skip ((cpu_type_t) 17) */ +#define CPU_TYPE_POWERPC ((cpu_type_t) 18) +#define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) + +/* + * Machine subtypes (these are defined here, instead of in a machine + * dependent directory, so that any program can get all definitions + * regardless of where is it compiled). + */ + +/* + * Capability bits used in the definition of cpu_subtype. + */ +#define CPU_SUBTYPE_MASK 0xff000000 /* mask for feature flags */ +#define CPU_SUBTYPE_LIB64 0x80000000 /* 64 bit libraries */ + + +/* + * Object files that are hand-crafted to run on any + * implementation of an architecture are tagged with + * CPU_SUBTYPE_MULTIPLE. This functions essentially the same as + * the "ALL" subtype of an architecture except that it allows us + * to easily find object files that may need to be modified + * whenever a new implementation of an architecture comes out. + * + * It is the responsibility of the implementor to make sure the + * software handles unsupported implementations elegantly. + */ +#define CPU_SUBTYPE_MULTIPLE ((cpu_subtype_t) -1) +#define CPU_SUBTYPE_LITTLE_ENDIAN ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_BIG_ENDIAN ((cpu_subtype_t) 1) + +/* + * Machine threadtypes. + * This is none - not defined - for most machine types/subtypes. + */ +#define CPU_THREADTYPE_NONE ((cpu_threadtype_t) 0) + +/* + * VAX subtypes (these do *not* necessary conform to the actual cpu + * ID assigned by DEC available via the SID register). + */ + +#define CPU_SUBTYPE_VAX_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_VAX780 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_VAX785 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_VAX750 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_VAX730 ((cpu_subtype_t) 4) +#define CPU_SUBTYPE_UVAXI ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_UVAXII ((cpu_subtype_t) 6) +#define CPU_SUBTYPE_VAX8200 ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_VAX8500 ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_VAX8600 ((cpu_subtype_t) 9) +#define CPU_SUBTYPE_VAX8650 ((cpu_subtype_t) 10) +#define CPU_SUBTYPE_VAX8800 ((cpu_subtype_t) 11) +#define CPU_SUBTYPE_UVAXIII ((cpu_subtype_t) 12) + +/* + * 680x0 subtypes + * + * The subtype definitions here are unusual for historical reasons. + * NeXT used to consider 68030 code as generic 68000 code. For + * backwards compatability: + * + * CPU_SUBTYPE_MC68030 symbol has been preserved for source code + * compatability. + * + * CPU_SUBTYPE_MC680x0_ALL has been defined to be the same + * subtype as CPU_SUBTYPE_MC68030 for binary comatability. + * + * CPU_SUBTYPE_MC68030_ONLY has been added to allow new object + * files to be tagged as containing 68030-specific instructions. + */ + +#define CPU_SUBTYPE_MC680x0_ALL ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MC68030 ((cpu_subtype_t) 1) /* compat */ +#define CPU_SUBTYPE_MC68040 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_MC68030_ONLY ((cpu_subtype_t) 3) + +/* + * I386 subtypes + */ + +#define CPU_SUBTYPE_INTEL(f, m) ((cpu_subtype_t) (f) + ((m) << 4)) + +#define CPU_SUBTYPE_I386_ALL CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_386 CPU_SUBTYPE_INTEL(3, 0) +#define CPU_SUBTYPE_486 CPU_SUBTYPE_INTEL(4, 0) +#define CPU_SUBTYPE_486SX CPU_SUBTYPE_INTEL(4, 8) // 8 << 4 = 128 +#define CPU_SUBTYPE_586 CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0) +#define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1) +#define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3) +#define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5) +#define CPU_SUBTYPE_CELERON CPU_SUBTYPE_INTEL(7, 6) +#define CPU_SUBTYPE_CELERON_MOBILE CPU_SUBTYPE_INTEL(7, 7) +#define CPU_SUBTYPE_PENTIUM_3 CPU_SUBTYPE_INTEL(8, 0) +#define CPU_SUBTYPE_PENTIUM_3_M CPU_SUBTYPE_INTEL(8, 1) +#define CPU_SUBTYPE_PENTIUM_3_XEON CPU_SUBTYPE_INTEL(8, 2) +#define CPU_SUBTYPE_PENTIUM_M CPU_SUBTYPE_INTEL(9, 0) +#define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0) +#define CPU_SUBTYPE_PENTIUM_4_M CPU_SUBTYPE_INTEL(10, 1) +#define CPU_SUBTYPE_ITANIUM CPU_SUBTYPE_INTEL(11, 0) +#define CPU_SUBTYPE_ITANIUM_2 CPU_SUBTYPE_INTEL(11, 1) +#define CPU_SUBTYPE_XEON CPU_SUBTYPE_INTEL(12, 0) +#define CPU_SUBTYPE_XEON_MP CPU_SUBTYPE_INTEL(12, 1) + +#define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15) +#define CPU_SUBTYPE_INTEL_FAMILY_MAX 15 + +#define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4) +#define CPU_SUBTYPE_INTEL_MODEL_ALL 0 + +/* + * X86 subtypes. + */ + +#define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) +#define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3) +#define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4) +#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell feature subset */ + + +#define CPU_THREADTYPE_INTEL_HTT ((cpu_threadtype_t) 1) + +/* + * Mips subtypes. + */ + +#define CPU_SUBTYPE_MIPS_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MIPS_R2300 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MIPS_R2600 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_MIPS_R2800 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_MIPS_R2000a ((cpu_subtype_t) 4) /* pmax */ +#define CPU_SUBTYPE_MIPS_R2000 ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_MIPS_R3000a ((cpu_subtype_t) 6) /* 3max */ +#define CPU_SUBTYPE_MIPS_R3000 ((cpu_subtype_t) 7) + +/* + * MC98000 (PowerPC) subtypes + */ +#define CPU_SUBTYPE_MC98000_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MC98601 ((cpu_subtype_t) 1) + +/* + * HPPA subtypes for Hewlett-Packard HP-PA family of + * risc processors. Port by NeXT to 700 series. + */ + +#define CPU_SUBTYPE_HPPA_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_HPPA_7100 ((cpu_subtype_t) 0) /* compat */ +#define CPU_SUBTYPE_HPPA_7100LC ((cpu_subtype_t) 1) + +/* + * MC88000 subtypes. + */ +#define CPU_SUBTYPE_MC88000_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_MC88100 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_MC88110 ((cpu_subtype_t) 2) + +/* + * SPARC subtypes + */ +#define CPU_SUBTYPE_SPARC_ALL ((cpu_subtype_t) 0) + +/* + * I860 subtypes + */ +#define CPU_SUBTYPE_I860_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_I860_860 ((cpu_subtype_t) 1) + +/* + * PowerPC subtypes + */ +#define CPU_SUBTYPE_POWERPC_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_POWERPC_601 ((cpu_subtype_t) 1) +#define CPU_SUBTYPE_POWERPC_602 ((cpu_subtype_t) 2) +#define CPU_SUBTYPE_POWERPC_603 ((cpu_subtype_t) 3) +#define CPU_SUBTYPE_POWERPC_603e ((cpu_subtype_t) 4) +#define CPU_SUBTYPE_POWERPC_603ev ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_POWERPC_604 ((cpu_subtype_t) 6) +#define CPU_SUBTYPE_POWERPC_604e ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_POWERPC_620 ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_POWERPC_750 ((cpu_subtype_t) 9) +#define CPU_SUBTYPE_POWERPC_7400 ((cpu_subtype_t) 10) +#define CPU_SUBTYPE_POWERPC_7450 ((cpu_subtype_t) 11) +#define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) + +/* + * ARM subtypes + */ +#define CPU_SUBTYPE_ARM_ALL ((cpu_subtype_t) 0) +#define CPU_SUBTYPE_ARM_V4T ((cpu_subtype_t) 5) +#define CPU_SUBTYPE_ARM_V6 ((cpu_subtype_t) 6) +#define CPU_SUBTYPE_ARM_V5TEJ ((cpu_subtype_t) 7) +#define CPU_SUBTYPE_ARM_XSCALE ((cpu_subtype_t) 8) +#define CPU_SUBTYPE_ARM_V7 ((cpu_subtype_t) 9) + +/* + * CPU families (sysctl hw.cpufamily) + * + * These are meant to identify the CPU's marketing name - an + * application can map these to (possibly) localized strings. + * NB: the encodings of the CPU families are intentionally arbitrary. + * There is no ordering, and you should never try to deduce whether + * or not some feature is available based on the family. + * Use feature flags (eg, hw.optional.altivec) to test for optional + * functionality. + */ +#define CPUFAMILY_UNKNOWN 0 +#define CPUFAMILY_POWERPC_G3 0xcee41549 +#define CPUFAMILY_POWERPC_G4 0x77c184ae +#define CPUFAMILY_POWERPC_G5 0xed76d8aa +#define CPUFAMILY_INTEL_6_13 0xaa33392b +#define CPUFAMILY_INTEL_YONAH 0x73d67300 +#define CPUFAMILY_INTEL_MEROM 0x426f69ef +#define CPUFAMILY_INTEL_PENRYN 0x78ea4fbc +#define CPUFAMILY_INTEL_NEHALEM 0x6b5a4cd2 +#define CPUFAMILY_INTEL_WESTMERE 0x573b5eec +#define CPUFAMILY_INTEL_SANDYBRIDGE 0x5490b78c +#define CPUFAMILY_ARM_9 0xe73283ae +#define CPUFAMILY_ARM_11 0x8ff620d8 +#define CPUFAMILY_ARM_XSCALE 0x53b005f5 +#define CPUFAMILY_ARM_13 0x0cc90e64 +#define CPUFAMILY_ARM_14 0x96077ef1 + +/* The following synonyms are deprecated: */ +#define CPUFAMILY_INTEL_6_14 CPUFAMILY_INTEL_YONAH +#define CPUFAMILY_INTEL_6_15 CPUFAMILY_INTEL_MEROM +#define CPUFAMILY_INTEL_6_23 CPUFAMILY_INTEL_PENRYN +#define CPUFAMILY_INTEL_6_26 CPUFAMILY_INTEL_NEHALEM + +#define CPUFAMILY_INTEL_CORE CPUFAMILY_INTEL_YONAH +#define CPUFAMILY_INTEL_CORE2 CPUFAMILY_INTEL_MEROM + + +#endif /* _MACH_MACHINE_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/boolean.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/boolean.h new file mode 100644 index 0000000000..ffdc2390a8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/boolean.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef _MACH_MACHINE_BOOLEAN_H_ +#define _MACH_MACHINE_BOOLEAN_H_ + +#if defined (__i386__) || defined(__x86_64__) +#include "mach/i386/boolean.h" +#elif defined (__arm__) +#include "mach/arm/boolean.h" +#else +#error architecture not supported +#endif + +#endif /* _MACH_MACHINE_BOOLEAN_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_state.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_state.h new file mode 100644 index 0000000000..1547acac76 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_state.h @@ -0,0 +1,9 @@ +/* + * This file is a stub with the bare minimum needed to make things work. + */ +#ifndef _MACH_MACHINE_THREAD_STATE_H_ +#define _MACH_MACHINE_THREAD_STATE_H_ + +#define THREAD_STATE_MAX 1 + +#endif /* _MACH_MACHINE_THREAD_STATE_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_status.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_status.h new file mode 100644 index 0000000000..d1ab56ad58 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/thread_status.h @@ -0,0 +1 @@ +/* This file intentionally left blank */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/vm_types.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/vm_types.h new file mode 100644 index 0000000000..8ccd24be53 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/machine/vm_types.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef _MACH_MACHINE_VM_TYPES_H_ +#define _MACH_MACHINE_VM_TYPES_H_ + +#if defined (__i386__) || defined(__x86_64__) +#include "mach/i386/vm_types.h" +#elif defined (__arm__) +#include "mach/arm/vm_types.h" +#else +#error architecture not supported +#endif + +#endif /* _MACH_MACHINE_VM_TYPES_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/thread_status.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/thread_status.h new file mode 100644 index 0000000000..aead09bf97 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/thread_status.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * File: mach/thread_status.h + * Author: Avadis Tevanian, Jr. + * + * This file contains the structure definitions for the user-visible + * thread state. This thread state is examined with the thread_get_state + * kernel call and may be changed with the thread_set_state kernel call. + * + */ + +#ifndef _MACH_THREAD_STATUS_H_ +#define _MACH_THREAD_STATUS_H_ + +/* + * The actual structure that comprises the thread state is defined + * in the machine dependent module. + */ +#include +#include +#include + +/* + * Generic definition for machine-dependent thread status. + */ + +typedef natural_t *thread_state_t; /* Variable-length array */ + +/* THREAD_STATE_MAX is now defined in */ +typedef natural_t thread_state_data_t[THREAD_STATE_MAX]; + +#define THREAD_STATE_FLAVOR_LIST 0 /* List of valid flavors */ +#define THREAD_STATE_FLAVOR_LIST_NEW 128 + +typedef int thread_state_flavor_t; +typedef thread_state_flavor_t *thread_state_flavor_array_t; + +#endif /* _MACH_THREAD_STATUS_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/vm_prot.h b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/vm_prot.h new file mode 100644 index 0000000000..07c2114e5c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/mach/vm_prot.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * 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_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * File: mach/vm_prot.h + * Author: Avadis Tevanian, Jr., Michael Wayne Young + * + * Virtual memory protection definitions. + * + */ + +#ifndef _MACH_VM_PROT_H_ +#define _MACH_VM_PROT_H_ + +/* + * Types defined: + * + * vm_prot_t VM protection values. + */ + +typedef int vm_prot_t; + +/* + * Protection values, defined as bits within the vm_prot_t type + */ + +#define VM_PROT_NONE ((vm_prot_t) 0x00) + +#define VM_PROT_READ ((vm_prot_t) 0x01) /* read permission */ +#define VM_PROT_WRITE ((vm_prot_t) 0x02) /* write permission */ +#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) /* execute permission */ + +/* + * The default protection for newly-created virtual memory + */ + +#define VM_PROT_DEFAULT (VM_PROT_READ|VM_PROT_WRITE) + +/* + * The maximum privileges possible, for parameter checking. + */ + +#define VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE) + +/* + * An invalid protection value. + * Used only by memory_object_lock_request to indicate no change + * to page locks. Using -1 here is a bad idea because it + * looks like VM_PROT_ALL and then some. + */ + +#define VM_PROT_NO_CHANGE ((vm_prot_t) 0x08) + +/* + * When a caller finds that he cannot obtain write permission on a + * mapped entry, the following flag can be used. The entry will + * be made "needs copy" effectively copying the object (using COW), + * and write permission will be added to the maximum protections + * for the associated entry. + */ + +#define VM_PROT_COPY ((vm_prot_t) 0x10) + + +/* + * Another invalid protection value. + * Used only by memory_object_data_request upon an object + * which has specified a copy_call copy strategy. It is used + * when the kernel wants a page belonging to a copy of the + * object, and is only asking the object as a result of + * following a shadow chain. This solves the race between pages + * being pushed up by the memory manager and the kernel + * walking down the shadow chain. + */ + +#define VM_PROT_WANTS_COPY ((vm_prot_t) 0x10) + + +/* + * Another invalid protection value. + * Indicates that the other protection bits are to be applied as a mask + * against the actual protection bits of the map entry. + */ +#define VM_PROT_IS_MASK ((vm_prot_t) 0x40) + +#endif /* _MACH_VM_PROT_H_ */ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/musl/COPYRIGHT b/toolkit/crashreporter/google-breakpad/src/third_party/musl/COPYRIGHT new file mode 100644 index 0000000000..f0ee3b78d8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/musl/COPYRIGHT @@ -0,0 +1,163 @@ +musl as a whole is licensed under the following standard MIT license: + +---------------------------------------------------------------------- +Copyright © 2005-2014 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------------- + +Authors/contributors include: + +Alex Dowad +Alexander Monakov +Anthony G. Basile +Arvid Picciani +Bobby Bingham +Boris Brezillon +Brent Cook +Chris Spiegel +Clément Vasseur +Daniel Micay +Denys Vlasenko +Emil Renner Berthing +Felix Fietkau +Felix Janda +Gianluca Anzolin +Hauke Mehrtens +Hiltjo Posthuma +Isaac Dunham +Jaydeep Patil +Jens Gustedt +Jeremy Huntwork +Jo-Philipp Wich +Joakim Sindholt +John Spencer +Josiah Worcester +Justin Cormack +Khem Raj +Kylie McClain +Luca Barbato +Luka Perkov +M Farkas-Dyck (Strake) +Mahesh Bodapati +Michael Forney +Natanael Copa +Nicholas J. Kain +orc +Pascal Cuoq +Petr Hosek +Pierre Carrier +Rich Felker +Richard Pennington +Shiz +sin +Solar Designer +Stefan Kristiansson +Szabolcs Nagy +Timo Teräs +Trutz Behn +Valentin Ochs +William Haddon + +Portions of this software are derived from third-party works licensed +under terms compatible with the above MIT license: + +The TRE regular expression implementation (src/regex/reg* and +src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +under a 2-clause BSD license (license text in the source files). The +included version has been heavily modified by Rich Felker in 2012, in +the interests of size, simplicity, and namespace cleanliness. + +Much of the math library code (src/math/* and src/complex/*) is +Copyright © 1993,2004 Sun Microsystems or +Copyright © 2003-2011 David Schultz or +Copyright © 2003-2009 Steven G. Kargl or +Copyright © 2003-2009 Bruce D. Evans or +Copyright © 2008 Stephen L. Moshier +and labelled as such in comments in the individual source files. All +have been licensed under extremely permissive terms. + +The ARM memcpy code (src/string/arm/memcpy_el.S) is Copyright © 2008 +The Android Open Source Project and is licensed under a two-clause BSD +license. It was taken from Bionic libc, used on Android. + +The implementation of DES for crypt (src/crypt/crypt_des.c) is +Copyright © 1994 David Burren. It is licensed under a BSD license. + +The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +originally written by Solar Designer and placed into the public +domain. The code also comes with a fallback permissive license for use +in jurisdictions that may not recognize the public domain. + +The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +Valentin Ochs and is licensed under an MIT-style license. + +The BSD PRNG implementation (src/prng/random.c) and XSI search API +(src/search/*.c) functions are Copyright © 2011 Szabolcs Nagy and +licensed under following terms: "Permission to use, copy, modify, +and/or distribute this code for any purpose with or without fee is +hereby granted. There is no warranty." + +The x86_64 port was written by Nicholas J. Kain and is licensed under +the standard MIT terms. + +The mips and microblaze ports were originally written by Richard +Pennington for use in the ellcc project. The original code was adapted +by Rich Felker for build system and code conventions during upstream +integration. It is licensed under the standard MIT terms. + +The mips64 port was contributed by Imagination Technologies and is +licensed under the standard MIT terms. + +The powerpc port was also originally written by Richard Pennington, +and later supplemented and integrated by John Spencer. It is licensed +under the standard MIT terms. + +All other files which have no copyright comments are original works +produced specifically for use as part of this library, written either +by Rich Felker, the main author of the library, or by one or more +contibutors listed above. Details on authorship of individual files +can be found in the git version control history of the project. The +omission of copyright and license comments in each file is in the +interest of source tree size. + +In addition, permission is hereby granted for all public header files +(include/* and arch/*/bits/*) and crt files intended to be linked into +applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit +the copyright notice and permission notice otherwise required by the +license, and to use these files without any requirement of +attribution. These files include substantial contributions from: + +Bobby Bingham +John Spencer +Nicholas J. Kain +Rich Felker +Richard Pennington +Stefan Kristiansson +Szabolcs Nagy + +all of whom have explicitly granted such permission. + +This file previously contained text expressing a belief that most of +the files covered by the above exception were sufficiently trivial not +to be subject to copyright, resulting in confusion over whether it +negated the permissions granted in the license. In the spirit of +permissive licensing, and of not having licensing issues being an +obstacle to adoption, that text has been removed. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/musl/README b/toolkit/crashreporter/google-breakpad/src/third_party/musl/README new file mode 100644 index 0000000000..a30eb11275 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/musl/README @@ -0,0 +1,23 @@ + + musl libc + +musl, pronounced like the word "mussel", is an MIT-licensed +implementation of the standard C library targetting the Linux syscall +API, suitable for use in a wide range of deployment environments. musl +offers efficient static and dynamic linking support, lightweight code +and low runtime overhead, strong fail-safe guarantees under correct +usage, and correctness in the sense of standards conformance and +safety. musl is built on the principle that these goals are best +achieved through simple code that is easy to understand and maintain. + +The 1.1 release series for musl features coverage for all interfaces +defined in ISO C99 and POSIX 2008 base, along with a number of +non-standardized interfaces for compatibility with Linux, BSD, and +glibc functionality. + +For basic installation instructions, see the included INSTALL file. +Information on full musl-targeted compiler toolchains, system +bootstrapping, and Linux distributions built on musl can be found on +the project website: + + http://www.musl-libc.org/ diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/musl/README.breakpad b/toolkit/crashreporter/google-breakpad/src/third_party/musl/README.breakpad new file mode 100644 index 0000000000..f500c4359e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/musl/README.breakpad @@ -0,0 +1,3 @@ +This directory contains the elf header from +https://git.musl-libc.org/cgit/musl/tree/ +that is required to get ELF working in dump_syms on Mac OS X. diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/musl/VERSION b/toolkit/crashreporter/google-breakpad/src/third_party/musl/VERSION new file mode 100644 index 0000000000..e9bc14996e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/musl/VERSION @@ -0,0 +1 @@ +1.1.14 diff --git a/toolkit/crashreporter/google-breakpad/src/third_party/musl/include/elf.h b/toolkit/crashreporter/google-breakpad/src/third_party/musl/include/elf.h new file mode 100644 index 0000000000..aad522e484 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/third_party/musl/include/elf.h @@ -0,0 +1,3234 @@ +#ifndef _ELF_H +#define _ELF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + +#define EI_NIDENT (16) + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +#define EI_MAG0 0 +#define ELFMAG0 0x7f + +#define EI_MAG1 1 +#define ELFMAG1 'E' + +#define EI_MAG2 2 +#define ELFMAG2 'L' + +#define EI_MAG3 3 +#define ELFMAG3 'F' + + +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define EI_DATA 5 +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 +#define ELFDATANUM 3 + +#define EI_VERSION 6 + + +#define EI_OSABI 7 +#define ELFOSABI_NONE 0 +#define ELFOSABI_SYSV 0 +#define ELFOSABI_HPUX 1 +#define ELFOSABI_NETBSD 2 +#define ELFOSABI_LINUX 3 +#define ELFOSABI_GNU 3 +#define ELFOSABI_SOLARIS 6 +#define ELFOSABI_AIX 7 +#define ELFOSABI_IRIX 8 +#define ELFOSABI_FREEBSD 9 +#define ELFOSABI_TRU64 10 +#define ELFOSABI_MODESTO 11 +#define ELFOSABI_OPENBSD 12 +#define ELFOSABI_ARM 97 +#define ELFOSABI_STANDALONE 255 + +#define EI_ABIVERSION 8 + +#define EI_PAD 9 + + + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_NUM 5 +#define ET_LOOS 0xfe00 +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + + + +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_860 7 +#define EM_MIPS 8 +#define EM_S370 9 +#define EM_MIPS_RS3_LE 10 + +#define EM_PARISC 15 +#define EM_VPP500 17 +#define EM_SPARC32PLUS 18 +#define EM_960 19 +#define EM_PPC 20 +#define EM_PPC64 21 +#define EM_S390 22 + +#define EM_V800 36 +#define EM_FR20 37 +#define EM_RH32 38 +#define EM_RCE 39 +#define EM_ARM 40 +#define EM_FAKE_ALPHA 41 +#define EM_SH 42 +#define EM_SPARCV9 43 +#define EM_TRICORE 44 +#define EM_ARC 45 +#define EM_H8_300 46 +#define EM_H8_300H 47 +#define EM_H8S 48 +#define EM_H8_500 49 +#define EM_IA_64 50 +#define EM_MIPS_X 51 +#define EM_COLDFIRE 52 +#define EM_68HC12 53 +#define EM_MMA 54 +#define EM_PCP 55 +#define EM_NCPU 56 +#define EM_NDR1 57 +#define EM_STARCORE 58 +#define EM_ME16 59 +#define EM_ST100 60 +#define EM_TINYJ 61 +#define EM_X86_64 62 +#define EM_PDSP 63 + +#define EM_FX66 66 +#define EM_ST9PLUS 67 +#define EM_ST7 68 +#define EM_68HC16 69 +#define EM_68HC11 70 +#define EM_68HC08 71 +#define EM_68HC05 72 +#define EM_SVX 73 +#define EM_ST19 74 +#define EM_VAX 75 +#define EM_CRIS 76 +#define EM_JAVELIN 77 +#define EM_FIREPATH 78 +#define EM_ZSP 79 +#define EM_MMIX 80 +#define EM_HUANY 81 +#define EM_PRISM 82 +#define EM_AVR 83 +#define EM_FR30 84 +#define EM_D10V 85 +#define EM_D30V 86 +#define EM_V850 87 +#define EM_M32R 88 +#define EM_MN10300 89 +#define EM_MN10200 90 +#define EM_PJ 91 +#define EM_OR1K 92 +#define EM_OPENRISC 92 +#define EM_ARC_A5 93 +#define EM_ARC_COMPACT 93 +#define EM_XTENSA 94 +#define EM_VIDEOCORE 95 +#define EM_TMM_GPP 96 +#define EM_NS32K 97 +#define EM_TPC 98 +#define EM_SNP1K 99 +#define EM_ST200 100 +#define EM_IP2K 101 +#define EM_MAX 102 +#define EM_CR 103 +#define EM_F2MC16 104 +#define EM_MSP430 105 +#define EM_BLACKFIN 106 +#define EM_SE_C33 107 +#define EM_SEP 108 +#define EM_ARCA 109 +#define EM_UNICORE 110 +#define EM_EXCESS 111 +#define EM_DXP 112 +#define EM_ALTERA_NIOS2 113 +#define EM_CRX 114 +#define EM_XGATE 115 +#define EM_C166 116 +#define EM_M16C 117 +#define EM_DSPIC30F 118 +#define EM_CE 119 +#define EM_M32C 120 +#define EM_TSK3000 131 +#define EM_RS08 132 +#define EM_SHARC 133 +#define EM_ECOG2 134 +#define EM_SCORE7 135 +#define EM_DSP24 136 +#define EM_VIDEOCORE3 137 +#define EM_LATTICEMICO32 138 +#define EM_SE_C17 139 +#define EM_TI_C6000 140 +#define EM_TI_C2000 141 +#define EM_TI_C5500 142 +#define EM_TI_ARP32 143 +#define EM_TI_PRU 144 +#define EM_MMDSP_PLUS 160 +#define EM_CYPRESS_M8C 161 +#define EM_R32C 162 +#define EM_TRIMEDIA 163 +#define EM_QDSP6 164 +#define EM_8051 165 +#define EM_STXP7X 166 +#define EM_NDS32 167 +#define EM_ECOG1X 168 +#define EM_MAXQ30 169 +#define EM_XIMO16 170 +#define EM_MANIK 171 +#define EM_CRAYNV2 172 +#define EM_RX 173 +#define EM_METAG 174 +#define EM_MCST_ELBRUS 175 +#define EM_ECOG16 176 +#define EM_CR16 177 +#define EM_ETPU 178 +#define EM_SLE9X 179 +#define EM_L10M 180 +#define EM_K10M 181 +#define EM_AARCH64 183 +#define EM_AVR32 185 +#define EM_STM8 186 +#define EM_TILE64 187 +#define EM_TILEPRO 188 +#define EM_MICROBLAZE 189 +#define EM_CUDA 190 +#define EM_TILEGX 191 +#define EM_CLOUDSHIELD 192 +#define EM_COREA_1ST 193 +#define EM_COREA_2ND 194 +#define EM_ARC_COMPACT2 195 +#define EM_OPEN8 196 +#define EM_RL78 197 +#define EM_VIDEOCORE5 198 +#define EM_78KOR 199 +#define EM_56800EX 200 +#define EM_BA1 201 +#define EM_BA2 202 +#define EM_XCORE 203 +#define EM_MCHP_PIC 204 +#define EM_KM32 210 +#define EM_KMX32 211 +#define EM_EMX16 212 +#define EM_EMX8 213 +#define EM_KVARC 214 +#define EM_CDP 215 +#define EM_COGE 216 +#define EM_COOL 217 +#define EM_NORC 218 +#define EM_CSR_KALIMBA 219 +#define EM_Z80 220 +#define EM_VISIUM 221 +#define EM_FT32 222 +#define EM_MOXIE 223 +#define EM_AMDGPU 224 +#define EM_RISCV 243 +#define EM_BPF 247 +#define EM_CSKY 252 +#define EM_NUM 253 + +#define EM_ALPHA 0x9026 + +#define EV_NONE 0 +#define EV_CURRENT 1 +#define EV_NUM 2 + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + + + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_BEFORE 0xff00 + +#define SHN_AFTER 0xff01 + +#define SHN_HIPROC 0xff1f +#define SHN_LOOS 0xff20 +#define SHN_HIOS 0xff3f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_XINDEX 0xffff +#define SHN_HIRESERVE 0xffff + + + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_NUM 19 +#define SHT_LOOS 0x60000000 +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 +#define SHT_GNU_HASH 0x6ffffff6 +#define SHT_GNU_LIBLIST 0x6ffffff7 +#define SHT_CHECKSUM 0x6ffffff8 +#define SHT_LOSUNW 0x6ffffffa +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd +#define SHT_GNU_verneed 0x6ffffffe +#define SHT_GNU_versym 0x6fffffff +#define SHT_HISUNW 0x6fffffff +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0x8fffffff + +#define SHF_WRITE (1 << 0) +#define SHF_ALLOC (1 << 1) +#define SHF_EXECINSTR (1 << 2) +#define SHF_MERGE (1 << 4) +#define SHF_STRINGS (1 << 5) +#define SHF_INFO_LINK (1 << 6) +#define SHF_LINK_ORDER (1 << 7) +#define SHF_OS_NONCONFORMING (1 << 8) + +#define SHF_GROUP (1 << 9) +#define SHF_TLS (1 << 10) +#define SHF_COMPRESSED (1 << 11) +#define SHF_MASKOS 0x0ff00000 +#define SHF_MASKPROC 0xf0000000 +#define SHF_ORDERED (1 << 30) +#define SHF_EXCLUDE (1U << 31) + +typedef struct { + Elf32_Word ch_type; + Elf32_Word ch_size; + Elf32_Word ch_addralign; +} Elf32_Chdr; + +typedef struct { + Elf64_Word ch_type; + Elf64_Word ch_reserved; + Elf64_Xword ch_size; + Elf64_Xword ch_addralign; +} Elf64_Chdr; + +#define ELFCOMPRESS_ZLIB 1 +#define ELFCOMPRESS_LOOS 0x60000000 +#define ELFCOMPRESS_HIOS 0x6fffffff +#define ELFCOMPRESS_LOPROC 0x70000000 +#define ELFCOMPRESS_HIPROC 0x7fffffff + + +#define GRP_COMDAT 0x1 + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Section st_shndx; +} Elf32_Sym; + +typedef struct { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Section st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +typedef struct { + Elf32_Half si_boundto; + Elf32_Half si_flags; +} Elf32_Syminfo; + +typedef struct { + Elf64_Half si_boundto; + Elf64_Half si_flags; +} Elf64_Syminfo; + +#define SYMINFO_BT_SELF 0xffff +#define SYMINFO_BT_PARENT 0xfffe +#define SYMINFO_BT_LOWRESERVE 0xff00 + +#define SYMINFO_FLG_DIRECT 0x0001 +#define SYMINFO_FLG_PASSTHRU 0x0002 +#define SYMINFO_FLG_COPY 0x0004 +#define SYMINFO_FLG_LAZYLOAD 0x0008 + +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_NUM 3 +#define STB_LOOS 10 +#define STB_GNU_UNIQUE 10 +#define STB_HIOS 12 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_NUM 7 +#define STT_LOOS 10 +#define STT_GNU_IFUNC 10 +#define STT_HIOS 12 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define STN_UNDEF 0 + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +#define STV_DEFAULT 0 +#define STV_INTERNAL 1 +#define STV_HIDDEN 2 +#define STV_PROTECTED 3 + + + + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + + + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + + + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + + + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + + + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 +#define PT_NUM 8 +#define PT_LOOS 0x60000000 +#define PT_GNU_EH_FRAME 0x6474e550 +#define PT_GNU_STACK 0x6474e551 +#define PT_GNU_RELRO 0x6474e552 +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa +#define PT_SUNWSTACK 0x6ffffffb +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + + +#define PN_XNUM 0xffff + + +#define PF_X (1 << 0) +#define PF_W (1 << 1) +#define PF_R (1 << 2) +#define PF_MASKOS 0x0ff00000 +#define PF_MASKPROC 0xf0000000 + + + +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 +#define NT_PRXREG 4 +#define NT_TASKSTRUCT 4 +#define NT_PLATFORM 5 +#define NT_AUXV 6 +#define NT_GWINDOWS 7 +#define NT_ASRS 8 +#define NT_PSTATUS 10 +#define NT_PSINFO 13 +#define NT_PRCRED 14 +#define NT_UTSNAME 15 +#define NT_LWPSTATUS 16 +#define NT_LWPSINFO 17 +#define NT_PRFPXREG 20 +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f +#define NT_PPC_VMX 0x100 +#define NT_PPC_SPE 0x101 +#define NT_PPC_VSX 0x102 +#define NT_PPC_TAR 0x103 +#define NT_PPC_PPR 0x104 +#define NT_PPC_DSCR 0x105 +#define NT_PPC_EBB 0x106 +#define NT_PPC_PMU 0x107 +#define NT_PPC_TM_CGPR 0x108 +#define NT_PPC_TM_CFPR 0x109 +#define NT_PPC_TM_CVMX 0x10a +#define NT_PPC_TM_CVSX 0x10b +#define NT_PPC_TM_SPR 0x10c +#define NT_PPC_TM_CTAR 0x10d +#define NT_PPC_TM_CPPR 0x10e +#define NT_PPC_TM_CDSCR 0x10f +#define NT_386_TLS 0x200 +#define NT_386_IOPERM 0x201 +#define NT_X86_XSTATE 0x202 +#define NT_S390_HIGH_GPRS 0x300 +#define NT_S390_TIMER 0x301 +#define NT_S390_TODCMP 0x302 +#define NT_S390_TODPREG 0x303 +#define NT_S390_CTRS 0x304 +#define NT_S390_PREFIX 0x305 +#define NT_S390_LAST_BREAK 0x306 +#define NT_S390_SYSTEM_CALL 0x307 +#define NT_S390_TDB 0x308 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c +#define NT_S390_RI_CB 0x30d +#define NT_ARM_VFP 0x400 +#define NT_ARM_TLS 0x401 +#define NT_ARM_HW_BREAK 0x402 +#define NT_ARM_HW_WATCH 0x403 +#define NT_ARM_SYSTEM_CALL 0x404 +#define NT_ARM_SVE 0x405 +#define NT_ARM_PAC_MASK 0x406 +#define NT_METAG_CBUF 0x500 +#define NT_METAG_RPIPE 0x501 +#define NT_METAG_TLS 0x502 +#define NT_ARC_V2 0x600 +#define NT_VMCOREDD 0x700 +#define NT_MIPS_DSP 0x800 +#define NT_MIPS_FP_MODE 0x801 +#define NT_MIPS_MSA 0x802 +#define NT_VERSION 1 + + + + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + + + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 32 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 +#define DT_SYMTAB_SHNDX 34 +#define DT_NUM 35 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff +#define DT_PROCNUM DT_MIPS_NUM + +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc +#define DT_POSFLAG_1 0x6ffffdfd + +#define DT_SYMINSZ 0x6ffffdfe +#define DT_SYMINENT 0x6ffffdff +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) +#define DT_VALNUM 12 + +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 +#define DT_GNU_LIBLIST 0x6ffffef9 +#define DT_CONFIG 0x6ffffefa +#define DT_DEPAUDIT 0x6ffffefb +#define DT_AUDIT 0x6ffffefc +#define DT_PLTPAD 0x6ffffefd +#define DT_MOVETAB 0x6ffffefe +#define DT_SYMINFO 0x6ffffeff +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) +#define DT_ADDRNUM 11 + + + +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + + +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc + +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe + +#define DT_VERNEEDNUM 0x6fffffff +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) +#define DT_VERSIONTAGNUM 16 + + + +#define DT_AUXILIARY 0x7ffffffd +#define DT_FILTER 0x7fffffff +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + + +#define DF_ORIGIN 0x00000001 +#define DF_SYMBOLIC 0x00000002 +#define DF_TEXTREL 0x00000004 +#define DF_BIND_NOW 0x00000008 +#define DF_STATIC_TLS 0x00000010 + + + +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONFALT 0x00002000 +#define DF_1_ENDFILTEE 0x00004000 +#define DF_1_DISPRELDNE 0x00008000 +#define DF_1_DISPRELPND 0x00010000 +#define DF_1_NODIRECT 0x00020000 +#define DF_1_IGNMULDEF 0x00040000 +#define DF_1_NOKSYMS 0x00080000 +#define DF_1_NOHDR 0x00100000 +#define DF_1_EDITED 0x00200000 +#define DF_1_NORELOC 0x00400000 +#define DF_1_SYMINTPOSE 0x00800000 +#define DF_1_GLOBAUDIT 0x01000000 +#define DF_1_SINGLETON 0x02000000 +#define DF_1_STUB 0x04000000 +#define DF_1_PIE 0x08000000 + +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + + +#define DF_P1_LAZYLOAD 0x00000001 +#define DF_P1_GROUPPERM 0x00000002 + + + + +typedef struct { + Elf32_Half vd_version; + Elf32_Half vd_flags; + Elf32_Half vd_ndx; + Elf32_Half vd_cnt; + Elf32_Word vd_hash; + Elf32_Word vd_aux; + Elf32_Word vd_next; +} Elf32_Verdef; + +typedef struct { + Elf64_Half vd_version; + Elf64_Half vd_flags; + Elf64_Half vd_ndx; + Elf64_Half vd_cnt; + Elf64_Word vd_hash; + Elf64_Word vd_aux; + Elf64_Word vd_next; +} Elf64_Verdef; + + + +#define VER_DEF_NONE 0 +#define VER_DEF_CURRENT 1 +#define VER_DEF_NUM 2 + + +#define VER_FLG_BASE 0x1 +#define VER_FLG_WEAK 0x2 + + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 +#define VER_NDX_LORESERVE 0xff00 +#define VER_NDX_ELIMINATE 0xff01 + + + +typedef struct { + Elf32_Word vda_name; + Elf32_Word vda_next; +} Elf32_Verdaux; + +typedef struct { + Elf64_Word vda_name; + Elf64_Word vda_next; +} Elf64_Verdaux; + + + + +typedef struct { + Elf32_Half vn_version; + Elf32_Half vn_cnt; + Elf32_Word vn_file; + Elf32_Word vn_aux; + Elf32_Word vn_next; +} Elf32_Verneed; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + + + +#define VER_NEED_NONE 0 +#define VER_NEED_CURRENT 1 +#define VER_NEED_NUM 2 + + + +typedef struct { + Elf32_Word vna_hash; + Elf32_Half vna_flags; + Elf32_Half vna_other; + Elf32_Word vna_name; + Elf32_Word vna_next; +} Elf32_Vernaux; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + + + +#define VER_FLG_WEAK 0x2 + + + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + + + +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 +#define AT_CLKTCK 17 + + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 + + + + +#define AT_FPUCW 18 + + +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 + + + +#define AT_IGNOREPPC 22 + +#define AT_SECURE 23 + +#define AT_BASE_PLATFORM 24 + +#define AT_RANDOM 25 + +#define AT_HWCAP2 26 + +#define AT_EXECFN 31 + + + +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + + + +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +#define AT_L1I_CACHESIZE 40 +#define AT_L1I_CACHEGEOMETRY 41 +#define AT_L1D_CACHESIZE 42 +#define AT_L1D_CACHEGEOMETRY 43 +#define AT_L2_CACHESIZE 44 +#define AT_L2_CACHEGEOMETRY 45 +#define AT_L3_CACHESIZE 46 +#define AT_L3_CACHEGEOMETRY 47 + +#define AT_MINSIGSTKSZ 51 + + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + + + + +#define ELF_NOTE_SOLARIS "SUNW Solaris" + + +#define ELF_NOTE_GNU "GNU" + + + + + +#define ELF_NOTE_PAGESIZE_HINT 1 + + +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG + + + +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +#define NT_GNU_BUILD_ID 3 +#define NT_GNU_GOLD_VERSION 4 + + + +typedef struct { + Elf32_Xword m_value; + Elf32_Word m_info; + Elf32_Word m_poffset; + Elf32_Half m_repeat; + Elf32_Half m_stride; +} Elf32_Move; + +typedef struct { + Elf64_Xword m_value; + Elf64_Xword m_info; + Elf64_Xword m_poffset; + Elf64_Half m_repeat; + Elf64_Half m_stride; +} Elf64_Move; + + +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + +#define EF_CPU32 0x00810000 + +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 +#define R_68K_TLS_GD32 25 +#define R_68K_TLS_GD16 26 +#define R_68K_TLS_GD8 27 +#define R_68K_TLS_LDM32 28 +#define R_68K_TLS_LDM16 29 +#define R_68K_TLS_LDM8 30 +#define R_68K_TLS_LDO32 31 +#define R_68K_TLS_LDO16 32 +#define R_68K_TLS_LDO8 33 +#define R_68K_TLS_IE32 34 +#define R_68K_TLS_IE16 35 +#define R_68K_TLS_IE8 36 +#define R_68K_TLS_LE32 37 +#define R_68K_TLS_LE16 38 +#define R_68K_TLS_LE8 39 +#define R_68K_TLS_DTPMOD32 40 +#define R_68K_TLS_DTPREL32 41 +#define R_68K_TLS_TPREL32 42 +#define R_68K_NUM 43 + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 +#define R_386_TLS_IE 15 +#define R_386_TLS_GOTIE 16 +#define R_386_TLS_LE 17 +#define R_386_TLS_GD 18 +#define R_386_TLS_LDM 19 +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 +#define R_386_TLS_GD_PUSH 25 +#define R_386_TLS_GD_CALL 26 +#define R_386_TLS_GD_POP 27 +#define R_386_TLS_LDM_32 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_386_TLS_LDM_CALL 30 +#define R_386_TLS_LDM_POP 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_386_TLS_DTPMOD32 35 +#define R_386_TLS_DTPOFF32 36 +#define R_386_TLS_TPOFF32 37 +#define R_386_SIZE32 38 +#define R_386_TLS_GOTDESC 39 +#define R_386_TLS_DESC_CALL 40 +#define R_386_TLS_DESC 41 +#define R_386_IRELATIVE 42 +#define R_386_GOT32X 43 +#define R_386_NUM 44 + + + + + +#define STT_SPARC_REGISTER 13 + + + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 +#define EF_SPARC_SUN_US1 0x000200 +#define EF_SPARC_HAL_R1 0x000400 +#define EF_SPARC_SUN_US3 0x000800 + + + +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 + + + +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_HH22 34 +#define R_SPARC_HM10 35 +#define R_SPARC_LM22 36 +#define R_SPARC_PC_HH22 37 +#define R_SPARC_PC_HM10 38 +#define R_SPARC_PC_LM22 39 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_GLOB_JMP 42 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 +#define R_SPARC_DISP64 46 +#define R_SPARC_PLT64 47 +#define R_SPARC_HIX22 48 +#define R_SPARC_LOX10 49 +#define R_SPARC_H44 50 +#define R_SPARC_M44 51 +#define R_SPARC_L44 52 +#define R_SPARC_REGISTER 53 +#define R_SPARC_UA64 54 +#define R_SPARC_UA16 55 +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 + +#define R_SPARC_NUM 253 + + + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + + +#define EF_MIPS_NOREORDER 1 +#define EF_MIPS_PIC 2 +#define EF_MIPS_CPIC 4 +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_FP64 512 +#define EF_MIPS_NAN2008 1024 +#define EF_MIPS_ARCH 0xf0000000 + + + +#define EF_MIPS_ARCH_1 0x00000000 +#define EF_MIPS_ARCH_2 0x10000000 +#define EF_MIPS_ARCH_3 0x20000000 +#define EF_MIPS_ARCH_4 0x30000000 +#define EF_MIPS_ARCH_5 0x40000000 +#define EF_MIPS_ARCH_32 0x50000000 +#define EF_MIPS_ARCH_64 0x60000000 +#define EF_MIPS_ARCH_32R2 0x70000000 +#define EF_MIPS_ARCH_64R2 0x80000000 + + +#define E_MIPS_ARCH_1 0x00000000 +#define E_MIPS_ARCH_2 0x10000000 +#define E_MIPS_ARCH_3 0x20000000 +#define E_MIPS_ARCH_4 0x30000000 +#define E_MIPS_ARCH_5 0x40000000 +#define E_MIPS_ARCH_32 0x50000000 +#define E_MIPS_ARCH_64 0x60000000 + + + +#define SHN_MIPS_ACOMMON 0xff00 +#define SHN_MIPS_TEXT 0xff01 +#define SHN_MIPS_DATA 0xff02 +#define SHN_MIPS_SCOMMON 0xff03 +#define SHN_MIPS_SUNDEFINED 0xff04 + + + +#define SHT_MIPS_LIBLIST 0x70000000 +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 +#define SHT_MIPS_DEBUG 0x70000005 +#define SHT_MIPS_REGINFO 0x70000006 +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + + + +#define SHF_MIPS_GPREL 0x10000000 +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + + + + +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + + +#define STB_MIPS_SPLIT_COMMON 13 + + + +typedef union { + struct { + Elf32_Word gt_current_g_value; + Elf32_Word gt_unused; + } gt_header; + struct { + Elf32_Word gt_g_value; + Elf32_Word gt_bytes; + } gt_entry; +} Elf32_gptab; + + + +typedef struct { + Elf32_Word ri_gprmask; + Elf32_Word ri_cprmask[4]; + Elf32_Sword ri_gp_value; +} Elf32_RegInfo; + + + +typedef struct { + unsigned char kind; + + unsigned char size; + Elf32_Section section; + + Elf32_Word info; +} Elf_Options; + + + +#define ODK_NULL 0 +#define ODK_REGINFO 1 +#define ODK_EXCEPTIONS 2 +#define ODK_PAD 3 +#define ODK_HWPATCH 4 +#define ODK_FILL 5 +#define ODK_TAGS 6 +#define ODK_HWAND 7 +#define ODK_HWOR 8 + + + +#define OEX_FPU_MIN 0x1f +#define OEX_FPU_MAX 0x1f00 +#define OEX_PAGE0 0x10000 +#define OEX_SMM 0x20000 +#define OEX_FPDBUG 0x40000 +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + + + +#define OHW_R4KEOP 0x1 +#define OHW_R8KPFETCH 0x2 +#define OHW_R5KEOP 0x4 +#define OHW_R5KCVTL 0x8 + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + + + +typedef struct { + Elf32_Word hwp_flags1; + Elf32_Word hwp_flags2; +} Elf_Options_Hw; + + + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + + + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 +#define R_MIPS_TLS_DTPREL32 39 +#define R_MIPS_TLS_DTPMOD64 40 +#define R_MIPS_TLS_DTPREL64 41 +#define R_MIPS_TLS_GD 42 +#define R_MIPS_TLS_LDM 43 +#define R_MIPS_TLS_DTPREL_HI16 44 +#define R_MIPS_TLS_DTPREL_LO16 45 +#define R_MIPS_TLS_GOTTPREL 46 +#define R_MIPS_TLS_TPREL32 47 +#define R_MIPS_TLS_TPREL64 48 +#define R_MIPS_TLS_TPREL_HI16 49 +#define R_MIPS_TLS_TPREL_LO16 50 +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 + +#define R_MIPS_NUM 128 + + + +#define PT_MIPS_REGINFO 0x70000000 +#define PT_MIPS_RTPROC 0x70000001 +#define PT_MIPS_OPTIONS 0x70000002 +#define PT_MIPS_ABIFLAGS 0x70000003 + + + +#define PF_MIPS_LOCAL 0x10000000 + + + +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 +#define DT_MIPS_DELTA_CLASS 0x70000017 +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 + +#define DT_MIPS_DELTA_INSTANCE 0x70000019 +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a + +#define DT_MIPS_DELTA_RELOC 0x7000001b +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c + +#define DT_MIPS_DELTA_SYM 0x7000001d + +#define DT_MIPS_DELTA_SYM_NO 0x7000001e + +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 + +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 + +#define DT_MIPS_CXX_FLAGS 0x70000022 +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 +#define DT_MIPS_INTERFACE 0x7000002a +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d + +#define DT_MIPS_PERF_SUFFIX 0x7000002e + +#define DT_MIPS_COMPACT_SIZE 0x7000002f +#define DT_MIPS_GP_VALUE 0x70000030 +#define DT_MIPS_AUX_DYNAMIC 0x70000031 + +#define DT_MIPS_PLTGOT 0x70000032 + +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_RLD_MAP_REL 0x70000035 +#define DT_MIPS_NUM 0x36 + + + +#define RHF_NONE 0 +#define RHF_QUICKSTART (1 << 0) +#define RHF_NOTPOT (1 << 1) +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + + + +typedef struct { + Elf32_Word l_name; + Elf32_Word l_time_stamp; + Elf32_Word l_checksum; + Elf32_Word l_version; + Elf32_Word l_flags; +} Elf32_Lib; + +typedef struct { + Elf64_Word l_name; + Elf64_Word l_time_stamp; + Elf64_Word l_checksum; + Elf64_Word l_version; + Elf64_Word l_flags; +} Elf64_Lib; + + + + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) +#define LL_IGNORE_INT_VER (1 << 1) +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + + + +typedef Elf32_Addr Elf32_Conflict; + +typedef struct { + Elf32_Half version; + unsigned char isa_level; + unsigned char isa_rev; + unsigned char gpr_size; + unsigned char cpr1_size; + unsigned char cpr2_size; + unsigned char fp_abi; + Elf32_Word isa_ext; + Elf32_Word ases; + Elf32_Word flags1; + Elf32_Word flags2; +} Elf_MIPS_ABIFlags_v0; + +#define MIPS_AFL_REG_NONE 0x00 +#define MIPS_AFL_REG_32 0x01 +#define MIPS_AFL_REG_64 0x02 +#define MIPS_AFL_REG_128 0x03 + +#define MIPS_AFL_ASE_DSP 0x00000001 +#define MIPS_AFL_ASE_DSPR2 0x00000002 +#define MIPS_AFL_ASE_EVA 0x00000004 +#define MIPS_AFL_ASE_MCU 0x00000008 +#define MIPS_AFL_ASE_MDMX 0x00000010 +#define MIPS_AFL_ASE_MIPS3D 0x00000020 +#define MIPS_AFL_ASE_MT 0x00000040 +#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 +#define MIPS_AFL_ASE_VIRT 0x00000100 +#define MIPS_AFL_ASE_MSA 0x00000200 +#define MIPS_AFL_ASE_MIPS16 0x00000400 +#define MIPS_AFL_ASE_MICROMIPS 0x00000800 +#define MIPS_AFL_ASE_XPA 0x00001000 +#define MIPS_AFL_ASE_MASK 0x00001fff + +#define MIPS_AFL_EXT_XLR 1 +#define MIPS_AFL_EXT_OCTEON2 2 +#define MIPS_AFL_EXT_OCTEONP 3 +#define MIPS_AFL_EXT_LOONGSON_3A 4 +#define MIPS_AFL_EXT_OCTEON 5 +#define MIPS_AFL_EXT_5900 6 +#define MIPS_AFL_EXT_4650 7 +#define MIPS_AFL_EXT_4010 8 +#define MIPS_AFL_EXT_4100 9 +#define MIPS_AFL_EXT_3900 10 +#define MIPS_AFL_EXT_10000 11 +#define MIPS_AFL_EXT_SB1 12 +#define MIPS_AFL_EXT_4111 13 +#define MIPS_AFL_EXT_4120 14 +#define MIPS_AFL_EXT_5400 15 +#define MIPS_AFL_EXT_5500 16 +#define MIPS_AFL_EXT_LOONGSON_2E 17 +#define MIPS_AFL_EXT_LOONGSON_2F 18 + +#define MIPS_AFL_FLAGS1_ODDSPREG 1 + +enum +{ + Val_GNU_MIPS_ABI_FP_ANY = 0, + Val_GNU_MIPS_ABI_FP_DOUBLE = 1, + Val_GNU_MIPS_ABI_FP_SINGLE = 2, + Val_GNU_MIPS_ABI_FP_SOFT = 3, + Val_GNU_MIPS_ABI_FP_OLD_64 = 4, + Val_GNU_MIPS_ABI_FP_XX = 5, + Val_GNU_MIPS_ABI_FP_64 = 6, + Val_GNU_MIPS_ABI_FP_64A = 7, + Val_GNU_MIPS_ABI_FP_MAX = 7 +}; + + + + +#define EF_PARISC_TRAPNIL 0x00010000 +#define EF_PARISC_EXT 0x00020000 +#define EF_PARISC_LSB 0x00040000 +#define EF_PARISC_WIDE 0x00080000 +#define EF_PARISC_NO_KABP 0x00100000 + +#define EF_PARISC_LAZYSWAP 0x00400000 +#define EF_PARISC_ARCH 0x0000ffff + + + +#define EFA_PARISC_1_0 0x020b +#define EFA_PARISC_1_1 0x0210 +#define EFA_PARISC_2_0 0x0214 + + + +#define SHN_PARISC_ANSI_COMMON 0xff00 + +#define SHN_PARISC_HUGE_COMMON 0xff01 + + + +#define SHT_PARISC_EXT 0x70000000 +#define SHT_PARISC_UNWIND 0x70000001 +#define SHT_PARISC_DOC 0x70000002 + + + +#define SHF_PARISC_SHORT 0x20000000 +#define SHF_PARISC_HUGE 0x40000000 +#define SHF_PARISC_SBP 0x80000000 + + + +#define STT_PARISC_MILLICODE 13 + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + + + +#define R_PARISC_NONE 0 +#define R_PARISC_DIR32 1 +#define R_PARISC_DIR21L 2 +#define R_PARISC_DIR17R 3 +#define R_PARISC_DIR17F 4 +#define R_PARISC_DIR14R 6 +#define R_PARISC_PCREL32 9 +#define R_PARISC_PCREL21L 10 +#define R_PARISC_PCREL17R 11 +#define R_PARISC_PCREL17F 12 +#define R_PARISC_PCREL14R 14 +#define R_PARISC_DPREL21L 18 +#define R_PARISC_DPREL14R 22 +#define R_PARISC_GPREL21L 26 +#define R_PARISC_GPREL14R 30 +#define R_PARISC_LTOFF21L 34 +#define R_PARISC_LTOFF14R 38 +#define R_PARISC_SECREL32 41 +#define R_PARISC_SEGBASE 48 +#define R_PARISC_SEGREL32 49 +#define R_PARISC_PLTOFF21L 50 +#define R_PARISC_PLTOFF14R 54 +#define R_PARISC_LTOFF_FPTR32 57 +#define R_PARISC_LTOFF_FPTR21L 58 +#define R_PARISC_LTOFF_FPTR14R 62 +#define R_PARISC_FPTR64 64 +#define R_PARISC_PLABEL32 65 +#define R_PARISC_PLABEL21L 66 +#define R_PARISC_PLABEL14R 70 +#define R_PARISC_PCREL64 72 +#define R_PARISC_PCREL22F 74 +#define R_PARISC_PCREL14WR 75 +#define R_PARISC_PCREL14DR 76 +#define R_PARISC_PCREL16F 77 +#define R_PARISC_PCREL16WF 78 +#define R_PARISC_PCREL16DF 79 +#define R_PARISC_DIR64 80 +#define R_PARISC_DIR14WR 83 +#define R_PARISC_DIR14DR 84 +#define R_PARISC_DIR16F 85 +#define R_PARISC_DIR16WF 86 +#define R_PARISC_DIR16DF 87 +#define R_PARISC_GPREL64 88 +#define R_PARISC_GPREL14WR 91 +#define R_PARISC_GPREL14DR 92 +#define R_PARISC_GPREL16F 93 +#define R_PARISC_GPREL16WF 94 +#define R_PARISC_GPREL16DF 95 +#define R_PARISC_LTOFF64 96 +#define R_PARISC_LTOFF14WR 99 +#define R_PARISC_LTOFF14DR 100 +#define R_PARISC_LTOFF16F 101 +#define R_PARISC_LTOFF16WF 102 +#define R_PARISC_LTOFF16DF 103 +#define R_PARISC_SECREL64 104 +#define R_PARISC_SEGREL64 112 +#define R_PARISC_PLTOFF14WR 115 +#define R_PARISC_PLTOFF14DR 116 +#define R_PARISC_PLTOFF16F 117 +#define R_PARISC_PLTOFF16WF 118 +#define R_PARISC_PLTOFF16DF 119 +#define R_PARISC_LTOFF_FPTR64 120 +#define R_PARISC_LTOFF_FPTR14WR 123 +#define R_PARISC_LTOFF_FPTR14DR 124 +#define R_PARISC_LTOFF_FPTR16F 125 +#define R_PARISC_LTOFF_FPTR16WF 126 +#define R_PARISC_LTOFF_FPTR16DF 127 +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 +#define R_PARISC_IPLT 129 +#define R_PARISC_EPLT 130 +#define R_PARISC_TPREL32 153 +#define R_PARISC_TPREL21L 154 +#define R_PARISC_TPREL14R 158 +#define R_PARISC_LTOFF_TP21L 162 +#define R_PARISC_LTOFF_TP14R 166 +#define R_PARISC_LTOFF_TP14F 167 +#define R_PARISC_TPREL64 216 +#define R_PARISC_TPREL14WR 219 +#define R_PARISC_TPREL14DR 220 +#define R_PARISC_TPREL16F 221 +#define R_PARISC_TPREL16WF 222 +#define R_PARISC_TPREL16DF 223 +#define R_PARISC_LTOFF_TP64 224 +#define R_PARISC_LTOFF_TP14WR 227 +#define R_PARISC_LTOFF_TP14DR 228 +#define R_PARISC_LTOFF_TP16F 229 +#define R_PARISC_LTOFF_TP16WF 230 +#define R_PARISC_LTOFF_TP16DF 231 +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 +#define R_PARISC_TLS_GD14R 235 +#define R_PARISC_TLS_GDCALL 236 +#define R_PARISC_TLS_LDM21L 237 +#define R_PARISC_TLS_LDM14R 238 +#define R_PARISC_TLS_LDMCALL 239 +#define R_PARISC_TLS_LDO21L 240 +#define R_PARISC_TLS_LDO14R 241 +#define R_PARISC_TLS_DTPMOD32 242 +#define R_PARISC_TLS_DTPMOD64 243 +#define R_PARISC_TLS_DTPOFF32 244 +#define R_PARISC_TLS_DTPOFF64 245 +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + + + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + + + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + + + + + +#define EF_ALPHA_32BIT 1 +#define EF_ALPHA_CANRELAX 2 + + + + +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + + + +#define SHF_ALPHA_GPREL 0x10000000 + + +#define STO_ALPHA_NOPV 0x80 +#define STO_ALPHA_STD_GPLOAD 0x88 + + + +#define R_ALPHA_NONE 0 +#define R_ALPHA_REFLONG 1 +#define R_ALPHA_REFQUAD 2 +#define R_ALPHA_GPREL32 3 +#define R_ALPHA_LITERAL 4 +#define R_ALPHA_LITUSE 5 +#define R_ALPHA_GPDISP 6 +#define R_ALPHA_BRADDR 7 +#define R_ALPHA_HINT 8 +#define R_ALPHA_SREL16 9 +#define R_ALPHA_SREL32 10 +#define R_ALPHA_SREL64 11 +#define R_ALPHA_GPRELHIGH 17 +#define R_ALPHA_GPRELLOW 18 +#define R_ALPHA_GPREL16 19 +#define R_ALPHA_COPY 24 +#define R_ALPHA_GLOB_DAT 25 +#define R_ALPHA_JMP_SLOT 26 +#define R_ALPHA_RELATIVE 27 +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define R_ALPHA_NUM 46 + + +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + + +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + + + + +#define EF_PPC_EMB 0x80000000 + + +#define EF_PPC_RELOCATABLE 0x00010000 +#define EF_PPC_RELOCATABLE_LIB 0x00008000 + + + +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 +#define R_PPC_ADDR24 2 +#define R_PPC_ADDR16 3 +#define R_PPC_ADDR16_LO 4 +#define R_PPC_ADDR16_HI 5 +#define R_PPC_ADDR16_HA 6 +#define R_PPC_ADDR14 7 +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 +#define R_PPC_REL14 11 +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + + +#define R_PPC_TLS 67 +#define R_PPC_DTPMOD32 68 +#define R_PPC_TPREL16 69 +#define R_PPC_TPREL16_LO 70 +#define R_PPC_TPREL16_HI 71 +#define R_PPC_TPREL16_HA 72 +#define R_PPC_TPREL32 73 +#define R_PPC_DTPREL16 74 +#define R_PPC_DTPREL16_LO 75 +#define R_PPC_DTPREL16_HI 76 +#define R_PPC_DTPREL16_HA 77 +#define R_PPC_DTPREL32 78 +#define R_PPC_GOT_TLSGD16 79 +#define R_PPC_GOT_TLSGD16_LO 80 +#define R_PPC_GOT_TLSGD16_HI 81 +#define R_PPC_GOT_TLSGD16_HA 82 +#define R_PPC_GOT_TLSLD16 83 +#define R_PPC_GOT_TLSLD16_LO 84 +#define R_PPC_GOT_TLSLD16_HI 85 +#define R_PPC_GOT_TLSLD16_HA 86 +#define R_PPC_GOT_TPREL16 87 +#define R_PPC_GOT_TPREL16_LO 88 +#define R_PPC_GOT_TPREL16_HI 89 +#define R_PPC_GOT_TPREL16_HA 90 +#define R_PPC_GOT_DTPREL16 91 +#define R_PPC_GOT_DTPREL16_LO 92 +#define R_PPC_GOT_DTPREL16_HI 93 +#define R_PPC_GOT_DTPREL16_HA 94 +#define R_PPC_TLSGD 95 +#define R_PPC_TLSLD 96 + + +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 + + +#define R_PPC_DIAB_SDA21_LO 180 +#define R_PPC_DIAB_SDA21_HI 181 +#define R_PPC_DIAB_SDA21_HA 182 +#define R_PPC_DIAB_RELSDA_LO 183 +#define R_PPC_DIAB_RELSDA_HI 184 +#define R_PPC_DIAB_RELSDA_HA 185 + + +#define R_PPC_IRELATIVE 248 + + +#define R_PPC_REL16 249 +#define R_PPC_REL16_LO 250 +#define R_PPC_REL16_HI 251 +#define R_PPC_REL16_HA 252 + + + +#define R_PPC_TOC16 255 + + +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_OPT (DT_LOPROC + 1) +#define DT_PPC_NUM 2 + +#define PPC_OPT_TLS 1 + + +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 +#define R_PPC64_ADDR24 R_PPC_ADDR24 +#define R_PPC64_ADDR16 R_PPC_ADDR16 +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA +#define R_PPC64_ADDR14 R_PPC_ADDR14 +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 +#define R_PPC64_REL14 R_PPC_REL14 +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 +#define R_PPC64_ADDR64 38 +#define R_PPC64_ADDR16_HIGHER 39 +#define R_PPC64_ADDR16_HIGHERA 40 +#define R_PPC64_ADDR16_HIGHEST 41 +#define R_PPC64_ADDR16_HIGHESTA 42 +#define R_PPC64_UADDR64 43 +#define R_PPC64_REL64 44 +#define R_PPC64_PLT64 45 +#define R_PPC64_PLTREL64 46 +#define R_PPC64_TOC16 47 +#define R_PPC64_TOC16_LO 48 +#define R_PPC64_TOC16_HI 49 +#define R_PPC64_TOC16_HA 50 +#define R_PPC64_TOC 51 +#define R_PPC64_PLTGOT16 52 +#define R_PPC64_PLTGOT16_LO 53 +#define R_PPC64_PLTGOT16_HI 54 +#define R_PPC64_PLTGOT16_HA 55 + +#define R_PPC64_ADDR16_DS 56 +#define R_PPC64_ADDR16_LO_DS 57 +#define R_PPC64_GOT16_DS 58 +#define R_PPC64_GOT16_LO_DS 59 +#define R_PPC64_PLT16_LO_DS 60 +#define R_PPC64_SECTOFF_DS 61 +#define R_PPC64_SECTOFF_LO_DS 62 +#define R_PPC64_TOC16_DS 63 +#define R_PPC64_TOC16_LO_DS 64 +#define R_PPC64_PLTGOT16_DS 65 +#define R_PPC64_PLTGOT16_LO_DS 66 + + +#define R_PPC64_TLS 67 +#define R_PPC64_DTPMOD64 68 +#define R_PPC64_TPREL16 69 +#define R_PPC64_TPREL16_LO 70 +#define R_PPC64_TPREL16_HI 71 +#define R_PPC64_TPREL16_HA 72 +#define R_PPC64_TPREL64 73 +#define R_PPC64_DTPREL16 74 +#define R_PPC64_DTPREL16_LO 75 +#define R_PPC64_DTPREL16_HI 76 +#define R_PPC64_DTPREL16_HA 77 +#define R_PPC64_DTPREL64 78 +#define R_PPC64_GOT_TLSGD16 79 +#define R_PPC64_GOT_TLSGD16_LO 80 +#define R_PPC64_GOT_TLSGD16_HI 81 +#define R_PPC64_GOT_TLSGD16_HA 82 +#define R_PPC64_GOT_TLSLD16 83 +#define R_PPC64_GOT_TLSLD16_LO 84 +#define R_PPC64_GOT_TLSLD16_HI 85 +#define R_PPC64_GOT_TLSLD16_HA 86 +#define R_PPC64_GOT_TPREL16_DS 87 +#define R_PPC64_GOT_TPREL16_LO_DS 88 +#define R_PPC64_GOT_TPREL16_HI 89 +#define R_PPC64_GOT_TPREL16_HA 90 +#define R_PPC64_GOT_DTPREL16_DS 91 +#define R_PPC64_GOT_DTPREL16_LO_DS 92 +#define R_PPC64_GOT_DTPREL16_HI 93 +#define R_PPC64_GOT_DTPREL16_HA 94 +#define R_PPC64_TPREL16_DS 95 +#define R_PPC64_TPREL16_LO_DS 96 +#define R_PPC64_TPREL16_HIGHER 97 +#define R_PPC64_TPREL16_HIGHERA 98 +#define R_PPC64_TPREL16_HIGHEST 99 +#define R_PPC64_TPREL16_HIGHESTA 100 +#define R_PPC64_DTPREL16_DS 101 +#define R_PPC64_DTPREL16_LO_DS 102 +#define R_PPC64_DTPREL16_HIGHER 103 +#define R_PPC64_DTPREL16_HIGHERA 104 +#define R_PPC64_DTPREL16_HIGHEST 105 +#define R_PPC64_DTPREL16_HIGHESTA 106 +#define R_PPC64_TLSGD 107 +#define R_PPC64_TLSLD 108 +#define R_PPC64_TOCSAVE 109 +#define R_PPC64_ADDR16_HIGH 110 +#define R_PPC64_ADDR16_HIGHA 111 +#define R_PPC64_TPREL16_HIGH 112 +#define R_PPC64_TPREL16_HIGHA 113 +#define R_PPC64_DTPREL16_HIGH 114 +#define R_PPC64_DTPREL16_HIGHA 115 + + +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 +#define R_PPC64_REL16_LO 250 +#define R_PPC64_REL16_HI 251 +#define R_PPC64_REL16_HA 252 + +#define EF_PPC64_ABI 3 + +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_OPT (DT_LOPROC + 3) +#define DT_PPC64_NUM 4 + +#define PPC64_OPT_TLS 1 +#define PPC64_OPT_MULTI_TOC 2 +#define PPC64_OPT_LOCALENTRY 4 + +#define STO_PPC64_LOCAL_BIT 5 +#define STO_PPC64_LOCAL_MASK 0xe0 +#define PPC64_LOCAL_ENTRY_OFFSET(x) (1 << (((x)&0xe0)>>5) & 0xfc) + + +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +#define EF_ARM_ABI_FLOAT_SOFT 0x200 +#define EF_ARM_ABI_FLOAT_HARD 0x400 + + +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + + +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + + +#define STT_ARM_TFUNC STT_LOPROC +#define STT_ARM_16BIT STT_HIPROC + + +#define SHF_ARM_ENTRYSECT 0x10000000 +#define SHF_ARM_COMDEF 0x80000000 + + + +#define PF_ARM_SB 0x10000000 + +#define PF_ARM_PI 0x20000000 +#define PF_ARM_ABS 0x40000000 + + +#define PT_ARM_EXIDX (PT_LOPROC + 1) + + +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) + +#define R_AARCH64_NONE 0 +#define R_AARCH64_P32_ABS32 1 +#define R_AARCH64_P32_COPY 180 +#define R_AARCH64_P32_GLOB_DAT 181 +#define R_AARCH64_P32_JUMP_SLOT 182 +#define R_AARCH64_P32_RELATIVE 183 +#define R_AARCH64_P32_TLS_DTPMOD 184 +#define R_AARCH64_P32_TLS_DTPREL 185 +#define R_AARCH64_P32_TLS_TPREL 186 +#define R_AARCH64_P32_TLSDESC 187 +#define R_AARCH64_P32_IRELATIVE 188 +#define R_AARCH64_ABS64 257 +#define R_AARCH64_ABS32 258 +#define R_AARCH64_ABS16 259 +#define R_AARCH64_PREL64 260 +#define R_AARCH64_PREL32 261 +#define R_AARCH64_PREL16 262 +#define R_AARCH64_MOVW_UABS_G0 263 +#define R_AARCH64_MOVW_UABS_G0_NC 264 +#define R_AARCH64_MOVW_UABS_G1 265 +#define R_AARCH64_MOVW_UABS_G1_NC 266 +#define R_AARCH64_MOVW_UABS_G2 267 +#define R_AARCH64_MOVW_UABS_G2_NC 268 +#define R_AARCH64_MOVW_UABS_G3 269 +#define R_AARCH64_MOVW_SABS_G0 270 +#define R_AARCH64_MOVW_SABS_G1 271 +#define R_AARCH64_MOVW_SABS_G2 272 +#define R_AARCH64_LD_PREL_LO19 273 +#define R_AARCH64_ADR_PREL_LO21 274 +#define R_AARCH64_ADR_PREL_PG_HI21 275 +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 +#define R_AARCH64_ADD_ABS_LO12_NC 277 +#define R_AARCH64_LDST8_ABS_LO12_NC 278 +#define R_AARCH64_TSTBR14 279 +#define R_AARCH64_CONDBR19 280 +#define R_AARCH64_JUMP26 282 +#define R_AARCH64_CALL26 283 +#define R_AARCH64_LDST16_ABS_LO12_NC 284 +#define R_AARCH64_LDST32_ABS_LO12_NC 285 +#define R_AARCH64_LDST64_ABS_LO12_NC 286 +#define R_AARCH64_MOVW_PREL_G0 287 +#define R_AARCH64_MOVW_PREL_G0_NC 288 +#define R_AARCH64_MOVW_PREL_G1 289 +#define R_AARCH64_MOVW_PREL_G1_NC 290 +#define R_AARCH64_MOVW_PREL_G2 291 +#define R_AARCH64_MOVW_PREL_G2_NC 292 +#define R_AARCH64_MOVW_PREL_G3 293 +#define R_AARCH64_LDST128_ABS_LO12_NC 299 +#define R_AARCH64_MOVW_GOTOFF_G0 300 +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 +#define R_AARCH64_MOVW_GOTOFF_G1 302 +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 +#define R_AARCH64_MOVW_GOTOFF_G2 304 +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 +#define R_AARCH64_MOVW_GOTOFF_G3 306 +#define R_AARCH64_GOTREL64 307 +#define R_AARCH64_GOTREL32 308 +#define R_AARCH64_GOT_LD_PREL19 309 +#define R_AARCH64_LD64_GOTOFF_LO15 310 +#define R_AARCH64_ADR_GOT_PAGE 311 +#define R_AARCH64_LD64_GOT_LO12_NC 312 +#define R_AARCH64_LD64_GOTPAGE_LO15 313 +#define R_AARCH64_TLSGD_ADR_PREL21 512 +#define R_AARCH64_TLSGD_ADR_PAGE21 513 +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 +#define R_AARCH64_TLSGD_MOVW_G1 515 +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 +#define R_AARCH64_TLSLD_ADR_PREL21 517 +#define R_AARCH64_TLSLD_ADR_PAGE21 518 +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 +#define R_AARCH64_TLSLD_MOVW_G1 520 +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 +#define R_AARCH64_TLSLD_LD_PREL19 522 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 +#define R_AARCH64_TLSDESC_LD_PREL19 560 +#define R_AARCH64_TLSDESC_ADR_PREL21 561 +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 +#define R_AARCH64_TLSDESC_LD64_LO12 563 +#define R_AARCH64_TLSDESC_ADD_LO12 564 +#define R_AARCH64_TLSDESC_OFF_G1 565 +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 +#define R_AARCH64_TLSDESC_LDR 567 +#define R_AARCH64_TLSDESC_ADD 568 +#define R_AARCH64_TLSDESC_CALL 569 +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 +#define R_AARCH64_COPY 1024 +#define R_AARCH64_GLOB_DAT 1025 +#define R_AARCH64_JUMP_SLOT 1026 +#define R_AARCH64_RELATIVE 1027 +#define R_AARCH64_TLS_DTPMOD 1028 +#define R_AARCH64_TLS_DTPMOD64 1028 +#define R_AARCH64_TLS_DTPREL 1029 +#define R_AARCH64_TLS_DTPREL64 1029 +#define R_AARCH64_TLS_TPREL 1030 +#define R_AARCH64_TLS_TPREL64 1030 +#define R_AARCH64_TLSDESC 1031 + + +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 +#define R_ARM_REL32 3 +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 +#define R_ARM_ABS12 6 +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_TLS_DESC 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 +#define R_ARM_TLS_DTPOFF32 18 +#define R_ARM_TLS_TPOFF32 19 +#define R_ARM_COPY 20 +#define R_ARM_GLOB_DAT 21 +#define R_ARM_JUMP_SLOT 22 +#define R_ARM_RELATIVE 23 +#define R_ARM_GOTOFF 24 +#define R_ARM_GOTPC 25 +#define R_ARM_GOT32 26 +#define R_ARM_PLT32 27 +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_MOVW_PREL_NC 45 +#define R_ARM_MOVT_PREL 46 +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 +#define R_ARM_THM_JUMP19 51 +#define R_ARM_THM_JUMP6 52 +#define R_ARM_THM_ALU_PREL_11_0 53 +#define R_ARM_THM_PC12 54 +#define R_ARM_ABS32_NOI 55 +#define R_ARM_REL32_NOI 56 +#define R_ARM_ALU_PC_G0_NC 57 +#define R_ARM_ALU_PC_G0 58 +#define R_ARM_ALU_PC_G1_NC 59 +#define R_ARM_ALU_PC_G1 60 +#define R_ARM_ALU_PC_G2 61 +#define R_ARM_LDR_PC_G1 62 +#define R_ARM_LDR_PC_G2 63 +#define R_ARM_LDRS_PC_G0 64 +#define R_ARM_LDRS_PC_G1 65 +#define R_ARM_LDRS_PC_G2 66 +#define R_ARM_LDC_PC_G0 67 +#define R_ARM_LDC_PC_G1 68 +#define R_ARM_LDC_PC_G2 69 +#define R_ARM_ALU_SB_G0_NC 70 +#define R_ARM_ALU_SB_G0 71 +#define R_ARM_ALU_SB_G1_NC 72 +#define R_ARM_ALU_SB_G1 73 +#define R_ARM_ALU_SB_G2 74 +#define R_ARM_LDR_SB_G0 75 +#define R_ARM_LDR_SB_G1 76 +#define R_ARM_LDR_SB_G2 77 +#define R_ARM_LDRS_SB_G0 78 +#define R_ARM_LDRS_SB_G1 79 +#define R_ARM_LDRS_SB_G2 80 +#define R_ARM_LDC_SB_G0 81 +#define R_ARM_LDC_SB_G1 82 +#define R_ARM_LDC_SB_G2 83 +#define R_ARM_MOVW_BREL_NC 84 +#define R_ARM_MOVT_BREL 85 +#define R_ARM_MOVW_BREL 86 +#define R_ARM_THM_MOVW_BREL_NC 87 +#define R_ARM_THM_MOVT_BREL 88 +#define R_ARM_THM_MOVW_BREL 89 +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_PLT32_ABS 94 +#define R_ARM_GOT_ABS 95 +#define R_ARM_GOT_PREL 96 +#define R_ARM_GOT_BREL12 97 +#define R_ARM_GOTOFF12 98 +#define R_ARM_GOTRELAX 99 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 +#define R_ARM_THM_PC9 103 +#define R_ARM_TLS_GD32 104 + +#define R_ARM_TLS_LDM32 105 + +#define R_ARM_TLS_LDO32 106 + +#define R_ARM_TLS_IE32 107 + +#define R_ARM_TLS_LE32 108 +#define R_ARM_TLS_LDO12 109 +#define R_ARM_TLS_LE12 110 +#define R_ARM_TLS_IE12GP 111 +#define R_ARM_ME_TOO 128 +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_THM_TLS_DESCSEQ16 129 +#define R_ARM_THM_TLS_DESCSEQ32 130 +#define R_ARM_THM_GOT_BREL12 131 +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 + +#define R_ARM_NUM 256 + + +#define R_CKCORE_NONE 0 +#define R_CKCORE_ADDR32 1 +#define R_CKCORE_PCRELIMM8BY4 2 +#define R_CKCORE_PCRELIMM11BY2 3 +#define R_CKCORE_PCREL32 5 +#define R_CKCORE_PCRELJSR_IMM11BY2 6 +#define R_CKCORE_RELATIVE 9 +#define R_CKCORE_COPY 10 +#define R_CKCORE_GLOB_DAT 11 +#define R_CKCORE_JUMP_SLOT 12 +#define R_CKCORE_GOTOFF 13 +#define R_CKCORE_GOTPC 14 +#define R_CKCORE_GOT32 15 +#define R_CKCORE_PLT32 16 +#define R_CKCORE_ADDRGOT 17 +#define R_CKCORE_ADDRPLT 18 +#define R_CKCORE_PCREL_IMM26BY2 19 +#define R_CKCORE_PCREL_IMM16BY2 20 +#define R_CKCORE_PCREL_IMM16BY4 21 +#define R_CKCORE_PCREL_IMM10BY2 22 +#define R_CKCORE_PCREL_IMM10BY4 23 +#define R_CKCORE_ADDR_HI16 24 +#define R_CKCORE_ADDR_LO16 25 +#define R_CKCORE_GOTPC_HI16 26 +#define R_CKCORE_GOTPC_LO16 27 +#define R_CKCORE_GOTOFF_HI16 28 +#define R_CKCORE_GOTOFF_LO16 29 +#define R_CKCORE_GOT12 30 +#define R_CKCORE_GOT_HI16 31 +#define R_CKCORE_GOT_LO16 32 +#define R_CKCORE_PLT12 33 +#define R_CKCORE_PLT_HI16 34 +#define R_CKCORE_PLT_LO16 35 +#define R_CKCORE_ADDRGOT_HI16 36 +#define R_CKCORE_ADDRGOT_LO16 37 +#define R_CKCORE_ADDRPLT_HI16 38 +#define R_CKCORE_ADDRPLT_LO16 39 +#define R_CKCORE_PCREL_JSR_IMM26BY2 40 +#define R_CKCORE_TOFFSET_LO16 41 +#define R_CKCORE_DOFFSET_LO16 42 +#define R_CKCORE_PCREL_IMM18BY2 43 +#define R_CKCORE_DOFFSET_IMM18 44 +#define R_CKCORE_DOFFSET_IMM18BY2 45 +#define R_CKCORE_DOFFSET_IMM18BY4 46 +#define R_CKCORE_GOT_IMM18BY4 48 +#define R_CKCORE_PLT_IMM18BY4 49 +#define R_CKCORE_PCREL_IMM7BY4 50 +#define R_CKCORE_TLS_LE32 51 +#define R_CKCORE_TLS_IE32 52 +#define R_CKCORE_TLS_GD32 53 +#define R_CKCORE_TLS_LDM32 54 +#define R_CKCORE_TLS_LDO32 55 +#define R_CKCORE_TLS_DTPMOD32 56 +#define R_CKCORE_TLS_DTPOFF32 57 +#define R_CKCORE_TLS_TPOFF32 58 + + +#define EF_IA_64_MASKOS 0x0000000f +#define EF_IA_64_ABI64 0x00000010 +#define EF_IA_64_ARCH 0xff000000 + + +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) +#define PT_IA_64_UNWIND (PT_LOPROC + 1) +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + + +#define PF_IA_64_NORECOV 0x80000000 + + +#define SHT_IA_64_EXT (SHT_LOPROC + 0) +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) + + +#define SHF_IA_64_SHORT 0x10000000 +#define SHF_IA_64_NORECOV 0x20000000 + + +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + + +#define R_IA64_NONE 0x00 +#define R_IA64_IMM14 0x21 +#define R_IA64_IMM22 0x22 +#define R_IA64_IMM64 0x23 +#define R_IA64_DIR32MSB 0x24 +#define R_IA64_DIR32LSB 0x25 +#define R_IA64_DIR64MSB 0x26 +#define R_IA64_DIR64LSB 0x27 +#define R_IA64_GPREL22 0x2a +#define R_IA64_GPREL64I 0x2b +#define R_IA64_GPREL32MSB 0x2c +#define R_IA64_GPREL32LSB 0x2d +#define R_IA64_GPREL64MSB 0x2e +#define R_IA64_GPREL64LSB 0x2f +#define R_IA64_LTOFF22 0x32 +#define R_IA64_LTOFF64I 0x33 +#define R_IA64_PLTOFF22 0x3a +#define R_IA64_PLTOFF64I 0x3b +#define R_IA64_PLTOFF64MSB 0x3e +#define R_IA64_PLTOFF64LSB 0x3f +#define R_IA64_FPTR64I 0x43 +#define R_IA64_FPTR32MSB 0x44 +#define R_IA64_FPTR32LSB 0x45 +#define R_IA64_FPTR64MSB 0x46 +#define R_IA64_FPTR64LSB 0x47 +#define R_IA64_PCREL60B 0x48 +#define R_IA64_PCREL21B 0x49 +#define R_IA64_PCREL21M 0x4a +#define R_IA64_PCREL21F 0x4b +#define R_IA64_PCREL32MSB 0x4c +#define R_IA64_PCREL32LSB 0x4d +#define R_IA64_PCREL64MSB 0x4e +#define R_IA64_PCREL64LSB 0x4f +#define R_IA64_LTOFF_FPTR22 0x52 +#define R_IA64_LTOFF_FPTR64I 0x53 +#define R_IA64_LTOFF_FPTR32MSB 0x54 +#define R_IA64_LTOFF_FPTR32LSB 0x55 +#define R_IA64_LTOFF_FPTR64MSB 0x56 +#define R_IA64_LTOFF_FPTR64LSB 0x57 +#define R_IA64_SEGREL32MSB 0x5c +#define R_IA64_SEGREL32LSB 0x5d +#define R_IA64_SEGREL64MSB 0x5e +#define R_IA64_SEGREL64LSB 0x5f +#define R_IA64_SECREL32MSB 0x64 +#define R_IA64_SECREL32LSB 0x65 +#define R_IA64_SECREL64MSB 0x66 +#define R_IA64_SECREL64LSB 0x67 +#define R_IA64_REL32MSB 0x6c +#define R_IA64_REL32LSB 0x6d +#define R_IA64_REL64MSB 0x6e +#define R_IA64_REL64LSB 0x6f +#define R_IA64_LTV32MSB 0x74 +#define R_IA64_LTV32LSB 0x75 +#define R_IA64_LTV64MSB 0x76 +#define R_IA64_LTV64LSB 0x77 +#define R_IA64_PCREL21BI 0x79 +#define R_IA64_PCREL22 0x7a +#define R_IA64_PCREL64I 0x7b +#define R_IA64_IPLTMSB 0x80 +#define R_IA64_IPLTLSB 0x81 +#define R_IA64_COPY 0x84 +#define R_IA64_SUB 0x85 +#define R_IA64_LTOFF22X 0x86 +#define R_IA64_LDXMOV 0x87 +#define R_IA64_TPREL14 0x91 +#define R_IA64_TPREL22 0x92 +#define R_IA64_TPREL64I 0x93 +#define R_IA64_TPREL64MSB 0x96 +#define R_IA64_TPREL64LSB 0x97 +#define R_IA64_LTOFF_TPREL22 0x9a +#define R_IA64_DTPMOD64MSB 0xa6 +#define R_IA64_DTPMOD64LSB 0xa7 +#define R_IA64_LTOFF_DTPMOD22 0xaa +#define R_IA64_DTPREL14 0xb1 +#define R_IA64_DTPREL22 0xb2 +#define R_IA64_DTPREL64I 0xb3 +#define R_IA64_DTPREL32MSB 0xb4 +#define R_IA64_DTPREL32LSB 0xb5 +#define R_IA64_DTPREL64MSB 0xb6 +#define R_IA64_DTPREL64LSB 0xb7 +#define R_IA64_LTOFF_DTPREL22 0xba + + +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 + +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +#define R_SH_GOT20 201 +#define R_SH_GOTOFF20 202 +#define R_SH_GOTFUNCDESC 203 +#define R_SH_GOTFUNCDEST20 204 +#define R_SH_GOTOFFFUNCDESC 205 +#define R_SH_GOTOFFFUNCDEST20 206 +#define R_SH_FUNCDESC 207 +#define R_SH_FUNCDESC_VALUE 208 + +#define R_SH_NUM 256 + + + +#define R_390_NONE 0 +#define R_390_8 1 +#define R_390_12 2 +#define R_390_16 3 +#define R_390_32 4 +#define R_390_PC32 5 +#define R_390_GOT12 6 +#define R_390_GOT32 7 +#define R_390_PLT32 8 +#define R_390_COPY 9 +#define R_390_GLOB_DAT 10 +#define R_390_JMP_SLOT 11 +#define R_390_RELATIVE 12 +#define R_390_GOTOFF32 13 +#define R_390_GOTPC 14 +#define R_390_GOT16 15 +#define R_390_PC16 16 +#define R_390_PC16DBL 17 +#define R_390_PLT16DBL 18 +#define R_390_PC32DBL 19 +#define R_390_PLT32DBL 20 +#define R_390_GOTPCDBL 21 +#define R_390_64 22 +#define R_390_PC64 23 +#define R_390_GOT64 24 +#define R_390_PLT64 25 +#define R_390_GOTENT 26 +#define R_390_GOTOFF16 27 +#define R_390_GOTOFF64 28 +#define R_390_GOTPLT12 29 +#define R_390_GOTPLT16 30 +#define R_390_GOTPLT32 31 +#define R_390_GOTPLT64 32 +#define R_390_GOTPLTENT 33 +#define R_390_PLTOFF16 34 +#define R_390_PLTOFF32 35 +#define R_390_PLTOFF64 36 +#define R_390_TLS_LOAD 37 +#define R_390_TLS_GDCALL 38 + +#define R_390_TLS_LDCALL 39 + +#define R_390_TLS_GD32 40 + +#define R_390_TLS_GD64 41 + +#define R_390_TLS_GOTIE12 42 + +#define R_390_TLS_GOTIE32 43 + +#define R_390_TLS_GOTIE64 44 + +#define R_390_TLS_LDM32 45 + +#define R_390_TLS_LDM64 46 + +#define R_390_TLS_IE32 47 + +#define R_390_TLS_IE64 48 + +#define R_390_TLS_IEENT 49 + +#define R_390_TLS_LE32 50 + +#define R_390_TLS_LE64 51 + +#define R_390_TLS_LDO32 52 + +#define R_390_TLS_LDO64 53 + +#define R_390_TLS_DTPMOD 54 +#define R_390_TLS_DTPOFF 55 +#define R_390_TLS_TPOFF 56 + +#define R_390_20 57 +#define R_390_GOT20 58 +#define R_390_GOTPLT20 59 +#define R_390_TLS_GOTIE20 60 + + +#define R_390_NUM 61 + + + +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + + +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 + +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 +#define R_X86_64_DTPMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 + +#define R_X86_64_TLSLD 20 + +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 + +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_SIZE32 32 +#define R_X86_64_SIZE64 33 + +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 + +#define R_X86_64_TLSDESC 36 +#define R_X86_64_IRELATIVE 37 +#define R_X86_64_RELATIVE64 38 +#define R_X86_64_GOTPCRELX 41 +#define R_X86_64_REX_GOTPCRELX 42 +#define R_X86_64_NUM 43 + + + +#define R_MN10300_NONE 0 +#define R_MN10300_32 1 +#define R_MN10300_16 2 +#define R_MN10300_8 3 +#define R_MN10300_PCREL32 4 +#define R_MN10300_PCREL16 5 +#define R_MN10300_PCREL8 6 +#define R_MN10300_GNU_VTINHERIT 7 +#define R_MN10300_GNU_VTENTRY 8 +#define R_MN10300_24 9 +#define R_MN10300_GOTPC32 10 +#define R_MN10300_GOTPC16 11 +#define R_MN10300_GOTOFF32 12 +#define R_MN10300_GOTOFF24 13 +#define R_MN10300_GOTOFF16 14 +#define R_MN10300_PLT32 15 +#define R_MN10300_PLT16 16 +#define R_MN10300_GOT32 17 +#define R_MN10300_GOT24 18 +#define R_MN10300_GOT16 19 +#define R_MN10300_COPY 20 +#define R_MN10300_GLOB_DAT 21 +#define R_MN10300_JMP_SLOT 22 +#define R_MN10300_RELATIVE 23 + +#define R_MN10300_NUM 24 + + + +#define R_M32R_NONE 0 +#define R_M32R_16 1 +#define R_M32R_32 2 +#define R_M32R_24 3 +#define R_M32R_10_PCREL 4 +#define R_M32R_18_PCREL 5 +#define R_M32R_26_PCREL 6 +#define R_M32R_HI16_ULO 7 +#define R_M32R_HI16_SLO 8 +#define R_M32R_LO16 9 +#define R_M32R_SDA16 10 +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 + +#define R_M32R_16_RELA 33 +#define R_M32R_32_RELA 34 +#define R_M32R_24_RELA 35 +#define R_M32R_10_PCREL_RELA 36 +#define R_M32R_18_PCREL_RELA 37 +#define R_M32R_26_PCREL_RELA 38 +#define R_M32R_HI16_ULO_RELA 39 +#define R_M32R_HI16_SLO_RELA 40 +#define R_M32R_LO16_RELA 41 +#define R_M32R_SDA16_RELA 42 +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 + +#define R_M32R_GOT24 48 +#define R_M32R_26_PLTREL 49 +#define R_M32R_COPY 50 +#define R_M32R_GLOB_DAT 51 +#define R_M32R_JMP_SLOT 52 +#define R_M32R_RELATIVE 53 +#define R_M32R_GOTOFF 54 +#define R_M32R_GOTPC24 55 +#define R_M32R_GOT16_HI_ULO 56 + +#define R_M32R_GOT16_HI_SLO 57 + +#define R_M32R_GOT16_LO 58 +#define R_M32R_GOTPC_HI_ULO 59 + +#define R_M32R_GOTPC_HI_SLO 60 + +#define R_M32R_GOTPC_LO 61 + +#define R_M32R_GOTOFF_HI_ULO 62 + +#define R_M32R_GOTOFF_HI_SLO 63 + +#define R_M32R_GOTOFF_LO 64 +#define R_M32R_NUM 256 + +#define R_MICROBLAZE_NONE 0 +#define R_MICROBLAZE_32 1 +#define R_MICROBLAZE_32_PCREL 2 +#define R_MICROBLAZE_64_PCREL 3 +#define R_MICROBLAZE_32_PCREL_LO 4 +#define R_MICROBLAZE_64 5 +#define R_MICROBLAZE_32_LO 6 +#define R_MICROBLAZE_SRO32 7 +#define R_MICROBLAZE_SRW32 8 +#define R_MICROBLAZE_64_NONE 9 +#define R_MICROBLAZE_32_SYM_OP_SYM 10 +#define R_MICROBLAZE_GNU_VTINHERIT 11 +#define R_MICROBLAZE_GNU_VTENTRY 12 +#define R_MICROBLAZE_GOTPC_64 13 +#define R_MICROBLAZE_GOT_64 14 +#define R_MICROBLAZE_PLT_64 15 +#define R_MICROBLAZE_REL 16 +#define R_MICROBLAZE_JUMP_SLOT 17 +#define R_MICROBLAZE_GLOB_DAT 18 +#define R_MICROBLAZE_GOTOFF_64 19 +#define R_MICROBLAZE_GOTOFF_32 20 +#define R_MICROBLAZE_COPY 21 +#define R_MICROBLAZE_TLS 22 +#define R_MICROBLAZE_TLSGD 23 +#define R_MICROBLAZE_TLSLD 24 +#define R_MICROBLAZE_TLSDTPMOD32 25 +#define R_MICROBLAZE_TLSDTPREL32 26 +#define R_MICROBLAZE_TLSDTPREL64 27 +#define R_MICROBLAZE_TLSGOTTPREL32 28 +#define R_MICROBLAZE_TLSTPREL32 29 + +#define DT_NIOS2_GP 0x70000002 + +#define R_NIOS2_NONE 0 +#define R_NIOS2_S16 1 +#define R_NIOS2_U16 2 +#define R_NIOS2_PCREL16 3 +#define R_NIOS2_CALL26 4 +#define R_NIOS2_IMM5 5 +#define R_NIOS2_CACHE_OPX 6 +#define R_NIOS2_IMM6 7 +#define R_NIOS2_IMM8 8 +#define R_NIOS2_HI16 9 +#define R_NIOS2_LO16 10 +#define R_NIOS2_HIADJ16 11 +#define R_NIOS2_BFD_RELOC_32 12 +#define R_NIOS2_BFD_RELOC_16 13 +#define R_NIOS2_BFD_RELOC_8 14 +#define R_NIOS2_GPREL 15 +#define R_NIOS2_GNU_VTINHERIT 16 +#define R_NIOS2_GNU_VTENTRY 17 +#define R_NIOS2_UJMP 18 +#define R_NIOS2_CJMP 19 +#define R_NIOS2_CALLR 20 +#define R_NIOS2_ALIGN 21 +#define R_NIOS2_GOT16 22 +#define R_NIOS2_CALL16 23 +#define R_NIOS2_GOTOFF_LO 24 +#define R_NIOS2_GOTOFF_HA 25 +#define R_NIOS2_PCREL_LO 26 +#define R_NIOS2_PCREL_HA 27 +#define R_NIOS2_TLS_GD16 28 +#define R_NIOS2_TLS_LDM16 29 +#define R_NIOS2_TLS_LDO16 30 +#define R_NIOS2_TLS_IE16 31 +#define R_NIOS2_TLS_LE16 32 +#define R_NIOS2_TLS_DTPMOD 33 +#define R_NIOS2_TLS_DTPREL 34 +#define R_NIOS2_TLS_TPREL 35 +#define R_NIOS2_COPY 36 +#define R_NIOS2_GLOB_DAT 37 +#define R_NIOS2_JUMP_SLOT 38 +#define R_NIOS2_RELATIVE 39 +#define R_NIOS2_GOTOFF 40 +#define R_NIOS2_CALL26_NOAT 41 +#define R_NIOS2_GOT_LO 42 +#define R_NIOS2_GOT_HA 43 +#define R_NIOS2_CALL_LO 44 +#define R_NIOS2_CALL_HA 45 + +#define R_OR1K_NONE 0 +#define R_OR1K_32 1 +#define R_OR1K_16 2 +#define R_OR1K_8 3 +#define R_OR1K_LO_16_IN_INSN 4 +#define R_OR1K_HI_16_IN_INSN 5 +#define R_OR1K_INSN_REL_26 6 +#define R_OR1K_GNU_VTENTRY 7 +#define R_OR1K_GNU_VTINHERIT 8 +#define R_OR1K_32_PCREL 9 +#define R_OR1K_16_PCREL 10 +#define R_OR1K_8_PCREL 11 +#define R_OR1K_GOTPC_HI16 12 +#define R_OR1K_GOTPC_LO16 13 +#define R_OR1K_GOT16 14 +#define R_OR1K_PLT26 15 +#define R_OR1K_GOTOFF_HI16 16 +#define R_OR1K_GOTOFF_LO16 17 +#define R_OR1K_COPY 18 +#define R_OR1K_GLOB_DAT 19 +#define R_OR1K_JMP_SLOT 20 +#define R_OR1K_RELATIVE 21 +#define R_OR1K_TLS_GD_HI16 22 +#define R_OR1K_TLS_GD_LO16 23 +#define R_OR1K_TLS_LDM_HI16 24 +#define R_OR1K_TLS_LDM_LO16 25 +#define R_OR1K_TLS_LDO_HI16 26 +#define R_OR1K_TLS_LDO_LO16 27 +#define R_OR1K_TLS_IE_HI16 28 +#define R_OR1K_TLS_IE_LO16 29 +#define R_OR1K_TLS_LE_HI16 30 +#define R_OR1K_TLS_LE_LO16 31 +#define R_OR1K_TLS_TPOFF 32 +#define R_OR1K_TLS_DTPOFF 33 +#define R_OR1K_TLS_DTPMOD 34 + +#define R_BPF_NONE 0 +#define R_BPF_MAP_FD 1 + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc new file mode 100644 index 0000000000..c3a9da3988 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2012, 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. + +// core2md.cc: A utility to convert an ELF core file to a minidump file. + +#include + +#include "client/linux/minidump_writer/minidump_writer.h" +#include "client/linux/minidump_writer/linux_core_dumper.h" + +using google_breakpad::AppMemoryList; +using google_breakpad::MappingList; +using google_breakpad::LinuxCoreDumper; + +static int ShowUsage(const char* argv0) { + fprintf(stderr, "Usage: %s \n", argv0); + return 1; +} + +bool WriteMinidumpFromCore(const char* filename, + const char* core_path, + const char* procfs_override) { + MappingList mappings; + AppMemoryList memory_list; + LinuxCoreDumper dumper(0, core_path, procfs_override); + return google_breakpad::WriteMinidump(filename, mappings, memory_list, + &dumper); +} + +int main(int argc, char *argv[]) { + if (argc != 4) { + return ShowUsage(argv[0]); + } + + const char* core_file = argv[1]; + const char* procfs_dir = argv[2]; + const char* minidump_file = argv[3]; + if (!WriteMinidumpFromCore(minidump_file, + core_file, + procfs_dir)) { + perror("core2md: Unable to generate minidump"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..ebdf23146c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc @@ -0,0 +1,137 @@ +// Copyright (c) 2011, 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 +#include +#include + +#include +#include +#include +#include + +#include "common/linux/dump_symbols.h" + +using google_breakpad::WriteSymbolFile; +using google_breakpad::WriteSymbolFileHeader; + +int usage(const char* self) { + fprintf(stderr, "Usage: %s [OPTION] " + "[directories-for-debug-file]\n\n", self); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -i: Output module header information only.\n"); + fprintf(stderr, " -c Do not generate CFI section\n"); + fprintf(stderr, " -r Do not handle inter-compilation " + "unit references\n"); + fprintf(stderr, " -v Print all warnings to stderr\n"); + fprintf(stderr, " -n Use specified name for name of the object\n"); + fprintf(stderr, " -o Use specified name for the " + "operating system\n"); + return 1; +} + +int main(int argc, char **argv) { + if (argc < 2) + return usage(argv[0]); + bool header_only = false; + bool cfi = true; + bool handle_inter_cu_refs = true; + bool log_to_stderr = false; + std::string obj_name; + const char* obj_os = "Linux"; + int arg_index = 1; + while (arg_index < argc && strlen(argv[arg_index]) > 0 && + argv[arg_index][0] == '-') { + if (strcmp("-i", argv[arg_index]) == 0) { + header_only = true; + } else if (strcmp("-c", argv[arg_index]) == 0) { + cfi = false; + } else if (strcmp("-r", argv[arg_index]) == 0) { + handle_inter_cu_refs = false; + } else if (strcmp("-v", argv[arg_index]) == 0) { + log_to_stderr = true; + } else if (strcmp("-n", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -n\n"); + return usage(argv[0]); + } + obj_name = argv[arg_index + 1]; + ++arg_index; + } else if (strcmp("-o", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -o\n"); + return usage(argv[0]); + } + obj_os = argv[arg_index + 1]; + ++arg_index; + } else { + printf("2.4 %s\n", argv[arg_index]); + return usage(argv[0]); + } + ++arg_index; + } + if (arg_index == argc) + return usage(argv[0]); + // Save stderr so it can be used below. + FILE* saved_stderr = fdopen(dup(fileno(stderr)), "w"); + if (!log_to_stderr) { + if (freopen(_PATH_DEVNULL, "w", stderr)) { + // If it fails, not a lot we can (or should) do. + // Add this brace section to silence gcc warnings. + } + } + const char* binary; + std::vector debug_dirs; + binary = argv[arg_index]; + for (int debug_dir_index = arg_index + 1; + debug_dir_index < argc; + ++debug_dir_index) { + debug_dirs.push_back(argv[debug_dir_index]); + } + + if (obj_name.empty()) + obj_name = binary; + + if (header_only) { + if (!WriteSymbolFileHeader(binary, obj_name, obj_os, std::cout)) { + fprintf(saved_stderr, "Failed to process file.\n"); + return 1; + } + } else { + SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI; + google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs); + if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options, + std::cout)) { + fprintf(saved_stderr, "Failed to write symbol file.\n"); + return 1; + } + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc new file mode 100644 index 0000000000..a60be32354 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc @@ -0,0 +1,1428 @@ +// Copyright (c) 2009, 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. + +// Converts a minidump file to a core file which gdb can read. +// Large parts lifted from the userspace core dumper: +// http://code.google.com/p/google-coredumper/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/linux/memory_mapped_file.h" +#include "common/minidump_type_helper.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "third_party/lss/linux_syscall_support.h" +#include "tools/linux/md2core/minidump_memory_range.h" + +#if ULONG_MAX == 0xffffffffffffffff + #define ELF_CLASS ELFCLASS64 +#else + #define ELF_CLASS ELFCLASS32 +#endif +#define Ehdr ElfW(Ehdr) +#define Phdr ElfW(Phdr) +#define Shdr ElfW(Shdr) +#define Nhdr ElfW(Nhdr) +#define auxv_t ElfW(auxv_t) + + +#if defined(__x86_64__) + #define ELF_ARCH EM_X86_64 +#elif defined(__i386__) + #define ELF_ARCH EM_386 +#elif defined(__arm__) + #define ELF_ARCH EM_ARM +#elif defined(__mips__) + #define ELF_ARCH EM_MIPS +#elif defined(__aarch64__) + #define ELF_ARCH EM_AARCH64 +#endif + +#if defined(__arm__) +// GLibc/ARM and Android/ARM both use 'user_regs' for the structure type +// containing core registers, while they use 'user_regs_struct' on other +// architectures. This file-local typedef simplifies the source code. +typedef user_regs user_regs_struct; +#elif defined (__mips__) +// This file-local typedef simplifies the source code. +typedef gregset_t user_regs_struct; +#endif + +using google_breakpad::MDTypeHelper; +using google_breakpad::MemoryMappedFile; +using google_breakpad::MinidumpMemoryRange; + +typedef MDTypeHelper::MDRawDebug MDRawDebug; +typedef MDTypeHelper::MDRawLinkMap MDRawLinkMap; + +static const MDRVA kInvalidMDRVA = static_cast(-1); + +struct Options { + string minidump_path; + bool verbose; + int out_fd; + bool use_filename; + bool inc_guid; + string so_basedir; +}; + +static void +Usage(int argc, const char* argv[]) { + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Convert a minidump file into a core file (often for use by gdb).\n" + "\n" + "The shared library list will by default have filenames as the runtime expects.\n" + "There are many flags to control the output names though to make it easier to\n" + "integrate with your debug environment (e.g. gdb).\n" + " Default: /lib64/libpthread.so.0\n" + " -f: /lib64/libpthread-2.19.so\n" + " -i: /lib64/-libpthread.so.0\n" + " -f -i: /lib64/-libpthread-2.19.so\n" + " -S /foo/: /foo/libpthread.so.0\n" + "\n" + "Options:\n" + " -v Enable verbose output\n" + " -o Write coredump to specified file (otherwise use stdout).\n" + " -f Use the filename rather than the soname in the sharedlib list.\n" + " The soname is what the runtime system uses, but the filename is\n" + " how it's stored on disk.\n" + " -i Prefix sharedlib names with ID (when available). This makes it\n" + " easier to have a single directory full of symbols.\n" + " -S Set soname base directory. This will force all debug/symbol\n" + " lookups to be done in this directory rather than the filesystem\n" + " layout as it exists in the crashing image. This path should end\n" + " with a slash if it's a directory. e.g. /var/lib/breakpad/\n" + "", google_breakpad::BaseName(argv[0]).c_str()); +} + +static void +SetupOptions(int argc, const char* argv[], Options* options) { + extern int optind; + int ch; + const char* output_file = NULL; + + // Initialize the options struct as needed. + options->verbose = false; + options->use_filename = false; + options->inc_guid = false; + + while ((ch = getopt(argc, (char * const *)argv, "fhio:S:v")) != -1) { + switch (ch) { + case 'h': + Usage(argc, argv); + exit(0); + break; + case '?': + Usage(argc, argv); + exit(1); + break; + + case 'f': + options->use_filename = true; + break; + case 'i': + options->inc_guid = true; + break; + case 'o': + output_file = optarg; + break; + case 'S': + options->so_basedir = optarg; + break; + case 'v': + options->verbose = true; + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + if (output_file == NULL || !strcmp(output_file, "-")) { + options->out_fd = STDOUT_FILENO; + } else { + options->out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (options->out_fd == -1) { + fprintf(stderr, "%s: could not open output %s: %s\n", argv[0], + output_file, strerror(errno)); + exit(1); + } + } + + options->minidump_path = argv[optind]; +} + +// Write all of the given buffer, handling short writes and EINTR. Return true +// iff successful. +static bool +writea(int fd, const void* idata, size_t length) { + const uint8_t* data = (const uint8_t*) idata; + + size_t done = 0; + while (done < length) { + ssize_t r; + do { + r = write(fd, data + done, length - done); + } while (r == -1 && errno == EINTR); + + if (r < 1) + return false; + done += r; + } + + return true; +} + +/* Dynamically determines the byte sex of the system. Returns non-zero + * for big-endian machines. + */ +static inline int sex() { + int probe = 1; + return !*(char *)&probe; +} + +typedef struct elf_timeval { /* Time value with microsecond resolution */ + long tv_sec; /* Seconds */ + long tv_usec; /* Microseconds */ +} elf_timeval; + +typedef struct _elf_siginfo { /* Information about signal (unused) */ + int32_t si_signo; /* Signal number */ + int32_t si_code; /* Extra code */ + int32_t si_errno; /* Errno */ +} _elf_siginfo; + +typedef struct prstatus { /* Information about thread; includes CPU reg*/ + _elf_siginfo pr_info; /* Info associated with signal */ + uint16_t pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + pid_t pr_pid; /* Process ID */ + pid_t pr_ppid; /* Parent's process ID */ + pid_t pr_pgrp; /* Group ID */ + pid_t pr_sid; /* Session ID */ + elf_timeval pr_utime; /* User time */ + elf_timeval pr_stime; /* System time */ + elf_timeval pr_cutime; /* Cumulative user time */ + elf_timeval pr_cstime; /* Cumulative system time */ + user_regs_struct pr_reg; /* CPU registers */ + uint32_t pr_fpvalid; /* True if math co-processor being used */ +} prstatus; + +typedef struct prpsinfo { /* Information about process */ + unsigned char pr_state; /* Numeric process state */ + char pr_sname; /* Char for pr_state */ + unsigned char pr_zomb; /* Zombie */ + signed char pr_nice; /* Nice val */ + unsigned long pr_flag; /* Flags */ +#if defined(__x86_64__) || defined(__mips__) + uint32_t pr_uid; /* User ID */ + uint32_t pr_gid; /* Group ID */ +#else + uint16_t pr_uid; /* User ID */ + uint16_t pr_gid; /* Group ID */ +#endif + pid_t pr_pid; /* Process ID */ + pid_t pr_ppid; /* Parent's process ID */ + pid_t pr_pgrp; /* Group ID */ + pid_t pr_sid; /* Session ID */ + char pr_fname[16]; /* Filename of executable */ + char pr_psargs[80]; /* Initial part of arg list */ +} prpsinfo; + +// We parse the minidump file and keep the parsed information in this structure +struct CrashedProcess { + CrashedProcess() + : crashing_tid(-1), + auxv(NULL), + auxv_length(0) { + memset(&prps, 0, sizeof(prps)); + prps.pr_sname = 'R'; + memset(&debug, 0, sizeof(debug)); + } + + struct Mapping { + Mapping() + : permissions(0xFFFFFFFF), + start_address(0), + end_address(0), + offset(0) { + } + + uint32_t permissions; + uint64_t start_address, end_address, offset; + // The name we write out to the core. + string filename; + string data; + }; + std::map mappings; + + pid_t crashing_tid; + int fatal_signal; + + struct Thread { + pid_t tid; +#if defined(__mips__) + mcontext_t mcontext; +#else + user_regs_struct regs; +#endif +#if defined(__i386__) || defined(__x86_64__) + user_fpregs_struct fpregs; +#endif +#if defined(__i386__) + user_fpxregs_struct fpxregs; +#endif +#if defined(__aarch64__) + user_fpsimd_struct fpregs; +#endif + uintptr_t stack_addr; + const uint8_t* stack; + size_t stack_length; + }; + std::vector threads; + + const uint8_t* auxv; + size_t auxv_length; + + prpsinfo prps; + + // The GUID/filename from MD_MODULE_LIST_STREAM entries. + // We gather them for merging later on into the list of maps. + struct Signature { + char guid[40]; + string filename; + }; + std::map signatures; + + string dynamic_data; + MDRawDebug debug; + std::vector link_map; +}; + +#if defined(__i386__) +static uint32_t +U32(const uint8_t* data) { + uint32_t v; + memcpy(&v, data, sizeof(v)); + return v; +} + +static uint16_t +U16(const uint8_t* data) { + uint16_t v; + memcpy(&v, data, sizeof(v)); + return v; +} + +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextX86* rawregs = range.GetData(0); + + thread->regs.ebx = rawregs->ebx; + thread->regs.ecx = rawregs->ecx; + thread->regs.edx = rawregs->edx; + thread->regs.esi = rawregs->esi; + thread->regs.edi = rawregs->edi; + thread->regs.ebp = rawregs->ebp; + thread->regs.eax = rawregs->eax; + thread->regs.xds = rawregs->ds; + thread->regs.xes = rawregs->es; + thread->regs.xfs = rawregs->fs; + thread->regs.xgs = rawregs->gs; + thread->regs.orig_eax = rawregs->eax; + thread->regs.eip = rawregs->eip; + thread->regs.xcs = rawregs->cs; + thread->regs.eflags = rawregs->eflags; + thread->regs.esp = rawregs->esp; + thread->regs.xss = rawregs->ss; + + thread->fpregs.cwd = rawregs->float_save.control_word; + thread->fpregs.swd = rawregs->float_save.status_word; + thread->fpregs.twd = rawregs->float_save.tag_word; + thread->fpregs.fip = rawregs->float_save.error_offset; + thread->fpregs.fcs = rawregs->float_save.error_selector; + thread->fpregs.foo = rawregs->float_save.data_offset; + thread->fpregs.fos = rawregs->float_save.data_selector; + memcpy(thread->fpregs.st_space, rawregs->float_save.register_area, + 10 * 8); + + thread->fpxregs.cwd = rawregs->float_save.control_word; + thread->fpxregs.swd = rawregs->float_save.status_word; + thread->fpxregs.twd = rawregs->float_save.tag_word; + thread->fpxregs.fop = U16(rawregs->extended_registers + 6); + thread->fpxregs.fip = U16(rawregs->extended_registers + 8); + thread->fpxregs.fcs = U16(rawregs->extended_registers + 12); + thread->fpxregs.foo = U16(rawregs->extended_registers + 16); + thread->fpxregs.fos = U16(rawregs->extended_registers + 20); + thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24); + memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128); + memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128); +} +#elif defined(__x86_64__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextAMD64* rawregs = range.GetData(0); + + thread->regs.r15 = rawregs->r15; + thread->regs.r14 = rawregs->r14; + thread->regs.r13 = rawregs->r13; + thread->regs.r12 = rawregs->r12; + thread->regs.rbp = rawregs->rbp; + thread->regs.rbx = rawregs->rbx; + thread->regs.r11 = rawregs->r11; + thread->regs.r10 = rawregs->r10; + thread->regs.r9 = rawregs->r9; + thread->regs.r8 = rawregs->r8; + thread->regs.rax = rawregs->rax; + thread->regs.rcx = rawregs->rcx; + thread->regs.rdx = rawregs->rdx; + thread->regs.rsi = rawregs->rsi; + thread->regs.rdi = rawregs->rdi; + thread->regs.orig_rax = rawregs->rax; + thread->regs.rip = rawregs->rip; + thread->regs.cs = rawregs->cs; + thread->regs.eflags = rawregs->eflags; + thread->regs.rsp = rawregs->rsp; + thread->regs.ss = rawregs->ss; + thread->regs.fs_base = 0; + thread->regs.gs_base = 0; + thread->regs.ds = rawregs->ds; + thread->regs.es = rawregs->es; + thread->regs.fs = rawregs->fs; + thread->regs.gs = rawregs->gs; + + thread->fpregs.cwd = rawregs->flt_save.control_word; + thread->fpregs.swd = rawregs->flt_save.status_word; + thread->fpregs.ftw = rawregs->flt_save.tag_word; + thread->fpregs.fop = rawregs->flt_save.error_opcode; + thread->fpregs.rip = rawregs->flt_save.error_offset; + thread->fpregs.rdp = rawregs->flt_save.data_offset; + thread->fpregs.mxcsr = rawregs->flt_save.mx_csr; + thread->fpregs.mxcr_mask = rawregs->flt_save.mx_csr_mask; + memcpy(thread->fpregs.st_space, rawregs->flt_save.float_registers, 8 * 16); + memcpy(thread->fpregs.xmm_space, rawregs->flt_save.xmm_registers, 16 * 16); +} +#elif defined(__arm__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextARM* rawregs = range.GetData(0); + + thread->regs.uregs[0] = rawregs->iregs[0]; + thread->regs.uregs[1] = rawregs->iregs[1]; + thread->regs.uregs[2] = rawregs->iregs[2]; + thread->regs.uregs[3] = rawregs->iregs[3]; + thread->regs.uregs[4] = rawregs->iregs[4]; + thread->regs.uregs[5] = rawregs->iregs[5]; + thread->regs.uregs[6] = rawregs->iregs[6]; + thread->regs.uregs[7] = rawregs->iregs[7]; + thread->regs.uregs[8] = rawregs->iregs[8]; + thread->regs.uregs[9] = rawregs->iregs[9]; + thread->regs.uregs[10] = rawregs->iregs[10]; + thread->regs.uregs[11] = rawregs->iregs[11]; + thread->regs.uregs[12] = rawregs->iregs[12]; + thread->regs.uregs[13] = rawregs->iregs[13]; + thread->regs.uregs[14] = rawregs->iregs[14]; + thread->regs.uregs[15] = rawregs->iregs[15]; + + thread->regs.uregs[16] = rawregs->cpsr; + thread->regs.uregs[17] = 0; // what is ORIG_r0 exactly? +} +#elif defined(__aarch64__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { +#define COPY_REGS(rawregs) \ + do { \ + for (int i = 0; i < 31; ++i) \ + thread->regs.regs[i] = rawregs->iregs[i]; \ + thread->regs.sp = rawregs->iregs[MD_CONTEXT_ARM64_REG_SP]; \ + thread->regs.pc = rawregs->iregs[MD_CONTEXT_ARM64_REG_PC]; \ + thread->regs.pstate = rawregs->cpsr; \ + \ + memcpy(thread->fpregs.vregs, rawregs->float_save.regs, 8 * 32); \ + thread->fpregs.fpsr = rawregs->float_save.fpsr; \ + thread->fpregs.fpcr = rawregs->float_save.fpcr; \ + } while (false) + + if (range.length() == sizeof(MDRawContextARM64_Old)) { + const MDRawContextARM64_Old* rawregs = + range.GetData(0); + COPY_REGS(rawregs); + } else { + const MDRawContextARM64* rawregs = range.GetData(0); + COPY_REGS(rawregs); + } +#undef COPY_REGS +} +#elif defined(__mips__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextMIPS* rawregs = range.GetData(0); + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + thread->mcontext.gregs[i] = rawregs->iregs[i]; + + thread->mcontext.pc = rawregs->epc; + + thread->mcontext.mdlo = rawregs->mdlo; + thread->mcontext.mdhi = rawregs->mdhi; + + thread->mcontext.hi1 = rawregs->hi[0]; + thread->mcontext.lo1 = rawregs->lo[0]; + thread->mcontext.hi2 = rawregs->hi[1]; + thread->mcontext.lo2 = rawregs->lo[1]; + thread->mcontext.hi3 = rawregs->hi[2]; + thread->mcontext.lo3 = rawregs->lo[2]; + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) { + thread->mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs = + rawregs->float_save.regs[i]; + } + + thread->mcontext.fpc_csr = rawregs->float_save.fpcsr; +#if _MIPS_SIM == _ABIO32 + thread->mcontext.fpc_eir = rawregs->float_save.fir; +#endif +} +#else +#error "This code has not been ported to your platform yet" +#endif + +static void +ParseThreadList(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const uint32_t num_threads = *range.GetData(0); + if (options.verbose) { + fprintf(stderr, + "MD_THREAD_LIST_STREAM:\n" + "Found %d threads\n" + "\n\n", + num_threads); + } + for (unsigned i = 0; i < num_threads; ++i) { + CrashedProcess::Thread thread; + memset(&thread, 0, sizeof(thread)); + const MDRawThread* rawthread = + range.GetArrayElement(sizeof(uint32_t), i); + thread.tid = rawthread->thread_id; + thread.stack_addr = rawthread->stack.start_of_memory_range; + MinidumpMemoryRange stack_range = + full_file.Subrange(rawthread->stack.memory); + thread.stack = stack_range.data(); + thread.stack_length = rawthread->stack.memory.data_size; + + ParseThreadRegisters(&thread, + full_file.Subrange(rawthread->thread_context)); + + crashinfo->threads.push_back(thread); + } +} + +static void +ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const MDRawSystemInfo* sysinfo = range.GetData(0); + if (!sysinfo) { + fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n"); + exit(1); + } +#if defined(__i386__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) { + fprintf(stderr, + "This version of minidump-2-core only supports x86 (32bit)%s.\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ? + ",\nbut the minidump file is from a 64bit machine" : ""); + exit(1); + } +#elif defined(__x86_64__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) { + fprintf(stderr, + "This version of minidump-2-core only supports x86 (64bit)%s.\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ? + ",\nbut the minidump file is from a 32bit machine" : ""); + exit(1); + } +#elif defined(__arm__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) { + fprintf(stderr, + "This version of minidump-2-core only supports ARM (32bit).\n"); + exit(1); + } +#elif defined(__aarch64__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) { + fprintf(stderr, + "This version of minidump-2-core only supports ARM (64bit).\n"); + exit(1); + } +#elif defined(__mips__) +# if _MIPS_SIM == _ABIO32 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) { + fprintf(stderr, + "This version of minidump-2-core only supports mips o32 (32bit).\n"); + exit(1); + } +# elif _MIPS_SIM == _ABI64 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS64) { + fprintf(stderr, + "This version of minidump-2-core only supports mips n64 (64bit).\n"); + exit(1); + } +# else +# error "This mips ABI is currently not supported (n32)" +# endif +#else +#error "This code has not been ported to your platform yet" +#endif + if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(), + "Linux") && + sysinfo->platform_id != MD_OS_NACL) { + fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n"); + exit(1); + } + + if (options.verbose) { + fprintf(stderr, + "MD_SYSTEM_INFO_STREAM:\n" + "Architecture: %s\n" + "Number of processors: %d\n" + "Processor level: %d\n" + "Processor model: %d\n" + "Processor stepping: %d\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 + ? "i386" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 + ? "x86-64" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_ARM + ? "ARM" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS + ? "MIPS" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64 + ? "MIPS64" + : "???", + sysinfo->number_of_processors, + sysinfo->processor_level, + sysinfo->processor_revision >> 8, + sysinfo->processor_revision & 0xFF); + if (sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 || + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) { + fputs("Vendor id: ", stderr); + const char *nul = + (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, + sizeof(sysinfo->cpu.x86_cpu_info.vendor_id)); + fwrite(sysinfo->cpu.x86_cpu_info.vendor_id, + nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0] + : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr); + fputs("\n", stderr); + } + fprintf(stderr, "OS: %s\n", + full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str()); + fputs("\n\n", stderr); + } +} + +static void +ParseCPUInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_CPU_INFO:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n\n", stderr); + } +} + +static void +ParseProcessStatus(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_PROC_STATUS:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseLSBRelease(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_LSB_RELEASE:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseMaps(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_MAPS:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + } + for (const uint8_t* ptr = range.data(); + ptr < range.data() + range.length();) { + const uint8_t* eol = (uint8_t*)memchr(ptr, '\n', + range.data() + range.length() - ptr); + string line((const char*)ptr, + eol ? eol - ptr : range.data() + range.length() - ptr); + ptr = eol ? eol + 1 : range.data() + range.length(); + unsigned long long start, stop, offset; + char* permissions = NULL; + char* filename = NULL; + sscanf(line.c_str(), "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms", + &start, &stop, &permissions, &offset, &filename); + if (filename && *filename == '/') { + CrashedProcess::Mapping mapping; + mapping.permissions = 0; + if (strchr(permissions, 'r')) { + mapping.permissions |= PF_R; + } + if (strchr(permissions, 'w')) { + mapping.permissions |= PF_W; + } + if (strchr(permissions, 'x')) { + mapping.permissions |= PF_X; + } + mapping.start_address = start; + mapping.end_address = stop; + mapping.offset = offset; + if (filename) { + mapping.filename = filename; + } + crashinfo->mappings[mapping.start_address] = mapping; + } + free(permissions); + free(filename); + } + if (options.verbose) { + fputs("\n\n\n", stderr); + } +} + +static void +ParseEnvironment(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_ENVIRON:\n", stderr); + char* env = new char[range.length()]; + memcpy(env, range.data(), range.length()); + int nul_count = 0; + for (char *ptr = env;;) { + ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env)); + if (!ptr) { + break; + } + if (ptr > env && ptr[-1] == '\n') { + if (++nul_count > 5) { + // Some versions of Chrome try to rewrite the process' command line + // in a way that causes the environment to be corrupted. Afterwards, + // part of the environment will contain the trailing bit of the + // command line. The rest of the environment will be filled with + // NUL bytes. + // We detect this corruption by counting the number of consecutive + // NUL bytes. Normally, we would not expect any consecutive NUL + // bytes. But we are conservative and only suppress printing of + // the environment if we see at least five consecutive NULs. + fputs("Environment has been corrupted; no data available", stderr); + goto env_corrupted; + } + } else { + nul_count = 0; + } + *ptr = '\n'; + } + fwrite(env, range.length(), 1, stderr); + env_corrupted: + delete[] env; + fputs("\n\n\n", stderr); + } +} + +static void +ParseAuxVector(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + // Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value + // when dumping /proc/$x/maps + if (range.length() > 17) { + // The AUXV vector contains binary data, whereas the maps always begin + // with an 8+ digit hex address followed by a hyphen and another 8+ digit + // address. + char addresses[18]; + memcpy(addresses, range.data(), 17); + addresses[17] = '\000'; + if (strspn(addresses, "0123456789abcdef-") == 17) { + ParseMaps(options, crashinfo, range); + return; + } + } + + crashinfo->auxv = range.data(); + crashinfo->auxv_length = range.length(); +} + +static void +ParseCmdLine(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + // The command line is supposed to use NUL bytes to separate arguments. + // As Chrome rewrites its own command line and (incorrectly) substitutes + // spaces, this is often not the case in our minidump files. + const char* cmdline = (const char*) range.data(); + if (options.verbose) { + fputs("MD_LINUX_CMD_LINE:\n", stderr); + unsigned i = 0; + for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { } + fputs("argv[0] = \"", stderr); + fwrite(cmdline, i, 1, stderr); + fputs("\"\n", stderr); + for (unsigned j = ++i, argc = 1; j < range.length(); ++j) { + if (!cmdline[j] || cmdline[j] == ' ') { + fprintf(stderr, "argv[%d] = \"", argc++); + fwrite(cmdline + i, j - i, 1, stderr); + fputs("\"\n", stderr); + i = j + 1; + } + } + fputs("\n\n", stderr); + } + + const char *binary_name = cmdline; + for (size_t i = 0; i < range.length(); ++i) { + if (cmdline[i] == '/') { + binary_name = cmdline + i + 1; + } else if (cmdline[i] == 0 || cmdline[i] == ' ') { + static const size_t fname_len = sizeof(crashinfo->prps.pr_fname) - 1; + static const size_t args_len = sizeof(crashinfo->prps.pr_psargs) - 1; + memset(crashinfo->prps.pr_fname, 0, fname_len + 1); + memset(crashinfo->prps.pr_psargs, 0, args_len + 1); + unsigned len = cmdline + i - binary_name; + memcpy(crashinfo->prps.pr_fname, binary_name, + len > fname_len ? fname_len : len); + + len = range.length() > args_len ? args_len : range.length(); + memcpy(crashinfo->prps.pr_psargs, cmdline, len); + for (unsigned j = 0; j < len; ++j) { + if (crashinfo->prps.pr_psargs[j] == 0) + crashinfo->prps.pr_psargs[j] = ' '; + } + break; + } + } +} + +static void +ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const MDRawDebug* debug = range.GetData(0); + if (!debug) { + return; + } + if (options.verbose) { + fprintf(stderr, + "MD_LINUX_DSO_DEBUG:\n" + "Version: %d\n" + "Number of DSOs: %d\n" + "Brk handler: 0x%" PRIx64 "\n" + "Dynamic loader at: 0x%" PRIx64 "\n" + "_DYNAMIC: 0x%" PRIx64 "\n", + debug->version, + debug->dso_count, + static_cast(debug->brk), + static_cast(debug->ldbase), + static_cast(debug->dynamic)); + } + crashinfo->debug = *debug; + if (range.length() > sizeof(MDRawDebug)) { + char* dynamic_data = (char*)range.data() + sizeof(MDRawDebug); + crashinfo->dynamic_data.assign(dynamic_data, + range.length() - sizeof(MDRawDebug)); + } + if (debug->map != kInvalidMDRVA) { + for (unsigned int i = 0; i < debug->dso_count; ++i) { + const MDRawLinkMap* link_map = + full_file.GetArrayElement(debug->map, i); + if (link_map) { + if (options.verbose) { + fprintf(stderr, + "#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n", + i, static_cast(link_map->addr), + static_cast(link_map->ld), + full_file.GetAsciiMDString(link_map->name).c_str()); + } + crashinfo->link_map.push_back(*link_map); + } + } + } + if (options.verbose) { + fputs("\n\n", stderr); + } +} + +static void +ParseExceptionStream(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + const MDRawExceptionStream* exp = range.GetData(0); + crashinfo->crashing_tid = exp->thread_id; + crashinfo->fatal_signal = (int) exp->exception_record.exception_code; +} + +static bool +WriteThread(const Options& options, const CrashedProcess::Thread& thread, + int fatal_signal) { + struct prstatus pr; + memset(&pr, 0, sizeof(pr)); + + pr.pr_info.si_signo = fatal_signal; + pr.pr_cursig = fatal_signal; + pr.pr_pid = thread.tid; +#if defined(__mips__) + memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct)); +#else + memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); +#endif + + Nhdr nhdr; + memset(&nhdr, 0, sizeof(nhdr)); + nhdr.n_namesz = 5; + nhdr.n_descsz = sizeof(struct prstatus); + nhdr.n_type = NT_PRSTATUS; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &pr, sizeof(struct prstatus))) { + return false; + } + +#if defined(__i386__) || defined(__x86_64__) + nhdr.n_descsz = sizeof(user_fpregs_struct); + nhdr.n_type = NT_FPREGSET; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &thread.fpregs, sizeof(user_fpregs_struct))) { + return false; + } +#endif + +#if defined(__i386__) + nhdr.n_descsz = sizeof(user_fpxregs_struct); + nhdr.n_type = NT_PRXFPREG; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "LINUX\0\0\0", 8) || + !writea(options.out_fd, &thread.fpxregs, sizeof(user_fpxregs_struct))) { + return false; + } +#endif + + return true; +} + +static void +ParseModuleStream(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + if (options.verbose) { + fputs("MD_MODULE_LIST_STREAM:\n", stderr); + } + const uint32_t num_mappings = *range.GetData(0); + for (unsigned i = 0; i < num_mappings; ++i) { + CrashedProcess::Mapping mapping; + const MDRawModule* rawmodule = reinterpret_cast( + range.GetArrayElement(sizeof(uint32_t), MD_MODULE_SIZE, i)); + mapping.start_address = rawmodule->base_of_image; + mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image; + + if (crashinfo->mappings.find(mapping.start_address) == + crashinfo->mappings.end()) { + // We prefer data from MD_LINUX_MAPS over MD_MODULE_LIST_STREAM, as + // the former is a strict superset of the latter. + crashinfo->mappings[mapping.start_address] = mapping; + } + + const MDCVInfoPDB70* record = reinterpret_cast( + full_file.GetData(rawmodule->cv_record.rva, MDCVInfoPDB70_minsize)); + char guid[40]; + sprintf(guid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + record->signature.data1, record->signature.data2, + record->signature.data3, + record->signature.data4[0], record->signature.data4[1], + record->signature.data4[2], record->signature.data4[3], + record->signature.data4[4], record->signature.data4[5], + record->signature.data4[6], record->signature.data4[7]); + + string filename = full_file.GetAsciiMDString(rawmodule->module_name_rva); + + CrashedProcess::Signature signature; + strcpy(signature.guid, guid); + signature.filename = filename; + crashinfo->signatures[rawmodule->base_of_image] = signature; + + if (options.verbose) { + fprintf(stderr, "0x%" PRIx64 "-0x%" PRIx64 ", ChkSum: 0x%08X, GUID: %s, " + " \"%s\"\n", + rawmodule->base_of_image, + rawmodule->base_of_image + rawmodule->size_of_image, + rawmodule->checksum, guid, filename.c_str()); + } + } + if (options.verbose) { + fputs("\n\n", stderr); + } +} + +static void +AddDataToMapping(CrashedProcess* crashinfo, const string& data, + uintptr_t addr) { + for (std::map::iterator + iter = crashinfo->mappings.begin(); + iter != crashinfo->mappings.end(); + ++iter) { + if (addr >= iter->second.start_address && + addr < iter->second.end_address) { + CrashedProcess::Mapping mapping = iter->second; + if ((addr & ~4095) != iter->second.start_address) { + // If there are memory pages in the mapping prior to where the + // data starts, truncate the existing mapping so that it ends with + // the page immediately preceding the data region. + iter->second.end_address = addr & ~4095; + if (!mapping.filename.empty()) { + // "mapping" is a copy of "iter->second". We are splitting the + // existing mapping into two separate ones when we write the data + // to the core file. The first one does not have any associated + // data in the core file, the second one is backed by data that is + // included with the core file. + // If this mapping wasn't supposed to be anonymous, then we also + // have to update the file offset upon splitting the mapping. + mapping.offset += iter->second.end_address - + iter->second.start_address; + } + } + // Create a new mapping that contains the data contents. We often + // limit the amount of data that is actually written to the core + // file. But it is OK if the mapping itself extends past the end of + // the data. + mapping.start_address = addr & ~4095; + mapping.data.assign(addr & 4095, 0).append(data); + mapping.data.append(-mapping.data.size() & 4095, 0); + crashinfo->mappings[mapping.start_address] = mapping; + return; + } + } + // Didn't find a suitable existing mapping for the data. Create a new one. + CrashedProcess::Mapping mapping; + mapping.permissions = PF_R | PF_W; + mapping.start_address = addr & ~4095; + mapping.end_address = + (addr + data.size() + 4095) & ~4095; + mapping.data.assign(addr & 4095, 0).append(data); + mapping.data.append(-mapping.data.size() & 4095, 0); + crashinfo->mappings[mapping.start_address] = mapping; +} + +static void +AugmentMappings(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& full_file) { + // For each thread, find the memory mapping that matches the thread's stack. + // Then adjust the mapping to include the stack dump. + for (unsigned i = 0; i < crashinfo->threads.size(); ++i) { + const CrashedProcess::Thread& thread = crashinfo->threads[i]; + AddDataToMapping(crashinfo, + string((char *)thread.stack, thread.stack_length), + thread.stack_addr); + } + + // Create a new link map with information about DSOs. We move this map to + // the beginning of the address space, as this area should always be + // available. + static const uintptr_t start_addr = 4096; + string data; + struct r_debug debug = { 0 }; + debug.r_version = crashinfo->debug.version; + debug.r_brk = (ElfW(Addr))crashinfo->debug.brk; + debug.r_state = r_debug::RT_CONSISTENT; + debug.r_ldbase = (ElfW(Addr))crashinfo->debug.ldbase; + debug.r_map = crashinfo->debug.dso_count > 0 ? + (struct link_map*)(start_addr + sizeof(debug)) : 0; + data.append((char*)&debug, sizeof(debug)); + + struct link_map* prev = 0; + for (std::vector::iterator iter = crashinfo->link_map.begin(); + iter != crashinfo->link_map.end(); + ++iter) { + struct link_map link_map = { 0 }; + link_map.l_addr = (ElfW(Addr))iter->addr; + link_map.l_name = (char*)(start_addr + data.size() + sizeof(link_map)); + link_map.l_ld = (ElfW(Dyn)*)iter->ld; + link_map.l_prev = prev; + prev = (struct link_map*)(start_addr + data.size()); + string filename = full_file.GetAsciiMDString(iter->name); + + // Look up signature for this filename. If available, change filename + // to point to GUID, instead. + std::map::const_iterator sig = + crashinfo->signatures.find((uintptr_t)iter->addr); + if (sig != crashinfo->signatures.end()) { + // At this point, we have: + // old_filename: The path as found via SONAME (e.g. /lib/libpthread.so.0). + // sig_filename: The path on disk (e.g. /lib/libpthread-2.19.so). + const char* guid = sig->second.guid; + string sig_filename = sig->second.filename; + string old_filename = filename.empty() ? sig_filename : filename; + string new_filename; + + // First set up the leading path. We assume dirname always ends with a + // trailing slash (as needed), so we won't be appending one manually. + if (options.so_basedir.empty()) { + string dirname; + if (options.use_filename) { + dirname = sig_filename; + } else { + dirname = old_filename; + } + size_t slash = dirname.find_last_of('/'); + if (slash != string::npos) { + new_filename = dirname.substr(0, slash + 1); + } + } else { + new_filename = options.so_basedir; + } + + // Insert the module ID if requested. + if (options.inc_guid && + strcmp(guid, "00000000-0000-0000-0000-000000000000") != 0) { + new_filename += guid; + new_filename += "-"; + } + + // Decide whether we use the filename or the SONAME (where the SONAME tends + // to be a symlink to the actual file). + new_filename += google_breakpad::BaseName( + options.use_filename ? sig_filename : old_filename); + + if (filename != new_filename) { + if (options.verbose) { + fprintf(stderr, "0x%" PRIx64": rewriting mapping \"%s\" to \"%s\"\n", + static_cast(link_map.l_addr), + filename.c_str(), new_filename.c_str()); + } + filename = new_filename; + } + } + + if (std::distance(iter, crashinfo->link_map.end()) == 1) { + link_map.l_next = 0; + } else { + link_map.l_next = (struct link_map*)(start_addr + data.size() + + sizeof(link_map) + + ((filename.size() + 8) & ~7)); + } + data.append((char*)&link_map, sizeof(link_map)); + data.append(filename); + data.append(8 - (filename.size() & 7), 0); + } + AddDataToMapping(crashinfo, data, start_addr); + + // Map the page containing the _DYNAMIC array + if (!crashinfo->dynamic_data.empty()) { + // Make _DYNAMIC DT_DEBUG entry point to our link map + for (int i = 0;; ++i) { + ElfW(Dyn) dyn; + if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) { + no_dt_debug: + if (options.verbose) { + fprintf(stderr, "No DT_DEBUG entry found\n"); + } + return; + } + memcpy(&dyn, crashinfo->dynamic_data.c_str() + i*sizeof(dyn), + sizeof(dyn)); + if (dyn.d_tag == DT_DEBUG) { + crashinfo->dynamic_data.replace(i*sizeof(dyn) + + offsetof(ElfW(Dyn), d_un.d_ptr), + sizeof(start_addr), + (char*)&start_addr, sizeof(start_addr)); + break; + } else if (dyn.d_tag == DT_NULL) { + goto no_dt_debug; + } + } + AddDataToMapping(crashinfo, crashinfo->dynamic_data, + (uintptr_t)crashinfo->debug.dynamic); + } +} + +int +main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + + MemoryMappedFile mapped_file(options.minidump_path.c_str(), 0); + if (!mapped_file.data()) { + fprintf(stderr, "Failed to mmap dump file: %s: %s\n", + options.minidump_path.c_str(), strerror(errno)); + return 1; + } + + MinidumpMemoryRange dump(mapped_file.data(), mapped_file.size()); + + const MDRawHeader* header = dump.GetData(0); + + CrashedProcess crashinfo; + + // Always check the system info first, as that allows us to tell whether + // this is a minidump file that is compatible with our converter. + bool ok = false; + for (unsigned i = 0; i < header->stream_count; ++i) { + const MDRawDirectory* dirent = + dump.GetArrayElement(header->stream_directory_rva, i); + switch (dirent->stream_type) { + case MD_SYSTEM_INFO_STREAM: + ParseSystemInfo(options, &crashinfo, dump.Subrange(dirent->location), + dump); + ok = true; + break; + default: + break; + } + } + if (!ok) { + fprintf(stderr, "Cannot determine input file format.\n"); + exit(1); + } + + for (unsigned i = 0; i < header->stream_count; ++i) { + const MDRawDirectory* dirent = + dump.GetArrayElement(header->stream_directory_rva, i); + switch (dirent->stream_type) { + case MD_THREAD_LIST_STREAM: + ParseThreadList(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + case MD_LINUX_CPU_INFO: + ParseCPUInfo(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_PROC_STATUS: + ParseProcessStatus(options, &crashinfo, + dump.Subrange(dirent->location)); + break; + case MD_LINUX_LSB_RELEASE: + ParseLSBRelease(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_ENVIRON: + ParseEnvironment(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_MAPS: + ParseMaps(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_AUXV: + ParseAuxVector(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_CMD_LINE: + ParseCmdLine(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_DSO_DEBUG: + ParseDSODebugInfo(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + case MD_EXCEPTION_STREAM: + ParseExceptionStream(options, &crashinfo, + dump.Subrange(dirent->location)); + break; + case MD_MODULE_LIST_STREAM: + ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + default: + if (options.verbose) + fprintf(stderr, "Skipping %x\n", dirent->stream_type); + } + } + + AugmentMappings(options, &crashinfo, dump); + + // Write the ELF header. The file will look like: + // ELF header + // Phdr for the PT_NOTE + // Phdr for each of the thread stacks + // PT_NOTE + // each of the thread stacks + Ehdr ehdr; + memset(&ehdr, 0, sizeof(Ehdr)); + ehdr.e_ident[0] = ELFMAG0; + ehdr.e_ident[1] = ELFMAG1; + ehdr.e_ident[2] = ELFMAG2; + ehdr.e_ident[3] = ELFMAG3; + ehdr.e_ident[4] = ELF_CLASS; + ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB; + ehdr.e_ident[6] = EV_CURRENT; + ehdr.e_type = ET_CORE; + ehdr.e_machine = ELF_ARCH; + ehdr.e_version = EV_CURRENT; + ehdr.e_phoff = sizeof(Ehdr); + ehdr.e_ehsize = sizeof(Ehdr); + ehdr.e_phentsize= sizeof(Phdr); + ehdr.e_phnum = 1 + // PT_NOTE + crashinfo.mappings.size(); // memory mappings + ehdr.e_shentsize= sizeof(Shdr); + if (!writea(options.out_fd, &ehdr, sizeof(Ehdr))) + return 1; + + size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr); + size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) + + // sizeof(Nhdr) + 8 + sizeof(user) + + sizeof(Nhdr) + 8 + crashinfo.auxv_length + + crashinfo.threads.size() * ( + (sizeof(Nhdr) + 8 + sizeof(prstatus)) +#if defined(__i386__) || defined(__x86_64__) + + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) +#endif +#if defined(__i386__) + + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct) +#endif + ); + + Phdr phdr; + memset(&phdr, 0, sizeof(Phdr)); + phdr.p_type = PT_NOTE; + phdr.p_offset = offset; + phdr.p_filesz = filesz; + if (!writea(options.out_fd, &phdr, sizeof(phdr))) + return 1; + + phdr.p_type = PT_LOAD; + phdr.p_align = 4096; + size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align); + if (note_align == phdr.p_align) + note_align = 0; + offset += note_align; + + for (std::map::const_iterator iter = + crashinfo.mappings.begin(); + iter != crashinfo.mappings.end(); ++iter) { + const CrashedProcess::Mapping& mapping = iter->second; + if (mapping.permissions == 0xFFFFFFFF) { + // This is a map that we found in MD_MODULE_LIST_STREAM (as opposed to + // MD_LINUX_MAPS). It lacks some of the information that we would like + // to include. + phdr.p_flags = PF_R; + } else { + phdr.p_flags = mapping.permissions; + } + phdr.p_vaddr = mapping.start_address; + phdr.p_memsz = mapping.end_address - mapping.start_address; + if (mapping.data.size()) { + offset += filesz; + filesz = mapping.data.size(); + phdr.p_filesz = mapping.data.size(); + phdr.p_offset = offset; + } else { + phdr.p_filesz = 0; + phdr.p_offset = 0; + } + if (!writea(options.out_fd, &phdr, sizeof(phdr))) + return 1; + } + + Nhdr nhdr; + memset(&nhdr, 0, sizeof(nhdr)); + nhdr.n_namesz = 5; + nhdr.n_descsz = sizeof(prpsinfo); + nhdr.n_type = NT_PRPSINFO; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &crashinfo.prps, sizeof(prpsinfo))) { + return 1; + } + + nhdr.n_descsz = crashinfo.auxv_length; + nhdr.n_type = NT_AUXV; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, crashinfo.auxv, crashinfo.auxv_length)) { + return 1; + } + + for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { + if (crashinfo.threads[i].tid == crashinfo.crashing_tid) { + WriteThread(options, crashinfo.threads[i], crashinfo.fatal_signal); + break; + } + } + + for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { + if (crashinfo.threads[i].tid != crashinfo.crashing_tid) + WriteThread(options, crashinfo.threads[i], 0); + } + + if (note_align) { + google_breakpad::scoped_array scratch(new char[note_align]); + memset(scratch.get(), 0, note_align); + if (!writea(options.out_fd, scratch.get(), note_align)) + return 1; + } + + for (std::map::const_iterator iter = + crashinfo.mappings.begin(); + iter != crashinfo.mappings.end(); ++iter) { + const CrashedProcess::Mapping& mapping = iter->second; + if (mapping.data.size()) { + if (!writea(options.out_fd, mapping.data.c_str(), mapping.data.size())) + return 1; + } + } + + if (options.out_fd != STDOUT_FILENO) { + close(options.out_fd); + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h new file mode 100644 index 0000000000..a793e2cfb9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h @@ -0,0 +1,89 @@ +// Copyright (c) 2011, 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_memory_range.h: Define the google_breakpad::MinidumpMemoryRange +// class, which adds methods for handling minidump specific data structures +// on top of google_breakpad::MemoryRange. See common/memory_range.h for +// more details on MemoryRange. + +#ifndef TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ +#define TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ + +#include + +#include "common/memory_range.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// A derived class of MemoryRange with added methods for handling minidump +// specific data structures. To avoid virtual functions, it is not designed +// to be used polymorphically. +class MinidumpMemoryRange : public MemoryRange { + public: + MinidumpMemoryRange() {} + + MinidumpMemoryRange(const void* data, size_t length) + : MemoryRange(data, length) {} + + // Returns a subrange of |length| bytes at |offset| bytes of this memory + // range, or an empty range if the subrange is out of bounds. + // This methods overrides the base implemementation in order to return + // an instance of MinidumpMemoryRange instead of MemoryRange. + MinidumpMemoryRange Subrange(size_t sub_offset, size_t sub_length) const { + if (Covers(sub_offset, sub_length)) + return MinidumpMemoryRange(data() + sub_offset, sub_length); + return MinidumpMemoryRange(); + } + + // Returns a subrange that covers the offset and length specified by + // |location|, or an empty range if the subrange is out of bounds. + MinidumpMemoryRange Subrange(const MDLocationDescriptor& location) const { + return MinidumpMemoryRange::Subrange(location.rva, location.data_size); + } + + // Gets a STL string from a MDString at |sub_offset| bytes of this memory + // range. This method only works correctly for ASCII characters and does + // not convert between UTF-16 and UTF-8. + const std::string GetAsciiMDString(size_t sub_offset) const { + std::string str; + const MDString* md_str = GetData(sub_offset); + if (md_str) { + const uint16_t* buffer = &md_str->buffer[0]; + for (uint32_t i = 0; i < md_str->length && buffer[i]; ++i) { + str.push_back(buffer[i]); + } + } + return str; + } +}; + +} // namespace google_breakpad + +#endif // TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc new file mode 100644 index 0000000000..fe4ded83dc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc @@ -0,0 +1,258 @@ +// Copyright (c) 2011, 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_memory_range_unittest.cc: +// Unit tests for google_breakpad::MinidumpMemoryRange. + +#include "breakpad_googletest_includes.h" +#include "tools/linux/md2core/minidump_memory_range.h" + +using google_breakpad::MinidumpMemoryRange; +using testing::Message; + +namespace { + +const uint32_t kBuffer[10] = { 0 }; +const size_t kBufferSize = sizeof(kBuffer); +const uint8_t* kBufferPointer = reinterpret_cast(kBuffer); + +// Test vectors for verifying Covers, GetData, and Subrange. +const struct { + bool valid; + size_t offset; + size_t length; +} kSubranges[] = { + { true, 0, 0 }, + { true, 0, 2 }, + { true, 0, kBufferSize }, + { true, 2, 0 }, + { true, 2, 4 }, + { true, 2, kBufferSize - 2 }, + { true, kBufferSize - 1, 1 }, + { false, kBufferSize, 0 }, + { false, kBufferSize, static_cast(-1) }, + { false, kBufferSize + 1, 0 }, + { false, static_cast(-1), 2 }, + { false, 1, kBufferSize }, + { false, kBufferSize - 1, 2 }, + { false, 0, static_cast(-1) }, + { false, 1, static_cast(-1) }, +}; +const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]); + +// Test vectors for verifying GetArrayElement. +const struct { + size_t offset; + size_t size; + size_t index; + const void* const pointer; +} kElements[] = { + // Valid array elemenets + { 0, 1, 0, kBufferPointer }, + { 0, 1, 1, kBufferPointer + 1 }, + { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 }, + { 0, 2, 1, kBufferPointer + 2 }, + { 0, 4, 2, kBufferPointer + 8 }, + { 0, 4, 9, kBufferPointer + 36 }, + { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, + // Invalid array elemenets + { 0, 1, kBufferSize, NULL }, + { 0, 4, 10, NULL }, + { kBufferSize - 1, 1, 1, NULL }, + { kBufferSize - 1, 2, 0, NULL }, + { kBufferSize, 1, 0, NULL }, +}; +const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); + +} // namespace + +TEST(MinidumpMemoryRangeTest, DefaultConstructor) { + MinidumpMemoryRange range; + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, ConstructorWithDataAndLength) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); +} + +TEST(MinidumpMemoryRangeTest, Reset) { + MinidumpMemoryRange range; + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); + + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, Set) { + MinidumpMemoryRange range; + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Set(NULL, 0); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, SubrangeOfEmptyMemoryRange) { + MinidumpMemoryRange range; + MinidumpMemoryRange subrange = range.Subrange(0, 10); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); +} + +TEST(MinidumpMemoryRangeTest, SubrangeAndGetData) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MinidumpMemoryRange subrange = range.Subrange(sub_offset, sub_length); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MinidumpMemoryRangeTest, SubrangeWithMDLocationDescriptor) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MDLocationDescriptor location; + location.rva = sub_offset; + location.data_size = sub_length; + MinidumpMemoryRange subrange = range.Subrange(location); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MinidumpMemoryRangeTest, GetDataWithTemplateType) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetData(0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} + +TEST(MinidumpMemoryRangeTest, GetArrayElement) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumElements; ++i) { + size_t element_offset = kElements[i].offset; + size_t element_size = kElements[i].size; + unsigned element_index = kElements[i].index; + const void* const element_pointer = kElements[i].pointer; + SCOPED_TRACE(Message() << "offset=" << element_offset + << ", size=" << element_size + << ", index=" << element_index); + EXPECT_EQ(element_pointer, range.GetArrayElement( + element_offset, element_size, element_index)); + } +} + +TEST(MinidumpMemoryRangeTest, GetArrayElmentWithTemplateType) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), char_pointer); + const int* int_pointer = range.GetArrayElement(0, 0); + EXPECT_EQ(reinterpret_cast(kBufferPointer), int_pointer); +} + +TEST(MinidumpMemoryRangeTest, GetAsciiMDString) { + uint8_t buffer[100] = { 0 }; + + MDString* md_str = reinterpret_cast(buffer); + md_str->length = 4; + md_str->buffer[0] = 'T'; + md_str->buffer[1] = 'e'; + md_str->buffer[2] = 's'; + md_str->buffer[3] = 't'; + md_str->buffer[4] = '\0'; + + size_t str2_offset = + sizeof(MDString) + (md_str->length + 1) * sizeof(uint16_t); + + md_str = reinterpret_cast(buffer + str2_offset); + md_str->length = 9; // Test length larger than actual string + md_str->buffer[0] = 'S'; + md_str->buffer[1] = 't'; + md_str->buffer[2] = 'r'; + md_str->buffer[3] = 'i'; + md_str->buffer[4] = 'n'; + md_str->buffer[5] = 'g'; + md_str->buffer[6] = '\0'; + md_str->buffer[7] = '1'; + md_str->buffer[8] = '2'; + + MinidumpMemoryRange range(buffer, sizeof(buffer)); + EXPECT_EQ("Test", range.GetAsciiMDString(0)); + EXPECT_EQ("String", range.GetAsciiMDString(str2_offset)); + + // Test out-of-bounds cases. + EXPECT_EQ("", range.GetAsciiMDString( + sizeof(buffer) - sizeof(MDString) + 1)); + EXPECT_EQ("", range.GetAsciiMDString(sizeof(buffer))); +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc new file mode 100644 index 0000000000..19f17450a1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc @@ -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. + +// minidump_upload.cc: Upload a minidump to a HTTP server. +// The upload is sent as a multipart/form-data POST request with +// the following parameters: +// prod: the product name +// ver: the product version +// symbol_file: the breakpad format symbol file + +#include +#include +#include + +#include + +#include "common/linux/http_upload.h" +#include "common/using_std_string.h" + +using google_breakpad::HTTPUpload; + +struct Options { + string minidumpPath; + string uploadURLStr; + string product; + string version; + string proxy; + string proxy_user_pwd; + bool success; +}; + +//============================================================================= +static void Start(Options *options) { + std::map parameters; + // Add parameters + parameters["prod"] = options->product; + parameters["ver"] = options->version; + + std::map files; + files["upload_file_minidump"] = options->minidumpPath; + + // Send it + string response, error; + bool success = HTTPUpload::SendRequest(options->uploadURLStr, + parameters, + files, + options->proxy, + options->proxy_user_pwd, + "", + &response, + NULL, + &error); + + if (success) { + printf("Successfully sent the minidump file.\n"); + } else { + printf("Failed to send minidump: %s\n", error.c_str()); + } + printf("Response:\n"); + printf("%s\n", response.c_str()); + options->success = success; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit minidump information.\n"); + fprintf(stderr, "Usage: %s [options...] -p -v " + "\n", argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " should be a minidump.\n"); + fprintf(stderr, " is the destination for the upload\n"); + + fprintf(stderr, "-p:\t Product name\n"); + fprintf(stderr, "-v:\t Product version\n"); + fprintf(stderr, "-x:\t Use HTTP proxy on given port\n"); + fprintf(stderr, "-u:\t Set proxy user and password\n"); + fprintf(stderr, "-h:\t Usage\n"); + fprintf(stderr, "-?:\t Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + int ch; + + while ((ch = getopt(argc, (char * const *)argv, "p:u:v:x:h?")) != -1) { + switch (ch) { + case 'p': + options->product = optarg; + break; + case 'u': + options->proxy_user_pwd = optarg; + break; + case 'v': + options->version = optarg; + break; + case 'x': + options->proxy = optarg; + break; + + default: + fprintf(stderr, "Invalid option '%c'\n", ch); + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = argv[optind]; + options->uploadURLStr = argv[optind + 1]; +} + +//============================================================================= +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + Start(&options); + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc new file mode 100644 index 0000000000..f155eb9552 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc @@ -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. + +// symupload.cc: Upload a symbol file to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// code_file: the basename of the module, e.g. "app" +// debug_file: the basename of the debugging file, e.g. "app" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// version: the file version of the module, e.g. "1.2.3.4" +// os: the operating system that the module was built for +// cpu: the CPU that the module was built for +// symbol_file: the contents of the breakpad-format symbol file + +#include +#include +#include +#include + +#include + +#include "common/linux/symbol_upload.h" + +using google_breakpad::sym_upload::UploadProtocol; +using google_breakpad::sym_upload::Options; + +static void StrToUpper(std::string* str) { + if (str == nullptr) { + fprintf(stderr, "nullptr passed to StrToUpper.\n"); + exit(1); + } + for (size_t i = 0; i < str->length(); i++) { + (*str)[i] = std::toupper((*str)[i], std::locale::classic()); + } +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s [options...] \n", + argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " should be created by using the dump_syms" + "tool.\n"); + fprintf(stderr, " is the destination for the upload\n"); + fprintf(stderr, "-p:\t One of ['sym-upload-v1'," + " 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n"); + fprintf(stderr, "-v:\t Version information (e.g., 1.2.3.4)\n"); + fprintf(stderr, "-x:\t Use HTTP proxy on given port\n"); + fprintf(stderr, "-u:\t Set proxy user and password\n"); + fprintf(stderr, "-h:\t Usage\n"); + fprintf(stderr, "-?:\t Usage\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "These options only work with 'sym-upload-v2' protocol:\n"); + fprintf(stderr, "-k:\t A secret used to authenticate with the" + " API.\n"); + fprintf(stderr, "-f:\t Force symbol upload if already exists.\n"); + fprintf(stderr, "-t:\t Explicitly set symbol upload type (" + "default is 'breakpad').\n" + "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', " + "'dsym', 'pdb'].\n" + "\t Note: When this flag is set to anything other than 'breakpad', then " + "the '-c' and '-i' flags must also be set.\n"); + fprintf(stderr, "-c:\t Explicitly set 'code_file' for symbol " + "upload (basename of executable).\n"); + fprintf(stderr, "-i:\t Explicitly set 'debug_id' for symbol " + "upload (typically build ID of executable).\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Examples:\n"); + fprintf(stderr, " With 'sym-upload-v1':\n"); + fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n", + argv[0]); + fprintf(stderr, " With 'sym-upload-v2':\n"); + fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n"); + fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! " + "path/to/symbol_file http://myuploadserver\n", argv[0]); + fprintf(stderr, " [Explicitly set symbol type to 'elf']\n"); + fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! -t elf " + "-c app -i 11111111BBBB3333DDDD555555555555F " + "path/to/symbol_file http://myuploadserver\n", argv[0]); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + int ch; + constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?"; + + while ((ch = getopt(argc, (char * const *)argv, flag_pattern)) != -1) { + switch (ch) { + case 'h': + case '?': + Usage(argc, argv); + exit(0); + break; + case 'u': + options->proxy_user_pwd = optarg; + break; + case 'v': + options->version = optarg; + break; + case 'x': + options->proxy = optarg; + break; + case 'p': + if (strcmp(optarg, "sym-upload-v2") == 0) { + options->upload_protocol = UploadProtocol::SYM_UPLOAD_V2; + } else if (strcmp(optarg, "sym-upload-v1") == 0) { + options->upload_protocol = UploadProtocol::SYM_UPLOAD_V1; + } else { + fprintf(stderr, "Invalid protocol '%s'\n", optarg); + Usage(argc, argv); + exit(1); + } + break; + case 'k': + options->api_key = optarg; + break; + case 't': { + // This is really an enum, so treat as upper-case for consistency with + // enum naming convention on server-side. + options->type = optarg; + StrToUpper(&(options->type)); + break; + } + case 'c': + options->code_file = optarg; + break; + case 'i': + options->debug_id = optarg; + break; + case 'f': + options->force = true; + break; + + default: + fprintf(stderr, "Invalid option '%c'\n", ch); + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + bool is_breakpad_upload = options->type.empty() || + options->type == google_breakpad::sym_upload::kBreakpadSymbolType; + bool has_code_file = !options->code_file.empty(); + bool has_debug_id = !options->debug_id.empty(); + if (is_breakpad_upload && (has_code_file || has_debug_id)) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: -c and -i should only be specified for non-breakpad " + "symbol upload types.\n", argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + if (!is_breakpad_upload && (!has_code_file || !has_debug_id)) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: -c and -i must be specified for non-breakpad " + "symbol upload types.\n", argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + + options->symbolsPath = argv[optind]; + options->uploadURLStr = argv[optind + 1]; +} + +//============================================================================= +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + google_breakpad::sym_upload::Start(&options); + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi b/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi new file mode 100644 index 0000000000..020e4c1c71 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi @@ -0,0 +1,83 @@ +# Copyright 2014 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. + +{ + 'target_defaults': { + 'include_dirs': [ + '../..', + ], + }, + 'targets': [ + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms/dump_syms.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'md2core', + 'type': 'executable', + 'sources': [ + 'md2core/minidump-2-core.cc', + 'md2core/minidump_memory_range.h', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'minidump_upload', + 'type': 'executable', + 'sources': [ + 'symupload/minidump_upload.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload/sym_upload.cc', + ], + 'link_settings': { + 'libraries': [ + '-ldl', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm new file mode 100644 index 0000000000..f68200c7c9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm @@ -0,0 +1,408 @@ +// Copyright (c) 2010 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. + +// crash_report.mm: Convert the contents of a minidump into a format that +// looks more like Apple's CrashReporter format + +#include + +#include +#include + +#include + +#include + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/pathname_stripper.h" +#include "processor/simple_symbol_supplier.h" + +#include "on_demand_symbol_supplier.h" + +using std::string; + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::CodeModules; +using google_breakpad::Minidump; +using google_breakpad::MinidumpProcessor; +using google_breakpad::OnDemandSymbolSupplier; +using google_breakpad::PathnameStripper; +using google_breakpad::ProcessState; +using google_breakpad::scoped_ptr; +using google_breakpad::StackFrame; +using google_breakpad::StackFramePPC; +using google_breakpad::StackFrameX86; +using google_breakpad::SystemInfo; + +typedef struct { + NSString *minidumpPath; + NSString *searchDir; + NSString *symbolSearchDir; + BOOL printThreadMemory; +} Options; + +//============================================================================= +static int PrintRegister(const char *name, u_int32_t value, int sequence) { + if (sequence % 4 == 0) { + printf("\n"); + } + printf("%6s = 0x%08x ", name, value); + return ++sequence; +} + +//============================================================================= +static void PrintStack(const CallStack *stack, const string &cpu) { + size_t frame_count = stack->frames()->size(); + char buffer[1024]; + for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { + const StackFrame *frame = stack->frames()->at(frame_index); + const CodeModule *module = frame->module; + printf("%2zu ", frame_index); + + if (module) { + // Module name (20 chars max) + strcpy(buffer, PathnameStripper::File(module->code_file()).c_str()); + int maxStr = 20; + buffer[maxStr] = 0; + printf("%-*s", maxStr, buffer); + + strcpy(buffer, module->version().c_str()); + buffer[maxStr] = 0; + + printf("%-*s",maxStr, buffer); + + u_int64_t instruction = frame->instruction; + + // PPC only: Adjust the instruction to match that of Crash reporter. The + // instruction listed is actually the return address. See the detailed + // comments in stackwalker_ppc.cc for more information. + if (cpu == "ppc" && frame_index) + instruction += 4; + + printf(" 0x%08llx ", instruction); + + // Function name + if (!frame->function_name.empty()) { + printf("%s", frame->function_name.c_str()); + if (!frame->source_file_name.empty()) { + string source_file = PathnameStripper::File(frame->source_file_name); + printf(" + 0x%llx (%s:%d)", + instruction - frame->source_line_base, + source_file.c_str(), frame->source_line); + } else { + printf(" + 0x%llx", instruction - frame->function_base); + } + } + } + printf("\n"); + } +} + +//============================================================================= +static void PrintRegisters(const CallStack *stack, const string &cpu) { + int sequence = 0; + const StackFrame *frame = stack->frames()->at(0); + if (cpu == "x86") { + const StackFrameX86 *frame_x86 = + reinterpret_cast(frame); + + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) + sequence = PrintRegister("eip", frame_x86->context.eip, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) + sequence = PrintRegister("esp", frame_x86->context.esp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) + sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) + sequence = PrintRegister("esi", frame_x86->context.esi, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) + sequence = PrintRegister("edi", frame_x86->context.edi, sequence); + if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { + sequence = PrintRegister("eax", frame_x86->context.eax, sequence); + sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); + sequence = PrintRegister("edx", frame_x86->context.edx, sequence); + sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); + } + } else if (cpu == "ppc") { + const StackFramePPC *frame_ppc = + reinterpret_cast(frame); + + if ((frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL) == + StackFramePPC::CONTEXT_VALID_ALL) { + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence); + sequence = PrintRegister("cr", frame_ppc->context.cr, sequence); + sequence = PrintRegister("xer", frame_ppc->context.xer, sequence); + sequence = PrintRegister("lr", frame_ppc->context.lr, sequence); + sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence); + sequence = PrintRegister("mq", frame_ppc->context.mq, sequence); + sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence); + + sequence = 0; + char buffer[5]; + for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) { + sprintf(buffer, "r%d", i); + sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence); + } + } else { + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) + sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); + } + } + + printf("\n"); +} + +static void PrintModules(const CodeModules *modules) { + if (!modules) + return; + + printf("\n"); + printf("Loaded modules:\n"); + + u_int64_t main_address = 0; + const CodeModule *main_module = modules->GetMainModule(); + if (main_module) { + main_address = main_module->base_address(); + } + + unsigned int module_count = modules->module_count(); + for (unsigned int module_sequence = 0; + module_sequence < module_count; + ++module_sequence) { + const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + assert(module); + u_int64_t base_address = module->base_address(); + printf("0x%08llx - 0x%08llx %s %s%s %s\n", + base_address, base_address + module->size() - 1, + PathnameStripper::File(module->code_file()).c_str(), + module->version().empty() ? "???" : module->version().c_str(), + main_module != NULL && base_address == main_address ? + " (main)" : "", + module->code_file().c_str()); + } +} + +static void ProcessSingleReport(Options *options, NSString *file_path) { + string minidump_file([file_path fileSystemRepresentation]); + BasicSourceLineResolver resolver; + string search_dir = options->searchDir ? + [options->searchDir fileSystemRepresentation] : ""; + string symbol_search_dir = options->symbolSearchDir ? + [options->symbolSearchDir fileSystemRepresentation] : ""; + scoped_ptr symbol_supplier( + new OnDemandSymbolSupplier(search_dir, symbol_search_dir)); + scoped_ptr + minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver)); + ProcessState process_state; + scoped_ptr dump(new google_breakpad::Minidump(minidump_file)); + + if (!dump->Read()) { + fprintf(stderr, "Minidump %s could not be read\n", dump->path().c_str()); + return; + } + if (minidump_processor->Process(dump.get(), &process_state) != + google_breakpad::PROCESS_OK) { + fprintf(stderr, "MinidumpProcessor::Process failed\n"); + return; + } + + const SystemInfo *system_info = process_state.system_info(); + string cpu = system_info->cpu; + + // Convert the time to a string + u_int32_t time_date_stamp = process_state.time_date_stamp(); + struct tm timestruct; + gmtime_r(reinterpret_cast(&time_date_stamp), ×truct); + char timestr[20]; + strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); + printf("Date: %s GMT\n", timestr); + + printf("Operating system: %s (%s)\n", system_info->os.c_str(), + system_info->os_version.c_str()); + printf("Architecture: %s\n", cpu.c_str()); + + if (process_state.crashed()) { + printf("Crash reason: %s\n", process_state.crash_reason().c_str()); + printf("Crash address: 0x%llx\n", process_state.crash_address()); + } else { + printf("No crash\n"); + } + + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { + printf("\n"); + printf("Thread %d (%s)\n", + requesting_thread, + process_state.crashed() ? "crashed" : + "requested dump, did not crash"); + PrintStack(process_state.threads()->at(requesting_thread), cpu); + } + + // Print all of the threads in the dump. + int thread_count = static_cast(process_state.threads()->size()); + const std::vector + *thread_memory_regions = process_state.thread_memory_regions(); + + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + printf("\n"); + printf("Thread %d\n", thread_index); + PrintStack(process_state.threads()->at(thread_index), cpu); + google_breakpad::MemoryRegion *thread_stack_bytes = + thread_memory_regions->at(thread_index); + if (options->printThreadMemory) { + thread_stack_bytes->Print(); + } + } + } + + // Print the crashed registers + if (requesting_thread != -1) { + printf("\nThread %d:", requesting_thread); + PrintRegisters(process_state.threads()->at(requesting_thread), cpu); + } + + // Print information about modules + PrintModules(process_state.modules()); +} + +//============================================================================= +static void Start(Options *options) { + NSFileManager *manager = [NSFileManager defaultManager]; + NSString *minidump_path = options->minidumpPath; + BOOL is_dir = NO; + BOOL file_exists = [manager fileExistsAtPath:minidump_path + isDirectory:&is_dir]; + if (file_exists && is_dir) { + NSDirectoryEnumerator *enumerator = + [manager enumeratorAtPath:minidump_path]; + NSString *current_file = nil; + while ((current_file = [enumerator nextObject])) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if ([[current_file pathExtension] isEqualTo:@"dmp"]) { + printf("Attempting to process report: %s\n", + [current_file cStringUsingEncoding:NSASCIIStringEncoding]); + NSString *full_path = + [minidump_path stringByAppendingPathComponent:current_file]; + ProcessSingleReport(options, full_path); + } + [pool release]; + } + } else if (file_exists) { + ProcessSingleReport(options, minidump_path); + } +} + +//============================================================================= +static void Usage(int argc, const char *argv[]) { + fprintf(stderr, "Convert a minidump to a crash report. Breakpad symbol " + "files will be used (or created if missing) in /tmp.\n" + "If a symbol-file-search-dir is specified, any symbol " + "files in it will be used instead of being loaded from " + "modules on disk.\n" + "If modules cannot be found at the paths stored in the " + "minidump file, they will be searched for at " + "/.\n"); + fprintf(stderr, "Usage: %s [-s module-search-dir] [-S symbol-file-search-dir] " + "minidump-file\n", argv[0]); + fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n" + "\t-S: Specify a search directory to use for symbol files\n" + "\t-t: Print thread stack memory in hex\n" + "\t-h: Usage\n" + "\t-?: Usage\n"); +} + +//============================================================================= +static void SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "S:s:ht?")) != -1) { + switch (ch) { + case 's': + options->searchDir = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:optarg + length:strlen(optarg)]; + break; + + case 'S': + options->symbolSearchDir = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:optarg + length:strlen(optarg)]; + break; + + case 't': + options->printThreadMemory = YES; + break; + case 'h': + case '?': + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:argv[optind] + length:strlen(argv[optind])]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + [pool release]; + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..33204f7e2e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj @@ -0,0 +1,618 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; }; + 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; }; + 4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; }; + 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; }; + 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; }; + 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; }; + 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */; }; + 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */; }; + 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722C126F9B6E00B43EAF /* x86_misc.c */; }; + 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */; }; + 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7234126F9BC200B43EAF /* ia32_settings.c */; }; + 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */; }; + 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725A126F9C8000B43EAF /* ia32_operand.c */; }; + 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725C126F9C9200B43EAF /* x86_insn.c */; }; + 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */; }; + 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7263126F9CBB00B43EAF /* x86_imm.c */; }; + 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA5613DFBA84006CABE3 /* md5.cc */; }; + 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; }; + 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */; }; + 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */; }; + 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */; }; + 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */; }; + 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */; }; + 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */; }; + 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8411F0C6FB00FCF3E4 /* language.cc */; }; + 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8611F0C6FB00FCF3E4 /* module.cc */; }; + 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */; }; + 8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; }; + 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; }; + 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; }; + 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; }; + 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; }; + 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; }; + 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; }; + 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; }; + 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; }; + 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; }; + 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; }; + 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; }; + 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */; }; + 9BE650B20B52FE3000611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AC0B52FE3000611104 /* file_id.cc */; }; + 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AE0B52FE3000611104 /* macho_id.cc */; }; + 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650B00B52FE3000611104 /* macho_walker.cc */; }; + D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */; }; + D2A5DD631188658B00081F03 /* tokenize.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD621188658B00081F03 /* tokenize.cc */; }; + F407DC48185773C10064622B /* exploitability_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC40185773C10064622B /* exploitability_linux.cc */; }; + F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC41185773C10064622B /* stack_frame_symbolizer.cc */; }; + F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC42185773C10064622B /* stackwalker_arm64.cc */; }; + F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC44185773C10064622B /* stackwalker_mips.cc */; }; + F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC46185773C10064622B /* stackwalker_ppc64.cc */; }; + F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; }; + F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; }; + F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; }; + F47180561D745DEF0032F208 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180541D745DEF0032F208 /* elf_reader.cc */; }; + F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180571D7467630032F208 /* proc_maps_linux.cc */; }; + F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180591D7468A40032F208 /* symbolic_constants_win.cc */; }; + F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; }; + F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; }; + F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; }; + F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; }; + F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */; }; + FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */; }; + FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = ""; }; + 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = ""; }; + 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = ""; }; + 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = ""; }; + 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = ""; }; + 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = ""; }; + 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; }; + 4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; }; + 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; }; + 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disassembler_x86.cc; path = ../../../processor/disassembler_x86.cc; sourceTree = SOURCE_ROOT; }; + 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_disasm.c; path = ../../../third_party/libdisasm/x86_disasm.c; sourceTree = SOURCE_ROOT; }; + 4D2C722C126F9B6E00B43EAF /* x86_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_misc.c; path = ../../../third_party/libdisasm/x86_misc.c; sourceTree = SOURCE_ROOT; }; + 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_operand_list.c; path = ../../../third_party/libdisasm/x86_operand_list.c; sourceTree = SOURCE_ROOT; }; + 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_invariant.c; path = ../../../third_party/libdisasm/ia32_invariant.c; sourceTree = SOURCE_ROOT; }; + 4D2C7234126F9BC200B43EAF /* ia32_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_settings.c; path = ../../../third_party/libdisasm/ia32_settings.c; sourceTree = SOURCE_ROOT; }; + 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_insn.c; path = ../../../third_party/libdisasm/ia32_insn.c; sourceTree = SOURCE_ROOT; }; + 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_opcode_tables.c; path = ../../../third_party/libdisasm/ia32_opcode_tables.c; sourceTree = SOURCE_ROOT; }; + 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_implicit.c; path = ../../../third_party/libdisasm/ia32_implicit.c; sourceTree = SOURCE_ROOT; }; + 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_reg.c; path = ../../../third_party/libdisasm/ia32_reg.c; sourceTree = SOURCE_ROOT; }; + 4D2C725A126F9C8000B43EAF /* ia32_operand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_operand.c; path = ../../../third_party/libdisasm/ia32_operand.c; sourceTree = SOURCE_ROOT; }; + 4D2C725C126F9C9200B43EAF /* x86_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_insn.c; path = ../../../third_party/libdisasm/x86_insn.c; sourceTree = SOURCE_ROOT; }; + 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_modrm.c; path = ../../../third_party/libdisasm/ia32_modrm.c; sourceTree = SOURCE_ROOT; }; + 4D2C7263126F9CBB00B43EAF /* x86_imm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_imm.c; path = ../../../third_party/libdisasm/x86_imm.c; sourceTree = SOURCE_ROOT; }; + 4D72CA5613DFBA84006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; + 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; + 5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; + 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; + 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; + 8B31FF8411F0C6FB00FCF3E4 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF8511F0C6FB00FCF3E4 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; + 8B31FF8611F0C6FB00FCF3E4 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF8711F0C6FB00FCF3E4 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; + 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; + 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; + 8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; }; + 8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; }; + 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; }; + 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = ""; }; + 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = ""; }; + 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; }; + 9B44619D0B66C66B00BBB817 /* system_info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = system_info.h; sourceTree = ""; }; + 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = ""; }; + 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = ""; }; + 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = ""; }; + 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = ""; }; + 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = ""; }; + 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = ""; }; + 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = ""; }; + 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = ""; }; + 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = ""; }; + 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = ""; }; + 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = ""; }; + 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; }; + 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; }; + 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; }; + 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; }; + 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = ""; }; + 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = ""; }; + 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; }; + 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; }; + 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; }; + 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; }; + 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; }; + 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; }; + 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; }; + 9BE650AC0B52FE3000611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650AD0B52FE3000611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650AE0B52FE3000611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650AF0B52FE3000611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650B00B52FE3000611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; + 9BE650B10B52FE3000611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; + D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_frame_info.cc; path = ../../../processor/cfi_frame_info.cc; sourceTree = SOURCE_ROOT; }; + D2A5DD621188658B00081F03 /* tokenize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tokenize.cc; path = ../../../processor/tokenize.cc; sourceTree = SOURCE_ROOT; }; + F407DC40185773C10064622B /* exploitability_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_linux.cc; path = ../../../processor/exploitability_linux.cc; sourceTree = ""; }; + F407DC41185773C10064622B /* stack_frame_symbolizer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stack_frame_symbolizer.cc; path = ../../../processor/stack_frame_symbolizer.cc; sourceTree = ""; }; + F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = ""; }; + F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = ""; }; + F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = ""; }; + F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = ""; }; + F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = ""; }; + F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = ""; }; + F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = ""; }; + F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = ""; }; + F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = ""; }; + F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = ""; }; + F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = ""; }; + F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = ""; }; + F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = ""; }; + F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = ""; }; + F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = ""; }; + F47180571D7467630032F208 /* proc_maps_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proc_maps_linux.cc; path = ../../../processor/proc_maps_linux.cc; sourceTree = ""; }; + F47180591D7468A40032F208 /* symbolic_constants_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = symbolic_constants_win.cc; path = ../../../processor/symbolic_constants_win.cc; sourceTree = ""; }; + F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = ""; }; + F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = ""; }; + F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; + F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; + F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; }; + F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm.cc; path = ../../../processor/stackwalker_arm.cc; sourceTree = SOURCE_ROOT; }; + F9F0706610FBC02D0037B88B /* stackwalker_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm.h; path = ../../../processor/stackwalker_arm.h; sourceTree = SOURCE_ROOT; }; + FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_amd64.cc; path = ../../../processor/stackwalker_amd64.cc; sourceTree = SOURCE_ROOT; }; + FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_amd64.h; path = ../../../processor/stackwalker_amd64.h; sourceTree = SOURCE_ROOT; }; + FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_sparc.cc; path = ../../../processor/stackwalker_sparc.cc; sourceTree = SOURCE_ROOT; }; + FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stackwalker_sparc.h; path = ../../../processor/stackwalker_sparc.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* crash_report */ = { + isa = PBXGroup; + children = ( + 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */, + 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */, + 4247E63F2110D5A500482558 /* path_helper.cc */, + 4247E63E2110D5A500482558 /* path_helper.h */, + 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */, + 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */, + F9C7ECE10E8ABC7F00E953AD /* DWARF */, + 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */, + 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */, + 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */, + 5578003F0BE1F28500EC23E0 /* macho_utilities.h */, + 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */, + 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */, + 9BDF192D0B1BC15D00F8391B /* dump_syms.h */, + 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */, + 08FB7796FE84155DC02AAC07 /* crash_report.mm */, + F44DDD8D19C85CFC0047280E /* process_result.h */, + 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */, + F44DDD8419C85CD50047280E /* dump_context.cc */, + F44DDD8A19C85CFB0047280E /* dump_context.h */, + F44DDD8519C85CD50047280E /* dump_object.cc */, + F44DDD8B19C85CFB0047280E /* dump_object.h */, + F4D43B2E1A38490700C290B2 /* microdump.cc */, + F4D43B301A38492000C290B2 /* microdump.h */, + F44DDD8619C85CD50047280E /* microdump_processor.cc */, + F44DDD8C19C85CFC0047280E /* microdump_processor.h */, + 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */, + 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */, + 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */, + 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */, + 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */, + 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */, + 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */, + 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */, + 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */, + 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */, + 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */, + 8B31FF8411F0C6FB00FCF3E4 /* language.cc */, + 8B31FF8511F0C6FB00FCF3E4 /* language.h */, + 4D72CA5613DFBA84006CABE3 /* md5.cc */, + 8B31FF8611F0C6FB00FCF3E4 /* module.cc */, + 8B31FF8711F0C6FB00FCF3E4 /* module.h */, + 08FB7795FE84155DC02AAC07 /* breakpad */, + 4D2C726E126F9CE200B43EAF /* libdisasm */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = crash_report; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* breakpad */ = { + isa = PBXGroup; + children = ( + 9BE650AB0B52FE1A00611104 /* common */, + 9BDF17280B1B8B0200F8391B /* processor */, + 9BDF16F70B1B8ACD00F8391B /* google_breakpad */, + ); + name = breakpad; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* crash_report */, + ); + name = Products; + sourceTree = ""; + }; + 4D2C726E126F9CE200B43EAF /* libdisasm */ = { + isa = PBXGroup; + children = ( + 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */, + 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */, + 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */, + 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */, + 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */, + 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */, + 4D2C725A126F9C8000B43EAF /* ia32_operand.c */, + 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */, + 4D2C7234126F9BC200B43EAF /* ia32_settings.c */, + 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */, + 4D2C7263126F9CBB00B43EAF /* x86_imm.c */, + 4D2C725C126F9C9200B43EAF /* x86_insn.c */, + 4D2C722C126F9B6E00B43EAF /* x86_misc.c */, + 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */, + ); + name = libdisasm; + sourceTree = ""; + }; + 9BDF16F70B1B8ACD00F8391B /* google_breakpad */ = { + isa = PBXGroup; + children = ( + 9BDF16F80B1B8ACD00F8391B /* common */, + 9BDF16FB0B1B8ACD00F8391B /* processor */, + ); + name = google_breakpad; + path = ../../../google_breakpad; + sourceTree = SOURCE_ROOT; + }; + 9BDF16F80B1B8ACD00F8391B /* common */ = { + isa = PBXGroup; + children = ( + 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */, + 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */, + ); + path = common; + sourceTree = ""; + }; + 9BDF16FB0B1B8ACD00F8391B /* processor */ = { + isa = PBXGroup; + children = ( + 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */, + 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */, + 9B35FEE20B2675F9008DE8C7 /* code_module.h */, + 9B35FEE30B2675F9008DE8C7 /* code_modules.h */, + 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */, + 9BDF16FE0B1B8ACD00F8391B /* minidump.h */, + 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */, + 9BDF17000B1B8ACD00F8391B /* process_state.h */, + 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */, + 9BDF17010B1B8ACD00F8391B /* stack_frame.h */, + 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */, + 9BDF17030B1B8ACD00F8391B /* stackwalker.h */, + 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */, + 9B44619D0B66C66B00BBB817 /* system_info.h */, + ); + path = processor; + sourceTree = ""; + }; + 9BDF17280B1B8B0200F8391B /* processor */ = { + isa = PBXGroup; + children = ( + 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */, + F407DC40185773C10064622B /* exploitability_linux.cc */, + F407DC41185773C10064622B /* stack_frame_symbolizer.cc */, + F407DC42185773C10064622B /* stackwalker_arm64.cc */, + F407DC43185773C10064622B /* stackwalker_arm64.h */, + F407DC44185773C10064622B /* stackwalker_mips.cc */, + F407DC45185773C10064622B /* stackwalker_mips.h */, + F407DC46185773C10064622B /* stackwalker_ppc64.cc */, + F407DC47185773C10064622B /* stackwalker_ppc64.h */, + 4D2C721E126F9ADE00B43EAF /* exploitability.cc */, + 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */, + D2A5DD621188658B00081F03 /* tokenize.cc */, + D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */, + F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */, + F9F0706610FBC02D0037B88B /* stackwalker_arm.h */, + 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */, + 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */, + 9BDF1AFB0B1BEB6300F8391B /* address_map.h */, + 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */, + 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */, + 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */, + 9BDF172A0B1B8B2400F8391B /* call_stack.cc */, + 8B40BDBF0C0638E4009535AF /* logging.cc */, + 9BDF173F0B1B8B9A00F8391B /* minidump.cc */, + 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */, + 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */, + F47180571D7467630032F208 /* proc_maps_linux.cc */, + 9BDF175B0B1B8C1B00F8391B /* process_state.cc */, + 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */, + 9BDF1A7B0B1BE30100F8391B /* range_map.h */, + 9BDF17530B1B8BF900F8391B /* stackwalker.cc */, + 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */, + 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */, + FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */, + FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */, + FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */, + FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */, + F47180591D7468A40032F208 /* symbolic_constants_win.cc */, + ); + name = processor; + sourceTree = ""; + }; + 9BE650AB0B52FE1A00611104 /* common */ = { + isa = PBXGroup; + children = ( + 9BE650AC0B52FE3000611104 /* file_id.cc */, + 9BE650AD0B52FE3000611104 /* file_id.h */, + 9BE650AE0B52FE3000611104 /* macho_id.cc */, + 9BE650AF0B52FE3000611104 /* macho_id.h */, + 9BE650B00B52FE3000611104 /* macho_walker.cc */, + 9BE650B10B52FE3000611104 /* macho_walker.h */, + ); + name = common; + sourceTree = ""; + }; + F9C7ECE10E8ABC7F00E953AD /* DWARF */ = { + isa = PBXGroup; + children = ( + F9C7ECE20E8ABCA600E953AD /* bytereader.cc */, + F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */, + 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */, + 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */, + F47180541D745DEF0032F208 /* elf_reader.cc */, + F47180551D745DEF0032F208 /* elf_reader.h */, + F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */, + ); + name = DWARF; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* crash_report */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = crash_report; + productInstallPath = "$(HOME)/bin"; + productName = crash_report; + productReference = 8DD76FA10486AA7600D96B5E /* crash_report */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + }; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* crash_report */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */, + 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */, + F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */, + 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */, + 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */, + 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */, + F44DDD8719C85CD50047280E /* dump_context.cc in Sources */, + 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */, + 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */, + 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */, + 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */, + F47180561D745DEF0032F208 /* elf_reader.cc in Sources */, + 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */, + 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */, + 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */, + 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */, + 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */, + 9BE650B20B52FE3000611104 /* file_id.cc in Sources */, + 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */, + 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */, + 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */, + 8B40BDC00C0638E4009535AF /* logging.cc in Sources */, + FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */, + FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */, + F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */, + F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */, + F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */, + F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */, + D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */, + D2A5DD631188658B00081F03 /* tokenize.cc in Sources */, + 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */, + F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */, + 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */, + F44DDD8819C85CD50047280E /* dump_object.cc in Sources */, + 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */, + 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */, + 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */, + 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */, + 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */, + 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */, + 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */, + F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */, + F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */, + 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */, + 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */, + 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */, + 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */, + F407DC48185773C10064622B /* exploitability_linux.cc in Sources */, + 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */, + 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */, + 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */, + 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */, + F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */, + 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */, + 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */, + 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */, + 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */, + 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */, + 4247E6402110D5A500482558 /* path_helper.cc in Sources */, + F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */, + 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */, + 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */, + F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */, + 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */, + 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */, + F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */, + 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */, + 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ../../../../src; + PRODUCT_NAME = crash_report; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ../../../../src; + PRODUCT_NAME = crash_report; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h new file mode 100644 index 0000000000..3fbe108ebd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h @@ -0,0 +1,111 @@ +// 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. + +// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create +// a breakpad symbol file on demand. + +#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ +#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ + +#include +#include +#include "google_breakpad/processor/symbol_supplier.h" + +namespace google_breakpad { + +using std::map; +using std::string; +class MinidumpModule; + +class OnDemandSymbolSupplier : public SymbolSupplier { + public: + // |search_dir| is the directory to search for alternative symbols with + // the same name as the module in the minidump + OnDemandSymbolSupplier(const string &search_dir, + const string &symbol_search_dir); + virtual ~OnDemandSymbolSupplier() {} + + // Returns the path to the symbol file for the given module. + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file); + + // Returns the path to the symbol file for the given module. + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data); + // Allocates data buffer on heap, and takes the ownership of + // the data buffer. + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size); + + // Delete the data buffer allocated for module in GetCStringSymbolData(). + virtual void FreeSymbolData(const CodeModule *module); + + protected: + // Search directory + string search_dir_; + string symbol_search_dir_; + + // When we create a symbol file for a module, save the name of the module + // and the path to that module's symbol file. + map module_file_map_; + + // Map of allocated data buffers, keyed by module->code_file(). + map memory_buffers_; + + // Return the name for |module| This will be the value used as the key + // to the |module_file_map_|. + string GetNameForModule(const CodeModule *module); + + // Find the module on local system. If the module resides in a different + // location than the full path in the minidump, this will be the location + // used. + string GetLocalModulePath(const CodeModule *module); + + // Return the full path for |module|. + string GetModulePath(const CodeModule *module); + + // Return the path to the symbol file for |module|. If an empty string is + // returned, then |module| doesn't have a symbol file. + string GetModuleSymbolFile(const CodeModule *module); + + // Generate the breakpad symbol file for |module|. Return true if successful. + // File is generated in /tmp. + bool GenerateSymbolFile(const CodeModule *module, + const SystemInfo *system_info); +}; + +} // namespace google_breakpad + +#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm new file mode 100644 index 0000000000..1955d2667b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm @@ -0,0 +1,314 @@ +// 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. + +#import +#include +#include +#include +#include +#include +#include + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/pathname_stripper.h" + +#include "on_demand_symbol_supplier.h" +#include "common/mac/dump_syms.h" + +using std::map; +using std::string; + +using google_breakpad::OnDemandSymbolSupplier; +using google_breakpad::PathnameStripper; +using google_breakpad::SymbolSupplier; +using google_breakpad::SystemInfo; + +OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir, + const string &symbol_search_dir) + : search_dir_(search_dir) { + NSFileManager *mgr = [NSFileManager defaultManager]; + size_t length = symbol_search_dir.length(); + if (length) { + // Load all sym files in symbol_search_dir into our module_file_map + // A symbol file always starts with a line like this: + // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + // or + // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + const char *symbolSearchStr = symbol_search_dir.c_str(); + NSString *symbolSearchPath = + [mgr stringWithFileSystemRepresentation:symbolSearchStr + length:strlen(symbolSearchStr)]; + NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath]; + NSString *fileName; + NSCharacterSet *hexSet = + [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; + NSCharacterSet *newlineSet = + [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; + while ((fileName = [dirEnum nextObject])) { + // Check to see what type of file we have + NSDictionary *attrib = [dirEnum fileAttributes]; + NSString *fileType = [attrib objectForKey:NSFileType]; + if ([fileType isEqualToString:NSFileTypeDirectory]) { + // Skip subdirectories + [dirEnum skipDescendents]; + } else { + NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName]; + NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; + if (dataStr) { + // Check file to see if it is of appropriate type, and grab module + // name. + NSScanner *scanner = [NSScanner scannerWithString:dataStr]; + BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil]; + if (goodScan) { + goodScan = ([scanner scanString:@"x86 " intoString:nil] || + [scanner scanString:@"x86_64 " intoString:nil] || + [scanner scanString:@"ppc " intoString:nil]); + if (goodScan) { + NSString *moduleID; + goodScan = [scanner scanCharactersFromSet:hexSet + intoString:&moduleID]; + if (goodScan) { + // Module IDs are always 33 chars long + goodScan = [moduleID length] == 33; + if (goodScan) { + NSString *moduleName; + goodScan = [scanner scanUpToCharactersFromSet:newlineSet + intoString:&moduleName]; + if (goodScan) { + goodScan = [moduleName length] > 0; + if (goodScan) { + const char *moduleNameStr = [moduleName UTF8String]; + const char *filePathStr = [filePath fileSystemRepresentation]; + // Map our file + module_file_map_[moduleNameStr] = filePathStr; + } + } + } + } + } + } + } + } + } + } +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) { + string path(GetModuleSymbolFile(module)); + + if (path.empty()) { + if (!GenerateSymbolFile(module, system_info)) + return NOT_FOUND; + + path = GetModuleSymbolFile(module); + } + + if (path.empty()) + return NOT_FOUND; + + *symbol_file = path; + return FOUND; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) { + SymbolSupplier::SymbolResult s = GetSymbolFile(module, + system_info, + symbol_file); + + + if (s == FOUND) { + std::ifstream in(symbol_file->c_str()); + getline(in, *symbol_data, std::string::traits_type::to_char_type( + std::string::traits_type::eof())); + in.close(); + } + + return s; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) { + std::string symbol_data_string; + SymbolSupplier::SymbolResult result = GetSymbolFile(module, + system_info, + symbol_file, + &symbol_data_string); + if (result == FOUND) { + *symbol_data_size = symbol_data_string.size() + 1; + *symbol_data = new char[*symbol_data_size]; + if (*symbol_data == NULL) { + // Should return INTERRUPT on memory allocation failure. + return INTERRUPT; + } + memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); + (*symbol_data)[symbol_data_string.size()] = '\0'; + memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); + } + return result; +} + +void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) { + map::iterator it = memory_buffers_.find(module->code_file()); + if (it != memory_buffers_.end()) { + delete [] it->second; + memory_buffers_.erase(it); + } +} + +string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) { + NSFileManager *mgr = [NSFileManager defaultManager]; + const char *moduleStr = module->code_file().c_str(); + NSString *modulePath = + [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)]; + const char *searchStr = search_dir_.c_str(); + NSString *searchDir = + [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)]; + + if ([mgr fileExistsAtPath:modulePath]) + return module->code_file(); + + // If the module is not found, try to start appending the components to the + // search string and stop if a file (not dir) is found or all components + // have been appended + NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"]; + size_t count = [pathComponents count]; + NSMutableString *path = [NSMutableString string]; + + for (size_t i = 0; i < count; ++i) { + [path setString:searchDir]; + + for (size_t j = 0; j < i + 1; ++j) { + size_t idx = count - 1 - i + j; + [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]]; + } + + BOOL isDir; + if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) { + return [path fileSystemRepresentation]; + } + } + + return ""; +} + +string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) { + return module->code_file(); +} + +string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) { + return PathnameStripper::File(module->code_file()); +} + +string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) { + string name(GetNameForModule(module)); + map::iterator result = module_file_map_.find(name); + + return (result == module_file_map_.end()) ? "" : (*result).second; +} + +static float GetFileModificationTime(const char *path) { + float result = 0; + struct stat file_stat; + if (stat(path, &file_stat) == 0) + result = (float)file_stat.st_mtimespec.tv_sec + + (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f; + + return result; +} + +bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module, + const SystemInfo *system_info) { + bool result = true; + string name = GetNameForModule(module); + string module_path = GetLocalModulePath(module); + NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym", + name.c_str(), system_info->cpu.c_str()]; + + if (module_path.empty()) + return false; + + // Check if there's already a symbol file cached. Ensure that the file is + // newer than the module. Otherwise, generate a new one. + BOOL generate_file = YES; + if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) { + // Check if the module file is newer than the saved symbols + float cache_time = + GetFileModificationTime([symbol_path fileSystemRepresentation]); + float module_time = + GetFileModificationTime(module_path.c_str()); + + if (cache_time > module_time) + generate_file = NO; + } + + if (generate_file) { + DumpSymbols dump(ALL_SYMBOL_DATA, false); + if (dump.Read(module_path)) { + // What Breakpad calls "x86" should be given to the system as "i386". + std::string architecture; + if (system_info->cpu.compare("x86") == 0) { + architecture = "i386"; + } else { + architecture = system_info->cpu; + } + + if (dump.SetArchitecture(architecture)) { + std::fstream file([symbol_path fileSystemRepresentation], + std::ios_base::out | std::ios_base::trunc); + dump.WriteSymbolFile(file); + } else { + printf("Architecture %s not available for %s\n", + system_info->cpu.c_str(), name.c_str()); + result = false; + } + } else { + printf("Unable to open %s\n", module_path.c_str()); + result = false; + } + } + + // Add the mapping + if (result) + module_file_map_[name] = [symbol_path fileSystemRepresentation]; + + return result; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..5b644e24c8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj @@ -0,0 +1,1857 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXAggregateTarget section */ + B88FAFC9116BDCAD00407530 /* all_unittests */ = { + isa = PBXAggregateTarget; + buildConfigurationList = B88FAFCC116BDCCC00407530 /* Build configuration list for PBXAggregateTarget "all_unittests" */; + buildPhases = ( + B88FB094116CE73E00407530 /* ShellScript */, + ); + dependencies = ( + B88FB15B116CF53E00407530 /* PBXTargetDependency */, + B88FAFCF116BDD7000407530 /* PBXTargetDependency */, + B88FB01D116BDF9800407530 /* PBXTargetDependency */, + B88FB167116CF54B00407530 /* PBXTargetDependency */, + B88FAFD1116BDD7000407530 /* PBXTargetDependency */, + B88FB165116CF54B00407530 /* PBXTargetDependency */, + B88FB161116CF54B00407530 /* PBXTargetDependency */, + B88FB15F116CF54B00407530 /* PBXTargetDependency */, + B88FB15D116CF54B00407530 /* PBXTargetDependency */, + B84A9201116CF7D2006C210E /* PBXTargetDependency */, + B88FB0C8116CEB4A00407530 /* PBXTargetDependency */, + 8B31051511F100CF00FCF3E4 /* PBXTargetDependency */, + ); + name = all_unittests; + productName = all_unittests; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; }; + 162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; }; + 4247E63D2110D4B200482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; }; + 4262382721AC496F00E5A3A6 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */; }; + 4262382821AC49A000E5A3A6 /* dwarf_range_list_handler.h in Sources */ = {isa = PBXBuildFile; fileRef = 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */; }; + 4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CAF413DFBAC2006CABE3 /* md5.cc */; }; + 8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; }; + 8BCAAA4D1CE3B1260046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; }; + B84A91F8116CF78F006C210E /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B84A91FB116CF7AF006C210E /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3C11666C8900407530 /* stabs_to_module.cc */; }; + B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */; }; + B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1711665FE400407530 /* dwarf2diehandler.cc */; }; + B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */; }; + B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE201166603300407530 /* dwarf_line_to_module.cc */; }; + B88FAE281166603300407530 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE221166603300407530 /* language.cc */; }; + B88FAE291166603300407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FAE2C1166606200407530 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */; }; + B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3911666C6F00407530 /* stabs_reader.cc */; }; + B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3C11666C8900407530 /* stabs_to_module.cc */; }; + B88FAF37116A595400407530 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF34116A595400407530 /* cfi_assembler.cc */; }; + B88FAF38116A595400407530 /* dwarf2reader_cfi_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */; }; + B88FAF3F116A5A2E00407530 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */; }; + B88FAF40116A5A2E00407530 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B88FB00F116BDEA700407530 /* stabs_reader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */; }; + B88FB010116BDEA700407530 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3911666C6F00407530 /* stabs_reader.cc */; }; + B88FB028116BE03100407530 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; }; + B88FB029116BE03100407530 /* gmock-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA311665AEA00DD08C9 /* gmock-all.cc */; }; + B88FB02A116BE03100407530 /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E9F11665AC300DD08C9 /* gtest_main.cc */; }; + B88FB02B116BE03100407530 /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA011665AC300DD08C9 /* gtest-all.cc */; }; + B88FB03F116BE24200407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB042116BE3C400407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB057116C0CDE00407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0B5116CEA8A00407530 /* module_unittest.cc */; }; + B88FB0C1116CEB0600407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0C4116CEB4100407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB0E3116CEEB000407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1711665FE400407530 /* dwarf2diehandler.cc */; }; + B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */; }; + B88FB0F6116CEF2000407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE201166603300407530 /* dwarf_line_to_module.cc */; }; + B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */; }; + B88FB0FE116CF02400407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB10E116CF08100407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */; }; + B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */; }; + B88FB114116CF1F000407530 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE221166603300407530 /* language.cc */; }; + B88FB115116CF1F000407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB123116CF28500407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB129116CF2DD00407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */; }; + B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */; }; + B88FB139116CF31600407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF34116A595400407530 /* cfi_assembler.cc */; }; + B88FB13E116CF38300407530 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B88FB13F116CF38300407530 /* bytereader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */; }; + B88FB14F116CF4AE00407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB152116CF4D300407530 /* byte_cursor_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */; }; + B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E701166573700DD08C9 /* macho_dump.cc */; }; + B89E0E9911665A7200DD08C9 /* macho_reader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */; }; + B89E0E9A11665A7200DD08C9 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */; }; + B8C5B5181166534700D34F4E /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */; }; + B8C5B51A1166534700D34F4E /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650410B52F6D800611104 /* file_id.cc */; }; + B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650430B52F6D800611104 /* macho_id.cc */; }; + B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650450B52F6D800611104 /* macho_walker.cc */; }; + B8C5B51D1166534700D34F4E /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dump_syms.cc */; }; + B8C5B51E1166534700D34F4E /* dump_syms_tool.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */; }; + B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */; }; + D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; }; + EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D21F97D111CBA0F200239E38; + remoteInfo = test_assembler_unittest; + }; + B84A91F9116CF796006C210E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B84A9200116CF7D2006C210E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B84A91F3116CF784006C210E; + remoteInfo = stabs_to_module_unittest; + }; + B88FAFCE116BDD7000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B89E0E9411665A6400DD08C9; + remoteInfo = macho_reader_unittest; + }; + B88FAFD0116BDD7000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FAF2E116A591D00407530; + remoteInfo = dwarf2reader_cfi_unittest; + }; + B88FB01C116BDF9800407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB006116BDE8300407530; + remoteInfo = stabs_reader_unittest; + }; + B88FB039116BE17E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB087116CE6D800407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB08F116CE71000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0BF116CEAFE00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0C7116CEB4A00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0B8116CEABF00407530; + remoteInfo = module_unittest; + }; + B88FB0E7116CEEDA00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0F7116CEF2E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB10F116CF08A00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB124116CF29E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB13B116CF35C00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB150116CF4C100407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB15A116CF53E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB14A116CF4A700407530; + remoteInfo = byte_cursor_unittest; + }; + B88FB15C116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB11E116CF27F00407530; + remoteInfo = dwarf_cfi_to_module_unittest; + }; + B88FB15E116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0F1116CEF1900407530; + remoteInfo = dwarf_line_to_module_unittest; + }; + B88FB160116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB109116CF07900407530; + remoteInfo = dwarf_cu_to_module_unittest; + }; + B88FB164116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0DE116CEEA800407530; + remoteInfo = dwarf2diehandler_unittest; + }; + B88FB166116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB134116CF30F00407530; + remoteInfo = bytereader_unittest; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 162F64F8161C591500CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = ""; }; + 162F64F9161C591500CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = ""; }; + 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = ""; }; + 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = ""; }; + 4D72CAF413DFBAC2006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; + 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; + 5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; + 8B31023E11F0CF1C00FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = ""; }; + 8BCAAA4B1CE3A7980046090B /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = ""; }; + 9BDF186D0B1BB43700F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = ""; }; + 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dump_syms_tool.cc; sourceTree = ""; }; + 9BE650410B52F6D800611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650420B52F6D800611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650430B52F6D800611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650440B52F6D800611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650450B52F6D800611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; + 9BE650460B52F6D800611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; + B84A91F4116CF784006C210E /* stabs_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stabs_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FAE0911665B5700407530 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = SOURCE_ROOT; }; + B88FAE0A11665B5700407530 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = SOURCE_ROOT; }; + B88FAE1711665FE400407530 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; + B88FAE1811665FE400407530 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; + B88FAE1D1166603300407530 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = SOURCE_ROOT; }; + B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE201166603300407530 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE211166603300407530 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE221166603300407530 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; + B88FAE231166603300407530 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; + B88FAE241166603300407530 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE251166603300407530 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; + B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE3911666C6F00407530 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; + B88FAE3A11666C6F00407530 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; + B88FAE3C11666C8900407530 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE3D11666C8900407530 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf2reader_cfi_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FAF34116A595400407530 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = SOURCE_ROOT; }; + B88FAF35116A595400407530 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = SOURCE_ROOT; }; + B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader_cfi_unittest.cc; path = ../../../common/dwarf/dwarf2reader_cfi_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader_unittest.cc; path = ../../../common/stabs_reader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB007116BDE8300407530 /* stabs_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stabs_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB024116BDFFF00407530 /* libgtestmockall.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtestmockall.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0B5116CEA8A00407530 /* module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module_unittest.cc; path = ../../../common/module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0B9116CEABF00407530 /* module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = byte_cursor_unittest.cc; path = ../../../common/byte_cursor_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module_unittest.cc; path = ../../../common/dwarf_cfi_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module_unittest.cc; path = ../../../common/dwarf_cu_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module_unittest.cc; path = ../../../common/dwarf_line_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module_unittest.cc; path = ../../../common/stabs_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler_unittest.cc; path = ../../../common/test_assembler_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader_unittest.cc; path = ../../../common/dwarf/bytereader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler_unittest.cc; path = ../../../common/dwarf/dwarf2diehandler_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf2diehandler_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_line_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_cu_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_cfi_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB135116CF30F00407530 /* bytereader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bytereader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB14B116CF4A700407530 /* byte_cursor_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = byte_cursor_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader_unittest.cc; path = ../../../common/mac/macho_reader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B89E0E6E1166571D00DD08C9 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; + B89E0E6F1166571D00DD08C9 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; + B89E0E701166573700DD08C9 /* macho_dump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dump.cc; sourceTree = ""; }; + B89E0E741166575200DD08C9 /* macho_dump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_dump; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E9511665A6400DD08C9 /* macho_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E9F11665AC300DD08C9 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../../testing/googletest/src/gtest_main.cc; sourceTree = SOURCE_ROOT; }; + B89E0EA011665AC300DD08C9 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../../testing/googletest/src/gtest-all.cc"; sourceTree = SOURCE_ROOT; }; + B89E0EA311665AEA00DD08C9 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../../testing/googlemock/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; }; + B8C5B5111166531A00D34F4E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; }; + B8E8CA0C1156C854009E61B2 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = SOURCE_ROOT; }; + D21F97D211CBA0F200239E38 /* test_assembler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_assembler_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + EB06C7511FEBC515000214D9 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = ""; }; + EB06C7521FEBC516000214D9 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = ""; }; + F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = SOURCE_ROOT; }; + F95B422C0E0E22D100DBDE83 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; + F95B422D0E0E22D100DBDE83 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = SOURCE_ROOT; }; + F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = SOURCE_ROOT; }; + F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; + F95B42300E0E22D100DBDE83 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = SOURCE_ROOT; }; + F95B42310E0E22D100DBDE83 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B84A91F2116CF784006C210E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B84A91F8116CF78F006C210E /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FAF2D116A591D00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB042116BE3C400407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB005116BDE8300407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB03F116BE24200407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB022116BDFFF00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0B7116CEABF00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0C1116CEB0600407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0DD116CEEA800407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0E3116CEEB000407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0F0116CEF1900407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0F6116CEF2000407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB108116CF07900407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB10E116CF08100407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB11D116CF27F00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB123116CF28500407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB133116CF30F00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB139116CF31600407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB149116CF4A700407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB14F116CF4AE00407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E721166575200DD08C9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E9311665A6400DD08C9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB057116C0CDE00407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B8C5B50F1166531A00D34F4E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D21F97D011CBA0F200239E38 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* dump_syms */ = { + isa = PBXGroup; + children = ( + 8B31023E11F0CF1C00FCF3E4 /* Breakpad.xcconfig */, + 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */, + B89E0E9D11665A9500DD08C9 /* TESTING */, + F9F5344B0E7C8FFC0012363F /* DWARF */, + B89E0E6C1166569700DD08C9 /* MACHO */, + B88FAE3811666A1700407530 /* STABS */, + B88FAE1C11665FFD00407530 /* MODULE */, + 162F64F8161C591500CD68D5 /* arch_utilities.cc */, + 162F64F9161C591500CD68D5 /* arch_utilities.h */, + B88FAE1D1166603300407530 /* byte_cursor.h */, + B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */, + B8E8CA0C1156C854009E61B2 /* byteswap.h */, + 9BE650410B52F6D800611104 /* file_id.cc */, + 9BE650420B52F6D800611104 /* file_id.h */, + 9BDF186D0B1BB43700F8391B /* dump_syms.h */, + 08FB7796FE84155DC02AAC07 /* dump_syms.cc */, + 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */, + B89E0E701166573700DD08C9 /* macho_dump.cc */, + 4D72CAF413DFBAC2006CABE3 /* md5.cc */, + EB06C7511FEBC515000214D9 /* path_helper.cc */, + EB06C7521FEBC516000214D9 /* path_helper.h */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = dump_syms; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + B8C5B5111166531A00D34F4E /* dump_syms */, + B89E0E741166575200DD08C9 /* macho_dump */, + B89E0E9511665A6400DD08C9 /* macho_reader_unittest */, + B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */, + B88FB007116BDE8300407530 /* stabs_reader_unittest */, + B88FB024116BDFFF00407530 /* libgtestmockall.a */, + B88FB0B9116CEABF00407530 /* module_unittest */, + B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */, + B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */, + B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */, + B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */, + B88FB135116CF30F00407530 /* bytereader_unittest */, + B88FB14B116CF4A700407530 /* byte_cursor_unittest */, + B84A91F4116CF784006C210E /* stabs_to_module_unittest */, + D21F97D211CBA0F200239E38 /* test_assembler_unittest */, + ); + name = Products; + sourceTree = ""; + }; + B88FAE1C11665FFD00407530 /* MODULE */ = { + isa = PBXGroup; + children = ( + B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */, + B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */, + B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */, + B88FAE201166603300407530 /* dwarf_line_to_module.cc */, + B88FAE211166603300407530 /* dwarf_line_to_module.h */, + B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */, + B88FAE221166603300407530 /* language.cc */, + B88FAE231166603300407530 /* language.h */, + B88FAE241166603300407530 /* module.cc */, + B88FAE251166603300407530 /* module.h */, + B88FB0B5116CEA8A00407530 /* module_unittest.cc */, + B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */, + B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */, + B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */, + B88FAE3C11666C8900407530 /* stabs_to_module.cc */, + B88FAE3D11666C8900407530 /* stabs_to_module.h */, + B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */, + ); + name = MODULE; + sourceTree = ""; + }; + B88FAE3811666A1700407530 /* STABS */ = { + isa = PBXGroup; + children = ( + B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */, + B88FAE3911666C6F00407530 /* stabs_reader.cc */, + B88FAE3A11666C6F00407530 /* stabs_reader.h */, + ); + name = STABS; + sourceTree = ""; + }; + B89E0E6C1166569700DD08C9 /* MACHO */ = { + isa = PBXGroup; + children = ( + B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */, + B89E0E6E1166571D00DD08C9 /* macho_reader.cc */, + B89E0E6F1166571D00DD08C9 /* macho_reader.h */, + 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */, + 5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */, + 9BE650430B52F6D800611104 /* macho_id.cc */, + 9BE650440B52F6D800611104 /* macho_id.h */, + 9BE650450B52F6D800611104 /* macho_walker.cc */, + 9BE650460B52F6D800611104 /* macho_walker.h */, + ); + name = MACHO; + sourceTree = ""; + }; + B89E0E9D11665A9500DD08C9 /* TESTING */ = { + isa = PBXGroup; + children = ( + B88FAE0911665B5700407530 /* test_assembler.cc */, + B88FAE0A11665B5700407530 /* test_assembler.h */, + B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */, + B89E0EA311665AEA00DD08C9 /* gmock-all.cc */, + B89E0E9F11665AC300DD08C9 /* gtest_main.cc */, + B89E0EA011665AC300DD08C9 /* gtest-all.cc */, + ); + name = TESTING; + sourceTree = ""; + }; + F9F5344B0E7C8FFC0012363F /* DWARF */ = { + isa = PBXGroup; + children = ( + B88FAF34116A595400407530 /* cfi_assembler.cc */, + B88FAF35116A595400407530 /* cfi_assembler.h */, + F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */, + F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */, + 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */, + 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */, + F95B42300E0E22D100DBDE83 /* dwarf2reader.h */, + B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */, + F95B422D0E0E22D100DBDE83 /* bytereader.h */, + F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */, + F95B422C0E0E22D100DBDE83 /* bytereader.cc */, + B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */, + F95B42310E0E22D100DBDE83 /* line_state_machine.h */, + B88FAE1711665FE400407530 /* dwarf2diehandler.cc */, + B88FAE1811665FE400407530 /* dwarf2diehandler.h */, + B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */, + 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */, + 8BCAAA4B1CE3A7980046090B /* elf_reader.h */, + ); + name = DWARF; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B88FB020116BDFFF00407530 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B84A91F3116CF784006C210E /* stabs_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B84A9202116CF7F0006C210E /* Build configuration list for PBXNativeTarget "stabs_to_module_unittest" */; + buildPhases = ( + B84A91F1116CF784006C210E /* Sources */, + B84A91F2116CF784006C210E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B84A91FA116CF796006C210E /* PBXTargetDependency */, + ); + name = stabs_to_module_unittest; + productName = stabs_to_module_unittest; + productReference = B84A91F4116CF784006C210E /* stabs_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FAF33116A594800407530 /* Build configuration list for PBXNativeTarget "dwarf2reader_cfi_unittest" */; + buildPhases = ( + B88FAF2C116A591D00407530 /* Sources */, + B88FAF2D116A591D00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB03A116BE17E00407530 /* PBXTargetDependency */, + ); + name = dwarf2reader_cfi_unittest; + productName = dwarf2reader_cfi_unittest; + productReference = B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB006116BDE8300407530 /* stabs_reader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB013116BDEC800407530 /* Build configuration list for PBXNativeTarget "stabs_reader_unittest" */; + buildPhases = ( + B88FB004116BDE8300407530 /* Sources */, + B88FB005116BDE8300407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB088116CE6D800407530 /* PBXTargetDependency */, + ); + name = stabs_reader_unittest; + productName = stabs_reader_unittest; + productReference = B88FB007116BDE8300407530 /* stabs_reader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB023116BDFFF00407530 /* gtestmockall */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB027116BE02900407530 /* Build configuration list for PBXNativeTarget "gtestmockall" */; + buildPhases = ( + B88FB020116BDFFF00407530 /* Headers */, + B88FB021116BDFFF00407530 /* Sources */, + B88FB022116BDFFF00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = gtestmockall; + productName = gtestmockall; + productReference = B88FB024116BDFFF00407530 /* libgtestmockall.a */; + productType = "com.apple.product-type.library.static"; + }; + B88FB0B8116CEABF00407530 /* module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0BE116CEAFE00407530 /* Build configuration list for PBXNativeTarget "module_unittest" */; + buildPhases = ( + B88FB0B6116CEABF00407530 /* Sources */, + B88FB0B7116CEABF00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0C0116CEAFE00407530 /* PBXTargetDependency */, + ); + name = module_unittest; + productName = module_unittest; + productReference = B88FB0B9116CEABF00407530 /* module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0E4116CEECE00407530 /* Build configuration list for PBXNativeTarget "dwarf2diehandler_unittest" */; + buildPhases = ( + B88FB0DC116CEEA800407530 /* Sources */, + B88FB0DD116CEEA800407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0E8116CEEDA00407530 /* PBXTargetDependency */, + ); + name = dwarf2diehandler_unittest; + productName = dwarf2diehandler_unittest; + productReference = B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0F9116CEF9800407530 /* Build configuration list for PBXNativeTarget "dwarf_line_to_module_unittest" */; + buildPhases = ( + B88FB0EF116CEF1900407530 /* Sources */, + B88FB0F0116CEF1900407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0F8116CEF2E00407530 /* PBXTargetDependency */, + ); + name = dwarf_line_to_module_unittest; + productName = dwarf_line_to_module_unittest; + productReference = B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB111116CF0A800407530 /* Build configuration list for PBXNativeTarget "dwarf_cu_to_module_unittest" */; + buildPhases = ( + B88FB107116CF07900407530 /* Sources */, + B88FB108116CF07900407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB110116CF08A00407530 /* PBXTargetDependency */, + ); + name = dwarf_cu_to_module_unittest; + productName = dwarf_cu_to_module_unittest; + productReference = B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB128116CF2C800407530 /* Build configuration list for PBXNativeTarget "dwarf_cfi_to_module_unittest" */; + buildPhases = ( + B88FB11C116CF27F00407530 /* Sources */, + B88FB11D116CF27F00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB125116CF29E00407530 /* PBXTargetDependency */, + ); + name = dwarf_cfi_to_module_unittest; + productName = dwarf_cfi_to_module_unittest; + productReference = B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB134116CF30F00407530 /* bytereader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB13A116CF33400407530 /* Build configuration list for PBXNativeTarget "bytereader_unittest" */; + buildPhases = ( + B88FB132116CF30F00407530 /* Sources */, + B88FB133116CF30F00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB13C116CF35C00407530 /* PBXTargetDependency */, + ); + name = bytereader_unittest; + productName = bytereader_unittest; + productReference = B88FB135116CF30F00407530 /* bytereader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB14A116CF4A700407530 /* byte_cursor_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB159116CF4F900407530 /* Build configuration list for PBXNativeTarget "byte_cursor_unittest" */; + buildPhases = ( + B88FB148116CF4A700407530 /* Sources */, + B88FB149116CF4A700407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB151116CF4C100407530 /* PBXTargetDependency */, + ); + name = byte_cursor_unittest; + productName = byte_cursor_unittest; + productReference = B88FB14B116CF4A700407530 /* byte_cursor_unittest */; + productType = "com.apple.product-type.tool"; + }; + B89E0E731166575200DD08C9 /* macho_dump */ = { + isa = PBXNativeTarget; + buildConfigurationList = B89E0E7F116657A100DD08C9 /* Build configuration list for PBXNativeTarget "macho_dump" */; + buildPhases = ( + B89E0E711166575200DD08C9 /* Sources */, + B89E0E721166575200DD08C9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = macho_dump; + productName = macho_dump; + productReference = B89E0E741166575200DD08C9 /* macho_dump */; + productType = "com.apple.product-type.tool"; + }; + B89E0E9411665A6400DD08C9 /* macho_reader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B89E0E9E11665A9600DD08C9 /* Build configuration list for PBXNativeTarget "macho_reader_unittest" */; + buildPhases = ( + B89E0E9211665A6400DD08C9 /* Sources */, + B89E0E9311665A6400DD08C9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB090116CE71000407530 /* PBXTargetDependency */, + ); + name = macho_reader_unittest; + productName = macho_reader_unittest; + productReference = B89E0E9511665A6400DD08C9 /* macho_reader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B8C5B5101166531A00D34F4E /* dump_syms */ = { + isa = PBXNativeTarget; + buildConfigurationList = B8C5B5151166533900D34F4E /* Build configuration list for PBXNativeTarget "dump_syms" */; + buildPhases = ( + B8C5B50E1166531A00D34F4E /* Sources */, + B8C5B50F1166531A00D34F4E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dump_syms; + productName = dump_syms; + productReference = B8C5B5111166531A00D34F4E /* dump_syms */; + productType = "com.apple.product-type.tool"; + }; + D21F97D111CBA0F200239E38 /* test_assembler_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = D21F97D611CBA11000239E38 /* Build configuration list for PBXNativeTarget "test_assembler_unittest" */; + buildPhases = ( + D21F97CF11CBA0F200239E38 /* Sources */, + D21F97D011CBA0F200239E38 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = test_assembler_unittest; + productName = test_assembler_unittest; + productReference = D21F97D211CBA0F200239E38 /* test_assembler_unittest */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + }; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "dump_syms" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* dump_syms */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B8C5B5101166531A00D34F4E /* dump_syms */, + B89E0E731166575200DD08C9 /* macho_dump */, + B88FB023116BDFFF00407530 /* gtestmockall */, + B88FB14A116CF4A700407530 /* byte_cursor_unittest */, + B89E0E9411665A6400DD08C9 /* macho_reader_unittest */, + B88FB006116BDE8300407530 /* stabs_reader_unittest */, + B88FB134116CF30F00407530 /* bytereader_unittest */, + B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */, + B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */, + B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */, + B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */, + B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */, + B84A91F3116CF784006C210E /* stabs_to_module_unittest */, + B88FB0B8116CEABF00407530 /* module_unittest */, + B88FAFC9116BDCAD00407530 /* all_unittests */, + D21F97D111CBA0F200239E38 /* test_assembler_unittest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + B88FB094116CE73E00407530 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -eu\n\ncd $BUILT_PRODUCTS_DIR\npwd\n\n./byte_cursor_unittest\n./macho_reader_unittest\n./stabs_reader_unittest\n./bytereader_unittest\n./dwarf2reader_cfi_unittest\n./dwarf2diehandler_unittest\n./dwarf_cu_to_module_unittest\n./dwarf_line_to_module_unittest\n./dwarf_cfi_to_module_unittest\n./stabs_to_module_unittest\n./module_unittest\n./test_assembler_unittest\n\necho \"Expect two warnings from the following tests:\"\necho \" Errors.BadFileNumber\"\necho \" Errors.BadDirectoryNumber\"\necho \"The proper behavior of these tests is to print text that XCode confuses with compiler warnings.\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B84A91F1116CF784006C210E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B84A91FB116CF7AF006C210E /* module.cc in Sources */, + B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */, + B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FAF2C116A591D00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FAF38116A595400407530 /* dwarf2reader_cfi_unittest.cc in Sources */, + B88FAF3F116A5A2E00407530 /* dwarf2reader.cc in Sources */, + 8BCAAA4D1CE3B1260046090B /* elf_reader.cc in Sources */, + B88FAF40116A5A2E00407530 /* bytereader.cc in Sources */, + B88FAF37116A595400407530 /* cfi_assembler.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB004116BDE8300407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB00F116BDEA700407530 /* stabs_reader_unittest.cc in Sources */, + B88FB010116BDEA700407530 /* stabs_reader.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB021116BDFFF00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB028116BE03100407530 /* test_assembler.cc in Sources */, + B88FB029116BE03100407530 /* gmock-all.cc in Sources */, + B88FB02A116BE03100407530 /* gtest_main.cc in Sources */, + B88FB02B116BE03100407530 /* gtest-all.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0B6116CEABF00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */, + B88FB0C4116CEB4100407530 /* module.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0DC116CEEA800407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */, + B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0EF116CEF1900407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */, + B88FB0FE116CF02400407530 /* module.cc in Sources */, + B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB107116CF07900407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */, + B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */, + B88FB114116CF1F000407530 /* language.cc in Sources */, + B88FB115116CF1F000407530 /* module.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB11C116CF27F00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB129116CF2DD00407530 /* module.cc in Sources */, + B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */, + B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB132116CF30F00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */, + B88FB13E116CF38300407530 /* bytereader.cc in Sources */, + B88FB13F116CF38300407530 /* bytereader_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB148116CF4A700407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB152116CF4D300407530 /* byte_cursor_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E711166575200DD08C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4247E63D2110D4B200482558 /* path_helper.cc in Sources */, + 162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */, + B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */, + B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E9211665A6400DD08C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B89E0E9911665A7200DD08C9 /* macho_reader_unittest.cc in Sources */, + B89E0E9A11665A7200DD08C9 /* macho_reader.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B8C5B50E1166531A00D34F4E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4262382821AC49A000E5A3A6 /* dwarf_range_list_handler.h in Sources */, + 162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */, + B88FAE2C1166606200407530 /* macho_reader.cc in Sources */, + 8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */, + B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */, + EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */, + B8C5B5181166534700D34F4E /* bytereader.cc in Sources */, + B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */, + B8C5B51A1166534700D34F4E /* file_id.cc in Sources */, + B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */, + B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */, + B8C5B51D1166534700D34F4E /* dump_syms.cc in Sources */, + B8C5B51E1166534700D34F4E /* dump_syms_tool.cc in Sources */, + B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */, + B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */, + B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */, + 4262382721AC496F00E5A3A6 /* dwarf_range_list_handler.cc in Sources */, + B88FAE281166603300407530 /* language.cc in Sources */, + B88FAE291166603300407530 /* module.cc in Sources */, + B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */, + B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */, + B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */, + 4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D21F97CF11CBA0F200239E38 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */, + D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 8B31051511F100CF00FCF3E4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D21F97D111CBA0F200239E38 /* test_assembler_unittest */; + targetProxy = 8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */; + }; + B84A91FA116CF796006C210E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B84A91F9116CF796006C210E /* PBXContainerItemProxy */; + }; + B84A9201116CF7D2006C210E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B84A91F3116CF784006C210E /* stabs_to_module_unittest */; + targetProxy = B84A9200116CF7D2006C210E /* PBXContainerItemProxy */; + }; + B88FAFCF116BDD7000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B89E0E9411665A6400DD08C9 /* macho_reader_unittest */; + targetProxy = B88FAFCE116BDD7000407530 /* PBXContainerItemProxy */; + }; + B88FAFD1116BDD7000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */; + targetProxy = B88FAFD0116BDD7000407530 /* PBXContainerItemProxy */; + }; + B88FB01D116BDF9800407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB006116BDE8300407530 /* stabs_reader_unittest */; + targetProxy = B88FB01C116BDF9800407530 /* PBXContainerItemProxy */; + }; + B88FB03A116BE17E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB039116BE17E00407530 /* PBXContainerItemProxy */; + }; + B88FB088116CE6D800407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB087116CE6D800407530 /* PBXContainerItemProxy */; + }; + B88FB090116CE71000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB08F116CE71000407530 /* PBXContainerItemProxy */; + }; + B88FB0C0116CEAFE00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0BF116CEAFE00407530 /* PBXContainerItemProxy */; + }; + B88FB0C8116CEB4A00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0B8116CEABF00407530 /* module_unittest */; + targetProxy = B88FB0C7116CEB4A00407530 /* PBXContainerItemProxy */; + }; + B88FB0E8116CEEDA00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0E7116CEEDA00407530 /* PBXContainerItemProxy */; + }; + B88FB0F8116CEF2E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0F7116CEF2E00407530 /* PBXContainerItemProxy */; + }; + B88FB110116CF08A00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB10F116CF08A00407530 /* PBXContainerItemProxy */; + }; + B88FB125116CF29E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB124116CF29E00407530 /* PBXContainerItemProxy */; + }; + B88FB13C116CF35C00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB13B116CF35C00407530 /* PBXContainerItemProxy */; + }; + B88FB151116CF4C100407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB150116CF4C100407530 /* PBXContainerItemProxy */; + }; + B88FB15B116CF53E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB14A116CF4A700407530 /* byte_cursor_unittest */; + targetProxy = B88FB15A116CF53E00407530 /* PBXContainerItemProxy */; + }; + B88FB15D116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */; + targetProxy = B88FB15C116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB15F116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */; + targetProxy = B88FB15E116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB161116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */; + targetProxy = B88FB160116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB165116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */; + targetProxy = B88FB164116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB167116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB134116CF30F00407530 /* bytereader_unittest */; + targetProxy = B88FB166116CF54B00407530 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Release; + }; + B84A91F6116CF784006C210E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Debug; + }; + B84A91F7116CF784006C210E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Release; + }; + B88FAF31116A591F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/build/Debug\""; + PRODUCT_NAME = dwarf2reader_cfi_unittest; + }; + name = Debug; + }; + B88FAF32116A591F00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/build/Debug\""; + PRODUCT_NAME = dwarf2reader_cfi_unittest; + }; + name = Release; + }; + B88FAFCA116BDCAD00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = all_unittests; + }; + name = Debug; + }; + B88FAFCB116BDCAD00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = all_unittests; + }; + name = Release; + }; + B88FB009116BDE8400407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_reader_unittest; + }; + name = Debug; + }; + B88FB00A116BDE8400407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_reader_unittest; + }; + name = Release; + }; + B88FB025116BE00100407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Debug; + }; + B88FB026116BE00100407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Release; + }; + B88FB0BB116CEAC000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Debug; + }; + B88FB0BC116CEAC000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Release; + }; + B88FB0E1116CEEA800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Debug; + }; + B88FB0E2116CEEA800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Release; + }; + B88FB0F4116CEF1900407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Debug; + }; + B88FB0F5116CEF1900407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Release; + }; + B88FB10C116CF07A00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Debug; + }; + B88FB10D116CF07A00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Release; + }; + B88FB121116CF28000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Debug; + }; + B88FB122116CF28000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Release; + }; + B88FB137116CF30F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Debug; + }; + B88FB138116CF30F00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Release; + }; + B88FB14D116CF4A800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = byte_cursor_unittest; + }; + name = Debug; + }; + B88FB14E116CF4A800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = byte_cursor_unittest; + }; + name = Release; + }; + B89E0E761166575300DD08C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = macho_dump; + }; + name = Debug; + }; + B89E0E771166575300DD08C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = macho_dump; + }; + name = Release; + }; + B89E0E9711665A6400DD08C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = macho_reader_unittest; + }; + name = Debug; + }; + B89E0E9811665A6400DD08C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = macho_reader_unittest; + }; + name = Release; + }; + B8C5B5131166531B00D34F4E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_VERSION = ""; + PRODUCT_NAME = dump_syms; + }; + name = Debug; + }; + B8C5B5141166531B00D34F4E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_VERSION = ""; + PRODUCT_NAME = dump_syms; + }; + name = Release; + }; + D21F97D411CBA0F200239E38 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = test_assembler_unittest; + }; + name = Debug; + }; + D21F97D511CBA0F200239E38 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = test_assembler_unittest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "dump_syms" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B84A9202116CF7F0006C210E /* Build configuration list for PBXNativeTarget "stabs_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B84A91F6116CF784006C210E /* Debug */, + B84A91F7116CF784006C210E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FAF33116A594800407530 /* Build configuration list for PBXNativeTarget "dwarf2reader_cfi_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FAF31116A591F00407530 /* Debug */, + B88FAF32116A591F00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FAFCC116BDCCC00407530 /* Build configuration list for PBXAggregateTarget "all_unittests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FAFCA116BDCAD00407530 /* Debug */, + B88FAFCB116BDCAD00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB013116BDEC800407530 /* Build configuration list for PBXNativeTarget "stabs_reader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB009116BDE8400407530 /* Debug */, + B88FB00A116BDE8400407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB027116BE02900407530 /* Build configuration list for PBXNativeTarget "gtestmockall" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB025116BE00100407530 /* Debug */, + B88FB026116BE00100407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0BE116CEAFE00407530 /* Build configuration list for PBXNativeTarget "module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0BB116CEAC000407530 /* Debug */, + B88FB0BC116CEAC000407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0E4116CEECE00407530 /* Build configuration list for PBXNativeTarget "dwarf2diehandler_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0E1116CEEA800407530 /* Debug */, + B88FB0E2116CEEA800407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0F9116CEF9800407530 /* Build configuration list for PBXNativeTarget "dwarf_line_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0F4116CEF1900407530 /* Debug */, + B88FB0F5116CEF1900407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB111116CF0A800407530 /* Build configuration list for PBXNativeTarget "dwarf_cu_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB10C116CF07A00407530 /* Debug */, + B88FB10D116CF07A00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB128116CF2C800407530 /* Build configuration list for PBXNativeTarget "dwarf_cfi_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB121116CF28000407530 /* Debug */, + B88FB122116CF28000407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB13A116CF33400407530 /* Build configuration list for PBXNativeTarget "bytereader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB137116CF30F00407530 /* Debug */, + B88FB138116CF30F00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB159116CF4F900407530 /* Build configuration list for PBXNativeTarget "byte_cursor_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB14D116CF4A800407530 /* Debug */, + B88FB14E116CF4A800407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B89E0E7F116657A100DD08C9 /* Build configuration list for PBXNativeTarget "macho_dump" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B89E0E761166575300DD08C9 /* Debug */, + B89E0E771166575300DD08C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B89E0E9E11665A9600DD08C9 /* Build configuration list for PBXNativeTarget "macho_reader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B89E0E9711665A6400DD08C9 /* Debug */, + B89E0E9811665A6400DD08C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B8C5B5151166533900D34F4E /* Build configuration list for PBXNativeTarget "dump_syms" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B8C5B5131166531B00D34F4E /* Debug */, + B8C5B5141166531B00D34F4E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D21F97D611CBA11000239E38 /* Build configuration list for PBXNativeTarget "test_assembler_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D21F97D411CBA0F200239E38 /* Debug */, + D21F97D511CBA0F200239E38 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc new file mode 100644 index 0000000000..6f68457b4c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc @@ -0,0 +1,264 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011, 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. + +// dump_syms_tool.cc: Command line tool that uses the DumpSymbols class. +// TODO(waylonis): accept stdin + +#include +#include + +#include +#include +#include + +#include "common/mac/dump_syms.h" +#include "common/mac/arch_utilities.h" +#include "common/mac/macho_utilities.h" +#include "common/scoped_ptr.h" + +using google_breakpad::DumpSymbols; +using google_breakpad::Module; +using google_breakpad::scoped_ptr; +using std::vector; + +struct Options { + Options() + : srcPath(), dsymPath(), arch(), header_only(false), + cfi(true), handle_inter_cu_refs(true) {} + + string srcPath; + string dsymPath; + const NXArchInfo *arch; + bool header_only; + bool cfi; + bool handle_inter_cu_refs; +}; + +static bool StackFrameEntryComparator(const Module::StackFrameEntry* a, + const Module::StackFrameEntry* b) { + return a->address < b->address; +} + +// Copy the CFI data from |from_module| into |to_module|, for any non- +// overlapping ranges. +static void CopyCFIDataBetweenModules(Module* to_module, + const Module* from_module) { + typedef vector::const_iterator Iterator; + + // Get the CFI data from both the source and destination modules and ensure + // it is sorted by start address. + vector from_data; + from_module->GetStackFrameEntries(&from_data); + std::sort(from_data.begin(), from_data.end(), &StackFrameEntryComparator); + + vector to_data; + to_module->GetStackFrameEntries(&to_data); + std::sort(to_data.begin(), to_data.end(), &StackFrameEntryComparator); + + Iterator to_it = to_data.begin(); + + for (Iterator it = from_data.begin(); it != from_data.end(); ++it) { + Module::StackFrameEntry* from_entry = *it; + Module::Address from_entry_end = from_entry->address + from_entry->size; + + // Find the first CFI record in the |to_module| that does not have an + // address less than the entry to be copied. + while (to_it != to_data.end()) { + if (from_entry->address > (*to_it)->address) + ++to_it; + else + break; + } + + // If the entry does not overlap, then it is safe to copy to |to_module|. + if (to_it == to_data.end() || (from_entry->address < (*to_it)->address && + from_entry_end < (*to_it)->address)) { + to_module->AddStackFrameEntry(new Module::StackFrameEntry(*from_entry)); + } + } +} + +static bool Start(const Options &options) { + SymbolData symbol_data = options.cfi ? ALL_SYMBOL_DATA : NO_CFI; + DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs); + + // For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the + // Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI + // data is in the __DWARF,__debug_frame section, which is moved into the + // dSYM. Therefore, to get x86_64 CFI data, dump_syms needs to look at both + // the dSYM and the Mach-O file. If both paths are present and CFI was + // requested, then consider the Module as "split" and dump all the debug data + // from the primary debug info file, the dSYM, and then dump additional CFI + // data from the source Mach-O file. + bool split_module = + !options.dsymPath.empty() && !options.srcPath.empty() && options.cfi; + const string& primary_file = + split_module ? options.dsymPath : options.srcPath; + + if (!dump_symbols.Read(primary_file)) + return false; + + if (options.arch) { + if (!dump_symbols.SetArchitecture(options.arch->cputype, + options.arch->cpusubtype)) { + fprintf(stderr, "%s: no architecture '%s' is present in file.\n", + primary_file.c_str(), options.arch->name); + size_t available_size; + const SuperFatArch *available = + dump_symbols.AvailableArchitectures(&available_size); + if (available_size == 1) + fprintf(stderr, "the file's architecture is: "); + else + fprintf(stderr, "architectures present in the file are:\n"); + for (size_t i = 0; i < available_size; i++) { + const SuperFatArch *arch = &available[i]; + const NXArchInfo *arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType( + arch->cputype, arch->cpusubtype); + if (arch_info) + fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); + else + fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", + arch->cputype, arch->cpusubtype); + } + return false; + } + } + + if (options.header_only) + return dump_symbols.WriteSymbolFileHeader(std::cout); + + // Read the primary file into a Breakpad Module. + Module* module = NULL; + if (!dump_symbols.ReadSymbolData(&module)) + return false; + scoped_ptr scoped_module(module); + + // If this is a split module, read the secondary Mach-O file, from which the + // CFI data will be extracted. + if (split_module && primary_file == options.dsymPath) { + if (!dump_symbols.Read(options.srcPath)) + return false; + + Module* cfi_module = NULL; + if (!dump_symbols.ReadSymbolData(&cfi_module)) + return false; + scoped_ptr scoped_cfi_module(cfi_module); + + // Ensure that the modules are for the same debug code file. + if (cfi_module->name() != module->name() || + cfi_module->os() != module->os() || + cfi_module->architecture() != module->architecture() || + cfi_module->identifier() != module->identifier()) { + fprintf(stderr, "Cannot generate a symbol file from split sources that do" + " not match.\n"); + return false; + } + + CopyCFIDataBetweenModules(module, cfi_module); + } + + return module->Write(std::cout, symbol_data); +} + +//============================================================================= +static void Usage(int argc, const char *argv[]) { + fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n"); + fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] " + "\n", argv[0]); + fprintf(stderr, "\t-i: Output module header information only.\n"); + fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n"); + fprintf(stderr, "\t in the file, if it contains only one architecture]\n"); + fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the " + "Mach-o file\n"); + fprintf(stderr, "\t-c: Do not generate CFI section\n"); + fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n"); + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + signed char ch; + + while ((ch = getopt(argc, (char * const *)argv, "ia:g:chr?")) != -1) { + switch (ch) { + case 'i': + options->header_only = true; + break; + case 'a': { + const NXArchInfo *arch_info = + google_breakpad::BreakpadGetArchInfoFromName(optarg); + if (!arch_info) { + fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg); + Usage(argc, argv); + exit(1); + } + options->arch = arch_info; + break; + } + case 'g': + options->dsymPath = optarg; + break; + case 'c': + options->cfi = false; + break; + case 'r': + options->handle_inter_cu_refs = false; + break; + case '?': + case 'h': + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "Must specify Mach-o file\n"); + Usage(argc, argv); + exit(1); + } + + options->srcPath = argv[optind]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + Options options; + bool result; + + SetupOptions(argc, argv, &options); + result = Start(options); + + return !result; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc new file mode 100644 index 0000000000..6e784ca709 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2010, 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. + +// Original author: Jim Blandy + +// macho_dump.cc: Dump the contents of a Mach-O file. This is mostly +// a test program for the Mach_O::FatReader and Mach_O::Reader classes. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "common/byte_cursor.h" +#include "common/mac/arch_utilities.h" +#include "common/mac/macho_reader.h" +#include "common/path_helper.h" + +using google_breakpad::ByteBuffer; +using std::ostringstream; +using std::string; +using std::vector; + +namespace { +namespace mach_o = google_breakpad::mach_o; + +string program_name; + +int check_syscall(int result, const char *operation, const char *filename) { + if (result < 0) { + fprintf(stderr, "%s: %s '%s': %s\n", + program_name.c_str(), operation, + filename, strerror(errno)); + exit(1); + } + return result; +} + +class DumpSection: public mach_o::Reader::SectionHandler { + public: + DumpSection() : index_(0) { } + bool HandleSection(const mach_o::Section §ion) { + printf(" section %d '%s' in segment '%s'\n" + " address: 0x%llx\n" + " alignment: 1 << %d B\n" + " flags: %d\n" + " size: %ld\n", + index_++, section.section_name.c_str(), section.segment_name.c_str(), + section.address, section.align, + mach_o::SectionFlags(section.flags), + section.contents.Size()); + return true; + } + + private: + int index_; +}; + +class DumpCommand: public mach_o::Reader::LoadCommandHandler { + public: + DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { } + bool UnknownCommand(mach_o::LoadCommandType type, + const ByteBuffer &contents) { + printf(" load command %d: %d", index_++, type); + return true; + } + bool SegmentCommand(const mach_o::Segment &segment) { + printf(" load command %d: %s-bit segment '%s'\n" + " address: 0x%llx\n" + " memory size: 0x%llx\n" + " maximum protection: 0x%x\n" + " initial protection: 0x%x\n" + " flags: %d\n" + " section_list size: %ld B\n", + index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(), + segment.vmaddr, segment.vmsize, segment.maxprot, + segment.initprot, mach_o::SegmentFlags(segment.flags), + segment.section_list.Size()); + + DumpSection dump_section; + return reader_->WalkSegmentSections(segment, &dump_section); + } + private: + mach_o::Reader *reader_; + int index_; +}; + +void DumpFile(const char *filename) { + int fd = check_syscall(open(filename, O_RDONLY), "opening", filename); + struct stat attributes; + check_syscall(fstat(fd, &attributes), + "getting file attributes for", filename); + void *mapping = mmap(NULL, attributes.st_size, PROT_READ, + MAP_PRIVATE, fd, 0); + close(fd); + check_syscall(mapping == (void *)-1 ? -1 : 0, + "mapping contents of", filename); + + mach_o::FatReader::Reporter fat_reporter(filename); + mach_o::FatReader fat_reader(&fat_reporter); + if (!fat_reader.Read(reinterpret_cast(mapping), + attributes.st_size)) { + exit(1); + } + printf("filename: %s\n", filename); + size_t object_files_size; + const SuperFatArch* super_fat_object_files = + fat_reader.object_files(&object_files_size); + struct fat_arch *object_files; + if (!super_fat_object_files->ConvertToFatArch(object_files)) { + exit(1); + } + printf(" object file count: %ld\n", object_files_size); + for (size_t i = 0; i < object_files_size; i++) { + const struct fat_arch &file = object_files[i]; + const NXArchInfo *fat_arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType( + file.cputype, file.cpusubtype); + printf("\n object file %ld:\n" + " fat header:\n:" + " CPU type: %s (%s)\n" + " size: %d B\n" + " alignment: 1<<%d B\n", + i, fat_arch_info->name, fat_arch_info->description, + file.size, file.align); + + ostringstream name; + name << filename; + if (object_files_size > 1) + name << ", object file #" << i; + ByteBuffer file_contents(reinterpret_cast(mapping) + + file.offset, file.size); + mach_o::Reader::Reporter reporter(name.str()); + mach_o::Reader reader(&reporter); + if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) { + exit(1); + } + + const NXArchInfo *macho_arch_info = + NXGetArchInfoFromCpuType(reader.cpu_type(), + reader.cpu_subtype()); + printf(" Mach-O header:\n" + " word size: %s\n" + " CPU type: %s (%s)\n" + " File type: %d\n" + " flags: %x\n", + (reader.bits_64() ? "64 bits" : "32 bits"), + macho_arch_info->name, macho_arch_info->description, + reader.file_type(), reader.flags()); + + DumpCommand dump_command(&reader); + reader.WalkLoadCommands(&dump_command); + } + munmap(mapping, attributes.st_size); +} + +} // namespace + +int main(int argc, char **argv) { + program_name = google_breakpad::BaseName(argv[0]); + if (argc == 1) { + fprintf(stderr, "Usage: %s FILE ...\n" + "Dump the contents of the Mach-O or fat binary files " + "'FILE ...'.\n", program_name.c_str()); + } + for (int i = 1; i < argc; i++) { + DumpFile(argv[i]); + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m new file mode 100644 index 0000000000..741ad765e5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m @@ -0,0 +1,135 @@ +// 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_upload.m: Upload a minidump to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// prod: the product name +// ver: the product version +// symbol_file: the breakpad format symbol file + +#import + +#import + +#import "common/mac/HTTPMultipartUpload.h" + +typedef struct { + NSString *minidumpPath; + NSString *uploadURLStr; + NSString *product; + NSString *version; + BOOL success; +} Options; + +//============================================================================= +static void Start(Options *options) { + NSURL *url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + + // Add parameters + [parameters setObject:options->product forKey:@"prod"]; + [parameters setObject:options->version forKey:@"ver"]; + [ul setParameters:parameters]; + + // Add file + [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"]; + + // Send it + NSError *error = nil; + NSData *data = [ul send:&error]; + NSString *result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + + NSLog(@"Send: %@", error ? [error description] : @"No Error"); + NSLog(@"Response: %ld", (long)[[ul response] statusCode]); + NSLog(@"Result: %lu bytes\n%@", (unsigned long)[data length], result); + + [result release]; + [ul release]; + options->success = !error; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit minidump information.\n"); + fprintf(stderr, "Usage: %s -p -v " + "\n", argv[0]); + fprintf(stderr, " should be a minidump.\n"); + fprintf(stderr, " is the destination for the upload\n"); + + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "p:v:h?")) != -1) { + switch (ch) { + case 'p': + options->product = [NSString stringWithUTF8String:optarg]; + break; + case 'v': + options->version = [NSString stringWithUTF8String:optarg]; + break; + + default: + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = [NSString stringWithUTF8String:argv[optind]]; + options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + + [pool release]; + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m new file mode 100644 index 0000000000..a7cce7b00c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m @@ -0,0 +1,204 @@ +// 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. + +// symupload.m: Upload a symbol file to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// code_file: the basename of the module, e.g. "app" +// debug_file: the basename of the debugging file, e.g. "app" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// os: the operating system that the module was built for +// cpu: the CPU that the module was built for (x86 or ppc) +// symbol_file: the contents of the breakpad-format symbol file + +#include +#include +#include + +#include +#include "HTTPMultipartUpload.h" + +typedef struct { + NSString *symbolsPath; + NSString *uploadURLStr; + BOOL success; +} Options; + +//============================================================================= +static NSArray *ModuleDataForSymbolFile(NSString *file) { + NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:file]; + NSData *data = [fh readDataOfLength:1024]; + NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSScanner *scanner = [NSScanner scannerWithString:str]; + NSString *line; + NSMutableArray *parts = nil; + const int MODULE_ID_INDEX = 3; + + if ([scanner scanUpToString:@"\n" intoString:&line]) { + parts = [[NSMutableArray alloc] init]; + NSScanner *moduleInfoScanner = [NSScanner scannerWithString:line]; + NSString *moduleInfo; + // Get everything BEFORE the module name. None of these properties + // can have spaces. + for (int i = 0; i <= MODULE_ID_INDEX; i++) { + [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + // Now get the module name. This can have a space so we scan to + // the end of the line. + [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + [str release]; + + return parts; +} + +//============================================================================= +static void Start(Options *options) { + NSURL *url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); + NSMutableString *compactedID = + [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; + [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 + range:NSMakeRange(0, [compactedID length])]; + + // Add parameters + [parameters setObject:compactedID forKey:@"debug_identifier"]; + + // MODULE + // 0 1 2 3 4 + [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; + [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; + [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; + [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"]; + [ul setParameters:parameters]; + + NSArray *keys = [parameters allKeys]; + int count = [keys count]; + for (int i = 0; i < count; ++i) { + NSString *key = [keys objectAtIndex:i]; + NSString *value = [parameters objectForKey:key]; + fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], + [value UTF8String]); + } + + // Add file + [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; + + // Send it + NSError *error = nil; + NSData *data = [ul send:&error]; + NSString *result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int status = [[ul response] statusCode]; + + fprintf(stdout, "Send: %s\n", error ? [[error description] UTF8String] : + "No Error"); + fprintf(stdout, "Response: %d\n", status); + fprintf(stdout, "Result: %lu bytes\n%s\n", + (unsigned long)[data length], [result UTF8String]); + + [result release]; + [ul release]; + options->success = !error && status==200; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, " should be created by using the dump_syms tool.\n"); + fprintf(stderr, " is the destination for the upload\n"); + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { + switch (ch) { + default: + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + int fd = open(argv[optind], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + exit(1); + } + + struct stat statbuf; + if (fstat(fd, &statbuf) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + close(fd); + exit(1); + } + close(fd); + + if (!S_ISREG(statbuf.st_mode)) { + fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]); + exit(1); + } + + options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; + options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + + [pool release]; + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..a6a78dc5f3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj @@ -0,0 +1,254 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; }; + 9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; }; + 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; }; + 9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = ""; }; + 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = ""; }; + 9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD835F90B0544950055103E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* symupload */ = { + isa = PBXGroup; + children = ( + 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */, + 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */, + 08FB7796FE84155DC02AAC07 /* symupload.m */, + 9BD836000B0544BA0055103E /* minidump_upload.m */, + 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */, + 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = symupload; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* symupload */, + 9BD835FB0B0544950055103E /* minidump_upload */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* symupload */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = symupload; + productInstallPath = "$(HOME)/bin"; + productName = symupload; + productReference = 8DD76FA10486AA7600D96B5E /* symupload */; + productType = "com.apple.product-type.tool"; + }; + 9BD835FA0B0544950055103E /* minidump_upload */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */; + buildPhases = ( + 9BD835F80B0544950055103E /* Sources */, + 9BD835F90B0544950055103E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = minidump_upload; + productName = minidump_upload; + productReference = 9BD835FB0B0544950055103E /* minidump_upload */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* symupload */, + 9BD835FA0B0544950055103E /* minidump_upload */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */, + 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD835F80B0544950055103E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */, + 9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = symupload; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = symupload; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 9BD836030B0544BB0055103E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = minidump_upload; + }; + name = Debug; + }; + 9BD836040B0544BB0055103E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = minidump_upload; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9BD836030B0544BB0055103E /* Debug */, + 9BD836040B0544BB0055103E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi b/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi new file mode 100644 index 0000000000..7457573b4b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi @@ -0,0 +1,116 @@ +# Copyright 2014 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. + +{ + 'target_defaults': { + 'include_dirs': [ + '../..', + ], + }, + 'targets': [ + { + 'target_name': 'crash_report', + 'type': 'executable', + 'sources': [ + 'crash_report/crash_report.mm', + 'crash_report/on_demand_symbol_supplier.h', + 'crash_report/on_demand_symbol_supplier.mm', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + '../processor/processor.gyp:processor', + ], + }, + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms/dump_syms_tool.cc', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'macho_dump', + 'type': 'executable', + 'sources': [ + 'dump_syms/macho_dump.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'minidump_upload', + 'type': 'executable', + 'sources': [ + 'symupload/minidump_upload.m', + ], + 'include_dirs': [ + '../../common/mac', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload/symupload.m', + ], + 'include_dirs': [ + '../../common/mac', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h new file mode 100644 index 0000000000..e12e53e229 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h @@ -0,0 +1,67 @@ +/* Copyright 2014, 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 +#include +#include + +// Go/Cgo does not support #define constants, so turn them into symbols +// that are reachable from Go. + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif + +#ifndef CPU_SUBTYPE_ARM64_ALL +#define CPU_SUBTYPE_ARM64_ALL 0 +#endif + +#ifndef CPU_SUBTYPE_ARM64_E +#define CPU_SUBTYPE_ARM64_E 2 +#endif + +const cpu_type_t kCPU_TYPE_ARM = CPU_TYPE_ARM; +const cpu_type_t kCPU_TYPE_ARM64 = CPU_TYPE_ARM64; + +const cpu_subtype_t kCPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM64_ALL; +const cpu_subtype_t kCPU_SUBTYPE_ARM64_E = CPU_SUBTYPE_ARM64_E; +const cpu_subtype_t kCPU_SUBTYPE_ARM_V7S = CPU_SUBTYPE_ARM_V7S; + +const char* GetNXArchInfoName(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + const NXArchInfo* arch_info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); + if (!arch_info) + return 0; + return arch_info->name; +} + +const uint32_t kMachHeaderFtypeDylib = MH_DYLIB; +const uint32_t kMachHeaderFtypeBundle = MH_BUNDLE; +const uint32_t kMachHeaderFtypeExe = MH_EXECUTE; +const uint32_t kMachHeaderFtypeDylinker = MH_DYLINKER; diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go new file mode 100644 index 0000000000..ed98fa60f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go @@ -0,0 +1,69 @@ +/* Copyright 2014, 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. +*/ + +package main + +import ( + "debug/macho" +) + +/* +#include "arch_constants.h" +*/ +import "C" + +// getArchStringFromHeader takes a MachO FileHeader and returns a string that +// represents the CPU type and subtype. +// This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType(). +func getArchStringFromHeader(header macho.FileHeader) string { + // TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h. + if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL { + return "arm64" + } + if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_E { + return "arm64e" + } + if header.Cpu == C.kCPU_TYPE_ARM && header.SubCpu == C.kCPU_SUBTYPE_ARM_V7S { + return "armv7s" + } + + cstr := C.GetNXArchInfoName(C.cpu_type_t(header.Cpu), C.cpu_subtype_t(header.SubCpu)) + if cstr == nil { + return "" + } + return C.GoString(cstr) +} + +const ( + MachODylib macho.Type = C.kMachHeaderFtypeDylib + MachOBundle = C.kMachHeaderFtypeBundle + MachOExe = C.kMachHeaderFtypeExe + MachODylinker = C.kMachHeaderFtypeDylinker +) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go new file mode 100644 index 0000000000..05a7764abf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -0,0 +1,432 @@ +/* Copyright 2014, 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. +*/ + +/* +Tool upload_system_symbols generates and uploads Breakpad symbol files for OS X system libraries. + +This tool shells out to the dump_syms and symupload Breakpad tools. In its default mode, this +will find all dynamic libraries on the system, run dump_syms to create the Breakpad symbol files, +and then upload them to Google's crash infrastructure. + +The tool can also be used to only dump libraries or upload from a directory. See -help for more +information. + +Both i386 and x86_64 architectures will be dumped and uploaded. +*/ +package main + +import ( + "debug/macho" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "regexp" + "strings" + "sync" + "time" +) + +var ( + breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.") + uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.") + dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.") + systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.") + dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.") +) + +var ( + // pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries. + pathsToScan = []string{ + "/System/Library/Components", + "/System/Library/Frameworks", + "/System/Library/PrivateFrameworks", + "/usr/lib", + } + + // optionalPathsToScan is just like pathsToScan, but the paths are permitted to be absent. + optionalPathsToScan = []string{ + // Gone in 10.15. + "/Library/QuickTime", + } + + // uploadServers are the list of servers to which symbols should be uploaded. + uploadServers = []string{ + "https://clients2.google.com/cr/symbol", + "https://clients2.google.com/cr/staging_symbol", + } + + // blacklistRegexps match paths that should be excluded from dumping. + blacklistRegexps = []*regexp.Regexp{ + regexp.MustCompile(`/System/Library/Frameworks/Python\.framework/`), + regexp.MustCompile(`/System/Library/Frameworks/Ruby\.framework/`), + regexp.MustCompile(`_profile\.dylib$`), + regexp.MustCompile(`_debug\.dylib$`), + regexp.MustCompile(`\.a$`), + regexp.MustCompile(`\.dat$`), + } +) + +func main() { + flag.Parse() + log.SetFlags(0) + + var uq *UploadQueue + + if *uploadOnlyPath != "" { + // -upload-from specified, so handle that case early. + uq = StartUploadQueue() + uploadFromDirectory(*uploadOnlyPath, uq) + uq.Wait() + return + } + + if *systemRoot == "" { + log.Fatal("Need a -system-root to dump symbols for") + } + + if *dumpOnlyPath != "" { + // -dump-to specified, so make sure that the path is a directory. + if fi, err := os.Stat(*dumpOnlyPath); err != nil { + log.Fatalf("-dump-to location: %v", err) + } else if !fi.IsDir() { + log.Fatal("-dump-to location is not a directory") + } + } + + dumpPath := *dumpOnlyPath + if *dumpOnlyPath == "" { + // If -dump-to was not specified, then run the upload pipeline and create + // a temporary dump output directory. + uq = StartUploadQueue() + + if p, err := ioutil.TempDir("", "upload_system_symbols"); err != nil { + log.Fatalf("Failed to create temporary directory: %v", err) + } else { + dumpPath = p + defer os.RemoveAll(p) + } + } + + dq := StartDumpQueue(*systemRoot, dumpPath, uq) + dq.Wait() + if uq != nil { + uq.Wait() + } +} + +type WorkerPool struct { + wg sync.WaitGroup +} + +// StartWorkerPool will launch numWorkers goroutines all running workerFunc. +// When workerFunc exits, the goroutine will terminate. +func StartWorkerPool(numWorkers int, workerFunc func()) *WorkerPool { + p := new(WorkerPool) + for i := 0; i < numWorkers; i++ { + p.wg.Add(1) + go func() { + workerFunc() + p.wg.Done() + }() + } + return p +} + +// Wait for all the workers in the pool to complete the workerFunc. +func (p *WorkerPool) Wait() { + p.wg.Wait() +} + +type UploadQueue struct { + *WorkerPool + queue chan string +} + +// StartUploadQueue creates a new worker pool and queue, to which paths to +// Breakpad symbol files may be sent for uploading. +func StartUploadQueue() *UploadQueue { + uq := &UploadQueue{ + queue: make(chan string, 10), + } + uq.WorkerPool = StartWorkerPool(5, uq.worker) + return uq +} + +// Upload enqueues the contents of filepath to be uploaded. +func (uq *UploadQueue) Upload(filepath string) { + uq.queue <- filepath +} + +// Done tells the queue that no more files need to be uploaded. This must be +// called before WorkerPool.Wait. +func (uq *UploadQueue) Done() { + close(uq.queue) +} + +func (uq *UploadQueue) worker() { + symUpload := path.Join(*breakpadTools, "symupload") + + for symfile := range uq.queue { + for _, server := range uploadServers { + for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed. + cmd := exec.Command(symUpload, symfile, server) + if output, err := cmd.Output(); err == nil { + // Success. No retry needed. + fmt.Printf("Uploaded %s to %s\n", symfile, server) + break + } else { + log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output) + time.Sleep(1 * time.Second) + } + } + } + } +} + +type DumpQueue struct { + *WorkerPool + dumpPath string + queue chan dumpRequest + uq *UploadQueue +} + +type dumpRequest struct { + path string + arch string +} + +// StartDumpQueue creates a new worker pool to find all the Mach-O libraries in +// root and dump their symbols to dumpPath. If an UploadQueue is passed, the +// path to the symbol file will be enqueued there, too. +func StartDumpQueue(root, dumpPath string, uq *UploadQueue) *DumpQueue { + dq := &DumpQueue{ + dumpPath: dumpPath, + queue: make(chan dumpRequest), + uq: uq, + } + dq.WorkerPool = StartWorkerPool(12, dq.worker) + + findLibsInRoot(root, dq) + + return dq +} + +// DumpSymbols enqueues the filepath to have its symbols dumped in the specified +// architecture. +func (dq *DumpQueue) DumpSymbols(filepath string, arch string) { + dq.queue <- dumpRequest{ + path: filepath, + arch: arch, + } +} + +func (dq *DumpQueue) Wait() { + dq.WorkerPool.Wait() + if dq.uq != nil { + dq.uq.Done() + } +} + +func (dq *DumpQueue) done() { + close(dq.queue) +} + +func (dq *DumpQueue) worker() { + dumpSyms := path.Join(*breakpadTools, "dump_syms") + + for req := range dq.queue { + filebase := path.Join(dq.dumpPath, strings.Replace(req.path, "/", "_", -1)) + symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch) + f, err := os.Create(symfile) + if err != nil { + log.Fatalf("Error creating symbol file: %v", err) + } + + cmd := exec.Command(dumpSyms, "-a", req.arch, req.path) + cmd.Stdout = f + err = cmd.Run() + f.Close() + + if err != nil { + os.Remove(symfile) + log.Printf("Error running dump_syms(%s, %s): %v\n", req.arch, req.path, err) + } else if dq.uq != nil { + dq.uq.Upload(symfile) + } + } +} + +// uploadFromDirectory handles the upload-only case and merely uploads all files in +// a directory. +func uploadFromDirectory(directory string, uq *UploadQueue) { + d, err := os.Open(directory) + if err != nil { + log.Fatalf("Could not open directory to upload: %v", err) + } + defer d.Close() + + entries, err := d.Readdirnames(0) + if err != nil { + log.Fatalf("Could not read directory: %v", err) + } + + for _, entry := range entries { + uq.Upload(path.Join(directory, entry)) + } + + uq.Done() +} + +// findQueue is an implementation detail of the DumpQueue that finds all the +// Mach-O files and their architectures. +type findQueue struct { + *WorkerPool + queue chan string + dq *DumpQueue +} + +// findLibsInRoot looks in all the pathsToScan in the root and manages the +// interaction between findQueue and DumpQueue. +func findLibsInRoot(root string, dq *DumpQueue) { + fq := &findQueue{ + queue: make(chan string, 10), + dq: dq, + } + fq.WorkerPool = StartWorkerPool(12, fq.worker) + + for _, p := range pathsToScan { + fq.findLibsInPath(path.Join(root, p), true) + } + + for _, p := range optionalPathsToScan { + fq.findLibsInPath(path.Join(root, p), false) + } + + close(fq.queue) + fq.Wait() + dq.done() +} + +// findLibsInPath recursively walks the directory tree, sending file paths to +// test for being Mach-O to the findQueue. +func (fq *findQueue) findLibsInPath(loc string, mustExist bool) { + d, err := os.Open(loc) + if err != nil { + if !mustExist && os.IsNotExist(err) { + return + } + log.Fatalf("Could not open %s: %v", loc, err) + } + defer d.Close() + + for { + fis, err := d.Readdir(100) + if err != nil && err != io.EOF { + log.Fatalf("Error reading directory %s: %v", loc, err) + } + + for _, fi := range fis { + fp := path.Join(loc, fi.Name()) + if fi.IsDir() { + fq.findLibsInPath(fp, true) + continue + } else if fi.Mode()&os.ModeSymlink != 0 { + continue + } + + // Test the blacklist in the worker to not slow down this main loop. + + fq.queue <- fp + } + + if err == io.EOF { + break + } + } +} + +func (fq *findQueue) worker() { + for fp := range fq.queue { + blacklisted := false + for _, re := range blacklistRegexps { + blacklisted = blacklisted || re.MatchString(fp) + } + if blacklisted { + continue + } + + f, err := os.Open(fp) + if err != nil { + log.Printf("%s: %v", fp, err) + continue + } + + fatFile, err := macho.NewFatFile(f) + if err == nil { + // The file is fat, so dump its architectures. + for _, fatArch := range fatFile.Arches { + fq.dumpMachOFile(fp, fatArch.File) + } + fatFile.Close() + } else if err == macho.ErrNotFat { + // The file isn't fat but may still be MachO. + thinFile, err := macho.NewFile(f) + if err != nil { + log.Printf("%s: %v", fp, err) + continue + } + fq.dumpMachOFile(fp, thinFile) + thinFile.Close() + } else { + f.Close() + } + } +} + +func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) { + if image.Type != MachODylib && image.Type != MachOBundle && image.Type != MachODylinker { + return + } + + arch := getArchStringFromHeader(image.FileHeader) + if arch == "" { + // Don't know about this architecture type. + return + } + + if (*dumpArchitecture != "" && *dumpArchitecture == arch) || *dumpArchitecture == "" { + fq.dq.DumpSymbols(fp, arch) + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py b/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py new file mode 100755 index 0000000000..b456285431 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# Copyright 2016 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. + +"""Convert gclient's DEPS file to repo's manifest xml file.""" + +from __future__ import print_function + +import argparse +import os +import sys + + +REMOTES = { + 'chromium': 'https://chromium.googlesource.com/', + 'github': 'https://github.com/', +} +REVIEWS = { + 'chromium': 'https://chromium-review.googlesource.com', +} + +MANIFEST_HEAD = """ + + + + +""" + +MANIFEST_REMOTE = """ + +""" + +MANIFEST_PROJECT = """ + +""" + +MANIFEST_TAIL = """ + +""" + + +def ConvertDepsToManifest(deps, manifest): + """Convert the |deps| file to the |manifest|.""" + # Load the DEPS file data. + ctx = {} + execfile(deps, ctx) + + new_contents = '' + + # Write out the common header. + data = { + 'prog': os.path.basename(__file__), + } + new_contents += MANIFEST_HEAD % data + + # Write out the sections. + for name, fetch in REMOTES.items(): + data = { + 'name': name, + 'fetch': fetch, + 'review': REVIEWS.get(name, ''), + } + new_contents += MANIFEST_REMOTE % data + + # Write out the main repo itself. + data = { + 'path': 'src', + 'name': 'breakpad/breakpad', + 'revision': 'refs/heads/master', + 'remote': 'chromium', + } + new_contents += MANIFEST_PROJECT % data + + # Write out the sections. + for path, url in ctx['deps'].items(): + for name, fetch in REMOTES.items(): + if url.startswith(fetch): + remote = name + break + else: + raise ValueError('Unknown DEPS remote: %s: %s' % (path, url)) + + # The DEPS url will look like: + # https://chromium.googlesource.com/external/gyp/@e8ab0833a42691cd2 + remote_path, rev = url.split('@') + remote_path = remote_path[len(fetch):] + + # If it's not a revision, assume it's a tag. Repo wants full ref names. + if len(rev) != 40: + rev = 'refs/tags/%s' % rev + + data = { + 'path': path, + 'name': remote_path, + 'revision': rev, + 'remote': remote, + } + new_contents += MANIFEST_PROJECT % data + + # Write out the common footer. + new_contents += MANIFEST_TAIL + + # See if the manifest has actually changed contents to avoid thrashing. + try: + old_contents = open(manifest).read() + except IOError: + # In case the file doesn't exist yet. + old_contents = '' + if old_contents != new_contents: + print('Updating %s due to changed %s' % (manifest, deps)) + with open(manifest, 'w') as fp: + fp.write(new_contents) + + +def GetParser(): + """Return a CLI parser.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('deps', + help='The DEPS file to convert') + parser.add_argument('manifest', + help='The manifest xml to generate') + return parser + + +def main(argv): + """The main func!""" + parser = GetParser() + opts = parser.parse_args(argv) + ConvertDepsToManifest(opts.deps, opts.manifest) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py b/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py new file mode 100644 index 0000000000..abddf7893e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python +# Copyright (c) 2012 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. + +"""Normalizes and de-duplicates paths within Breakpad symbol files. + +When using DWARF for storing debug symbols, some file information will be +stored relative to the current working directory of the current compilation +unit, and may be further relativized based upon how the file was #included. + +This helper can be used to parse the Breakpad symbol file generated from such +DWARF files and normalize and de-duplicate the FILE records found within, +updating any references to the FILE records in the other record types. +""" + +import macpath +import ntpath +import optparse +import os +import posixpath +import sys + +class BreakpadParseError(Exception): + """Unsupported Breakpad symbol record exception class.""" + pass + +class SymbolFileParser(object): + """Parser for Breakpad symbol files. + + The format of these files is documented at + https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md + """ + + def __init__(self, input_stream, output_stream, ignored_prefixes=None, + path_handler=os.path): + """Inits a SymbolFileParser to read symbol records from |input_stream| and + write the processed output to |output_stream|. + + |ignored_prefixes| contains a list of optional path prefixes that + should be stripped from the final, normalized path outputs. + + For example, if the Breakpad symbol file had all paths starting with a + common prefix, such as: + FILE 1 /b/build/src/foo.cc + FILE 2 /b/build/src/bar.cc + Then adding "/b/build/src" as an ignored prefix would result in an output + file that contained: + FILE 1 foo.cc + FILE 2 bar.cc + + Note that |ignored_prefixes| does not necessarily contain file system + paths, as the contents of the DWARF DW_AT_comp_dir attribute is dependent + upon the host system and compiler, and may contain additional information + such as hostname or compiler version. + """ + + self.unique_files = {} + self.duplicate_files = {} + self.input_stream = input_stream + self.output_stream = output_stream + self.ignored_prefixes = ignored_prefixes or [] + self.path_handler = path_handler + + def Process(self): + """Processes the Breakpad symbol file.""" + for line in self.input_stream: + parsed = self._ParseRecord(line.rstrip()) + if parsed: + self.output_stream.write(parsed + '\n') + + def _ParseRecord(self, record): + """Parses a single Breakpad symbol record - a single line from the symbol + file. + + Returns: + The modified string to write to the output file, or None if no line + should be written. + """ + record_type = record.partition(' ')[0] + if record_type == 'FILE': + return self._ParseFileRecord(record) + elif self._IsLineRecord(record_type): + return self._ParseLineRecord(record) + else: + # Simply pass the record through unaltered. + return record + + def _NormalizePath(self, path): + """Normalizes a file path to its canonical form. + + As this may not execute on the machine or file system originally + responsible for compilation, it may be necessary to further correct paths + for symlinks, junctions, or other such file system indirections. + + Returns: + A unique, canonical representation for the the file path. + """ + return self.path_handler.normpath(path) + + def _AdjustPath(self, path): + """Adjusts the supplied path after performing path de-duplication. + + This may be used to perform secondary adjustments, such as removing a + common prefix, such as "/D/build", or replacing the file system path with + information from the version control system. + + Returns: + The actual path to use when writing the FILE record. + """ + return path[len(filter(path.startswith, + self.ignored_prefixes + [''])[0]):] + + def _ParseFileRecord(self, file_record): + """Parses and corrects a FILE record.""" + file_info = file_record[5:].split(' ', 3) + if len(file_info) > 2: + raise BreakpadParseError('Unsupported FILE record: ' + file_record) + file_index = int(file_info[0]) + file_name = self._NormalizePath(file_info[1]) + existing_file_index = self.unique_files.get(file_name) + if existing_file_index is None: + self.unique_files[file_name] = file_index + file_info[1] = self._AdjustPath(file_name) + return 'FILE ' + ' '.join(file_info) + else: + self.duplicate_files[file_index] = existing_file_index + return None + + def _IsLineRecord(self, record_type): + """Determines if the current record type is a Line record""" + try: + line = int(record_type, 16) + except (ValueError, TypeError): + return False + return True + + def _ParseLineRecord(self, line_record): + """Parses and corrects a Line record.""" + line_info = line_record.split(' ', 5) + if len(line_info) > 4: + raise BreakpadParseError('Unsupported Line record: ' + line_record) + file_index = int(line_info[3]) + line_info[3] = str(self.duplicate_files.get(file_index, file_index)) + return ' '.join(line_info) + +def main(): + option_parser = optparse.OptionParser() + option_parser.add_option("-p", "--prefix", + action="append", dest="prefixes", type="string", + default=[], + help="A path prefix that should be removed from " + "all FILE lines. May be repeated to specify " + "multiple prefixes.") + option_parser.add_option("-t", "--path_type", + action="store", type="choice", dest="path_handler", + choices=['win32', 'posix'], + help="Indicates how file paths should be " + "interpreted. The default is to treat paths " + "the same as the OS running Python (eg: " + "os.path)") + options, args = option_parser.parse_args() + if args: + option_parser.error('Unknown argument: %s' % args) + + path_handler = { 'win32': ntpath, + 'posix': posixpath }.get(options.path_handler, os.path) + try: + symbol_parser = SymbolFileParser(sys.stdin, sys.stdout, options.prefixes, + path_handler) + symbol_parser.Process() + except BreakpadParseError, e: + print >> sys.stderr, 'Got an error while processing symbol file' + print >> sys.stderr, str(e) + return 1 + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py b/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py new file mode 100644 index 0000000000..b111f34983 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# Copyright (c) 2012 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. + +"""Unit tests for filter_syms.py""" + +import cStringIO +import ntpath +import os +import StringIO +import sys +import unittest + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(ROOT_DIR, '..')) + +# In root +import filter_syms + +class FilterSysmsTest(unittest.TestCase): + def assertParsed(self, input_data, ignored_prefixes, expected): + input_io = cStringIO.StringIO(input_data) + output_io = cStringIO.StringIO() + parser = filter_syms.SymbolFileParser(input_io, output_io, + ignored_prefixes, ntpath) + parser.Process() + self.assertEqual(output_io.getvalue(), expected) + + def testDuplicateFiles(self): + """Tests that duplicate files in FILE records are correctly removed and + that Line records are updated.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 foo/../file1_1.cc +FILE 2 bar/../file1_1.cc +FILE 3 baz/../file1_1.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 1 +1008 4 46 1 +100c 4 44 1 +""" + self.assertParsed(INPUT, [], EXPECTED_OUTPUT) + + def testIgnoredPrefix(self): + """Tests that prefixes in FILE records are correctly removed.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 /src/build/foo/../file1_1.cc +FILE 2 /src/build/bar/../file1_2.cc +FILE 3 /src/build/baz/../file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FILE 2 file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 2 +100c 4 44 1 +""" + IGNORED_PREFIXES = ['\\src\\build\\'] + self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) + + def testIgnoredPrefixesDuplicateFiles(self): + """Tests that de-duplication of FILE records happens BEFORE prefixes + are removed.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 /src/build/foo/../file1_1.cc +FILE 2 /src/build/bar/../file1_2.cc +FILE 3 D:/src/build2/baz/../file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FILE 2 file1_2.cc +FILE 3 file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + IGNORED_PREFIXES = ['\\src\\build\\', 'D:\\src\\build2\\'] + self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile new file mode 100644 index 0000000000..ff77105c61 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile @@ -0,0 +1,64 @@ +# 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. + +# Author: Alfred Peng + +CXX=CC +CC=cc + +CXXFLAGS=-g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -lelf -ldemangle -D_REENTRANT + +.PHONY:all clean + +BIN=dump_syms + +all:$(BIN) + +DUMP_OBJ=dump_symbols.o guid_creator.o dump_syms.o file_id.o md5.o + +dump_syms:$(DUMP_OBJ) + $(CXX) $(CXXFLAGS) -o $@ $^ + +dump_symbols.o:../../../common/solaris/dump_symbols.cc + $(CXX) $(CXXFLAGS) -c $^ + +guid_creator.o:../../../common/solaris/guid_creator.cc + $(CXX) $(CXXFLAGS) -c $^ + +file_id.o:../../../common/solaris/file_id.cc + $(CXX) $(CXXFLAGS) -c $^ + +md5.o:../../../common/md5.cc + $(CXX) $(CXXFLAGS) -c $^ + +test:all + ./run_regtest.sh + +clean: + rm -f $(BIN) $(DUMP_OBJ) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in new file mode 100644 index 0000000000..7bef51e078 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HOST_LDFLAGS += -lelf -ldemangle diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..54cea57e75 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc @@ -0,0 +1,54 @@ +// 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. + +// Author: Alfred Peng + +#include +#include + +#include "common/solaris/dump_symbols.h" + +using namespace google_breakpad; + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + const char *binary = argv[1]; + + DumpSymbols dumper; + if (!dumper.WriteSymbolFile(binary, fileno(stdout))) { + fprintf(stderr, "Failed to write symbol file.\n"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh new file mode 100644 index 0000000000..ffb3433067 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# 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. + +./dump_syms testdata/dump_syms_regtest.o > testdata/dump_syms_regtest.new +status=$? + +if [ $status -ne 0 ] ; then + echo "FAIL, dump_syms failed" + exit $status +fi + +diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \ + testdata/dump_syms_regtest.diff +status=$? + +if [ $status -eq 0 ] ; then + rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new + echo "PASS" +else + echo "FAIL, see testdata/dump_syms_regtest.[new|diff]" +fi + +exit $status diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc new file mode 100644 index 0000000000..e617a23b81 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc @@ -0,0 +1,64 @@ +// 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. + +// ./dump_syms dump_syms_regtest.pdb > dump_syms_regtest.sym + +namespace google_breakpad { + +class C { + public: + C() : member_(1) {} + virtual ~C() {} + + void set_member(int value) { member_ = value; } + int member() const { return member_; } + + void f() { member_ = g(); } + virtual int g() { return 2; } + static char* h(const C &that) { return 0; } + + private: + int member_; +}; + +static int i() { + return 3; +} + +} // namespace google_breakpad + +int main(int argc, char **argv) { + google_breakpad::C object; + object.set_member(google_breakpad::i()); + object.f(); + int value = object.g(); + char *nothing = object.h(object); + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o new file mode 100644 index 0000000000..a1c61b2dfd Binary files /dev/null and b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.o differ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs new file mode 100644 index 0000000000..c5f93ef78c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs @@ -0,0 +1,129 @@ + + +Debugging Stab table -- 104 entries + + 0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x67,0x71c + 1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0 + 2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0 + 3: .stabs "",N_OBJ,0x0,0x0,0x0 + 4: .stabs "",N_OBJ,0x0,0x0,0x0 + 5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e + 6: .stabs "dump_syms_regtest.cc",N_SOL,0x0,0x0,0x0 + 7: .stabs "char:t(0,1)=bsc1;0;8",N_ISYM,0x0,0x0,0x0 + 8: .stabs "short:t(0,2)=bs2;0;16",N_ISYM,0x0,0x0,0x0 + 9: .stabs "int:t(0,3)=bs4;0;32",N_ISYM,0x0,0x0,0x0 + 10: .stabs "long:t(0,4)=bs4;0;32",N_ISYM,0x0,0x0,0x0 + 11: .stabs "long long:t(0,5)=bs8;0;64",N_ISYM,0x0,0x0,0x0 + 12: .stabs "unsigned char:t(0,6)=buc1;0;8",N_ISYM,0x0,0x0,0x0 + 13: .stabs "unsigned short:t(0,7)=bu2;0;16",N_ISYM,0x0,0x0,0x0 + 14: .stabs "unsigned:t(0,8)=bu4;0;32",N_ISYM,0x0,0x0,0x0 + 15: .stabs "unsigned long:t(0,9)=bu4;0;32",N_ISYM,0x0,0x0,0x0 + 16: .stabs "unsigned long long:t(0,10)=bu8;0;64",N_ISYM,0x0,0x0,0x0 + 17: .stabs "signed char:t(0,11)=bsc1;0;8",N_ISYM,0x0,0x0,0x0 + 18: .stabs "wchar_t:t(0,12)=buc4;0;32",N_ISYM,0x0,0x0,0x0 + 19: .stabs "void:t(0,13)=bs0;0;0",N_ISYM,0x0,0x0,0x0 + 20: .stabs "float:t(0,14)=R1;4",N_ISYM,0x0,0x0,0x0 + 21: .stabs "double:t(0,15)=R2;8",N_ISYM,0x0,0x0,0x0 + 22: .stabs "long double:t(0,16)=R6;12",N_ISYM,0x0,0x0,0x0 + 23: .stabs "...:t(0,17)=buv4;0;32",N_ISYM,0x0,0x0,0x0 + 24: .stabs "bool:t(0,18)=bub1;0;8",N_ISYM,0x0,0x0,0x0 + 25: .stabs "__1nPgoogle_breakpad_:T(0,19)=Yn0google_breakpad;",N_ISYM,0x0,0x0,0x0 + 26: .stabs "nBC(0,19):U(0,20)",N_ESYM,0x0,0x0,0x0 + 27: .stabs "nBC(0,19):T(0,20)=Yc8C;;AcHmember_:(0,3),32,32;;Cc2t6M_v K2c2T6M_v CcKset_member6Mi_v CcGmember6kM_i CcBf6M_v K3cBg6M_i GcBh6Frk1_pc;;;2 0;;;;110;",N_ESYM,0x0,0x8,0x0 + 28: .stabs "main:F(0,3);(0,3);(0,21)=*(0,22)=*(0,1)",N_FUN,0x0,0x38,0x0 + 29: .stabs "main",N_MAIN,0x0,0x0,0x0 + 30: .stabs "argc:p(0,3)",N_PSYM,0x0,0x4,0x8 + 31: .stabs "argv:p(0,21)",N_PSYM,0x0,0x4,0xc + 32: .stabn N_LBRAC,0x0,0x1,0x12 + 33: .stabs "object:(0,20)",N_LSYM,0x0,0x8,0xfffffff4 + 34: .stabs "value:(0,3)",N_LSYM,0x0,0x4,0xfffffff0 + 35: .stabs "nothing:(0,22)",N_LSYM,0x0,0x4,0xffffffec + 36: .stabn N_SLINE,0x0,0x39,0x12 + 37: .stabs "object:2",N_CONSTRUCT,0x0,0xc,0x12 + 38: .stabn N_SLINE,0x2,0x3a,0x1e + 39: .stabn N_SLINE,0x0,0x3b,0x36 + 40: .stabn N_SLINE,0x0,0x3c,0x42 + 41: .stabn N_SLINE,0x0,0x3d,0x57 + 42: .stabn N_SLINE,0x0,0x3f,0x6c + 43: .stabs "2:0",N_DESTRUCT,0x0,0xc,0x73 + 44: .stabn N_SLINE,0xfffffffe,0x40,0x9c + 45: .stabn N_RBRAC,0x0,0x1,0x9c + 46: .stabs "__1cPgoogle_breakpadBi6F_i_:f(0,3)",N_FUN,0x0,0x32,0x0 + 47: .stabn N_LBRAC,0x0,0x1,0x6 + 48: .stabn N_SLINE,0x0,0x33,0x6 + 49: .stabn N_SLINE,0x0,0x34,0x10 + 50: .stabn N_RBRAC,0x0,0x1,0x10 + 51: .stabs "__1cPgoogle_breakpadBC2t6M_v_:F(0,13);(0,23)=*(0,20)",N_FUN,0x0,0x24,0x0 + 52: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 53: .stabn N_LBRAC,0x0,0x1,0x3 + 54: .stabn N_SLINE,0x0,0x24,0x25 + 55: .stabn N_RBRAC,0x0,0x1,0x25 + 56: .stabs "__1cPgoogle_breakpadBC2T6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0 + 57: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 58: .stabn N_LBRAC,0x0,0x1,0x3 + 59: .stabn N_SLINE,0x0,0x25,0x3 + 60: .stabn N_RBRAC,0x0,0x1,0x3 + 61: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_:F(0,13);(0,23);(0,3)",N_FUN,0x0,0x27,0x0 + 62: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 63: .stabs "value:p(0,3)",N_PSYM,0x0,0x4,0xc + 64: .stabn N_LBRAC,0x0,0x1,0x3 + 65: .stabn N_SLINE,0x0,0x27,0x3 + 66: .stabn N_SLINE,0x0,0x27,0xc + 67: .stabn N_RBRAC,0x0,0x1,0xc + 68: .stabs "__1cPgoogle_breakpadBCBf6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x2a,0x0 + 69: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 70: .stabn N_LBRAC,0x0,0x1,0x3 + 71: .stabn N_SLINE,0x0,0x2a,0x3 + 72: .stabn N_SLINE,0x0,0x2a,0x1d + 73: .stabn N_RBRAC,0x0,0x1,0x1d + 74: .stabs "__1cPgoogle_breakpadBCBg6M_i_:F(0,3);(0,23)",N_FUN,0x0,0x2b,0x0 + 75: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 76: .stabn N_LBRAC,0x0,0x1,0x6 + 77: .stabn N_SLINE,0x0,0x2b,0x6 + 78: .stabn N_SLINE,0x0,0x2b,0x10 + 79: .stabn N_RBRAC,0x0,0x1,0x10 + 80: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_:F(0,22);(0,24)=&(0,25)=k(0,20)",N_FUN,0x0,0x2c,0x0 + 81: .stabs "that:p(0,24)",N_PSYM,0x0,0x4,0x8 + 82: .stabn N_LBRAC,0x0,0x1,0x6 + 83: .stabn N_SLINE,0x0,0x2c,0x6 + 84: .stabn N_SLINE,0x0,0x2c,0x10 + 85: .stabn N_RBRAC,0x0,0x1,0x10 + 86: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0 + 87: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 88: .stabn N_LBRAC,0x0,0x1,0x3 + 89: .stabn N_SLINE,0x0,0x25,0xf + 90: .stabn N_RBRAC,0x0,0x1,0xf + 91: .stabs "__SLIP.DELETER__A:f(0,13);(0,23);(0,3)",N_FUN,0x0,0x25,0x0 + 92: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 93: .stabs "delete:p(0,3)",N_PSYM,0x0,0x4,0xc + 94: .stabn N_LBRAC,0x0,0x1,0x3 + 95: .stabn N_LBRAC,0x0,0x2,0x3 + 96: .stabn N_RBRAC,0x0,0x2,0x28 + 97: .stabn N_RBRAC,0x0,0x1,0x28 + 98: .stabs "true:l(0,18);1",N_LSYM,0x0,0x4,0x0 + 99: .stabs "false:l(0,18);0",N_LSYM,0x0,0x4,0x0 + 100: .stabs "__1c2k6Fpv_v_:P(0,13);(0,26)=*(0,13)",N_FUN,0x0,0x0,0x0 + 101: .stabs "__1cPgoogle_breakpadBC2t5B6M_v_:F__1cPgoogle_breakpadBC2t6M_v_",N_ALIAS,0x0,0x0,0x0 + 102: .stabs "cbD__RTTI__1nPgoogle_breakpadBC_(0,19):YR(0,20)",N_LSYM,0x0,0x0,0x0 + 103: .stabn N_ENDM,0x0,0x0,0x0 + + +Index Stab table -- 17 entries + + 0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x10,0x3b1 + 1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0 + 2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0 + 3: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata",N_OBJ,0x0,0x0,0x0 + 4: .stabs "dump_syms_regtest.o",N_OBJ,0x0,0x0,0x0 + 5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e + 6: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/; /ws/on10-tools-prc/SUNWspro/SS11/prod/bin/CC -g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -D_REENTRANT -xs dump_syms_regtest.cc -Qoption ccfe -prefix -Qoption ccfe .XAB6Z2hOiL\$Gl1b.",N_CMDLINE,0x0,0x0,0x0 + 7: .stabs "__1nPgoogle_breakpadBC_:U",N_ESYM,0x0,0x0,0x0 + 8: .stabs "main",N_MAIN,0x0,0x0,0x0 + 9: .stabs "main",N_FUN,0x0,0x0,0x0 + 10: .stabs "__1cPgoogle_breakpadBC2t6M_v_",N_FUN,0x0,0x0,0x0 + 11: .stabs "__1cPgoogle_breakpadBC2T6M_v_",N_FUN,0x0,0x0,0x0 + 12: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_",N_FUN,0x0,0x0,0x0 + 13: .stabs "__1cPgoogle_breakpadBCBf6M_v_",N_FUN,0x0,0x0,0x0 + 14: .stabs "__1cPgoogle_breakpadBCBg6M_i_",N_FUN,0x0,0x0,0x0 + 15: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_",N_FUN,0x0,0x0,0x0 + 16: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_",N_FUN,0x0,0x0,0x0 diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym new file mode 100644 index 0000000000..44d3c5391c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym @@ -0,0 +1,33 @@ +MODULE solaris x86 3DC8191474338D8587339B5FB3E2C62A0 dump_syms_regtest.o +FILE 0 dump_syms_regtest.cc +FUNC 0 156 0 main +12 18 57 0 +1e 12 58 0 +36 24 59 0 +42 12 60 0 +57 21 61 0 +6c 21 63 0 +9c 48 64 0 +FUNC 0 16 0 int google_breakpad::i() +6 6 51 0 +10 10 52 0 +FUNC 0 37 0 google_breakpad::C::C() +25 37 36 0 +FUNC 0 3 0 google_breakpad::C::~C() +3 3 37 0 +FUNC 0 12 0 void google_breakpad::C::set_member(int) +3 3 39 0 +c 9 39 0 +FUNC 0 29 0 void google_breakpad::C::f() +3 3 42 0 +1d 26 42 0 +FUNC 0 16 0 int google_breakpad::C::g() +6 6 43 0 +10 10 43 0 +FUNC 0 16 0 char*google_breakpad::C::h(const google_breakpad::C&) +6 6 44 0 +10 10 44 0 +FUNC 0 15 0 google_breakpad::C::~C #Nvariant 1() +f 15 37 0 +FUNC 0 0 0 __SLIP.DELETER__A +FUNC 0 0 0 void operator delete(void*) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp b/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp new file mode 100644 index 0000000000..e6a4210fec --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp @@ -0,0 +1,38 @@ +# Copyright 2014 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. + +{ + 'conditions': [ + ['OS=="mac"', { + 'includes': ['mac/tools_mac.gypi'], + }], + ['OS=="linux"', { + 'includes': ['linux/tools_linux.gypi'], + }], + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe new file mode 100644 index 0000000000..3a2dfd8e50 Binary files /dev/null and b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe differ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe new file mode 100644 index 0000000000..09d2a55b5c Binary files /dev/null and b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe differ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc new file mode 100644 index 0000000000..2b40faeeb5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc @@ -0,0 +1,752 @@ +// 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. + +// ms_symbol_server_converter.cc: Obtain symbol files from a Microsoft +// symbol server, and convert them to Breakpad's dumped format. +// +// See ms_symbol_server_converter.h for documentation. +// +// Author: Mark Mentovai + +#include +#include +#include + +#include +#include + +#include "tools/windows/converter/ms_symbol_server_converter.h" +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/pe_source_line_writer.h" +#include "common/windows/string_utils-inl.h" + +// SYMOPT_NO_PROMPTS is not defined in earlier platform SDKs. Define it +// in that case, in the event that this code is used with a newer version +// of DbgHelp at runtime that recognizes the option. The presence of this +// bit in the symbol options should not harm earlier versions of DbgHelp. +#ifndef SYMOPT_NO_PROMPTS +#define SYMOPT_NO_PROMPTS 0x00080000 +#endif // SYMOPT_NO_PROMPTS + +namespace { + +std::wstring GetExeDirectory() { + wchar_t directory[MAX_PATH]; + + // Get path to this process exe. + DWORD result = GetModuleFileName(/*hModule=*/nullptr, directory, MAX_PATH); + if (result <= 0 || result == MAX_PATH) { + fprintf(stderr, + "GetExeDirectory: failed to get path to process exe.\n"); + return L""; + } + HRESULT hr = PathCchRemoveFileSpec(directory, result + 1); + if (hr != S_OK) { + fprintf(stderr, + "GetExeDirectory: failed to remove basename from path '%ls'.\n", + directory); + return L""; + } + + return std::wstring(directory); +} + +} // namespace + +namespace google_breakpad { + +// Use sscanf_s if it is available, to quench the warning about scanf being +// deprecated. Use scanf where sscanf_is not available. Note that the +// parameters passed to sscanf and sscanf_s are only compatible as long as +// fields of type c, C, s, S, and [ are not used. +#if _MSC_VER >= 1400 // MSVC 2005/8 +#define SSCANF sscanf_s +#else // _MSC_VER >= 1400 +#define SSCANF sscanf +#endif // _MSC_VER >= 1400 + +bool GUIDOrSignatureIdentifier::InitializeFromString( + const string &identifier) { + type_ = TYPE_NONE; + + size_t length = identifier.length(); + + if (length > 32 && length <= 40) { + // GUID + if (SSCANF(identifier.c_str(), + "%08X%04hX%04hX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%X", + &guid_.Data1, &guid_.Data2, &guid_.Data3, + &guid_.Data4[0], &guid_.Data4[1], + &guid_.Data4[2], &guid_.Data4[3], + &guid_.Data4[4], &guid_.Data4[5], + &guid_.Data4[6], &guid_.Data4[7], + &age_) != 12) { + return false; + } + + type_ = TYPE_GUID; + } else if (length > 8 && length <= 15) { + // Signature + if (SSCANF(identifier.c_str(), "%08X%x", &signature_, &age_) != 2) { + return false; + } + + type_ = TYPE_SIGNATURE; + } else { + return false; + } + + return true; +} + +#undef SSCANF + +MSSymbolServerConverter::MSSymbolServerConverter( + const string &local_cache, const vector &symbol_servers) + : symbol_path_(), + fail_dns_(false), + fail_timeout_(false), + fail_not_found_(false) { + // Setting local_cache can be done without verifying that it exists because + // SymSrv will create it if it is missing - any creation failures will occur + // at that time, so there's nothing to check here, making it safe to + // assign this in the constructor. + + assert(symbol_servers.size() > 0); + +#if !defined(NDEBUG) + // These are characters that are interpreted as having special meanings in + // symbol_path_. + const char kInvalidCharacters[] = "*;"; + assert(local_cache.find_first_of(kInvalidCharacters) == string::npos); +#endif // !defined(NDEBUG) + + for (vector::const_iterator symbol_server = symbol_servers.begin(); + symbol_server != symbol_servers.end(); + ++symbol_server) { + // The symbol path format is explained by + // http://msdn.microsoft.com/library/en-us/debug/base/using_symsrv.asp . + // "srv*" is the same as "symsrv*symsrv.dll*", which means that + // symsrv.dll is to be responsible for locating symbols. symsrv.dll + // interprets the rest of the string as a series of symbol stores separated + // by '*'. "srv*local_cache*symbol_server" means to check local_cache + // first for the symbol file, and if it is not found there, to check + // symbol_server. Symbol files found on the symbol server will be placed + // in the local cache, decompressed. + // + // Multiple specifications in this format may be presented, separated by + // semicolons. + + assert((*symbol_server).find_first_of(kInvalidCharacters) == string::npos); + symbol_path_ += "srv*" + local_cache + "*" + *symbol_server + ";"; + } + + // Strip the trailing semicolon. + symbol_path_.erase(symbol_path_.length() - 1); +} + +// A stack-based class that manages SymInitialize and SymCleanup calls. +class AutoSymSrv { + public: + AutoSymSrv() : initialized_(false) {} + + ~AutoSymSrv() { + if (!Cleanup()) { + // Print the error message here, because destructors have no return + // value. + fprintf(stderr, "~AutoSymSrv: SymCleanup: error %lu\n", GetLastError()); + } + } + + bool Initialize(HANDLE process, char *path, bool invade_process) { + process_ = process; + + // TODO(nbilling): Figure out why dbghelp.dll is being loaded from + // system32/SysWOW64 before exe folder. + + // Attempt to locate and load dbghelp.dll beside the process exe. This is + // somewhat of a workaround to loader delay load behavior that is occurring + // when we call into symsrv APIs. dbghelp.dll must be loaded from beside + // the process exe so that we are guaranteed to find symsrv.dll alongside + // dbghelp.dll (a security requirement of dbghelp.dll) and so that the + // symsrv.dll file that is loaded has a symsrv.yes file alongside it (a + // requirement of symsrv.dll when accessing Microsoft-owned symbol + // servers). + // 'static local' because we don't care about the value but we need the + // initialization to happen exactly once. + static HMODULE dbghelp_module = [] () -> HMODULE { + std::wstring exe_directory = GetExeDirectory(); + if (exe_directory.empty()) { + return nullptr; + } + std::wstring dbghelp_path = exe_directory + L"\\dbghelp.dll"; + return LoadLibrary(dbghelp_path.c_str()); + }(); + if (dbghelp_module == nullptr) { + fprintf(stderr, + "AutoSymSrv::Initialize: failed to load dbghelp.dll beside exe."); + return false; + } + + initialized_ = SymInitialize(process, path, invade_process) == TRUE; + return initialized_; + } + + bool Cleanup() { + if (initialized_) { + if (SymCleanup(process_)) { + initialized_ = false; + return true; + } + return false; + } + + return true; + } + + private: + HANDLE process_; + bool initialized_; +}; + +// A stack-based class that "owns" a pathname and deletes it when destroyed, +// unless told not to by having its Release() method called. Early deletions +// are supported by calling Delete(). +class AutoDeleter { + public: + explicit AutoDeleter(const string &path) : path_(path) {} + + ~AutoDeleter() { + int error; + if ((error = Delete()) != 0) { + // Print the error message here, because destructors have no return + // value. + fprintf(stderr, "~AutoDeleter: Delete: error %d for %s\n", + error, path_.c_str()); + } + } + + int Delete() { + if (path_.empty()) + return 0; + + int error = remove(path_.c_str()); + Release(); + return error; + } + + void Release() { + path_.clear(); + } + + private: + string path_; +}; + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, + const string &debug_or_code_id, + const string &version, + string *file_name) { + assert(file_name); + file_name->clear(); + + GUIDOrSignatureIdentifier identifier; + if (!identifier.InitializeFromString(debug_or_code_id)) { + fprintf(stderr, + "LocateFile: Unparseable identifier for %s %s %s\n", + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + HANDLE process = GetCurrentProcess(); // CloseHandle is not needed. + AutoSymSrv symsrv; + if (!symsrv.Initialize(process, + const_cast(symbol_path_.c_str()), + false)) { + fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + if (!SymRegisterCallback64(process, SymCallback, + reinterpret_cast(this))) { + fprintf(stderr, + "LocateFile: SymRegisterCallback64: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + // SYMOPT_DEBUG arranges for SymCallback to be called with additional + // debugging information. This is used to determine the nature of failures. + DWORD options = SymGetOptions() | SYMOPT_DEBUG | SYMOPT_NO_PROMPTS | + SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_SECURE; + SymSetOptions(options); + + // SymCallback will set these as needed inisde the SymFindFileInPath call. + fail_dns_ = false; + fail_timeout_ = false; + fail_not_found_ = false; + + // Do the lookup. + char path[MAX_PATH]; + if (!SymFindFileInPath( + process, NULL, + const_cast(debug_or_code_file.c_str()), + const_cast(identifier.guid_or_signature_pointer()), + identifier.age(), 0, + identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ? + SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR, + path, SymFindFileInPathCallback, this)) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + // This can be returned for a number of reasons. Use the crumbs + // collected by SymCallback to determine which one is relevant. + + // These errors are possibly transient. + if (fail_dns_ || fail_timeout_) { + return LOCATE_RETRY; + } + + // This is an authoritiative file-not-found message. + if (fail_not_found_) { + fprintf(stderr, + "LocateFile: SymFindFileInPath: LOCATE_NOT_FOUND error " + "for %s %s %s\n", + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_NOT_FOUND; + } + + // If the error is FILE_NOT_FOUND but none of the known error + // conditions are matched, fall through to LOCATE_FAILURE. + } + + fprintf(stderr, + "LocateFile: SymFindFileInPath: error %lu for %s %s %s\n", + error, + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + // Making sure path is null-terminated. + path[MAX_PATH - 1] = '\0'; + + // The AutoDeleter ensures that the file is only kept when returning + // LOCATE_SUCCESS. + AutoDeleter deleter(path); + + // Do the cleanup here even though it will happen when symsrv goes out of + // scope, to allow it to influence the return value. + if (!symsrv.Cleanup()) { + fprintf(stderr, "LocateFile: SymCleanup: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + deleter.Release(); + + printf("Downloaded: %s\n", path); + *file_name = path; + return LOCATE_SUCCESS; +} + + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing, + string *pe_file) { + return LocateFile(missing.code_file, missing.code_identifier, + missing.version, pe_file); +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo &missing, + string *symbol_file) { + return LocateFile(missing.debug_file, missing.debug_identifier, + missing.version, symbol_file); +} + + +// static +BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, + ULONG action, + ULONG64 data, + ULONG64 context) { + MSSymbolServerConverter *self = + reinterpret_cast(context); + + switch (action) { + case CBA_EVENT: { + IMAGEHLP_CBA_EVENT *cba_event = + reinterpret_cast(data); + + // Put the string into a string object to be able to use string::find + // for substring matching. This is important because the not-found + // message does not use the entire string but is appended to the URL + // that SymSrv attempted to retrieve. + string desc(cba_event->desc); + + // desc_action maps strings (in desc) to boolean pointers that are to + // be set to true if the string matches. + struct desc_action { + const char *desc; // The substring to match. + bool *action; // On match, this pointer will be set to true. + }; + + static const desc_action desc_actions[] = { + // When a DNS error occurs, it could be indiciative of network + // problems. + { "SYMSRV: The server name or address could not be resolved\n", + &self->fail_dns_ }, + + // This message is produced if no connection is opened. + { "SYMSRV: A connection with the server could not be established\n", + &self->fail_timeout_ }, + + // This message is produced if a connection is established but the + // server fails to respond to the HTTP request. + { "SYMSRV: The operation timed out\n", + &self->fail_timeout_ }, + + // This message is produced when the requested file is not found, + // even if one or more of the above messages are also produced. + // It's trapped to distinguish between not-found and unknown-failure + // conditions. Note that this message will not be produced if a + // connection is established and the server begins to respond to the + // HTTP request but does not finish transmitting the file. + { " not found\n", + &self->fail_not_found_ } + }; + + for (int desc_action_index = 0; + desc_action_index < + static_cast(sizeof(desc_actions) / sizeof(desc_action)); + ++desc_action_index) { + if (desc.find(desc_actions[desc_action_index].desc) != string::npos) { + *(desc_actions[desc_action_index].action) = true; + break; + } + } + + break; + } + } + + // This function is a mere fly on the wall. Treat everything as unhandled. + return FALSE; +} + +// static +BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( + const char *filename, void *context) { + // FALSE ends the search, indicating that the located symbol file is + // satisfactory. + return FALSE; +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateAndConvertSymbolFile( + const MissingSymbolInfo &missing, + bool keep_symbol_file, + bool keep_pe_file, + string *converted_symbol_file, + string *symbol_file, + string *out_pe_file) { + assert(converted_symbol_file); + converted_symbol_file->clear(); + if (symbol_file) { + symbol_file->clear(); + } + + string pdb_file; + LocateResult result = LocateSymbolFile(missing, &pdb_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "Fallback to PE-only symbol generation for: %s\n", + missing.debug_file.c_str()); + return LocateAndConvertPEFile(missing, keep_pe_file, converted_symbol_file, + out_pe_file); + } + + if (symbol_file && keep_symbol_file) { + *symbol_file = pdb_file; + } + + // The conversion of a symbol file for a Windows 64-bit module requires + // loading of the executable file. If there is no executable file, convert + // using only the PDB file. Without an executable file, the conversion will + // fail for 64-bit modules but it should succeed for 32-bit modules. + string pe_file; + result = LocatePEFile(missing, &pe_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str()); + } + + if (out_pe_file && keep_pe_file) { + *out_pe_file = pe_file; + } + + // Conversion may fail because the file is corrupt. If a broken file is + // kept in the local cache, LocateSymbolFile will not hit the network again + // to attempt to locate it. To guard against problems like this, the + // symbol file in the local cache will be removed if conversion fails. + AutoDeleter pdb_deleter(pdb_file); + AutoDeleter pe_deleter(pe_file); + + // Be sure that it's a .pdb file, since we'll be replacing .pdb with .sym + // for the converted file's name. + string pdb_extension = pdb_file.substr(pdb_file.length() - 4); + // strcasecmp is called _stricmp here. + if (_stricmp(pdb_extension.c_str(), ".pdb") != 0) { + fprintf(stderr, "LocateAndConvertSymbolFile: " + "no .pdb extension for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pdb_file.c_str()); + return LOCATE_FAILURE; + } + + PDBSourceLineWriter writer; + wstring pe_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) { + fprintf(stderr, + "LocateAndConvertSymbolFile: " + "WindowsStringUtils::safe_mbstowcs failed for %s\n", + pe_file.c_str()); + return LOCATE_FAILURE; + } + wstring pdb_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pdb_file, &pdb_file_w)) { + fprintf(stderr, + "LocateAndConvertSymbolFile: " + "WindowsStringUtils::safe_mbstowcs failed for %ws\n", + pdb_file_w.c_str()); + return LOCATE_FAILURE; + } + if (!writer.Open(pdb_file_w, PDBSourceLineWriter::PDB_FILE)) { + fprintf(stderr, + "ERROR: PDBSourceLineWriter::Open failed for %s %s %s %ws\n", + missing.debug_file.c_str(), missing.debug_identifier.c_str(), + missing.version.c_str(), pdb_file_w.c_str()); + return LOCATE_FAILURE; + } + if (!writer.SetCodeFile(pe_file_w)) { + fprintf(stderr, + "ERROR: PDBSourceLineWriter::SetCodeFile failed for %s %s %s %ws\n", + missing.debug_file.c_str(), missing.debug_identifier.c_str(), + missing.version.c_str(), pe_file_w.c_str()); + return LOCATE_FAILURE; + } + + *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym"; + + FILE *converted_output = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) + != 0) { +#else // _MSC_VER >= 1400 + // fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier + // environments. Don't use fopen with MSVC8 and later, because it's + // deprecated. fopen does not provide reliable error codes, so just use + // -1 in the event of a failure. + int err; + if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) { + err = -1; +#endif // _MSC_VER >= 1400 + fprintf(stderr, "LocateAndConvertSymbolFile: " + "fopen_s: error %d for %s %s %s %s\n", + err, + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + converted_symbol_file->c_str()); + return LOCATE_FAILURE; + } + + AutoDeleter sym_deleter(*converted_symbol_file); + + bool success = writer.WriteSymbols(converted_output); + fclose(converted_output); + + if (!success) { + fprintf(stderr, "LocateAndConvertSymbolFile: " + "PDBSourceLineWriter::WriteMap failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pdb_file.c_str()); + return LOCATE_FAILURE; + } + + if (keep_symbol_file) { + pdb_deleter.Release(); + } + + if (keep_pe_file) { + pe_deleter.Release(); + } + + sym_deleter.Release(); + + return LOCATE_SUCCESS; +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateAndConvertPEFile( + const MissingSymbolInfo &missing, + bool keep_pe_file, + string *converted_symbol_file, + string *out_pe_file) { + assert(converted_symbol_file); + converted_symbol_file->clear(); + + string pe_file; + MSSymbolServerConverter::LocateResult result = LocatePEFile(missing, + &pe_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str()); + return result; + } + + if (out_pe_file && keep_pe_file) { + *out_pe_file = pe_file; + } + + // Conversion may fail because the file is corrupt. If a broken file is + // kept in the local cache, LocatePEFile will not hit the network again + // to attempt to locate it. To guard against problems like this, the + // PE file in the local cache will be removed if conversion fails. + AutoDeleter pe_deleter(pe_file); + + // Be sure that it's a .exe or .dll file, since we'll be replacing extension + // with .sym for the converted file's name. + string pe_extension = pe_file.substr(pe_file.length() - 4); + // strcasecmp is called _stricmp here. + if (_stricmp(pe_extension.c_str(), ".exe") != 0 && + _stricmp(pe_extension.c_str(), ".dll") != 0) { + fprintf(stderr, "LocateAndConvertPEFile: " + "no .dll/.exe extension for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + + *converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym"; + + FILE *converted_output = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) + != 0) { +#else // _MSC_VER >= 1400 + // fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier + // environments. Don't use fopen with MSVC8 and later, because it's + // deprecated. fopen does not provide reliable error codes, so just use + // -1 in the event of a failure. + int err; + if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) { + err = -1; +#endif // _MSC_VER >= 1400 + fprintf(stderr, "LocateAndConvertPEFile: " + "fopen_s: error %d for %s %s %s %s\n", + err, + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + converted_symbol_file->c_str()); + return LOCATE_FAILURE; + } + AutoDeleter sym_deleter(*converted_symbol_file); + + wstring pe_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) { + fprintf(stderr, + "LocateAndConvertPEFile: " + "WindowsStringUtils::safe_mbstowcs failed for %s\n", + pe_file.c_str()); + return LOCATE_FAILURE; + } + PESourceLineWriter writer(pe_file_w); + PDBModuleInfo module_info; + if (!writer.GetModuleInfo(&module_info)) { + fprintf(stderr, "LocateAndConvertPEFile: " + "PESourceLineWriter::GetModuleInfo failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + if (module_info.cpu.compare(L"x86_64") != 0) { + // This module is not x64 so we cannot generate Breakpad symbols from the + // PE alone. Don't delete PE-- no need to retry download. + pe_deleter.Release(); + return LOCATE_FAILURE; + } + + bool success = writer.WriteSymbols(converted_output); + fclose(converted_output); + + if (!success) { + fprintf(stderr, "LocateAndConvertPEFile: " + "PESourceLineWriter::WriteMap failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + + if (keep_pe_file) { + pe_deleter.Release(); + } + + sym_deleter.Release(); + + return LOCATE_SUCCESS; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp new file mode 100644 index 0000000000..57ec790686 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp @@ -0,0 +1,46 @@ +# Copyright 2013 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'ms_symbol_server_converter', + 'type': 'static_library', + 'msvs_guid': '1463C4CD-23FC-4DE9-BFDE-283338200157', + 'sources': [ + 'ms_symbol_server_converter.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h new file mode 100644 index 0000000000..401f7c3443 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h @@ -0,0 +1,235 @@ +// 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. + +// ms_symbol_server_converter.h: Obtain symbol files from a Microsoft +// symbol server, and convert them to Breakpad's dumped format. +// +// At runtime, MSSymbolServerConverter and code that it calls depend on being +// able to locate suitable versions of dbghelp.dll and symsrv.dll. For best +// results, place these files in the same directory as the executable. +// dbghelp.dll and symsrv.dll as supplied with Debugging Tools for Windows are +// both redistributable, as indicated by the package's redist.txt file. +// +// When connecting to Microsoft's symbol server at +// http://msdl.microsoft.com/download/symbols/, which provides access to +// symbols for the operating system itself, symsrv.dll requires agreement to +// Microsoft's "Terms of Use for Microsoft Symbols and Binaries." Because this +// library places the symbol engine into a promptless mode, the dialog with the +// terms will not appear, and use of Microsoft's symbol server will not be +// possible. To indicate agreement to the terms, create a file called +// symsrv.yes in the same directory as symsrv.dll. (Note that symsrv.dll will +// also recognize a symsrv.no file as indicating that you do not accept the +// terms; the .yes file takes priority over the .no file.) The terms of use +// are contained within symsrv.dll; they were formerly available online at +// http://www.microsoft.com/whdc/devtools/debugging/symsrvTOU2.mspx , but +// do not appear to be available online any longer as of January, 2007. It is +// possible to view the terms from within WinDbg (Debugging Tools for Windows) +// by removing any symsrv.yes and symsrv.no files from WinDbg's directory, +// setting the symbol path to include Microsoft's symbol server (.sympath), and +// attempting to load symbols from their server (.reload). +// +// This code has been tested with dbghelp.dll 6.5.3.7 and symsrv.dll 6.5.3.8, +// included with Microsoft Visual Studio 8 in Common7/IDE. This has also been +// tested with dbghelp.dll and symsrv.dll versions 6.6.7.5 and 6.12.2.633, +// included with the same versions of Debugging Tools for Windows, available at +// http://www.microsoft.com/whdc/devtools/debugging/ . +// +// Author: Mark Mentovai + +#ifndef TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ +#define TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ + +#include + +#include +#include + +namespace google_breakpad { + +using std::string; +using std::vector; + +// MissingSymbolInfo contains the subset of the information in the processor's +// CodeModule structure relevant to obtaining a missing symbol file. Only +// debug_file and debug_identifier are relevant in actually obtaining the +// missing file; the other fields are for convenience. +struct MissingSymbolInfo { + string code_file; + string code_identifier; + string debug_file; + string debug_identifier; + string version; +}; + +class GUIDOrSignatureIdentifier { + public: + enum GUIDOrSignatureType { + TYPE_NONE = 0, + TYPE_GUID, + TYPE_SIGNATURE + }; + + GUIDOrSignatureIdentifier() : type_(TYPE_NONE) {} + + // Converts |identifier|, a debug_identifier-formatted string, into its + // component fields: either a GUID and age, or signature and age. If + // successful, sets the relevant fields in the object, including the type + // field, and returns true. On error, returns false. + bool InitializeFromString(const string &identifier); + + GUIDOrSignatureType type() const { return type_; } + GUID guid() const { return guid_; } + DWORD signature() const { return signature_; } + int age() const { return age_; } + const void *guid_or_signature_pointer() const { return &guid_; } + + private: + GUIDOrSignatureType type_; + + // An identifier contains either a 128-bit uuid or a 32-bit signature. + union { + GUID guid_; + DWORD signature_; + }; + + // All identifiers used here have age fields, which indicate a specific + // revision given a uuid or signature. + int age_; +}; + +class MSSymbolServerConverter { + public: + enum LocateResult { + LOCATE_FAILURE = 0, + LOCATE_NOT_FOUND, // Authoritative: the file is not present. + LOCATE_RETRY, // Transient (network?) error, try again later. + LOCATE_SUCCESS + }; + + // Create a new object. local_cache is the location (pathname) of a local + // symbol store used to hold downloaded and converted symbol files. This + // directory will be created by LocateSymbolFile when it successfully + // retrieves a symbol file. symbol_servers contains a list of locations (URLs + // or pathnames) of the upstream symbol server stores, given in order of + // preference, with the first string in the vector identifying the first + // store to try. The vector must contain at least one string. None of the + // strings passed to this constructor may contain asterisk ('*') or semicolon + // (';') characters, as the symbol engine uses these characters as separators. + MSSymbolServerConverter(const string &local_cache, + const vector &symbol_servers); + + // Locates the PE file (DLL or EXE) specified by the identifying information + // in |missing|, by checking the symbol stores identified when the object + // was created. When returning LOCATE_SUCCESS, pe_file is set to + // the pathname of the decompressed PE file as it is stored in the + // local cache. + LocateResult LocatePEFile(const MissingSymbolInfo &missing, string *pe_file); + + // Locates the symbol file specified by the identifying information in + // |missing|, by checking the symbol stores identified when the object + // was created. When returning LOCATE_SUCCESS, symbol_file is set to + // the pathname of the decompressed symbol file as it is stored in the + // local cache. + LocateResult LocateSymbolFile(const MissingSymbolInfo &missing, + string *symbol_file); + + // Calls LocateSymbolFile and converts the returned symbol file to the + // dumped-symbol format, storing it adjacent to the symbol file. The + // only conversion supported is from pdb files. Returns the return + // value of LocateSymbolFile, or if LocateSymbolFile succeeds but + // conversion fails, returns LOCATE_FAILURE. The pathname to the + // pdb file and to the converted symbol file are returned in + // |converted_symbol_file|, |symbol_file|, and |pe_file|. |symbol_file| and + // |pe_file| are optional and may be NULL. If only the converted symbol file + // is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate + // that the original symbol file (pdb) and executable file (exe, dll) should + // be deleted after conversion. + LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo &missing, + bool keep_symbol_file, + bool keep_pe_file, + string *converted_symbol_file, + string *symbol_file, + string *pe_file); + + // Calls LocatePEFile and converts the returned PE file to the + // dumped-symbol format, storing it adjacent to the PE file. The + // only conversion supported is from PE files. Returns the return + // value of LocatePEFile, or if LocatePEFile succeeds but + // conversion fails, returns LOCATE_FAILURE. The pathname to the + // PE file and to the converted symbol file are returned in + // |converted_symbol_file| and |pe_file|. |pe_file| is optional and may be + // NULL. If only the converted symbol file is desired, set |keep_pe_file| + // to false to indicate that the executable file (exe, dll) should be deleted + // after conversion. + // NOTE: Currrently only supports x64 PEs. + LocateResult LocateAndConvertPEFile(const MissingSymbolInfo &missing, + bool keep_pe_file, + string *converted_symbol_file, + string *pe_file); + + private: + // Locates the PDB or PE file (DLL or EXE) specified by the identifying + // information in |debug_or_code_file| and |debug_or_code_id|, by checking + // the symbol stores identified when the object was created. When + // returning LOCATE_SUCCESS, file_name is set to the pathname of the + // decompressed PDB or PE file file as it is stored in the local cache. + LocateResult LocateFile(const string &debug_or_code_file, + const string &debug_or_code_id, + const string &version, string *file_name); + + // Called by various SymSrv functions to report status as progress is made + // and to allow the callback to influence processing. Messages sent to this + // callback can be used to distinguish between the various failure modes + // that SymFindFileInPath might encounter. + static BOOL CALLBACK SymCallback(HANDLE process, ULONG action, ULONG64 data, + ULONG64 context); + + // Called by SymFindFileInPath (in LocateSymbolFile) after a candidate + // symbol file is located, when it's present in the local cache. + // SymFindFileInPath actually seems to accept NULL for a callback function + // and behave properly for our needs in that case, but the documentation + // doesn't mention it, so this little callback is provided. + static BOOL CALLBACK SymFindFileInPathCallback(const char *filename, + void *context); + + // The search path used by SymSrv, built based on the arguments to the + // constructor. + string symbol_path_; + + // SymCallback will set at least one of these failure variables if + // SymFindFileInPath fails for an expected reason. + bool fail_dns_; // DNS failures (fail_not_found_ will also be set). + bool fail_timeout_; // Timeouts (fail_not_found_ will also be set). + bool fail_not_found_; // The file could not be found. If this is the only + // fail_* member set, then it is authoritative. +}; + +} // namespace google_breakpad + +#endif // TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj new file mode 100644 index 0000000000..ee1263a147 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj @@ -0,0 +1,368 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Purify + Win32 + + + Purify + x64 + + + Release + Win32 + + + Release + x64 + + + + {1463C4CD-23FC-4DE9-BFDE-283338200157} + Win32Proj + ms_symbol_server_converter + true + + + + Unicode + StaticLibrary + + + + + + + + + $(ExecutablePath);$(MSBuildProjectDirectory)\..\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\..\third_party\python_26\ + $(SolutionDir)$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + false + false + false + true + true + $(ProjectName) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + EnableFastChecks + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions) + + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + false + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + Disabled + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + true + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories) + /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + true + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + true + Console + MachineX86 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + ..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + /MP %(AdditionalOptions) + true + ProgramDatabase + 4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings) + false + true + false + MaxSpeed + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions) + MultiThreaded + false + true + Level4 + + + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /ignore:4221 %(AdditionalOptions) + $(OutDir)lib\$(ProjectName)$(TargetExt) + + + wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib + ../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories) + /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions) + dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs) + false + true + $(OutDir)lib\$(TargetName).lib + $(OutDir)$(TargetName).map + Console + MachineX64 + + + dlldata.c + true + %(Filename).h + %(Filename)_i.c + $(IntDir) + %(Filename)_p.c + %(Filename).tlb + + + ../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories) + 0x0409 + _WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions) + + + + + + + + + + + diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd new file mode 100644 index 0000000000..5464a61ed7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd @@ -0,0 +1,33 @@ +@if "%ECHOON%"=="" @echo off +SETLOCAL + +REM ****************************************************************** +REM Please, make sure to run this in an Elevated Command Prompt. +REM Usage: +REM configure.cmd +REM ****************************************************************** + +REM ****************************************************************** +REM Initialize +REM ****************************************************************** +SET SCRIPT_LOCATION=%~dp0 + +REM ****************************************************************** +REM Go to script location +REM ****************************************************************** +pushd %SCRIPT_LOCATION% + +REM ****************************************************************** +REM Register msdia140.dll. +REM ****************************************************************** +SET MSG=Failed to register msdia140.dll. Make sure to run this in elevated command prompt. +%systemroot%\SysWoW64\regsvr32.exe /s msdia140.dll & if errorlevel 1 echo %MSG% & goto :fail + +:success +echo Configuration was successful. +ENDLOCAL +exit /b 0 + +:fail +ENDLOCAL +exit /b 1 diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc new file mode 100644 index 0000000000..5b70903a4d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc @@ -0,0 +1,807 @@ +// Copyright 2019 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. + +#pragma comment(lib, "winhttp.lib") +#pragma comment(lib, "wininet.lib") +#pragma comment(lib, "diaguids.lib") +#pragma comment(lib, "imagehlp.lib") + +#include +#include +#include +#include +#include +#include +#include + +#include "tools/windows/converter_exe/escaping.h" +#include "tools/windows/converter_exe/http_download.h" +#include "tools/windows/converter_exe/tokenizer.h" +#include "common/windows/http_upload.h" +#include "common/windows/string_utils-inl.h" +#include "tools/windows/converter/ms_symbol_server_converter.h" + +using strings::WebSafeBase64Unescape; +using strings::WebSafeBase64Escape; + +namespace { + +using std::map; +using std::string; +using std::vector; +using std::wstring; +using crash::HTTPDownload; +using crash::Tokenizer; +using google_breakpad::HTTPUpload; +using google_breakpad::MissingSymbolInfo; +using google_breakpad::MSSymbolServerConverter; +using google_breakpad::WindowsStringUtils; + +const char *kMissingStringDelimiters = "|"; +const char *kLocalCachePath = "c:\\symbols"; +const char *kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/"; + +// Windows stdio doesn't do line buffering. Use this function to flush after +// writing to stdout and stderr so that a log will be available if the +// converter crashes. +static int FprintfFlush(FILE *file, const char *format, ...) { + va_list arguments; + va_start(arguments, format); + int retval = vfprintf(file, format, arguments); + va_end(arguments); + fflush(file); + return retval; +} + +static string CurrentDateAndTime() { + const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)"; + + time_t current_time; + time(¤t_time); + + // localtime_s is safer but is only available in MSVC8. Use localtime + // in earlier environments. + struct tm *time_pointer; +#if _MSC_VER >= 1400 // MSVC 2005/8 + struct tm time_struct; + time_pointer = &time_struct; + if (localtime_s(time_pointer, ¤t_time) != 0) { + return kUnknownDateAndTime; + } +#else // _MSC_VER >= 1400 + time_pointer = localtime(¤t_time); + if (!time_pointer) { + return kUnknownDateAndTime; + } +#endif // _MSC_VER >= 1400 + + char buffer[256]; + if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) { + return kUnknownDateAndTime; + } + + return string(buffer); +} + +// ParseMissingString turns |missing_string| into a MissingSymbolInfo +// structure. It returns true on success, and false if no such conversion +// is possible. +static bool ParseMissingString(const string &missing_string, + MissingSymbolInfo *missing_info) { + assert(missing_info); + + vector tokens; + Tokenizer::Tokenize(kMissingStringDelimiters, missing_string, &tokens); + if (tokens.size() != 5) { + return false; + } + + missing_info->debug_file = tokens[0]; + missing_info->debug_identifier = tokens[1]; + missing_info->version = tokens[2]; + missing_info->code_file = tokens[3]; + missing_info->code_identifier = tokens[4]; + + return true; +} + +// StringMapToWStringMap takes each element in a map that associates +// (narrow) strings to strings and converts the keys and values to wstrings. +// Returns true on success and false on failure, printing an error message. +static bool StringMapToWStringMap(const map &smap, + map *wsmap) { + assert(wsmap); + wsmap->clear(); + + for (map::const_iterator iterator = smap.begin(); + iterator != smap.end(); + ++iterator) { + wstring key; + if (!WindowsStringUtils::safe_mbstowcs(iterator->first, &key)) { + FprintfFlush(stderr, + "StringMapToWStringMap: safe_mbstowcs failed for key %s\n", + iterator->first.c_str()); + return false; + } + + wstring value; + if (!WindowsStringUtils::safe_mbstowcs(iterator->second, &value)) { + FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed " + "for value %s\n", + iterator->second.c_str()); + return false; + } + + wsmap->insert(make_pair(key, value)); + } + + return true; +} + +// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a +// map of parameters suitable for passing to HTTPDownload or HTTPUpload. +// Returns true on success and false on failure, printing an error message. +static bool MissingSymbolInfoToParameters(const MissingSymbolInfo &missing_info, + map *wparameters) { + assert(wparameters); + + map parameters; + string encoded_param; + // Indicate the params are encoded. + parameters["encoded"] = "true"; // The string value here does not matter. + + WebSafeBase64Escape(missing_info.code_file, &encoded_param); + parameters["code_file"] = encoded_param; + + WebSafeBase64Escape(missing_info.code_identifier, &encoded_param); + parameters["code_identifier"] = encoded_param; + + WebSafeBase64Escape(missing_info.debug_file, &encoded_param); + parameters["debug_file"] = encoded_param; + + WebSafeBase64Escape(missing_info.debug_identifier, &encoded_param); + parameters["debug_identifier"] = encoded_param; + + if (!missing_info.version.empty()) { + // The version is optional. + WebSafeBase64Escape(missing_info.version, &encoded_param); + parameters["version"] = encoded_param; + } + + WebSafeBase64Escape("WinSymConv", &encoded_param); + parameters["product"] = encoded_param; + + if (!StringMapToWStringMap(parameters, wparameters)) { + // StringMapToWStringMap will have printed an error. + return false; + } + + return true; +} + +// UploadSymbolFile sends |converted_file| as identified by |missing_info| +// to the symbol server rooted at |upload_symbol_url|. Returns true on +// success and false on failure, printing an error message. +static bool UploadSymbolFile(const wstring &upload_symbol_url, + const MissingSymbolInfo &missing_info, + const string &converted_file) { + map parameters; + if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) { + // MissingSymbolInfoToParameters or a callee will have printed an error. + return false; + } + + wstring converted_file_w; + + if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) { + FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n", + converted_file.c_str()); + return false; + } + map files; + files[L"symbol_file"] = converted_file_w; + + FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str()); + if (!HTTPUpload::SendMultipartPostRequest( + upload_symbol_url, parameters, + files, NULL, NULL, NULL)) { + FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest failed " + "for %s %s %s\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + return false; + } + + return true; +} + +// SendFetchFailedPing informs the symbol server based at +// |fetch_symbol_failure_url| that the symbol file identified by +// |missing_info| could authoritatively not be located. Returns +// true on success and false on failure. +static bool SendFetchFailedPing(const wstring &fetch_symbol_failure_url, + const MissingSymbolInfo &missing_info) { + map parameters; + if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) { + // MissingSymbolInfoToParameters or a callee will have printed an error. + return false; + } + + string content; + if (!HTTPDownload::Download(fetch_symbol_failure_url, + ¶meters, + &content, + NULL)) { + FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed " + "for %s %s %s\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + return false; + } + + return true; +} + +// Returns true if it's safe to make an external request for the symbol +// file described in missing_info. It's considered safe to make an +// external request unless the symbol file's debug_file string matches +// the given blacklist regular expression. +// The debug_file name is used from the MissingSymbolInfo struct, +// matched against the blacklist_regex. +static bool SafeToMakeExternalRequest(const MissingSymbolInfo &missing_info, + std::regex blacklist_regex) { + string file_name = missing_info.debug_file; + // Use regex_search because we want to match substrings. + if (std::regex_search(file_name, blacklist_regex)) { + FprintfFlush(stderr, "Not safe to make external request for file %s\n", + file_name.c_str()); + return false; + } + + return true; +} + +// Converter options derived from command line parameters. +struct ConverterOptions { + ConverterOptions() + : report_fetch_failures(true) { + } + + ~ConverterOptions() { + } + + // Names of MS Symbol Supplier Servers that are internal to Google, and may + // have symbols for any request. + vector full_internal_msss_servers; + + // Names of MS Symbol Supplier Servers that are internal to Google, and + // shouldn't be checked for symbols for any .exe files. + vector full_external_msss_servers; + + // Names of MS Symbol Supplier Servers that are external to Google, and may + // have symbols for any request. + vector no_exe_internal_msss_servers; + + // Names of MS Symbol Supplier Servers that are external to Google, and + // shouldn't be checked for symbols for any .exe files. + vector no_exe_external_msss_servers; + + // Temporary local storage for symbols. + string local_cache_path; + + // URL for uploading symbols. + wstring upload_symbols_url; + + // URL to fetch list of missing symbols. + wstring missing_symbols_url; + + // URL to report symbol fetch failure. + wstring fetch_symbol_failure_url; + + // Are symbol fetch failures reported. + bool report_fetch_failures; + + // File containing the list of missing symbols. Fetch failures are not + // reported if such file is provided. + string missing_symbols_file; + + // Regex used to blacklist files to prevent external symbol requests. + // Owned and cleaned up by this struct. + std::regex blacklist_regex; + + private: + // DISABLE_COPY_AND_ASSIGN + ConverterOptions(const ConverterOptions&); + ConverterOptions& operator=(const ConverterOptions&); +}; + +// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and +// attempts to locate it from the symbol servers provided in the +// |options.*_msss_servers| arguments. "Full" servers are those that will be +// queried for all symbol files; "No-EXE" servers will only be queried for +// modules whose missing symbol data indicates are not main program executables. +// Results will be sent to the |options.upload_symbols_url| on success or +// |options.fetch_symbol_failure_url| on failure, and the local cache will be +// stored at |options.local_cache_path|. Because nothing can be done even in +// the event of a failure, this function returns no value, although it +// may result in error messages being printed. +static void ConvertMissingSymbolFile(const MissingSymbolInfo &missing_info, + const ConverterOptions &options) { + string time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n", + time_string.c_str(), + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + + // The first lookup is always to internal symbol servers. + // Always ask the symbol servers identified as "full." + vector msss_servers = options.full_internal_msss_servers; + + // If the file is not an .exe file, also ask an additional set of symbol + // servers, such as Microsoft's public symbol server. + bool is_exe = false; + + if (missing_info.code_file.length() >= 4) { + string code_extension = + missing_info.code_file.substr(missing_info.code_file.size() - 4); + + // Firefox is a special case: .dll-only servers should be consulted for + // its symbols. This enables us to get its symbols from Mozilla's + // symbol server when crashes occur in Google extension code hosted by a + // Firefox process. + if (_stricmp(code_extension.c_str(), ".exe") == 0 && + _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) { + is_exe = true; + } + } + + if (!is_exe) { + msss_servers.insert(msss_servers.end(), + options.no_exe_internal_msss_servers.begin(), + options.no_exe_internal_msss_servers.end()); + } + + // If there are any suitable internal symbol servers, make a request. + MSSymbolServerConverter::LocateResult located = + MSSymbolServerConverter::LOCATE_FAILURE; + string converted_file; + if (msss_servers.size() > 0) { + // Attempt to fetch the symbol file and convert it. + FprintfFlush(stderr, "Making internal request for %s (%s)\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str()); + MSSymbolServerConverter converter(options.local_cache_path, msss_servers); + located = converter.LocateAndConvertSymbolFile(missing_info, + false, // keep_symbol_file + false, // keep_pe_file + &converted_file, + NULL, // symbol_file + NULL); // pe_file + switch (located) { + case MSSymbolServerConverter::LOCATE_SUCCESS: + FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n"); + // Upload it. Don't bother checking the return value. If this + // succeeds, it should disappear from the missing symbol list. + // If it fails, something will print an error message indicating + // the cause of the failure, and the item will remain on the + // missing symbol list. + UploadSymbolFile(options.upload_symbols_url, missing_info, + converted_file); + remove(converted_file.c_str()); + + // Note: this does leave some directories behind that could be + // cleaned up. The directories inside options.local_cache_path for + // debug_file/debug_identifier can be removed at this point. + break; + + case MSSymbolServerConverter::LOCATE_NOT_FOUND: + FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n"); + // The symbol file definitively did not exist. Fall through, + // so we can attempt an external query if it's safe to do so. + break; + + case MSSymbolServerConverter::LOCATE_RETRY: + FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n"); + // Fall through in case we should make an external request. + // If not, or if an external request fails in the same way, + // we'll leave the entry in the symbol file list and + // try again on a future pass. Print a message so that there's + // a record. + break; + + case MSSymbolServerConverter::LOCATE_FAILURE: + FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n"); + // LocateAndConvertSymbolFile printed an error message. + break; + + default: + FprintfFlush( + stderr, + "FATAL: Unexpected return value '%d' from " + "LocateAndConvertSymbolFile()\n", + located); + assert(0); + break; + } + } else { + // No suitable internal symbol servers. This is fine because the converter + // is mainly used for downloading and converting of external symbols. + } + + // Make a request to an external server if the internal request didn't + // succeed, and it's safe to do so. + if (located != MSSymbolServerConverter::LOCATE_SUCCESS && + SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) { + msss_servers = options.full_external_msss_servers; + if (!is_exe) { + msss_servers.insert(msss_servers.end(), + options.no_exe_external_msss_servers.begin(), + options.no_exe_external_msss_servers.end()); + } + if (msss_servers.size() > 0) { + FprintfFlush(stderr, "Making external request for %s (%s)\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str()); + MSSymbolServerConverter external_converter(options.local_cache_path, + msss_servers); + located = external_converter.LocateAndConvertSymbolFile( + missing_info, + false, // keep_symbol_file + false, // keep_pe_file + &converted_file, + NULL, // symbol_file + NULL); // pe_file + } else { + FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n"); + } + } + + // Final handling for this symbol file is based on the result from the + // external request (if performed above), or on the result from the + // previous internal lookup. + switch (located) { + case MSSymbolServerConverter::LOCATE_SUCCESS: + FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n"); + // Upload it. Don't bother checking the return value. If this + // succeeds, it should disappear from the missing symbol list. + // If it fails, something will print an error message indicating + // the cause of the failure, and the item will remain on the + // missing symbol list. + UploadSymbolFile(options.upload_symbols_url, missing_info, + converted_file); + remove(converted_file.c_str()); + + // Note: this does leave some directories behind that could be + // cleaned up. The directories inside options.local_cache_path for + // debug_file/debug_identifier can be removed at this point. + break; + + case MSSymbolServerConverter::LOCATE_NOT_FOUND: + // The symbol file definitively didn't exist. Inform the server. + // If this fails, something will print an error message indicating + // the cause of the failure, but there's really nothing more to + // do. If this succeeds, the entry should be removed from the + // missing symbols list. + if (!options.report_fetch_failures) { + FprintfFlush(stderr, "SendFetchFailedPing skipped\n"); + } else if (SendFetchFailedPing(options.fetch_symbol_failure_url, + missing_info)) { + FprintfFlush(stderr, "SendFetchFailedPing succeeded\n"); + } else { + FprintfFlush(stderr, "SendFetchFailedPing failed\n"); + } + break; + + case MSSymbolServerConverter::LOCATE_RETRY: + FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n"); + // Nothing to do but leave the entry in the symbol file list and + // try again on a future pass. Print a message so that there's + // a record. + FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry " + "for %s %s %s\n", + missing_info.debug_file.c_str(), + missing_info.debug_identifier.c_str(), + missing_info.version.c_str()); + break; + + case MSSymbolServerConverter::LOCATE_FAILURE: + FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n"); + // LocateAndConvertSymbolFile printed an error message. + + // This is due to a bad debug file name, so fetch failed. + if (!options.report_fetch_failures) { + FprintfFlush(stderr, "SendFetchFailedPing skipped\n"); + } else if (SendFetchFailedPing(options.fetch_symbol_failure_url, + missing_info)) { + FprintfFlush(stderr, "SendFetchFailedPing succeeded\n"); + } else { + FprintfFlush(stderr, "SendFetchFailedPing failed\n"); + } + break; + + default: + FprintfFlush( + stderr, + "FATAL: Unexpected return value '%d' from " + "LocateAndConvertSymbolFile()\n", + located); + assert(0); + break; + } +} + + +// Reads the contents of file |file_name| and populates |contents|. +// Returns true on success. +static bool ReadFile(string file_name, string *contents) { + char buffer[1024 * 8]; + FILE *fp = fopen(file_name.c_str(), "rt"); + if (!fp) { + return false; + } + contents->clear(); + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + contents->append(buffer); + } + fclose(fp); + return true; +} + +// ConvertMissingSymbolsList obtains a missing symbol list from +// |options.missing_symbols_url| or |options.missing_symbols_file| and calls +// ConvertMissingSymbolFile for each missing symbol file in the list. +static bool ConvertMissingSymbolsList(const ConverterOptions &options) { + // Set param to indicate requesting for encoded response. + map parameters; + parameters[L"product"] = L"WinSymConv"; + parameters[L"encoded"] = L"true"; + // Get the missing symbol list. + string missing_symbol_list; + if (!options.missing_symbols_file.empty()) { + if (!ReadFile(options.missing_symbols_file, &missing_symbol_list)) { + return false; + } + } else if (!HTTPDownload::Download(options.missing_symbols_url, ¶meters, + &missing_symbol_list, NULL)) { + return false; + } + + // Tokenize the content into a vector. + vector missing_symbol_lines; + Tokenizer::Tokenize("\n", missing_symbol_list, &missing_symbol_lines); + + FprintfFlush(stderr, "Found %d missing symbol files in list.\n", + missing_symbol_lines.size() - 1); // last line is empty. + int convert_attempts = 0; + for (vector::const_iterator iterator = missing_symbol_lines.begin(); + iterator != missing_symbol_lines.end(); + ++iterator) { + // Decode symbol line. + const string &encoded_line = *iterator; + // Skip lines that are blank. + if (encoded_line.empty()) { + continue; + } + + string line; + if (!WebSafeBase64Unescape(encoded_line, &line)) { + // If decoding fails, assume the line is not encoded. + // This is helpful when the program connects to a debug server without + // encoding. + line = encoded_line; + } + + FprintfFlush(stderr, "\nLine: %s\n", line.c_str()); + + // Turn each element into a MissingSymbolInfo structure. + MissingSymbolInfo missing_info; + if (!ParseMissingString(line, &missing_info)) { + FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed " + "for %s from %ws\n", + line.c_str(), options.missing_symbols_url.c_str()); + continue; + } + + ++convert_attempts; + ConvertMissingSymbolFile(missing_info, options); + } + + // Say something reassuring, since ConvertMissingSymbolFile was never called + // and therefore never reported any progress. + if (convert_attempts == 0) { + string current_time = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: nothing to convert\n", + current_time.c_str()); + } + + return true; +} + +// usage prints the usage message. It returns 1 as a convenience, to be used +// as a return value from main. +static int usage(const char *program_name) { + FprintfFlush(stderr, + "usage: %s [options]\n" + " -f MS servers to ask for all symbols\n" + " -n same, but prevent asking for EXEs\n" + " -l Temporary local storage for symbols\n" + " -s URL for uploading symbols\n" + " -m URL to fetch list of missing symbols\n" + " -mf File containing the list of missing\n" + " symbols. Fetch failures are not\n" + " reported if such file is provided.\n" + " -t URL to report symbol fetch failure\n" + " -b Regex used to blacklist files to\n" + " prevent external symbol requests\n" + " Note that any server specified by -f or -n that starts with \\filer\n" + " will be treated as internal, and all others as external.\n", + program_name); + + return 1; +} + +// "Internal" servers consist only of those whose names start with +// the literal string "\\filer\". +static bool IsInternalServer(const string &server_name) { + if (server_name.find("\\\\filer\\") == 0) { + return true; + } + return false; +} + +// Adds a server with the given name to the list of internal or external +// servers, as appropriate. +static void AddServer(const string &server_name, + vector *internal_servers, + vector *external_servers) { + if (IsInternalServer(server_name)) { + internal_servers->push_back(server_name); + } else { + external_servers->push_back(server_name); + } +} + +} // namespace + +int main(int argc, char **argv) { + string time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str()); + + ConverterOptions options; + options.report_fetch_failures = true; + + // All arguments are paired. + if (argc % 2 != 1) { + return usage(argv[0]); + } + + string blacklist_regex_str; + bool have_any_msss_servers = false; + for (int argi = 1; argi < argc; argi += 2) { + string option = argv[argi]; + string value = argv[argi + 1]; + + if (option == "-f") { + AddServer(value, &options.full_internal_msss_servers, + &options.full_external_msss_servers); + have_any_msss_servers = true; + } else if (option == "-n") { + AddServer(value, &options.no_exe_internal_msss_servers, + &options.no_exe_external_msss_servers); + have_any_msss_servers = true; + } else if (option == "-l") { + if (!options.local_cache_path.empty()) { + return usage(argv[0]); + } + options.local_cache_path = value; + } else if (option == "-s") { + if (!WindowsStringUtils::safe_mbstowcs(value, + &options.upload_symbols_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-m") { + if (!WindowsStringUtils::safe_mbstowcs(value, + &options.missing_symbols_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-mf") { + options.missing_symbols_file = value; + printf("Getting the list of missing symbols from a file. Fetch failures" + " will not be reported.\n"); + options.report_fetch_failures = false; + } else if (option == "-t") { + if (!WindowsStringUtils::safe_mbstowcs( + value, + &options.fetch_symbol_failure_url)) { + FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n", + value.c_str()); + return 1; + } + } else if (option == "-b") { + blacklist_regex_str = value; + } else { + return usage(argv[0]); + } + } + + if (blacklist_regex_str.empty()) { + FprintfFlush(stderr, "No blacklist specified.\n"); + return usage(argv[0]); + } + + // Compile the blacklist regular expression for later use. + options.blacklist_regex = std::regex(blacklist_regex_str.c_str(), + std::regex_constants::icase); + + // Set the defaults. If the user specified any MSSS servers, don't use + // any default. + if (!have_any_msss_servers) { + AddServer(kNoExeMSSSServer, &options.no_exe_internal_msss_servers, + &options.no_exe_external_msss_servers); + } + + if (options.local_cache_path.empty()) { + options.local_cache_path = kLocalCachePath; + } + + if (options.upload_symbols_url.empty()) { + FprintfFlush(stderr, "No upload symbols URL specified.\n"); + return usage(argv[0]); + } + if (options.missing_symbols_url.empty() && + options.missing_symbols_file.empty()) { + FprintfFlush(stderr, "No missing symbols URL or file specified.\n"); + return usage(argv[0]); + } + if (options.fetch_symbol_failure_url.empty()) { + FprintfFlush(stderr, "No fetch symbol failure URL specified.\n"); + return usage(argv[0]); + } + + FprintfFlush(stdout, + "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n", + options.full_internal_msss_servers.size(), + options.full_external_msss_servers.size(), + options.no_exe_internal_msss_servers.size(), + options.no_exe_external_msss_servers.size()); + + if (!ConvertMissingSymbolsList(options)) { + return 1; + } + + time_string = CurrentDateAndTime(); + FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str()); + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp new file mode 100644 index 0000000000..fe443d1b40 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp @@ -0,0 +1,57 @@ +# Copyright 2013 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'converter_exe', + 'type': 'executable', + 'sources': [ + 'converter.cc', + 'escaping.cc', + 'escaping.h', + 'http_client.h', + 'http_download.cc', + 'http_download.h', + 'tokenizer.cc', + 'tokenizer.h', + 'winhttp_client.cc', + 'winhttp_client.h', + 'wininet_client.cc', + 'wininet_client.h', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + '../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc new file mode 100644 index 0000000000..74a7203ab4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc @@ -0,0 +1,757 @@ +// Copyright 2019 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 "tools/windows/converter_exe/escaping.h" + +#include + +#define kApb kAsciiPropertyBits + +const unsigned char kAsciiPropertyBits[256] = { + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 + 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 + 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, +}; + +// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'. +static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); } + +/////////////////////////////////// +// scoped_array +/////////////////////////////////// +// scoped_array is like scoped_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// scoped_array is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](std::ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether a scoped_array and a raw pointer refer to + // the same array, not just to two different but equal arrays. + bool operator==(const C* p) const { return array_ == p; } + bool operator!=(const C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + + +/////////////////////////////////// +// Escape methods +/////////////////////////////////// + +namespace strings { + +// Return a mutable char* pointing to a string's internal buffer, +// which may not be null-terminated. Writing through this pointer will +// modify the string. +// +// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the +// next call to a string method that invalidates iterators. +// +// As of 2006-04, there is no standard-blessed way of getting a +// mutable reference to a string's internal buffer. However, issue 530 +// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) +// proposes this as the method. According to Matt Austern, this should +// already work on all current implementations. +inline char* string_as_array(string* str) { + // DO NOT USE const_cast(str->data())! See the unittest for why. + return str->empty() ? NULL : &*str->begin(); +} + +int CalculateBase64EscapedLen(int input_len, bool do_padding) { + // these formulae were copied from comments that used to go with the base64 + // encoding functions + int intermediate_result = 8 * input_len + 5; + assert(intermediate_result > 0); // make sure we didn't overflow + int len = intermediate_result / 6; + if (do_padding) len = ((len + 3) / 4) * 4; + return len; +} + +// Base64Escape does padding, so this calculation includes padding. +int CalculateBase64EscapedLen(int input_len) { + return CalculateBase64EscapedLen(input_len, true); +} + +// ---------------------------------------------------------------------- +// int Base64Unescape() - base64 decoder +// int Base64Escape() - base64 encoder +// int WebSafeBase64Unescape() - Google's variation of base64 decoder +// int WebSafeBase64Escape() - Google's variation of base64 encoder +// +// Check out +// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal +// description, but what we care about is that... +// Take the encoded stuff in groups of 4 characters and turn each +// character into a code 0 to 63 thus: +// A-Z map to 0 to 25 +// a-z map to 26 to 51 +// 0-9 map to 52 to 61 +// +(- for WebSafe) maps to 62 +// /(_ for WebSafe) maps to 63 +// There will be four numbers, all less than 64 which can be represented +// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). +// Arrange the 6 digit binary numbers into three bytes as such: +// aaaaaabb bbbbcccc ccdddddd +// Equals signs (one or two) are used at the end of the encoded block to +// indicate that the text was not an integer multiple of three bytes long. +// ---------------------------------------------------------------------- + +int Base64UnescapeInternal(const char *src, int szsrc, + char *dest, int szdest, + const signed char* unbase64) { + static const char kPad64 = '='; + + int decode = 0; + int destidx = 0; + int state = 0; + unsigned int ch = 0; + unsigned int temp = 0; + + // The GET_INPUT macro gets the next input character, skipping + // over any whitespace, and stopping when we reach the end of the + // string or when we read any non-data character. The arguments are + // an arbitrary identifier (used as a label for goto) and the number + // of data bytes that must remain in the input to avoid aborting the + // loop. +#define GET_INPUT(label, remain) \ + label: \ + --szsrc; \ + ch = *src++; \ + decode = unbase64[ch]; \ + if (decode < 0) { \ + if (ascii_isspace((char)ch) && szsrc >= remain) \ + goto label; \ + state = 4 - remain; \ + break; \ + } + + // if dest is null, we're just checking to see if it's legal input + // rather than producing output. (I suspect this could just be done + // with a regexp...). We duplicate the loop so this test can be + // outside it instead of in every iteration. + + if (dest) { + // This loop consumes 4 input bytes and produces 3 output bytes + // per iteration. We can't know at the start that there is enough + // data left in the string for a full iteration, so the loop may + // break out in the middle; if so 'state' will be set to the + // number of input bytes read. + + while (szsrc >= 4) { + // We'll start by optimistically assuming that the next four + // bytes of the string (src[0..3]) are four good data bytes + // (that is, no nulls, whitespace, padding chars, or illegal + // chars). We need to test src[0..2] for nulls individually + // before constructing temp to preserve the property that we + // never read past a null in the string (no matter how long + // szsrc claims the string is). + + if (!src[0] || !src[1] || !src[2] || + (temp = ((unbase64[static_cast(src[0])] << 18) | + (unbase64[static_cast(src[1])] << 12) | + (unbase64[static_cast(src[2])] << 6) | + (unbase64[static_cast(src[3])]))) & 0x80000000) { + // Iff any of those four characters was bad (null, illegal, + // whitespace, padding), then temp's high bit will be set + // (because unbase64[] is -1 for all bad characters). + // + // We'll back up and resort to the slower decoder, which knows + // how to handle those cases. + + GET_INPUT(first, 4); + temp = decode; + GET_INPUT(second, 3); + temp = (temp << 6) | decode; + GET_INPUT(third, 2); + temp = (temp << 6) | decode; + GET_INPUT(fourth, 1); + temp = (temp << 6) | decode; + } else { + // We really did have four good data bytes, so advance four + // characters in the string. + + szsrc -= 4; + src += 4; + decode = -1; + ch = '\0'; + } + + // temp has 24 bits of input, so write that out as three bytes. + + if (destidx+3 > szdest) return -1; + dest[destidx+2] = (char)temp; + temp >>= 8; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + destidx += 3; + } + } else { + while (szsrc >= 4) { + if (!src[0] || !src[1] || !src[2] || + (temp = ((unbase64[static_cast(src[0])] << 18) | + (unbase64[static_cast(src[1])] << 12) | + (unbase64[static_cast(src[2])] << 6) | + (unbase64[static_cast(src[3])]))) & 0x80000000) { + GET_INPUT(first_no_dest, 4); + GET_INPUT(second_no_dest, 3); + GET_INPUT(third_no_dest, 2); + GET_INPUT(fourth_no_dest, 1); + } else { + szsrc -= 4; + src += 4; + decode = -1; + ch = '\0'; + } + destidx += 3; + } + } + +#undef GET_INPUT + + // if the loop terminated because we read a bad character, return + // now. + if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch)) + return -1; + + if (ch == kPad64) { + // if we stopped by hitting an '=', un-read that character -- we'll + // look at it again when we count to check for the proper number of + // equals signs at the end. + ++szsrc; + --src; + } else { + // This loop consumes 1 input byte per iteration. It's used to + // clean up the 0-3 input bytes remaining when the first, faster + // loop finishes. 'temp' contains the data from 'state' input + // characters read by the first loop. + while (szsrc > 0) { + --szsrc; + ch = *src++; + decode = unbase64[ch]; + if (decode < 0) { + if (ascii_isspace((char)ch)) { + continue; + } else if (ch == '\0') { + break; + } else if (ch == kPad64) { + // back up one character; we'll read it again when we check + // for the correct number of equals signs at the end. + ++szsrc; + --src; + break; + } else { + return -1; + } + } + + // Each input character gives us six bits of output. + temp = (temp << 6) | decode; + ++state; + if (state == 4) { + // If we've accumulated 24 bits of output, write that out as + // three bytes. + if (dest) { + if (destidx+3 > szdest) return -1; + dest[destidx+2] = (char)temp; + temp >>= 8; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + } + destidx += 3; + state = 0; + temp = 0; + } + } + } + + // Process the leftover data contained in 'temp' at the end of the input. + int expected_equals = 0; + switch (state) { + case 0: + // Nothing left over; output is a multiple of 3 bytes. + break; + + case 1: + // Bad input; we have 6 bits left over. + return -1; + + case 2: + // Produce one more output byte from the 12 input bits we have left. + if (dest) { + if (destidx+1 > szdest) return -1; + temp >>= 4; + dest[destidx] = (char)temp; + } + ++destidx; + expected_equals = 2; + break; + + case 3: + // Produce two more output bytes from the 18 input bits we have left. + if (dest) { + if (destidx+2 > szdest) return -1; + temp >>= 2; + dest[destidx+1] = (char)temp; + temp >>= 8; + dest[destidx] = (char)temp; + } + destidx += 2; + expected_equals = 1; + break; + + default: + // state should have no other values at this point. + fprintf(stdout, "This can't happen; base64 decoder state = %d", state); + } + + // The remainder of the string should be all whitespace, mixed with + // exactly 0 equals signs, or exactly 'expected_equals' equals + // signs. (Always accepting 0 equals signs is a google extension + // not covered in the RFC.) + + int equals = 0; + while (szsrc > 0 && *src) { + if (*src == kPad64) + ++equals; + else if (!ascii_isspace(*src)) + return -1; + --szsrc; + ++src; + } + + return (equals == 0 || equals == expected_equals) ? destidx : -1; +} + +int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) { + static const signed char UnBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 + }; + // The above array was generated by the following code + // #include + // #include + // #include + // main() + // { + // static const char Base64[] = + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + // char *pos; + // int idx, i, j; + // printf(" "); + // for (i = 0; i < 255; i += 8) { + // for (j = i; j < i + 8; j++) { + // pos = strchr(Base64, j); + // if ((pos == NULL) || (j == 0)) + // idx = -1; + // else + // idx = pos - Base64; + // if (idx == -1) + // printf(" %2d, ", idx); + // else + // printf(" %2d/*%c*/,", idx, j); + // } + // printf("\n "); + // } + // } + + return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64); +} + +bool Base64Unescape(const char *src, int slen, string* dest) { + // Determine the size of the output string. Base64 encodes every 3 bytes into + // 4 characters. any leftover chars are added directly for good measure. + // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt + const int dest_len = 3 * (slen / 4) + (slen % 4); + + dest->resize(dest_len); + + // We are getting the destination buffer by getting the beginning of the + // string and converting it into a char *. + const int len = Base64Unescape(src, slen, + string_as_array(dest), dest->size()); + if (len < 0) { + return false; + } + + // could be shorter if there was padding + assert(len <= dest_len); + dest->resize(len); + + return true; +} + +// Base64Escape +// +// NOTE: We have to use an unsigned type for src because code built +// in the the /google tree treats characters as signed unless +// otherwised specified. +// +// TODO(who?): Move this function to use the char* type for "src" +int Base64EscapeInternal(const unsigned char *src, int szsrc, + char *dest, int szdest, const char *base64, + bool do_padding) { + static const char kPad64 = '='; + + if (szsrc <= 0) return 0; + + char *cur_dest = dest; + const unsigned char *cur_src = src; + + // Three bytes of data encodes to four characters of cyphertext. + // So we can pump through three-byte chunks atomically. + while (szsrc > 2) { /* keep going until we have less than 24 bits */ + if ((szdest -= 4) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)]; + cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)]; + cur_dest[3] = base64[cur_src[2] & 0x3f]; + + cur_dest += 4; + cur_src += 3; + szsrc -= 3; + } + + /* now deal with the tail (<=2 bytes) */ + switch (szsrc) { + case 0: + // Nothing left; nothing more to do. + break; + case 1: + // One byte left: this encodes to two characters, and (optionally) + // two pad characters to round out the four-character cypherblock. + if ((szdest -= 2) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[(cur_src[0] & 0x03) << 4]; + cur_dest += 2; + if (do_padding) { + if ((szdest -= 2) < 0) return 0; + cur_dest[0] = kPad64; + cur_dest[1] = kPad64; + cur_dest += 2; + } + break; + case 2: + // Two bytes left: this encodes to three characters, and (optionally) + // one pad character to round out the four-character cypherblock. + if ((szdest -= 3) < 0) return 0; + cur_dest[0] = base64[cur_src[0] >> 2]; + cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)]; + cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2]; + cur_dest += 3; + if (do_padding) { + if ((szdest -= 1) < 0) return 0; + cur_dest[0] = kPad64; + cur_dest += 1; + } + break; + default: + // Should not be reached: blocks of 3 bytes are handled + // in the while loop before this switch statement. + fprintf(stderr, "Logic problem? szsrc = %d", szsrc); + assert(false); + break; + } + return (cur_dest - dest); +} + +static const char kBase64Chars[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const char kWebSafeBase64Chars[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) { + return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true); +} + +void Base64Escape(const unsigned char *src, int szsrc, + string* dest, bool do_padding) { + const int max_escaped_size = + CalculateBase64EscapedLen(szsrc, do_padding); + dest->clear(); + dest->resize(max_escaped_size + 1, '\0'); + const int escaped_len = Base64EscapeInternal(src, szsrc, + &*dest->begin(), dest->size(), + kBase64Chars, + do_padding); + assert(max_escaped_size <= escaped_len); + dest->resize(escaped_len); +} + +void Base64Escape(const string& src, string* dest) { + Base64Escape(reinterpret_cast(src.c_str()), + src.size(), dest, true); +} + +//////////////////////////////////////////////////// +// WebSafe methods +//////////////////////////////////////////////////// + +int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) { + static const signed char UnBase64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 62/*-*/, -1, -1, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 + }; + // The above array was generated by the following code + // #include + // #include + // #include + // main() + // { + // static const char Base64[] = + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + // char *pos; + // int idx, i, j; + // printf(" "); + // for (i = 0; i < 255; i += 8) { + // for (j = i; j < i + 8; j++) { + // pos = strchr(Base64, j); + // if ((pos == NULL) || (j == 0)) + // idx = -1; + // else + // idx = pos - Base64; + // if (idx == -1) + // printf(" %2d, ", idx); + // else + // printf(" %2d/*%c*/,", idx, j); + // } + // printf("\n "); + // } + // } + + return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64); +} + +bool WebSafeBase64Unescape(const char *src, int slen, string* dest) { + int dest_len = 3 * (slen / 4) + (slen % 4); + dest->clear(); + dest->resize(dest_len); + int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size()); + if (len < 0) { + dest->clear(); + return false; + } + // could be shorter if there was padding + assert(len <= dest_len); + dest->resize(len); + return true; +} + +bool WebSafeBase64Unescape(const string& src, string* dest) { + return WebSafeBase64Unescape(src.data(), src.size(), dest); +} + +int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest, + int szdest, bool do_padding) { + return Base64EscapeInternal(src, szsrc, dest, szdest, + kWebSafeBase64Chars, do_padding); +} + +void WebSafeBase64Escape(const unsigned char *src, int szsrc, + string *dest, bool do_padding) { + const int max_escaped_size = + CalculateBase64EscapedLen(szsrc, do_padding); + dest->clear(); + dest->resize(max_escaped_size + 1, '\0'); + const int escaped_len = Base64EscapeInternal(src, szsrc, + &*dest->begin(), dest->size(), + kWebSafeBase64Chars, + do_padding); + assert(max_escaped_size <= escaped_len); + dest->resize(escaped_len); +} + +void WebSafeBase64EscapeInternal(const string& src, + string* dest, + bool do_padding) { + int encoded_len = CalculateBase64EscapedLen(src.size()); + scoped_array buf(new char[encoded_len]); + int len = WebSafeBase64Escape(reinterpret_cast(src.c_str()), + src.size(), buf.get(), + encoded_len, do_padding); + dest->assign(buf.get(), len); +} + +void WebSafeBase64Escape(const string& src, string* dest) { + WebSafeBase64EscapeInternal(src, dest, false); +} + +void WebSafeBase64EscapeWithPadding(const string& src, string* dest) { + WebSafeBase64EscapeInternal(src, dest, true); +} + +} // namespace strings diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h new file mode 100644 index 0000000000..c8aa90b7b2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h @@ -0,0 +1,99 @@ +// Copyright 2019 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. +// +// Base64 escaping methods to encode/decode strings. + +#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_ + +#include + +namespace strings { + +using std::string; + +// ---------------------------------------------------------------------- +// Base64Escape() +// WebSafeBase64Escape() +// Encode "src" to "dest" using base64 encoding. +// src is not null terminated, instead specify len. +// 'dest' should have at least CalculateBase64EscapedLen() length. +// RETURNS the length of dest. +// The WebSafe variation use '-' instead of '+' and '_' instead of '/' +// so that we can place the out in the URL or cookies without having +// to escape them. It also has an extra parameter "do_padding", +// which when set to false will prevent padding with "=". +// ---------------------------------------------------------------------- +void Base64Escape(const string& src, string* dest); +int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest); +// Encode src into dest with padding. +void Base64Escape(const unsigned char* src, int szsrc, + string* dest, bool do_padding); + +int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest, + int szdest, bool do_padding); +// Encode src into dest web-safely without padding. +void WebSafeBase64Escape(const string& src, string* dest); +// Encode src into dest web-safely with padding. +void WebSafeBase64EscapeWithPadding(const string& src, string* dest); +void WebSafeBase64Escape(const unsigned char* src, int szsrc, + string* dest, bool do_padding); + +// ---------------------------------------------------------------------- +// Base64Unescape() +// WebSafeBase64Unescape() +// Copies "src" to "dest", where src is in base64 and is written to its +// ASCII equivalents. src is not null terminated, instead specify len. +// I recommend that slen +#include +#include + +typedef void* HttpHandle; + +namespace crash { + +// HttpClient provides an abstract layer for HTTP APIs. The actual +// implementation can be based on either WinHttp or WinInet. +class HttpClient { + public: + enum AccessType { + ACCESS_TYPE_PRECONFIG, + ACCESS_TYPE_DIRECT, + ACCESS_TYPE_PROXY, + }; + + virtual ~HttpClient() {} + + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const = 0; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const = 0; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const = 0; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const = 0; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const = 0; + virtual bool ReceiveResponse(HttpHandle request_handle) const = 0; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const = 0; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const = 0; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const = 0; + virtual bool Close(HttpHandle handle) const = 0; + + static const DWORD kUnknownContentLength = (DWORD)-1; +}; + +} // namespace crash + +#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc new file mode 100644 index 0000000000..5afc1ccc14 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc @@ -0,0 +1,326 @@ +// Copyright 2019 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 +#include +#include +#include + +#include + +#include "tools/windows/converter_exe/http_download.h" +#include "tools/windows/converter_exe/winhttp_client.h" +#include "tools/windows/converter_exe/wininet_client.h" + +namespace crash { +static const std::vector::size_type kVectorChunkSize = 4096; // 4 KB + +using std::vector; + +// Class that atuo closes the contained HttpHandle when the object +// goes out of scope. +class AutoHttpHandle { + public: + AutoHttpHandle() : handle_(NULL) {} + explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {} + ~AutoHttpHandle() { + if (handle_) { + InternetCloseHandle(handle_); + } + } + + HttpHandle get() { return handle_; } + HttpHandle* get_handle_addr () { return &handle_; } + + private: + HttpHandle handle_; +}; + +// Template class for auto releasing the contained pointer when +// the object goes out of scope. +template +class AutoPtr { + public: + explicit AutoPtr(T* ptr) : ptr_(ptr) {} + ~AutoPtr() { + if (ptr_) { + delete ptr_; + } + } + + T* get() { return ptr_; } + T* operator -> () { return ptr_; } + + private: + T* ptr_; +}; + +// CheckParameters ensures that the parameters in |parameters| are safe for +// use in an HTTP URL. Returns true if they are, false if unsafe characters +// are present. +static bool CheckParameters(const map *parameters) { + for (map::const_iterator iterator = parameters->begin(); + iterator != parameters->end(); + ++iterator) { + const wstring &key = iterator->first; + if (key.empty()) { + // Disallow empty parameter names. + return false; + } + for (unsigned int i = 0; i < key.size(); ++i) { + wchar_t c = key[i]; + if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) { + return false; + } + } + + const wstring &value = iterator->second; + for (unsigned int i = 0; i < value.size(); ++i) { + wchar_t c = value[i]; + if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) { + return false; + } + } + } + + return true; +} + +HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) { + const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP"); + TCHAR buffer[2] = {0}; + HttpClient* http_client = NULL; + + if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable, + buffer, + sizeof(buffer)/sizeof(buffer[0])) > 0) { + fprintf(stdout, + "Environment variable [%ws] is set, use WinHttp\n", + kHttpApiPolicyEnvironmentVariable); + http_client = CreateWinHttpClient(url); + if (http_client == NULL) { + fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? " + "Fall back to WinInet API.\n"); + } + } else { + fprintf(stderr, + "Environment variable [%ws] is NOT set, use WinInet API\n", + kHttpApiPolicyEnvironmentVariable); + } + + if (http_client == NULL) { + return CreateWinInetClient(url); + } + + return http_client; +} + +// static +bool HTTPDownload::Download(const wstring &url, + const map *parameters, + string *content, int *status_code) { + assert(content); + AutoPtr http_client(CreateHttpClient(url.c_str())); + + if (!http_client.get()) { + fprintf(stderr, "Failed to create any http client.\n"); + return false; + } + + if (status_code) { + *status_code = 0; + } + + wchar_t scheme[16] = {0}; + wchar_t host[256] = {0}; + wchar_t path[256] = {0}; + int port = 0; + if (!http_client->CrackUrl(url.c_str(), + 0, + scheme, + sizeof(scheme)/sizeof(scheme[0]), + host, + sizeof(host)/sizeof(host[0]), + path, + sizeof(path)/sizeof(path[0]), + &port)) { + fprintf(stderr, + "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + bool secure = false; + if (_wcsicmp(scheme, L"https") == 0) { + secure = true; + } else if (wcscmp(scheme, L"http") != 0) { + fprintf(stderr, + "HTTPDownload::Download: scheme must be http or https for %ws\n", + url.c_str()); + return false; + } + + AutoHttpHandle internet; + if (!http_client->Open(NULL, // user agent + HttpClient::ACCESS_TYPE_PRECONFIG, + NULL, // proxy name + NULL, // proxy bypass + internet.get_handle_addr())) { + fprintf(stderr, + "HTTPDownload::Download: Open: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + AutoHttpHandle connection; + if (!http_client->Connect(internet.get(), + host, + port, + connection.get_handle_addr())) { + fprintf(stderr, + "HTTPDownload::Download: InternetConnect: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + wstring request_string = path; + if (parameters) { + // TODO(mmentovai): escape bad characters in parameters instead of + // forbidding them. + if (!CheckParameters(parameters)) { + fprintf(stderr, + "HTTPDownload::Download: invalid characters in parameters\n"); + return false; + } + + bool added_parameter = false; + for (map::const_iterator iterator = parameters->begin(); + iterator != parameters->end(); + ++iterator) { + request_string.append(added_parameter ? L"&" : L"?"); + request_string.append(iterator->first); + request_string.append(L"="); + request_string.append(iterator->second); + added_parameter = true; + } + } + + AutoHttpHandle request; + if (!http_client->OpenRequest(connection.get(), + L"GET", + request_string.c_str(), + NULL, // version + NULL, // referer + secure, + request.get_handle_addr())) { + fprintf(stderr, + "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n", + GetLastError(), url.c_str(), request_string.c_str()); + return false; + } + + if (!http_client->SendRequest(request.get(), NULL, 0)) { + fprintf(stderr, + "HttpClient::SendRequest: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + if (!http_client->ReceiveResponse(request.get())) { + fprintf(stderr, + "HttpClient::ReceiveResponse: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + + int http_status = 0; + if (!http_client->GetHttpStatusCode(request.get(), &http_status)) { + fprintf(stderr, + "HttpClient::GetHttpStatusCode: error %lu for %ws\n", + GetLastError(), url.c_str()); + return false; + } + if (http_status != 200) { + fprintf(stderr, + "HTTPDownload::Download: HTTP status code %d for %ws\n", + http_status, url.c_str()); + return false; + } + + DWORD content_length = 0; + vector::size_type buffer_size = 0; + http_client->GetContentLength(request.get(), &content_length); + if (content_length == HttpClient::kUnknownContentLength) { + buffer_size = kVectorChunkSize; + } else { + buffer_size = content_length; + } + + if (content_length != 0) { + vector response_buffer = vector(buffer_size+1); + DWORD size_read; + DWORD total_read = 0; + bool read_result; + do { + if (content_length == HttpClient::kUnknownContentLength + && buffer_size == total_read) { + // The content length wasn't specified in the response header, so we + // have to keep growing the buffer until we're done reading. + buffer_size += kVectorChunkSize; + response_buffer.resize(buffer_size); + } + read_result = !!http_client->ReadData( + request.get(), + &response_buffer[total_read], + static_cast(buffer_size) - total_read, + &size_read); + total_read += size_read; + } while (read_result && (size_read != 0)); + + if (!read_result) { + fprintf(stderr, + "HttpClient::ReadData: error %lu for %ws\n", + GetLastError(), + url.c_str()); + return false; + } else if (size_read != 0) { + fprintf(stderr, + "HttpClient::ReadData: error %lu/%lu for %ws\n", + total_read, + content_length, + url.c_str()); + return false; + } + content->assign(&response_buffer[0], total_read); + } else { + content->clear(); + } + return true; +} + +} // namespace crash diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h new file mode 100644 index 0000000000..2d705d5ece --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h @@ -0,0 +1,62 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ + +#include +#include +#include "tools/windows/converter_exe/winhttp_client.h" + +namespace crash { + +using std::map; +using std::string; +using std::wstring; + +class HTTPDownload { + public: + // Retrieves the resource located at |url|, a http or https URL, via WinInet. + // The request is fetched with GET request; the optional |parameters| are + // appended to the URL. Returns true on success, placing the content of the + // retrieved resource in |content|. Returns false on failure. HTTP status + // codes other than 200 cause Download to return false. If |status_code| is + // supplied, it will be set to the value of the HTTP status code, if an HTTP + // transaction occurs. If Download fails before a transaction can occur, + // |status_code| will be set to 0. Any failures will result in messages + // being printed to stderr. + static bool Download(const wstring &url, + const map *parameters, + string *content, int *status_code); + private: + static HttpClient* CreateHttpClient(const wchar_t*); +}; + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt new file mode 100644 index 0000000000..91641fca96 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt @@ -0,0 +1,5 @@ +msctf.pdb|6A5BABB8E88644C696530BFE3C90F32F2|6.1.7600.16385|msctf.dll|4A5BDFAA109000 +imm32.pdb|98F27BA5AEE541ECBEE00CD03AD50FEE2|6.1.7600.16385|imm32.dll|4A5BDF402e000 +amd_opencl64.pdb|3D306D0FCCB14F47AF322A5ACDF5EEA81||amd_opencl64.dll|587901FB1E000 +igd10iumd64.pdb|B2B72475BB0846D8ADE4344FAE0CCE361 ||igd10iumd64.dll|568D69FBD99000 +NvCameraWhitelisting64.pdb|3C364C4D3FBF4180B021D52D469C6DAB1||NvCameraWhitelisting64.dll|5B8ED23485000 \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes new file mode 100644 index 0000000000..1d01dda71b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes @@ -0,0 +1,2 @@ +See breakpad/tools/windows/converter/ms_symbol_server_converter.h for a +description of this file's function. diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc new file mode 100644 index 0000000000..992694cd0c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc @@ -0,0 +1,61 @@ +// Copyright 2019 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 + +#include "tools/windows/converter_exe/tokenizer.h" + +namespace crash { + +// static +void Tokenizer::Tokenize(const string &delimiters, const string &input, + vector *output) { + assert(output); + output->clear(); + + string::size_type position = 0; // Where to begin looking for a delimiter + string::size_type new_position; // Position of found delimiter + string token; + + while ((new_position = input.find_first_of(delimiters, position)) != + string::npos) { + token = input.substr(position, new_position - position); + output->push_back(token); + + // Next time, begin looking right after this delimiter. + position = new_position + 1; + } + + // There are no more delimiters in the string. Take everything from the + // final delimiter up to the end of the string as a token. This may be + // an empty string. + token = input.substr(position); + output->push_back(token); +} + +} // namespace crash diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h new file mode 100644 index 0000000000..f4bbcfd0e8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h @@ -0,0 +1,51 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ + +#include +#include + +namespace crash { + +using std::string; +using std::vector; + +class Tokenizer { + public: + // Splits |input| into a series of tokens delimited in the input string by + // any of the characters in |delimiters|. The tokens are passed back in the + // |output| vector. + static void Tokenize(const string &delimiters, const string &input, + vector *output); +}; + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc new file mode 100644 index 0000000000..8a8ade3b6c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc @@ -0,0 +1,307 @@ +// Copyright 2019 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 "tools/windows/converter_exe/winhttp_client.h" + +#include +#include +#include +#include +#include + +namespace crash { + +namespace internal { + +// This class implements HttpClient based on WinInet APIs. +class WinHttpClient : public HttpClient { + public: + virtual ~WinHttpClient() {} + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const; + virtual bool ReceiveResponse(HttpHandle request_handle) const; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const; + virtual bool Close(HttpHandle handle) const; + + private: + static DWORD MapAccessType(DWORD access_type); + static HINTERNET ToHINTERNET(HttpHandle handle); + static HttpHandle FromHINTERNET(HINTERNET handle); +}; + +bool WinHttpClient::CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const { + assert(url); + assert(scheme); + assert(host); + assert(uri); + assert(port); + + URL_COMPONENTS url_comp = {0}; + url_comp.dwStructSize = sizeof(url_comp); + url_comp.lpszScheme = scheme; + url_comp.dwSchemeLength = static_cast(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast(uri_buffer_length); + + bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast(url_comp.nPort); + } + return result; +} + +bool WinHttpClient::Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const { + *session_handle = FromHINTERNET(::WinHttpOpen(user_agent, + MapAccessType(access_type), + proxy_name, + proxy_bypass, + 0)); + + return !!(*session_handle); +} + +bool WinHttpClient::Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const { + assert(server); + + // Uses NULL user name and password to connect. + *connection_handle = FromHINTERNET(::WinHttpConnect( + ToHINTERNET(session_handle), + server, + static_cast(port), + NULL)); + return !!(*connection_handle); +} + +bool WinHttpClient::OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const { + assert(connection_handle); + assert(verb); + assert(uri); + assert(request_handle); + + *request_handle = FromHINTERNET(::WinHttpOpenRequest( + ToHINTERNET(connection_handle), + verb, + uri, + version, + referrer, + WINHTTP_DEFAULT_ACCEPT_TYPES, + is_secure ? WINHTTP_FLAG_SECURE : 0)); + return !!(*request_handle); +} + +bool WinHttpClient::SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const { + assert(request_handle); + + return !!::WinHttpSendRequest(ToHINTERNET(request_handle), + headers, + headers_length, + NULL, + 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, + NULL); +} + +bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const { + assert(request_handle); + + return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL); +} + +bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const { + TCHAR http_status_string[4] = {0}; + DWORD http_status_string_size = sizeof(http_status_string); + if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle), + WINHTTP_QUERY_STATUS_CODE, + WINHTTP_HEADER_NAME_BY_INDEX, + static_cast(&http_status_string), + &http_status_string_size, 0)) { + return false; + } + + *status_code = static_cast(_tcstol(http_status_string, NULL, 10)); + return true; +} + +bool WinHttpClient::GetContentLength(HttpHandle request_handle, + DWORD* content_length) const { + assert(request_handle); + assert(content_length); + + TCHAR content_length_string[11] = {0}; + DWORD content_length_string_size = sizeof(content_length_string); + if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle), + WINHTTP_QUERY_CONTENT_LENGTH, + WINHTTP_HEADER_NAME_BY_INDEX, + static_cast(&content_length_string), + &content_length_string_size, 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = + static_cast(wcstol(content_length_string, NULL, 10)); + } + return true; +} + +bool WinHttpClient::ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const { + assert(request_handle); + assert(buffer); + assert(bytes_read); + + DWORD bytes_read_local = 0; + if (!::WinHttpReadData(ToHINTERNET(request_handle), + buffer, + buffer_length, + &bytes_read_local)) { + return false; + } + *bytes_read = bytes_read_local; + return true; +} + +bool WinHttpClient::Close(HttpHandle handle) const { + assert(handle); + return !!::WinHttpCloseHandle(ToHINTERNET(handle)); +} + +DWORD WinHttpClient::MapAccessType(DWORD access_type) { + switch (static_cast(access_type)) { + case ACCESS_TYPE_PRECONFIG: + default: + return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; + case ACCESS_TYPE_DIRECT: + return WINHTTP_ACCESS_TYPE_NO_PROXY; + case ACCESS_TYPE_PROXY: + return WINHTTP_ACCESS_TYPE_NAMED_PROXY; + } +} + + +HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) { + return static_cast(handle); +} + +HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) { + return static_cast(handle); +} + +} // namespace internal + +HttpClient* CreateWinHttpClient(const TCHAR* url) { + assert(url); + + internal::WinHttpClient winhttp; + wchar_t scheme[16] = {0}; + wchar_t host[256] = {0}; + wchar_t path[256] = {0}; + int port = 0; + + if (!winhttp.CrackUrl(url, + 0, + scheme, + sizeof(scheme)/sizeof(scheme[0]), + host, + sizeof(host)/sizeof(host[0]), + path, + sizeof(path)/sizeof(path[0]), + &port)) { + return NULL; + } + + if (_wcsicmp(scheme, L"https") == 0) { + // Winhttp under WINE doesn't support wildcard certificates, so avoid + // to use it if the scheme is https. The caller should fall back to + // use wininet if NULL is returned. + return NULL; + } + + return new internal::WinHttpClient(); +} + +} // namespace crash diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h new file mode 100644 index 0000000000..819d610f1c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h @@ -0,0 +1,40 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ + +#include "tools/windows/converter_exe/http_client.h" + +namespace crash { + +HttpClient* CreateWinHttpClient(const TCHAR* url); + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc new file mode 100644 index 0000000000..3e542db25f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc @@ -0,0 +1,278 @@ +// Copyright 2019 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 "tools/windows/converter_exe/wininet_client.h" + +#include +#include +#include +#include + +namespace crash { + +namespace internal { + +// This class implements HttpClient based on WinInet APIs. +class WinInetClient : public HttpClient { + public: + virtual ~WinInetClient() {} + virtual bool CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const; + virtual bool Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const; + virtual bool Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const; + virtual bool OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const; + virtual bool SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const; + virtual bool ReceiveResponse(HttpHandle request_handle) const; + virtual bool GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const; + virtual bool GetContentLength(HttpHandle request_handle, + DWORD* content_length) const; + virtual bool ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const; + virtual bool Close(HttpHandle handle) const; + + private: + static DWORD MapAccessType(DWORD access_type); + static HINTERNET ToHINTERNET(HttpHandle handle); + static HttpHandle FromHINTERNET(HINTERNET handle); +}; + +bool WinInetClient::CrackUrl(const TCHAR* url, + DWORD flags, + TCHAR* scheme, + size_t scheme_buffer_length, + TCHAR* host, + size_t host_buffer_length, + TCHAR* uri, + size_t uri_buffer_length, + int* port) const { + assert(url); + assert(scheme); + assert(host); + assert(uri); + assert(port); + + URL_COMPONENTS url_comp = {0}; + url_comp.dwStructSize = sizeof(url_comp); + url_comp.lpszScheme = scheme; + url_comp.dwSchemeLength = static_cast(scheme_buffer_length); + url_comp.lpszHostName = host; + url_comp.dwHostNameLength = static_cast(host_buffer_length); + url_comp.lpszUrlPath = uri; + url_comp.dwUrlPathLength = static_cast(uri_buffer_length); + + bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp); + if (result) { + *port = static_cast(url_comp.nPort); + } + return result; +} + +bool WinInetClient::Open(const TCHAR* user_agent, + DWORD access_type, + const TCHAR* proxy_name, + const TCHAR* proxy_bypass, + HttpHandle* session_handle) const { + *session_handle = FromHINTERNET(::InternetOpen(user_agent, + MapAccessType(access_type), + proxy_name, + proxy_bypass, + 0)); + return !!(*session_handle); +} + +bool WinInetClient::Connect(HttpHandle session_handle, + const TCHAR* server, + int port, + HttpHandle* connection_handle) const { + assert(server); + + // Uses NULL user name and password to connect. Always uses http service. + *connection_handle = FromHINTERNET(::InternetConnect( + ToHINTERNET(session_handle), + server, + static_cast(port), + NULL, + NULL, + INTERNET_SERVICE_HTTP, + 0, + 0)); + return !!(*connection_handle); +} + +bool WinInetClient::OpenRequest(HttpHandle connection_handle, + const TCHAR* verb, + const TCHAR* uri, + const TCHAR* version, + const TCHAR* referrer, + bool is_secure, + HttpHandle* request_handle) const { + assert(connection_handle); + assert(verb); + assert(uri); + + *request_handle = FromHINTERNET(::HttpOpenRequest( + ToHINTERNET(connection_handle), + verb, + uri, + version, + referrer, + NULL, + is_secure ? INTERNET_FLAG_SECURE : 0, + NULL)); + return !!(*request_handle); +} + +bool WinInetClient::SendRequest(HttpHandle request_handle, + const TCHAR* headers, + DWORD headers_length) const { + assert(request_handle); + + return !!::HttpSendRequest(ToHINTERNET(request_handle), + headers, + headers_length, + NULL, + 0); +} + +bool WinInetClient::ReceiveResponse(HttpHandle) const { + return true; +} + +bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle, + int* status_code) const { + assert(request_handle); + + TCHAR http_status_string[4] = {0}; + DWORD http_status_string_size = sizeof(http_status_string); + if (!::HttpQueryInfo(ToHINTERNET(request_handle), + HTTP_QUERY_STATUS_CODE, + static_cast(&http_status_string), + &http_status_string_size, + 0)) { + return false; + } + + *status_code = _tcstol(http_status_string, NULL, 10); + return true; +} + +bool WinInetClient::GetContentLength(HttpHandle request_handle, + DWORD* content_length) const { + assert(request_handle); + assert(content_length); + + TCHAR content_length_string[11]; + DWORD content_length_string_size = sizeof(content_length_string); + if (!::HttpQueryInfo(ToHINTERNET(request_handle), + HTTP_QUERY_CONTENT_LENGTH, + static_cast(&content_length_string), + &content_length_string_size, + 0)) { + *content_length = kUnknownContentLength; + } else { + *content_length = wcstol(content_length_string, NULL, 10); + } + return true; +} + +bool WinInetClient::ReadData(HttpHandle request_handle, + void* buffer, + DWORD buffer_length, + DWORD* bytes_read) const { + assert(request_handle); + assert(buffer); + assert(bytes_read); + + DWORD bytes_read_local = 0; + if (!::InternetReadFile(ToHINTERNET(request_handle), + buffer, + buffer_length, + &bytes_read_local)) { + return false; + } + *bytes_read = bytes_read_local; + return true; +} + +bool WinInetClient::Close(HttpHandle handle) const { + assert(handle); + return !!::InternetCloseHandle(ToHINTERNET(handle)); +} + +DWORD WinInetClient::MapAccessType(DWORD access_type) { + switch (static_cast(access_type)) { + case ACCESS_TYPE_PRECONFIG: + default: + return INTERNET_OPEN_TYPE_PRECONFIG; + case ACCESS_TYPE_DIRECT: + return INTERNET_OPEN_TYPE_DIRECT; + case ACCESS_TYPE_PROXY: + return INTERNET_OPEN_TYPE_PROXY; + } +} + +HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) { + return static_cast(handle); +} + +HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) { + return static_cast(handle); +} + +} // namespace internal + +HttpClient* CreateWinInetClient(const TCHAR*) { + return new internal::WinInetClient(); +} + +} // namespace crash diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h new file mode 100644 index 0000000000..bd04b605dc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h @@ -0,0 +1,40 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ +#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ + +#include "tools/windows/converter_exe/http_client.h" + +namespace crash { + +HttpClient* CreateWinInetClient(const TCHAR* url); + +} // namespace crash + +#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd new file mode 100644 index 0000000000..bea84b589f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd @@ -0,0 +1,86 @@ +@if "%ECHOON%"=="" @echo off +SETLOCAL + +REM ****************************************************************** +REM Usage: +REM winsymconv +REM ****************************************************************** + +REM ****************************************************************** +REM Initialize +REM ****************************************************************** +SET SCRIPT_LOCATION=%~dp0 +SET DBGHELP_WINHTTP= +SET USE_WINHTTP= + +REM ****************************************************************** +REM Go to script location +REM ****************************************************************** +pushd %SCRIPT_LOCATION% + +REM ****************************************************************** +REM Make sure the symbol file directory exists +REM ****************************************************************** +SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol +if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR% +if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail + +:restart + +REM ****************************************************************** +REM Convert missing Windows symbols on the staging instance. +REM ****************************************************************** +echo Converting missing Windows symbols on staging instance ... + +google_converter.exe ^ + -n http://msdl.microsoft.com/download/symbols ^ + -n http://symbols.mozilla.org/firefox ^ + -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^ + -n https://download.amd.com/dir/bin ^ + -n https://driver-symbols.nvidia.com ^ + -n https://software.intel.com/sites/downloads/symbols ^ + -l %SYMBOL_DIR% ^ + -s https://clients2.google.com/cr/staging_symbol ^ + -m https://clients2.google.com/cr/staging_symbol/missingsymbols ^ + -t https://clients2.google.com/cr/staging_symbol/fetchfailed ^ + -b "google|chrome|internal|private" ^ + > %SCRIPT_LOCATION%last_cycle_staging.txt + +REM ****************************************************************** +REM Convert missing Windows symbols on the production instance. +REM ****************************************************************** +echo Converting missing Windows symbols on production instance ... + +google_converter.exe ^ + -n http://msdl.microsoft.com/download/symbols ^ + -n http://symbols.mozilla.org/firefox ^ + -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^ + -n https://download.amd.com/dir/bin ^ + -n https://driver-symbols.nvidia.com ^ + -n https://software.intel.com/sites/downloads/symbols ^ + -l %SYMBOL_DIR% ^ + -s https://clients2.google.com/cr/symbol ^ + -m https://clients2.google.com/cr/symbol/missingsymbols ^ + -t https://clients2.google.com/cr/symbol/fetchfailed ^ + -b "google|chrome|internal|private" ^ + > %SCRIPT_LOCATION%last_cycle_prod.txt + +REM ****************************************************************** +REM Sleep for 5 minutes ... +REM ****************************************************************** +echo Sleeping for 5 minutes ... + +%SCRIPT_LOCATION%sleep.exe 300 + +REM ****************************************** +REM Restart work loop ... +REM ****************************************** +goto :restart + +:success +ENDLOCAL +exit /b 0 + +:fail +ENDLOCAL +exit /b 1 diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd new file mode 100644 index 0000000000..c177706608 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd @@ -0,0 +1,72 @@ +@if "%ECHOON%"=="" @echo off +SETLOCAL + +REM ****************************************************************** +REM Usage: +REM winsymconv_test +REM ****************************************************************** + +REM ****************************************************************** +REM Initialize +REM ****************************************************************** +SET SCRIPT_LOCATION=%~dp0 +SET DBGHELP_WINHTTP= +SET USE_WINHTTP= + +REM ****************************************************************** +REM Go to script location +REM ****************************************************************** +pushd %SCRIPT_LOCATION% + +REM ****************************************************************** +REM Make sure the symbol file directory exists +REM ****************************************************************** +SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol +if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR% +if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail + +REM ****************************************************************** +REM Testing on the staging instance. +REM ****************************************************************** +echo Testing on the staging instance ... + +google_converter.exe ^ + -n http://msdl.microsoft.com/download/symbols ^ + -n http://symbols.mozilla.org/firefox ^ + -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^ + -n https://download.amd.com/dir/bin ^ + -n https://driver-symbols.nvidia.com ^ + -n https://software.intel.com/sites/downloads/symbols ^ + -l %SYMBOL_DIR% ^ + -s https://clients2.google.com/cr/staging_symbol ^ + -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^ + -t https://clients2.google.com/cr/staging_symbol/fetchfailed ^ + -b "google|chrome|internal|private" ^ + > %SCRIPT_LOCATION%last_cycle_staging.txt + +REM ****************************************************************** +REM Testing on the production instance. +REM ****************************************************************** +echo Testing on the production instance ... + +google_converter.exe ^ + -n http://msdl.microsoft.com/download/symbols ^ + -n http://symbols.mozilla.org/firefox ^ + -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^ + -n https://download.amd.com/dir/bin ^ + -n https://driver-symbols.nvidia.com ^ + -n https://software.intel.com/sites/downloads/symbols ^ + -l %SYMBOL_DIR% ^ + -s https://clients2.google.com/cr/symbol ^ + -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^ + -t https://clients2.google.com/cr/symbol/fetchfailed ^ + -b "google|chrome|internal|private" ^ + > %SCRIPT_LOCATION%last_cycle_prod.txt + +:success +ENDLOCAL +exit /b 0 + +:fail +ENDLOCAL +exit /b 1 diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..5b7d177753 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc @@ -0,0 +1,73 @@ +// 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. + +// Windows utility to dump the line number data from a pdb file to +// a text-based format that we can use from the minidump processor. + +#include +#include + +#include + +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/pe_source_line_writer.h" + +using std::wstring; +using google_breakpad::PDBSourceLineWriter; +using google_breakpad::PESourceLineWriter; +using std::unique_ptr; + +int wmain(int argc, wchar_t **argv) { + bool success; + if (argc == 2) { + PDBSourceLineWriter pdb_writer; + if (!pdb_writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) { + fprintf(stderr, "Open failed.\n"); + return 1; + } + success = pdb_writer.WriteSymbols(stdout); + } else if (argc == 3 && wcscmp(argv[1], L"--pe") == 0) { + PESourceLineWriter pe_writer(argv[2]); + success = pe_writer.WriteSymbols(stdout); + } else { + fprintf(stderr, "Usage: %ws [--pe] \n", argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "--pe:\tRead debugging information from PE file and do " + "not attempt to locate matching PDB file.\n" + "\tThis is only supported for PE32+ (64 bit) PE files.\n"); + return 1; + } + + if (!success) { + fprintf(stderr, "WriteSymbols failed.\n"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp new file mode 100644 index 0000000000..b815574b29 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp @@ -0,0 +1,64 @@ +# Copyright 2013 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + }, + { + 'target_name': 'dump_syms_unittest', + 'type': 'executable', + 'sources': [ + 'dump_syms_unittest.cc', + ], + 'dependencies': [ + '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', + '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', + 'dump_syms', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalDependencies': [ + 'shell32.lib', + ], + }, + }, + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj new file mode 100644 index 0000000000..2fbe301ed8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc new file mode 100644 index 0000000000..766e5c09d0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -0,0 +1,244 @@ +// Copyright 2003 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 +#include + +#include +#include + +#include "breakpad_googletest_includes.h" + +namespace tools { +namespace windows { +namespace dump_syms { + +namespace { + +// Root names of PDB and dumped symbol files to be regression tested. These are +// specified in complexity of the resulting dumped symbol files. +const wchar_t* kRootNames[] = { + // A PDB file with no OMAP data. + L"dump_syms_regtest", + // A PDB file with OMAP data for an image that has been function-level + // reordered. + L"omap_reorder_funcs", + // A PDB file with OMAP data for an image that had new content injected, all + // of it with source data. + L"omap_stretched_filled", + // A PDB file with OMAP data for an image that had new content injected, but + // without source data. + L"omap_stretched", + // A PDB file with OMAP data for an image that has been basic block reordered. + L"omap_reorder_bbs", + // A 64bit PDB file with no OMAP data. + L"dump_syms_regtest64", +}; + +const wchar_t* kPEOnlyRootNames[] = { + L"pe_only_symbol_test", +}; + +void TrimLastComponent(const std::wstring& path, + std::wstring* trimmed, + std::wstring* component) { + size_t len = path.size(); + while (len > 0 && path[len - 1] != '\\') + --len; + + if (component != NULL) + component->assign(path.c_str() + len, path.c_str() + path.size()); + + while (len > 0 && path[len - 1] == '\\') + --len; + + if (trimmed != NULL) + trimmed->assign(path.c_str(), len); +} + +// Get the directory of the current executable. +bool GetSelfDirectory(std::wstring* self_dir) { + std::wstring command_line = GetCommandLineW(); + + int num_args = 0; + wchar_t** args = NULL; + args = ::CommandLineToArgvW(command_line.c_str(), &num_args); + if (args == NULL) + return false; + + *self_dir = args[0]; + TrimLastComponent(*self_dir, self_dir, NULL); + + return true; +} + +void RunCommand(const std::wstring& command_line, + std::string* stdout_string) { + // Create a PIPE for the child process stdout. + HANDLE child_stdout_read = 0; + HANDLE child_stdout_write = 0; + SECURITY_ATTRIBUTES sec_attr_stdout = {}; + sec_attr_stdout.nLength = sizeof(sec_attr_stdout); + sec_attr_stdout.bInheritHandle = TRUE; + ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write, + &sec_attr_stdout, 0)); + ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT, + 0)); + + // Create a PIPE for the child process stdin. + HANDLE child_stdin_read = 0; + HANDLE child_stdin_write = 0; + SECURITY_ATTRIBUTES sec_attr_stdin = {}; + sec_attr_stdin.nLength = sizeof(sec_attr_stdin); + sec_attr_stdin.bInheritHandle = TRUE; + ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write, + &sec_attr_stdin, 0)); + ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT, + 0)); + + // Startup the child. + STARTUPINFO startup_info = {}; + PROCESS_INFORMATION process_info = {}; + startup_info.cb = sizeof(STARTUPINFO); + startup_info.hStdError = NULL; + startup_info.hStdInput = child_stdin_read; + startup_info.hStdOutput = child_stdout_write; + startup_info.dwFlags = STARTF_USESTDHANDLES; + ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL, + TRUE, 0, NULL, NULL, + &startup_info, &process_info)); + + // Collect the output. + ASSERT_TRUE(::CloseHandle(child_stdout_write)); + char buffer[4096] = {}; + DWORD bytes_read = 0; + while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read, + NULL) && bytes_read > 0) { + stdout_string->append(buffer, bytes_read); + } + + // Wait for the process to finish. + ::WaitForSingleObject(process_info.hProcess, INFINITE); + + // Shut down all of our handles. + ASSERT_TRUE(::CloseHandle(process_info.hThread)); + ASSERT_TRUE(::CloseHandle(process_info.hProcess)); + ASSERT_TRUE(::CloseHandle(child_stdin_write)); + ASSERT_TRUE(::CloseHandle(child_stdin_read)); + ASSERT_TRUE(::CloseHandle(child_stdout_read)); +} + +void GetFileContents(const std::wstring& path, std::string* content) { + FILE* f = ::_wfopen(path.c_str(), L"rb"); + ASSERT_TRUE(f != NULL); + + char buffer[4096] = {}; + while (true) { + size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f); + if (bytes_read == 0) + break; + content->append(buffer, bytes_read); + } +} + +class DumpSymsRegressionTest : public testing::TestWithParam { + public: + virtual void SetUp() { + std::wstring self_dir; + ASSERT_TRUE(GetSelfDirectory(&self_dir)); + dump_syms_exe = self_dir + L"\\dump_syms.exe"; + + TrimLastComponent(self_dir, &testdata_dir, NULL); + testdata_dir += L"\\testdata"; + } + + std::wstring dump_syms_exe; + std::wstring testdata_dir; +}; + +class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam { +public: + virtual void SetUp() { + std::wstring self_dir; + ASSERT_TRUE(GetSelfDirectory(&self_dir)); + dump_syms_exe = self_dir + L"\\dump_syms.exe"; + + TrimLastComponent(self_dir, &testdata_dir, NULL); + testdata_dir += L"\\testdata"; + } + + std::wstring dump_syms_exe; + std::wstring testdata_dir; +}; + +} //namespace + +TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) { + const wchar_t* root_name = GetParam(); + std::wstring root_path = testdata_dir + L"\\" + root_name; + + std::wstring sym_path = root_path + L".sym"; + std::string expected_symbols; + ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols)); + + std::wstring pdb_path = root_path + L".pdb"; + std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" + + pdb_path + L"\""; + std::string symbols; + ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols)); + + EXPECT_EQ(expected_symbols, symbols); +} + +INSTANTIATE_TEST_CASE_P(DumpSyms, DumpSymsRegressionTest, + testing::ValuesIn(kRootNames)); + +TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) { + const wchar_t* root_name = GetParam(); + std::wstring root_path = testdata_dir + L"\\" + root_name; + + std::wstring sym_path = root_path + L".sym"; + std::string expected_symbols; + ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols)); + + std::wstring dll_path = root_path + L".dll"; + std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" + + dll_path + L"\""; + std::string symbols; + ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols)); + + EXPECT_EQ(expected_symbols, symbols); +} + +INSTANTIATE_TEST_CASE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest, + testing::ValuesIn(kPEOnlyRootNames)); + + +} // namespace dump_syms +} // namespace windows +} // namespace tools diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh new file mode 100755 index 0000000000..1f20f64fd5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +# 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. + +Release/dump_syms.exe testdata/dump_syms_regtest.pdb | \ + tr -d '\015' > \ + testdata/dump_syms_regtest.new +status=$? + +if [ $status -ne 0 ] ; then + echo "FAIL, dump_syms.exe failed" + exit $status +fi + +diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \ + testdata/dump_syms_regtest.diff +status=$? + +if [ $status -eq 0 ] ; then + rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new + echo "PASS" +else + echo "FAIL, see testdata/dump_syms_regtest.[new|diff]" +fi + +exit $status diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat b/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat new file mode 100644 index 0000000000..bf18d5079d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat @@ -0,0 +1,23 @@ +REM This batch file is meant to facilitate regenerating prebuilt binaries for +REM the Windows tools. +REM You MUST run it from a Visual Studio xxxx Command Prompt. To do this, +REM navigate to: +REM +REM Start->Programs->Microsoft Visual Studio XXXX->Tools-> +REM Visual Studio Command Prompt +REM +REM Then run this batch file. It performs an SVN update, edits the +REM README.binaries file to contain +REM the revision number, and builds the tools. You must run 'svn commit' to +REM commit the pending edits to the repository. + +pushd %~dp0 +if %VisualStudioVersion% == 14.0 set GYP_MSVS_VERSION=2015 +gyp tools_windows.gyp +msbuild tools_windows.sln /p:Configuration=Release /t:Clean,Build +copy Release\symupload.exe binaries\ +copy Release\dump_syms.exe binaries\ +git add binaries +git commit -m "Built Windows binaries" +echo Done! +popd diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc new file mode 100644 index 0000000000..7e3029326d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc @@ -0,0 +1,394 @@ +// 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. + +// Tool to upload an exe/dll and its associated symbols to an HTTP server. +// The PDB file is located automatically, using the path embedded in the +// executable. The upload is sent as a multipart/form-data POST request, +// with the following parameters: +// code_file: the basename of the module, e.g. "app.exe" +// debug_file: the basename of the debugging file, e.g. "app.pdb" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// product: the HTTP-friendly product name, e.g. "MyApp" +// version: the file version of the module, e.g. "1.2.3.4" +// os: the operating system that the module was built for, always +// "windows" in this implementation. +// cpu: the CPU that the module was built for, typically "x86". +// symbol_file: the contents of the breakpad-format symbol file + +#include +#include +#include + +#include +#include +#include +#include + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/http_upload.h" +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/symbol_collector_client.h" + +using std::string; +using std::wstring; +using std::vector; +using std::map; +using google_breakpad::HTTPUpload; +using google_breakpad::SymbolCollectorClient; +using google_breakpad::SymbolStatus; +using google_breakpad::UploadUrlResponse; +using google_breakpad::CompleteUploadResult; +using google_breakpad::PDBModuleInfo; +using google_breakpad::PDBSourceLineWriter; +using google_breakpad::WindowsStringUtils; + +// Extracts the file version information for the given filename, +// as a string, for example, "1.2.3.4". Returns true on success. +static bool GetFileVersionString(const wchar_t *filename, wstring *version) { + DWORD handle; + DWORD version_size = GetFileVersionInfoSize(filename, &handle); + if (version_size < sizeof(VS_FIXEDFILEINFO)) { + return false; + } + + vector version_info(version_size); + if (!GetFileVersionInfo(filename, handle, version_size, &version_info[0])) { + return false; + } + + void *file_info_buffer = NULL; + unsigned int file_info_length; + if (!VerQueryValue(&version_info[0], L"\\", + &file_info_buffer, &file_info_length)) { + return false; + } + + // The maximum value of each version component is 65535 (0xffff), + // so the max length is 24, including the terminating null. + wchar_t ver_string[24]; + VS_FIXEDFILEINFO *file_info = + reinterpret_cast(file_info_buffer); + swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]), + L"%d.%d.%d.%d", + file_info->dwFileVersionMS >> 16, + file_info->dwFileVersionMS & 0xffff, + file_info->dwFileVersionLS >> 16, + file_info->dwFileVersionLS & 0xffff); + + // remove when VC++7.1 is no longer supported + ver_string[sizeof(ver_string) / sizeof(ver_string[0]) - 1] = L'\0'; + + *version = ver_string; + return true; +} + +// Creates a new temporary file and writes the symbol data from the given +// exe/dll file to it. Returns the path to the temp file in temp_file_path +// and information about the pdb in pdb_info. +static bool DumpSymbolsToTempFile(const wchar_t *file, + wstring *temp_file_path, + PDBModuleInfo *pdb_info) { + google_breakpad::PDBSourceLineWriter writer; + // Use EXE_FILE to get information out of the exe/dll in addition to the + // pdb. The name and version number of the exe/dll are of value, and + // there's no way to locate an exe/dll given a pdb. + if (!writer.Open(file, PDBSourceLineWriter::EXE_FILE)) { + return false; + } + + wchar_t temp_path[_MAX_PATH]; + if (GetTempPath(_MAX_PATH, temp_path) == 0) { + return false; + } + + wchar_t temp_filename[_MAX_PATH]; + if (GetTempFileName(temp_path, L"sym", 0, temp_filename) == 0) { + return false; + } + + FILE *temp_file = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) +#else // _MSC_VER >= 1400 + // _wfopen_s was introduced in MSVC8. Use _wfopen for earlier environments. + // Don't use it with MSVC8 and later, because it's deprecated. + if (!(temp_file = _wfopen(temp_filename, L"w"))) +#endif // _MSC_VER >= 1400 + { + return false; + } + + bool success = writer.WriteSymbols(temp_file); + fclose(temp_file); + if (!success) { + _wunlink(temp_filename); + return false; + } + + *temp_file_path = temp_filename; + + return writer.GetModuleInfo(pdb_info); +} + +static bool DoSymUploadV2( + const wchar_t* api_url, + const wchar_t* api_key, + const wstring& debug_file, + const wstring& debug_id, + const wstring& symbol_file, + bool force) { + wstring url(api_url); + wstring key(api_key); + + if (!force) { + SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( + url, + key, + debug_file, + debug_id); + if (symbolStatus == SymbolStatus::Found) { + wprintf(L"Symbol file already exists, upload aborted." + L" Use \"-f\" to overwrite.\n"); + return true; + } + else if (symbolStatus == SymbolStatus::Unknown) { + wprintf(L"Failed to get check for existing symbol.\n"); + return false; + } + } + + UploadUrlResponse uploadUrlResponse; + if (!SymbolCollectorClient::CreateUploadUrl( + url, + key, + &uploadUrlResponse)) { + wprintf(L"Failed to create upload URL.\n"); + return false; + } + + wstring signed_url = uploadUrlResponse.upload_url; + wstring upload_key = uploadUrlResponse.upload_key; + wstring response; + int response_code; + bool success = HTTPUpload::SendPutRequest( + signed_url, + symbol_file, + /* timeout = */ NULL, + &response, + &response_code); + if (!success) { + wprintf(L"Failed to send symbol file.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + else if (response_code == 0) { + wprintf(L"Failed to send symbol file: No response code\n"); + return false; + } + else if (response_code != 200) { + wprintf(L"Failed to send symbol file: Response code %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + + CompleteUploadResult completeUploadResult = + SymbolCollectorClient::CompleteUpload( + url, + key, + upload_key, + debug_file, + debug_id); + if (completeUploadResult == CompleteUploadResult::Error) { + wprintf(L"Failed to complete upload.\n"); + return false; + } + else if (completeUploadResult == CompleteUploadResult::DuplicateData) { + wprintf(L"Uploaded file checksum matched existing file checksum," + L" no change necessary.\n"); + } + else { + wprintf(L"Successfully sent the symbol file.\n"); + } + + return true; +} + +__declspec(noreturn) void printUsageAndExit() { + wprintf(L"Usage:\n\n" + L" symupload [--timeout NN] [--product product_name] ^\n" + L" ^\n" + L" [...]\n\n"); + wprintf(L" - Timeout is in milliseconds, or can be 0 to be unlimited.\n"); + wprintf(L" - product_name is an HTTP-friendly product name. It must only\n" + L" contain an ascii subset: alphanumeric and punctuation.\n" + L" This string is case-sensitive.\n\n"); + wprintf(L"Example:\n\n" + L" symupload.exe --timeout 0 --product Chrome ^\n" + L" chrome.dll http://no.free.symbol.server.for.you\n"); + wprintf(L"\n"); + wprintf(L"sym-upload-v2 usage:\n" + L" symupload -p [-f] \n"); + wprintf(L"\n"); + wprintf(L"sym_upload_v2 Options:\n"); + wprintf(L" is the sym_upload_v2 API URL.\n"); + wprintf(L" is a secret used to authenticate with the API.\n"); + wprintf(L" -p:\t Use sym_upload_v2 protocol.\n"); + wprintf(L" -f:\t Force symbol upload if already exists.\n"); + + exit(0); +} + +int wmain(int argc, wchar_t *argv[]) { + const wchar_t *module; + const wchar_t *product = nullptr; + int timeout = -1; + int currentarg = 1; + bool use_sym_upload_v2 = false; + bool force = false; + const wchar_t* api_url = nullptr; + const wchar_t* api_key = nullptr; + while (argc > currentarg + 1) { + if (!wcscmp(L"--timeout", argv[currentarg])) { + timeout = _wtoi(argv[currentarg + 1]); + currentarg += 2; + continue; + } + if (!wcscmp(L"--product", argv[currentarg])) { + product = argv[currentarg + 1]; + currentarg += 2; + continue; + } + if (!wcscmp(L"-p", argv[currentarg])) { + use_sym_upload_v2 = true; + ++currentarg; + continue; + } + if (!wcscmp(L"-f", argv[currentarg])) { + force = true; + ++currentarg; + continue; + } + break; + } + + if (argc >= currentarg + 2) + module = argv[currentarg++]; + else + printUsageAndExit(); + + wstring symbol_file; + PDBModuleInfo pdb_info; + if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info)) { + fwprintf(stderr, L"Could not get symbol data from %s\n", module); + return 1; + } + + wstring code_file = WindowsStringUtils::GetBaseName(wstring(module)); + wstring file_version; + // Don't make a missing version a hard error. Issue a warning, and let the + // server decide whether to reject files without versions. + if (!GetFileVersionString(module, &file_version)) { + fwprintf(stderr, L"Warning: Could not get file version for %s\n", module); + } + + bool success = true; + + if (use_sym_upload_v2) { + if (argc >= currentarg + 2) { + api_url = argv[currentarg++]; + api_key = argv[currentarg++]; + + success = DoSymUploadV2( + api_url, + api_key, + pdb_info.debug_file, + pdb_info.debug_identifier, + symbol_file, + force); + } else { + printUsageAndExit(); + } + } else { + map parameters; + parameters[L"code_file"] = code_file; + parameters[L"debug_file"] = pdb_info.debug_file; + parameters[L"debug_identifier"] = pdb_info.debug_identifier; + parameters[L"os"] = L"windows"; // This version of symupload is Windows-only + parameters[L"cpu"] = pdb_info.cpu; + + map files; + files[L"symbol_file"] = symbol_file; + + if (!file_version.empty()) { + parameters[L"version"] = file_version; + } + + // Don't make a missing product name a hard error. Issue a warning and let + // the server decide whether to reject files without product name. + if (product) { + parameters[L"product"] = product; + } + else { + fwprintf( + stderr, + L"Warning: No product name (flag --product) was specified for %s\n", + module); + } + + while (currentarg < argc) { + int response_code; + if (!HTTPUpload::SendMultipartPostRequest(argv[currentarg], parameters, files, + timeout == -1 ? NULL : &timeout, + nullptr, &response_code)) { + success = false; + fwprintf(stderr, + L"Symbol file upload to %s failed. Response code = %ld\n", + argv[currentarg], response_code); + } + currentarg++; + } + } + + _wunlink(symbol_file.c_str()); + + if (success) { + wprintf(L"Uploaded breakpad symbols for windows-%s/%s/%s (%s %s)\n", + pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(), + pdb_info.debug_identifier.c_str(), code_file.c_str(), + file_version.c_str()); + } + + return success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp new file mode 100644 index 0000000000..4567a4bdfd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp @@ -0,0 +1,50 @@ +# Copyright 2013 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'LargeAddressAware': '2', + }, + }, + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp new file mode 100644 index 0000000000..17b88b4a7a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp @@ -0,0 +1,46 @@ +# Copyright 2017 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. + + +{ + 'includes': [ + '../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'build_all', + 'type': 'none', + 'dependencies': [ + './converter/ms_symbol_server_converter.gyp:*', + './converter_exe/converter.gyp:*', + './dump_syms/dump_syms.gyp:*', + './symupload/symupload.gyp:*', + ], + }, + ], +} diff --git a/toolkit/crashreporter/injector/injector.cpp b/toolkit/crashreporter/injector/injector.cpp new file mode 100644 index 0000000000..7fda400410 --- /dev/null +++ b/toolkit/crashreporter/injector/injector.cpp @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "windows/handler/exception_handler.h" + +using google_breakpad::ExceptionHandler; +using std::wstring; + +extern "C" BOOL WINAPI DummyEntryPoint(HINSTANCE instance, DWORD reason, + void* reserved) { + __debugbreak(); + + return FALSE; // We're being loaded remotely, this shouldn't happen! +} + +// support.microsoft.com/kb/94248 +extern "C" BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, + LPVOID lpReserved); + +extern "C" __declspec(dllexport) DWORD Start(void* context) { + // Because the remote DLL injector does not call DllMain, we have to + // initialize the CRT manually + _CRT_INIT(nullptr, DLL_PROCESS_ATTACH, nullptr); + + HANDLE hCrashPipe = reinterpret_cast(context); + + ExceptionHandler* e = new (std::nothrow) ExceptionHandler( + wstring(), nullptr, nullptr, nullptr, ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, hCrashPipe, nullptr); + if (e) e->set_handle_debug_exceptions(true); + return 1; +} diff --git a/toolkit/crashreporter/injector/moz.build b/toolkit/crashreporter/injector/moz.build new file mode 100644 index 0000000000..05aa9af37d --- /dev/null +++ b/toolkit/crashreporter/injector/moz.build @@ -0,0 +1,27 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SOURCES += [ + "injector.cpp", +] + +SharedLibrary("breakpadinjector") + +include("/ipc/chromium/chromium-config.mozbuild") + +LOCAL_INCLUDES += [ + "/toolkit/crashreporter/breakpad-client", + "/toolkit/crashreporter/google-breakpad/src", +] + +USE_STATIC_LIBS = True + +if CONFIG["CC_TYPE"] in ("clang", "gcc"): + LDFLAGS += ["-Wl,-e,_DummyEntryPoint@12"] +else: + LDFLAGS += ["-ENTRY:DummyEntryPoint"] + +DisableStlWrapping() diff --git a/toolkit/crashreporter/jar.mn b/toolkit/crashreporter/jar.mn new file mode 100644 index 0000000000..641fcaa2fe --- /dev/null +++ b/toolkit/crashreporter/jar.mn @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +toolkit.jar: +#ifdef MOZ_CRASHREPORTER + content/global/crashes.html (content/crashes.html) + content/global/crashes.js (content/crashes.js) + content/global/crashes.css (content/crashes.css) +#endif diff --git a/toolkit/crashreporter/mac_utils.h b/toolkit/crashreporter/mac_utils.h new file mode 100644 index 0000000000..839baad558 --- /dev/null +++ b/toolkit/crashreporter/mac_utils.h @@ -0,0 +1,14 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef toolkit_breakpad_mac_utils_h__ +#define toolkit_breakpad_mac_utils_h__ + +#include "nsString.h" + +// Given an Objective-C NSException object, put exception info into a string. +void GetObjCExceptionInfo(void* inException, nsACString& outString); + +#endif /* toolkit_breakpad_mac_utils_h__ */ diff --git a/toolkit/crashreporter/mac_utils.mm b/toolkit/crashreporter/mac_utils.mm new file mode 100644 index 0000000000..dfceb1013f --- /dev/null +++ b/toolkit/crashreporter/mac_utils.mm @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "mac_utils.h" +#include "nsXPCOM.h" +#include "mozilla/MacStringHelpers.h" +#include "mozilla/Unused.h" + +void GetObjCExceptionInfo(void* inException, nsACString& outString) { + NSException* e = (NSException*)inException; + + NSString* name = [e name]; + NSString* reason = [e reason]; + NSArray* stackAddresses = [e callStackReturnAddresses]; + + outString.AssignLiteral("\nObj-C Exception data:\n"); + outString.Append([name UTF8String]); + outString.AppendLiteral(": "); + outString.Append([reason UTF8String]); + outString.AppendLiteral("\n\nThrown at stack:\n"); + for (NSNumber* address in stackAddresses) { + outString.AppendPrintf("0x%lx\n", [address unsignedIntegerValue]); + } + outString.AppendLiteral("\n"); +} diff --git a/toolkit/crashreporter/minidump-analyzer/MinidumpAnalyzerUtils.h b/toolkit/crashreporter/minidump-analyzer/MinidumpAnalyzerUtils.h new file mode 100644 index 0000000000..2fb8319be8 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/MinidumpAnalyzerUtils.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MinidumpAnalyzerUtils_h +#define MinidumpAnalyzerUtils_h + +#ifdef XP_WIN +# include +#endif + +#include +#include +#include +#include + +namespace CrashReporter { + +struct MinidumpAnalyzerOptions { + bool fullMinidump; + std::string forceUseModule; +}; + +extern MinidumpAnalyzerOptions gMinidumpAnalyzerOptions; + +#ifdef XP_WIN + +static inline std::string WideToMBCP(const std::wstring& wide, unsigned int cp, + bool* success = nullptr) { + int bufferCharLen = WideCharToMultiByte(cp, 0, wide.c_str(), wide.length(), + nullptr, 0, nullptr, nullptr); + if (!bufferCharLen) { + if (success) { + *success = false; + } + + return ""; + } + + auto buffer = std::make_unique(bufferCharLen); + if (!buffer) { + if (success) { + *success = false; + } + + return ""; + } + + int result = + WideCharToMultiByte(cp, 0, wide.c_str(), wide.length(), buffer.get(), + bufferCharLen, nullptr, nullptr); + if (success) { + *success = result > 0; + } + + return std::string(buffer.get(), result); +} + +static inline std::wstring MBCPToWide(const std::string& aMbStr, + unsigned int aCodepage, + bool* aSuccess = nullptr) { + int bufferCharLen = MultiByteToWideChar(aCodepage, 0, aMbStr.c_str(), + aMbStr.length(), nullptr, 0); + if (!bufferCharLen) { + if (aSuccess) { + *aSuccess = false; + } + + return L""; + } + + auto buffer = std::make_unique(bufferCharLen); + if (!buffer) { + if (aSuccess) { + *aSuccess = false; + } + + return L""; + } + + int result = + MultiByteToWideChar(aCodepage, 0, aMbStr.c_str(), aMbStr.length(), + buffer.get(), bufferCharLen); + if (aSuccess) { + *aSuccess = result > 0; + } + + return std::wstring(buffer.get(), result); +} + +static inline std::string WideToUTF8(const std::wstring& aWide, + bool* aSuccess = nullptr) { + return WideToMBCP(aWide, CP_UTF8, aSuccess); +} + +static inline std::wstring UTF8ToWide(const std::string& aUtf8Str, + bool* aSuccess = nullptr) { + return MBCPToWide(aUtf8Str, CP_UTF8, aSuccess); +} + +static inline std::string WideToMBCS(const std::wstring& aWide, + bool* aSuccess = nullptr) { + return WideToMBCP(aWide, CP_ACP, aSuccess); +} + +static inline std::string UTF8ToMBCS(const std::string& aUtf8) { + return WideToMBCS(UTF8ToWide(aUtf8)); +} + +#endif // XP_WIN + +} // namespace CrashReporter + +#endif // MinidumpAnalyzerUtils_h diff --git a/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.cpp b/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.cpp new file mode 100644 index 0000000000..7d7e3c4b2f --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.cpp @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if XP_WIN && HAVE_64BIT_BUILD + +# include "MozStackFrameSymbolizer.h" + +# include "MinidumpAnalyzerUtils.h" + +# include "processor/cfi_frame_info.h" + +# include +# include + +namespace CrashReporter { + +extern MinidumpAnalyzerOptions gMinidumpAnalyzerOptions; + +using google_breakpad::CFIFrameInfo; + +MozStackFrameSymbolizer::MozStackFrameSymbolizer() + : StackFrameSymbolizer(nullptr, nullptr) {} + +MozStackFrameSymbolizer::SymbolizerResult +MozStackFrameSymbolizer::FillSourceLineInfo(const CodeModules* modules, + const CodeModules* unloaded_modules, + const SystemInfo* system_info, + StackFrame* stack_frame) { + SymbolizerResult ret = StackFrameSymbolizer::FillSourceLineInfo( + modules, unloaded_modules, system_info, stack_frame); + + if (ret == kNoError && this->HasImplementation() && + stack_frame->function_name.empty()) { + // Breakpad's Stackwalker::InstructionAddressSeemsValid only considers an + // address valid if it has associated symbols. + // + // This makes sense for complete & accurate symbols, but ours may be + // incomplete or wrong. Returning a function name tells Breakpad we + // recognize this address as code, so it's OK to use in stack scanning. + // This function is only called with addresses that land in this module. + // + // This allows us to fall back to stack scanning in the case where we were + // unable to provide CFI. + stack_frame->function_name = ""; + } + return ret; +} + +CFIFrameInfo* MozStackFrameSymbolizer::FindCFIFrameInfo( + const StackFrame* frame) { + std::string modulePath; + + // For unit testing, support loading a specified module instead of + // the real one. + bool moduleHasBeenReplaced = false; + if (gMinidumpAnalyzerOptions.forceUseModule.size() > 0) { + modulePath = gMinidumpAnalyzerOptions.forceUseModule; + moduleHasBeenReplaced = true; + } else { + if (!frame->module) { + return nullptr; + } + modulePath = frame->module->code_file(); + } + + // Get/create the unwind parser. + auto itMod = mModuleMap.find(modulePath); + std::shared_ptr unwindParser; + if (itMod != mModuleMap.end()) { + unwindParser = itMod->second; + } else { + unwindParser.reset(new ModuleUnwindParser(modulePath)); + mModuleMap[modulePath] = unwindParser; + } + + UnwindCFI cfi; + DWORD offsetAddr; + + if (moduleHasBeenReplaced) { + // If we are replacing a module, addresses will never line up. + // So just act like the 1st entry is correct. + offsetAddr = unwindParser->GetAnyOffsetAddr(); + } else { + offsetAddr = frame->instruction - frame->module->base_address(); + } + + if (!unwindParser->GetCFI(offsetAddr, cfi)) { + return nullptr; + } + + std::unique_ptr rules(new CFIFrameInfo()); + + static const size_t exprSize = 50; + char expr[exprSize]; + if (cfi.stackSize == 0) { + snprintf(expr, exprSize, "$rsp"); + } else { + snprintf(expr, exprSize, "$rsp %d +", cfi.stackSize); + } + rules->SetCFARule(expr); + + if (cfi.ripOffset == 0) { + snprintf(expr, exprSize, ".cfa ^"); + } else { + snprintf(expr, exprSize, ".cfa %d - ^", cfi.ripOffset); + } + rules->SetRARule(expr); + + return rules.release(); +} + +} // namespace CrashReporter + +#endif // XP_WIN && HAVE_64BIT_BUILD diff --git a/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.h b/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.h new file mode 100644 index 0000000000..dfe4299d85 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/MozStackFrameSymbolizer.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MozStackFrameSymbolizer_h +#define MozStackFrameSymbolizer_h + +#if XP_WIN && HAVE_64BIT_BUILD + +# include "Win64ModuleUnwindMetadata.h" + +# include "google_breakpad/processor/stack_frame_symbolizer.h" +# include "google_breakpad/processor/stack_frame.h" + +# include + +namespace CrashReporter { + +using google_breakpad::CodeModule; +using google_breakpad::CodeModules; +using google_breakpad::SourceLineResolverInterface; +using google_breakpad::StackFrame; +using google_breakpad::StackFrameSymbolizer; +using google_breakpad::SymbolSupplier; +using google_breakpad::SystemInfo; + +class MozStackFrameSymbolizer : public StackFrameSymbolizer { + using google_breakpad::StackFrameSymbolizer::SymbolizerResult; + + std::map> mModuleMap; + + public: + MozStackFrameSymbolizer(); + + virtual SymbolizerResult FillSourceLineInfo( + const CodeModules* modules, const CodeModules* unloaded_modules, + const SystemInfo* system_info, StackFrame* stack_frame); + + virtual class google_breakpad::CFIFrameInfo* FindCFIFrameInfo( + const StackFrame* frame); +}; + +} // namespace CrashReporter + +#endif // XP_WIN && HAVE_64BIT_BUILD + +#endif // MozStackFrameSymbolizer_h diff --git a/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.cpp b/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.cpp new file mode 100644 index 0000000000..efe67aa021 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if XP_WIN && HAVE_64BIT_BUILD + +# include "Win64ModuleUnwindMetadata.h" + +# include "MinidumpAnalyzerUtils.h" + +# include +# include +# include +# include +# include +# include + +# include "mozilla/WindowsUnwindInfo.h" + +using namespace mozilla; + +namespace CrashReporter { + +ModuleUnwindParser::~ModuleUnwindParser() { + if (mImg) { + ImageUnload(mImg); + } +} + +void* ModuleUnwindParser::RvaToVa(ULONG aRva) { + return ImageRvaToVa(mImg->FileHeader, mImg->MappedAddress, aRva, + &mImg->LastRvaSection); +} + +ModuleUnwindParser::ModuleUnwindParser(const std::string& aPath) + : mPath(aPath) { + // Convert wchar to native charset because ImageLoad only takes + // a PSTR as input. + std::string code_file = UTF8ToMBCS(aPath); + + mImg = ImageLoad((PSTR)code_file.c_str(), NULL); + if (!mImg || !mImg->FileHeader) { + return; + } + + PIMAGE_OPTIONAL_HEADER64 optional_header = &mImg->FileHeader->OptionalHeader; + if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + return; + } + + DWORD exception_rva = + optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] + .VirtualAddress; + + DWORD exception_size = + optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; + + auto funcs = (PIMAGE_RUNTIME_FUNCTION_ENTRY)RvaToVa(exception_rva); + if (!funcs) { + return; + } + + for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) { + mUnwindMap[funcs[i].BeginAddress] = &funcs[i]; + } +} + +bool ModuleUnwindParser::GenerateCFIForFunction( + IMAGE_RUNTIME_FUNCTION_ENTRY& aFunc, UnwindCFI& aRet) { + DWORD unwind_rva = aFunc.UnwindInfoAddress; + // Holds RVA to all visited IMAGE_RUNTIME_FUNCTION_ENTRY, to avoid + // circular references. + std::set visited; + + // Follow chained function entries + while (unwind_rva & 0x1) { + unwind_rva ^= 0x1; + + if (visited.end() != visited.find(unwind_rva)) { + return false; + } + visited.insert(unwind_rva); + + auto chained_func = (PIMAGE_RUNTIME_FUNCTION_ENTRY)RvaToVa(unwind_rva); + if (!chained_func) { + return false; + } + unwind_rva = chained_func->UnwindInfoAddress; + } + + visited.insert(unwind_rva); + + auto unwind_info = (UnwindInfo*)RvaToVa(unwind_rva); + if (!unwind_info) { + return false; + } + + DWORD stack_size = 8; // minimal stack size is 8 for RIP + DWORD rip_offset = 8; + do { + for (uint8_t c = 0; c < unwind_info->count_of_codes; c++) { + UnwindCode* unwind_code = &unwind_info->unwind_code[c]; + switch (unwind_code->unwind_operation_code) { + case UWOP_PUSH_NONVOL: { + stack_size += 8; + break; + } + case UWOP_ALLOC_LARGE: { + if (unwind_code->operation_info == 0) { + c++; + if (c < unwind_info->count_of_codes) { + stack_size += (unwind_code + 1)->frame_offset * 8; + } + } else { + c += 2; + if (c < unwind_info->count_of_codes) { + stack_size += (unwind_code + 1)->frame_offset | + ((unwind_code + 2)->frame_offset << 16); + } + } + break; + } + case UWOP_ALLOC_SMALL: { + stack_size += unwind_code->operation_info * 8 + 8; + break; + } + case UWOP_SET_FPREG: + // To correctly track RSP when it's been transferred to another + // register, we would need to emit CFI records for every unwind op. + // For simplicity, don't emit CFI records for this function as + // we know it will be incorrect after this point. + return false; + case UWOP_SAVE_NONVOL: + case UWOP_SAVE_XMM: // also v2 UWOP_EPILOG + case UWOP_SAVE_XMM128: { + c++; // skip slot with offset + break; + } + case UWOP_SAVE_NONVOL_FAR: + case UWOP_SAVE_XMM_FAR: // also v2 UWOP_SPARE + case UWOP_SAVE_XMM128_FAR: { + c += 2; // skip 2 slots with offset + break; + } + case UWOP_PUSH_MACHFRAME: { + if (unwind_code->operation_info) { + stack_size += 88; + } else { + stack_size += 80; + } + rip_offset += 80; + break; + } + default: { + return false; + } + } + } + + if (unwind_info->flags & UNW_FLAG_CHAININFO) { + auto chained_func = (PIMAGE_RUNTIME_FUNCTION_ENTRY)(( + unwind_info->unwind_code + ((unwind_info->count_of_codes + 1) & ~1))); + + if (visited.end() != visited.find(chained_func->UnwindInfoAddress)) { + return false; // Circular reference + } + + visited.insert(chained_func->UnwindInfoAddress); + + unwind_info = (UnwindInfo*)RvaToVa(chained_func->UnwindInfoAddress); + } else { + unwind_info = nullptr; + } + } while (unwind_info); + + aRet.beginAddress = aFunc.BeginAddress; + aRet.size = aFunc.EndAddress - aFunc.BeginAddress; + aRet.stackSize = stack_size; + aRet.ripOffset = rip_offset; + return true; +} + +// For unit testing we sometimes need any address that's valid in this module. +// Just return the first address we know of. +DWORD +ModuleUnwindParser::GetAnyOffsetAddr() const { + if (mUnwindMap.size() < 1) { + return 0; + } + return mUnwindMap.begin()->first; +} + +bool ModuleUnwindParser::GetCFI(DWORD aAddress, UnwindCFI& aRet) { + // Figure out the begin address of the requested address. + auto itUW = mUnwindMap.lower_bound(aAddress + 1); + if (itUW == mUnwindMap.begin()) { + return false; // address before this module. + } + --itUW; + + // Ensure that the function entry is big enough to contain this address. + IMAGE_RUNTIME_FUNCTION_ENTRY& func = *itUW->second; + if (aAddress > func.EndAddress) { + return false; + } + + // Do we have CFI for this function already? + auto itCFI = mCFIMap.find(aAddress); + if (itCFI != mCFIMap.end()) { + aRet = itCFI->second; + return true; + } + + // No, generate it. + if (!GenerateCFIForFunction(func, aRet)) { + return false; + } + + mCFIMap[func.BeginAddress] = aRet; + return true; +} + +} // namespace CrashReporter + +#endif // XP_WIN && HAVE_64BIT_BUILD diff --git a/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.h b/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.h new file mode 100644 index 0000000000..3ce9dd7bb4 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/Win64ModuleUnwindMetadata.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef Win64ModuleUnwindMetadata_h +#define Win64ModuleUnwindMetadata_h + +#if XP_WIN && HAVE_64BIT_BUILD + +# include +# include +# include + +# include +# include +# include + +namespace CrashReporter { + +struct UnwindCFI { + uint32_t beginAddress; + uint32_t size; + uint32_t stackSize; + uint32_t ripOffset; +}; + +// Does lazy-parsing of unwind info. +class ModuleUnwindParser { + PLOADED_IMAGE mImg; + std::string mPath; + + // Maps begin address to exception record. + // Populated upon construction. + std::map mUnwindMap; + + // Maps begin address to CFI. + // Populated as needed. + std::map mCFIMap; + + bool GenerateCFIForFunction(IMAGE_RUNTIME_FUNCTION_ENTRY& aFunc, + UnwindCFI& aRet); + void* RvaToVa(ULONG aRva); + + public: + explicit ModuleUnwindParser(const std::string& aPath); + ~ModuleUnwindParser(); + bool GetCFI(DWORD aAddress, UnwindCFI& aRet); + DWORD GetAnyOffsetAddr() const; +}; + +} // namespace CrashReporter + +#endif // XP_WIN && HAVE_64BIT_BUILD + +#endif // Win64ModuleUnwindMetadata_h diff --git a/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp new file mode 100644 index 0000000000..66d71e3984 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.cpp @@ -0,0 +1,603 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include +#include + +#include "json/json.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame.h" +#include "processor/pathname_stripper.h" + +#include "mozilla/FStream.h" +#include "mozilla/Unused.h" + +#if defined(XP_WIN) + +# include +# include "mozilla/glue/WindowsDllServices.h" + +#elif defined(XP_UNIX) || defined(XP_MACOSX) + +# include +# include +# include + +#endif + +#include "MinidumpAnalyzerUtils.h" + +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) +# include "MozStackFrameSymbolizer.h" +#endif + +namespace CrashReporter { + +#if defined(XP_WIN) + +static mozilla::glue::BasicDllServices gDllServices; + +#endif + +using std::hex; +using std::ios; +using std::ios_base; +using std::map; +using std::showbase; +using std::string; +using std::stringstream; +using std::wstring; + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::CodeModules; +using google_breakpad::Minidump; +using google_breakpad::MinidumpProcessor; +using google_breakpad::PathnameStripper; +using google_breakpad::ProcessResult; +using google_breakpad::ProcessState; +using google_breakpad::StackFrame; + +using mozilla::IFStream; +using mozilla::OFStream; +using mozilla::Unused; + +MinidumpAnalyzerOptions gMinidumpAnalyzerOptions; + +// Path of the minidump to be analyzed. +static string gMinidumpPath; + +struct ModuleCompare { + bool operator()(const CodeModule* aLhs, const CodeModule* aRhs) const { + return aLhs->base_address() < aRhs->base_address(); + } +}; + +typedef map OrderedModulesMap; + +static void AddModulesFromCallStack(OrderedModulesMap& aOrderedModules, + const CallStack* aStack) { + int frameCount = aStack->frames()->size(); + + for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + const StackFrame* frame = aStack->frames()->at(frameIndex); + + if (frame->module) { + aOrderedModules.insert( + std::pair(frame->module, 0)); + } + } +} + +static void PopulateModuleList(const ProcessState& aProcessState, + OrderedModulesMap& aOrderedModules, + bool aFullStacks) { + int threadCount = aProcessState.threads()->size(); + int requestingThread = aProcessState.requesting_thread(); + + if (!aFullStacks && (requestingThread != -1)) { + AddModulesFromCallStack(aOrderedModules, + aProcessState.threads()->at(requestingThread)); + } else { + for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) { + AddModulesFromCallStack(aOrderedModules, + aProcessState.threads()->at(threadIndex)); + } + } + + int moduleCount = 0; + for (auto& itr : aOrderedModules) { + itr.second = moduleCount++; + } +} + +static const char kExtraDataExtension[] = ".extra"; + +static string ToHex(uint64_t aValue) { + stringstream output; + + output << hex << showbase << aValue; + + return output.str(); +} + +// Convert the stack frame trust value into a readable string. + +static string FrameTrust(const StackFrame::FrameTrust aTrust) { + switch (aTrust) { + case StackFrame::FRAME_TRUST_NONE: + return "none"; + case StackFrame::FRAME_TRUST_SCAN: + return "scan"; + case StackFrame::FRAME_TRUST_CFI_SCAN: + return "cfi_scan"; + case StackFrame::FRAME_TRUST_FP: + return "frame_pointer"; + case StackFrame::FRAME_TRUST_CFI: + return "cfi"; + case StackFrame::FRAME_TRUST_PREWALKED: + return "prewalked"; + case StackFrame::FRAME_TRUST_CONTEXT: + return "context"; + } + + return "none"; +} + +// Convert the result value of the minidump processing step into a readable +// string. + +static string ResultString(ProcessResult aResult) { + switch (aResult) { + case google_breakpad::PROCESS_OK: + return "OK"; + case google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND: + return "ERROR_MINIDUMP_NOT_FOUND"; + case google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER: + return "ERROR_NO_MINIDUMP_HEADER"; + case google_breakpad::PROCESS_ERROR_NO_THREAD_LIST: + return "ERROR_NO_THREAD_LIST"; + case google_breakpad::PROCESS_ERROR_GETTING_THREAD: + return "ERROR_GETTING_THREAD"; + case google_breakpad::PROCESS_ERROR_GETTING_THREAD_ID: + return "ERROR_GETTING_THREAD_ID"; + case google_breakpad::PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS: + return "ERROR_DUPLICATE_REQUESTING_THREADS"; + case google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED: + return "SYMBOL_SUPPLIER_INTERRUPTED"; + default: + return ""; + } +} + +// Convert the list of stack frames to JSON and append them to the array +// specified in the |aNode| parameter. + +static void ConvertStackToJSON(const ProcessState& aProcessState, + const OrderedModulesMap& aOrderedModules, + const CallStack* aStack, Json::Value& aNode) { + int frameCount = aStack->frames()->size(); + + for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + const StackFrame* frame = aStack->frames()->at(frameIndex); + Json::Value frameNode; + + if (frame->module) { + const auto& itr = aOrderedModules.find(frame->module); + + if (itr != aOrderedModules.end()) { + frameNode["module_index"] = (*itr).second; + } + } + + frameNode["trust"] = FrameTrust(frame->trust); + // The 'ip' field is equivalent to socorro's 'offset' field + frameNode["ip"] = ToHex(frame->instruction); + + aNode.append(frameNode); + } +} + +// Extract the list of certifications subjects from the list of modules and +// store it in the |aCertSubjects| parameter + +static void RetrieveCertSubjects(const CodeModules* modules, + Json::Value& aCertSubjects) { +#if defined(XP_WIN) + if (modules) { + for (size_t i = 0; i < modules->module_count(); i++) { + const CodeModule* module = modules->GetModuleAtIndex(i); + auto certSubject = gDllServices.GetBinaryOrgName( + UTF8ToWide(module->code_file()).c_str()); + if (certSubject) { + string strSubject(WideToUTF8(certSubject.get())); + // Json::Value::operator[] creates and returns a null member if the key + // does not exist. + Json::Value& subjectNode = aCertSubjects[strSubject]; + if (!subjectNode) { + // If the member is null, we want to convert that to an array. + subjectNode = Json::Value(Json::arrayValue); + } + + // Now we're guaranteed that subjectNode is an array. Add the new entry. + subjectNode.append(PathnameStripper::File(module->code_file())); + } + } + } +#endif // defined(XP_WIN) +} + +// Convert the list of modules to JSON and append them to the array specified +// in the |aNode| parameter. + +static int ConvertModulesToJSON(const ProcessState& aProcessState, + const OrderedModulesMap& aOrderedModules, + Json::Value& aNode) { + const CodeModules* modules = aProcessState.modules(); + + if (!modules) { + return -1; + } + + uint64_t mainAddress = 0; + const CodeModule* mainModule = modules->GetMainModule(); + + if (mainModule) { + mainAddress = mainModule->base_address(); + } + + int mainModuleIndex = -1; + + for (const auto& itr : aOrderedModules) { + const CodeModule* module = itr.first; + + if ((module->base_address() == mainAddress) && mainModule) { + mainModuleIndex = itr.second; + } + + Json::Value moduleNode; + moduleNode["filename"] = PathnameStripper::File(module->code_file()); + moduleNode["code_id"] = PathnameStripper::File(module->code_identifier()); + moduleNode["version"] = module->version(); + moduleNode["debug_file"] = PathnameStripper::File(module->debug_file()); + moduleNode["debug_id"] = module->debug_identifier(); + moduleNode["base_addr"] = ToHex(module->base_address()); + moduleNode["end_addr"] = ToHex(module->base_address() + module->size()); + + aNode.append(moduleNode); + } + + return mainModuleIndex; +} + +// Convert the list of unloaded modules to JSON and append them to the array +// specified in the |aNode| parameter. Return the number of unloaded modules +// that were found. + +static size_t ConvertUnloadedModulesToJSON(const ProcessState& aProcessState, + Json::Value& aNode) { + const CodeModules* unloadedModules = aProcessState.unloaded_modules(); + if (!unloadedModules) { + return 0; + } + + const size_t unloadedModulesLen = unloadedModules->module_count(); + for (size_t i = 0; i < unloadedModulesLen; i++) { + const CodeModule* unloadedModule = unloadedModules->GetModuleAtIndex(i); + + Json::Value unloadedModuleNode; + unloadedModuleNode["filename"] = + PathnameStripper::File(unloadedModule->code_file()); + unloadedModuleNode["code_id"] = + PathnameStripper::File(unloadedModule->code_identifier()); + unloadedModuleNode["base_addr"] = ToHex(unloadedModule->base_address()); + unloadedModuleNode["end_addr"] = + ToHex(unloadedModule->base_address() + unloadedModule->size()); + + aNode.append(unloadedModuleNode); + } + + return unloadedModulesLen; +} + +// Convert the process state to JSON, this includes information about the +// crash, the module list and stack traces for every thread + +static void ConvertProcessStateToJSON(const ProcessState& aProcessState, + Json::Value& aStackTraces, + const bool aFullStacks, + Json::Value& aCertSubjects) { + // Crash info + Json::Value crashInfo; + int requestingThread = aProcessState.requesting_thread(); + + if (aProcessState.crashed()) { + crashInfo["type"] = aProcessState.crash_reason(); + crashInfo["address"] = ToHex(aProcessState.crash_address()); + + if (requestingThread != -1) { + // Record the crashing thread index only if this is a full minidump + // and all threads' stacks are present, otherwise only the crashing + // thread stack is written out and this field is set to 0. + crashInfo["crashing_thread"] = aFullStacks ? requestingThread : 0; + } + } else { + crashInfo["type"] = Json::Value(Json::nullValue); + // Add assertion info, if available + string assertion = aProcessState.assertion(); + + if (!assertion.empty()) { + crashInfo["assertion"] = assertion; + } + } + + aStackTraces["crash_info"] = crashInfo; + + // Modules + OrderedModulesMap orderedModules; + PopulateModuleList(aProcessState, orderedModules, aFullStacks); + + Json::Value modules(Json::arrayValue); + int mainModule = ConvertModulesToJSON(aProcessState, orderedModules, modules); + + if (mainModule != -1) { + aStackTraces["main_module"] = mainModule; + } + + aStackTraces["modules"] = modules; + + Json::Value unloadedModules(Json::arrayValue); + size_t unloadedModulesLen = + ConvertUnloadedModulesToJSON(aProcessState, unloadedModules); + + if (unloadedModulesLen > 0) { + aStackTraces["unloaded_modules"] = unloadedModules; + } + + RetrieveCertSubjects(aProcessState.modules(), aCertSubjects); + RetrieveCertSubjects(aProcessState.unloaded_modules(), aCertSubjects); + + // Threads + Json::Value threads(Json::arrayValue); + int threadCount = aProcessState.threads()->size(); + + if (!aFullStacks && (requestingThread != -1)) { + // Only add the crashing thread + Json::Value thread; + Json::Value stack(Json::arrayValue); + const CallStack* rawStack = aProcessState.threads()->at(requestingThread); + + ConvertStackToJSON(aProcessState, orderedModules, rawStack, stack); + thread["frames"] = stack; + threads.append(thread); + } else { + for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) { + Json::Value thread; + Json::Value stack(Json::arrayValue); + const CallStack* rawStack = aProcessState.threads()->at(threadIndex); + + ConvertStackToJSON(aProcessState, orderedModules, rawStack, stack); + thread["frames"] = stack; + threads.append(thread); + } + } + + aStackTraces["threads"] = threads; +} + +// Process the minidump file and append the JSON-formatted stack traces to +// the node specified in |aStackTraces|. We also populate |aCertSubjects| with +// information about the certificates used to sign modules, when present and +// supported by the underlying OS. +static bool ProcessMinidump(Json::Value& aStackTraces, + Json::Value& aCertSubjects, const string& aDumpFile, + const bool aFullStacks) { +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) + MozStackFrameSymbolizer symbolizer; + MinidumpProcessor minidumpProcessor(&symbolizer, false); +#else + BasicSourceLineResolver resolver; + // We don't have a valid symbol resolver so we pass nullptr instead. + MinidumpProcessor minidumpProcessor(nullptr, &resolver); +#endif + + // Process the minidump. +#if defined(XP_WIN) + // Breakpad invokes std::ifstream directly, so this path needs to be ANSI + Minidump dump(UTF8ToMBCS(aDumpFile)); +#else + Minidump dump(aDumpFile); +#endif // defined(XP_WIN) + if (!dump.Read()) { + return false; + } + + ProcessResult rv; + ProcessState processState; + rv = minidumpProcessor.Process(&dump, &processState); + aStackTraces["status"] = ResultString(rv); + + ConvertProcessStateToJSON(processState, aStackTraces, aFullStacks, + aCertSubjects); + + return true; +} + +static bool ReadExtraFile(const string& aExtraDataPath, Json::Value& aExtra) { + IFStream f( +#if defined(XP_WIN) + UTF8ToWide(aExtraDataPath).c_str(), +#else + aExtraDataPath.c_str(), +#endif // defined(XP_WIN) + ios::in); + if (!f.is_open()) { + return false; + } + + Json::CharReaderBuilder builder; + return parseFromStream(builder, f, &aExtra, nullptr); +} + +// Update the extra data file by adding the StackTraces and ModuleSignatureInfo +// fields that contain the JSON outputs of this program. +static bool UpdateExtraDataFile(const string& aDumpPath, + const Json::Value& aStackTraces, + const Json::Value& aCertSubjects) { + string extraDataPath(aDumpPath); + int dot = extraDataPath.rfind('.'); + + if (dot < 0) { + return false; // Not a valid dump path + } + + extraDataPath.replace(dot, extraDataPath.length() - dot, kExtraDataExtension); + + Json::Value extra; + if (!ReadExtraFile(extraDataPath, extra)) { + return false; + } + + OFStream f( +#if defined(XP_WIN) + UTF8ToWide(extraDataPath).c_str(), +#else + extraDataPath.c_str(), +#endif // defined(XP_WIN) + ios::out | ios::trunc); + + bool res = false; + if (f.is_open()) { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + + // The StackTraces field is not stored as a string because it's not a + // crash annotation. It's only used by the crash reporter client which + // strips it before submitting the other annotations to Socorro. + extra["StackTraces"] = aStackTraces; + + if (!!aCertSubjects) { + extra["ModuleSignatureInfo"] = Json::writeString(builder, aCertSubjects); + } + + std::unique_ptr writer(builder.newStreamWriter()); + writer->write(extra, &f); + f << "\n"; + res = !f.fail(); + f.close(); + } + + return res; +} + +static bool GenerateStacks(const string& aDumpPath, const bool aFullStacks) { + Json::Value stackTraces; + Json::Value certSubjects; + + if (!ProcessMinidump(stackTraces, certSubjects, aDumpPath, aFullStacks)) { + return false; + } + + return UpdateExtraDataFile(aDumpPath, stackTraces, certSubjects); +} + +} // namespace CrashReporter + +using namespace CrashReporter; + +#if defined(XP_WIN) +# define XP_LITERAL(s) L##s +#else +# define XP_LITERAL(s) s +#endif + +template +struct CharTraits; + +template <> +struct CharTraits { + static int compare(const char* left, const char* right) { + return strcmp(left, right); + } + + static string& assign(string& left, const char* right) { + left = right; + return left; + } +}; + +#if defined(XP_WIN) + +template <> +struct CharTraits { + static int compare(const wchar_t* left, const wchar_t* right) { + return wcscmp(left, right); + } + + static string& assign(string& left, const wchar_t* right) { + left = WideToUTF8(right); + return left; + } +}; + +#endif // defined(XP_WIN) + +static void LowerPriority() { +#if defined(XP_WIN) + Unused << SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); +#else // Linux, MacOS X, etc... + Unused << nice(20); +#endif +} + +template > +static void ParseArguments(int argc, CharT** argv) { + if (argc <= 1) { + exit(EXIT_FAILURE); + } + + for (int i = 1; i < argc - 1; i++) { + if (!Traits::compare(argv[i], XP_LITERAL("--full"))) { + gMinidumpAnalyzerOptions.fullMinidump = true; + } else if (!Traits::compare(argv[i], XP_LITERAL("--force-use-module")) && + (i < argc - 2)) { + Traits::assign(gMinidumpAnalyzerOptions.forceUseModule, argv[i + 1]); + ++i; + } else { + exit(EXIT_FAILURE); + } + } + + Traits::assign(gMinidumpPath, argv[argc - 1]); +} + +#if defined(XP_WIN) +// WARNING: Windows does *NOT* use UTF8 for char strings off the command line! +// Using wmain here so that the CRT doesn't need to perform a wasteful and +// lossy UTF-16 to MBCS conversion; ParseArguments will convert to UTF8 +// directly. +extern "C" int wmain(int argc, wchar_t** argv) +#else +int main(int argc, char** argv) +#endif +{ + LowerPriority(); + ParseArguments(argc, argv); + + if (!GenerateStacks(gMinidumpPath, gMinidumpAnalyzerOptions.fullMinidump)) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.exe.manifest b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.exe.manifest new file mode 100644 index 0000000000..731502e805 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/minidump-analyzer.exe.manifest @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/toolkit/crashreporter/minidump-analyzer/moz.build b/toolkit/crashreporter/minidump-analyzer/moz.build new file mode 100644 index 0000000000..912e830ab4 --- /dev/null +++ b/toolkit/crashreporter/minidump-analyzer/moz.build @@ -0,0 +1,43 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +GeckoProgram("minidump-analyzer", linkage=None) + +if CONFIG["OS_TARGET"] == "WINNT": + DEFINES["UNICODE"] = True + DEFINES["_UNICODE"] = True + + if CONFIG["TARGET_CPU"] == "x86_64": + UNIFIED_SOURCES += [ + "MozStackFrameSymbolizer.cpp", + "Win64ModuleUnwindMetadata.cpp", + ] + + OS_LIBS += ["dbghelp", "imagehlp"] + +if CONFIG["OS_TARGET"] == "WINNT" and CONFIG["CC_TYPE"] in ("gcc", "clang"): + # This allows us to use wmain as the entry point on mingw + LDFLAGS += [ + "-municode", + ] + +UNIFIED_SOURCES += [ + "minidump-analyzer.cpp", +] + +USE_LIBS += [ + "breakpad_processor", + "jsoncpp", +] + +LOCAL_INCLUDES += [ + "/toolkit/components/jsoncpp/include", +] + +if CONFIG["OS_TARGET"] != "WINNT": + DisableStlWrapping() + +include("/toolkit/crashreporter/crashreporter.mozbuild") diff --git a/toolkit/crashreporter/moz.build b/toolkit/crashreporter/moz.build new file mode 100644 index 0000000000..d6f49680e7 --- /dev/null +++ b/toolkit/crashreporter/moz.build @@ -0,0 +1,141 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +SPHINX_TREES["crashreporter"] = "docs" + +with Files("docs/**"): + SCHEDULES.exclusive = ["docs"] + +EXPORTS += [ + "!CrashAnnotations.h", + "nsExceptionHandler.h", +] + +JAR_MANIFESTS += ["jar.mn"] + +UNIFIED_SOURCES = [ + "CrashAnnotations.cpp", + "nsExceptionHandlerUtils.cpp", +] + +FINAL_LIBRARY = "xul" + +if CONFIG["MOZ_CRASHREPORTER"]: + if CONFIG["OS_ARCH"] == "WINNT": + DIRS += [ + "breakpad-windows-libxul", + "google-breakpad/src/common", + "google-breakpad/src/processor", + "mozwer", + "mozwer-rust", + ] + + if CONFIG["MOZ_CRASHREPORTER_INJECTOR"]: + DIRS += ["breakpad-windows-standalone"] + + elif CONFIG["OS_ARCH"] == "Darwin": + DIRS += [ + "breakpad-client", + "breakpad-client/mac/crash_generation", + "breakpad-client/mac/handler", + "google-breakpad/src/common", + "google-breakpad/src/common/mac", + "google-breakpad/src/processor", + ] + + elif CONFIG["OS_ARCH"] == "Linux": + DIRS += [ + "breakpad-client", + "breakpad-client/linux/", + "google-breakpad/src/common", + "google-breakpad/src/common/linux", + "google-breakpad/src/processor", + ] + + if CONFIG["MOZ_OXIDIZED_BREAKPAD"]: + DIRS += ["rust_minidump_writer_linux"] + + if CONFIG["OS_TARGET"] != "Android": + DIRS += ["minidump-analyzer"] + + DIRS += [ + "client", + "mozannotation_client", + "mozannotation_server", + ] + + if CONFIG["MOZ_CRASHREPORTER_INJECTOR"]: + DIRS += ["injector"] + UNIFIED_SOURCES += [ + "InjectCrashReporter.cpp", + "LoadLibraryRemote.cpp", + ] + + TEST_DIRS += ["test"] + + UNIFIED_SOURCES += [ + "nsExceptionHandler.cpp", + ] + + if CONFIG["OS_ARCH"] == "Darwin": + UNIFIED_SOURCES += [ + "mac_utils.mm", + ] + + EXTRA_JS_MODULES += [ + "CrashReports.sys.mjs", + "CrashSubmit.sys.mjs", + ] + + include("/ipc/chromium/chromium-config.mozbuild") + + if CONFIG["OS_TARGET"] == "Android": + DEFINES["ANDROID_NDK_MAJOR_VERSION"] = CONFIG["ANDROID_NDK_MAJOR_VERSION"] + DEFINES["ANDROID_NDK_MINOR_VERSION"] = CONFIG["ANDROID_NDK_MINOR_VERSION"] + DEFINES["ANDROID_PACKAGE_NAME"] = '"%s"' % CONFIG["ANDROID_PACKAGE_NAME"] + # NDK5 workarounds + DEFINES["_STLP_CONST_CONSTRUCTOR_BUG"] = True + DEFINES["_STLP_NO_MEMBER_TEMPLATES"] = True + LOCAL_INCLUDES += [ + "/toolkit/crashreporter/google-breakpad/src/common/android/include", + ] + + DEFINES["UNICODE"] = True + DEFINES["_UNICODE"] = True + + if CONFIG["MOZ_PHC"]: + DEFINES["MOZ_PHC"] = True + + LOCAL_INCLUDES += [ + "google-breakpad/src", + ] + + PYTHON_UNITTEST_MANIFESTS += [ + "tools/python.toml", + ] + + include("/toolkit/crashreporter/crashreporter.mozbuild") + + if CONFIG["CC_TYPE"] in ("clang", "gcc"): + CXXFLAGS += ["-Wno-error=stack-protector"] +else: + UNIFIED_SOURCES += [ + "nsDummyExceptionHandler.cpp", + ] + +# Generate CrashAnnotations.h +GeneratedFile( + "CrashAnnotations.h", + script="generate_crash_reporter_sources.py", + entry_point="emit_header", + inputs=[ + "CrashAnnotations.h.in", + "CrashAnnotations.yaml", + ], +) + +with Files("**"): + BUG_COMPONENT = ("Toolkit", "Crash Reporting") diff --git a/toolkit/crashreporter/mozannotation_client/Cargo.toml b/toolkit/crashreporter/mozannotation_client/Cargo.toml new file mode 100644 index 0000000000..0586c9b969 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "mozannotation_client" +version = "0.1.0" +authors = ["Gabriele Svelto"] +edition = "2018" +license = "MPL-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nsstring = { path = "../../../xpcom/rust/nsstring/" } diff --git a/toolkit/crashreporter/mozannotation_client/cbindgen.toml b/toolkit/crashreporter/mozannotation_client/cbindgen.toml new file mode 100644 index 0000000000..59b81645c0 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_client/cbindgen.toml @@ -0,0 +1,15 @@ +header = """/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */""" +autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */ +""" +include_version = true +braces = "SameLine" +line_length = 100 +tab_width = 2 +language = "C++" +include_guard = "mozannotation_client_ffi_generated_h" +includes = ["nsStringFwd.h"] + +[export.rename] +"ThinVec" = "nsTArray" diff --git a/toolkit/crashreporter/mozannotation_client/moz.build b/toolkit/crashreporter/mozannotation_client/moz.build new file mode 100644 index 0000000000..7d5597390a --- /dev/null +++ b/toolkit/crashreporter/mozannotation_client/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG["COMPILE_ENVIRONMENT"]: + # This tells mach to run cbindgen and that this header-file should be created + CbindgenHeader( + "mozannotation_client_ffi_generated.h", + inputs=["/toolkit/crashreporter/mozannotation_client"], + ) + + # This tells mach to copy that generated file to obj/dist/include/mozilla/toolkit/crashreporter + EXPORTS.mozilla.toolkit.crashreporter += [ + "!mozannotation_client_ffi_generated.h", + ] diff --git a/toolkit/crashreporter/mozannotation_client/src/lib.rs b/toolkit/crashreporter/mozannotation_client/src/lib.rs new file mode 100644 index 0000000000..17fe017095 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_client/src/lib.rs @@ -0,0 +1,354 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use nsstring::nsCString; +use std::{ffi::c_void, sync::Mutex}; + +#[cfg(any(target_os = "linux", target_os = "android"))] +use std::arch::global_asm; + +#[repr(C)] +#[derive(Copy, Clone)] +pub enum AnnotationContents { + Empty, + NSCString, + CString, + CharBuffer, + USize, + ByteBuffer(u32), +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Annotation { + pub id: u32, + pub contents: AnnotationContents, + pub address: usize, +} + +pub struct AnnotationTable { + data: Vec, + magic_number: u32, +} + +impl AnnotationTable { + const fn new() -> AnnotationTable { + AnnotationTable { + data: Vec::new(), + magic_number: ANNOTATION_TYPE, + } + } + + pub const fn verify(&self) -> bool { + self.magic_number == ANNOTATION_TYPE + } + + pub fn get_ptr(&self) -> *const Annotation { + self.data.as_ptr() + } + + pub fn len(&self) -> usize { + self.data.len() + } +} + +pub type AnnotationMutex = Mutex; + +#[cfg(target_os = "windows")] +#[link_section = "mozannot"] +static MOZANNOTATIONS: AnnotationMutex = Mutex::new(AnnotationTable::new()); +#[cfg(any(target_os = "linux", target_os = "android"))] +static MOZANNOTATIONS: AnnotationMutex = Mutex::new(AnnotationTable::new()); +#[cfg(target_os = "macos")] +#[link_section = "__DATA,mozannotation"] +static MOZANNOTATIONS: AnnotationMutex = Mutex::new(AnnotationTable::new()); + +#[no_mangle] +unsafe fn mozannotation_get() -> *const AnnotationMutex { + &MOZANNOTATIONS as _ +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +extern "C" { + pub static MOZANNOTATION_NOTE_REFERENCE: &'static u32; + pub static __ehdr_start: [u8; 0]; +} + +#[cfg(target_os = "windows")] +pub const ANNOTATION_SECTION: &'static [u8; 8] = b"mozannot"; + +// TODO: Use the following constants in the assembly below when constant +// expressions are stabilized: https://github.com/rust-lang/rust/issues/93332 +#[cfg(any(target_os = "linux", target_os = "android"))] +const _ANNOTATION_NOTE_ALIGNMENT: u32 = 4; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub const ANNOTATION_NOTE_NAME: &str = "mozannotation"; +pub const ANNOTATION_TYPE: u32 = u32::from_le_bytes(*b"MOZA"); + +// We use the crashpad crash info trick here. We create a program note which +// we'll use to find the location of the MOZANNOTATIONS static. Since program +// headers are always available we'll always be able to find this note in the +// memory of the crashed program, even if it's stripped or the backing file on +// disk has been deleted. +// +// We'll set the note type and name so we can easily recognize it (see the +// constants above). In the note's desc field we'll have the linker store the +// offset between the address of the MOZANNOTATIONS static and the desc field +// itself. +// +// At runtime we'll localize the note in the target process' memory, find the +// address of the `desc` field, load its contents (that is the offset we stored +// at link time) and add them together. The resulting address is the location of +// the MOZANNOTATIONS static in memory. +// +// When elfhack is used, the note might be moved after the aforementioned offset +// is calculated, without it being updated. To compensate for this we store the +// offset between the `ehdr` field and the ELF header. At runtime we can +// use this offset to adjust for the shift of the `desc` field. +#[cfg(all( + target_pointer_width = "64", + any(target_os = "linux", target_os = "android") +))] +global_asm!( + // The section holding the note will be called '.note.moz.annotation'. We + // create a program note that's allocated ('a' option) in the target binary + // so that it's loaded into memory. + " .section .note.moz.annotation,\"a\",%note", + // Note alignment must be 4 bytes because that's the default alignment for + // that section. If a different alignment is chosen the note will end up in + // its own section which we don't want. + " .balign 4", // TODO: _ANNOTATION_NOTE_ALIGNMENT + "MOZANNOTATION_NOTE:", + " .long name_end - name", // size in bytes of the note's name + " .long desc_end - desc", // size in bytes of the note's desc field + " .long 0x415a4f4d", // TODO: _ANNOTATION_TYPE, MOZA in reverse + "name:", + " .asciz \"mozannotation\"", // TODO: _ANNOTATION_NOTE_NAME + "name_end:", + " .balign 4", // TODO: _ANNOTATION_NOTE_ALIGNMENT + "desc:", + " .quad {mozannotation_symbol} - desc", + "ehdr:", + " .quad {__ehdr_start} - ehdr", + "desc_end:", + " .size MOZANNOTATION_NOTE, .-MOZANNOTATION_NOTE", + mozannotation_symbol = sym MOZANNOTATIONS, + __ehdr_start = sym __ehdr_start +); + +// The following global_asm!() expressions for other targets because Rust's +// support for putting statements within expressions is still experimental-only. +// Once https://github.com/rust-lang/rust/issues/15701 is fixed this can be +// folded in the `global_asm!()` statement above. + +#[cfg(all( + target_pointer_width = "32", + any(target_os = "linux", target_os = "android") +))] +global_asm!( + " .section .note.moz.annotation,\"a\",%note", + " .balign 4", + "MOZANNOTATION_NOTE:", + " .long name_end - name", + " .long desc_end - desc", + " .long 0x415a4f4d", + "name:", + " .asciz \"mozannotation\"", + "name_end:", + " .balign 4", + "desc:", + " .long {mozannotation_symbol} - desc", + "ehdr:", + " .long {__ehdr_start} - ehdr", + "desc_end:", + " .size MOZANNOTATION_NOTE, .-MOZANNOTATION_NOTE", + mozannotation_symbol = sym MOZANNOTATIONS, + __ehdr_start = sym __ehdr_start +); + +#[cfg(all( + any(target_os = "linux", target_os = "android"), + not(target_arch = "arm") +))] +global_asm!( + // MOZANNOTATION_NOTE can't be referenced directly because the relocation + // used to make the reference may require that the address be 8-byte aligned + // and notes must have 4-byte alignment. + " .section .rodata,\"a\",%progbits", + " .balign 8", + // .globl indicates that it's available to link against other .o files. + // .hidden indicates that it will not appear in the executable's symbol + // table. + " .globl", + " .hidden MOZANNOTATION_NOTE_REFERENCE", + " .type MOZANNOTATION_NOTE_REFERENCE, %object", + "MOZANNOTATION_NOTE_REFERENCE:", + // The value of this quad isn't important. It exists to reference + // MOZANNOTATION_NOTE, causing the linker to include the note into the + // binary linking the mozannotation_client crate. The subtraction from name + // is a convenience to allow the value to be computed statically. + " .quad name - MOZANNOTATION_NOTE", +); + +// In theory we could have used the statement above for ARM targets but for some +// reason the current rust compiler rejects the .quad directive. As with the other +// duplicate code above we could replace this with a single conditional line once +// once https://github.com/rust-lang/rust/issues/15701 is fixed. + +#[cfg(all(any(target_os = "linux", target_os = "android"), target_arch = "arm"))] +global_asm!( + " .section .rodata,\"a\",%progbits", + " .balign 8", + " .globl", + " .hidden MOZANNOTATION_NOTE_REFERENCE", + " .type MOZANNOTATION_NOTE_REFERENCE, %object", + "MOZANNOTATION_NOTE_REFERENCE:", + " .long name - MOZANNOTATION_NOTE", +); + +/// This structure mirrors the contents of the note declared above in the +/// assembly blocks. It is used to copy the contents of the note out of the +/// target process. +#[cfg(any(target_os = "linux", target_os = "android"))] +#[allow(dead_code)] +#[repr(C, packed(4))] +pub struct MozAnnotationNote { + pub namesz: u32, + pub descsz: u32, + pub note_type: u32, + pub name: [u8; 16], // "mozannotation" plus padding to next 4-bytes boundary + pub desc: usize, + pub ehdr: isize, +} + +/// Register an annotation containing an nsCString. +/// Returns false if the annotation is already present (and doesn't change it). +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_register_nscstring(id: u32, address: *const nsCString) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + + if annotations.iter().any(|e| e.id == id) { + return false; + } + + annotations.push(Annotation { + id, + contents: AnnotationContents::NSCString, + address: address as usize, + }); + + true +} + +/// Register an annotation containing a null-terminated string. +/// Returns false if the annotation is already present (and doesn't change it). +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_register_cstring( + id: u32, + address: *const *const std::ffi::c_char, +) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + + if annotations.iter().any(|e| e.id == id) { + return false; + } + + annotations.push(Annotation { + id, + contents: AnnotationContents::CString, + address: address as usize, + }); + + true +} + +/// Register an annotation pointing to a buffer holding a null-terminated string. +/// Returns false if the annotation is already present (and doesn't change it). +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_register_char_buffer( + id: u32, + address: *const std::ffi::c_char, +) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + + if annotations.iter().any(|e| e.id == id) { + return false; + } + + annotations.push(Annotation { + id, + contents: AnnotationContents::CharBuffer, + address: address as usize, + }); + + true +} + +/// Register an annotation pointing to a variable of type usize. +/// Returns false if the annotation is already present (and doesn't change it). +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_register_usize(id: u32, address: *const usize) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + + if annotations.iter().any(|e| e.id == id) { + return false; + } + + annotations.push(Annotation { + id, + contents: AnnotationContents::USize, + address: address as usize, + }); + + true +} + +/// Register an annotation pointing to a fixed size buffer. +/// Returns false if the annotation is already present (and doesn't change it). +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_register_bytebuffer( + id: u32, + address: *const c_void, + size: u32, +) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + + if annotations.iter().any(|e| e.id == id) { + return false; + } + + annotations.push(Annotation { + id, + contents: AnnotationContents::ByteBuffer(size), + address: address as usize, + }); + + true +} + +/// Unregister a crash annotation. Returns false if the annotation is not present. +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_unregister(id: u32) -> bool { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + let index = annotations.iter().position(|e| e.id == id); + + if let Some(index) = index { + annotations.remove(index); + return true; + } + + false +} diff --git a/toolkit/crashreporter/mozannotation_server/Cargo.toml b/toolkit/crashreporter/mozannotation_server/Cargo.toml new file mode 100644 index 0000000000..747aff791e --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "mozannotation_server" +version = "0.1.0" +authors = ["Gabriele Svelto"] +edition = "2018" +license = "MPL-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +goblin = { version = "0.7", features = ["elf32", "elf64", "pe32", "pe64"] } +memoffset = "0.8" +mozannotation_client = { path = "../mozannotation_client/" } +nsstring = { path = "../../../xpcom/rust/nsstring/" } +thin-vec = { version = "0.2.7", features = ["gecko-ffi"] } +thiserror = "1.0.38" + +[target."cfg(any(target_os = \"linux\", target_os = \"android\"))".dependencies] +libc = "0.2" + +[target."cfg(target_os = \"windows\")".dependencies] +winapi = { version = "0.3", features = ["minwindef", "memoryapi", "psapi"] } + +[target."cfg(target_os = \"macos\")".dependencies] +mach2 = { version = "0.4" } diff --git a/toolkit/crashreporter/mozannotation_server/cbindgen.toml b/toolkit/crashreporter/mozannotation_server/cbindgen.toml new file mode 100644 index 0000000000..5329196262 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/cbindgen.toml @@ -0,0 +1,15 @@ +header = """/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */""" +autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */ +""" +include_version = true +braces = "SameLine" +line_length = 100 +tab_width = 2 +language = "C++" +include_guard = "mozannotation_server_ffi_generated_h" +includes = ["nsString.h", "nsTArrayForwardDeclare.h"] + +[export.rename] +"ThinVec" = "nsTArray" diff --git a/toolkit/crashreporter/mozannotation_server/moz.build b/toolkit/crashreporter/mozannotation_server/moz.build new file mode 100644 index 0000000000..21762b95b1 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG["COMPILE_ENVIRONMENT"]: + # This tells mach to run cbindgen and that this header-file should be created + CbindgenHeader( + "mozannotation_server_ffi_generated.h", + inputs=["/toolkit/crashreporter/mozannotation_server"], + ) + + # This tells mach to copy that generated file to obj/dist/include/mozilla/toolkit/crashreporter + EXPORTS.mozilla.toolkit.crashreporter += [ + "!mozannotation_server_ffi_generated.h", + ] diff --git a/toolkit/crashreporter/mozannotation_server/src/errors.rs b/toolkit/crashreporter/mozannotation_server/src/errors.rs new file mode 100644 index 0000000000..037d432e5e --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/errors.rs @@ -0,0 +1,81 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum RetrievalError { + #[error("The process handle/PID was invalid")] + InvalidProcessHandle, + #[error("Could not find the address of the annotations vector")] + AnnotationTableNotFound(#[from] FindAnnotationsAddressError), + #[error("Corrupt or wrong annotation table")] + InvalidAnnotationTable, + #[error("The data read from the target process is invalid")] + InvalidData, + #[cfg(any(target_os = "linux", target_os = "android"))] + #[error("Could not attach to the target process")] + AttachError(#[from] PtraceError), + #[error("Could not read from the target process address space")] + ReadFromProcessError(#[from] ReadError), + #[error("waitpid() failed when attaching to the process")] + WaitPidError, +} + +#[derive(Debug, Error)] +pub enum FindAnnotationsAddressError { + #[error("Could not convert address {0}")] + ConvertAddressError(#[from] std::num::TryFromIntError), + #[error("goblin failed to parse a module")] + GoblinError(#[from] goblin::error::Error), + #[error("Address was out of bounds")] + InvalidAddress, + #[error("IO error for file {0}")] + IOError(#[from] std::io::Error), + #[error("Could not find the address of the annotations vector")] + NotFound, + #[error("Could not parse address {0}")] + ParseAddressError(#[from] std::num::ParseIntError), + #[error("Could not parse a line in /proc//maps")] + ProcMapsParseError, + #[cfg(any(target_os = "linux", target_os = "android"))] + #[error("Program header was not found")] + ProgramHeaderNotFound, + #[cfg(target_os = "windows")] + #[error("Section was not found")] + SectionNotFound, + #[cfg(target_os = "windows")] + #[error("Cannot enumerate the target process's modules")] + EnumProcessModulesError, + #[error("Could not read memory from the target process")] + ReadError(#[from] ReadError), + #[cfg(target_os = "macos")] + #[error("Failure when requesting the task information")] + TaskInfoError, + #[cfg(target_os = "macos")] + #[error("The task dyld information format is unknown or invalid")] + ImageFormatError, +} + +#[derive(Debug, Error)] +pub enum ReadError { + #[cfg(any(target_os = "linux", target_os = "android"))] + #[error("ptrace-specific error")] + PtraceError(#[from] PtraceError), + #[cfg(target_os = "windows")] + #[error("ReadProcessMemory failed")] + ReadProcessMemoryError, + #[cfg(target_os = "macos")] + #[error("mach call failed")] + MachError, +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +#[derive(Debug, Error)] +pub enum PtraceError { + #[error("Could not read from the target process address space")] + ReadError(#[source] std::io::Error), + #[error("Could not trace the process")] + TraceError(#[source] std::io::Error), +} diff --git a/toolkit/crashreporter/mozannotation_server/src/lib.rs b/toolkit/crashreporter/mozannotation_server/src/lib.rs new file mode 100644 index 0000000000..4ecb8ec919 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/lib.rs @@ -0,0 +1,217 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +mod errors; +mod process_reader; + +use crate::errors::*; +use process_reader::ProcessReader; + +use mozannotation_client::{Annotation, AnnotationContents, AnnotationMutex}; +use nsstring::nsCString; +use std::cmp::min; +use std::iter::FromIterator; +use std::mem::size_of; +use std::ptr::null_mut; +use thin_vec::ThinVec; + +#[repr(C)] +pub enum AnnotationData { + Empty, + UsizeData(usize), + NSCStringData(nsCString), + ByteBuffer(ThinVec), +} + +#[repr(C)] +pub struct CAnnotation { + id: u32, + data: AnnotationData, +} + +#[cfg(target_os = "windows")] +type ProcessHandle = winapi::shared::ntdef::HANDLE; +#[cfg(any(target_os = "linux", target_os = "android"))] +type ProcessHandle = libc::pid_t; +#[cfg(any(target_os = "macos"))] +type ProcessHandle = mach2::mach_types::task_t; + +/// Return the annotations of a given process. +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_retrieve( + process: usize, + max_annotations: usize, +) -> *mut ThinVec { + let result = retrieve_annotations(process as _, max_annotations); + match result { + // Leak the object as it will be owned by the C++ code from now on + Ok(annotations) => Box::into_raw(annotations) as *mut _, + Err(_) => null_mut(), + } +} + +/// Free the annotations returned by `mozannotation_retrieve()`. +/// +/// # Safety +/// +/// `ptr` must contain the value returned by a call to +/// `mozannotation_retrieve()` and be called only once. +#[no_mangle] +pub unsafe extern "C" fn mozannotation_free(ptr: *mut ThinVec) { + // The annotation vector will be automatically destroyed when the contents + // of this box are automatically dropped at the end of the function. + let _box = Box::from_raw(ptr); +} + +pub fn retrieve_annotations( + process: ProcessHandle, + max_annotations: usize, +) -> Result>, RetrievalError> { + let reader = ProcessReader::new(process)?; + let address = reader.find_annotations()?; + + let mut mutex = reader.copy_object_shallow::(address)?; + let mutex = unsafe { mutex.assume_init_mut() }; + + // TODO: we should clear the poison value here before getting the mutex + // contents. Right now we have to fail if the mutex was poisoned. + let annotation_table = mutex.get_mut().map_err(|_e| RetrievalError::InvalidData)?; + + if !annotation_table.verify() { + return Err(RetrievalError::InvalidAnnotationTable); + } + + let vec_pointer = annotation_table.get_ptr(); + let length = annotation_table.len(); + let mut annotations = ThinVec::::with_capacity(min(max_annotations, length)); + + for i in 0..length { + let annotation_address = unsafe { vec_pointer.add(i) }; + if let Ok(annotation) = read_annotation(&reader, annotation_address as usize) { + annotations.push(annotation); + } + } + + Ok(Box::new(annotations)) +} + +// Read an annotation from the given address +fn read_annotation(reader: &ProcessReader, address: usize) -> Result { + let raw_annotation = reader.copy_object::(address)?; + let mut annotation = CAnnotation { + id: raw_annotation.id, + data: AnnotationData::Empty, + }; + + match raw_annotation.contents { + AnnotationContents::Empty => {} + AnnotationContents::NSCString => { + let string = copy_nscstring(reader, raw_annotation.address)?; + annotation.data = AnnotationData::NSCStringData(string); + } + AnnotationContents::CString => { + let string = copy_null_terminated_string_pointer(reader, raw_annotation.address)?; + annotation.data = AnnotationData::NSCStringData(string); + } + AnnotationContents::CharBuffer => { + let string = copy_null_terminated_string(reader, raw_annotation.address)?; + annotation.data = AnnotationData::NSCStringData(string); + } + AnnotationContents::USize => { + let value = reader.copy_object::(raw_annotation.address)?; + annotation.data = AnnotationData::UsizeData(value); + } + AnnotationContents::ByteBuffer(size) => { + let value = copy_bytebuffer(reader, raw_annotation.address, size)?; + annotation.data = AnnotationData::ByteBuffer(value); + } + }; + + Ok(annotation) +} + +fn copy_null_terminated_string_pointer( + reader: &ProcessReader, + address: usize, +) -> Result { + let buffer_address = reader.copy_object::(address)?; + copy_null_terminated_string(reader, buffer_address) +} + +fn copy_null_terminated_string( + reader: &ProcessReader, + address: usize, +) -> Result { + // Try copying the string word-by-word first, this is considerably faster + // than one byte at a time. + if let Ok(string) = copy_null_terminated_string_word_by_word(reader, address) { + return Ok(string); + } + + // Reading the string one word at a time failed, let's try again one byte + // at a time. It's slow but it might work in situations where the string + // alignment causes word-by-word access to straddle page boundaries. + let mut length = 0; + let mut string = Vec::::new(); + + loop { + let char = reader.copy_object::(address + length)?; + length += 1; + string.push(char); + + if char == 0 { + break; + } + } + + Ok(nsCString::from(&string[..length])) +} + +fn copy_null_terminated_string_word_by_word( + reader: &ProcessReader, + address: usize, +) -> Result { + const WORD_SIZE: usize = size_of::(); + let mut length = 0; + let mut string = Vec::::new(); + + loop { + let mut array = reader.copy_array::(address + length, WORD_SIZE)?; + let null_terminator = array.iter().position(|&e| e == 0); + length += null_terminator.unwrap_or(WORD_SIZE); + string.append(&mut array); + + if null_terminator.is_some() { + break; + } + } + + Ok(nsCString::from(&string[..length])) +} + +fn copy_nscstring(reader: &ProcessReader, address: usize) -> Result { + // HACK: This assumes the layout of the string + let length_address = address + size_of::(); + let length = reader.copy_object::(length_address)?; + + if length > 0 { + let data_address = reader.copy_object::(address)?; + reader + .copy_array::(data_address, length as _) + .map(nsCString::from) + } else { + Ok(nsCString::new()) + } +} + +fn copy_bytebuffer( + reader: &ProcessReader, + address: usize, + size: u32, +) -> Result, ReadError> { + let value = reader.copy_array::(address, size as _)?; + Ok(ThinVec::::from_iter(value.into_iter())) +} diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader.rs new file mode 100644 index 0000000000..b405b4b725 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/process_reader.rs @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::ProcessHandle; + +pub struct ProcessReader { + process: ProcessHandle, +} + +#[cfg(target_os = "windows")] +mod windows; + +#[cfg(any(target_os = "android", target_os = "linux"))] +mod linux; + +#[cfg(target_os = "macos")] +mod macos; diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs new file mode 100644 index 0000000000..db6dbd3df2 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs @@ -0,0 +1,312 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use mozannotation_client::MozAnnotationNote; +use std::{ + cmp::min, + fs::File, + io::{BufRead, BufReader, Error}, + mem::{size_of, MaybeUninit}, + ptr::null_mut, + slice, +}; + +use crate::{ + errors::{FindAnnotationsAddressError, PtraceError, ReadError, RetrievalError}, + ProcessHandle, +}; + +use super::ProcessReader; + +use goblin::elf::{ + self, + program_header::{PF_R, PT_NOTE}, + Elf, ProgramHeader, +}; +use libc::{ + c_int, c_long, c_void, pid_t, ptrace, waitpid, EINTR, PTRACE_ATTACH, PTRACE_DETACH, + PTRACE_PEEKDATA, __WALL, +}; +use memoffset::offset_of; +use mozannotation_client::ANNOTATION_TYPE; + +impl ProcessReader { + pub fn new(process: ProcessHandle) -> Result { + let pid: pid_t = process; + + ptrace_attach(pid)?; + + let mut status: i32 = 0; + + loop { + let res = unsafe { waitpid(pid, &mut status as *mut _, __WALL) }; + if res < 0 { + match get_errno() { + EINTR => continue, + _ => { + ptrace_detach(pid)?; + return Err(RetrievalError::WaitPidError); + } + } + } else { + break; + } + } + + Ok(ProcessReader { process: pid }) + } + + pub fn find_annotations(&self) -> Result { + let maps_file = File::open(format!("/proc/{}/maps", self.process))?; + + BufReader::new(maps_file) + .lines() + .flatten() + .find_map(|line| self.find_annotations_in_module(&line).ok()) + .ok_or(FindAnnotationsAddressError::NotFound) + } + + fn find_annotations_in_module(&self, line: &str) -> Result { + parse_proc_maps_line(line).and_then(|module_address| { + let header_bytes = self.copy_array(module_address, size_of::())?; + let elf_header = Elf::parse_header(&header_bytes)?; + + let program_header_bytes = self.copy_array( + module_address + (elf_header.e_phoff as usize), + (elf_header.e_phnum as usize) * (elf_header.e_phentsize as usize), + )?; + + let mut elf = Elf::lazy_parse(elf_header)?; + let context = goblin::container::Ctx { + container: elf.header.container()?, + le: elf.header.endianness()?, + }; + + elf.program_headers = ProgramHeader::parse( + &program_header_bytes, + 0, + elf_header.e_phnum as usize, + context, + )?; + + self.find_mozannotation_note(module_address, &elf) + .ok_or(FindAnnotationsAddressError::ProgramHeaderNotFound) + }) + } + + // Looks through the program headers for the note contained in the + // mozannotation_client crate. If the note is found return the address of the + // note's desc field as well as its contents. + fn find_mozannotation_note(&self, module_address: usize, elf: &Elf) -> Option { + for program_header in elf.program_headers.iter() { + // We're looking for a note in the program headers, it needs to be + // readable and it needs to be at least as large as the + // MozAnnotationNote structure. + if (program_header.p_type == PT_NOTE) + && ((program_header.p_flags & PF_R) != 0 + && (program_header.p_memsz as usize >= size_of::())) + { + // Iterate over the notes + let notes_address = module_address + program_header.p_offset as usize; + let mut notes_offset = 0; + let notes_size = program_header.p_memsz as usize; + while notes_offset < notes_size { + let note_address = notes_address + notes_offset; + if let Ok(note) = self.copy_object::(note_address) { + if note.n_type == ANNOTATION_TYPE { + if let Ok(note) = self.copy_object::(note_address) { + let desc = note.desc; + let ehdr = (-note.ehdr) as usize; + let offset = desc + ehdr + - (offset_of!(MozAnnotationNote, ehdr) + - offset_of!(MozAnnotationNote, desc)); + + return usize::checked_add(module_address, offset); + } + } + + notes_offset += size_of::() + + (note.n_descsz as usize) + + (note.n_namesz as usize); + } else { + break; + } + } + } + } + + None + } + + pub fn copy_object_shallow(&self, src: usize) -> Result, ReadError> { + let data = self.copy_array(src, size_of::())?; + let mut object = MaybeUninit::::uninit(); + let uninitialized_object = uninit_as_bytes_mut(&mut object); + + for (index, &value) in data.iter().enumerate() { + uninitialized_object[index].write(value); + } + + Ok(object) + } + + pub fn copy_object(&self, src: usize) -> Result { + self.copy_object_shallow(src) + .map(|object| unsafe { object.assume_init() }) + } + + pub fn copy_array(&self, src: usize, num: usize) -> Result, ReadError> { + let mut array = Vec::>::with_capacity(num); + let num_bytes = num * size_of::(); + let mut array_buffer = array.as_mut_ptr() as *mut u8; + let mut index = 0; + + while index < num_bytes { + let word = ptrace_read(self.process, src + index)?; + let len = min(size_of::(), num_bytes - index); + let word_as_bytes = word.to_ne_bytes(); + for &byte in word_as_bytes.iter().take(len) { + unsafe { + array_buffer.write(byte); + array_buffer = array_buffer.add(1); + } + } + + index += size_of::(); + } + + unsafe { + array.set_len(num); + Ok(std::mem::transmute(array)) + } + } +} + +impl Drop for ProcessReader { + fn drop(&mut self) { + let _ignored = ptrace_detach(self.process); + } +} + +fn parse_proc_maps_line(line: &str) -> Result { + let mut splits = line.trim().splitn(6, ' '); + let address_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + let _perms_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + let _offset_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + let _dev_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + let _inode_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + let _path_str = splits + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + + let address = get_proc_maps_address(address_str)?; + + Ok(address) +} + +fn get_proc_maps_address(addresses: &str) -> Result { + let begin = addresses + .split('-') + .next() + .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?; + usize::from_str_radix(begin, 16).map_err(FindAnnotationsAddressError::from) +} + +fn uninit_as_bytes_mut(elem: &mut MaybeUninit) -> &mut [MaybeUninit] { + // SAFETY: MaybeUninit is always valid, even for padding bytes + unsafe { slice::from_raw_parts_mut(elem.as_mut_ptr() as *mut MaybeUninit, size_of::()) } +} + +/*********************************************************************** + ***** libc helpers ***** + ***********************************************************************/ + +fn get_errno() -> c_int { + #[cfg(target_os = "linux")] + unsafe { + *libc::__errno_location() + } + #[cfg(target_os = "android")] + unsafe { + *libc::__errno() + } +} + +fn clear_errno() { + #[cfg(target_os = "linux")] + unsafe { + *libc::__errno_location() = 0; + } + #[cfg(target_os = "android")] + unsafe { + *libc::__errno() = 0; + } +} + +#[derive(Clone, Copy)] +enum PTraceOperation { + Attach, + Detach, + PeekData, +} + +#[cfg(target_os = "linux")] +type PTraceOperationNative = libc::c_uint; +#[cfg(target_os = "android")] +type PTraceOperationNative = c_int; + +impl From for PTraceOperationNative { + fn from(val: PTraceOperation) -> Self { + match val { + PTraceOperation::Attach => PTRACE_ATTACH, + PTraceOperation::Detach => PTRACE_DETACH, + PTraceOperation::PeekData => PTRACE_PEEKDATA, + } + } +} + +fn ptrace_attach(pid: pid_t) -> Result<(), PtraceError> { + ptrace_helper(pid, PTraceOperation::Attach, 0).map(|_r| ()) +} + +fn ptrace_detach(pid: pid_t) -> Result<(), PtraceError> { + ptrace_helper(pid, PTraceOperation::Detach, 0).map(|_r| ()) +} + +fn ptrace_read(pid: libc::pid_t, addr: usize) -> Result { + ptrace_helper(pid, PTraceOperation::PeekData, addr) +} + +fn ptrace_helper(pid: pid_t, op: PTraceOperation, addr: usize) -> Result { + clear_errno(); + let result = unsafe { ptrace(op.into(), pid, addr, null_mut::()) }; + + if result == -1 { + let errno = get_errno(); + if errno != 0 { + let error = match op { + PTraceOperation::Attach => PtraceError::TraceError(Error::from_raw_os_error(errno)), + PTraceOperation::Detach => PtraceError::TraceError(Error::from_raw_os_error(errno)), + PTraceOperation::PeekData => { + PtraceError::ReadError(Error::from_raw_os_error(errno)) + } + }; + Err(error) + } else { + Ok(result) + } + } else { + Ok(result) + } +} diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs new file mode 100644 index 0000000000..52a3957ca9 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs @@ -0,0 +1,214 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use goblin::mach::{ + header::{Header64, MH_DYLIB, MH_EXECUTE, MH_MAGIC_64}, + load_command::{LoadCommandHeader, Section64, SegmentCommand64, LC_SEGMENT_64}, +}; +use mach2::{ + kern_return::KERN_SUCCESS, + task::task_info, + task_info::{task_dyld_info, TASK_DYLD_ALL_IMAGE_INFO_64, TASK_DYLD_INFO}, + vm::mach_vm_read_overwrite, +}; +use std::mem::{size_of, MaybeUninit}; + +use crate::{ + errors::{FindAnnotationsAddressError, ReadError, RetrievalError}, + ProcessHandle, +}; + +use super::ProcessReader; + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +struct AllImagesInfo { + // VERSION 1 + pub version: u32, + /// The number of [`ImageInfo`] structs at that following address + info_array_count: u32, + /// The address in the process where the array of [`ImageInfo`] structs is + info_array_addr: u64, + /// A function pointer, unused + _notification: u64, + /// Unused + _process_detached_from_shared_region: bool, + // VERSION 2 + lib_system_initialized: bool, + // Note that crashpad adds a 32-bit int here to get proper alignment when + // building on 32-bit targets...but we explicitly don't care about 32-bit + // targets since Apple doesn't + pub dyld_image_load_address: u64, +} + +/// `dyld_image_info` from +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct ImageInfo { + /// The address in the process where the image is loaded + pub load_address: u64, + /// The address in the process where the image's file path can be read + pub file_path: u64, + /// Timestamp for when the image's file was last modified + pub file_mod_date: u64, +} + +const DATA_SEGMENT: &[u8; 16] = b"__DATA\0\0\0\0\0\0\0\0\0\0"; +const MOZANNOTATION_SECTION: &[u8; 16] = b"mozannotation\0\0\0"; + +impl ProcessReader { + pub fn new(process: ProcessHandle) -> Result { + Ok(ProcessReader { process }) + } + + pub fn find_annotations(&self) -> Result { + let dyld_info = self.task_info()?; + if (dyld_info.all_image_info_format as u32) != TASK_DYLD_ALL_IMAGE_INFO_64 { + return Err(FindAnnotationsAddressError::ImageFormatError); + } + + let all_image_info_size = dyld_info.all_image_info_size; + let all_image_info_addr = dyld_info.all_image_info_addr; + if (all_image_info_size as usize) < size_of::() { + return Err(FindAnnotationsAddressError::ImageFormatError); + } + + let all_images_info = self.copy_object::(all_image_info_addr as _)?; + + // Load the images + let images = self.copy_array::( + all_images_info.info_array_addr as _, + all_images_info.info_array_count as _, + )?; + + images + .iter() + .find_map(|image| self.find_annotations_in_image(image)) + .ok_or(FindAnnotationsAddressError::NotFound) + } + + fn task_info(&self) -> Result { + let mut info = std::mem::MaybeUninit::::uninit(); + let mut count = (std::mem::size_of::() / std::mem::size_of::()) as u32; + + let res = unsafe { + task_info( + self.process, + TASK_DYLD_INFO, + info.as_mut_ptr().cast(), + &mut count, + ) + }; + + if res == KERN_SUCCESS { + // SAFETY: this will be initialized if the call succeeded + unsafe { Ok(info.assume_init()) } + } else { + Err(FindAnnotationsAddressError::TaskInfoError) + } + } + + fn find_annotations_in_image(&self, image: &ImageInfo) -> Option { + self.copy_object::(image.load_address as _) + .map_err(FindAnnotationsAddressError::from) + .and_then(|header| { + let image_address = image.load_address as usize; + let mut address = image_address + size_of::(); + + if header.magic == MH_MAGIC_64 + && (header.filetype == MH_EXECUTE || header.filetype == MH_DYLIB) + { + let end_of_commands = address + (header.sizeofcmds as usize); + + while address < end_of_commands { + let command = self.copy_object::(address)?; + + if command.cmd == LC_SEGMENT_64 { + if let Ok(offset) = self.find_annotations_in_segment(address) { + return image_address + .checked_add(offset) + .ok_or(FindAnnotationsAddressError::InvalidAddress); + } + } + + address += command.cmdsize as usize; + } + } + + Err(FindAnnotationsAddressError::NotFound) + }) + .ok() + } + + fn find_annotations_in_segment( + &self, + segment_address: usize, + ) -> Result { + let segment = self.copy_object::(segment_address)?; + + if segment.segname.eq(DATA_SEGMENT) { + let sections_addr = segment_address + size_of::(); + let sections = self.copy_array::(sections_addr, segment.nsects as usize)?; + for section in §ions { + if section.sectname.eq(MOZANNOTATION_SECTION) { + return Ok(section.offset as usize); + } + } + } + + Err(FindAnnotationsAddressError::InvalidAddress) + } + + pub fn copy_object_shallow(&self, src: usize) -> Result, ReadError> { + let mut object = MaybeUninit::::uninit(); + let mut size: u64 = 0; + let res = unsafe { + mach_vm_read_overwrite( + self.process, + src as u64, + size_of::() as u64, + object.as_mut_ptr() as _, + &mut size as _, + ) + }; + + if res == KERN_SUCCESS { + Ok(object) + } else { + Err(ReadError::MachError) + } + } + + pub fn copy_object(&self, src: usize) -> Result { + let object = self.copy_object_shallow(src)?; + Ok(unsafe { object.assume_init() }) + } + + pub fn copy_array(&self, src: usize, num: usize) -> Result, ReadError> { + let mut array: Vec> = Vec::with_capacity(num); + let mut size: u64 = 0; + let res = unsafe { + mach_vm_read_overwrite( + self.process, + src as u64, + (num * size_of::()) as u64, + array.as_mut_ptr() as _, + &mut size as _, + ) + }; + + if res == KERN_SUCCESS { + unsafe { + array.set_len(num); + Ok(std::mem::transmute(array)) + } + } else { + Err(ReadError::MachError) + } + } +} + +impl Drop for ProcessReader { + fn drop(&mut self) {} +} diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs new file mode 100644 index 0000000000..ffdcd95937 --- /dev/null +++ b/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs @@ -0,0 +1,193 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::{ + convert::TryInto, + mem::{size_of, MaybeUninit}, + ptr::null_mut, +}; + +use winapi::{ + shared::{ + basetsd::SIZE_T, + minwindef::{DWORD, FALSE, HMODULE}, + }, + um::{ + memoryapi::ReadProcessMemory, + psapi::{K32EnumProcessModules, K32GetModuleInformation, MODULEINFO}, + }, +}; + +use crate::{ + errors::{FindAnnotationsAddressError, ReadError, RetrievalError}, + ProcessHandle, +}; + +use super::ProcessReader; + +impl ProcessReader { + pub fn new(process: ProcessHandle) -> Result { + Ok(ProcessReader { process }) + } + + pub fn find_annotations(&self) -> Result { + let modules = self.get_module_list()?; + + modules + .iter() + .find_map(|&module| { + self.get_module_info(module).and_then(|info| { + self.find_annotations_in_module( + info.lpBaseOfDll as usize, + info.SizeOfImage as usize, + ) + .ok() + }) + }) + .ok_or(FindAnnotationsAddressError::InvalidAddress) + } + + fn get_module_list(&self) -> Result, FindAnnotationsAddressError> { + let mut module_num: usize = 100; + let mut required_buffer_size: DWORD = 0; + let mut module_array = Vec::>::with_capacity(module_num); + + loop { + let buffer_size: DWORD = (module_num * size_of::()).try_into()?; + let res = unsafe { + K32EnumProcessModules( + self.process, + module_array.as_mut_ptr() as *mut _, + buffer_size, + &mut required_buffer_size as *mut _, + ) + }; + + module_num = required_buffer_size as usize / size_of::(); + + if res == 0 { + if required_buffer_size > buffer_size { + module_array = Vec::>::with_capacity(module_num); + } else { + return Err(FindAnnotationsAddressError::EnumProcessModulesError); + } + } else { + break; + } + } + + // SAFETY: module_array has been filled by K32EnumProcessModules() + let module_array: Vec = unsafe { + module_array.set_len(module_num); + std::mem::transmute(module_array) + }; + + Ok(module_array) + } + + fn get_module_info(&self, module: HMODULE) -> Option { + let mut info: MaybeUninit = MaybeUninit::uninit(); + let res = unsafe { + K32GetModuleInformation( + self.process, + module, + info.as_mut_ptr(), + size_of::() as DWORD, + ) + }; + + if res == 0 { + None + } else { + let info = unsafe { info.assume_init() }; + Some(info) + } + } + + fn find_annotations_in_module( + &self, + module_address: usize, + size: usize, + ) -> Result { + // We read only the first page from the module, this should be more than + // enough to read the header and section list. In the future we might do + // this incrementally but for now goblin requires an array to parse + // so we can't do it just yet. + let page_size = 4096; + if size < page_size { + // Don't try to read from the target module if it's too small + return Err(FindAnnotationsAddressError::ReadError( + ReadError::ReadProcessMemoryError, + )); + } + + let bytes = self.copy_array(module_address as _, 4096)?; + let header = goblin::pe::header::Header::parse(&bytes)?; + + // Skip the PE header so we can parse the sections + let optional_header_offset = header.dos_header.pe_pointer as usize + + goblin::pe::header::SIZEOF_PE_MAGIC + + goblin::pe::header::SIZEOF_COFF_HEADER; + let offset = + &mut (optional_header_offset + header.coff_header.size_of_optional_header as usize); + + let sections = header.coff_header.sections(&bytes, offset)?; + + for section in sections { + if section.name.eq(mozannotation_client::ANNOTATION_SECTION) { + let address = module_address.checked_add(section.virtual_address as usize); + return address.ok_or(FindAnnotationsAddressError::InvalidAddress); + } + } + + Err(FindAnnotationsAddressError::SectionNotFound) + } + + pub fn copy_object_shallow(&self, src: usize) -> Result, ReadError> { + let mut object = MaybeUninit::::uninit(); + let res = unsafe { + ReadProcessMemory( + self.process, + src as _, + object.as_mut_ptr() as _, + size_of::() as SIZE_T, + null_mut(), + ) + }; + + if res != FALSE { + Ok(object) + } else { + Err(ReadError::ReadProcessMemoryError) + } + } + + pub fn copy_object(&self, src: usize) -> Result { + let object = self.copy_object_shallow(src)?; + Ok(unsafe { object.assume_init() }) + } + + pub fn copy_array(&self, src: usize, num: usize) -> Result, ReadError> { + let num_of_bytes = num * size_of::(); + let mut array: Vec> = Vec::with_capacity(num); + let res = unsafe { + ReadProcessMemory( + self.process, + src as _, + array.as_mut_ptr() as _, + num_of_bytes as SIZE_T, + null_mut(), + ) + }; + + if res != FALSE { + unsafe { + array.set_len(num); + Ok(std::mem::transmute(array)) + } + } else { + Err(ReadError::ReadProcessMemoryError) + } + } +} diff --git a/toolkit/crashreporter/mozwer-rust/Cargo.toml b/toolkit/crashreporter/mozwer-rust/Cargo.toml new file mode 100644 index 0000000000..561a10b015 --- /dev/null +++ b/toolkit/crashreporter/mozwer-rust/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "mozwer_s" +version = "0.1.0" +authors = ["Gabriele Svelto "] +edition = "2018" +license = "MPL-2.0" + +[dependencies] +libc = "0.2.0" +mozilla-central-workspace-hack = { version = "0.1", features = ["mozwer_s"], optional = true } +process_reader = { path = "../process_reader/" } +rust-ini = "0.10" +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0" } +uuid = { version = "1.0", features = ["v4"] } + +[dependencies.windows-sys] +version = "0.52" +features = [ + "Wdk_System_Threading", + "Win32_Foundation", + "Win32_Security", + "Win32_System_Com", + "Win32_System_Diagnostics_Debug", + "Win32_System_ErrorReporting", + "Win32_System_ProcessStatus", + "Win32_System_SystemInformation", + "Win32_System_SystemServices", + "Win32_System_Threading", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", +] + +[lib] +name = "mozwer_s" +crate-type = ["staticlib"] +path = "lib.rs" diff --git a/toolkit/crashreporter/mozwer-rust/lib.rs b/toolkit/crashreporter/mozwer-rust/lib.rs new file mode 100644 index 0000000000..198a14a34b --- /dev/null +++ b/toolkit/crashreporter/mozwer-rust/lib.rs @@ -0,0 +1,868 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use ini::Ini; +use libc::time; +use process_reader::ProcessReader; +use serde::Serialize; +use serde_json::ser::to_writer; +use std::convert::TryInto; +use std::ffi::{c_void, OsString}; +use std::fs::{read_to_string, DirBuilder, File}; +use std::io::{BufRead, BufReader, Write}; +use std::mem::{size_of, transmute, zeroed}; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle, RawHandle}; +use std::path::{Path, PathBuf}; +use std::ptr::{addr_of, null, null_mut}; +use std::slice::from_raw_parts; +use uuid::Uuid; +use windows_sys::core::{HRESULT, PWSTR}; +use windows_sys::Wdk::System::Threading::{NtQueryInformationProcess, ProcessBasicInformation}; +use windows_sys::Win32::{ + Foundation::{ + CloseHandle, GetLastError, SetLastError, BOOL, ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS, + EXCEPTION_BREAKPOINT, E_UNEXPECTED, FALSE, FILETIME, HANDLE, HWND, LPARAM, MAX_PATH, + STATUS_SUCCESS, S_OK, TRUE, WAIT_OBJECT_0, + }, + Security::{ + GetSidSubAuthority, GetSidSubAuthorityCount, GetTokenInformation, IsTokenRestricted, + TokenIntegrityLevel, TOKEN_MANDATORY_LABEL, TOKEN_QUERY, + }, + System::Com::CoTaskMemFree, + System::Diagnostics::Debug::{ + GetThreadContext, MiniDumpWithFullMemoryInfo, MiniDumpWithIndirectlyReferencedMemory, + MiniDumpWithProcessThreadData, MiniDumpWithUnloadedModules, MiniDumpWriteDump, + WriteProcessMemory, EXCEPTION_POINTERS, MINIDUMP_EXCEPTION_INFORMATION, MINIDUMP_TYPE, + }, + System::ErrorReporting::WER_RUNTIME_EXCEPTION_INFORMATION, + System::Memory::{ + VirtualAllocEx, VirtualFreeEx, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, + }, + System::ProcessStatus::K32GetModuleFileNameExW, + System::SystemInformation::{ + VerSetConditionMask, VerifyVersionInfoW, OSVERSIONINFOEXW, VER_MAJORVERSION, + VER_MINORVERSION, VER_SERVICEPACKMAJOR, VER_SERVICEPACKMINOR, + }, + System::SystemServices::{SECURITY_MANDATORY_MEDIUM_RID, VER_GREATER_EQUAL}, + System::Threading::{ + CreateProcessW, CreateRemoteThread, GetProcessId, GetProcessTimes, GetThreadId, + OpenProcess, OpenProcessToken, OpenThread, TerminateProcess, WaitForSingleObject, + CREATE_NO_WINDOW, CREATE_UNICODE_ENVIRONMENT, LPTHREAD_START_ROUTINE, + NORMAL_PRIORITY_CLASS, PROCESS_ALL_ACCESS, PROCESS_BASIC_INFORMATION, PROCESS_INFORMATION, + STARTUPINFOW, THREAD_GET_CONTEXT, + }, + UI::Shell::{FOLDERID_RoamingAppData, SHGetKnownFolderPath}, + UI::WindowsAndMessaging::{EnumWindows, GetWindowThreadProcessId, IsHungAppWindow}, +}; + +type DWORD = u32; +type ULONG = u32; +type DWORDLONG = u64; +type LPVOID = *mut c_void; +type PVOID = LPVOID; +type PBOOL = *mut BOOL; +type PDWORD = *mut DWORD; +#[allow(non_camel_case_types)] +type PWER_RUNTIME_EXCEPTION_INFORMATION = *mut WER_RUNTIME_EXCEPTION_INFORMATION; + +/* The following struct must be kept in sync with the identically named one in + * nsExceptionHandler.h. WER will use it to communicate with the main process + * when a child process is encountered. */ +#[repr(C)] +struct WindowsErrorReportingData { + child_pid: DWORD, + minidump_name: [u8; 40], +} + +// This value comes from GeckoProcessTypes.h +static MAIN_PROCESS_TYPE: u32 = 0; + +#[no_mangle] +pub extern "C" fn OutOfProcessExceptionEventCallback( + context: PVOID, + exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION, + b_ownership_claimed: PBOOL, + _wsz_event_name: PWSTR, + _pch_size: PDWORD, + _dw_signature_count: PDWORD, +) -> HRESULT { + let result = out_of_process_exception_event_callback(context, exception_information); + + match result { + Ok(_) => { + unsafe { + // Inform WER that we claim ownership of this crash + *b_ownership_claimed = TRUE; + // Make sure that the process shuts down + TerminateProcess((*exception_information).hProcess, 1); + } + S_OK + } + Err(_) => E_UNEXPECTED, + } +} + +#[no_mangle] +pub extern "C" fn OutOfProcessExceptionEventSignatureCallback( + _context: PVOID, + _exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION, + _w_index: DWORD, + _wsz_name: PWSTR, + _ch_name: PDWORD, + _wsz_value: PWSTR, + _ch_value: PDWORD, +) -> HRESULT { + S_OK +} + +#[no_mangle] +pub extern "C" fn OutOfProcessExceptionEventDebuggerLaunchCallback( + _context: PVOID, + _exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION, + b_is_custom_debugger: PBOOL, + _wsz_debugger_launch: PWSTR, + _ch_debugger_launch: PDWORD, + _b_is_debugger_autolaunch: PBOOL, +) -> HRESULT { + unsafe { + *b_is_custom_debugger = FALSE; + } + + S_OK +} + +type Result = std::result::Result; + +fn out_of_process_exception_event_callback( + context: PVOID, + exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION, +) -> Result<()> { + let exception_information = unsafe { &mut *exception_information }; + let is_fatal = exception_information.bIsFatal.to_bool(); + let mut is_ui_hang = false; + if !is_fatal { + 'hang: { + // Check whether this error is a hang. A hang always results in an EXCEPTION_BREAKPOINT. + // Hangs may have an hThread/context that is unrelated to the hanging thread, so we get + // it by searching for process windows that are hung. + if exception_information.exceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT { + if let Ok(thread_id) = find_hung_window_thread(exception_information.hProcess) { + // In the case of a hang, change the crashing thread to be the one that created + // the hung window. + // + // This is all best-effort, so don't return errors (just fall through to the + // Ok return). + let thread_handle = unsafe { OpenThread(THREAD_GET_CONTEXT, FALSE, thread_id) }; + if thread_handle != 0 + && unsafe { + GetThreadContext(thread_handle, &mut exception_information.context) + } + .to_bool() + { + exception_information.hThread = thread_handle; + break 'hang; + } + } + } + + // A non-fatal but non-hang exception should not do anything else. + return Ok(()); + } + is_ui_hang = true; + } + + let process = exception_information.hProcess; + let application_info = ApplicationInformation::from_process(process)?; + let process_type: u32 = (context as usize).try_into().map_err(|_| ())?; + let startup_time = get_startup_time(process)?; + let crash_report = CrashReport::new(&application_info, startup_time, is_ui_hang); + crash_report.write_minidump(exception_information)?; + if process_type == MAIN_PROCESS_TYPE { + match is_sandboxed_process(process) { + Ok(false) => handle_main_process_crash(crash_report, &application_info), + _ => { + // The parent process should never be sandboxed, bail out so the + // process which is impersonating it gets killed right away. Also + // bail out if is_sandboxed_process() failed while checking. + Ok(()) + } + } + } else { + handle_child_process_crash(crash_report, process) + } +} + +/// Find whether the given process has a hung window, and return the thread id related to the +/// window. +fn find_hung_window_thread(process: HANDLE) -> Result { + let process_id = get_process_id(process)?; + + struct WindowSearch { + process_id: DWORD, + ui_thread_id: Option, + } + + let mut search = WindowSearch { + process_id, + ui_thread_id: None, + }; + + unsafe extern "system" fn enum_window_callback(wnd: HWND, data: LPARAM) -> BOOL { + let data = &mut *(data as *mut WindowSearch); + let mut window_proc_id = DWORD::default(); + let thread_id = GetWindowThreadProcessId(wnd, &mut window_proc_id); + if thread_id != 0 && window_proc_id == data.process_id && IsHungAppWindow(wnd).to_bool() { + data.ui_thread_id = Some(thread_id); + FALSE + } else { + TRUE + } + } + + // Disregard the return value, we are trying for best-effort service (it's okay if ui_thread_id + // is never set). + unsafe { EnumWindows(Some(enum_window_callback), &mut search as *mut _ as LPARAM) }; + + search.ui_thread_id.ok_or(()) +} + +fn get_parent_process(process: HANDLE) -> Result { + let pbi = get_process_basic_information(process)?; + get_process_handle(pbi.InheritedFromUniqueProcessId as u32) +} + +fn handle_main_process_crash( + crash_report: CrashReport, + application_information: &ApplicationInformation, +) -> Result<()> { + crash_report.write_extra_file()?; + crash_report.write_event_file()?; + + launch_crash_reporter_client(&application_information.install_path, &crash_report); + + Ok(()) +} + +fn handle_child_process_crash(crash_report: CrashReport, child_process: HANDLE) -> Result<()> { + let parent_process = get_parent_process(child_process)?; + let process_reader = ProcessReader::new(parent_process).map_err(|_e| ())?; + let wer_notify_proc = process_reader + .find_section("xul.dll", "mozwerpt") + .map_err(|_e| ())?; + let wer_notify_proc = unsafe { transmute::<_, LPTHREAD_START_ROUTINE>(wer_notify_proc) }; + + let wer_data = WindowsErrorReportingData { + child_pid: get_process_id(child_process)?, + minidump_name: crash_report.get_minidump_name(), + }; + let address = copy_object_into_process(parent_process, wer_data)?; + notify_main_process(parent_process, wer_notify_proc, address) +} + +fn copy_object_into_process(process: HANDLE, data: T) -> Result<*mut T> { + let address = unsafe { + VirtualAllocEx( + process, + null(), + size_of::(), + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE, + ) + }; + + if address.is_null() { + return Err(()); + } + + let res = unsafe { + WriteProcessMemory( + process, + address, + addr_of!(data) as *const _, + size_of::(), + null_mut(), + ) + }; + + if res == 0 { + unsafe { VirtualFreeEx(process, address as *mut _, 0, MEM_RELEASE) }; + Err(()) + } else { + Ok(address as *mut T) + } +} + +fn notify_main_process( + process: HANDLE, + wer_notify_proc: LPTHREAD_START_ROUTINE, + address: *mut WindowsErrorReportingData, +) -> Result<()> { + let thread = unsafe { + CreateRemoteThread( + process, + null_mut(), + 0, + wer_notify_proc, + address as LPVOID, + 0, + null_mut(), + ) + }; + + if thread == 0 { + unsafe { VirtualFreeEx(process, address as *mut _, 0, MEM_RELEASE) }; + return Err(()); + } + + // From this point on the memory pointed to by address is owned by the + // thread we've created in the main process, so we don't free it. + + let thread = unsafe { OwnedHandle::from_raw_handle(thread as RawHandle) }; + + // Don't wait forever as we want the process to get killed eventually + let res = unsafe { WaitForSingleObject(thread.as_raw_handle() as HANDLE, 5000) }; + if res != WAIT_OBJECT_0 { + return Err(()); + } + + Ok(()) +} + +fn get_startup_time(process: HANDLE) -> Result { + const ZERO_FILETIME: FILETIME = FILETIME { + dwLowDateTime: 0, + dwHighDateTime: 0, + }; + let mut create_time: FILETIME = ZERO_FILETIME; + let mut exit_time: FILETIME = ZERO_FILETIME; + let mut kernel_time: FILETIME = ZERO_FILETIME; + let mut user_time: FILETIME = ZERO_FILETIME; + unsafe { + if GetProcessTimes( + process, + &mut create_time as *mut _, + &mut exit_time as *mut _, + &mut kernel_time as *mut _, + &mut user_time as *mut _, + ) == 0 + { + return Err(()); + } + } + let start_time_in_ticks = + ((create_time.dwHighDateTime as u64) << 32) + create_time.dwLowDateTime as u64; + let windows_tick: u64 = 10000000; + let sec_to_unix_epoch = 11644473600; + Ok((start_time_in_ticks / windows_tick) - sec_to_unix_epoch) +} + +fn get_process_id(process: HANDLE) -> Result { + match unsafe { GetProcessId(process) } { + 0 => Err(()), + pid => Ok(pid), + } +} + +fn get_process_handle(pid: DWORD) -> Result { + let handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid) }; + if handle != 0 { + Ok(handle) + } else { + Err(()) + } +} + +fn launch_crash_reporter_client(install_path: &Path, crash_report: &CrashReport) { + // Prepare the command line + let client_path = install_path.join("crashreporter.exe"); + + let mut cmd_line = OsString::from("\""); + cmd_line.push(client_path); + cmd_line.push("\" \""); + cmd_line.push(crash_report.get_minidump_path()); + cmd_line.push("\"\0"); + let mut cmd_line: Vec = cmd_line.encode_wide().collect(); + + let mut pi = unsafe { zeroed::() }; + let mut si = STARTUPINFOW { + cb: size_of::().try_into().unwrap(), + ..unsafe { zeroed() } + }; + + unsafe { + if CreateProcessW( + null_mut(), + cmd_line.as_mut_ptr(), + null_mut(), + null_mut(), + FALSE, + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + null_mut(), + null_mut(), + &mut si, + &mut pi, + ) != 0 + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } +} + +#[derive(Debug)] +struct ApplicationData { + vendor: Option, + name: String, + version: String, + build_id: String, + product_id: String, + server_url: String, +} + +impl ApplicationData { + fn load_from_disk(install_path: &Path) -> Result { + let ini_path = ApplicationData::get_path(install_path); + let conf = Ini::load_from_file(ini_path).map_err(|_e| ())?; + + // Parse the "App" section + let app_section = conf.section(Some("App")).ok_or(())?; + let vendor = app_section.get("Vendor").map(|s| s.to_owned()); + let name = app_section.get("Name").ok_or(())?.to_owned(); + let version = app_section.get("Version").ok_or(())?.to_owned(); + let build_id = app_section.get("BuildID").ok_or(())?.to_owned(); + let product_id = app_section.get("ID").ok_or(())?.to_owned(); + + // Parse the "Crash Reporter" section + let crash_reporter_section = conf.section(Some("Crash Reporter")).ok_or(())?; + let server_url = crash_reporter_section + .get("ServerURL") + .ok_or(())? + .to_owned(); + + // InstallTime + + Ok(ApplicationData { + vendor, + name, + version, + build_id, + product_id, + server_url, + }) + } + + fn get_path(install_path: &Path) -> PathBuf { + install_path.join("application.ini") + } +} + +#[derive(Serialize)] +#[allow(non_snake_case)] +struct Annotations { + BuildID: String, + CrashTime: String, + InstallTime: String, + #[serde(skip_serializing_if = "Option::is_none")] + Hang: Option, + ProductID: String, + ProductName: String, + ReleaseChannel: String, + ServerURL: String, + StartupTime: String, + UptimeTS: String, + #[serde(skip_serializing_if = "Option::is_none")] + Vendor: Option, + Version: String, + WindowsErrorReporting: String, +} + +impl Annotations { + fn from_application_data( + application_data: &ApplicationData, + release_channel: String, + install_time: String, + crash_time: u64, + startup_time: u64, + ui_hang: bool, + ) -> Annotations { + Annotations { + BuildID: application_data.build_id.clone(), + CrashTime: crash_time.to_string(), + InstallTime: install_time, + Hang: ui_hang.then(|| "ui".to_string()), + ProductID: application_data.product_id.clone(), + ProductName: application_data.name.clone(), + ReleaseChannel: release_channel, + ServerURL: application_data.server_url.clone(), + StartupTime: startup_time.to_string(), + UptimeTS: (crash_time - startup_time).to_string() + ".0", + Vendor: application_data.vendor.clone(), + Version: application_data.version.clone(), + WindowsErrorReporting: "1".to_string(), + } + } +} + +/// Encapsulates the information about the application that crashed. This includes the install path as well as version information +struct ApplicationInformation { + install_path: PathBuf, + application_data: ApplicationData, + release_channel: String, + crash_reports_dir: PathBuf, + install_time: String, +} + +impl ApplicationInformation { + fn from_process(process: HANDLE) -> Result { + let mut install_path = ApplicationInformation::get_application_path(process)?; + install_path.pop(); + let application_data = ApplicationData::load_from_disk(install_path.as_ref())?; + let release_channel = ApplicationInformation::get_release_channel(install_path.as_ref())?; + let crash_reports_dir = ApplicationInformation::get_crash_reports_dir(&application_data)?; + let install_time = ApplicationInformation::get_install_time( + &crash_reports_dir, + &application_data.build_id, + ) + .unwrap_or("0".to_string()); + + Ok(ApplicationInformation { + install_path, + application_data, + release_channel, + crash_reports_dir, + install_time, + }) + } + + fn get_application_path(process: HANDLE) -> Result { + let mut path: [u16; MAX_PATH as usize + 1] = [0; MAX_PATH as usize + 1]; + unsafe { + let res = K32GetModuleFileNameExW( + process, + 0, + (&mut path).as_mut_ptr(), + (MAX_PATH + 1) as DWORD, + ); + + if res == 0 { + return Err(()); + } + + let application_path = PathBuf::from(OsString::from_wide(&path[0..res as usize])); + Ok(application_path) + } + } + + fn get_release_channel(install_path: &Path) -> Result { + let channel_prefs = + File::open(install_path.join("defaults/pref/channel-prefs.js")).map_err(|_e| ())?; + let lines = BufReader::new(channel_prefs).lines(); + let line = lines + .filter_map(std::result::Result::ok) + .find(|line| line.contains("app.update.channel")) + .ok_or(())?; + line.split("\"").nth(3).map(|s| s.to_string()).ok_or(()) + } + + fn get_crash_reports_dir(application_data: &ApplicationData) -> Result { + let mut psz_path: PWSTR = null_mut(); + unsafe { + let res = SHGetKnownFolderPath( + &FOLDERID_RoamingAppData as *const _, + 0, + 0, + &mut psz_path as *mut _, + ); + + if res == S_OK { + let mut len = 0; + while psz_path.offset(len).read() != 0 { + len += 1; + } + let str = OsString::from_wide(from_raw_parts(psz_path, len as usize)); + CoTaskMemFree(psz_path as _); + let mut path = PathBuf::from(str); + if let Some(vendor) = &application_data.vendor { + path.push(vendor); + } + path.push(&application_data.name); + path.push("Crash Reports"); + Ok(path) + } else { + Err(()) + } + } + } + + fn get_install_time(crash_reports_path: &Path, build_id: &str) -> Result { + let file_name = "InstallTime".to_owned() + build_id; + let file_path = crash_reports_path.join(file_name); + read_to_string(file_path).map_err(|_e| ()) + } +} + +struct CrashReport { + uuid: String, + crash_reports_path: PathBuf, + release_channel: String, + annotations: Annotations, + crash_time: u64, +} + +impl CrashReport { + fn new( + application_information: &ApplicationInformation, + startup_time: u64, + ui_hang: bool, + ) -> CrashReport { + let uuid = Uuid::new_v4() + .as_hyphenated() + .encode_lower(&mut Uuid::encode_buffer()) + .to_owned(); + let crash_reports_path = application_information.crash_reports_dir.clone(); + let crash_time: u64 = unsafe { time(null_mut()) as u64 }; + let annotations = Annotations::from_application_data( + &application_information.application_data, + application_information.release_channel.clone(), + application_information.install_time.clone(), + crash_time, + startup_time, + ui_hang, + ); + CrashReport { + uuid, + crash_reports_path, + release_channel: application_information.release_channel.clone(), + annotations, + crash_time, + } + } + + fn is_nightly(&self) -> bool { + self.release_channel == "nightly" || self.release_channel == "default" + } + + fn get_minidump_type(&self) -> MINIDUMP_TYPE { + let mut minidump_type = MiniDumpWithFullMemoryInfo | MiniDumpWithUnloadedModules; + if self.is_nightly() { + // This is Nightly only because this doubles the size of minidumps based + // on the experimental data. + minidump_type = minidump_type | MiniDumpWithProcessThreadData; + + // dbghelp.dll on Win7 can't handle overlapping memory regions so we only + // enable this feature on Win8 or later. + if is_windows8_or_later() { + // This allows us to examine heap objects referenced from stack objects + // at the cost of further doubling the size of minidumps. + minidump_type = minidump_type | MiniDumpWithIndirectlyReferencedMemory + } + } + minidump_type + } + + fn get_pending_path(&self) -> PathBuf { + self.crash_reports_path.join("pending") + } + + fn get_events_path(&self) -> PathBuf { + self.crash_reports_path.join("events") + } + + fn get_minidump_path(&self) -> PathBuf { + self.get_pending_path().join(self.uuid.to_string() + ".dmp") + } + + fn get_minidump_name(&self) -> [u8; 40] { + let bytes = (self.uuid.to_string() + ".dmp").into_bytes(); + bytes[0..40].try_into().unwrap() + } + + fn get_extra_file_path(&self) -> PathBuf { + self.get_pending_path() + .join(self.uuid.to_string() + ".extra") + } + + fn get_event_file_path(&self) -> PathBuf { + self.get_events_path().join(self.uuid.to_string()) + } + + fn write_minidump( + &self, + exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION, + ) -> Result<()> { + // Make sure that the target directory is present + DirBuilder::new() + .recursive(true) + .create(self.get_pending_path()) + .map_err(|_e| ())?; + + let minidump_path = self.get_minidump_path(); + let minidump_file = File::create(minidump_path).map_err(|_e| ())?; + let minidump_type: MINIDUMP_TYPE = self.get_minidump_type(); + + unsafe { + let mut exception_pointers = EXCEPTION_POINTERS { + ExceptionRecord: &mut ((*exception_information).exceptionRecord), + ContextRecord: &mut ((*exception_information).context), + }; + + let mut exception = MINIDUMP_EXCEPTION_INFORMATION { + ThreadId: GetThreadId((*exception_information).hThread), + ExceptionPointers: &mut exception_pointers, + ClientPointers: FALSE, + }; + + MiniDumpWriteDump( + (*exception_information).hProcess, + get_process_id((*exception_information).hProcess)?, + minidump_file.as_raw_handle() as _, + minidump_type, + &mut exception, + /* userStream */ null(), + /* callback */ null(), + ) + .success() + } + } + + fn write_extra_file(&self) -> Result<()> { + let extra_file = File::create(self.get_extra_file_path()).map_err(|_e| ())?; + to_writer(extra_file, &self.annotations).map_err(|_e| ()) + } + + fn write_event_file(&self) -> Result<()> { + // Make that the target directory is present + DirBuilder::new() + .recursive(true) + .create(self.get_events_path()) + .map_err(|_e| ())?; + + let mut event_file = File::create(self.get_event_file_path()).map_err(|_e| ())?; + writeln!(event_file, "crash.main.3").map_err(|_e| ())?; + writeln!(event_file, "{}", self.crash_time).map_err(|_e| ())?; + writeln!(event_file, "{}", self.uuid).map_err(|_e| ())?; + to_writer(event_file, &self.annotations).map_err(|_e| ()) + } +} + +fn is_windows8_or_later() -> bool { + let mut info = OSVERSIONINFOEXW { + dwOSVersionInfoSize: size_of::().try_into().unwrap(), + dwMajorVersion: 6, + dwMinorVersion: 2, + ..unsafe { zeroed() } + }; + + unsafe { + let mut mask: DWORDLONG = 0; + let ge: u8 = VER_GREATER_EQUAL.try_into().unwrap(); + mask = VerSetConditionMask(mask, VER_MAJORVERSION, ge); + mask = VerSetConditionMask(mask, VER_MINORVERSION, ge); + mask = VerSetConditionMask(mask, VER_SERVICEPACKMAJOR, ge); + mask = VerSetConditionMask(mask, VER_SERVICEPACKMINOR, ge); + + VerifyVersionInfoW( + &mut info, + VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, + mask, + ) + .to_bool() + } +} + +trait WinBool: Sized { + fn to_bool(self) -> bool; + fn if_true(self, value: T) -> Result { + if self.to_bool() { + Ok(value) + } else { + Err(()) + } + } + fn success(self) -> Result<()> { + self.if_true(()) + } +} + +impl WinBool for BOOL { + fn to_bool(self) -> bool { + match self { + FALSE => false, + _ => true, + } + } +} + +fn get_process_basic_information(process: HANDLE) -> Result { + let mut pbi: PROCESS_BASIC_INFORMATION = unsafe { zeroed() }; + let mut length: ULONG = 0; + let result = unsafe { + NtQueryInformationProcess( + process, + ProcessBasicInformation, + &mut pbi as *mut _ as _, + size_of::().try_into().unwrap(), + &mut length, + ) + }; + + if result != STATUS_SUCCESS { + return Err(()); + } + + Ok(pbi) +} + +fn is_sandboxed_process(process: HANDLE) -> Result { + let mut token: HANDLE = 0; + let res = unsafe { OpenProcessToken(process, TOKEN_QUERY, &mut token as *mut _) }; + + if res != TRUE { + return Err(()); + } + + let is_restricted = unsafe { IsTokenRestricted(token) } != FALSE; + + unsafe { SetLastError(ERROR_SUCCESS) }; + let mut buffer_size: DWORD = 0; + let res = unsafe { + GetTokenInformation( + token, + TokenIntegrityLevel, + null_mut(), + 0, + &mut buffer_size as *mut _, + ) + }; + + if (res != FALSE) || (unsafe { GetLastError() } != ERROR_INSUFFICIENT_BUFFER) { + return Err(()); + } + + let mut buffer: Vec = vec![Default::default(); buffer_size as usize]; + let res = unsafe { + GetTokenInformation( + token, + TokenIntegrityLevel, + buffer.as_mut_ptr() as *mut _, + buffer_size, + &mut buffer_size as *mut _, + ) + }; + + if res != TRUE { + return Err(()); + } + + let token_mandatory_label = &unsafe { *(buffer.as_ptr() as *const TOKEN_MANDATORY_LABEL) }; + let sid = token_mandatory_label.Label.Sid; + // We're not checking for errors in the following two calls because these + // functions can only fail if provided with an invalid SID and we know the + // one we obtained from `GetTokenInformation()` is valid. + let sid_subauthority_count = unsafe { *GetSidSubAuthorityCount(sid) - 1u8 }; + let integrity_level = unsafe { *GetSidSubAuthority(sid, sid_subauthority_count.into()) }; + + Ok((integrity_level < SECURITY_MANDATORY_MEDIUM_RID as u32) || is_restricted) +} diff --git a/toolkit/crashreporter/mozwer-rust/moz.build b/toolkit/crashreporter/mozwer-rust/moz.build new file mode 100644 index 0000000000..980547f8e8 --- /dev/null +++ b/toolkit/crashreporter/mozwer-rust/moz.build @@ -0,0 +1,13 @@ +RustLibrary("mozwer_s") + +OS_LIBS += [ + "dbghelp", + "kernel32", + "ntdll", + "ole32", + "psapi", + "shell32", + "user32", + "userenv", + "ws2_32", +] diff --git a/toolkit/crashreporter/mozwer/moz.build b/toolkit/crashreporter/mozwer/moz.build new file mode 100644 index 0000000000..1f6418fd48 --- /dev/null +++ b/toolkit/crashreporter/mozwer/moz.build @@ -0,0 +1,17 @@ +UNIFIED_SOURCES = [ + "mozwer.cpp", +] + +USE_LIBS += [ + "mozwer_s", +] + +OS_LIBS += [ + "advapi32", + "bcrypt", +] + +DEFFILE = "mozwer.def" +USE_STATIC_LIBS = True + +SharedLibrary("mozwer") diff --git a/toolkit/crashreporter/mozwer/mozwer.cpp b/toolkit/crashreporter/mozwer/mozwer.cpp new file mode 100644 index 0000000000..4f4c184949 --- /dev/null +++ b/toolkit/crashreporter/mozwer/mozwer.cpp @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "nscore.h" + +extern "C" { + +NS_EXPORT_(BOOL) +DllMain(HINSTANCE DllInstance, DWORD Reason, LPVOID Reserved) { + UNREFERENCED_PARAMETER(DllInstance); + UNREFERENCED_PARAMETER(Reason); + UNREFERENCED_PARAMETER(Reserved); + + return TRUE; +} + +} /* extern "C" */ diff --git a/toolkit/crashreporter/mozwer/mozwer.def b/toolkit/crashreporter/mozwer/mozwer.def new file mode 100644 index 0000000000..b9ea6ed3ac --- /dev/null +++ b/toolkit/crashreporter/mozwer/mozwer.def @@ -0,0 +1,5 @@ +LIBRARY +EXPORTS + OutOfProcessExceptionEventCallback + OutOfProcessExceptionEventSignatureCallback + OutOfProcessExceptionEventDebuggerLaunchCallback diff --git a/toolkit/crashreporter/nsDummyExceptionHandler.cpp b/toolkit/crashreporter/nsDummyExceptionHandler.cpp new file mode 100644 index 0000000000..7ccede695f --- /dev/null +++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include + +#include "nsExceptionHandler.h" +#include "nsExceptionHandlerUtils.h" + +namespace CrashReporter { + +void AnnotateOOMAllocationSize(size_t size) {} + +void AnnotateTexturesSize(size_t size) {} + +void AnnotatePendingIPC(size_t aNumOfPendingIPC, uint32_t aTopPendingIPCCount, + const char* aTopPendingIPCName, + uint32_t aTopPendingIPCType) {} + +nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force /*=false*/) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +bool GetEnabled() { return false; } + +bool GetMinidumpPath(nsAString& aPath) { return false; } + +nsresult SetMinidumpPath(const nsAString& aPath) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult SetupExtraData(nsIFile* aAppDataDirectory, + const nsACString& aBuildID) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult UnsetExceptionHandler() { return NS_ERROR_NOT_IMPLEMENTED; } + +nsresult AnnotateCrashReport(Annotation key, bool data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult AnnotateCrashReport(Annotation key, int data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult AnnotateCrashReport(Annotation key, unsigned int data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult AnnotateCrashReport(Annotation key, const nsACString& data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult AppendToCrashReportAnnotation(Annotation key, const nsACString& data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult RemoveCrashReportAnnotation(Annotation key) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, bool data) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, int data) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, + unsigned data) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, + const nsACString& data) {} + +AutoAnnotateCrashReport::~AutoAnnotateCrashReport() {} + +void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc) { +} + +nsresult SetGarbageCollecting(bool collecting) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +void SetEventloopNestingLevel(uint32_t level) {} + +void SetMinidumpAnalysisAllThreads() {} + +nsresult AppendAppNotesToCrashReport(const nsACString& data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +bool GetAnnotation(const nsACString& key, nsACString& data) { return false; } + +void GetAnnotation(uint32_t childPid, Annotation annotation, + nsACString& outStr) { + return; +} + +nsresult RegisterAppMemory(void* ptr, size_t length) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult UnregisterAppMemory(void* ptr) { return NS_ERROR_NOT_IMPLEMENTED; } + +void SetIncludeContextHeap(bool aValue) {} + +bool GetServerURL(nsACString& aServerURL) { return false; } + +nsresult SetServerURL(const nsACString& aServerURL) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult SetRestartArgs(int argc, char** argv) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +#ifdef XP_WIN +nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo) { + return NS_ERROR_NOT_IMPLEMENTED; +} +#endif + +#ifdef XP_LINUX +bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc) { + return false; +} +#endif + +#ifdef XP_MACOSX +nsresult AppendObjCExceptionInfoToAppNotes(void* inException) { + return NS_ERROR_NOT_IMPLEMENTED; +} +#endif + +nsresult GetSubmitReports(bool* aSubmitReports) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult SetSubmitReports(bool aSubmitReports) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +void SetProfileDirectory(nsIFile* aDir) {} + +void SetUserAppDataDirectory(nsIFile* aDir) {} + +void UpdateCrashEventsDir() {} + +bool GetCrashEventsDir(nsAString& aPath) { return false; } + +void SetMemoryReportFile(nsIFile* aFile) {} + +nsresult GetDefaultMemoryReportFile(nsIFile** aFile) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +void DeleteMinidumpFilesForID(const nsAString& aId, + const Maybe& aAdditionalMinidump) {} + +bool GetMinidumpForID(const nsAString& id, nsIFile** minidump, + const Maybe& aAdditionalMinidump) { + return false; +} + +bool GetIDFromMinidump(nsIFile* minidump, nsAString& id) { return false; } + +bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile) { + return false; +} + +bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile) { + return false; +} + +bool WriteExtraFile(const nsAString& id, const AnnotationTable& annotations) { + return false; +} + +void OOPInit() {} + +#if defined(XP_WIN) || defined(XP_MACOSX) +const char* GetChildNotificationPipe() { return nullptr; } +#endif + +#ifdef MOZ_CRASHREPORTER_INJECTOR +void InjectCrashReporterIntoProcess(DWORD processID, + InjectorCrashCallback* cb) {} + +void UnregisterInjectorCallback(DWORD processID) {} + +#endif // MOZ_CRASHREPORTER_INJECTOR + +bool GetLastRunCrashID(nsAString& id) { return false; } + +#if !defined(XP_WIN) && !defined(XP_MACOSX) + +bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) { + return false; +} + +#endif // !defined(XP_WIN) && !defined(XP_MACOSX) + +bool SetRemoteExceptionHandler(const char* aCrashPipe) { return false; } + +bool TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, + AnnotationTable& aAnnotations, uint32_t* aSequence) { + return false; +} + +bool FinalizeOrphanedMinidump(uint32_t aChildPid, GeckoProcessType aType, + nsString* aDumpId) { + return false; +} + +#if defined(XP_WIN) + +DWORD WINAPI WerNotifyProc(LPVOID aParameter) { return 0; } + +#endif // defined(XP_WIN) + +ThreadId CurrentThreadId() { return -1; } + +bool TakeMinidump(nsIFile** aResult, bool aMoveToPending) { return false; } + +bool CreateMinidumpsAndPair(ProcessHandle aTargetPid, + ThreadId aTargetBlamedThread, + const nsACString& aIncomingPairName, + AnnotationTable& aTargetAnnotations, + nsIFile** aTargetDumpOut) { + return false; +} + +bool UnsetRemoteExceptionHandler(bool wasSet) { return false; } + +#if defined(MOZ_WIDGET_ANDROID) +void SetNotificationPipeForChild(FileHandle childCrashFd) {} + +void AddLibraryMapping(const char* library_name, uintptr_t start_address, + size_t mapping_length, size_t file_offset) {} +#endif + +} // namespace CrashReporter diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp new file mode 100644 index 0000000000..ceb021f7f3 --- /dev/null +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -0,0 +1,3926 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsExceptionHandler.h" +#include "nsExceptionHandlerUtils.h" + +#include "nsAppDirectoryServiceDefs.h" +#include "nsComponentManagerUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryService.h" +#include "nsString.h" +#include "nsTHashMap.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/EnumeratedRange.h" +#include "mozilla/Services.h" +#include "nsIObserverService.h" +#include "mozilla/Unused.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Printf.h" +#include "mozilla/RuntimeExceptionModule.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/Sprintf.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/SyncRunnable.h" +#include "mozilla/TimeStamp.h" + +#include "nsPrintfCString.h" +#include "nsThreadUtils.h" +#include "nsThread.h" +#include "jsfriendapi.h" +#include "private/pprio.h" +#include "base/process_util.h" +#include "common/basictypes.h" + +#include "mozilla/toolkit/crashreporter/mozannotation_client_ffi_generated.h" +#include "mozilla/toolkit/crashreporter/mozannotation_server_ffi_generated.h" + +#if defined(XP_WIN) +# ifdef WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +# endif + +# include "nsXULAppAPI.h" +# include "nsIXULAppInfo.h" +# include "nsIWindowsRegKey.h" +# include "breakpad-client/windows/crash_generation/client_info.h" +# include "breakpad-client/windows/crash_generation/crash_generation_server.h" +# include "breakpad-client/windows/handler/exception_handler.h" +# include +# include +# include "nsDirectoryServiceUtils.h" + +# include "nsWindowsDllInterceptor.h" +# include "mozilla/WindowsDllBlocklist.h" +# include "psapi.h" // For PERFORMANCE_INFORMATION and K32GetPerformanceInfo() +#elif defined(XP_MACOSX) +# include "breakpad-client/mac/crash_generation/client_info.h" +# include "breakpad-client/mac/crash_generation/crash_generation_server.h" +# include "breakpad-client/mac/handler/exception_handler.h" +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "mac_utils.h" +#elif defined(XP_LINUX) +# include "nsIINIParser.h" +# include "common/linux/linux_libc_support.h" +# include "third_party/lss/linux_syscall_support.h" +# include "breakpad-client/linux/crash_generation/client_info.h" +# include "breakpad-client/linux/crash_generation/crash_generation_server.h" +# include "breakpad-client/linux/handler/exception_handler.h" +# include "common/linux/eintr_wrapper.h" +# include +# include +# include "sys/sysinfo.h" +# include +# include +#else +# error "Not yet implemented for this platform" +#endif // defined(XP_WIN) + +#ifdef MOZ_CRASHREPORTER_INJECTOR +# include "InjectCrashReporter.h" +using mozilla::InjectCrashRunnable; +#endif + +#include +#include +#include +#include +#include "mozilla/Mutex.h" +#include "nsDebug.h" +#include "nsCRT.h" +#include "nsIFile.h" + +#include "mozilla/IOInterposer.h" +#include "mozilla/mozalloc_oom.h" + +#if defined(XP_MACOSX) +CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter"); +#endif +#if defined(MOZ_WIDGET_ANDROID) +# include "common/linux/file_id.h" +#endif + +using google_breakpad::ClientInfo; +using google_breakpad::CrashGenerationServer; +#ifdef XP_LINUX +using google_breakpad::MinidumpDescriptor; +#elif defined(XP_WIN) +using google_breakpad::ExceptionHandler; +#endif +#if defined(MOZ_WIDGET_ANDROID) +using google_breakpad::auto_wasteful_vector; +using google_breakpad::FileID; +using google_breakpad::kDefaultBuildIdSize; +using google_breakpad::PageAllocator; +#endif +using namespace mozilla; + +namespace mozilla::phc { + +// Global instance that is retrieved by the process generating the crash report +mozilla::phc::AddrInfo gAddrInfo; + +} // namespace mozilla::phc + +namespace CrashReporter { + +#ifdef XP_WIN +typedef wchar_t XP_CHAR; +typedef std::wstring xpstring; +# define XP_TEXT(x) L##x +# define CONVERT_XP_CHAR_TO_UTF16(x) x +# define XP_STRLEN(x) wcslen(x) +# define my_strlen strlen +# define my_memchr memchr +# define CRASH_REPORTER_FILENAME u"crashreporter.exe"_ns +# define XP_PATH_SEPARATOR L"\\" +# define XP_PATH_SEPARATOR_CHAR L'\\' +# define XP_PATH_MAX (MAX_PATH + 1) +// "" "" +# define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6) +# define XP_TTOA(time, buffer) _i64toa((time), (buffer), 10) +# define XP_STOA(size, buffer) _ui64toa((size), (buffer), 10) +#else +typedef char XP_CHAR; +typedef std::string xpstring; +# define XP_TEXT(x) x +# define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x) +# define CRASH_REPORTER_FILENAME u"crashreporter"_ns +# define XP_PATH_SEPARATOR "/" +# define XP_PATH_SEPARATOR_CHAR '/' +# define XP_PATH_MAX PATH_MAX +# ifdef XP_LINUX +# define XP_STRLEN(x) my_strlen(x) +# define XP_TTOA(time, buffer) \ + my_u64tostring(uint64_t(time), (buffer), sizeof(buffer)) +# define XP_STOA(size, buffer) \ + my_u64tostring((size), (buffer), sizeof(buffer)) +# else +# define XP_STRLEN(x) strlen(x) +# define XP_TTOA(time, buffer) sprintf(buffer, "%" PRIu64, uint64_t(time)) +# define XP_STOA(size, buffer) sprintf(buffer, "%zu", size_t(size)) +# define my_strlen strlen +# define my_memchr memchr +# define sys_close close +# define sys_fork fork +# define sys_open open +# define sys_read read +# define sys_write write +# endif +#endif // XP_WIN + +#if defined(__GNUC__) +# define MAYBE_UNUSED __attribute__((unused)) +#else +# define MAYBE_UNUSED +#endif // defined(__GNUC__) + +#ifndef XP_LINUX +static const XP_CHAR dumpFileExtension[] = XP_TEXT(".dmp"); +#endif + +static const XP_CHAR extraFileExtension[] = XP_TEXT(".extra"); +static const XP_CHAR memoryReportExtension[] = XP_TEXT(".memory.json.gz"); +static xpstring* defaultMemoryReportPath = nullptr; + +static const char kCrashMainID[] = "crash.main.3\n"; + +static google_breakpad::ExceptionHandler* gExceptionHandler = nullptr; +static mozilla::Atomic gEncounteredChildException(false); + +static xpstring pendingDirectory; +static xpstring crashReporterPath; +static xpstring memoryReportPath; + +// Where crash events should go. +static xpstring eventsDirectory; + +// If this is false, we don't launch the crash reporter +static bool doReport = true; + +// if this is true, we pass the exception on to the OS crash reporter +static bool showOSCrashReporter = false; + +// The time of the last recorded crash, as a time_t value. +static time_t lastCrashTime = 0; +// The pathname of a file to store the crash time in +static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0}; + +#if defined(MOZ_WIDGET_ANDROID) +// on Android 4.2 and above there is a user serial number associated +// with the current process that gets lost when we fork so we need to +// explicitly pass it to am +static char* androidUserSerial = nullptr; + +// Before Android 8 we needed to use "startservice" to start the crash reporting +// service. After Android 8 we need to use "start-foreground-service" +static const char* androidStartServiceCommand = nullptr; +#endif + +// this holds additional data sent via the API +static Mutex* crashReporterAPILock; +static Mutex* notesFieldLock; +static AnnotationTable crashReporterAPIData_Table; +static nsCString* notesField = nullptr; +static bool isGarbageCollecting; +static uint32_t eventloopNestingLevel = 0; +static time_t inactiveStateStart = 0; + +static +#if defined(XP_UNIX) + pthread_t +#elif defined(XP_WIN) // defined(XP_UNIX) + DWORD +#endif // defined(XP_WIN) + gMainThreadId = 0; + +// Avoid a race during application termination. +static Mutex* dumpSafetyLock; +static bool isSafeToDump = false; + +// Whether to include heap regions of the crash context. +static bool sIncludeContextHeap = false; + +// OOP crash reporting +static CrashGenerationServer* crashServer; // chrome process has this + +static std::terminate_handler oldTerminateHandler = nullptr; + +#if defined(XP_WIN) || defined(XP_MACOSX) +// If crash reporting is disabled, we hand out this "null" pipe to the +// child process and don't attempt to connect to a parent server. +static const char kNullNotifyPipe[] = "-"; +static char* childCrashNotifyPipe; + +#elif defined(XP_LINUX) +static int serverSocketFd = -1; +static int clientSocketFd = -1; + +// On Linux these file descriptors are created in the parent process and +// remapped in the child ones. See PosixProcessLauncher::DoSetup() for more +// details. +static FileHandle gMagicChildCrashReportFd = +# if defined(MOZ_WIDGET_ANDROID) + // On android the fd is set at the time of child creation. + kInvalidFileHandle +# else + 4 +# endif // defined(MOZ_WIDGET_ANDROID) + ; +#endif + +// |dumpMapLock| must protect all access to |pidToMinidump|. +static Mutex* dumpMapLock; +struct ChildProcessData : public nsUint32HashKey { + explicit ChildProcessData(KeyTypePointer aKey) + : nsUint32HashKey(aKey), + sequence(0), + annotations(nullptr), + minidumpOnly(false) +#ifdef MOZ_CRASHREPORTER_INJECTOR + , + callback(nullptr) +#endif + { + } + + nsCOMPtr minidump; + // Each crashing process is assigned an increasing sequence number to + // indicate which process crashed first. + uint32_t sequence; + UniquePtr annotations; + bool minidumpOnly; // If true then no annotations are present +#ifdef MOZ_CRASHREPORTER_INJECTOR + InjectorCrashCallback* callback; +#endif +}; + +typedef nsTHashtable ChildMinidumpMap; +static ChildMinidumpMap* pidToMinidump; +static uint32_t crashSequence; +static bool OOPInitialized(); + +#ifdef MOZ_CRASHREPORTER_INJECTOR +static nsIThread* sInjectorThread; + +class ReportInjectedCrash : public Runnable { + public: + explicit ReportInjectedCrash(uint32_t pid) + : Runnable("ReportInjectedCrash"), mPID(pid) {} + + NS_IMETHOD Run() override; + + private: + uint32_t mPID; +}; +#endif // MOZ_CRASHREPORTER_INJECTOR + +void RecordMainThreadId() { + gMainThreadId = +#if defined(XP_UNIX) + pthread_self() +#elif defined(XP_WIN) // defined(XP_UNIX) + GetCurrentThreadId() +#endif // defined(XP_WIN) + ; +} + +bool SignalSafeIsMainThread() { + // We can't rely on NS_IsMainThread() because we are in a signal handler, and + // sTLSIsMainThread is a thread local variable and it can be lazy allocated + // i.e., we could hit code path where this variable has not been accessed + // before and needs to be allocated right now, which will lead to spinlock + // deadlock effectively hanging the process, as in bug 1756407. + +#if defined(XP_UNIX) + pthread_t th = pthread_self(); + return pthread_equal(th, gMainThreadId); +#elif defined(XP_WIN) // defined(XP_UNIX) + DWORD th = GetCurrentThreadId(); + return th == gMainThreadId; +#endif // defined(XP_WIN) +} + +#if defined(XP_WIN) +// the following are used to prevent other DLLs reverting the last chance +// exception handler to the windows default. Any attempt to change the +// unhandled exception filter or to reset it is ignored and our crash +// reporter is loaded instead (in case it became unloaded somehow) +typedef LPTOP_LEVEL_EXCEPTION_FILTER(WINAPI* SetUnhandledExceptionFilter_func)( + LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); +static WindowsDllInterceptor::FuncHookType + stub_SetUnhandledExceptionFilter; +static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; +static WindowsDllInterceptor gKernel32Intercept; +static bool gBlockUnhandledExceptionFilter = true; + +static LPTOP_LEVEL_EXCEPTION_FILTER GetUnhandledExceptionFilter() { + // Set a dummy value to get the current filter, then restore + LPTOP_LEVEL_EXCEPTION_FILTER current = SetUnhandledExceptionFilter(nullptr); + SetUnhandledExceptionFilter(current); + return current; +} + +static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI patched_SetUnhandledExceptionFilter( + LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { + if (!gBlockUnhandledExceptionFilter) { + // don't intercept + return stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); + } + + if (lpTopLevelExceptionFilter == previousUnhandledExceptionFilter) { + // OK to swap back and forth between the previous filter + previousUnhandledExceptionFilter = + stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); + return previousUnhandledExceptionFilter; + } + + // intercept attempts to change the filter + return nullptr; +} + +# if defined(HAVE_64BIT_BUILD) +static LPTOP_LEVEL_EXCEPTION_FILTER sUnhandledExceptionFilter = nullptr; + +static long JitExceptionHandler(void* exceptionRecord, void* context) { + EXCEPTION_POINTERS pointers = {(PEXCEPTION_RECORD)exceptionRecord, + (PCONTEXT)context}; + return sUnhandledExceptionFilter(&pointers); +} + +static void SetJitExceptionHandler() { + sUnhandledExceptionFilter = GetUnhandledExceptionFilter(); + if (sUnhandledExceptionFilter) + js::SetJitExceptionHandler(JitExceptionHandler); +} +# endif + +/** + * Reserve some VM space. In the event that we crash because VM space is + * being leaked without leaking memory, freeing this space before taking + * the minidump will allow us to collect a minidump. + * + * This size is bigger than xul.dll plus some extra for MinidumpWriteDump + * allocations. + */ +static const SIZE_T kReserveSize = 0x5000000; // 80 MB +static void* gBreakpadReservedVM; +#endif + +#ifdef XP_LINUX +static inline void my_u64tostring(uint64_t aValue, char* aBuffer, + size_t aBufferLength) { + my_memset(aBuffer, 0, aBufferLength); + my_uitos(aBuffer, aValue, my_uint_len(aValue)); +} +#endif + +#ifdef XP_WIN +static void CreateFileFromPath(const xpstring& path, nsIFile** file) { + NS_NewLocalFile(nsDependentString(path.c_str()), false, file); +} + +static xpstring* CreatePathFromFile(nsIFile* file) { + nsAutoString path; + nsresult rv = file->GetPath(path); + if (NS_FAILED(rv)) { + return nullptr; + } + return new xpstring(static_cast(path.get()), path.Length()); +} +#else +static void CreateFileFromPath(const xpstring& path, nsIFile** file) { + NS_NewNativeLocalFile(nsDependentCString(path.c_str()), false, file); +} + +MAYBE_UNUSED static xpstring* CreatePathFromFile(nsIFile* file) { + nsAutoCString path; + nsresult rv = file->GetNativePath(path); + if (NS_FAILED(rv)) { + return nullptr; + } + return new xpstring(path.get(), path.Length()); +} +#endif + +static time_t GetCurrentTimeForCrashTime() { +#ifdef XP_LINUX + struct kernel_timeval tv; + sys_gettimeofday(&tv, nullptr); + return tv.tv_sec; +#else + return time(nullptr); +#endif +} + +static XP_CHAR* Concat(XP_CHAR* str, const XP_CHAR* toAppend, size_t* size) { + size_t appendLen = XP_STRLEN(toAppend); + if (appendLen >= *size) { + appendLen = *size - 1; + } + + memcpy(str, toAppend, appendLen * sizeof(XP_CHAR)); + str += appendLen; + *str = '\0'; + *size -= appendLen; + + return str; +} + +void AnnotateOOMAllocationSize(size_t size) { gOOMAllocationSize = size; } + +static size_t gTexturesSize = 0; + +void AnnotateTexturesSize(size_t size) { gTexturesSize = size; } + +#ifndef XP_WIN +// Like Windows CopyFile for *nix +// +// This function is not declared static even though it's not used outside of +// this file because of an issue in Fennec which prevents breakpad's exception +// handler from invoking the MinidumpCallback function. See bug 1424304. +bool copy_file(const char* from, const char* to) { + const int kBufSize = 4096; + int fdfrom = sys_open(from, O_RDONLY, 0); + if (fdfrom < 0) { + return false; + } + + bool ok = false; + + int fdto = sys_open(to, O_WRONLY | O_CREAT, 0666); + if (fdto < 0) { + sys_close(fdfrom); + return false; + } + + char buf[kBufSize]; + while (true) { + int r = sys_read(fdfrom, buf, kBufSize); + if (r == 0) { + ok = true; + break; + } + if (r < 0) { + break; + } + char* wbuf = buf; + while (r) { + int w = sys_write(fdto, wbuf, r); + if (w > 0) { + r -= w; + wbuf += w; + } else if (errno != EINTR) { + break; + } + } + if (r) { + break; + } + } + + sys_close(fdfrom); + sys_close(fdto); + + return ok; +} +#endif + +/** + * The PlatformWriter class provides a tool to create and write to a file that + * is safe to call from within an exception handler. To use it this way the + * file path needs to be provided as a bare C string. + */ +class PlatformWriter { + public: + PlatformWriter() : mBuffer{}, mPos(0), mFD(kInvalidFileHandle) {} + explicit PlatformWriter(const XP_CHAR* aPath) : PlatformWriter() { + Open(aPath); + } + + ~PlatformWriter() { + if (Valid()) { + Flush(); +#ifdef XP_WIN + CloseHandle(mFD); +#elif defined(XP_UNIX) + sys_close(mFD); +#endif + } + } + + void Open(const XP_CHAR* aPath) { +#ifdef XP_WIN + mFD = CreateFile(aPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); +#elif defined(XP_UNIX) + mFD = sys_open(aPath, O_WRONLY | O_CREAT | O_TRUNC, 0600); +#endif + } + + void OpenHandle(FileHandle aFD) { mFD = aFD; } + bool Valid() { return mFD != kInvalidFileHandle; } + + void WriteBuffer(const char* aBuffer, size_t aLen) { + if (!Valid()) { + return; + } + + while (aLen-- > 0) { + WriteChar(*aBuffer++); + } + } + + void WriteString(const char* aStr) { WriteBuffer(aStr, my_strlen(aStr)); } + + template + void WriteLiteral(const char (&aStr)[N]) { + WriteBuffer(aStr, N - 1); + } + + FileHandle FileDesc() { return mFD; } + + private: + PlatformWriter(const PlatformWriter&) = delete; + + const PlatformWriter& operator=(const PlatformWriter&) = delete; + + void WriteChar(char aChar) { + if (mPos == kBufferSize) { + Flush(); + } + + mBuffer[mPos++] = aChar; + } + + void Flush() { + if (mPos > 0) { + char* buffer = mBuffer; + size_t length = mPos; + while (length > 0) { +#ifdef XP_WIN + DWORD written_bytes = 0; + if (!WriteFile(mFD, buffer, length, &written_bytes, nullptr)) { + break; + } +#elif defined(XP_UNIX) + ssize_t written_bytes = sys_write(mFD, buffer, length); + if (written_bytes < 0) { + if (errno == EAGAIN) { + continue; + } + + break; + } +#endif + buffer += written_bytes; + length -= written_bytes; + } + + mPos = 0; + } + } + + static const size_t kBufferSize = 512; + + char mBuffer[kBufferSize]; + size_t mPos; + FileHandle mFD; +}; + +class JSONAnnotationWriter : public AnnotationWriter { + public: + explicit JSONAnnotationWriter(PlatformWriter& aPlatformWriter) + : mWriter(aPlatformWriter), mEmpty(true) { + mWriter.WriteBuffer("{", 1); + } + + ~JSONAnnotationWriter() { mWriter.WriteBuffer("}", 1); } + + void Write(Annotation aAnnotation, const char* aValue, + size_t aLen = 0) override { + size_t len = aLen ? aLen : my_strlen(aValue); + const char* annotationStr = AnnotationToString(aAnnotation); + + WritePrefix(); + mWriter.WriteBuffer(annotationStr, my_strlen(annotationStr)); + WriteSeparator(); + WriteEscapedString(aValue, len); + WriteSuffix(); + }; + + void Write(Annotation aAnnotation, uint64_t aValue) override { + char buffer[32] = {}; + XP_STOA(aValue, buffer); + Write(aAnnotation, buffer); + }; + + private: + void WritePrefix() { + if (mEmpty) { + mWriter.WriteBuffer("\"", 1); + mEmpty = false; + } else { + mWriter.WriteBuffer(",\"", 2); + } + } + + void WriteSeparator() { mWriter.WriteBuffer("\":\"", 3); } + void WriteSuffix() { mWriter.WriteBuffer("\"", 1); } + void WriteEscapedString(const char* aStr, size_t aLen) { + for (size_t i = 0; i < aLen; i++) { + uint8_t c = aStr[i]; + if (c <= 0x1f || c == '\\' || c == '\"') { + mWriter.WriteBuffer("\\u00", 4); + WriteHexDigitAsAsciiChar((c & 0x00f0) >> 4); + WriteHexDigitAsAsciiChar(c & 0x000f); + } else { + mWriter.WriteBuffer(aStr + i, 1); + } + } + } + + void WriteHexDigitAsAsciiChar(uint8_t u) { + char buf[1]; + buf[0] = static_cast((u < 10) ? '0' + u : 'a' + (u - 10)); + mWriter.WriteBuffer(buf, 1); + } + + PlatformWriter& mWriter; + bool mEmpty; +}; + +class BinaryAnnotationWriter : public AnnotationWriter { + public: + explicit BinaryAnnotationWriter(PlatformWriter& aPlatformWriter) + : mPlatformWriter(aPlatformWriter) {} + + void Write(Annotation aAnnotation, const char* aValue, + size_t aLen = 0) override { + uint64_t len = aLen ? aLen : my_strlen(aValue); + mPlatformWriter.WriteBuffer((const char*)&aAnnotation, sizeof(aAnnotation)); + mPlatformWriter.WriteBuffer((const char*)&len, sizeof(len)); + mPlatformWriter.WriteBuffer(aValue, len); + }; + + void Write(Annotation aAnnotation, uint64_t aValue) override { + char buffer[32] = {}; + XP_STOA(aValue, buffer); + Write(aAnnotation, buffer); + }; + + private: + PlatformWriter& mPlatformWriter; +}; + +#ifdef MOZ_PHC + +// 21 is the max length of a 64-bit decimal address entry, including the +// trailing comma or '\0'. And then we add another 32 just to be safe. +const size_t phcStringifiedAnnotationSize = + (mozilla::phc::StackTrace::kMaxFrames * 21) + 32; + +static void PHCStackTraceToString(char* aBuffer, size_t aBufferLen, + const phc::StackTrace& aStack) { + char addrString[32]; + *aBuffer = 0; + for (size_t i = 0; i < aStack.mLength; i++) { + if (i != 0) { + strcat(aBuffer, ","); + } + XP_STOA(uintptr_t(aStack.mPcs[i]), addrString); + strncat(aBuffer, addrString, aBufferLen); + } +} + +// The stack traces are encoded as a comma-separated list of decimal +// (not hexadecimal!) addresses, e.g. "12345678,12345679,12345680". +static void WritePHCStackTrace(AnnotationWriter& aWriter, + const Annotation aName, + const Maybe& aStack) { + if (aStack.isNothing()) { + return; + } + + // 21 is the max length of a 64-bit decimal address entry, including the + // trailing comma or '\0'. And then we add another 32 just to be safe. + char addrsString[phcStringifiedAnnotationSize]; + PHCStackTraceToString(addrsString, sizeof(addrsString), *aStack); + aWriter.Write(aName, addrsString); +} + +static void WritePHCAddrInfo(AnnotationWriter& writer, + const phc::AddrInfo* aAddrInfo) { + // Is this a PHC allocation needing special treatment? + if (aAddrInfo && aAddrInfo->mKind != phc::AddrInfo::Kind::Unknown) { + const char* kindString; + switch (aAddrInfo->mKind) { + case phc::AddrInfo::Kind::Unknown: + kindString = "Unknown(?!)"; + break; + case phc::AddrInfo::Kind::NeverAllocatedPage: + kindString = "NeverAllocatedPage"; + break; + case phc::AddrInfo::Kind::InUsePage: + kindString = "InUsePage(?!)"; + break; + case phc::AddrInfo::Kind::FreedPage: + kindString = "FreedPage"; + break; + case phc::AddrInfo::Kind::GuardPage: + kindString = "GuardPage"; + break; + default: + kindString = "Unmatched(?!)"; + break; + } + writer.Write(Annotation::PHCKind, kindString); + writer.Write(Annotation::PHCBaseAddress, uintptr_t(aAddrInfo->mBaseAddr)); + writer.Write(Annotation::PHCUsableSize, aAddrInfo->mUsableSize); + + WritePHCStackTrace(writer, Annotation::PHCAllocStack, + aAddrInfo->mAllocStack); + WritePHCStackTrace(writer, Annotation::PHCFreeStack, aAddrInfo->mFreeStack); + } +} + +static void PopulatePHCStackTraceAnnotation( + AnnotationTable& aAnnotations, const Annotation aName, + const Maybe& aStack) { + if (aStack.isNothing()) { + return; + } + + char addrsString[phcStringifiedAnnotationSize]; + PHCStackTraceToString(addrsString, sizeof(addrsString), *aStack); + aAnnotations[aName] = addrsString; +} + +static void PopulatePHCAnnotations(AnnotationTable& aAnnotations, + const phc::AddrInfo* aAddrInfo) { + // Is this a PHC allocation needing special treatment? + if (aAddrInfo && aAddrInfo->mKind != phc::AddrInfo::Kind::Unknown) { + const char* kindString; + switch (aAddrInfo->mKind) { + case phc::AddrInfo::Kind::Unknown: + kindString = "Unknown(?!)"; + break; + case phc::AddrInfo::Kind::NeverAllocatedPage: + kindString = "NeverAllocatedPage"; + break; + case phc::AddrInfo::Kind::InUsePage: + kindString = "InUsePage(?!)"; + break; + case phc::AddrInfo::Kind::FreedPage: + kindString = "FreedPage"; + break; + case phc::AddrInfo::Kind::GuardPage: + kindString = "GuardPage"; + break; + default: + kindString = "Unmatched(?!)"; + break; + } + + aAnnotations[Annotation::PHCKind] = kindString; + aAnnotations[Annotation::PHCBaseAddress] = + nsPrintfCString("%zu", uintptr_t(aAddrInfo->mBaseAddr)); + aAnnotations[Annotation::PHCUsableSize] = + nsPrintfCString("%zu", aAddrInfo->mUsableSize); + PopulatePHCStackTraceAnnotation(aAnnotations, Annotation::PHCAllocStack, + aAddrInfo->mAllocStack); + PopulatePHCStackTraceAnnotation(aAnnotations, Annotation::PHCFreeStack, + aAddrInfo->mFreeStack); + } +} +#endif + +/** + * If minidump_id is null, we assume that dump_path contains the full + * dump file path. + */ +static void OpenAPIData(PlatformWriter& aWriter, const XP_CHAR* dump_path, + const XP_CHAR* minidump_id = nullptr) { + static XP_CHAR extraDataPath[XP_PATH_MAX]; + size_t size = XP_PATH_MAX; + XP_CHAR* p; + if (minidump_id) { + p = Concat(extraDataPath, dump_path, &size); + p = Concat(p, XP_PATH_SEPARATOR, &size); + p = Concat(p, minidump_id, &size); + } else { + p = Concat(extraDataPath, dump_path, &size); + // Skip back past the .dmp extension, if any. + if (*(p - 4) == XP_TEXT('.')) { + p -= 4; + size += 4; + } + } + Concat(p, extraFileExtension, &size); + aWriter.Open(extraDataPath); +} + +#ifdef XP_WIN +static void AnnotateMemoryStatus(AnnotationWriter& aWriter) { + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + if (GlobalMemoryStatusEx(&statex)) { + aWriter.Write(Annotation::SystemMemoryUsePercentage, statex.dwMemoryLoad); + aWriter.Write(Annotation::TotalVirtualMemory, statex.ullTotalVirtual); + aWriter.Write(Annotation::AvailableVirtualMemory, statex.ullAvailVirtual); + aWriter.Write(Annotation::TotalPhysicalMemory, statex.ullTotalPhys); + aWriter.Write(Annotation::AvailablePhysicalMemory, statex.ullAvailPhys); + } + + PERFORMANCE_INFORMATION info; + if (K32GetPerformanceInfo(&info, sizeof(info))) { + aWriter.Write(Annotation::TotalPageFile, info.CommitLimit * info.PageSize); + aWriter.Write(Annotation::AvailablePageFile, + (info.CommitLimit - info.CommitTotal) * info.PageSize); + } +} +#elif XP_MACOSX +// Extract the total physical memory of the system. +static void WritePhysicalMemoryStatus(AnnotationWriter& aWriter) { + uint64_t physicalMemoryByteSize = 0; + const size_t NAME_LEN = 2; + int name[NAME_LEN] = {/* Hardware */ CTL_HW, + /* 64-bit physical memory size */ HW_MEMSIZE}; + size_t infoByteSize = sizeof(physicalMemoryByteSize); + if (sysctl(name, NAME_LEN, &physicalMemoryByteSize, &infoByteSize, + /* We do not replace data */ nullptr, + /* We do not replace data */ 0) != -1) { + aWriter.Write(Annotation::TotalPhysicalMemory, physicalMemoryByteSize); + } +} + +// Extract available and purgeable physical memory. +static void WriteAvailableMemoryStatus(AnnotationWriter& aWriter) { + auto host = mach_host_self(); + vm_statistics64_data_t stats; + unsigned int count = HOST_VM_INFO64_COUNT; + if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&stats, &count) == + KERN_SUCCESS) { + aWriter.Write(Annotation::AvailablePhysicalMemory, + stats.free_count * vm_page_size); + aWriter.Write(Annotation::PurgeablePhysicalMemory, + stats.purgeable_count * vm_page_size); + } +} + +// Extract the status of the swap. +static void WriteSwapFileStatus(AnnotationWriter& aWriter) { + const size_t NAME_LEN = 2; + int name[] = {/* Hardware */ CTL_VM, + /* 64-bit physical memory size */ VM_SWAPUSAGE}; + struct xsw_usage swapUsage; + size_t infoByteSize = sizeof(swapUsage); + if (sysctl(name, NAME_LEN, &swapUsage, &infoByteSize, + /* We do not replace data */ nullptr, + /* We do not replace data */ 0) != -1) { + aWriter.Write(Annotation::AvailableSwapMemory, swapUsage.xsu_avail); + } +} +static void AnnotateMemoryStatus(AnnotationWriter& aWriter) { + WritePhysicalMemoryStatus(aWriter); + WriteAvailableMemoryStatus(aWriter); + WriteSwapFileStatus(aWriter); +} + +#elif XP_LINUX + +static void AnnotateMemoryStatus(AnnotationWriter& aWriter) { + // We can't simply call `sysinfo` as this requires libc. + // So we need to parse /proc/meminfo. + + // We read the entire file to memory prior to parsing + // as it makes the parser code a little bit simpler. + // As /proc/meminfo is synchronized via `proc_create_single`, + // there's no risk of race condition regardless of how we + // read it. + + // The buffer in which we're going to load the entire file. + // A typical size for /proc/meminfo is 1KiB, so 4KiB should + // be large enough until further notice. + const size_t BUFFER_SIZE_BYTES = 4096; + char buffer[BUFFER_SIZE_BYTES]; + + size_t bufferLen = 0; + { + // Read and load into memory. + int fd = sys_open("/proc/meminfo", O_RDONLY, /* chmod */ 0); + if (fd == -1) { + // No /proc/meminfo? Well, fail silently. + return; + } + auto Guard = MakeScopeExit([fd]() { mozilla::Unused << sys_close(fd); }); + + ssize_t bytesRead = 0; + do { + if ((bytesRead = sys_read(fd, buffer + bufferLen, + BUFFER_SIZE_BYTES - bufferLen)) < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) { + continue; + } + + // Cannot read for some reason. Let's give up. + return; + } + + bufferLen += bytesRead; + + if (bufferLen == BUFFER_SIZE_BYTES) { + // The file is too large, bail out + return; + } + } while (bytesRead != 0); + } + + // Each line of /proc/meminfo looks like + // SomeLabel: number unit + // The last line is empty. + // Let's write a parser. + // Note that we don't care about writing a normative parser, so + // we happily skip whitespaces without checking that it's necessary. + + // A stack-allocated structure containing a 0-terminated string. + // We could avoid the memory copies and make it a slice at the cost + // of a slightly more complicated parser. Since we're not in a + // performance-critical section, we didn't. + struct DataBuffer { + DataBuffer() : data{0}, pos(0) {} + // Clear the buffer. + void reset() { + pos = 0; + data[0] = 0; + } + // Append a character. + // + // In case of error (if c is '\0' or the buffer is full), does nothing. + void append(char c) { + if (c == 0 || pos >= sizeof(data) - 1) { + return; + } + data[pos++] = c; + data[pos] = 0; + } + // Compare the buffer against a nul-terminated string. + bool operator==(const char* s) const { + for (size_t i = 0; i < pos; ++i) { + if (s[i] != data[i]) { + // Note: Since `data` never contains a '0' in positions [0,pos) + // this will bailout once we have reached the end of `s`. + return false; + } + } + return true; + } + + // A NUL-terminated string of `pos + 1` chars (the +1 is for the 0). + char data[256]; + + // Invariant: < 256. + size_t pos; + }; + + // A DataBuffer holding the string representation of a non-negative number. + struct NumberBuffer : DataBuffer { + // If possible, convert the string into a number. + // Returns `true` in case of success, `false` in case of failure. + bool asNumber(size_t* number) { + int result; + if (!my_strtoui(&result, data)) { + return false; + } + *number = result; + return true; + } + }; + + // A DataBuffer holding the string representation of a unit. As of this + // writing, we only support unit `kB`, which seems to be the only unit used in + // `/proc/meminfo`. + struct UnitBuffer : DataBuffer { + // If possible, convert the string into a multiplier, e.g. `kB => 1024`. + // Return `true` in case of success, `false` in case of failure. + bool asMultiplier(size_t* multiplier) { + if (*this == "kB") { + *multiplier = 1024; + return true; + } + // Other units don't seem to be specified/used. + return false; + } + }; + + // The state of the mini-parser. + enum class State { + // Reading the label, including the trailing ':'. + Label, + // Reading the number, ignoring any whitespace. + Number, + // Reading the unit, ignoring any whitespace. + Unit, + }; + + // A single measure being read from /proc/meminfo, e.g. + // the total physical memory available on the system. + struct Measure { + Measure() : state(State::Label) {} + // Reset the measure for a new read. + void reset() { + state = State::Label; + label.reset(); + number.reset(); + unit.reset(); + } + // Attempt to convert the measure into a number. + // Return `true` if both the number and the multiplier could be + // converted, `false` otherwise. + // In case of overflow, produces the maximal possible `size_t`. + bool asValue(size_t* result) { + size_t numberAsSize = 0; + if (!number.asNumber(&numberAsSize)) { + return false; + } + size_t unitAsMultiplier = 0; + if (!unit.asMultiplier(&unitAsMultiplier)) { + return false; + } + if (numberAsSize * unitAsMultiplier >= numberAsSize) { + *result = numberAsSize * unitAsMultiplier; + } else { + // Overflow. Unlikely, but just in case, let's return + // the maximal possible value. + *result = size_t(-1); + } + return true; + } + + // The label being read, e.g. `MemFree`. Does not include the trailing ':'. + DataBuffer label; + + // The number being read, e.g. "1024". + NumberBuffer number; + + // The unit being read, e.g. "kB". + UnitBuffer unit; + + // What we're reading at the moment. + State state; + }; + + // A value we wish to store for later processing. + // e.g. to compute `AvailablePageFile`, we need to + // store `CommitLimit` and `Committed_AS`. + struct ValueStore { + ValueStore() : value(0), found(false) {} + size_t value; + bool found; + }; + ValueStore commitLimit; + ValueStore committedAS; + ValueStore memTotal; + ValueStore swapTotal; + + // The current measure. + Measure measure; + + for (size_t pos = 0; pos < size_t(bufferLen); ++pos) { + const char c = buffer[pos]; + switch (measure.state) { + case State::Label: + if (c == ':') { + // We have finished reading the label. + measure.state = State::Number; + } else { + measure.label.append(c); + } + break; + case State::Number: + if (c == ' ') { + // Ignore whitespace + } else if ('0' <= c && c <= '9') { + // Accumulate numbers. + measure.number.append(c); + } else { + // We have jumped to the unit. + measure.unit.append(c); + measure.state = State::Unit; + } + break; + case State::Unit: + if (c == ' ') { + // Ignore whitespace + } else if (c == '\n') { + // Flush line. + // - If this one of the measures we're interested in, write it. + // - Once we're done, reset the parser. + auto Guard = MakeScopeExit([&measure]() { measure.reset(); }); + + struct PointOfInterest { + // The label we're looking for, e.g. "MemTotal". + const char* label; + // If non-nullptr, store the value at this address. + ValueStore* dest; + // If other than Annotation::Count, write the value for this + // annotation. + Annotation annotation; + }; + const PointOfInterest POINTS_OF_INTEREST[] = { + {"MemTotal", &memTotal, Annotation::TotalPhysicalMemory}, + {"MemFree", nullptr, Annotation::AvailablePhysicalMemory}, + {"MemAvailable", nullptr, Annotation::AvailableVirtualMemory}, + {"SwapFree", nullptr, Annotation::AvailableSwapMemory}, + {"SwapTotal", &swapTotal, Annotation::Count}, + {"CommitLimit", &commitLimit, Annotation::Count}, + {"Committed_AS", &committedAS, Annotation::Count}, + }; + for (const auto& pointOfInterest : POINTS_OF_INTEREST) { + if (measure.label == pointOfInterest.label) { + size_t value; + if (measure.asValue(&value)) { + if (pointOfInterest.dest != nullptr) { + pointOfInterest.dest->found = true; + pointOfInterest.dest->value = value; + } + if (pointOfInterest.annotation != Annotation::Count) { + aWriter.Write(pointOfInterest.annotation, value); + } + } + break; + } + } + // Otherwise, ignore. + } else { + measure.unit.append(c); + } + break; + } + } + + if (commitLimit.found && committedAS.found) { + // If available, attempt to determine the available virtual memory. + // As `commitLimit` is not guaranteed to be larger than `committedAS`, + // we return `0` in case the commit limit has already been exceeded. + uint64_t availablePageFile = (committedAS.value <= commitLimit.value) + ? (commitLimit.value - committedAS.value) + : 0; + aWriter.Write(Annotation::AvailablePageFile, availablePageFile); + } + if (memTotal.found && swapTotal.found) { + // If available, attempt to determine the available virtual memory. + aWriter.Write(Annotation::TotalPageFile, memTotal.value + swapTotal.value); + } +} + +#else + +static void AnnotateMemoryStatus(AnnotationTable&) { + // No memory data for other platforms yet. +} + +#endif // XP_WIN || XP_MACOSX || XP_LINUX || else + +#if !defined(MOZ_WIDGET_ANDROID) + +/** + * Launches the program specified in aProgramPath with aMinidumpPath as its + * sole argument. + * + * @param aProgramPath The path of the program to be launched + * @param aMinidumpPath The path of the minidump file, passed as an argument + * to the launched program + */ +static bool LaunchProgram(const XP_CHAR* aProgramPath, + const XP_CHAR* aMinidumpPath) { +# ifdef XP_WIN + XP_CHAR cmdLine[CMDLINE_SIZE]; + XP_CHAR* p; + + size_t size = CMDLINE_SIZE; + p = Concat(cmdLine, L"\"", &size); + p = Concat(p, aProgramPath, &size); + p = Concat(p, L"\" \"", &size); + p = Concat(p, aMinidumpPath, &size); + Concat(p, L"\"", &size); + + PROCESS_INFORMATION pi = {}; + STARTUPINFO si = {}; + si.cb = sizeof(si); + + // If CreateProcess() fails don't do anything. + if (CreateProcess( + /* lpApplicationName */ nullptr, (LPWSTR)cmdLine, + /* lpProcessAttributes */ nullptr, /* lpThreadAttributes */ nullptr, + /* bInheritHandles */ FALSE, + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_BREAKAWAY_FROM_JOB, + /* lpEnvironment */ nullptr, /* lpCurrentDirectory */ nullptr, &si, + &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } +# elif defined(XP_MACOSX) + pid_t pid = 0; + char* const my_argv[] = {const_cast(aProgramPath), + const_cast(aMinidumpPath), nullptr}; + + char** env = nullptr; + char*** nsEnv = _NSGetEnviron(); + if (nsEnv) { + env = *nsEnv; + } + + int rv = posix_spawnp(&pid, my_argv[0], nullptr, nullptr, my_argv, env); + + if (rv != 0) { + return false; + } +# else // !XP_MACOSX + pid_t pid = sys_fork(); + + if (pid == -1) { + return false; + } else if (pid == 0) { + Unused << execl(aProgramPath, aProgramPath, aMinidumpPath, nullptr); + _exit(1); + } +# endif // XP_MACOSX + + return true; +} + +#else + +/** + * Launch the crash reporter activity on Android + * + * @param aProgramPath The path of the program to be launched + * @param aMinidumpPath The path to the crash minidump file + */ + +static bool LaunchCrashHandlerService(const XP_CHAR* aProgramPath, + const XP_CHAR* aMinidumpPath) { + static XP_CHAR extrasPath[XP_PATH_MAX]; + size_t size = XP_PATH_MAX; + + XP_CHAR* p = Concat(extrasPath, aMinidumpPath, &size); + p = Concat(p - 3, "extra", &size); + + pid_t pid = sys_fork(); + + if (pid == -1) + return false; + else if (pid == 0) { + // Invoke the crash handler service using am + if (androidUserSerial) { + Unused << execlp("/system/bin/am", "/system/bin/am", + androidStartServiceCommand, "--user", androidUserSerial, + "-a", "org.mozilla.gecko.ACTION_CRASHED", "-n", + aProgramPath, "--es", "minidumpPath", aMinidumpPath, + "--es", "extrasPath", extrasPath, "--ez", "fatal", + "true", "--es", "processType", "MAIN", (char*)0); + } else { + Unused << execlp( + "/system/bin/am", "/system/bin/am", androidStartServiceCommand, "-a", + "org.mozilla.gecko.ACTION_CRASHED", "-n", aProgramPath, "--es", + "minidumpPath", aMinidumpPath, "--es", "extrasPath", extrasPath, + "--ez", "fatal", "true", "--es", "processType", "MAIN", (char*)0); + } + _exit(1); + + } else { + // We need to wait on the 'am start' command above to finish, otherwise + // everything will be killed by the ActivityManager as soon as the signal + // handler exits + int status; + Unused << HANDLE_EINTR(sys_waitpid(pid, &status, __WALL)); + } + + return true; +} + +#endif + +static void WriteMainThreadRunnableName(AnnotationWriter& aWriter) { +#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY + // Only try to collect this information if the main thread is crashing. + if (!SignalSafeIsMainThread()) { + return; + } + + // NOTE: Use `my_memchr` over `strlen` to ensure we don't run off the end of + // the buffer if it contains no null bytes. This is used instead of `strnlen`, + // as breakpad's linux support library doesn't export a `my_strnlen` function. + const char* buf = nsThread::sMainThreadRunnableName.begin(); + size_t len = nsThread::kRunnableNameBufSize; + if (const void* end = my_memchr(buf, '\0', len)) { + len = static_cast(end) - buf; + } + + if (len > 0) { + aWriter.Write(Annotation::MainThreadRunnableName, buf, len); + } +#endif +} + +static void WriteOOMAllocationSize(AnnotationWriter& aWriter) { + if (gOOMAllocationSize) { + aWriter.Write(Annotation::OOMAllocationSize, gOOMAllocationSize); + } +} + +static void WriteMozCrashReason(AnnotationWriter& aWriter) { + if (gMozCrashReason != nullptr) { + aWriter.Write(Annotation::MozCrashReason, gMozCrashReason); + } +} + +static void WriteAnnotations(AnnotationWriter& aWriter, + const AnnotationTable& aAnnotations) { + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + const nsCString& value = aAnnotations[key]; + if (!value.IsEmpty()) { + aWriter.Write(key, value.get(), value.Length()); + } + } +} + +static void WriteSynthesizedAnnotations(AnnotationWriter& aWriter) { + AnnotateMemoryStatus(aWriter); +} + +static void WriteAnnotationsForMainProcessCrash(PlatformWriter& pw, + const phc::AddrInfo* addrInfo, + time_t crashTime) { + JSONAnnotationWriter writer(pw); + WriteAnnotations(writer, crashReporterAPIData_Table); + WriteSynthesizedAnnotations(writer); + writer.Write(Annotation::CrashTime, uint64_t(crashTime)); + + if (inactiveStateStart) { + writer.Write(Annotation::LastInteractionDuration, + crashTime - inactiveStateStart); + } + + double uptimeTS = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()) + .ToSecondsSigDigits(); + char uptimeTSString[64] = {}; + SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString)); + writer.Write(Annotation::UptimeTS, uptimeTSString); + + // calculate time since last crash (if possible). + if (lastCrashTime != 0) { + uint64_t timeSinceLastCrash = crashTime - lastCrashTime; + + if (timeSinceLastCrash != 0) { + writer.Write(Annotation::SecondsSinceLastCrash, timeSinceLastCrash); + } + } + + if (isGarbageCollecting) { + writer.Write(Annotation::IsGarbageCollecting, "1"); + } + + if (eventloopNestingLevel > 0) { + writer.Write(Annotation::EventLoopNestingLevel, eventloopNestingLevel); + } + +#if defined(XP_WIN) && defined(HAS_DLL_BLOCKLIST) + // HACK: The DLL blocklist code will manually write its annotations as JSON + DllBlocklist_WriteNotes(writer); +#endif // defined(XP_WIN) && defined(HAS_DLL_BLOCKLIST) + + WriteMozCrashReason(writer); + + WriteMainThreadRunnableName(writer); + + WriteOOMAllocationSize(writer); + + if (gTexturesSize) { + writer.Write(Annotation::TextureUsage, gTexturesSize); + } + +#ifdef MOZ_PHC + WritePHCAddrInfo(writer, addrInfo); +#endif +} + +static void WriteCrashEventFile(time_t crashTime, const char* crashTimeString, + const phc::AddrInfo* addrInfo, +#ifdef XP_LINUX + const MinidumpDescriptor& descriptor +#else + const XP_CHAR* minidump_id +#endif +) { + // Minidump IDs are UUIDs (36) + NULL. + static char id_ascii[37] = {}; +#ifdef XP_LINUX + const char* index = strrchr(descriptor.path(), '/'); + MOZ_ASSERT(index); + MOZ_ASSERT(strlen(index) == 1 + 36 + 4); // "/" + UUID + ".dmp" + for (uint32_t i = 0; i < 36; i++) { + id_ascii[i] = *(index + 1 + i); + } +#else + MOZ_ASSERT(XP_STRLEN(minidump_id) == 36); + for (uint32_t i = 0; i < 36; i++) { + id_ascii[i] = *((char*)(minidump_id + i)); + } +#endif + + PlatformWriter eventFile; + + if (!eventsDirectory.empty()) { + static XP_CHAR crashEventPath[XP_PATH_MAX]; + size_t size = XP_PATH_MAX; + XP_CHAR* p; + p = Concat(crashEventPath, eventsDirectory.c_str(), &size); + p = Concat(p, XP_PATH_SEPARATOR, &size); +#ifdef XP_LINUX + Concat(p, id_ascii, &size); +#else + Concat(p, minidump_id, &size); +#endif + + eventFile.Open(crashEventPath); + eventFile.WriteLiteral(kCrashMainID); + eventFile.WriteString(crashTimeString); + eventFile.WriteLiteral("\n"); + eventFile.WriteString(id_ascii); + eventFile.WriteLiteral("\n"); + WriteAnnotationsForMainProcessCrash(eventFile, addrInfo, crashTime); + } +} + +// Callback invoked from breakpad's exception handler, this writes out the +// last annotations after a crash occurs and launches the crash reporter client. +// +// This function is not declared static even though it's not used outside of +// this file because of an issue in Fennec which prevents breakpad's exception +// handler from invoking it. See bug 1424304. +bool MinidumpCallback( +#ifdef XP_LINUX + const MinidumpDescriptor& descriptor, +#else + const XP_CHAR* dump_path, const XP_CHAR* minidump_id, +#endif + void* context, +#ifdef XP_WIN + EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, +#endif + const phc::AddrInfo* addrInfo, bool succeeded) { + bool returnValue = showOSCrashReporter ? false : succeeded; + + static XP_CHAR minidumpPath[XP_PATH_MAX]; + size_t size = XP_PATH_MAX; + XP_CHAR* p; +#ifndef XP_LINUX + p = Concat(minidumpPath, dump_path, &size); + p = Concat(p, XP_PATH_SEPARATOR, &size); + p = Concat(p, minidump_id, &size); + Concat(p, dumpFileExtension, &size); +#else + Concat(minidumpPath, descriptor.path(), &size); +#endif + + static XP_CHAR memoryReportLocalPath[XP_PATH_MAX]; + size = XP_PATH_MAX; +#ifndef XP_LINUX + p = Concat(memoryReportLocalPath, dump_path, &size); + p = Concat(p, XP_PATH_SEPARATOR, &size); + p = Concat(p, minidump_id, &size); +#else + p = Concat(memoryReportLocalPath, descriptor.path(), &size); + // Skip back past the .dmp extension + p -= 4; +#endif + Concat(p, memoryReportExtension, &size); + + if (!memoryReportPath.empty()) { +#ifdef XP_WIN + CopyFile(memoryReportPath.c_str(), memoryReportLocalPath, false); +#else + copy_file(memoryReportPath.c_str(), memoryReportLocalPath); +#endif + } + + time_t crashTime = GetCurrentTimeForCrashTime(); + char crashTimeString[32]; + XP_TTOA(crashTime, crashTimeString); + + // write crash time to file + if (lastCrashTimeFilename[0] != 0) { + PlatformWriter lastCrashFile(lastCrashTimeFilename); + lastCrashFile.WriteString(crashTimeString); + } + + WriteCrashEventFile(crashTime, crashTimeString, addrInfo, +#ifdef XP_LINUX + descriptor +#else + minidump_id +#endif + ); + + { + PlatformWriter apiData; +#ifdef XP_LINUX + OpenAPIData(apiData, descriptor.path()); +#else + OpenAPIData(apiData, dump_path, minidump_id); +#endif + WriteAnnotationsForMainProcessCrash(apiData, addrInfo, crashTime); + } + + if (doReport && isSafeToDump) { + // We launch the crash reporter client/dialog only if we've been explicitly + // asked to report crashes and if we weren't already trying to unset the + // exception handler (which is indicated by isSafeToDump being false). +#if defined(MOZ_WIDGET_ANDROID) // Android + returnValue = + LaunchCrashHandlerService(crashReporterPath.c_str(), minidumpPath); +#else // Windows, Mac, Linux, etc... + returnValue = LaunchProgram(crashReporterPath.c_str(), minidumpPath); +#endif + } + +#ifdef XP_WIN + TerminateProcess(GetCurrentProcess(), 1); +#endif + + return returnValue; +} + +#if defined(XP_MACOSX) || defined(__ANDROID__) || defined(XP_LINUX) +static size_t EnsureTrailingSlash(XP_CHAR* aBuf, size_t aBufLen) { + size_t len = XP_STRLEN(aBuf); + if ((len + 1) < aBufLen && len > 0 && + aBuf[len - 1] != XP_PATH_SEPARATOR_CHAR) { + aBuf[len] = XP_PATH_SEPARATOR_CHAR; + ++len; + aBuf[len] = 0; + } + return len; +} +#endif + +#if defined(XP_WIN) + +static size_t BuildTempPath(wchar_t* aBuf, size_t aBufLen) { + // first figure out buffer size + DWORD pathLen = GetTempPath(0, nullptr); + if (pathLen == 0 || pathLen >= aBufLen) { + return 0; + } + + return GetTempPath(pathLen, aBuf); +} + +static size_t BuildTempPath(char16_t* aBuf, size_t aBufLen) { + return BuildTempPath(reinterpret_cast(aBuf), aBufLen); +} + +#elif defined(XP_MACOSX) + +static size_t BuildTempPath(char* aBuf, size_t aBufLen) { + if (aBufLen < PATH_MAX) { + return 0; + } + + FSRef fsRef; + OSErr err = + FSFindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder, &fsRef); + if (err != noErr) { + return 0; + } + + OSStatus status = FSRefMakePath(&fsRef, (UInt8*)aBuf, PATH_MAX); + if (status != noErr) { + return 0; + } + + return EnsureTrailingSlash(aBuf, aBufLen); +} + +#elif defined(__ANDROID__) + +static size_t BuildTempPath(char* aBuf, size_t aBufLen) { + // GeckoAppShell sets this in the environment + const char* tempenv = PR_GetEnv("TMPDIR"); + if (!tempenv) { + return false; + } + size_t size = aBufLen; + Concat(aBuf, tempenv, &size); + return EnsureTrailingSlash(aBuf, aBufLen); +} + +#elif defined(XP_UNIX) + +static size_t BuildTempPath(char* aBuf, size_t aBufLen) { + const char* tempenv = PR_GetEnv("TMPDIR"); + const char* tmpPath = "/tmp/"; + if (!tempenv) { + tempenv = tmpPath; + } + size_t size = aBufLen; + Concat(aBuf, tempenv, &size); + return EnsureTrailingSlash(aBuf, aBufLen); +} + +#else +# error "Implement this for your platform" +#endif + +template +static size_t BuildTempPath(CharT (&aBuf)[N]) { + static_assert(N >= XP_PATH_MAX, "char array length is too small"); + return BuildTempPath(&aBuf[0], N); +} + +template +static bool BuildTempPath(PathStringT& aResult) { + aResult.SetLength(XP_PATH_MAX); + size_t actualLen = BuildTempPath(aResult.BeginWriting(), XP_PATH_MAX); + if (!actualLen) { + return false; + } + aResult.SetLength(actualLen); + return true; +} + +#ifdef XP_WIN + +static void ReserveBreakpadVM() { + if (!gBreakpadReservedVM) { + gBreakpadReservedVM = + VirtualAlloc(nullptr, kReserveSize, MEM_RESERVE, PAGE_NOACCESS); + } +} + +static void FreeBreakpadVM() { + if (gBreakpadReservedVM) { + VirtualFree(gBreakpadReservedVM, 0, MEM_RELEASE); + } +} + +static bool IsCrashingException(EXCEPTION_POINTERS* exinfo) { + if (!exinfo) { + return true; + } + + PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)exinfo->ExceptionRecord; + switch (e->ExceptionCode) { + case STATUS_FLOAT_DENORMAL_OPERAND: + case STATUS_FLOAT_DIVIDE_BY_ZERO: + case STATUS_FLOAT_INEXACT_RESULT: + case STATUS_FLOAT_INVALID_OPERATION: + case STATUS_FLOAT_OVERFLOW: + case STATUS_FLOAT_STACK_CHECK: + case STATUS_FLOAT_UNDERFLOW: + case STATUS_FLOAT_MULTIPLE_FAULTS: + case STATUS_FLOAT_MULTIPLE_TRAPS: + return false; // Don't write minidump, continue exception search + default: + return true; + } +} + +#endif // XP_WIN + +// Do various actions to prepare the child process for minidump generation. +// This includes disabling the I/O interposer and DLL blocklist which both +// would get in the way. We also free the address space we had reserved in +// 32-bit builds to free room for the minidump generation to do its work. +static void PrepareForMinidump() { + mozilla::IOInterposer::Disable(); +#if defined(XP_WIN) +# if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST) + DllBlocklist_Shutdown(); +# endif + FreeBreakpadVM(); +#endif // XP_WIN +} + +#ifdef XP_WIN + +/** + * Filters out floating point exceptions which are handled by nsSigHandlers.cpp + * and should not be handled as crashes. + */ +static ExceptionHandler::FilterResult Filter(void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion) { + if (!IsCrashingException(exinfo)) { + return ExceptionHandler::FilterResult::ContinueSearch; + } + + PrepareForMinidump(); + return ExceptionHandler::FilterResult::HandleException; +} + +static ExceptionHandler::FilterResult ChildFilter( + void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { + if (!IsCrashingException(exinfo)) { + return ExceptionHandler::FilterResult::ContinueSearch; + } + + if (gEncounteredChildException.exchange(true)) { + return ExceptionHandler::FilterResult::AbortWithoutMinidump; + } + + PrepareForMinidump(); + return ExceptionHandler::FilterResult::HandleException; +} + +static MINIDUMP_TYPE GetMinidumpType() { + MINIDUMP_TYPE minidump_type = static_cast( + MiniDumpWithFullMemoryInfo | MiniDumpWithUnloadedModules | + MiniDumpWithHandleData); + +# ifdef NIGHTLY_BUILD + minidump_type = static_cast( + minidump_type | + // This is Nightly only because this doubles the size of minidumps based + // on the experimental data. + MiniDumpWithProcessThreadData | + // This allows us to examine heap objects referenced from stack objects + // at the cost of further doubling the size of minidumps. + MiniDumpWithIndirectlyReferencedMemory); +# endif + + const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP"); + if (e && *e) { + minidump_type = MiniDumpWithFullMemory; + } + + return minidump_type; +} + +#else + +static bool Filter(void* context) { + PrepareForMinidump(); + return true; +} + +static bool ChildFilter(void* context) { + if (gEncounteredChildException.exchange(true)) { + return false; + } + + PrepareForMinidump(); + return true; +} + +#endif // !defined(XP_WIN) + +static bool ChildMinidumpCallback( +#if defined(XP_WIN) + const wchar_t* dump_path, const wchar_t* minidump_id, +#elif defined(XP_LINUX) + const MinidumpDescriptor& descriptor, +#else // defined(XP_MACOSX) + const char* dump_dir, const char* minidump_id, +#endif + void* context, +#if defined(XP_WIN) + EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, +#endif // defined(XP_WIN) + const mozilla::phc::AddrInfo* addr_info, bool succeeded) { + return succeeded; +} + +static bool ShouldReport() { + // this environment variable prevents us from launching + // the crash reporter client + const char* envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT"); + if (envvar && *envvar) { + return false; + } + + envvar = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP"); + if (envvar && *envvar) { + return false; + } + + return true; +} + +static void TerminateHandler() { MOZ_CRASH("Unhandled exception"); } + +#if !defined(MOZ_WIDGET_ANDROID) + +// Locate the specified executable and store its path as a native string in +// the |aPath| so we can later invoke it from within the exception handler. +static nsresult LocateExecutable(nsIFile* aXREDirectory, const nsAString& aName, + PathString& aPath) { + nsCOMPtr exePath; + nsresult rv = aXREDirectory->Clone(getter_AddRefs(exePath)); + NS_ENSURE_SUCCESS(rv, rv); + +# ifdef XP_MACOSX + exePath->SetNativeLeafName("MacOS"_ns); + exePath->Append(u"crashreporter.app"_ns); + exePath->Append(u"Contents"_ns); + exePath->Append(u"MacOS"_ns); +# endif + + exePath->Append(aName); + aPath = exePath->NativePath(); + return NS_OK; +} + +#endif // !defined(MOZ_WIDGET_ANDROID) + +static void InitializeAnnotationFacilities() { + crashReporterAPILock = new Mutex("crashReporterAPILock"); + notesFieldLock = new Mutex("notesFieldLock"); + notesField = new nsCString(); +} + +static void TeardownAnnotationFacilities() { + std::fill(crashReporterAPIData_Table.begin(), + crashReporterAPIData_Table.end(), ""_ns); + + delete crashReporterAPILock; + crashReporterAPILock = nullptr; + + delete notesFieldLock; + notesFieldLock = nullptr; + + delete notesField; + notesField = nullptr; +} + +nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force /*=false*/) { + if (gExceptionHandler) return NS_ERROR_ALREADY_INITIALIZED; + +#if defined(DEBUG) + // In debug builds, disable the crash reporter by default, and allow to + // enable it with the MOZ_CRASHREPORTER environment variable. + const char* envvar = PR_GetEnv("MOZ_CRASHREPORTER"); + if ((!envvar || !*envvar) && !force) return NS_OK; +#else + // In other builds, enable the crash reporter by default, and allow + // disabling it with the MOZ_CRASHREPORTER_DISABLE environment variable. + const char* envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE"); + if (envvar && *envvar && !force) return NS_OK; +#endif + + // this environment variable prevents us from launching + // the crash reporter client + doReport = ShouldReport(); + + RegisterRuntimeExceptionModule(); + InitializeAnnotationFacilities(); + +#if !defined(MOZ_WIDGET_ANDROID) + // Locate the crash reporter executable + PathString crashReporterPath_temp; + nsresult rv = LocateExecutable(aXREDirectory, CRASH_REPORTER_FILENAME, + crashReporterPath_temp); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + crashReporterPath = crashReporterPath_temp.get(); +#else + // On Android, we launch a service defined via MOZ_ANDROID_CRASH_HANDLER + const char* androidCrashHandler = PR_GetEnv("MOZ_ANDROID_CRASH_HANDLER"); + if (androidCrashHandler) { + crashReporterPath = xpstring(androidCrashHandler); + } else { + NS_WARNING("No Android crash handler set"); + } + + const char* deviceAndroidVersion = + PR_GetEnv("MOZ_ANDROID_DEVICE_SDK_VERSION"); + if (deviceAndroidVersion != nullptr) { + const int deviceSdkVersion = atol(deviceAndroidVersion); + if (deviceSdkVersion >= 26) { + androidStartServiceCommand = (char*)"start-foreground-service"; + } else { + androidStartServiceCommand = (char*)"startservice"; + } + } +#endif // !defined(MOZ_WIDGET_ANDROID) + + // get temp path to use for minidump path + PathString tempPath; + if (!BuildTempPath(tempPath)) { + return NS_ERROR_FAILURE; + } + +#ifdef XP_WIN + ReserveBreakpadVM(); + + // Pre-load psapi.dll to prevent it from being loaded during exception + // handling. + ::LoadLibraryW(L"psapi.dll"); +#endif // XP_WIN + +#ifdef MOZ_WIDGET_ANDROID + androidUserSerial = getenv("MOZ_ANDROID_USER_SERIAL_NUMBER"); +#endif + + // Initialize the flag and mutex used to avoid dump processing + // once browser termination has begun. + NS_ASSERTION(!dumpSafetyLock, "Shouldn't have a lock yet"); + // Do not deallocate this lock while it is still possible for + // isSafeToDump to be tested on another thread. + dumpSafetyLock = new Mutex("dumpSafetyLock"); + MutexAutoLock lock(*dumpSafetyLock); + isSafeToDump = true; + + // now set the exception handler +#ifdef XP_LINUX + MinidumpDescriptor descriptor(tempPath.get()); +#endif + +#ifdef XP_WIN + previousUnhandledExceptionFilter = GetUnhandledExceptionFilter(); +#endif + + gExceptionHandler = new google_breakpad::ExceptionHandler( +#ifdef XP_LINUX + descriptor, +#elif defined(XP_WIN) + std::wstring(tempPath.get()), +#else + tempPath.get(), +#endif + + Filter, MinidumpCallback, nullptr, +#ifdef XP_WIN + google_breakpad::ExceptionHandler::HANDLER_ALL, GetMinidumpType(), + (const wchar_t*)nullptr, nullptr); +#else + true +# ifdef XP_MACOSX + , + nullptr +# endif +# ifdef XP_LINUX + , + -1 +# endif + ); +#endif // XP_WIN + + if (!gExceptionHandler) return NS_ERROR_OUT_OF_MEMORY; + +#ifdef XP_WIN + gExceptionHandler->set_handle_debug_exceptions(true); + + // Initially set sIncludeContextHeap to true for debugging startup crashes + // even if the controlling pref value is false. + SetIncludeContextHeap(true); +# if defined(HAVE_64BIT_BUILD) + // Tell JS about the new filter before we disable SetUnhandledExceptionFilter + SetJitExceptionHandler(); +# endif + + RecordMainThreadId(); + + // protect the crash reporter from being unloaded + gBlockUnhandledExceptionFilter = true; + gKernel32Intercept.Init("kernel32.dll"); + DebugOnly ok = stub_SetUnhandledExceptionFilter.Set( + gKernel32Intercept, "SetUnhandledExceptionFilter", + &patched_SetUnhandledExceptionFilter); + +# ifdef DEBUG + if (!ok) + printf_stderr( + "SetUnhandledExceptionFilter hook failed; crash reporter is " + "vulnerable.\n"); +# endif +#endif + + // store application start time + char timeString[32]; + time_t startupTime = time(nullptr); + XP_TTOA(startupTime, timeString); + AnnotateCrashReport(Annotation::StartupTime, nsDependentCString(timeString)); + +#if defined(XP_MACOSX) + // On OS X, many testers like to see the OS crash reporting dialog + // since it offers immediate stack traces. We allow them to set + // a default to pass exceptions to the OS handler. + Boolean keyExistsAndHasValidFormat = false; + Boolean prefValue = ::CFPreferencesGetAppBooleanValue( + CFSTR("OSCrashReporter"), kCFPreferencesCurrentApplication, + &keyExistsAndHasValidFormat); + if (keyExistsAndHasValidFormat) showOSCrashReporter = prefValue; +#endif + + oldTerminateHandler = std::set_terminate(&TerminateHandler); + + return NS_OK; +} + +bool GetEnabled() { return gExceptionHandler != nullptr; } + +bool GetMinidumpPath(nsAString& aPath) { + if (!gExceptionHandler) return false; + +#ifndef XP_LINUX + aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str()); +#else + aPath = CONVERT_XP_CHAR_TO_UTF16( + gExceptionHandler->minidump_descriptor().directory().c_str()); +#endif + return true; +} + +nsresult SetMinidumpPath(const nsAString& aPath) { + if (!gExceptionHandler) return NS_ERROR_NOT_INITIALIZED; + +#ifdef XP_WIN + gExceptionHandler->set_dump_path( + std::wstring(char16ptr_t(aPath.BeginReading()))); +#elif defined(XP_LINUX) + gExceptionHandler->set_minidump_descriptor( + MinidumpDescriptor(NS_ConvertUTF16toUTF8(aPath).BeginReading())); +#else + gExceptionHandler->set_dump_path(NS_ConvertUTF16toUTF8(aPath).BeginReading()); +#endif + return NS_OK; +} + +static nsresult WriteDataToFile(nsIFile* aFile, const nsACString& data) { + PRFileDesc* fd; + nsresult rv = aFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 00600, &fd); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_OK; + if (PR_Write(fd, data.Data(), data.Length()) == -1) { + rv = NS_ERROR_FAILURE; + } + PR_Close(fd); + return rv; +} + +static nsresult GetFileContents(nsIFile* aFile, nsACString& data) { + PRFileDesc* fd; + nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_OK; + int32_t filesize = PR_Available(fd); + if (filesize <= 0) { + rv = NS_ERROR_FILE_NOT_FOUND; + } else { + data.SetLength(filesize); + if (PR_Read(fd, data.BeginWriting(), filesize) == -1) { + rv = NS_ERROR_FAILURE; + } + } + PR_Close(fd); + return rv; +} + +// Function typedef for initializing a piece of data that we +// don't already have. +typedef nsresult (*InitDataFunc)(nsACString&); + +// Attempt to read aFile's contents into aContents, if aFile +// does not exist, create it and initialize its contents +// by calling aInitFunc for the data. +static nsresult GetOrInit(nsIFile* aDir, const nsACString& filename, + nsACString& aContents, InitDataFunc aInitFunc) { + bool exists; + + nsCOMPtr dataFile; + nsresult rv = aDir->Clone(getter_AddRefs(dataFile)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = dataFile->AppendNative(filename); + NS_ENSURE_SUCCESS(rv, rv); + + rv = dataFile->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + + if (!exists) { + if (aInitFunc) { + // get the initial value and write it to the file + rv = aInitFunc(aContents); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteDataToFile(dataFile, aContents); + } else { + // didn't pass in an init func + rv = NS_ERROR_FAILURE; + } + } else { + // just get the file's contents + rv = GetFileContents(dataFile, aContents); + } + + return rv; +} + +// Init the "install time" data. We're taking an easy way out here +// and just setting this to "the time when this version was first run". +static nsresult InitInstallTime(nsACString& aInstallTime) { + time_t t = time(nullptr); + aInstallTime = nsPrintfCString("%" PRIu64, static_cast(t)); + + return NS_OK; +} + +// Ensure a directory exists and create it if missing. +static nsresult EnsureDirectoryExists(nsIFile* dir) { + nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700); + + if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) { + return rv; + } + + return NS_OK; +} + +// Creates a directory that will be accessible by the crash reporter. The +// directory will live under Firefox default data directory and will use the +// specified name. The directory path will be passed to the crashreporter via +// the specified environment variable. +static nsresult SetupCrashReporterDirectory(nsIFile* aAppDataDirectory, + const char* aDirName, + const XP_CHAR* aEnvVarName, + nsIFile** aDirectory = nullptr) { + nsCOMPtr directory; + nsresult rv = aAppDataDirectory->Clone(getter_AddRefs(directory)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = directory->AppendNative(nsDependentCString(aDirName)); + NS_ENSURE_SUCCESS(rv, rv); + + EnsureDirectoryExists(directory); + xpstring* directoryPath = CreatePathFromFile(directory); + + if (!directoryPath) { + return NS_ERROR_FAILURE; + } + +#if defined(XP_WIN) + SetEnvironmentVariableW(aEnvVarName, directoryPath->c_str()); +#else + setenv(aEnvVarName, directoryPath->c_str(), /* overwrite */ 1); +#endif + + delete directoryPath; + + if (aDirectory) { + directory.forget(aDirectory); + } + + return NS_OK; +} + +// Annotate the crash report with a Unique User ID and time +// since install. Also do some prep work for recording +// time since last crash, which must be calculated at +// crash time. +// If any piece of data doesn't exist, initialize it first. +nsresult SetupExtraData(nsIFile* aAppDataDirectory, + const nsACString& aBuildID) { + nsCOMPtr dataDirectory; + nsresult rv = + SetupCrashReporterDirectory(aAppDataDirectory, "Crash Reports", + XP_TEXT("MOZ_CRASHREPORTER_DATA_DIRECTORY"), + getter_AddRefs(dataDirectory)); + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = SetupCrashReporterDirectory(aAppDataDirectory, "Pending Pings", + XP_TEXT("MOZ_CRASHREPORTER_PING_DIRECTORY")); + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsAutoCString data; + if (NS_SUCCEEDED(GetOrInit(dataDirectory, "InstallTime"_ns + aBuildID, data, + InitInstallTime))) + AnnotateCrashReport(Annotation::InstallTime, data); + + // this is a little different, since we can't init it with anything, + // since it's stored at crash time, and we can't annotate the + // crash report with the stored value, since we really want + // (now - LastCrash), so we just get a value if it exists, + // and store it in a time_t value. + if (NS_SUCCEEDED(GetOrInit(dataDirectory, "LastCrash"_ns, data, nullptr))) { + lastCrashTime = (time_t)atol(data.get()); + } + + // not really the best place to init this, but I have the path I need here + nsCOMPtr lastCrashFile; + rv = dataDirectory->Clone(getter_AddRefs(lastCrashFile)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = lastCrashFile->AppendNative("LastCrash"_ns); + NS_ENSURE_SUCCESS(rv, rv); + memset(lastCrashTimeFilename, 0, sizeof(lastCrashTimeFilename)); + + PathString filename; +#if defined(XP_WIN) + rv = lastCrashFile->GetPath(filename); +#else + rv = lastCrashFile->GetNativePath(filename); +#endif + NS_ENSURE_SUCCESS(rv, rv); + + if (filename.Length() < XP_PATH_MAX) { +#if defined(XP_WIN) + wcsncpy(lastCrashTimeFilename, filename.get(), filename.Length()); +#else + strncpy(lastCrashTimeFilename, filename.get(), filename.Length()); +#endif + } + + return NS_OK; +} + +static void OOPDeinit(); + +nsresult UnsetExceptionHandler() { + if (isSafeToDump) { + MutexAutoLock lock(*dumpSafetyLock); + isSafeToDump = false; + } + +#ifdef XP_WIN + // allow SetUnhandledExceptionFilter + gBlockUnhandledExceptionFilter = false; +#endif + + delete gExceptionHandler; + + TeardownAnnotationFacilities(); + + if (!gExceptionHandler) return NS_ERROR_NOT_INITIALIZED; + + gExceptionHandler = nullptr; + + OOPDeinit(); + + delete dumpSafetyLock; + dumpSafetyLock = nullptr; + + std::set_terminate(oldTerminateHandler); + + return NS_OK; +} + +nsresult AnnotateCrashReport(Annotation key, bool data) { + return AnnotateCrashReport(key, data ? "1"_ns : "0"_ns); +} + +nsresult AnnotateCrashReport(Annotation key, int data) { + nsAutoCString dataString; + dataString.AppendInt(data); + + return AnnotateCrashReport(key, dataString); +} + +nsresult AnnotateCrashReport(Annotation key, unsigned int data) { + nsAutoCString dataString; + dataString.AppendInt(data); + + return AnnotateCrashReport(key, dataString); +} + +nsresult AnnotateCrashReport(Annotation key, const nsACString& data) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + + MutexAutoLock lock(*crashReporterAPILock); + crashReporterAPIData_Table[key] = data; + + return NS_OK; +} + +nsresult AppendToCrashReportAnnotation(Annotation key, const nsACString& data) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + + MutexAutoLock lock(*crashReporterAPILock); + nsAutoCString newString(crashReporterAPIData_Table[key]); + newString.Append(" - "_ns); + newString.Append(data); + crashReporterAPIData_Table[key] = newString; + + return NS_OK; +} + +nsresult RemoveCrashReportAnnotation(Annotation key) { + return AnnotateCrashReport(key, ""_ns); +} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, bool data) + : AutoAnnotateCrashReport(key, data ? "1"_ns : "0"_ns) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, int data) + : AutoAnnotateCrashReport(key, nsPrintfCString("%d", data)) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, unsigned data) + : AutoAnnotateCrashReport(key, nsPrintfCString("%u", data)) {} + +AutoAnnotateCrashReport::AutoAnnotateCrashReport(Annotation key, + const nsACString& data) + : mKey(key) { + if (GetEnabled()) { + MutexAutoLock lock(*crashReporterAPILock); + auto& entry = crashReporterAPIData_Table[mKey]; + mPrevious = std::move(entry); + entry = data; + } +} + +AutoAnnotateCrashReport::~AutoAnnotateCrashReport() { + if (GetEnabled()) { + MutexAutoLock lock(*crashReporterAPILock); + crashReporterAPIData_Table[mKey] = std::move(mPrevious); + } +} + +void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc) { + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + const nsCString& value = aSrc[key]; + if (!value.IsEmpty()) { + aDst[key] = value; + } + } +} + +static void MergeContentCrashAnnotations(AnnotationTable& aDst) { + MutexAutoLock lock(*crashReporterAPILock); + MergeCrashAnnotations(aDst, crashReporterAPIData_Table); +} + +// Adds crash time, uptime and memory report annotations +static void AddCommonAnnotations(AnnotationTable& aAnnotations) { + const time_t crashTime = time(nullptr); + nsAutoCString crashTimeStr; + crashTimeStr.AppendInt(static_cast(crashTime)); + aAnnotations[Annotation::CrashTime] = crashTimeStr; + + if (inactiveStateStart) { + nsAutoCString inactiveDuration; + inactiveDuration.AppendInt( + static_cast(crashTime - inactiveStateStart)); + aAnnotations[Annotation::LastInteractionDuration] = inactiveDuration; + } + + double uptimeTS = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()) + .ToSecondsSigDigits(); + nsAutoCString uptimeStr; + uptimeStr.AppendFloat(uptimeTS); + aAnnotations[Annotation::UptimeTS] = uptimeStr; +} + +nsresult SetGarbageCollecting(bool collecting) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + + isGarbageCollecting = collecting; + + return NS_OK; +} + +void SetEventloopNestingLevel(uint32_t level) { eventloopNestingLevel = level; } + +void ClearInactiveStateStart() { inactiveStateStart = 0; } +void SetInactiveStateStart() { + if (!inactiveStateStart) { + inactiveStateStart = GetCurrentTimeForCrashTime(); + } +} + +void SetMinidumpAnalysisAllThreads() { + char* env = strdup("MOZ_CRASHREPORTER_DUMP_ALL_THREADS=1"); + PR_SetEnv(env); +} + +nsresult AppendAppNotesToCrashReport(const nsACString& data) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + + MutexAutoLock lock(*notesFieldLock); + + notesField->Append(data); + return AnnotateCrashReport(Annotation::Notes, *notesField); +} + +// Returns true if found, false if not found. +static bool GetAnnotation(CrashReporter::Annotation key, nsACString& data) { + if (!gExceptionHandler) return false; + + MutexAutoLock lock(*crashReporterAPILock); + const nsCString& entry = crashReporterAPIData_Table[key]; + if (entry.IsEmpty()) { + return false; + } + + data = entry; + return true; +} + +nsresult RegisterAppMemory(void* ptr, size_t length) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + +#if defined(XP_LINUX) || defined(XP_WIN) + gExceptionHandler->RegisterAppMemory(ptr, length); + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult UnregisterAppMemory(void* ptr) { + if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; + +#if defined(XP_LINUX) || defined(XP_WIN) + gExceptionHandler->UnregisterAppMemory(ptr); + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +void SetIncludeContextHeap(bool aValue) { + sIncludeContextHeap = aValue; + +#ifdef XP_WIN + if (gExceptionHandler) { + gExceptionHandler->set_include_context_heap(sIncludeContextHeap); + } +#endif +} + +bool GetServerURL(nsACString& aServerURL) { + if (!gExceptionHandler) return false; + + return GetAnnotation(CrashReporter::Annotation::ServerURL, aServerURL); +} + +nsresult SetServerURL(const nsACString& aServerURL) { + // store server URL with the API data + // the client knows to handle this specially + return AnnotateCrashReport(Annotation::ServerURL, aServerURL); +} + +nsresult SetRestartArgs(int argc, char** argv) { + if (!gExceptionHandler) return NS_OK; + + int i; + nsAutoCString envVar; + char* env; + for (i = 1; i < argc; i++) { + envVar = "MOZ_CRASHREPORTER_RESTART_ARG_"; + envVar.AppendInt(i); + envVar += "="; + envVar += argv[i]; + + // PR_SetEnv() wants the string to be available for the lifetime + // of the app, so dup it here. This conversion is not lossy. + env = ToNewCString(envVar, mozilla::fallible); + if (!env) return NS_ERROR_OUT_OF_MEMORY; + + PR_SetEnv(env); + } + + // make sure the arg list is terminated + envVar = "MOZ_CRASHREPORTER_RESTART_ARG_"; + envVar.AppendInt(i); + envVar += "="; + + // PR_SetEnv() wants the string to be available for the lifetime + // of the app, so dup it here. This conversion is not lossy. + env = ToNewCString(envVar, mozilla::fallible); + if (!env) return NS_ERROR_OUT_OF_MEMORY; + + PR_SetEnv(env); + + // make sure we save the info in XUL_APP_FILE for the reporter + const char* appfile = PR_GetEnv("XUL_APP_FILE"); + if (appfile && *appfile) { + envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE="; + envVar += appfile; + + // PR_SetEnv() wants the string to be available for the lifetime + // of the app, so dup it here. This conversion is not lossy. + env = ToNewCString(envVar); + PR_SetEnv(env); + } + + return NS_OK; +} + +#ifdef XP_WIN +nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo) { + if (!gExceptionHandler) return NS_ERROR_NOT_INITIALIZED; + + return gExceptionHandler->WriteMinidumpForException(aExceptionInfo) + ? NS_OK + : NS_ERROR_FAILURE; +} +#endif + +#ifdef XP_LINUX +bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc) { + if (!gExceptionHandler) { + // Crash reporting is disabled. + return false; + } + return gExceptionHandler->HandleSignal(signo, info, uc); +} +#endif + +#ifdef XP_MACOSX +nsresult AppendObjCExceptionInfoToAppNotes(void* inException) { + nsAutoCString excString; + GetObjCExceptionInfo(inException, excString); + AppendAppNotesToCrashReport(excString); + return NS_OK; +} +#endif + +/* + * Combined code to get/set the crash reporter submission pref on + * different platforms. + */ +static nsresult PrefSubmitReports(bool* aSubmitReports, bool writePref) { + nsresult rv; +#if defined(XP_WIN) + /* + * NOTE! This needs to stay in sync with the preference checking code + * in toolkit/crashreporter/client/crashreporter_win.cpp + */ + nsCOMPtr appinfo = + do_GetService("@mozilla.org/xre/app-info;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString appVendor, appName; + rv = appinfo->GetVendor(appVendor); + NS_ENSURE_SUCCESS(rv, rv); + rv = appinfo->GetName(appName); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr regKey( + do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString regPath; + + regPath.AppendLiteral("Software\\"); + + // We need to ensure the registry keys are created so we can properly + // write values to it + + // Create appVendor key + if (!appVendor.IsEmpty()) { + regPath.Append(appVendor); + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_SET_VALUE); + regPath.Append('\\'); + } + + // Create appName key + regPath.Append(appName); + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_SET_VALUE); + regPath.Append('\\'); + + // Create Crash Reporter key + regPath.AppendLiteral("Crash Reporter"); + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_SET_VALUE); + + // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER + // and we're done. + if (writePref) { + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_SET_VALUE); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t value = *aSubmitReports ? 1 : 0; + rv = regKey->WriteIntValue(u"SubmitCrashReport"_ns, value); + regKey->Close(); + return rv; + } + + // We're reading the pref value, so we need to first look under + // ROOT_KEY_LOCAL_MACHINE to see if it's set there, and then fall back to + // ROOT_KEY_CURRENT_USER. If it's not set in either place, the pref defaults + // to "true". + uint32_t value; + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_QUERY_VALUE); + if (NS_SUCCEEDED(rv)) { + rv = regKey->ReadIntValue(u"SubmitCrashReport"_ns, &value); + regKey->Close(); + if (NS_SUCCEEDED(rv)) { + *aSubmitReports = !!value; + return NS_OK; + } + } + + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, + NS_ConvertUTF8toUTF16(regPath), + nsIWindowsRegKey::ACCESS_QUERY_VALUE); + if (NS_FAILED(rv)) { + *aSubmitReports = true; + return NS_OK; + } + + rv = regKey->ReadIntValue(u"SubmitCrashReport"_ns, &value); + // default to true on failure + if (NS_FAILED(rv)) { + value = 1; + rv = NS_OK; + } + regKey->Close(); + + *aSubmitReports = !!value; + return NS_OK; +#elif defined(XP_MACOSX) + rv = NS_OK; + if (writePref) { + CFPropertyListRef cfValue = + (CFPropertyListRef)(*aSubmitReports ? kCFBooleanTrue : kCFBooleanFalse); + ::CFPreferencesSetAppValue(CFSTR("submitReport"), cfValue, + reporterClientAppID); + if (!::CFPreferencesAppSynchronize(reporterClientAppID)) + rv = NS_ERROR_FAILURE; + } else { + *aSubmitReports = true; + Boolean keyExistsAndHasValidFormat = false; + Boolean prefValue = ::CFPreferencesGetAppBooleanValue( + CFSTR("submitReport"), reporterClientAppID, + &keyExistsAndHasValidFormat); + if (keyExistsAndHasValidFormat) *aSubmitReports = !!prefValue; + } + return rv; +#elif defined(XP_UNIX) + /* + * NOTE! This needs to stay in sync with the preference checking code + * in toolkit/crashreporter/client/crashreporter_linux.cpp + */ + nsCOMPtr reporterINI; + rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(reporterINI)); + NS_ENSURE_SUCCESS(rv, rv); + reporterINI->AppendNative("Crash Reports"_ns); + reporterINI->AppendNative("crashreporter.ini"_ns); + + bool exists; + rv = reporterINI->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists) { + if (!writePref) { + // If reading the pref, default to true if .ini doesn't exist. + *aSubmitReports = true; + return NS_OK; + } + // Create the file so the INI processor can write to it. + rv = reporterINI->Create(nsIFile::NORMAL_FILE_TYPE, 0600); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCOMPtr iniFactory = + do_GetService("@mozilla.org/xpcom/ini-parser-factory;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr iniParser; + rv = iniFactory->CreateINIParser(reporterINI, getter_AddRefs(iniParser)); + NS_ENSURE_SUCCESS(rv, rv); + + // If we're writing the pref, just set and we're done. + if (writePref) { + nsCOMPtr iniWriter = do_QueryInterface(iniParser); + NS_ENSURE_TRUE(iniWriter, NS_ERROR_FAILURE); + + rv = iniWriter->SetString("Crash Reporter"_ns, "SubmitReport"_ns, + *aSubmitReports ? "1"_ns : "0"_ns); + NS_ENSURE_SUCCESS(rv, rv); + rv = iniWriter->WriteFile(reporterINI); + return rv; + } + + nsAutoCString submitReportValue; + rv = iniParser->GetString("Crash Reporter"_ns, "SubmitReport"_ns, + submitReportValue); + + // Default to "true" if the pref can't be found. + if (NS_FAILED(rv)) + *aSubmitReports = true; + else if (submitReportValue.EqualsASCII("0")) + *aSubmitReports = false; + else + *aSubmitReports = true; + + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + +nsresult GetSubmitReports(bool* aSubmitReports) { + return PrefSubmitReports(aSubmitReports, false); +} + +nsresult SetSubmitReports(bool aSubmitReports) { + nsresult rv; + + nsCOMPtr obsServ = + mozilla::services::GetObserverService(); + if (!obsServ) { + return NS_ERROR_FAILURE; + } + + rv = PrefSubmitReports(&aSubmitReports, true); + if (NS_FAILED(rv)) { + return rv; + } + + obsServ->NotifyObservers(nullptr, "submit-reports-pref-changed", nullptr); + return NS_OK; +} + +static void SetCrashEventsDir(nsIFile* aDir) { + static const XP_CHAR eventsDirectoryEnv[] = + XP_TEXT("MOZ_CRASHREPORTER_EVENTS_DIRECTORY"); + + nsCOMPtr eventsDir = aDir; + + const char* env = PR_GetEnv("CRASHES_EVENTS_DIR"); + if (env && *env) { + NS_NewNativeLocalFile(nsDependentCString(env), false, + getter_AddRefs(eventsDir)); + EnsureDirectoryExists(eventsDir); + } + + xpstring* path = CreatePathFromFile(eventsDir); + if (!path) { + return; // There's no clean failure from this + } + + eventsDirectory = xpstring(*path); +#ifdef XP_WIN + SetEnvironmentVariableW(eventsDirectoryEnv, path->c_str()); +#else + setenv(eventsDirectoryEnv, path->c_str(), /* overwrite */ 1); +#endif + + delete path; +} + +void SetProfileDirectory(nsIFile* aDir) { + nsCOMPtr dir; + aDir->Clone(getter_AddRefs(dir)); + + dir->Append(u"crashes"_ns); + EnsureDirectoryExists(dir); + dir->Append(u"events"_ns); + EnsureDirectoryExists(dir); + SetCrashEventsDir(dir); +} + +void SetUserAppDataDirectory(nsIFile* aDir) { + nsCOMPtr dir; + aDir->Clone(getter_AddRefs(dir)); + + dir->Append(u"Crash Reports"_ns); + EnsureDirectoryExists(dir); + dir->Append(u"events"_ns); + EnsureDirectoryExists(dir); + SetCrashEventsDir(dir); +} + +void UpdateCrashEventsDir() { + const char* env = PR_GetEnv("CRASHES_EVENTS_DIR"); + if (env && *env) { + SetCrashEventsDir(nullptr); + } + + nsCOMPtr eventsDir; + nsresult rv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(eventsDir)); + if (NS_SUCCEEDED(rv)) { + SetProfileDirectory(eventsDir); + return; + } + + rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(eventsDir)); + if (NS_SUCCEEDED(rv)) { + SetUserAppDataDirectory(eventsDir); + return; + } + + NS_WARNING( + "Couldn't get the user appdata directory. Crash events may not be " + "produced."); +} + +bool GetCrashEventsDir(nsAString& aPath) { + if (eventsDirectory.empty()) { + return false; + } + aPath = CONVERT_XP_CHAR_TO_UTF16(eventsDirectory.c_str()); + return true; +} + +void SetMemoryReportFile(nsIFile* aFile) { + if (!gExceptionHandler) { + return; + } + + PathString path; +#ifdef XP_WIN + aFile->GetPath(path); +#else + aFile->GetNativePath(path); +#endif + memoryReportPath = xpstring(path.get()); +} + +nsresult GetDefaultMemoryReportFile(nsIFile** aFile) { + nsCOMPtr defaultMemoryReportFile; + if (!defaultMemoryReportPath) { + nsresult rv = NS_GetSpecialDirectory( + NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(defaultMemoryReportFile)); + if (NS_FAILED(rv)) { + return rv; + } + defaultMemoryReportFile->AppendNative("memory-report.json.gz"_ns); + defaultMemoryReportPath = CreatePathFromFile(defaultMemoryReportFile); + if (!defaultMemoryReportPath) { + return NS_ERROR_FAILURE; + } + } else { + CreateFileFromPath(*defaultMemoryReportPath, + getter_AddRefs(defaultMemoryReportFile)); + if (!defaultMemoryReportFile) { + return NS_ERROR_FAILURE; + } + } + defaultMemoryReportFile.forget(aFile); + return NS_OK; +} + +static void FindPendingDir() { + if (!pendingDirectory.empty()) { + return; + } + nsCOMPtr pendingDir; + nsresult rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(pendingDir)); + if (NS_FAILED(rv)) { + NS_WARNING( + "Couldn't get the user appdata directory, crash dumps will go in an " + "unusual location"); + } else { + pendingDir->Append(u"Crash Reports"_ns); + pendingDir->Append(u"pending"_ns); + + PathString path; +#ifdef XP_WIN + pendingDir->GetPath(path); +#else + pendingDir->GetNativePath(path); +#endif + pendingDirectory = xpstring(path.get()); + } +} + +// The "pending" dir is Crash Reports/pending, from which minidumps +// can be submitted. Because this method may be called off the main thread, +// we store the pending directory as a path. +static bool GetPendingDir(nsIFile** dir) { + // MOZ_ASSERT(OOPInitialized()); + if (pendingDirectory.empty()) { + return false; + } + + nsCOMPtr pending = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if (!pending) { + NS_WARNING("Can't set up pending directory during shutdown."); + return false; + } +#ifdef XP_WIN + pending->InitWithPath(nsDependentString(pendingDirectory.c_str())); +#else + pending->InitWithNativePath(nsDependentCString(pendingDirectory.c_str())); +#endif + pending.swap(*dir); + return true; +} + +// The "limbo" dir is where minidumps go to wait for something else to +// use them. If we're |ShouldReport()|, then the "something else" is +// a minidump submitter, and they're coming from the +// Crash Reports/pending/ dir. Otherwise, we don't know what the +// "somthing else" is, but the minidumps stay in [profile]/minidumps/ +// limbo. +static bool GetMinidumpLimboDir(nsIFile** dir) { + if (ShouldReport()) { + return GetPendingDir(dir); + } else { +#ifndef XP_LINUX + CreateFileFromPath(gExceptionHandler->dump_path(), dir); +#else + CreateFileFromPath(gExceptionHandler->minidump_descriptor().directory(), + dir); +#endif + return nullptr != *dir; + } +} + +void DeleteMinidumpFilesForID(const nsAString& aId, + const Maybe& aAdditionalMinidump) { + nsCOMPtr minidumpFile; + if (GetMinidumpForID(aId, getter_AddRefs(minidumpFile))) { + minidumpFile->Remove(false); + } + + nsCOMPtr extraFile; + if (GetExtraFileForID(aId, getter_AddRefs(extraFile))) { + extraFile->Remove(false); + } + + if (aAdditionalMinidump && GetMinidumpForID(aId, getter_AddRefs(minidumpFile), + aAdditionalMinidump)) { + minidumpFile->Remove(false); + } +} + +bool GetMinidumpForID(const nsAString& id, nsIFile** minidump, + const Maybe& aAdditionalMinidump) { + if (!GetMinidumpLimboDir(minidump)) { + return false; + } + + nsAutoString fileName(id); + + if (aAdditionalMinidump) { + fileName.Append('-'); + fileName.Append(*aAdditionalMinidump); + } + + fileName.Append(u".dmp"_ns); + (*minidump)->Append(fileName); + + bool exists; + if (NS_FAILED((*minidump)->Exists(&exists)) || !exists) { + return false; + } + + return true; +} + +bool GetIDFromMinidump(nsIFile* minidump, nsAString& id) { + if (minidump && NS_SUCCEEDED(minidump->GetLeafName(id))) { + id.ReplaceLiteral(id.Length() - 4, 4, u""); + return true; + } + return false; +} + +bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile) { + if (!GetMinidumpLimboDir(extraFile)) { + return false; + } + + (*extraFile)->Append(id + u".extra"_ns); + + bool exists; + if (NS_FAILED((*extraFile)->Exists(&exists)) || !exists) { + return false; + } + + return true; +} + +bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile) { + nsAutoString leafName; + nsresult rv = minidump->GetLeafName(leafName); + if (NS_FAILED(rv)) return false; + + nsCOMPtr extraF; + rv = minidump->Clone(getter_AddRefs(extraF)); + if (NS_FAILED(rv)) return false; + + leafName.Replace(leafName.Length() - 3, 3, u"extra"_ns); + rv = extraF->SetLeafName(leafName); + if (NS_FAILED(rv)) return false; + + *extraFile = nullptr; + extraF.swap(*extraFile); + return true; +} + +static bool WriteExtraFile(PlatformWriter& pw, + const AnnotationTable& aAnnotations) { + if (!pw.Valid()) { + return false; + } + + JSONAnnotationWriter writer(pw); + WriteAnnotations(writer, aAnnotations); + WriteSynthesizedAnnotations(writer); + + return true; +} + +bool WriteExtraFile(const nsAString& id, const AnnotationTable& annotations) { + nsCOMPtr extra; + if (!GetMinidumpLimboDir(getter_AddRefs(extra))) { + return false; + } + + extra->Append(id + u".extra"_ns); + PathString path; +#ifdef XP_WIN + NS_ENSURE_SUCCESS(extra->GetPath(path), false); +#elif defined(XP_UNIX) + NS_ENSURE_SUCCESS(extra->GetNativePath(path), false); +#endif + + PlatformWriter pw(path.get()); + return WriteExtraFile(pw, annotations); +} + +// This adds annotations that were populated in the main process but are not +// present among the ones that were passed in. Additionally common annotations +// which are present in every crash report are added, including crash time, +// uptime, etc... +static void AddSharedAnnotations(AnnotationTable& aAnnotations) { + MergeContentCrashAnnotations(aAnnotations); + AddCommonAnnotations(aAnnotations); +} + +static void AddChildProcessAnnotations( + AnnotationTable& aAnnotations, nsTArray* aChildAnnotations) { + if (!aChildAnnotations) { + // TODO: We should probably make a list of errors that occurred when + // generating a crash report as more than one can occurr. + aAnnotations[Annotation::DumperError] = "MissingAnnotations"; + return; + } + + for (const auto& annotation : *aChildAnnotations) { + switch (annotation.data.tag) { + case AnnotationData::Tag::Empty: + break; + + case AnnotationData::Tag::UsizeData: + if (annotation.id == + static_cast(Annotation::OOMAllocationSize)) { + // We need to special-case OOMAllocationSize here because it should + // not be added if its value is 0. We'll come up with a more general + // method of skipping ignored values for crash annotations in the + // follow-ups. + if (annotation.data.usize_data._0 != 0) { + aAnnotations[static_cast(annotation.id)] = + nsPrintfCString("%zu", annotation.data.usize_data._0); + } + } else { + aAnnotations[static_cast(annotation.id)] = + nsPrintfCString("%zu", annotation.data.usize_data._0); + } + break; + + case AnnotationData::Tag::NSCStringData: { + const auto& string = annotation.data.nsc_string_data._0; + if (!string.IsEmpty()) { + aAnnotations[static_cast(annotation.id)] = + annotation.data.nsc_string_data._0; + } + } break; + + case AnnotationData::Tag::ByteBuffer: { + if (annotation.id == + static_cast(Annotation::PHCBaseAddress)) { +#ifdef MOZ_PHC + const auto& buffer = annotation.data.byte_buffer._0; + mozilla::phc::AddrInfo addr_info; + memcpy(&addr_info, buffer.Elements(), sizeof(addr_info)); + PopulatePHCAnnotations(aAnnotations, &addr_info); +#endif + } + } break; + } + } +} + +// It really only makes sense to call this function when +// ShouldReport() is true. +// Uses dumpFile's filename to generate memoryReport's filename (same name with +// a different extension) +static bool MoveToPending(nsIFile* dumpFile, nsIFile* extraFile, + nsIFile* memoryReport) { + nsCOMPtr pendingDir; + if (!GetPendingDir(getter_AddRefs(pendingDir))) return false; + + if (NS_FAILED(dumpFile->MoveTo(pendingDir, u""_ns))) { + return false; + } + + if (extraFile && NS_FAILED(extraFile->MoveTo(pendingDir, u""_ns))) { + return false; + } + + if (memoryReport) { + nsAutoString leafName; + nsresult rv = dumpFile->GetLeafName(leafName); + if (NS_FAILED(rv)) { + return false; + } + // Generate the correct memory report filename from the dumpFile's name + leafName.Replace( + leafName.Length() - 4, 4, + static_cast(CONVERT_XP_CHAR_TO_UTF16(memoryReportExtension))); + if (NS_FAILED(memoryReport->MoveTo(pendingDir, leafName))) { + return false; + } + } + + return true; +} + +static void MaybeAnnotateDumperError(const ClientInfo& aClientInfo, + AnnotationTable& aAnnotations) { +#if defined(MOZ_OXIDIZED_BREAKPAD) + if (aClientInfo.had_error()) { + aAnnotations[Annotation::DumperError] = *aClientInfo.error_msg(); + } +#endif +} + +static void OnChildProcessDumpRequested( + void* aContext, const ClientInfo& aClientInfo, + const xpstring& aFilePath) MOZ_NO_THREAD_SAFETY_ANALYSIS { + nsCOMPtr minidump; + + // Hold the mutex until the current dump request is complete, to + // prevent UnsetExceptionHandler() from pulling the rug out from + // under us. + MutexAutoLock lock(*dumpSafetyLock); + if (!isSafeToDump) return; + + CreateFileFromPath(aFilePath, getter_AddRefs(minidump)); + + ProcessId pid = aClientInfo.pid(); + if (ShouldReport()) { + nsCOMPtr memoryReport; + if (!memoryReportPath.empty()) { + CreateFileFromPath(memoryReportPath, getter_AddRefs(memoryReport)); + MOZ_ASSERT(memoryReport); + } + MoveToPending(minidump, nullptr, memoryReport); + } + +#if XP_WIN + nsTArray* child_annotations = mozannotation_retrieve( + reinterpret_cast(aClientInfo.process_handle()), + static_cast(Annotation::Count)); +#elif defined(XP_MACOSX) + nsTArray* child_annotations = mozannotation_retrieve( + aClientInfo.task(), static_cast(Annotation::Count)); +#else + nsTArray* child_annotations = + mozannotation_retrieve(pid, static_cast(Annotation::Count)); +#endif + + // TODO: Write a minimal set of annotations if we fail to read them, and + // add an error to the minidump to highlight this fact. + + { +#ifdef MOZ_CRASHREPORTER_INJECTOR + bool runCallback; +#endif + { + MutexAutoLock lock(*dumpMapLock); + ChildProcessData* pd = pidToMinidump->PutEntry(pid); + MOZ_ASSERT(!pd->minidump); + pd->minidump = minidump; + pd->sequence = ++crashSequence; + pd->annotations = MakeUnique(); + AnnotationTable& annotations = *(pd->annotations); + AddSharedAnnotations(annotations); + AddChildProcessAnnotations(annotations, child_annotations); + + MaybeAnnotateDumperError(aClientInfo, annotations); + +#ifdef MOZ_CRASHREPORTER_INJECTOR + runCallback = nullptr != pd->callback; +#endif + } +#ifdef MOZ_CRASHREPORTER_INJECTOR + if (runCallback) NS_DispatchToMainThread(new ReportInjectedCrash(pid)); +#endif + } + + if (child_annotations) { + mozannotation_free(child_annotations); + } +} + +static bool OOPInitialized() { return pidToMinidump != nullptr; } + +void OOPInit() { + class ProxyToMainThread : public Runnable { + public: + ProxyToMainThread() : Runnable("nsExceptionHandler::ProxyToMainThread") {} + NS_IMETHOD Run() override { + OOPInit(); + return NS_OK; + } + }; + if (!NS_IsMainThread()) { + // This logic needs to run on the main thread + nsCOMPtr mainThread = do_GetMainThread(); + mozilla::SyncRunnable::DispatchToThread(mainThread, + new ProxyToMainThread()); + return; + } + + if (OOPInitialized()) return; + + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_ASSERT(gExceptionHandler != nullptr, + "attempt to initialize OOP crash reporter before in-process " + "crashreporter!"); + +#if defined(XP_WIN) + childCrashNotifyPipe = + mozilla::Smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i", + static_cast(::GetCurrentProcessId())) + .release(); + + const std::wstring dumpPath = gExceptionHandler->dump_path(); + crashServer = new CrashGenerationServer( + std::wstring(NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get()), + nullptr, // default security attributes + nullptr, nullptr, // we don't care about process connect here + OnChildProcessDumpRequested, nullptr, nullptr, nullptr, + nullptr, // we don't care about process exit here + nullptr, nullptr, // we don't care about upload request here + true, // automatically generate dumps + &dumpPath); + + if (sIncludeContextHeap) { + crashServer->set_include_context_heap(sIncludeContextHeap); + } + +#elif defined(XP_LINUX) + if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd, + &clientSocketFd)) + MOZ_CRASH("can't create crash reporter socketpair()"); + + const std::string dumpPath = + gExceptionHandler->minidump_descriptor().directory(); + crashServer = + new CrashGenerationServer(serverSocketFd, OnChildProcessDumpRequested, + nullptr, nullptr, nullptr, true, &dumpPath); + +#elif defined(XP_MACOSX) + childCrashNotifyPipe = mozilla::Smprintf("gecko-crash-server-pipe.%i", + static_cast(getpid())) + .release(); + const std::string dumpPath = gExceptionHandler->dump_path(); + + crashServer = new CrashGenerationServer(childCrashNotifyPipe, nullptr, + nullptr, OnChildProcessDumpRequested, + nullptr, nullptr, nullptr, + true, // automatically generate dumps + dumpPath); +#endif + + if (!crashServer->Start()) MOZ_CRASH("can't start crash reporter server()"); + + pidToMinidump = new ChildMinidumpMap(); + + dumpMapLock = new Mutex("CrashReporter::dumpMapLock"); + + FindPendingDir(); + UpdateCrashEventsDir(); +} + +static void OOPDeinit() { + if (!OOPInitialized()) { + NS_WARNING("OOPDeinit() without successful OOPInit()"); + return; + } + +#ifdef MOZ_CRASHREPORTER_INJECTOR + if (sInjectorThread) { + sInjectorThread->Shutdown(); + NS_RELEASE(sInjectorThread); + } +#endif + + delete crashServer; + crashServer = nullptr; + + delete dumpMapLock; + dumpMapLock = nullptr; + + delete pidToMinidump; + pidToMinidump = nullptr; + +#if defined(XP_WIN) || defined(XP_MACOSX) + free(childCrashNotifyPipe); + childCrashNotifyPipe = nullptr; +#endif +} + +#if defined(XP_WIN) || defined(XP_MACOSX) +// Parent-side API for children +const char* GetChildNotificationPipe() { + if (!GetEnabled()) return kNullNotifyPipe; + + MOZ_ASSERT(OOPInitialized()); + + return childCrashNotifyPipe; +} +#endif + +#ifdef MOZ_CRASHREPORTER_INJECTOR +void InjectCrashReporterIntoProcess(DWORD processID, + InjectorCrashCallback* cb) { + if (!GetEnabled()) return; + + if (!OOPInitialized()) OOPInit(); + + if (!sInjectorThread) { + if (NS_FAILED(NS_NewNamedThread("CrashRep Inject", &sInjectorThread))) + return; + } + + { + MutexAutoLock lock(*dumpMapLock); + ChildProcessData* pd = pidToMinidump->PutEntry(processID); + MOZ_ASSERT(!pd->minidump && !pd->callback); + pd->callback = cb; + pd->minidumpOnly = true; + } + + nsCOMPtr r = new InjectCrashRunnable(processID); + sInjectorThread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL); +} + +NS_IMETHODIMP +ReportInjectedCrash::Run() { + // Crash reporting may have been disabled after this method was dispatched + if (!OOPInitialized()) return NS_OK; + + InjectorCrashCallback* cb; + { + MutexAutoLock lock(*dumpMapLock); + ChildProcessData* pd = pidToMinidump->GetEntry(mPID); + if (!pd || !pd->callback) return NS_OK; + + MOZ_ASSERT(pd->minidump); + + cb = pd->callback; + } + + cb->OnCrash(mPID); + return NS_OK; +} + +void UnregisterInjectorCallback(DWORD processID) { + if (!OOPInitialized()) return; + + MutexAutoLock lock(*dumpMapLock); + pidToMinidump->RemoveEntry(processID); +} + +#endif // MOZ_CRASHREPORTER_INJECTOR + +#if defined(XP_LINUX) + +// Parent-side API for children +bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) { + if (!GetEnabled()) { + *childCrashFd = -1; + *childCrashRemapFd = -1; + return true; + } + + MOZ_ASSERT(OOPInitialized()); + + *childCrashFd = clientSocketFd; + *childCrashRemapFd = gMagicChildCrashReportFd; + + return true; +} + +#endif // defined(XP_LINUX) + +bool SetRemoteExceptionHandler(const char* aCrashPipe) { + MOZ_ASSERT(!gExceptionHandler, "crash client already init'd"); + RegisterRuntimeExceptionModule(); + InitializeAnnotationFacilities(); + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + switch (key) { + case Annotation::MozCrashReason: +#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY + case Annotation::MainThreadRunnableName: +#endif + case Annotation::OOMAllocationSize: +#ifdef MOZ_PHC + case Annotation::PHCBaseAddress: +#endif + break; + + default: + mozannotation_register_nscstring(static_cast(key), + &crashReporterAPIData_Table[key]); + } + } + + mozannotation_register_cstring( + static_cast(Annotation::MozCrashReason), &gMozCrashReason); + +#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY + mozannotation_register_char_buffer( + static_cast(Annotation::MainThreadRunnableName), + &nsThread::sMainThreadRunnableName[0]); +#endif + + mozannotation_register_usize( + static_cast(Annotation::OOMAllocationSize), + &gOOMAllocationSize); + +#ifdef MOZ_PHC + // HACK: We're using the PHCBaseAddress annotation to point to the actual + // PHC address information object. This is because we currently have no + // difference between the internal representation of annotations and their + // external representation. Once we remove the old annotation API this will + // be properly addressed. + mozannotation_register_bytebuffer( + static_cast(Annotation::PHCBaseAddress), + &mozilla::phc::gAddrInfo, sizeof(mozilla::phc::gAddrInfo)); +#endif + +#if defined(XP_WIN) + gExceptionHandler = new google_breakpad::ExceptionHandler( + L"", ChildFilter, ChildMinidumpCallback, + nullptr, // no callback context + google_breakpad::ExceptionHandler::HANDLER_ALL, GetMinidumpType(), + NS_ConvertASCIItoUTF16(aCrashPipe).get(), nullptr); + gExceptionHandler->set_handle_debug_exceptions(true); + +# if defined(HAVE_64BIT_BUILD) + SetJitExceptionHandler(); +# endif +#elif defined(XP_LINUX) + // MinidumpDescriptor requires a non-empty path. + google_breakpad::MinidumpDescriptor path("."); + + gExceptionHandler = new google_breakpad::ExceptionHandler( + path, ChildFilter, ChildMinidumpCallback, + nullptr, // no callback context + true, // install signal handlers + gMagicChildCrashReportFd); +#elif defined(XP_MACOSX) + gExceptionHandler = new google_breakpad::ExceptionHandler( + "", ChildFilter, ChildMinidumpCallback, + nullptr, // no callback context + true, // install signal handlers + aCrashPipe); +#endif + + RecordMainThreadId(); + + oldTerminateHandler = std::set_terminate(&TerminateHandler); + + // we either do remote or nothing, no fallback to regular crash reporting + return gExceptionHandler->IsOutOfProcess(); +} + +void GetAnnotation(uint32_t childPid, Annotation annotation, + nsACString& outStr) { + if (!GetEnabled()) { + return; + } + + MutexAutoLock lock(*dumpMapLock); + + ChildProcessData* pd = pidToMinidump->GetEntry(childPid); + if (!pd) { + return; + } + + outStr = (*pd->annotations)[annotation]; +} + +bool TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, + AnnotationTable& aAnnotations, uint32_t* aSequence) { + if (!GetEnabled()) return false; + + MutexAutoLock lock(*dumpMapLock); + + ChildProcessData* pd = pidToMinidump->GetEntry(childPid); + if (!pd) return false; + + NS_IF_ADDREF(*dump = pd->minidump); + // Only plugin process minidumps taken using the injector don't have + // annotations. + if (!pd->minidumpOnly) { + aAnnotations = *(pd->annotations); + } + if (aSequence) { + *aSequence = pd->sequence; + } + + pidToMinidump->RemoveEntry(pd); + + return !!*dump; +} + +bool FinalizeOrphanedMinidump(uint32_t aChildPid, GeckoProcessType aType, + nsString* aDumpId) { + AnnotationTable annotations; + nsCOMPtr minidump; + + if (!TakeMinidumpForChild(aChildPid, getter_AddRefs(minidump), annotations)) { + return false; + } + + nsAutoString id; + if (!GetIDFromMinidump(minidump, id)) { + return false; + } + + if (aDumpId) { + *aDumpId = id; + } + + annotations[Annotation::ProcessType] = + XRE_ChildProcessTypeToAnnotation(aType); + + return WriteExtraFile(id, annotations); +} + +#ifdef XP_WIN + +// Function invoked by the WER runtime exception handler running in an +// external process. This function isn't used anywhere inside Gecko directly +// but rather invoked via CreateRemoteThread() in the main process. + +// Store this global in a section called mozwerpt where we can find it by just +// looking at the program headers. +# pragma section("mozwerpt", read, executable, shared) + +__declspec(allocate("mozwerpt")) MOZ_EXPORT DWORD WINAPI + WerNotifyProc(LPVOID aParameter) { + const WindowsErrorReportingData* werData = + static_cast(aParameter); + + auto freeParameterOnExit = MakeScopeExit([&aParameter] { + VirtualFree(aParameter, sizeof(WindowsErrorReportingData), MEM_RELEASE); + }); + + // Hold the mutex until the current dump request is complete, to + // prevent UnsetExceptionHandler() from pulling the rug out from + // under us. + MutexAutoLock safetyLock(*dumpSafetyLock); + if (!isSafeToDump || !ShouldReport()) { + return S_OK; + } + + ProcessId pid = werData->mChildPid; + nsCOMPtr minidump; + if (!GetPendingDir(getter_AddRefs(minidump))) { + return S_OK; + } + xpstring minidump_native_name(werData->mMinidumpFile, + werData->mMinidumpFile + 40); + nsString minidump_name(minidump_native_name.c_str()); + minidump->Append(minidump_name); + + { + MutexAutoLock lock(*dumpMapLock); + ChildProcessData* pd = pidToMinidump->PutEntry(pid); + MOZ_ASSERT(!pd->minidump); + pd->minidump = minidump; + pd->sequence = ++crashSequence; + pd->annotations = MakeUnique(); + (*pd->annotations)[Annotation::WindowsErrorReporting] = "1"_ns; + AddSharedAnnotations(*(pd->annotations)); + } + + return S_OK; +} + +#endif // XP_WIN + +//----------------------------------------------------------------------------- +// CreateMinidumpsAndPair() and helpers +// + +/* + * Renames the stand alone dump file aDumpFile to: + * |aOwnerDumpFile-aDumpFileProcessType.dmp| + * and moves it into the same directory as aOwnerDumpFile. Does not + * modify aOwnerDumpFile in any way. + * + * @param aDumpFile - the dump file to associate with aOwnerDumpFile. + * @param aOwnerDumpFile - the new owner of aDumpFile. + * @param aDumpFileProcessType - process name associated with aDumpFile. + */ +static void RenameAdditionalHangMinidump(nsIFile* minidump, + nsIFile* childMinidump, + const nsACString& name) { + nsCOMPtr directory; + childMinidump->GetParent(getter_AddRefs(directory)); + if (!directory) return; + + nsAutoCString leafName; + childMinidump->GetNativeLeafName(leafName); + + // turn ".dmp" into "-.dmp + leafName.Insert("-"_ns + name, leafName.Length() - 4); + + if (NS_FAILED(minidump->MoveToNative(directory, leafName))) { + NS_WARNING("RenameAdditionalHangMinidump failed to move minidump."); + } +} + +// Stores the minidump in the nsIFile pointed by the |context| parameter. +static bool PairedDumpCallback( +#ifdef XP_LINUX + const MinidumpDescriptor& descriptor, +#else + const XP_CHAR* dump_path, const XP_CHAR* minidump_id, +#endif + void* context, +#ifdef XP_WIN + EXCEPTION_POINTERS* /*unused*/, MDRawAssertionInfo* /*unused*/, +#endif + const phc::AddrInfo* addrInfo, bool succeeded) { + XP_CHAR* path = static_cast(context); + size_t size = XP_PATH_MAX; + +#ifdef XP_LINUX + Concat(path, descriptor.path(), &size); +#else + path = Concat(path, dump_path, &size); + path = Concat(path, XP_PATH_SEPARATOR, &size); + path = Concat(path, minidump_id, &size); + Concat(path, dumpFileExtension, &size); +#endif + + return true; +} + +ThreadId CurrentThreadId() { +#if defined(XP_WIN) + return ::GetCurrentThreadId(); +#elif defined(XP_LINUX) + return sys_gettid(); +#elif defined(XP_MACOSX) + // Just return an index, since Mach ports can't be directly serialized + 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 -1; + + for (unsigned int i = 0; i < thread_count; ++i) { + if (threads_for_task[i] == mach_thread_self()) return i; + } + abort(); +#else +# error "Unsupported platform" +#endif +} + +#ifdef XP_MACOSX +static mach_port_t GetChildThread(ProcessHandle childPid, + ThreadId childBlamedThread) { + mach_port_t childThread = MACH_PORT_NULL; + thread_act_port_array_t threads_for_task; + mach_msg_type_number_t thread_count; + + if (task_threads(childPid, &threads_for_task, &thread_count) == + KERN_SUCCESS && + childBlamedThread < thread_count) { + childThread = threads_for_task[childBlamedThread]; + } + + return childThread; +} +#endif + +bool CreateMinidumpsAndPair(ProcessHandle aTargetHandle, + ThreadId aTargetBlamedThread, + const nsACString& aIncomingPairName, + AnnotationTable& aTargetAnnotations, + nsIFile** aMainDumpOut) { + if (!GetEnabled()) { + return false; + } + + AutoIOInterposerDisable disableIOInterposition; + +#ifdef XP_MACOSX + mach_port_t targetThread = GetChildThread(aTargetHandle, aTargetBlamedThread); +#else + ThreadId targetThread = aTargetBlamedThread; +#endif + + xpstring dump_path; +#ifndef XP_LINUX + dump_path = gExceptionHandler->dump_path(); +#else + dump_path = gExceptionHandler->minidump_descriptor().directory(); +#endif + + // Ugly, but due to Breakpad limitations we can't allocate memory in the + // callback when generating a dump of the calling process. + XP_CHAR minidumpPath[XP_PATH_MAX] = {}; + + // dump the target + if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild( + aTargetHandle, targetThread, dump_path, PairedDumpCallback, + static_cast(minidumpPath) +#ifdef XP_WIN + , + GetMinidumpType() +#endif + )) { + return false; + } + + nsCOMPtr targetMinidump; + CreateFileFromPath(xpstring(minidumpPath), getter_AddRefs(targetMinidump)); + + // Create a dump of this process. + if (!google_breakpad::ExceptionHandler::WriteMinidump( + dump_path, +#ifdef XP_MACOSX + true, +#endif + PairedDumpCallback, static_cast(minidumpPath) +#ifdef XP_WIN + , + GetMinidumpType() +#endif + )) { + targetMinidump->Remove(false); + return false; + } + + nsCOMPtr incomingDump; + CreateFileFromPath(xpstring(minidumpPath), getter_AddRefs(incomingDump)); + + RenameAdditionalHangMinidump(incomingDump, targetMinidump, aIncomingPairName); + + if (ShouldReport()) { + MoveToPending(targetMinidump, nullptr, nullptr); + MoveToPending(incomingDump, nullptr, nullptr); + } +#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST) + DllBlocklist_Shutdown(); +#endif + + AddSharedAnnotations(aTargetAnnotations); +#if XP_WIN + nsTArray* child_annotations = + mozannotation_retrieve(reinterpret_cast(aTargetHandle), + static_cast(Annotation::Count)); +#else + nsTArray* child_annotations = mozannotation_retrieve( + aTargetHandle, static_cast(Annotation::Count)); +#endif + AddChildProcessAnnotations(aTargetAnnotations, child_annotations); + if (child_annotations) { + mozannotation_free(child_annotations); + } + + targetMinidump.forget(aMainDumpOut); + + return true; +} + +bool UnsetRemoteExceptionHandler(bool wasSet) { + // On Linux we don't unset breakpad's exception handler if the sandbox is + // enabled because it requires invoking `sigaltstack` and we don't want to + // allow that syscall in the sandbox. See bug 1622452. +#if !defined(XP_LINUX) || !defined(MOZ_SANDBOX) + if (wasSet) { + std::set_terminate(oldTerminateHandler); + delete gExceptionHandler; + gExceptionHandler = nullptr; + } +#endif + TeardownAnnotationFacilities(); + + return true; +} + +#if defined(MOZ_WIDGET_ANDROID) +void SetNotificationPipeForChild(int childCrashFd) { + gMagicChildCrashReportFd = childCrashFd; +} +#endif + +} // namespace CrashReporter + +#if defined(__ANDROID_API__) && (__ANDROID_API__ < 24) + +// Bionic introduced support for getgrgid_r() and getgrnam_r() only in version +// 24 (that is Android Nougat / 7.1.2). Since GeckoView is built by version 16 +// (32-bit) or 21 (64-bit), those functions aren't defined, but nix needs them +// and minidump-writer relies on nix. These functions should never be called in +// practice hence we implement them only to satisfy nix linking requirements but +// we crash if we accidentally enter them. + +extern "C" { + +int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, + struct group** result) { + MOZ_CRASH("getgrgid_r() is not available"); + return EPERM; +} + +int getgrnam_r(const char* name, struct group* grp, char* buf, size_t buflen, + struct group** result) { + MOZ_CRASH("getgrnam_r() is not available"); + return EPERM; +} + +int mlockall(int flags) { + MOZ_CRASH("mlockall() is not available"); + return EPERM; +} + +int munlockall(void) { + MOZ_CRASH("munlockall() is not available"); + return EPERM; +} +} + +#endif // __ANDROID_API__ && (__ANDROID_API__ < 24) diff --git a/toolkit/crashreporter/nsExceptionHandler.h b/toolkit/crashreporter/nsExceptionHandler.h new file mode 100644 index 0000000000..f81cc07c8c --- /dev/null +++ b/toolkit/crashreporter/nsExceptionHandler.h @@ -0,0 +1,323 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This header has two implementations, the real one in nsExceptionHandler.cpp +// and a dummy in nsDummyExceptionHandler.cpp. The latter is used in builds +// configured with --disable-crashreporter. If you add or remove a function +// from this header you must update both implementations otherwise you'll break +// builds that disable the crash reporter. + +#ifndef nsExceptionHandler_h__ +#define nsExceptionHandler_h__ + +#include "mozilla/Assertions.h" +#include "mozilla/EnumeratedArray.h" +#include "mozilla/Maybe.h" + +#include "CrashAnnotations.h" + +#include +#include +#include "nsError.h" +#include "nsString.h" +#include "nsXULAppAPI.h" +#include "prio.h" + +#if defined(XP_WIN) +# ifdef WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +# endif +# include +#endif + +#if defined(XP_MACOSX) +# include +#endif + +#if defined(XP_LINUX) +# include +#endif + +class nsIFile; + +namespace CrashReporter { + +using mozilla::Maybe; +using mozilla::Nothing; + +/** + * Returns true if the crash reporter is using the dummy implementation. + */ +static inline bool IsDummy() { +#ifdef MOZ_CRASHREPORTER + return false; +#else + return true; +#endif +} + +nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force = false); +nsresult UnsetExceptionHandler(); + +/** + * Tell the crash reporter to recalculate where crash events files should go. + * SetCrashEventsDir is used before XPCOM is initialized from the startup + * code. + * + * UpdateCrashEventsDir uses the directory service to re-set the + * crash event directory based on the current profile. + * + * 1. If environment variable is present, use it. We don't expect + * the environment variable except for tests and other atypical setups. + * 2. /crashes/events + * 3. /Crash Reports/events + */ +void SetUserAppDataDirectory(nsIFile* aDir); +void SetProfileDirectory(nsIFile* aDir); +void UpdateCrashEventsDir(); +void SetMemoryReportFile(nsIFile* aFile); +nsresult GetDefaultMemoryReportFile(nsIFile** aFile); + +/** + * Get the path where crash event files should be written. + */ +bool GetCrashEventsDir(nsAString& aPath); + +bool GetEnabled(); +bool GetServerURL(nsACString& aServerURL); +nsresult SetServerURL(const nsACString& aServerURL); +bool GetMinidumpPath(nsAString& aPath); +nsresult SetMinidumpPath(const nsAString& aPath); + +// These functions are thread safe and can be called in both the parent and +// child processes. Annotations added in the main process will be included in +// child process crashes too unless the child process sets its own annotations. +// If it does the child-provided annotation overrides the one set in the parent. +nsresult AnnotateCrashReport(Annotation key, bool data); +nsresult AnnotateCrashReport(Annotation key, int data); +nsresult AnnotateCrashReport(Annotation key, unsigned int data); +nsresult AnnotateCrashReport(Annotation key, const nsACString& data); +nsresult AppendToCrashReportAnnotation(Annotation key, const nsACString& data); +nsresult RemoveCrashReportAnnotation(Annotation key); +nsresult AppendAppNotesToCrashReport(const nsACString& data); + +// RAII class for setting a crash annotation during a limited scope of time. +// Will reset the named annotation to its previous value when destroyed. +// +// This type's behavior is identical to that of AnnotateCrashReport(). +class MOZ_RAII AutoAnnotateCrashReport final { + public: + AutoAnnotateCrashReport(Annotation key, bool data); + AutoAnnotateCrashReport(Annotation key, int data); + AutoAnnotateCrashReport(Annotation key, unsigned int data); + AutoAnnotateCrashReport(Annotation key, const nsACString& data); + ~AutoAnnotateCrashReport(); + +#ifdef MOZ_CRASHREPORTER + private: + Annotation mKey; + nsCString mPrevious; +#endif +}; + +void AnnotateOOMAllocationSize(size_t size); +void AnnotateTexturesSize(size_t size); +nsresult SetGarbageCollecting(bool collecting); +void SetEventloopNestingLevel(uint32_t level); +void SetMinidumpAnalysisAllThreads(); +void ClearInactiveStateStart(); +void SetInactiveStateStart(); + +nsresult SetRestartArgs(int argc, char** argv); +nsresult SetupExtraData(nsIFile* aAppDataDirectory, const nsACString& aBuildID); +// Registers an additional memory region to be included in the minidump +nsresult RegisterAppMemory(void* ptr, size_t length); +nsresult UnregisterAppMemory(void* ptr); + +// Include heap regions of the crash context. +void SetIncludeContextHeap(bool aValue); + +void GetAnnotation(uint32_t childPid, Annotation annotation, + nsACString& outStr); + +// Functions for working with minidumps and .extras +typedef mozilla::EnumeratedArray + AnnotationTable; +void DeleteMinidumpFilesForID( + const nsAString& aId, + const Maybe& aAdditionalMinidump = Nothing()); +bool GetMinidumpForID(const nsAString& id, nsIFile** minidump, + const Maybe& aAdditionalMinidump = Nothing()); +bool GetIDFromMinidump(nsIFile* minidump, nsAString& id); +bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile); +bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile); +bool WriteExtraFile(const nsAString& id, const AnnotationTable& annotations); + +/** + * Copies the non-empty annotations in the source table to the destination + * overwriting the corresponding entries. + */ +void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc); + +#ifdef XP_WIN +nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo); +#endif +#ifdef XP_LINUX +bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc); +#endif +#ifdef XP_MACOSX +nsresult AppendObjCExceptionInfoToAppNotes(void* inException); +#endif +nsresult GetSubmitReports(bool* aSubmitReport); +nsresult SetSubmitReports(bool aSubmitReport); + +#ifdef XP_WIN +// This data is stored in the parent process, there is one copy for each child +// process. The mChildPid and mMinidumpFile fields are filled by the WER runtime +// exception module when the associated child process crashes. +struct WindowsErrorReportingData { + // PID of the child process that crashed. + DWORD mChildPid; + // Filename of the generated minidump; this is not a 0-terminated string + char mMinidumpFile[40]; +}; +#endif // XP_WIN + +// Out-of-process crash reporter API. + +// Initializes out-of-process crash reporting. This method must be called +// before the platform-specific notification pipe APIs are called. If called +// from off the main thread, this method will synchronously proxy to the main +// thread. +void OOPInit(); + +// Return true if a dump was found for |childPid|, and return the +// path in |dump|. The caller owns the last reference to |dump| if it +// is non-nullptr. The annotations for the crash will be stored in +// |aAnnotations|. The sequence parameter will be filled with an ordinal +// indicating which remote process crashed first. +bool TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, + AnnotationTable& aAnnotations, + uint32_t* aSequence = nullptr); + +/** + * If a dump was found for |childPid| then write a minimal .extra file to + * complete it and remove it from the list of pending crash dumps. It's + * required to call this method after a non-main process crash if the crash + * report could not be finalized via the CrashReporterHost (for example because + * it wasn't instanced yet). + * + * @param aChildPid The pid of the crashed child process + * @param aType The type of the crashed process + * @param aDumpId A string that will be filled with the dump ID + */ +[[nodiscard]] bool FinalizeOrphanedMinidump(uint32_t aChildPid, + GeckoProcessType aType, + nsString* aDumpId = nullptr); + +#if defined(XP_WIN) +typedef HANDLE ProcessHandle; +typedef DWORD ProcessId; +typedef DWORD ThreadId; +typedef HANDLE FileHandle; +const FileHandle kInvalidFileHandle = INVALID_HANDLE_VALUE; +#elif defined(XP_MACOSX) +typedef task_t ProcessHandle; +typedef pid_t ProcessId; +typedef mach_port_t ThreadId; +typedef int FileHandle; +const FileHandle kInvalidFileHandle = -1; +#else +typedef int ProcessHandle; +typedef pid_t ProcessId; +typedef int ThreadId; +typedef int FileHandle; +const FileHandle kInvalidFileHandle = -1; +#endif + +// Return the current thread's ID. +// +// XXX: this is a somewhat out-of-place interface to expose through +// crashreporter, but it takes significant work to call sys_gettid() +// correctly on Linux and breakpad has already jumped through those +// hoops for us. +ThreadId CurrentThreadId(); + +/* + * Take a minidump of the target process and pair it with a new minidump of the + * calling process and thread. The caller will own both dumps after this call. + * If this function fails it will attempt to delete any files that were created. + * + * The .extra information created will not include an 'additional_minidumps' + * annotation. + * + * @param aTargetPid The target process for the minidump. + * @param aTargetBlamedThread The target thread for the minidump. + * @param aIncomingPairName The name to apply to the paired dump the caller + * passes in. + * @param aTargetDumpOut The target minidump file paired up with the new one. + * @param aTargetAnnotations The crash annotations of the target process. + * @return bool indicating success or failure + */ +bool CreateMinidumpsAndPair(ProcessHandle aTargetPid, + ThreadId aTargetBlamedThread, + const nsACString& aIncomingPairName, + AnnotationTable& aTargetAnnotations, + nsIFile** aTargetDumpOut); + +#if defined(XP_WIN) || defined(XP_MACOSX) +// Parent-side API for children +const char* GetChildNotificationPipe(); + +# ifdef MOZ_CRASHREPORTER_INJECTOR +// Inject a crash report client into an arbitrary process, and inform the +// callback object when it crashes. Parent process only. + +class InjectorCrashCallback { + public: + InjectorCrashCallback() {} + + /** + * Inform the callback of a crash. The client code should call + * TakeMinidumpForChild to remove it from the PID mapping table. + * + * The callback will not be fired if the client has already called + * TakeMinidumpForChild for this process ID. + */ + virtual void OnCrash(DWORD processID) = 0; +}; + +// This method implies OOPInit +void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb); +void UnregisterInjectorCallback(DWORD processID); +# endif +#else +// Parent-side API for children + +// Set the outparams for crash reporter server's fd (|childCrashFd|) +// and the magic fd number it should be remapped to +// (|childCrashRemapFd|) before exec() in the child process. +// |SetRemoteExceptionHandler()| in the child process expects to find +// the server at |childCrashRemapFd|. Return true if successful. +// +// If crash reporting is disabled, both outparams will be set to -1 +// and |true| will be returned. +bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd); + +#endif // XP_WIN + +// Child-side API +bool SetRemoteExceptionHandler(const char* aCrashPipe = nullptr); +bool UnsetRemoteExceptionHandler(bool wasSet = true); + +#if defined(MOZ_WIDGET_ANDROID) +// Android creates child process as services so we must explicitly set +// the handle for the pipe since it can't get remapped to a default value. +void SetNotificationPipeForChild(FileHandle childCrashFd); +#endif + +} // namespace CrashReporter + +#endif /* nsExceptionHandler_h__ */ diff --git a/toolkit/crashreporter/nsExceptionHandlerUtils.cpp b/toolkit/crashreporter/nsExceptionHandlerUtils.cpp new file mode 100644 index 0000000000..e7f70e599b --- /dev/null +++ b/toolkit/crashreporter/nsExceptionHandlerUtils.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsExceptionHandlerUtils.h" + +#include + +#include "double-conversion/double-conversion.h" + +// Format a non-negative double to a string, without using C-library functions, +// which need to be avoided (.e.g. bug 1240160, comment 10). Return false if +// we failed to get the formatting done correctly. +bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength) { + // aBufferLength is the size of the buffer. Be paranoid. + aBuffer[aBufferLength - 1] = '\0'; + + if (aValue < 0) { + return false; + } + + int length, point, i; + bool sign; + bool ok = true; + double_conversion::DoubleToStringConverter::DoubleToAscii( + aValue, double_conversion::DoubleToStringConverter::SHORTEST, 8, aBuffer, + aBufferLength, &sign, &length, &point); + + // length does not account for the 0 terminator. + if (length > point && (length + 1) < (aBufferLength - 1)) { + // We have to insert a decimal point. Not worried about adding a leading + // zero in the < 1 (point == 0) case. + aBuffer[length + 1] = '\0'; + for (i = length; i > std::max(point, 0); i -= 1) { + aBuffer[i] = aBuffer[i - 1]; + } + aBuffer[i] = '.'; // Not worried about locales + } else if (length < point) { + // Trailing zeros scenario + for (i = length; i < point; i += 1) { + if (i >= aBufferLength - 2) { + ok = false; + } + aBuffer[i] = '0'; + } + aBuffer[i] = '\0'; + } + return ok; +} diff --git a/toolkit/crashreporter/nsExceptionHandlerUtils.h b/toolkit/crashreporter/nsExceptionHandlerUtils.h new file mode 100644 index 0000000000..e6578a6fa4 --- /dev/null +++ b/toolkit/crashreporter/nsExceptionHandlerUtils.h @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsExceptionHandlerUtils_h__ +#define nsExceptionHandlerUtils_h__ + +bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength); + +#endif // nsExceptionHandlerUtils_h__ diff --git a/toolkit/crashreporter/process_reader/Cargo.toml b/toolkit/crashreporter/process_reader/Cargo.toml new file mode 100644 index 0000000000..f84a00a29f --- /dev/null +++ b/toolkit/crashreporter/process_reader/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "process_reader" +version = "0.1.0" +authors = ["Gabriele Svelto"] +edition = "2018" +license = "MPL-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +goblin = { version = "0.7", features = ["elf32", "elf64", "pe32", "pe64"] } +memoffset = "0.9" +mozilla-central-workspace-hack = { version = "0.1", optional = true } +thiserror = "1.0" + +[target."cfg(target_os = \"windows\")".dependencies] +[dependencies.windows-sys] +version = "0.52" +features = [ + "Win32_Foundation", + "Win32_System_Diagnostics_Debug", + "Win32_System_ProcessStatus", +] diff --git a/toolkit/crashreporter/process_reader/src/error.rs b/toolkit/crashreporter/process_reader/src/error.rs new file mode 100644 index 0000000000..af4d803a7a --- /dev/null +++ b/toolkit/crashreporter/process_reader/src/error.rs @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ProcessReaderError { + #[error("Could not convert address {0}")] + ConvertAddressError(#[from] std::num::TryFromIntError), + #[cfg(target_os = "windows")] + #[error("Cannot enumerate the target process's modules")] + EnumProcessModulesError, + #[error("goblin failed to parse a module")] + GoblinError(#[from] goblin::error::Error), + #[error("Address was out of bounds")] + InvalidAddress, + #[error("Could not read from the target process address space")] + ReadFromProcessError(#[from] ReadError), + #[cfg(target_os = "windows")] + #[error("Section was not found")] + SectionNotFound, +} + +#[derive(Debug, Error)] +pub enum ReadError { + #[cfg(target_os = "windows")] + #[error("ReadProcessMemory failed")] + ReadProcessMemoryError, +} diff --git a/toolkit/crashreporter/process_reader/src/lib.rs b/toolkit/crashreporter/process_reader/src/lib.rs new file mode 100644 index 0000000000..1189ff144e --- /dev/null +++ b/toolkit/crashreporter/process_reader/src/lib.rs @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#[cfg(target_os = "windows")] +type ProcessHandle = windows_sys::Win32::Foundation::HANDLE; + +pub struct ProcessReader { + process: ProcessHandle, +} + +mod error; +mod process_reader; diff --git a/toolkit/crashreporter/process_reader/src/process_reader.rs b/toolkit/crashreporter/process_reader/src/process_reader.rs new file mode 100644 index 0000000000..1473aafa09 --- /dev/null +++ b/toolkit/crashreporter/process_reader/src/process_reader.rs @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#[cfg(target_os = "windows")] +mod windows; diff --git a/toolkit/crashreporter/process_reader/src/process_reader/windows.rs b/toolkit/crashreporter/process_reader/src/process_reader/windows.rs new file mode 100644 index 0000000000..1dd1a13049 --- /dev/null +++ b/toolkit/crashreporter/process_reader/src/process_reader/windows.rs @@ -0,0 +1,218 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::{ + convert::TryInto, + ffi::OsString, + mem::{size_of, MaybeUninit}, + os::windows::ffi::OsStringExt, + ptr::null_mut, +}; + +use windows_sys::Win32::{ + Foundation::{FALSE, HMODULE, MAX_PATH}, + System::{ + Diagnostics::Debug::ReadProcessMemory, + ProcessStatus::{ + GetModuleBaseNameW, K32EnumProcessModules, K32GetModuleInformation, MODULEINFO, + }, + }, +}; + +use crate::{ + error::{ProcessReaderError, ReadError}, + ProcessHandle, ProcessReader, +}; + +impl ProcessReader { + pub fn new(process: ProcessHandle) -> Result { + Ok(ProcessReader { process }) + } + + pub fn find_section( + &self, + module_name: &str, + section_name: &str, + ) -> Result { + let modules = self.get_module_list()?; + + modules + .iter() + .filter(|&&module| { + let name = self.get_module_name(module); + // Crude way of mimicking Windows lower-case comparisons but + // sufficient for our use-cases. + name.is_some_and(|name| name.eq_ignore_ascii_case(module_name)) + }) + .find_map(|&module| { + self.get_module_info(module).and_then(|info| { + self.find_section_in_module( + section_name, + info.lpBaseOfDll as usize, + info.SizeOfImage as usize, + ) + .ok() + }) + }) + .ok_or(ProcessReaderError::InvalidAddress) + } + + fn get_module_list(&self) -> Result, ProcessReaderError> { + let mut module_num: usize = 100; + let mut required_buffer_size: u32 = 0; + let mut module_array = Vec::::with_capacity(module_num); + + loop { + let buffer_size: u32 = (module_num * size_of::()).try_into()?; + let res = unsafe { + K32EnumProcessModules( + self.process, + module_array.as_mut_ptr() as *mut _, + buffer_size, + &mut required_buffer_size as *mut _, + ) + }; + + module_num = required_buffer_size as usize / size_of::(); + + if res == 0 { + if required_buffer_size > buffer_size { + module_array = Vec::::with_capacity(module_num); + } else { + return Err(ProcessReaderError::EnumProcessModulesError); + } + } else { + break; + } + } + + // SAFETY: module_array has been filled by K32EnumProcessModules() + unsafe { + module_array.set_len(module_num); + }; + + Ok(module_array) + } + + fn get_module_name(&self, module: HMODULE) -> Option { + let mut path: [u16; MAX_PATH as usize] = [0; MAX_PATH as usize]; + let res = + unsafe { GetModuleBaseNameW(self.process, module, (&mut path).as_mut_ptr(), MAX_PATH) }; + + if res == 0 { + None + } else { + let name = OsString::from_wide(&path[0..res as usize]); + let name = name.to_str()?; + Some(name.to_string()) + } + } + + fn get_module_info(&self, module: HMODULE) -> Option { + let mut info: MaybeUninit = MaybeUninit::uninit(); + let res = unsafe { + K32GetModuleInformation( + self.process, + module, + info.as_mut_ptr(), + size_of::() as u32, + ) + }; + + if res == 0 { + None + } else { + let info = unsafe { info.assume_init() }; + Some(info) + } + } + + fn find_section_in_module( + &self, + section_name: &str, + module_address: usize, + size: usize, + ) -> Result { + // We read only the first page from the module, this should be more than + // enough to read the header and section list. In the future we might do + // this incrementally but for now goblin requires an array to parse + // so we can't do it just yet. + let page_size = 4096; + if size < page_size { + // Don't try to read from the target module if it's too small + return Err(ProcessReaderError::ReadFromProcessError( + ReadError::ReadProcessMemoryError, + )); + } + + let bytes = self.copy_array(module_address as _, 4096)?; + let header = goblin::pe::header::Header::parse(&bytes)?; + + // Skip the PE header so we can parse the sections + let optional_header_offset = header.dos_header.pe_pointer as usize + + goblin::pe::header::SIZEOF_PE_MAGIC + + goblin::pe::header::SIZEOF_COFF_HEADER; + let offset = + &mut (optional_header_offset + header.coff_header.size_of_optional_header as usize); + + let sections = header.coff_header.sections(&bytes, offset)?; + + for section in sections { + if section.name.eq(section_name.as_bytes()) { + let address = module_address.checked_add(section.virtual_address as usize); + return address.ok_or(ProcessReaderError::InvalidAddress); + } + } + + Err(ProcessReaderError::SectionNotFound) + } + + pub fn copy_object_shallow(&self, src: usize) -> Result, ReadError> { + let mut object = MaybeUninit::::uninit(); + let res = unsafe { + ReadProcessMemory( + self.process, + src as _, + object.as_mut_ptr() as _, + size_of::(), + null_mut(), + ) + }; + + if res != FALSE { + Ok(object) + } else { + Err(ReadError::ReadProcessMemoryError) + } + } + + pub fn copy_object(&self, src: usize) -> Result { + let object = self.copy_object_shallow(src)?; + Ok(unsafe { object.assume_init() }) + } + + pub fn copy_array(&self, src: usize, num: usize) -> Result, ReadError> { + let num_of_bytes = num * size_of::(); + let mut array: Vec = Vec::with_capacity(num); + let res = unsafe { + ReadProcessMemory( + self.process, + src as _, + array.as_mut_ptr() as _, + num_of_bytes, + null_mut(), + ) + }; + + if res != FALSE { + unsafe { + array.set_len(num); + } + + Ok(array) + } else { + Err(ReadError::ReadProcessMemoryError) + } + } +} diff --git a/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml b/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml new file mode 100644 index 0000000000..b4bbd8e40b --- /dev/null +++ b/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rust_minidump_writer_linux" +version = "0.1.0" +authors = ["Martin Sirringhaus"] +edition = "2018" +license = "MPL-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +crash-context = "0.6.1" +minidump-writer = "0.8.3" +libc = "0.2.74" +anyhow = "1.0" +nsstring = { path = "../../../xpcom/rust/nsstring/" } diff --git a/toolkit/crashreporter/rust_minidump_writer_linux/cbindgen.toml b/toolkit/crashreporter/rust_minidump_writer_linux/cbindgen.toml new file mode 100644 index 0000000000..429af4d723 --- /dev/null +++ b/toolkit/crashreporter/rust_minidump_writer_linux/cbindgen.toml @@ -0,0 +1,15 @@ +header = """/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */""" +autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */ +""" +include_version = true +braces = "SameLine" +line_length = 100 +tab_width = 2 +language = "C++" +include_guard = "rust_minidump_writer_linux_ffi_generated_h" +sys_includes = ["signal.h", "sys/signalfd.h"] + +[export] +exclude = ["fpregset_t"] diff --git a/toolkit/crashreporter/rust_minidump_writer_linux/moz.build b/toolkit/crashreporter/rust_minidump_writer_linux/moz.build new file mode 100644 index 0000000000..834a97de28 --- /dev/null +++ b/toolkit/crashreporter/rust_minidump_writer_linux/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +if CONFIG["COMPILE_ENVIRONMENT"]: + # This tells mach to run cbindgen and that this header-file should be created + CbindgenHeader( + "rust_minidump_writer_linux_ffi_generated.h", + inputs=["/toolkit/crashreporter/rust_minidump_writer_linux"], + ) + + # This tells mach to copy that generated file to obj/dist/includes/mozilla/toolkit/crashreporter/ + EXPORTS.mozilla.toolkit.crashreporter += [ + "!rust_minidump_writer_linux_ffi_generated.h", + ] diff --git a/toolkit/crashreporter/rust_minidump_writer_linux/src/lib.rs b/toolkit/crashreporter/rust_minidump_writer_linux/src/lib.rs new file mode 100644 index 0000000000..fe5f30943e --- /dev/null +++ b/toolkit/crashreporter/rust_minidump_writer_linux/src/lib.rs @@ -0,0 +1,137 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +extern crate minidump_writer; + +use anyhow; +use libc::pid_t; +use minidump_writer::crash_context::CrashContext; +use minidump_writer::minidump_writer::MinidumpWriter; +use nsstring::nsCString; +use std::ffi::CStr; +use std::mem::{self, MaybeUninit}; +use std::os::raw::c_char; + +// This function will be exposed to C++ +#[no_mangle] +pub unsafe extern "C" fn write_minidump_linux( + dump_path: *const c_char, + child: pid_t, + child_blamed_thread: pid_t, + error_msg: &mut nsCString, +) -> bool { + assert!(!dump_path.is_null()); + let c_path = CStr::from_ptr(dump_path); + let path = match c_path.to_str() { + Ok(s) => s, + Err(x) => { + error_msg.assign(&format!( + "Wrapper error. Path not convertable: {:#}", + anyhow::Error::new(x) + )); + return false; + } + }; + + let mut dump_file = match std::fs::OpenOptions::new() + .create(true) // Create file if it doesn't exist + .write(true) // Truncate file + .open(path) + { + Ok(f) => f, + Err(x) => { + error_msg.assign(&format!( + "Wrapper error when opening minidump destination at {:?}: {:#}", + path, + anyhow::Error::new(x) + )); + return false; + } + }; + + match MinidumpWriter::new(child, child_blamed_thread).dump(&mut dump_file) { + Ok(_) => { + return true; + } + Err(x) => { + error_msg.assign(&format!("{:#}", anyhow::Error::new(x))); + return false; + } + } +} + +#[allow(non_camel_case_types)] +#[cfg(not(target_arch = "arm"))] +type fpregset_t = crash_context::fpregset_t; +#[allow(non_camel_case_types)] +#[cfg(target_arch = "arm")] +pub struct fpregset_t {} + +// This function will be exposed to C++ +#[no_mangle] +pub unsafe extern "C" fn write_minidump_linux_with_context( + dump_path: *const c_char, + child: pid_t, + ucontext: *const crash_context::ucontext_t, + #[allow(unused)] float_state: *const fpregset_t, + siginfo: *const libc::signalfd_siginfo, + child_thread: libc::pid_t, + error_msg: &mut nsCString, +) -> bool { + let c_path = CStr::from_ptr(dump_path); + + let mut crash_context: MaybeUninit = mem::MaybeUninit::zeroed(); + let cc = &mut *crash_context.as_mut_ptr(); + + core::ptr::copy_nonoverlapping(siginfo, &mut cc.siginfo, 1); + core::ptr::copy_nonoverlapping(ucontext, &mut cc.context, 1); + #[cfg(not(target_arch = "arm"))] + core::ptr::copy_nonoverlapping(float_state, &mut cc.float_state, 1); + + cc.pid = child; + cc.tid = child_thread; + let crash_context = crash_context.assume_init(); + let crash_context = CrashContext { + inner: crash_context, + }; + + let path = match c_path.to_str() { + Ok(s) => s, + Err(x) => { + error_msg.assign(&format!( + "Wrapper error. Path not convertable: {:#}", + anyhow::Error::new(x) + )); + return false; + } + }; + + let mut dump_file = match std::fs::OpenOptions::new() + .create(true) // Create file if it doesn't exist + .write(true) // Truncate file + .open(path) + { + Ok(f) => f, + Err(x) => { + error_msg.assign(&format!( + "Wrapper error when opening minidump destination at {:?}: {:#}", + path, + anyhow::Error::new(x) + )); + return false; + } + }; + + match MinidumpWriter::new(child, child_thread) + .set_crash_context(crash_context) + .dump(&mut dump_file) + { + Ok(_) => { + return true; + } + Err(x) => { + error_msg.assign(&format!("{:#}", anyhow::Error::new(x))); + return false; + } + } +} diff --git a/toolkit/crashreporter/test/CrashTestUtils.sys.mjs b/toolkit/crashreporter/test/CrashTestUtils.sys.mjs new file mode 100644 index 0000000000..13cf1fec49 --- /dev/null +++ b/toolkit/crashreporter/test/CrashTestUtils.sys.mjs @@ -0,0 +1,106 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +export var CrashTestUtils = { + // These will be defined using ctypes APIs below. + crash: null, + dumpHasStream: null, + dumpHasInstructionPointerMemory: null, + dumpWin64CFITestSymbols: null, + enablePHC: null, + + // Constants for crash() + // Keep these in sync with nsTestCrasher.cpp! + CRASH_INVALID_POINTER_DEREF: 0, + CRASH_PURE_VIRTUAL_CALL: 1, + CRASH_RUNTIMEABORT: 2, + CRASH_OOM: 3, + CRASH_MOZ_CRASH: 4, + CRASH_ABORT: 5, + CRASH_UNCAUGHT_EXCEPTION: 6, + CRASH_X64CFI_NO_MANS_LAND: 7, + CRASH_X64CFI_LAUNCHER: 8, + CRASH_X64CFI_UNKNOWN_OPCODE: 9, + CRASH_X64CFI_PUSH_NONVOL: 10, + CRASH_X64CFI_ALLOC_SMALL: 11, + CRASH_X64CFI_ALLOC_LARGE: 12, + CRASH_X64CFI_SAVE_NONVOL: 15, + CRASH_X64CFI_SAVE_NONVOL_FAR: 16, + CRASH_X64CFI_SAVE_XMM128: 17, + CRASH_X64CFI_SAVE_XMM128_FAR: 18, + CRASH_X64CFI_EPILOG: 19, + CRASH_X64CFI_EOF: 20, + CRASH_PHC_USE_AFTER_FREE: 21, + CRASH_PHC_DOUBLE_FREE: 22, + CRASH_PHC_BOUNDS_VIOLATION: 23, + CRASH_HEAP_CORRUPTION: 24, + CRASH_EXC_GUARD: 25, + CRASH_STACK_OVERFLOW: 26, + + // Constants for dumpHasStream() + // From google_breakpad/common/minidump_format.h + MD_THREAD_LIST_STREAM: 3, + MD_MEMORY_INFO_LIST_STREAM: 16, +}; + +// Grab APIs from the testcrasher shared library +import { ctypes } from "resource://gre/modules/ctypes.sys.mjs"; + +var dir = Services.dirsvc.get("CurWorkD", Ci.nsIFile); +var file = dir.clone(); +file = file.parent; +file.append(ctypes.libraryName("testcrasher")); +var lib = ctypes.open(file.path); +CrashTestUtils.crash = lib.declare( + "Crash", + ctypes.default_abi, + ctypes.void_t, + ctypes.int16_t +); +CrashTestUtils.saveAppMemory = lib.declare( + "SaveAppMemory", + ctypes.default_abi, + ctypes.uint64_t +); +CrashTestUtils.enablePHC = lib.declare( + "EnablePHC", + ctypes.default_abi, + ctypes.void_t +); + +try { + CrashTestUtils.TryOverrideExceptionHandler = lib.declare( + "TryOverrideExceptionHandler", + ctypes.default_abi, + ctypes.void_t + ); +} catch (ex) {} + +CrashTestUtils.dumpHasStream = lib.declare( + "DumpHasStream", + ctypes.default_abi, + ctypes.bool, + ctypes.char.ptr, + ctypes.uint32_t +); + +CrashTestUtils.dumpHasInstructionPointerMemory = lib.declare( + "DumpHasInstructionPointerMemory", + ctypes.default_abi, + ctypes.bool, + ctypes.char.ptr +); + +CrashTestUtils.dumpCheckMemory = lib.declare( + "DumpCheckMemory", + ctypes.default_abi, + ctypes.bool, + ctypes.char.ptr +); + +CrashTestUtils.getWin64CFITestFnAddrOffset = lib.declare( + "GetWin64CFITestFnAddrOffset", + ctypes.default_abi, + ctypes.int32_t, + ctypes.int16_t +); diff --git a/toolkit/crashreporter/test/ExceptionThrower.cpp b/toolkit/crashreporter/test/ExceptionThrower.cpp new file mode 100644 index 0000000000..7404d13c47 --- /dev/null +++ b/toolkit/crashreporter/test/ExceptionThrower.cpp @@ -0,0 +1,3 @@ +#include "ExceptionThrower.h" + +void ThrowException() { throw 1; } diff --git a/toolkit/crashreporter/test/ExceptionThrower.h b/toolkit/crashreporter/test/ExceptionThrower.h new file mode 100644 index 0000000000..e8d30aee4b --- /dev/null +++ b/toolkit/crashreporter/test/ExceptionThrower.h @@ -0,0 +1 @@ +void ThrowException(); diff --git a/toolkit/crashreporter/test/browser/browser.toml b/toolkit/crashreporter/test/browser/browser.toml new file mode 100644 index 0000000000..017cf7c60c --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser.toml @@ -0,0 +1,21 @@ +[DEFAULT] +support-files = ["head.js"] + +["browser_aboutCrashes.js"] + +["browser_aboutCrashesResubmit.js"] +https_first_disabled = true + +["browser_bug471404.js"] + +["browser_clearReports.js"] + +["browser_cpu_microcode.js"] +skip-if = ["os != 'win'"] +reason = "Windows-specific crash annotation" + +["browser_sandbox_crash.js"] +skip-if = [ + "os != 'linux'", # Linux-specific crash type + "release_or_beta", # release/beta builds do not crash on sandbox violations +] diff --git a/toolkit/crashreporter/test/browser/browser_aboutCrashes.js b/toolkit/crashreporter/test/browser/browser_aboutCrashes.js new file mode 100644 index 0000000000..1885be4ca3 --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_aboutCrashes.js @@ -0,0 +1,82 @@ +add_task(async function test() { + const appD = make_fake_appdir(); + const crD = appD.clone(); + crD.append("Crash Reports"); + const crashes = add_fake_crashes(crD, 5); + // sanity check + const appDtest = Services.dirsvc.get("UAppData", Ci.nsIFile); + ok(appD.equals(appDtest), "directory service provider registered ok"); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:crashes" }, + browser => { + info("about:crashes loaded"); + return SpecialPowers.spawn(browser, [crashes], crashes => { + const doc = content.document; + + const submitted = doc.getElementById("reportListSubmitted"); + Assert.ok( + !submitted.classList.contains("hidden"), + "the submitted crash list is visible" + ); + const unsubmitted = doc.getElementById("reportListUnsubmitted"); + Assert.ok( + unsubmitted.classList.contains("hidden"), + "the unsubmitted crash list is hidden" + ); + + const crashIds = doc.getElementsByClassName("crash-id"); + Assert.equal( + crashIds.length, + crashes.length, + "about:crashes lists correct number of crash reports" + ); + for (let i = 0; i < crashes.length; i++) { + Assert.equal( + crashIds[i].textContent, + crashes[i].id, + i + ": crash ID is correct" + ); + } + }); + } + ); + + clear_fake_crashes(crD, crashes); + const pendingCrash = addPendingCrashreport(crD, Date.now(), { foo: "bar" }); + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:crashes" }, + browser => { + info("about:crashes loaded"); + return SpecialPowers.spawn(browser, [pendingCrash], pendingCrash => { + const doc = content.document; + + const submitted = doc.getElementById("reportListSubmitted"); + Assert.ok( + submitted.classList.contains("hidden"), + "the submitted crash list is hidden" + ); + const unsubmitted = doc.getElementById("reportListUnsubmitted"); + Assert.ok( + !unsubmitted.classList.contains("hidden"), + "the unsubmitted crash list is visible" + ); + + const crashIds = doc.getElementsByClassName("crash-id"); + Assert.equal( + crashIds.length, + 1, + "about:crashes lists correct number of crash reports" + ); + const pendingRow = doc.getElementById(pendingCrash.id); + Assert.equal( + pendingRow.cells[0].textContent, + pendingCrash.id, + "about:crashes lists pending crash IDs correctly" + ); + }); + } + ); + + cleanup_fake_appdir(); +}); diff --git a/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js b/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js new file mode 100644 index 0000000000..93a21d451d --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_aboutCrashesResubmit.js @@ -0,0 +1,202 @@ +function cleanup_and_finish() { + try { + cleanup_fake_appdir(); + } catch (ex) {} + Services.prefs.clearUserPref("breakpad.reportURL"); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + finish(); +} + +/* + * check_crash_list + * + * Check that the list of crashes displayed by about:crashes matches + * the list of crashes that we placed in the pending+submitted directories. + * + * This function is run in a separate JS context via SpecialPowers.spawn, so + * it has no access to other functions or variables in this file. + */ +function check_crash_list(crashes) { + const doc = content.document; + const crashIdNodes = Array.from(doc.getElementsByClassName("crash-id")); + const pageCrashIds = new Set(crashIdNodes.map(node => node.textContent)); + const crashIds = new Set(crashes.map(crash => crash.id)); + Assert.deepEqual( + pageCrashIds, + crashIds, + "about:crashes lists the correct crash reports." + ); +} + +/* + * check_submit_pending + * + * Click on a pending crash in about:crashes, wait for it to be submitted (which + * should redirect us to the crash report page). Verify that the data provided + * by our test crash report server matches the data we submitted. + * Additionally, click "back" and verify that the link now points to our new + */ +function check_submit_pending(tab, crashes) { + const browser = gBrowser.getBrowserForTab(tab); + let SubmittedCrash = null; + let CrashID = null; + let CrashURL = null; + function csp_onsuccess() { + const crashLinks = content.document.getElementsByClassName("crash-link"); + // Get the last link since it is appended to the end of the list + const link = crashLinks[crashLinks.length - 1]; + link.click(); + } + function csp_onload() { + // loaded the crash report page + ok(true, "got submission onload"); + + SpecialPowers.spawn(browser, [], function () { + // grab the Crash ID here to verify later + let CrashID = content.location.search.split("=")[1]; + let CrashURL = content.location.toString(); + + // check the JSON content vs. what we submitted + let result = JSON.parse(content.document.documentElement.textContent); + Assert.equal( + result.upload_file_minidump, + "MDMP", + "minidump file sent properly" + ); + Assert.equal( + result.memory_report, + "Let's pretend this is a memory report", + "memory report sent properly" + ); + Assert.equal( + +result.Throttleable, + 0, + "correctly sent as non-throttleable" + ); + Assert.equal( + result.SubmittedFrom, + "AboutCrashes", + "correctly flagged as sent from about:crashes" + ); + // we checked these, they're set by the submission process, + // so they won't be in the "extra" data. + delete result.upload_file_minidump; + delete result.memory_report; + delete result.Throttleable; + delete result.SubmittedFrom; + + return { id: CrashID, url: CrashURL, result }; + }).then(({ id, url, result }) => { + // Likewise, this is discarded before it gets to the server + delete SubmittedCrash.extra.ServerURL; + + CrashID = id; + CrashURL = url; + for (let x in result) { + if (x in SubmittedCrash.extra) { + is( + result[x], + SubmittedCrash.extra[x], + "submitted value for " + x + " matches expected" + ); + } else { + ok(false, "property " + x + " missing from submitted data!"); + } + } + for (let y in SubmittedCrash.extra) { + if (!(y in result)) { + ok(false, "property " + y + " missing from result data!"); + } + } + + // We can listen for pageshow like this because the tab is not remote. + BrowserTestUtils.waitForEvent(browser, "pageshow", true).then( + csp_pageshow + ); + + // now navigate back + browser.goBack(); + }); + } + function csp_fail() { + browser.removeEventListener("CrashSubmitFailed", csp_fail, true); + ok(false, "failed to submit crash report!"); + cleanup_and_finish(); + } + browser.addEventListener("CrashSubmitSucceeded", csp_onsuccess, true); + browser.addEventListener("CrashSubmitFailed", csp_fail, true); + BrowserTestUtils.browserLoaded( + browser, + false, + url => url !== "about:crashes" + ).then(csp_onload); + function csp_pageshow() { + SpecialPowers.spawn( + browser, + [{ CrashID, CrashURL }], + function ({ CrashID, CrashURL }) { + Assert.equal( + content.location.href, + "about:crashes", + "navigated back successfully" + ); + const link = content.document + .getElementById(CrashID) + .getElementsByClassName("crash-link")[0]; + Assert.notEqual(link, null, "crash report link changed correctly"); + if (link) { + Assert.equal( + link.href, + CrashURL, + "crash report link points to correct href" + ); + } + } + ).then(cleanup_and_finish); + } + + // try submitting the pending report + for (const crash of crashes) { + if (crash.pending) { + SubmittedCrash = crash; + break; + } + } + + SpecialPowers.spawn(browser, [SubmittedCrash.id], id => { + const submitButton = content.document + .getElementById(id) + .getElementsByClassName("submit-button")[0]; + submitButton.click(); + }); +} + +function test() { + waitForExplicitFinish(); + const appD = make_fake_appdir(); + const crD = appD.clone(); + crD.append("Crash Reports"); + const crashes = add_fake_crashes(crD, 1); + // we don't need much data here, it's not going to a real Socorro + crashes.push( + addPendingCrashreport(crD, crashes[crashes.length - 1].date + 60000, { + ServerURL: + "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs", + ProductName: "Test App", + Foo: "ABC=XYZ", // test that we don't truncat eat = (bug 512853) + }) + ); + crashes.sort((a, b) => b.date - a.date); + + // set this pref so we can link to our test server + Services.prefs.setCharPref( + "breakpad.reportURL", + "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs?id=" + ); + + BrowserTestUtils.openNewForegroundTab(gBrowser, "about:crashes").then(tab => { + SpecialPowers.spawn(tab.linkedBrowser, [crashes], check_crash_list).then( + () => check_submit_pending(tab, crashes) + ); + }); +} diff --git a/toolkit/crashreporter/test/browser/browser_bug471404.js b/toolkit/crashreporter/test/browser/browser_bug471404.js new file mode 100644 index 0000000000..4f16a3b3b6 --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_bug471404.js @@ -0,0 +1,61 @@ +function check_clear_visible(browser, aVisible) { + return SpecialPowers.spawn(browser, [aVisible], function (aVisible) { + const doc = content.document; + let visible = false; + const reportListSubmitted = doc.getElementById("reportListSubmitted"); + if (reportListSubmitted) { + const style = doc.defaultView.getComputedStyle(reportListSubmitted); + if (style.display !== "none" && style.visibility === "visible") { + visible = true; + } + } + Assert.equal( + visible, + aVisible, + "clear submitted reports button is " + (aVisible ? "visible" : "hidden") + ); + }); +} + +// each test here has a setup (run before loading about:crashes) and onload (run after about:crashes loads) +var _tests = [ + { + setup: null, + onload(browser) { + return check_clear_visible(browser, false); + }, + }, + { + setup(crD) { + return add_fake_crashes(crD, 1); + }, + onload(browser) { + return check_clear_visible(browser, true); + }, + }, +]; + +add_task(async function test() { + let appD = make_fake_appdir(); + let crD = appD.clone(); + crD.append("Crash Reports"); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async function (browser) { + for (let test of _tests) { + // Run setup before loading about:crashes. + if (test.setup) { + await test.setup(crD); + } + + BrowserTestUtils.startLoadingURIString(browser, "about:crashes"); + await BrowserTestUtils.browserLoaded(browser).then(() => + test.onload(browser) + ); + } + } + ); + + cleanup_fake_appdir(); +}); diff --git a/toolkit/crashreporter/test/browser/browser_clearReports.js b/toolkit/crashreporter/test/browser/browser_clearReports.js new file mode 100644 index 0000000000..2f780f1955 --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_clearReports.js @@ -0,0 +1,134 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function clickClearReports() { + const doc = content.document; + const reportListUnsubmitted = doc.getElementById("reportListUnsubmitted"); + const reportListSubmitted = doc.getElementById("reportListSubmitted"); + if (!reportListUnsubmitted || !reportListSubmitted) { + Assert.ok(false, "Report list not found"); + } + + const unsubmittedStyle = doc.defaultView.getComputedStyle( + reportListUnsubmitted + ); + const submittedStyle = doc.defaultView.getComputedStyle(reportListSubmitted); + Assert.notEqual( + unsubmittedStyle.display, + "none", + "Unsubmitted report list is visible" + ); + Assert.notEqual( + submittedStyle.display, + "none", + "Submitted report list is visible" + ); + + const clearUnsubmittedButton = doc.getElementById("clearUnsubmittedReports"); + const clearSubmittedButton = doc.getElementById("clearSubmittedReports"); + clearUnsubmittedButton.click(); + clearSubmittedButton.click(); +} + +var promptShown = false; + +var oldPrompt = Services.prompt; +Services.prompt = { + confirm() { + promptShown = true; + return true; + }, +}; + +registerCleanupFunction(function () { + Services.prompt = oldPrompt; +}); + +add_task(async function test() { + let appD = make_fake_appdir(); + let crD = appD.clone(); + crD.append("Crash Reports"); + + // Add crashes to submitted dir + let submitdir = crD.clone(); + submitdir.append("submitted"); + + let file1 = submitdir.clone(); + file1.append("bp-nontxt"); + file1.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + let file2 = submitdir.clone(); + file2.append("nonbp-file.txt"); + file2.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + add_fake_crashes(crD, 5); + + // Add crashes to pending dir + let pendingdir = crD.clone(); + pendingdir.append("pending"); + + let crashes = add_fake_crashes(crD, 2); + addPendingCrashreport(crD, crashes[0].date); + addPendingCrashreport(crD, crashes[1].date); + + // Add crashes to reports dir + let report1 = crD.clone(); + report1.append("NotInstallTime777"); + report1.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + let report2 = crD.clone(); + report2.append("InstallTime" + Services.appinfo.appBuildID); + report2.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + let report3 = crD.clone(); + report3.append("InstallTimeNew"); + report3.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + let report4 = crD.clone(); + report4.append("InstallTimeOld"); + report4.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + report4.lastModifiedTime = Date.now() - 63172000000; + + registerCleanupFunction(function () { + cleanup_fake_appdir(); + }); + + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:crashes" }, + async function (browser) { + let dirs = [submitdir, pendingdir, crD]; + let existing = [ + file1.path, + file2.path, + report1.path, + report2.path, + report3.path, + submitdir.path, + pendingdir.path, + ]; + + SpecialPowers.spawn(browser, [], clickClearReports); + await BrowserTestUtils.waitForCondition( + () => + content.document + .getElementById("reportListUnsubmitted") + .classList.contains("hidden") && + content.document + .getElementById("reportListSubmitted") + .classList.contains("hidden") + ); + + for (let dir of dirs) { + let entries = dir.directoryEntries; + while (entries.hasMoreElements()) { + let file = entries.nextFile; + let index = existing.indexOf(file.path); + isnot(index, -1, file.leafName + " exists"); + + if (index != -1) { + existing.splice(index, 1); + } + } + } + + is(existing.length, 0, "All the files that should still exist exist"); + ok(promptShown, "Prompt shown"); + } + ); +}); diff --git a/toolkit/crashreporter/test/browser/browser_cpu_microcode.js b/toolkit/crashreporter/test/browser/browser_cpu_microcode.js new file mode 100644 index 0000000000..e4efd1c86d --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_cpu_microcode.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +/* global BrowserTestUtils, ok, gBrowser, add_task */ + +"use strict"; + +/** + * Checks that we set the CPUMicrocodeVersion annotation. + */ +add_task(async function test_cpu_microcode_version_annotation() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + }, + async function (browser) { + // Crash the tab + let annotations = await BrowserTestUtils.crashFrame(browser); + + ok( + "CPUMicrocodeVersion" in annotations, + "contains CPU microcode version" + ); + } + ); +}); diff --git a/toolkit/crashreporter/test/browser/browser_sandbox_crash.js b/toolkit/crashreporter/test/browser/browser_sandbox_crash.js new file mode 100644 index 0000000000..4cd3d782e5 --- /dev/null +++ b/toolkit/crashreporter/test/browser/browser_sandbox_crash.js @@ -0,0 +1,77 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ +/* global BrowserTestUtils, ok, gBrowser, add_task */ + +"use strict"; + +/** + * Checks that we set the CPUMicrocodeVersion annotation. + * This is a Windows-specific crash annotation. + */ +if (AppConstants.platform == "win") { + add_task(async function test_cpu_microcode_version_annotation() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + }, + async function (browser) { + // Crash the tab + let annotations = await BrowserTestUtils.crashFrame(browser); + + ok( + "CPUMicrocodeVersion" in annotations, + "contains CPU microcode version" + ); + } + ); + }); +} + +/** + * Checks that Linux sandbox violations are reported as SIGSYS crashes with + * the syscall number provided in the address field of the minidump's exception + * stream. + */ +if (AppConstants.platform == "linux") { + add_task(async function test_sandbox_violation_is_sigsys() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + }, + async function (browser) { + // Crash the tab + let annotations = await BrowserTestUtils.crashFrame( + browser, + true, + true, + /* Default browsing context */ null, + { crashType: "CRASH_SYSCALL" } + ); + + Assert.equal( + annotations.StackTraces.crash_info.type, + "SIGSYS", + "The crash type is SIGSYS" + ); + + function chroot_syscall_number() { + // We crash by calling chroot(), see BrowserTestUtilsChild.sys.mjs + switch (Services.sysinfo.get("arch")) { + case "x86-64": + return "0xa1"; + case "aarch64": + return "0x33"; + default: + return "0x3d"; + } + } + + Assert.equal( + annotations.StackTraces.crash_info.address, + chroot_syscall_number(), + "The address corresponds to the chroot() syscall number" + ); + } + ); + }); +} diff --git a/toolkit/crashreporter/test/browser/crashreport.sjs b/toolkit/crashreporter/test/browser/crashreport.sjs new file mode 100644 index 0000000000..908455c9e6 --- /dev/null +++ b/toolkit/crashreporter/test/browser/crashreport.sjs @@ -0,0 +1,176 @@ +const CC = Components.Constructor; + +const BinaryInputStream = CC( + "@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream" +); + +function parseHeaders(data, start) { + let headers = {}; + + while (true) { + let end = data.indexOf("\r\n", start); + if (end == -1) { + end = data.length; + } + let line = data.substring(start, end); + start = end + 2; + if (line == "") { + // empty line, we're done + break; + } + + //XXX: this doesn't handle multi-line headers. do we care? + let [name, value] = line.split(":"); + //XXX: not normalized, should probably use nsHttpHeaders or something + headers[name] = value.trimLeft(); + } + return [headers, start]; +} + +function parseMultipartForm(request) { + let boundary = null; + // See if this is a multipart/form-data request, and if so, find the + // boundary string + if (request.hasHeader("Content-Type")) { + var contenttype = request.getHeader("Content-Type"); + var bits = contenttype.split(";"); + if (bits[0] == "multipart/form-data") { + for (var i = 1; i < bits.length; i++) { + var b = bits[i].trimLeft(); + if (b.indexOf("boundary=") == 0) { + // grab everything after boundary= + boundary = "--" + b.substring(9); + break; + } + } + } + } + if (boundary == null) { + return null; + } + + let body = new BinaryInputStream(request.bodyInputStream); + let avail; + let bytes = []; + while ((avail = body.available()) > 0) { + let readBytes = body.readByteArray(avail); + for (let b of readBytes) { + bytes.push(b); + } + } + let data = ""; + for (let b of bytes) { + data += String.fromCharCode(b); + } + let formData = {}; + let start = 0; + while (true) { + // read first line + let end = data.indexOf("\r\n", start); + if (end == -1) { + end = data.length; + } + + let line = data.substring(start, end); + // look for closing boundary delimiter line + if (line == boundary + "--") { + break; + } + + if (line != boundary) { + dump("expected boundary line but didn't find it!"); + break; + } + + // parse headers + start = end + 2; + let headers = null; + [headers, start] = parseHeaders(data, start); + + // find next boundary string + end = data.indexOf("\r\n" + boundary, start); + if (end == -1) { + dump("couldn't find next boundary string\n"); + break; + } + + // read part data, stick in formData using Content-Disposition header + let part = data.substring(start, end); + start = end + 2; + + if ("Content-Disposition" in headers) { + let bits = headers["Content-Disposition"].split(";"); + if (bits[0] == "form-data") { + for (let i = 0; i < bits.length; i++) { + let b = bits[i].trimLeft(); + if (b.indexOf("name=") == 0) { + //TODO: handle non-ascii here? + let name = b.substring(6, b.length - 1); + //TODO: handle multiple-value properties? + if ( + "Content-Type" in headers && + headers["Content-Type"] == "application/json" + ) { + formData = Object.assign(formData, JSON.parse(part)); + } else { + formData[name] = part; + } + } + //TODO: handle filename= ? + //TODO: handle multipart/mixed for multi-file uploads? + } + } + } + } + return formData; +} + +function handleRequest(request, response) { + if (request.method == "GET") { + let id = null; + for (let p of request.queryString.split("&")) { + let [key, value] = p.split("="); + if (key == "id") { + id = value; + } + } + if (id == null) { + response.setStatusLine(request.httpVersion, 400, "Bad Request"); + response.write("Missing id parameter"); + } else { + let data = getState(id); + if (data == "") { + response.setStatusLine(request.httpVersion, 404, "Not Found"); + response.write("Not Found"); + } else { + response.setHeader("Content-Type", "text/plain", false); + response.write(data); + } + } + } else if (request.method == "POST") { + let formData = parseMultipartForm(request); + + if (formData && "upload_file_minidump" in formData) { + response.setHeader("Content-Type", "text/plain", false); + + let uuid = Services.uuid.generateUUID().toString(); + // ditch the {}, add bp- prefix + uuid = "bp-" + uuid.substring(1, uuid.length - 1); + + let d = JSON.stringify(formData); + //dump('saving crash report ' + uuid + ': ' + d + '\n'); + setState(uuid, d); + + response.write("CrashID=" + uuid + "\n"); + } else { + dump("*** crashreport.sjs: Malformed request?\n"); + response.setStatusLine(request.httpVersion, 400, "Bad Request"); + response.write("Missing minidump file"); + } + } else { + response.setStatusLine(request.httpVersion, 405, "Method not allowed"); + response.write("Can't handle HTTP method " + request.method); + } +} diff --git a/toolkit/crashreporter/test/browser/head.js b/toolkit/crashreporter/test/browser/head.js new file mode 100644 index 0000000000..fea602a028 --- /dev/null +++ b/toolkit/crashreporter/test/browser/head.js @@ -0,0 +1,163 @@ +function create_subdir(dir, subdirname) { + let subdir = dir.clone(); + subdir.append(subdirname); + if (subdir.exists()) { + subdir.remove(true); + } + subdir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + return subdir; +} + +function generate_uuid() { + let uuidGenerator = Services.uuid; + let uuid = uuidGenerator.generateUUID().toString(); + // ditch the {} + return uuid.substring(1, uuid.length - 1); +} + +// need to hold on to this to unregister for cleanup +var _provider = null; + +function make_fake_appdir() { + // Create a directory inside the profile and register it as UAppData, so + // we can stick fake crash reports inside there. We put it inside the profile + // just because we know that will get cleaned up after the mochitest run. + let profD = Services.dirsvc.get("ProfD", Ci.nsIFile); + // create a subdir just to keep our files out of the way + let appD = create_subdir(profD, "UAppData"); + + let crashesDir = create_subdir(appD, "Crash Reports"); + create_subdir(crashesDir, "pending"); + create_subdir(crashesDir, "submitted"); + + _provider = { + getFile(prop, persistent) { + persistent.value = true; + if (prop == "UAppData") { + return appD.clone(); + } + // Depending on timing we can get requests for other files. + // When we threw an exception here, in the world before bug 997440, this got lost + // because of the arbitrary JSContext being used in nsXPCWrappedJS::CallMethod. + // After bug 997440 this gets reported to our window and causes the tests to fail. + // So, we'll just dump out a message to the logs. + dump( + "WARNING: make_fake_appdir - fake nsIDirectoryServiceProvider - Unexpected getFile for: '" + + prop + + "'\n" + ); + return null; + }, + QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]), + }; + // register our new provider + Services.dirsvc + .QueryInterface(Ci.nsIDirectoryService) + .registerProvider(_provider); + // and undefine the old value + try { + Services.dirsvc.undefine("UAppData"); + } catch (ex) {} // it's ok if this fails, the value might not be cached yet + return appD.clone(); +} + +function cleanup_fake_appdir() { + Services.dirsvc + .QueryInterface(Ci.nsIDirectoryService) + .unregisterProvider(_provider); + // undefine our value so future calls get the real value + try { + Services.dirsvc.undefine("UAppData"); + } catch (ex) { + dump("cleanup_fake_appdir: dirSvc.undefine failed: " + ex.message + "\n"); + } +} + +function add_fake_crashes(crD, count) { + let results = []; + let submitdir = crD.clone(); + submitdir.append("submitted"); + // create them from oldest to newest, to ensure that about:crashes + // displays them in the correct order + let date = Date.now() - count * 60000; + for (let i = 0; i < count; i++) { + let uuid = "bp-" + generate_uuid(); + let fn = uuid + ".txt"; + let file = submitdir.clone(); + file.append(fn); + file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); + file.lastModifiedTime = date; + results.push({ id: uuid, date, pending: false }); + + date += 60000; + } + // we want them sorted newest to oldest, since that's the order + // that about:crashes lists them in + results.sort((a, b) => b.date - a.date); + return results; +} + +function clear_fake_crashes(crD, crashes) { + let submitdir = crD.clone(); + submitdir.append("submitted"); + for (let i of crashes) { + let fn = i.id + ".txt"; + let file = submitdir.clone(); + file.append(fn); + file.remove(false); + } +} + +function writeDataToFile(file, data) { + var fstream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance( + Ci.nsIFileOutputStream + ); + // open, write, truncate + fstream.init(file, -1, -1, 0); + var os = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance( + Ci.nsIConverterOutputStream + ); + os.init(fstream, "UTF-8"); + os.writeString(data); + os.close(); + fstream.close(); +} + +function writeCrashReportFile(dir, uuid, suffix, date, data) { + let file = dir.clone(); + file.append(uuid + suffix); + writeDataToFile(file, data); + file.lastModifiedTime = date; +} + +function writeMinidumpFile(dir, uuid, date) { + // that's the start of a valid minidump, anyway + writeCrashReportFile(dir, uuid, ".dmp", date, "MDMP"); +} + +function writeExtraFile(dir, uuid, date, data) { + writeCrashReportFile(dir, uuid, ".extra", date, JSON.stringify(data)); +} + +function writeMemoryReport(dir, uuid, date) { + let data = "Let's pretend this is a memory report"; + writeCrashReportFile(dir, uuid, ".memory.json.gz", date, data); +} + +function addPendingCrashreport(crD, date, extra) { + let pendingdir = crD.clone(); + pendingdir.append("pending"); + let uuid = generate_uuid(); + writeMinidumpFile(pendingdir, uuid, date); + writeExtraFile(pendingdir, uuid, date, extra); + writeMemoryReport(pendingdir, uuid, date); + return { id: uuid, date, pending: true, extra }; +} + +function addIncompletePendingCrashreport(crD, date) { + let pendingdir = crD.clone(); + pendingdir.append("pending"); + let uuid = generate_uuid(); + writeMinidumpFile(pendingdir, uuid, date); + return { id: uuid, date, pending: true }; +} diff --git a/toolkit/crashreporter/test/dumputils.cpp b/toolkit/crashreporter/test/dumputils.cpp new file mode 100644 index 0000000000..fedaa6532a --- /dev/null +++ b/toolkit/crashreporter/test/dumputils.cpp @@ -0,0 +1,83 @@ +#include + +#include "google_breakpad/processor/minidump.h" +#include "nscore.h" + +using namespace google_breakpad; + +// Return true if the specified minidump contains a stream of |stream_type|. +extern "C" NS_EXPORT bool DumpHasStream(const char* dump_file, + uint32_t stream_type) { + Minidump dump(dump_file); + if (!dump.Read()) return false; + + uint32_t length; + if (!dump.SeekToStreamType(stream_type, &length) || length == 0) return false; + + return true; +} + +// Return true if the specified minidump contains a memory region +// that contains the instruction pointer from the exception record. +extern "C" NS_EXPORT bool DumpHasInstructionPointerMemory( + const char* dump_file) { + Minidump minidump(dump_file); + if (!minidump.Read()) return false; + + MinidumpException* exception = minidump.GetException(); + MinidumpMemoryList* memory_list = minidump.GetMemoryList(); + if (!exception || !memory_list) { + return false; + } + + MinidumpContext* context = exception->GetContext(); + if (!context) return false; + + uint64_t instruction_pointer; + if (!context->GetInstructionPointer(&instruction_pointer)) { + return false; + } + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(instruction_pointer); + return region != nullptr; +} + +// This function tests for a very specific condition. It finds +// an address in a file, "crash-addr", in the CWD. It checks +// that the minidump has a memory region starting at that +// address. The region must be 32 bytes long and contain the +// values 0 to 31 as bytes, in ascending order. +extern "C" NS_EXPORT bool DumpCheckMemory(const char* dump_file) { + Minidump dump(dump_file); + if (!dump.Read()) return false; + + MinidumpMemoryList* memory_list = dump.GetMemoryList(); + if (!memory_list) { + return false; + } + + void* addr; + FILE* fp = fopen("crash-addr", "r"); + if (!fp) return false; + if (fscanf(fp, "%p", &addr) != 1) { + fclose(fp); + return false; + } + fclose(fp); + + remove("crash-addr"); + + MinidumpMemoryRegion* region = + memory_list->GetMemoryRegionForAddress(uint64_t(addr)); + if (!region) return false; + + const uint8_t* chars = region->GetMemory(); + if (region->GetSize() != 32) return false; + + for (int i = 0; i < 32; i++) { + if (chars[i] != i) return false; + } + + return true; +} diff --git a/toolkit/crashreporter/test/moz.build b/toolkit/crashreporter/test/moz.build new file mode 100644 index 0000000000..1ebd9b9029 --- /dev/null +++ b/toolkit/crashreporter/test/moz.build @@ -0,0 +1,67 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +FINAL_TARGET = "_tests/xpcshell/toolkit/crashreporter/test" + +XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell.toml", "unit_ipc/xpcshell.toml"] +if CONFIG["MOZ_PHC"]: + XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell-phc.toml", "unit_ipc/xpcshell-phc.toml"] + +BROWSER_CHROME_MANIFESTS += ["browser/browser.toml"] + +UNIFIED_SOURCES += [ + "../google-breakpad/src/processor/basic_code_modules.cc", + "../google-breakpad/src/processor/convert_old_arm64_context.cc", + "../google-breakpad/src/processor/dump_context.cc", + "../google-breakpad/src/processor/dump_object.cc", + "../google-breakpad/src/processor/logging.cc", + "../google-breakpad/src/processor/minidump.cc", + "../google-breakpad/src/processor/pathname_stripper.cc", + "../google-breakpad/src/processor/proc_maps_linux.cc", + "dumputils.cpp", + "nsTestCrasher.cpp", +] + +SOURCES += [ + "ExceptionThrower.cpp", +] + +if CONFIG["OS_TARGET"] == "WINNT" and CONFIG["TARGET_CPU"] == "x86_64": + if CONFIG["CC_TYPE"] not in ("gcc", "clang"): + SOURCES += [ + "win64UnwindInfoTests.asm", + ] + +if CONFIG["CC_TYPE"] == "clang-cl": + SOURCES["ExceptionThrower.cpp"].flags += [ + "-Xclang", + "-fcxx-exceptions", + ] +else: + SOURCES["ExceptionThrower.cpp"].flags += [ + "-fexceptions", + ] + +if CONFIG["MOZ_PHC"]: + DEFINES["MOZ_PHC"] = True + +GeckoSharedLibrary("testcrasher") + +DEFINES["SHARED_LIBRARY"] = "%s%s%s" % ( + CONFIG["DLL_PREFIX"], + LIBRARY_NAME, + CONFIG["DLL_SUFFIX"], +) + +TEST_HARNESS_FILES.xpcshell.toolkit.crashreporter.test.unit += [ + "CrashTestUtils.sys.mjs" +] +TEST_HARNESS_FILES.xpcshell.toolkit.crashreporter.test.unit_ipc += [ + "CrashTestUtils.sys.mjs" +] + +include("/toolkit/crashreporter/crashreporter.mozbuild") + +NO_PGO = True diff --git a/toolkit/crashreporter/test/nsTestCrasher.cpp b/toolkit/crashreporter/test/nsTestCrasher.cpp new file mode 100644 index 0000000000..2148a60088 --- /dev/null +++ b/toolkit/crashreporter/test/nsTestCrasher.cpp @@ -0,0 +1,370 @@ +#include "mozilla/Assertions.h" + +#include +#include + +#include "nscore.h" +#include "mozilla/Unused.h" +#include "ExceptionThrower.h" + +#ifdef XP_WIN +# include +# include +#elif defined(XP_MACOSX) +# include +# include +# include +# include // For dlsym() +// See https://github.com/apple/darwin-xnu/blob/main/bsd/sys/guarded.h +# define GUARD_CLOSE (1u << 0) +# define GUARD_DUP (1u << 1) +# define GUARD_SOCKET_IPC (1u << 2) +# define GUARD_FILEPORT (1u << 3) +# define GUARD_WRITE (1u << 4) +typedef uint64_t guardid_t; +typedef int (*guarded_open_np_t)(const char*, const guardid_t*, u_int, int, + ...); +#endif + +#ifndef XP_WIN +# include +#endif + +#ifdef MOZ_PHC +# include "PHC.h" +#endif + +/* + * This pure virtual call example is from MSDN + */ +class A; + +void fcn(A*); + +class A { + public: + virtual void f() = 0; + A() { fcn(this); } +}; + +class B : A { + void f() override {} + + public: + void use() {} +}; + +void fcn(A* p) { p->f(); } + +void PureVirtualCall() { + // generates a pure virtual function call + B b; + b.use(); // make sure b's actually used +} + +extern "C" { +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) && !defined(__MINGW32__) +// Implementation in win64unwindInfoTests.asm +uint64_t x64CrashCFITest_NO_MANS_LAND(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_Launcher(uint64_t returnpfn, void* testProc); +uint64_t x64CrashCFITest_UnknownOpcode(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_PUSH_NONVOL(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_ALLOC_SMALL(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_ALLOC_LARGE(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_SAVE_NONVOL(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_SAVE_NONVOL_FAR(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_SAVE_XMM128(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_SAVE_XMM128_FAR(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_EPILOG(uint64_t returnpfn, void*); +uint64_t x64CrashCFITest_EOF(uint64_t returnpfn, void*); +#endif // XP_WIN && HAVE_64BIT_BUILD && !defined(__MINGW32__) +} + +// Keep these in sync with CrashTestUtils.jsm! +const int16_t CRASH_INVALID_POINTER_DEREF = 0; +const int16_t CRASH_PURE_VIRTUAL_CALL = 1; +const int16_t CRASH_OOM = 3; +const int16_t CRASH_MOZ_CRASH = 4; +const int16_t CRASH_ABORT = 5; +const int16_t CRASH_UNCAUGHT_EXCEPTION = 6; +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) && !defined(__MINGW32__) +const int16_t CRASH_X64CFI_NO_MANS_LAND = 7; +const int16_t CRASH_X64CFI_LAUNCHER = 8; +const int16_t CRASH_X64CFI_UNKNOWN_OPCODE = 9; +const int16_t CRASH_X64CFI_PUSH_NONVOL = 10; +const int16_t CRASH_X64CFI_ALLOC_SMALL = 11; +const int16_t CRASH_X64CFI_ALLOC_LARGE = 12; +const int16_t CRASH_X64CFI_SAVE_NONVOL = 15; +const int16_t CRASH_X64CFI_SAVE_NONVOL_FAR = 16; +const int16_t CRASH_X64CFI_SAVE_XMM128 = 17; +const int16_t CRASH_X64CFI_SAVE_XMM128_FAR = 18; +const int16_t CRASH_X64CFI_EPILOG = 19; +const int16_t CRASH_X64CFI_EOF = 20; +#endif +const int16_t CRASH_PHC_USE_AFTER_FREE = 21; +const int16_t CRASH_PHC_DOUBLE_FREE = 22; +const int16_t CRASH_PHC_BOUNDS_VIOLATION = 23; +#if XP_WIN +const int16_t CRASH_HEAP_CORRUPTION = 24; +#endif +#ifdef XP_MACOSX +const int16_t CRASH_EXC_GUARD = 25; +#endif +#ifndef XP_WIN +const int16_t CRASH_STACK_OVERFLOW = 26; +#endif + +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) && !defined(__MINGW32__) + +typedef decltype(&x64CrashCFITest_UnknownOpcode) win64CFITestFnPtr_t; + +static std::map GetWin64CFITestMap() { + std::map ret = { + {CRASH_X64CFI_NO_MANS_LAND, x64CrashCFITest_NO_MANS_LAND}, + {CRASH_X64CFI_LAUNCHER, x64CrashCFITest_Launcher}, + {CRASH_X64CFI_UNKNOWN_OPCODE, x64CrashCFITest_UnknownOpcode}, + {CRASH_X64CFI_PUSH_NONVOL, x64CrashCFITest_PUSH_NONVOL}, + {CRASH_X64CFI_ALLOC_SMALL, x64CrashCFITest_ALLOC_SMALL}, + {CRASH_X64CFI_ALLOC_LARGE, x64CrashCFITest_ALLOC_LARGE}, + {CRASH_X64CFI_SAVE_NONVOL, x64CrashCFITest_SAVE_NONVOL}, + {CRASH_X64CFI_SAVE_NONVOL_FAR, x64CrashCFITest_SAVE_NONVOL_FAR}, + {CRASH_X64CFI_SAVE_XMM128, x64CrashCFITest_SAVE_XMM128}, + {CRASH_X64CFI_SAVE_XMM128_FAR, x64CrashCFITest_SAVE_XMM128_FAR}, + {CRASH_X64CFI_EPILOG, x64CrashCFITest_EPILOG}, + {CRASH_X64CFI_EOF, x64CrashCFITest_EOF}}; + // ret values point to jump table entries, not the actual function bodies. + // Get the correct pointer by calling the function with returnpfn=1 + for (auto it = ret.begin(); it != ret.end(); ++it) { + it->second = (win64CFITestFnPtr_t)it->second(1, nullptr); + } + return ret; +} + +// This ensures tests have enough committed stack space. +// Must not be inlined, or the stack space would not be freed for the caller +// to use. +void MOZ_NEVER_INLINE ReserveStack() { + // We must actually use the memory in some way that the compiler can't + // optimize away. + static const size_t elements = (1024000 / sizeof(FILETIME)) + 1; + FILETIME stackmem[elements]; + ::GetSystemTimeAsFileTime(&stackmem[0]); + ::GetSystemTimeAsFileTime(&stackmem[elements - 1]); +} + +#endif // XP_WIN && HAVE_64BIT_BUILD + +#ifdef MOZ_PHC +uint8_t* GetPHCAllocation(size_t aSize) { + // A crude but effective way to get a PHC allocation. + for (int i = 0; i < 2000000; i++) { + uint8_t* p = (uint8_t*)malloc(aSize); + if (mozilla::phc::IsPHCAllocation(p, nullptr)) { + return p; + } + free(p); + } + // This failure doesn't seem to occur in practice... + MOZ_CRASH("failed to get a PHC allocation"); +} +#endif + +#ifndef XP_WIN +static int64_t recurse(int64_t aRandom) { + char buff[256] = {}; + int64_t result = aRandom; + + strncpy(buff, "This is gibberish", sizeof(buff)); + + for (auto& c : buff) { + result += c; + } + + if (result == 0) { + return result; + } + + return recurse(result) + 1; +} + +static void* overflow_stack(void* aInput) { + int64_t result = recurse(*((int64_t*)(aInput))); + + return (void*)result; +} +#endif // XP_WIN + +extern "C" NS_EXPORT void Crash(int16_t how) { + switch (how) { + case CRASH_INVALID_POINTER_DEREF: { + volatile int* foo = (int*)0x42; + *foo = 0; + // not reached + break; + } + case CRASH_PURE_VIRTUAL_CALL: { + PureVirtualCall(); + // not reached + break; + } + case CRASH_OOM: { + mozilla::Unused << moz_xmalloc((size_t)-1); + mozilla::Unused << moz_xmalloc((size_t)-1); + mozilla::Unused << moz_xmalloc((size_t)-1); + break; + } + case CRASH_MOZ_CRASH: { + MOZ_CRASH(); + break; + } + case CRASH_ABORT: { + abort(); + break; + } + case CRASH_UNCAUGHT_EXCEPTION: { + ThrowException(); + break; + } +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) && !defined(__MINGW32__) + case CRASH_X64CFI_UNKNOWN_OPCODE: + case CRASH_X64CFI_PUSH_NONVOL: + case CRASH_X64CFI_ALLOC_SMALL: + case CRASH_X64CFI_ALLOC_LARGE: + case CRASH_X64CFI_SAVE_NONVOL: + case CRASH_X64CFI_SAVE_NONVOL_FAR: + case CRASH_X64CFI_SAVE_XMM128: + case CRASH_X64CFI_SAVE_XMM128_FAR: + case CRASH_X64CFI_EPILOG: { + auto m = GetWin64CFITestMap(); + if (m.find(how) == m.end()) { + break; + } + auto pfnTest = m[how]; + auto pfnLauncher = m[CRASH_X64CFI_LAUNCHER]; + ReserveStack(); + pfnLauncher(0, reinterpret_cast(pfnTest)); + break; + } +#endif // XP_WIN && HAVE_64BIT_BUILD && !defined(__MINGW32__) +#ifdef MOZ_PHC + case CRASH_PHC_USE_AFTER_FREE: { + // Do a UAF, triggering a crash. + uint8_t* p = GetPHCAllocation(32); + free(p); + p[0] = 0; + // not reached + } + case CRASH_PHC_DOUBLE_FREE: { + // Do a double free, triggering a crash. + uint8_t* p = GetPHCAllocation(64); + free(p); + free(p); + // not reached + } + case CRASH_PHC_BOUNDS_VIOLATION: { + // Do a bounds violation, triggering a crash. + uint8_t* p = GetPHCAllocation(96); + p[96] = 0; + // not reached + } +#endif +#if XP_WIN + case CRASH_HEAP_CORRUPTION: { + // We override the HeapFree() function in mozglue so that we can force + // the code calling it to use our allocator instead of the Windows one. + // Since we need to call the real HeapFree() we get its pointer directly. + HMODULE kernel32 = LoadLibraryW(L"Kernel32.dll"); + if (kernel32) { + typedef BOOL (*HeapFreeT)(HANDLE, DWORD, LPVOID); + HeapFreeT heapFree = (HeapFreeT)GetProcAddress(kernel32, "HeapFree"); + if (heapFree) { + HANDLE heap = GetProcessHeap(); + LPVOID badPointer = (LPVOID)3; + heapFree(heap, 0, badPointer); + break; // This should be unreachable + } + } + } +#endif // XP_WIN +#ifdef XP_MACOSX + case CRASH_EXC_GUARD: { + guarded_open_np_t dl_guarded_open_np; + void* kernellib = + (void*)dlopen("/usr/lib/system/libsystem_kernel.dylib", RTLD_GLOBAL); + dl_guarded_open_np = + (guarded_open_np_t)dlsym(kernellib, "guarded_open_np"); + const guardid_t guard = 0x123456789ABCDEFULL; + // Guard the file descriptor against regular close() calls + int fd = dl_guarded_open_np( + "/tmp/try.txt", &guard, + GUARD_CLOSE | GUARD_DUP | GUARD_SOCKET_IPC | GUARD_FILEPORT, + O_CREAT | O_CLOEXEC | O_RDWR, 0666); + + if (fd != -1) { + close(fd); + // not reached + } + } +#endif // XP_MACOSX +#ifndef XP_WIN + case CRASH_STACK_OVERFLOW: { + pthread_t thread_id; + int64_t data = 1337; + int rv = pthread_create(&thread_id, nullptr, overflow_stack, &data); + if (!rv) { + pthread_join(thread_id, nullptr); + } + + break; // This should be unreachable + } +#endif // XP_WIN + default: + break; + } +} + +extern "C" NS_EXPORT void EnablePHC() { +#ifdef MOZ_PHC + mozilla::phc::SetPHCState(mozilla::phc::PHCState::Enabled); +#endif +}; + +char testData[32]; + +extern "C" NS_EXPORT uint64_t SaveAppMemory() { + for (size_t i = 0; i < sizeof(testData); i++) testData[i] = i; + + FILE* fp = fopen("crash-addr", "w"); + if (!fp) return 0; + fprintf(fp, "%p\n", (void*)testData); + fclose(fp); + + return (int64_t)testData; +} + +#ifdef XP_WIN +static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo) { + TerminateProcess(GetCurrentProcess(), 0); + return 0; +} + +extern "C" NS_EXPORT void TryOverrideExceptionHandler() { + SetUnhandledExceptionFilter(HandleException); +} +#endif + +extern "C" NS_EXPORT uint32_t GetWin64CFITestFnAddrOffset(int16_t fnid) { +#if XP_WIN && HAVE_64BIT_BUILD && defined(_M_X64) && !defined(__MINGW32__) + // fnid uses the same constants as Crash(). + // Returns the RVA of the requested function. + // Returns 0 on failure. + auto m = GetWin64CFITestMap(); + if (m.find(fnid) == m.end()) { + return 0; + } + uint64_t moduleBase = (uint64_t)GetModuleHandleW(L"testcrasher.dll"); + return ((uint64_t)m[fnid]) - moduleBase; +#else + return 0; +#endif // XP_WIN && HAVE_64BIT_BUILD && !defined(__MINGW32__) +} diff --git a/toolkit/crashreporter/test/unit/crasher_subprocess_head.js b/toolkit/crashreporter/test/unit/crasher_subprocess_head.js new file mode 100644 index 0000000000..6aa5c8192e --- /dev/null +++ b/toolkit/crashreporter/test/unit/crasher_subprocess_head.js @@ -0,0 +1,32 @@ +// enable crash reporting first +var cwd = Services.dirsvc.get("CurWorkD", Ci.nsIFile); + +// get the temp dir +var _tmpd = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); +_tmpd.initWithPath(Services.env.get("XPCSHELL_TEST_TEMP_DIR")); + +// Allow `crashReporter` to be used as an alias in the tests. +var crashReporter = Services.appinfo; + +// We need to call this or crash events go in an undefined location. +Services.appinfo.UpdateCrashEventsDir(); + +// Setting the minidump path is not allowed in content processes +var processType = Services.appinfo.processType; +if (processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + Services.appinfo.minidumpPath = _tmpd; +} + +var protocolHandler = Services.io + .getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); +var curDirURI = Services.io.newFileURI(cwd); +protocolHandler.setSubstitution("test", curDirURI); +const { CrashTestUtils } = ChromeUtils.importESModule( + "resource://test/CrashTestUtils.sys.mjs" +); +var crashType = CrashTestUtils.CRASH_INVALID_POINTER_DEREF; +var shouldDelay = false; + +// Turn PHC on so that the PHC tests work. +CrashTestUtils.enablePHC(); diff --git a/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js b/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js new file mode 100644 index 0000000000..c9e415b567 --- /dev/null +++ b/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js @@ -0,0 +1,20 @@ +/* import-globals-from crasher_subprocess_head.js */ + +// Let the event loop process a bit before crashing. +if (shouldDelay) { + let shouldCrashNow = false; + + Services.tm.dispatchToMainThread({ + run: () => { + shouldCrashNow = true; + }, + }); + + Services.tm.spinEventLoopUntil( + "Test(crasher_subprocess_tail.js:shouldDelay)", + () => shouldCrashNow + ); +} + +// now actually crash +CrashTestUtils.crash(crashType); diff --git a/toolkit/crashreporter/test/unit/head_crashreporter.js b/toolkit/crashreporter/test/unit/head_crashreporter.js new file mode 100644 index 0000000000..c37c8acf8c --- /dev/null +++ b/toolkit/crashreporter/test/unit/head_crashreporter.js @@ -0,0 +1,347 @@ +const { makeFakeAppDir } = ChromeUtils.importESModule( + "resource://testing-common/AppData.sys.mjs" +); +var { AppConstants } = ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +function getEventDir() { + return PathUtils.join(do_get_tempdir().path, "crash-events"); +} + +function sendCommandAsync(command) { + return new Promise(resolve => { + sendCommand(command, resolve); + }); +} + +/* + * Run an xpcshell subprocess and crash it. + * + * @param setup + * A string of JavaScript code to execute in the subprocess + * before crashing. If this is a function and not a string, + * it will have .toSource() called on it, and turned into + * a call to itself. (for programmer convenience) + * This code will be evaluted between crasher_subprocess_head.js + * and crasher_subprocess_tail.js, so it will have access + * to everything defined in crasher_subprocess_head.js, + * which includes "crashReporter", a variable holding + * the crash reporter service. + * + * @param callback + * A JavaScript function to be called after the subprocess + * crashes. It will be passed (minidump, extra, extrafile), where + * - minidump is an nsIFile of the minidump file produced, + * - extra is an object containing the key,value pairs from + * the .extra file. + * - extrafile is an nsIFile of the extra file + * + * @param canReturnZero + * If true, the subprocess may return with a zero exit code. + * Certain types of crashes may not cause the process to + * exit with an error. + * + */ +async function do_crash(setup, callback, canReturnZero) { + // get current process filename (xpcshell) + let bin = Services.dirsvc.get("XREExeF", Ci.nsIFile); + if (!bin.exists()) { + // weird, can't find xpcshell binary? + do_throw("Can't find xpcshell binary!"); + } + // get Gre dir (GreD) + let greD = Services.dirsvc.get("GreD", Ci.nsIFile); + let headfile = do_get_file("crasher_subprocess_head.js"); + let tailfile = do_get_file("crasher_subprocess_tail.js"); + // run xpcshell -g GreD -f head -e "some setup code" -f tail + let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); + process.init(bin); + let args = ["-g", greD.path, "-f", headfile.path]; + if (setup) { + if (typeof setup == "function") { + // funky, but convenient + setup = "(" + setup.toSource() + ")();"; + } + args.push("-e", setup); + } + args.push("-f", tailfile.path); + + let crashD = do_get_tempdir(); + crashD.append("crash-events"); + if (!crashD.exists()) { + crashD.create(crashD.DIRECTORY_TYPE, 0o700); + } + + Services.env.set("CRASHES_EVENTS_DIR", crashD.path); + + try { + process.run(true, args, args.length); + } catch (ex) { + // on Windows we exit with a -1 status when crashing. + } finally { + Services.env.set("CRASHES_EVENTS_DIR", ""); + } + + if (!canReturnZero) { + // should exit with an error (should have crashed) + Assert.notEqual(process.exitValue, 0); + } + + await handleMinidump(callback); +} + +function getMinidump() { + let en = do_get_tempdir().directoryEntries; + while (en.hasMoreElements()) { + let f = en.nextFile; + if (f.leafName.substr(-4) == ".dmp") { + return f; + } + } + + return null; +} + +function getMinidumpAnalyzerPath() { + const binSuffix = AppConstants.platform === "win" ? ".exe" : ""; + const exeName = "minidump-analyzer" + binSuffix; + + let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile); + exe.append(exeName); + + return exe; +} + +function runMinidumpAnalyzer(dumpFile, additionalArgs) { + let bin = getMinidumpAnalyzerPath(); + let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); + process.init(bin); + let args = []; + if (additionalArgs) { + args = args.concat(additionalArgs); + } + args.push(dumpFile.path); + process.run(true /* blocking */, args, args.length); +} + +async function handleMinidump(callback) { + // find minidump + let minidump = getMinidump(); + + if (minidump == null) { + do_throw("No minidump found!"); + } + + let extrafile = minidump.clone(); + extrafile.leafName = extrafile.leafName.slice(0, -4) + ".extra"; + + let memoryfile = minidump.clone(); + memoryfile.leafName = memoryfile.leafName.slice(0, -4) + ".memory.json.gz"; + + let cleanup = async function () { + for (let file of [minidump, extrafile, memoryfile]) { + while (file.exists()) { + try { + file.remove(false); + } catch (e) { + // On Windows the file may be locked, wait briefly and try again + await new Promise(resolve => do_timeout(50, resolve)); + } + } + } + }; + + // Just in case, don't let these files linger. + registerCleanupFunction(cleanup); + + Assert.ok(extrafile.exists()); + let extra = await IOUtils.readJSON(extrafile.path); + + if (callback) { + await callback(minidump, extra, extrafile, memoryfile); + } + + await cleanup(); +} + +function spinEventLoop() { + return new Promise(resolve => { + executeSoon(resolve); + }); +} + +/** + * Helper for testing a content process crash. + * + * This variant accepts a setup function which runs in the content process + * to set data as needed _before_ the crash. The tail file triggers a generic + * crash after setup. + */ +async function do_content_crash(setup, callback) { + do_load_child_test_harness(); + + // Setting the minidump path won't work in the child, so we need to do + // that here. + Services.appinfo.minidumpPath = do_get_tempdir(); + + /* import-globals-from ../unit/crasher_subprocess_head.js */ + /* import-globals-from ../unit/crasher_subprocess_tail.js */ + + let headfile = do_get_file("../unit/crasher_subprocess_head.js"); + let tailfile = do_get_file("../unit/crasher_subprocess_tail.js"); + if (setup) { + if (typeof setup == "function") { + // funky, but convenient + setup = "(" + setup.toSource() + ")();"; + } + } + + do_get_profile(); + await makeFakeAppDir(); + await sendCommandAsync('load("' + headfile.path.replace(/\\/g, "/") + '");'); + if (setup) { + await sendCommandAsync(setup); + } + await sendCommandAsync('load("' + tailfile.path.replace(/\\/g, "/") + '");'); + await spinEventLoop(); + + let minidump = getMinidump(); + let id = minidump.leafName.slice(0, -4); + await Services.crashmanager.ensureCrashIsPresent(id); + try { + await handleMinidump(callback); + } catch (x) { + do_report_unexpected_exception(x); + } +} + +/** + * Helper for testing a content process crash. + * + * This variant accepts a trigger function which runs in the content process + * and does something to _trigger_ the crash. + */ +async function do_triggered_content_crash(trigger, callback) { + do_load_child_test_harness(); + + // Setting the minidump path won't work in the child, so we need to do + // that here. + Services.appinfo.minidumpPath = do_get_tempdir(); + + /* import-globals-from ../unit/crasher_subprocess_head.js */ + + let headfile = do_get_file("../unit/crasher_subprocess_head.js"); + if (trigger) { + if (typeof trigger == "function") { + // funky, but convenient + trigger = "(" + trigger.toSource() + ")();"; + } + } + + do_get_profile(); + await makeFakeAppDir(); + await sendCommandAsync('load("' + headfile.path.replace(/\\/g, "/") + '");'); + await sendCommandAsync(trigger); + await spinEventLoop(); + let id = getMinidump().leafName.slice(0, -4); + await Services.crashmanager.ensureCrashIsPresent(id); + try { + await handleMinidump(callback); + } catch (x) { + do_report_unexpected_exception(x); + } +} + +/* + * Run the `crash` backgroundtask subprocess, crashing it in the + * specified manner. + * + * @param crashType Integer `CrashTestUtils.CRASH_...` code. + * @param crashExtras Dictionary of key-value pairs to include in + * minidump extras. + * + * @param callback + * A JavaScript function to be called after the subprocess + * crashes. It will be passed (minidump, extra, extrafile), where + * - minidump is an nsIFile of the minidump file produced, + * - extra is an object containing the key,value pairs from + * the .extra file. + * - extrafile is an nsIFile of the extra file + * + * @param canReturnZero + * If true, the subprocess may return with a zero exit code. + * Certain types of crashes may not cause the process to + * exit with an error. + * + */ +async function do_backgroundtask_crash( + crashType, + crashExtras, + callback, + canReturnZero +) { + Assert.ok(AppConstants.MOZ_BACKGROUNDTASKS); + + // Get full path to application (not xpcshell) + let bin = Services.dirsvc.get("GreBinD", Ci.nsIFile); + if (AppConstants.platform === "win") { + bin.append(AppConstants.MOZ_APP_NAME + ".exe"); + } else { + bin.append(AppConstants.MOZ_APP_NAME); + } + + // run `application --backgroundtask crash ...`. + let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); + process.init(bin); + + let args = ["--backgroundtask", "crash"]; + args.push(crashType.toString()); + + // Sorted to be deterministic. + let sorted = Object.entries(crashExtras).sort((a, b) => a[0] < b[0]); + for (let [key, value] of sorted) { + args.push(key); + args.push(value); + } + + let crashD = do_get_tempdir(); + crashD.append("crash-events"); + if (!crashD.exists()) { + crashD.create(crashD.DIRECTORY_TYPE, 0o700); + } + + Services.env.set("CRASHES_EVENTS_DIR", crashD.path); + + // Ensure `resource://testing-common` gets mapped. + let protocolHandler = Services.io + .getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); + + let uri = protocolHandler.getSubstitution("testing-common"); + Assert.ok(uri, "resource://testing-common is not substituted"); + + // The equivalent of _TESTING_MODULES_DIR in xpcshell. + Services.env.set("XPCSHELL_TESTING_MODULES_URI", uri.spec); + + try { + process.run(true, args, args.length); + } catch (ex) { + // on Windows we exit with a -1 status when crashing. + } finally { + Services.env.set("CRASHES_EVENTS_DIR", ""); + Services.env.set("XPCSHELL_TESTING_MODULES_URI", ""); + } + + if (!canReturnZero) { + // should exit with an error (should have crashed) + Assert.notEqual(process.exitValue, 0); + } + + await handleMinidump(callback); +} + +// Import binary APIs via js-ctypes. +var { CrashTestUtils } = ChromeUtils.importESModule( + "resource://test/CrashTestUtils.sys.mjs" +); diff --git a/toolkit/crashreporter/test/unit/head_win64cfi.js b/toolkit/crashreporter/test/unit/head_win64cfi.js new file mode 100644 index 0000000000..4df99213db --- /dev/null +++ b/toolkit/crashreporter/test/unit/head_win64cfi.js @@ -0,0 +1,215 @@ +/* import-globals-from head_crashreporter.js */ + +let gTestCrasherSyms = null; +let gModules = null; + +// Returns the offset (int) of an IP with a given base address. +// This is effectively (ip - base), except a bit more complication due to +// Javascript's shaky handling of 64-bit integers. +// base & ip are passed as hex strings. +function getModuleOffset(base, ip) { + let i = 0; + // Find where the two addresses diverge, which enables us to perform a 32-bit + // subtraction. + // e.g. "0x1111111111112222" + // - "0x1111111111111111" + // becomes 2222 - 1111 + for (; i < base.length; ++i) { + if (base[i] != ip[i]) { + break; + } + } + if (i == base.length) { + return 0; + } + let lhs2 = "0x" + base.substring(i); + let rhs2 = "0x" + ip.substring(i); + return parseInt(rhs2) - parseInt(lhs2); +} + +// Uses gTestCrasherSyms to convert an address to a symbol. +function findNearestTestCrasherSymbol(addr) { + addr += 1; // Breakpad sometimes offsets addresses; correct for this. + let closestDistance = null; + let closestSym = null; + for (let sym in gTestCrasherSyms) { + if (addr >= gTestCrasherSyms[sym]) { + let thisDistance = addr - gTestCrasherSyms[sym]; + if (closestDistance === null || thisDistance < closestDistance) { + closestDistance = thisDistance; + closestSym = sym; + } + } + } + if (closestSym === null) { + return null; + } + return { symbol: closestSym, offset: closestDistance }; +} + +// Populate known symbols for testcrasher.dll. +// Use the same prop names as from CrashTestUtils to avoid the need for mapping. +function initTestCrasherSymbols() { + gTestCrasherSyms = {}; + for (let k in CrashTestUtils) { + // Not all keys here are valid symbol names. getWin64CFITestFnAddrOffset + // will return 0 in those cases, no need to filter here. + if (Number.isInteger(CrashTestUtils[k])) { + let t = CrashTestUtils.getWin64CFITestFnAddrOffset(CrashTestUtils[k]); + if (t > 0) { + gTestCrasherSyms[k] = t; + } + } + } +} + +function stackFrameToString(frameIndex, frame) { + // Calculate the module offset. + let ip = frame.ip; + let symbol = ""; + let moduleOffset = "unknown_offset"; + let filename = "unknown_module"; + + if ( + typeof frame.module_index !== "undefined" && + frame.module_index >= 0 && + frame.module_index < gModules.length + ) { + let base = gModules[frame.module_index].base_addr; + moduleOffset = getModuleOffset(base, ip); + filename = gModules[frame.module_index].filename; + + if (filename === "testcrasher.dll") { + let nearestSym = findNearestTestCrasherSymbol(moduleOffset); + if (nearestSym !== null) { + symbol = nearestSym.symbol + "+" + nearestSym.offset.toString(16); + } + } + } + + let ret = + "frames[" + + frameIndex + + "] ip=" + + ip + + " " + + symbol + + ", module:" + + filename + + ", trust:" + + frame.trust + + ", moduleOffset:" + + moduleOffset.toString(16); + return ret; +} + +function dumpStackFrames(frames, maxFrames) { + for (let i = 0; i < Math.min(maxFrames, frames.length); ++i) { + info(stackFrameToString(i, frames[i])); + } +} + +// Test that the top of the given stack (from extra data) matches the given +// expected frames. +// +// expected is { symbol: "", trust: "" } +function assertStack(stack, expected) { + for (let i = 0; i < stack.length; ++i) { + if (i >= expected.length) { + ok("Top stack frames were expected"); + return; + } + let frame = stack[i]; + let expectedFrame = expected[i]; + let dumpThisFrame = function () { + info(" Actual frame: " + stackFrameToString(i, frame)); + info( + "Expected { symbol: " + + expectedFrame.symbol + + ", trust: " + + expectedFrame.trust + + "}" + ); + }; + + if (expectedFrame.trust) { + if (expectedFrame.trust.startsWith("!")) { + // A "!" prefix on the frame trust matching is a logical "not". + if (frame.trust === expectedFrame.trust.substring(1)) { + dumpThisFrame(); + info("Expected frame trust matched when it should not have."); + ok(false); + } + } else if (frame.trust !== expectedFrame.trust) { + dumpThisFrame(); + info("Expected frame trust did not match."); + ok(false); + } + } + + if (expectedFrame.symbol) { + if (typeof frame.module_index === "undefined") { + // Without a module_index, it happened in an unknown module. Currently + // you can't specify an expected "unknown" module. + info("Unknown symbol in unknown module."); + ok(false); + } + if (frame.module_index < 0 || frame.module_index >= gModules.length) { + dumpThisFrame(); + info("Unknown module."); + ok(false); + return; + } + let base = gModules[frame.module_index].base_addr; + let moduleOffset = getModuleOffset(base, frame.ip); + let filename = gModules[frame.module_index].filename; + if (filename == "testcrasher.dll") { + let nearestSym = findNearestTestCrasherSymbol(moduleOffset); + if (nearestSym === null) { + dumpThisFrame(); + info("Unknown symbol."); + ok(false); + return; + } + + if (nearestSym.symbol !== expectedFrame.symbol) { + dumpThisFrame(); + info("Mismatching symbol."); + ok(false); + } + } + } + } +} + +// Performs a crash, runs minidump-analyzer, and checks expected stack analysis. +// +// how: The crash to perform. Constants defined in both CrashTestUtils.jsm +// and nsTestCrasher.cpp (i.e. CRASH_X64CFI_PUSH_NONVOL) +// expectedStack: An array of {"symbol", "trust"} where trust is "cfi", +// "context", "scan", et al. May be null if you don't need to check the stack. +// minidumpAnalyzerArgs: An array of additional arguments to pass to +// minidump-analyzer.exe. +async function do_x64CFITest(how, expectedStack, minidumpAnalyzerArgs) { + // Setup is run in the subprocess so we cannot use any closures. + let setupFn = "crashType = CrashTestUtils." + how + ";"; + + let callbackFn = async function (minidumpFile, extra, extraFile) { + runMinidumpAnalyzer(minidumpFile, minidumpAnalyzerArgs); + + // Refresh updated extra data + extra = await IOUtils.readJSON(extraFile.path); + + initTestCrasherSymbols(); + let stackTraces = extra.StackTraces; + let crashingThreadIndex = stackTraces.crash_info.crashing_thread; + gModules = stackTraces.modules; + let crashingFrames = stackTraces.threads[crashingThreadIndex].frames; + + dumpStackFrames(crashingFrames, 10); + + assertStack(crashingFrames, expectedStack); + }; + + do_crash(setupFn, callbackFn, true, true); +} diff --git a/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js b/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js new file mode 100644 index 0000000000..c4011c7474 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js @@ -0,0 +1,68 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that AsyncShutdown report errors correctly + +// Note: these functions are evaluated in their own process, hence the need +// to import modules into each function. + +function setup_crash() { + const { AsyncShutdown } = ChromeUtils.importESModule( + "resource://gre/modules/AsyncShutdown.sys.mjs" + ); + + Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true); + Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 10); + + let TOPIC = "testing-async-shutdown-crash"; + let phase = AsyncShutdown._getPhase(TOPIC); + phase.addBlocker("A blocker that is never satisfied", function () { + dump("Installing blocker\n"); + let deferred = Promise.withResolvers(); + return deferred.promise; + }); + + Services.obs.notifyObservers(null, TOPIC); + dump(new Error().stack + "\n"); + dump("Waiting for crash\n"); +} + +function after_crash(mdump, extra) { + info("after crash: " + extra.AsyncShutdownTimeout); + let data = JSON.parse(extra.AsyncShutdownTimeout); + Assert.equal(data.phase, "testing-async-shutdown-crash"); + Assert.equal(data.conditions[0].name, "A blocker that is never satisfied"); + // This test spawns subprocesses by using argument "-e" of xpcshell, so + // this is the filename known to xpcshell. + Assert.equal(data.conditions[0].filename, "-e"); +} + +// Test that AsyncShutdown + IOUtils reports errors correctly., + +function setup_ioutils_crash() { + Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 1); + + IOUtils.profileBeforeChange.addBlocker( + "Adding a blocker that will never be resolved", + () => Promise.withResolvers().promise + ); + + Services.startup.advanceShutdownPhase( + Services.startup.SHUTDOWN_PHASE_APPSHUTDOWN + ); + dump("Waiting for crash\n"); +} + +function after_ioutils_crash(mdump, extra) { + info("after IOUtils crash: " + extra.AsyncShutdownTimeout); + let data = JSON.parse(extra.AsyncShutdownTimeout); + Assert.equal( + data.phase, + "IOUtils: waiting for profileBeforeChange IO to complete" + ); +} + +add_task(async function run_test() { + await do_crash(setup_crash, after_crash); + await do_crash(setup_ioutils_crash, after_ioutils_crash); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_abort.js b/toolkit/crashreporter/test/unit/test_crash_abort.js new file mode 100644 index 0000000000..aa602dacb4 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_abort.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function run_test() { + // Try crashing with an abort(). + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_ABORT; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js new file mode 100644 index 0000000000..611ba9b6ac --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js @@ -0,0 +1,23 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_after_js_large_allocation_failure.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "Yes"); + Cu.getJSTestingFunctions().reportLargeAllocationFailure(); + Cu.forceGC(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "Yes"); + Assert.equal(false, "JSOutOfMemory" in extra); + Assert.equal(extra.JSLargeAllocationFailure, "Recovered"); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js new file mode 100644 index 0000000000..cdae0f2d8e --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js @@ -0,0 +1,27 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_after_js_oom_reporting.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "Yes"); + + function crashWhileReporting() { + CrashTestUtils.crash(crashType); + } + + Services.obs.addObserver(crashWhileReporting, "memory-pressure"); + Cu.getJSTestingFunctions().reportLargeAllocationFailure(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "Yes"); + Assert.equal(extra.JSLargeAllocationFailure, "Reporting"); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js new file mode 100644 index 0000000000..7b2491bc0b --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js @@ -0,0 +1,22 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_after_js_oom_recovered.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "Yes"); + Cu.getJSTestingFunctions().reportOutOfMemory(); + Cu.forceGC(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "Yes"); + Assert.equal(extra.JSOutOfMemory, "Recovered"); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js new file mode 100644 index 0000000000..8796aee3c0 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js @@ -0,0 +1,36 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_after_js_oom_reported.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "Yes"); + + // GC now to avoid having it happen randomly later, which would make the + // test bogusly fail. See comment below. + Cu.forceGC(); + + Cu.getJSTestingFunctions().reportOutOfMemory(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "Yes"); + + // The JSOutOfMemory field is absent if the JS engine never reported OOM, + // "Reported" if it did, and "Recovered" if it reported OOM but + // subsequently completed a full GC cycle. Since this test calls + // reportOutOfMemory() and then crashes, we expect "Reported". + // + // Theoretically, GC can happen any time, so it is just possible that + // this property could be "Recovered" even if the implementation is + // correct. More likely, though, that indicates a bug, so only accept + // "Reported". + Assert.equal(extra.JSOutOfMemory, "Reported"); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js new file mode 100644 index 0000000000..ba67981444 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js @@ -0,0 +1,28 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_after_js_oom_reported_2.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "Yes"); + Cu.getJSTestingFunctions().reportOutOfMemory(); + Cu.forceGC(); // recover from first OOM + Cu.getJSTestingFunctions().reportOutOfMemory(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "Yes"); + + // Technically, GC can happen at any time, but it would be really + // peculiar for it to happen again heuristically right after a GC was + // forced. If extra.JSOutOfMemory is "Recovered" here, that's most + // likely a bug in the error reporting machinery. + Assert.equal(extra.JSOutOfMemory, "Reported"); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_backgroundtask_moz_crash.js b/toolkit/crashreporter/test/unit/test_crash_backgroundtask_moz_crash.js new file mode 100644 index 0000000000..847e260925 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_backgroundtask_moz_crash.js @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function run_test() { + if (!AppConstants.MOZ_BACKGROUNDTASKS) { + return; + } + + // Try crashing background task with a runtime abort + await do_backgroundtask_crash( + CrashTestUtils.CRASH_MOZ_CRASH, + { TestKey: "TestValue" }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + Assert.equal(extra.BackgroundTaskMode, "1"); + Assert.equal(extra.BackgroundTaskName, "crash"); + Assert.equal(extra.HeadlessMode, "1"); + Assert.equal(false, "OOMAllocationSize" in extra); + Assert.equal(false, "JSOutOfMemory" in extra); + Assert.equal(false, "JSLargeAllocationFailure" in extra); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_exc_guard.js b/toolkit/crashreporter/test/unit/test_crash_exc_guard.js new file mode 100644 index 0000000000..f7daffe68c --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_exc_guard.js @@ -0,0 +1,30 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_exc_guard.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing by closing a guarded file descriptor + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_EXC_GUARD; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + async function (mdump, extra, extraFile) { + runMinidumpAnalyzer(mdump); + + // Refresh updated extra data + extra = await IOUtils.readJSON(extraFile.path); + + Assert.equal( + extra.StackTraces.crash_info.type, + "EXC_GUARD / GUARD_TYPE_FD / GUARD_EXC_CLOSE" + ); + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_heap_corruption.js b/toolkit/crashreporter/test/unit/test_crash_heap_corruption.js new file mode 100644 index 0000000000..0530b8b074 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_heap_corruption.js @@ -0,0 +1,27 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_heap_corruption.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with a STATUS_HEAP_CORRUPTION exception + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_HEAP_CORRUPTION; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + async function (mdump, extra, extraFile) { + runMinidumpAnalyzer(mdump); + + // Refresh updated extra data + extra = await IOUtils.readJSON(extraFile.path); + + Assert.equal(extra.StackTraces.crash_info.type, "STATUS_HEAP_CORRUPTION"); + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_modules.js b/toolkit/crashreporter/test/unit/test_crash_modules.js new file mode 100644 index 0000000000..dd14e77dab --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_modules.js @@ -0,0 +1,44 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_modules.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + const { ctypes } = ChromeUtils.importESModule( + "resource://gre/modules/ctypes.sys.mjs" + ); + // Load and unload a DLL so that it will show up as unloaded in the minidump + let lib = ctypes.open("wininet"); + lib.close(); + }, + async function (mdump, extra, extraFile) { + runMinidumpAnalyzer(mdump); + + // Refresh updated extra data + extra = await IOUtils.readJSON(extraFile.path); + + // Check unloaded modules + const unloadedModules = extra.StackTraces.unloaded_modules; + Assert.ok(!!unloadedModules, "The unloaded_modules field exists"); + Assert.notEqual(unloadedModules.find(e => e.filename == "wininet.DLL")); + + // Check the module signature information + const sigInfo = JSON.parse(extra.ModuleSignatureInfo); + Assert.ok( + !!sigInfo["Microsoft Windows"], + "The module signature info contains valid data" + ); + Assert.greater( + sigInfo["Microsoft Windows"].length, + 0, + "Multiple signed binaries were found" + ); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_moz_crash.js b/toolkit/crashreporter/test/unit/test_crash_moz_crash.js new file mode 100644 index 0000000000..6016957d44 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_moz_crash.js @@ -0,0 +1,17 @@ +add_task(async function run_test() { + // Try crashing with a runtime abort + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + Assert.equal(false, "OOMAllocationSize" in extra); + Assert.equal(false, "JSOutOfMemory" in extra); + Assert.equal(false, "JSLargeAllocationFailure" in extra); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_oom.js b/toolkit/crashreporter/test/unit/test_crash_oom.js new file mode 100644 index 0000000000..3b32da4ab8 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_oom.js @@ -0,0 +1,21 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_oom.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_OOM; + }, + function (mdump, extra) { + Assert.ok("OOMAllocationSize" in extra); + Assert.ok(Number(extra.OOMAllocationSize) > 0); + Assert.ok("TotalPhysicalMemory" in extra); + Assert.ok(Number(extra.TotalPhysicalMemory) >= 0); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_phc.js b/toolkit/crashreporter/test/unit/test_crash_phc.js new file mode 100644 index 0000000000..54bc8ec34e --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_phc.js @@ -0,0 +1,59 @@ +function check(extra, kind, size, hasFreeStack) { + Assert.equal(extra.PHCKind, kind); + + // This is a string holding a decimal address. + Assert.ok(/^\d+$/.test(extra.PHCBaseAddress)); + + Assert.equal(extra.PHCUsableSize, size); + + // These are strings holding comma-separated lists of decimal addresses. + // Sometimes on Mac they have a single entry. + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack)); + if (hasFreeStack) { + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack)); + } else { + Assert.ok(!extra.hasOwnProperty("PHCFreeStack")); + } +} + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_phc.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_USE_AFTER_FREE; + }, + function (mdump, extra) { + // CRASH_PHC_USE_AFTER_FREE uses 32 for the size. + check(extra, "FreedPage", 32, /* hasFreeStack */ true); + }, + true + ); + + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_DOUBLE_FREE; + }, + function (mdump, extra) { + // CRASH_PHC_DOUBLE_FREE uses 64 for the size. + check(extra, "FreedPage", 64, /* hasFreeStack */ true); + }, + true + ); + + do_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_BOUNDS_VIOLATION; + }, + function (mdump, extra) { + // CRASH_PHC_BOUNDS_VIOLATION uses 96 for the size. + check(extra, "GuardPage", 96, /* hasFreeStack */ false); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_purevirtual.js b/toolkit/crashreporter/test/unit/test_crash_purevirtual.js new file mode 100644 index 0000000000..cc81c008df --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_purevirtual.js @@ -0,0 +1,21 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_purevirtual.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with a pure virtual call + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_PURE_VIRTUAL_CALL; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_rust_panic.js b/toolkit/crashreporter/test/unit/test_crash_rust_panic.js new file mode 100644 index 0000000000..dff1d6281a --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_rust_panic.js @@ -0,0 +1,15 @@ +add_task(async function run_test() { + // Try crashing with a Rust panic + await do_crash( + function () { + Cc["@mozilla.org/xpcom/debug;1"] + .getService(Ci.nsIDebug2) + .rustPanic("OH NO"); + }, + function (mdump, extra) { + Assert.equal(extra.MozCrashReason, "OH NO"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_rust_panic_multiline.js b/toolkit/crashreporter/test/unit/test_crash_rust_panic_multiline.js new file mode 100644 index 0000000000..3908c76a2e --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_rust_panic_multiline.js @@ -0,0 +1,15 @@ +add_task(async function run_test() { + // Try crashing with a Rust panic + await do_crash( + function () { + Cc["@mozilla.org/xpcom/debug;1"] + .getService(Ci.nsIDebug2) + .rustPanic("OH NO\nOH NOES!"); + }, + function (mdump, extra) { + Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_stack_overflow.js b/toolkit/crashreporter/test/unit/test_crash_stack_overflow.js new file mode 100644 index 0000000000..a47c217238 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_stack_overflow.js @@ -0,0 +1,21 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_stack_overflow.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing by overflowing a thread's stack + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_STACK_OVERFLOW; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + async function (mdump, extra, extraFile) { + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_terminator.js b/toolkit/crashreporter/test/unit/test_crash_terminator.js new file mode 100644 index 0000000000..c051a7e277 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_terminator.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that the Shutdown Terminator report errors correctly + +function setup_crash() { + Services.prefs.setBoolPref("toolkit.terminator.testing", true); + Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 150); + + // Initialize the terminator + // (normally, this is done through the manifest file, but xpcshell + // doesn't take them into account). + let terminator = Cc[ + "@mozilla.org/toolkit/shutdown-terminator;1" + ].createInstance(Ci.nsIObserver); + terminator.observe(null, "terminator-test-profile-after-change", null); + + // Inform the terminator that shutdown has started + // Pick an arbitrary notification + terminator.observe(null, "terminator-test-profile-before-change", null); + terminator.observe(null, "terminator-test-xpcom-will-shutdown", null); + + dump("Waiting (actively) for the crash\n"); + Services.tm.spinEventLoopUntil( + "Test(test_crash_terminator.js:setup_crash())", + () => false + ); +} + +function after_crash(mdump, extra) { + info("Crash signature: " + JSON.stringify(extra, null, "\t")); + Assert.equal(extra.ShutdownProgress, "xpcom-will-shutdown"); +} + +add_task(async function run_test() { + await do_crash(setup_crash, after_crash); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_uncaught_exception.js b/toolkit/crashreporter/test/unit/test_crash_uncaught_exception.js new file mode 100644 index 0000000000..bfcd2b0ef2 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_uncaught_exception.js @@ -0,0 +1,17 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function run_test() { + // Try crashing with an uncaught exception. + await do_crash( + function () { + crashType = CrashTestUtils.CRASH_UNCAUGHT_EXCEPTION; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + }, + // process will exit with a zero exit status + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_large.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_large.js new file mode 100644 index 0000000000..a16fe20b4c --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_large.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_ALLOC_LARGE", [ + { symbol: "CRASH_X64CFI_ALLOC_LARGE", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_small.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_small.js new file mode 100644 index 0000000000..0b321bac6f --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_alloc_small.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_ALLOC_SMALL", [ + { symbol: "CRASH_X64CFI_ALLOC_SMALL", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_epilog.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_epilog.js new file mode 100644 index 0000000000..423b67f6f9 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_epilog.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_EPILOG", [ + { symbol: "CRASH_X64CFI_EPILOG", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.exe b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.exe new file mode 100644 index 0000000000..5283cc5df7 Binary files /dev/null and b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.exe differ diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.js new file mode 100644 index 0000000000..a8a900c995 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_code_chain.js @@ -0,0 +1,22 @@ +add_task(async function run_test() { + // Test that minidump-analyzer gracefully handles chained + // unwind code entries that form a circular reference + // (infinite loop). + let exe = do_get_file("test_crash_win64cfi_infinite_code_chain.exe"); + ok(exe); + + // Perform a crash. The PE used for unwind info should fail, resulting in + // fallback behavior, calculating the first frame from thread context. + // Further frames would be calculated with either frame_pointer or scan trust, + // but should not be calculated via CFI. If we see CFI here that would be an + // indication that either our alternative EXE was not used, or we failed to + // abandon unwind info parsing. + await do_x64CFITest( + "CRASH_X64CFI_ALLOC_SMALL", + [ + { symbol: "CRASH_X64CFI_ALLOC_SMALL", trust: "context" }, + { symbol: null, trust: "!cfi" }, + ], + ["--force-use-module", exe.path] + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.exe b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.exe new file mode 100644 index 0000000000..de48576f65 Binary files /dev/null and b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.exe differ diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.js new file mode 100644 index 0000000000..de3d31f0ef --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_infinite_entry_chain.js @@ -0,0 +1,22 @@ +add_task(async function run_test() { + // Test that minidump-analyzer gracefully handles chained + // IMAGE_RUNTIME_FUNCTION_ENTRY items that form a circular reference + // (infinite loop). + let exe = do_get_file("test_crash_win64cfi_infinite_entry_chain.exe"); + ok(exe); + + // Perform a crash. The PE used for unwind info should fail, resulting in + // fallback behavior, calculating the first frame from thread context. + // Further frames would be calculated with either frame_pointer or scan trust, + // but should not be calculated via CFI. If we see CFI here that would be an + // indication that either our alternative EXE was not used, or we failed to + // abandon unwind info parsing. + await do_x64CFITest( + "CRASH_X64CFI_ALLOC_SMALL", + [ + { symbol: "CRASH_X64CFI_ALLOC_SMALL", trust: "context" }, + { symbol: null, trust: "!cfi" }, + ], + ["--force-use-module", exe.path] + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.exe b/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.exe new file mode 100644 index 0000000000..ab4ce326bd Binary files /dev/null and b/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.exe differ diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.js new file mode 100644 index 0000000000..3d1eb02011 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_invalid_exception_rva.js @@ -0,0 +1,21 @@ +add_task(async function run_test() { + // Test that minidump-analyzer gracefully handles an invalid pointer to the + // exception unwind information. + let exe = do_get_file("test_crash_win64cfi_invalid_exception_rva.exe"); + ok(exe); + + // Perform a crash. The PE used for unwind info should fail, resulting in + // fallback behavior, calculating the first frame from thread context. + // Further frames would be calculated with either frame_pointer or scan trust, + // but should not be calculated via CFI. If we see CFI here that would be an + // indication that either our alternative EXE was not used, or we failed to + // abandon unwind info parsing. + await do_x64CFITest( + "CRASH_X64CFI_ALLOC_SMALL", + [ + { symbol: "CRASH_X64CFI_ALLOC_SMALL", trust: "context" }, + { symbol: null, trust: "!cfi" }, + ], + ["--force-use-module", exe.path] + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.exe b/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.exe new file mode 100644 index 0000000000..5fa1d76ffc --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.exe @@ -0,0 +1 @@ +this is not a valid PE file. \ No newline at end of file diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.js new file mode 100644 index 0000000000..5fcbee9cbe --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_not_a_pe.js @@ -0,0 +1,20 @@ +add_task(async function run_test() { + // Test that minidump-analyzer gracefully handles corrupt PE files. + let exe = do_get_file("test_crash_win64cfi_not_a_pe.exe"); + ok(exe); + + // Perform a crash. The PE used for unwind info should fail, resulting in + // fallback behavior, calculating the first frame from thread context. + // Further frames would be calculated with either frame_pointer or scan trust, + // but should not be calculated via CFI. If we see CFI here that would be an + // indication that either our alternative EXE was not used, or we failed to + // abandon unwind info parsing. + await do_x64CFITest( + "CRASH_X64CFI_ALLOC_SMALL", + [ + { symbol: "CRASH_X64CFI_ALLOC_SMALL", trust: "context" }, + { symbol: null, trust: "!cfi" }, + ], + ["--force-use-module", exe.path] + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_push_nonvol.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_push_nonvol.js new file mode 100644 index 0000000000..e875ab3434 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_push_nonvol.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_PUSH_NONVOL", [ + { symbol: "CRASH_X64CFI_PUSH_NONVOL", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol.js new file mode 100644 index 0000000000..9bc309834a --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_SAVE_NONVOL", [ + { symbol: "CRASH_X64CFI_SAVE_NONVOL", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol_far.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol_far.js new file mode 100644 index 0000000000..b87b4b35b4 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_nonvol_far.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_SAVE_NONVOL_FAR", [ + { symbol: "CRASH_X64CFI_SAVE_NONVOL_FAR", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128.js new file mode 100644 index 0000000000..22d09f157a --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_SAVE_XMM128", [ + { symbol: "CRASH_X64CFI_SAVE_XMM128", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128_far.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128_far.js new file mode 100644 index 0000000000..bd5f16baa8 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_save_xmm128_far.js @@ -0,0 +1,6 @@ +add_task(async function run_test() { + await do_x64CFITest("CRASH_X64CFI_SAVE_XMM128_FAR", [ + { symbol: "CRASH_X64CFI_SAVE_XMM128_FAR", trust: "context" }, + { symbol: "CRASH_X64CFI_LAUNCHER", trust: "cfi" }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_win64cfi_unknown_op.js b/toolkit/crashreporter/test/unit/test_crash_win64cfi_unknown_op.js new file mode 100644 index 0000000000..cdcd8c2aad --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_win64cfi_unknown_op.js @@ -0,0 +1,12 @@ +add_task(async function run_test() { + // In the case of an unknown unwind code or missing CFI, + // make certain we can still walk the stack via stack scan. The crashing + // function places NO_MANS_LAND on the stack so it will get picked up via + // stack scan. + await do_x64CFITest("CRASH_X64CFI_UNKNOWN_OPCODE", [ + { symbol: "CRASH_X64CFI_UNKNOWN_OPCODE", trust: "context" }, + // Trust may either be scan or frame_pointer; we don't really care as + // long as the address is expected. + { symbol: "CRASH_X64CFI_NO_MANS_LAND", trust: null }, + ]); +}); diff --git a/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js b/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js new file mode 100644 index 0000000000..e10e6697df --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js @@ -0,0 +1,49 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_oom.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // This was shamelessly copied and stripped down from do_get_profile() in + // head.js so that nsICrashReporter::saveMemoryReport can use a profile + // within the crasher subprocess. + + await do_crash( + function () { + // Delay crashing so that the memory report has time to complete. + shouldDelay = true; + + let profd = Services.env.get("XPCSHELL_TEST_PROFILE_DIR"); + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(profd); + + let provider = { + getFile(prop, persistent) { + persistent.value = true; + if ( + prop == "ProfD" || + prop == "ProfLD" || + prop == "ProfDS" || + prop == "ProfLDS" || + prop == "TmpD" + ) { + return file.clone(); + } + throw Components.Exception("", Cr.NS_ERROR_FAILURE); + }, + QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]), + }; + Services.dirsvc + .QueryInterface(Ci.nsIDirectoryService) + .registerProvider(provider); + + crashReporter.saveMemoryReport(); + }, + function (mdump, extra, extrafile, memoryfile) { + Assert.ok(memoryfile.exists()); + }, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crashreporter.js b/toolkit/crashreporter/test/unit/test_crashreporter.js new file mode 100644 index 0000000000..d1a8b10316 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crashreporter.js @@ -0,0 +1,90 @@ +function run_test() { + dump("INFO | test_crashreporter.js | Get crashreporter service.\n"); + var cr = Services.appinfo; + Assert.ok(Services.appinfo.crashReporterEnabled); + + try { + cr.serverURL; + do_throw("Getting serverURL when not set should have thrown!"); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_FAILURE); + } + + // check setting/getting serverURL + + // try it with two different URLs, just for kicks + var testspecs = [ + "http://example.com/submit", + "https://example.org/anothersubmit", + ]; + for (var i = 0; i < testspecs.length; ++i) { + cr.serverURL = Services.io.newURI(testspecs[i]); + Assert.equal(cr.serverURL.spec, testspecs[i]); + } + + // should not allow setting non-http/https URLs + try { + cr.serverURL = Services.io.newURI("ftp://example.com/submit"); + do_throw("Setting serverURL to a non-http(s) URL should have thrown!"); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + + // check getting/setting minidumpPath + // it should be $TEMP by default, but I'm not sure if we can exactly test that + // this will at least test that it doesn't throw + Assert.notEqual(cr.minidumpPath.path, ""); + var cwd = do_get_cwd(); + cr.minidumpPath = cwd; + Assert.equal(cr.minidumpPath.path, cwd.path); + + // Test annotateCrashReport() + try { + cr.annotateCrashReport(undefined, ""); + do_throw( + "Calling annotateCrashReport() with an undefined key should have thrown!" + ); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + try { + cr.annotateCrashReport("foobar", ""); + do_throw( + "Calling annotateCrashReport() with a bogus key should have thrown!" + ); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + cr.annotateCrashReport("TestKey", "testData1"); + // Replace previous data. + cr.annotateCrashReport("TestKey", "testData2"); + // Allow nul chars in annotations. + cr.annotateCrashReport("TestKey", "da\0ta"); + + cr.appendAppNotesToCrashReport("additional testData3"); + // Add more data. + cr.appendAppNotesToCrashReport("additional testData4"); + + // Test removeCrashReportAnnotation() + try { + cr.removeCrashReportAnnotation(undefined); + do_throw( + "Calling removeCrashReportAnnotation() with an undefined key should have thrown!" + ); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + try { + cr.removeCrashReportAnnotation("foobar"); + do_throw( + "Calling removeCrashReportAnnotation() with a bogus key should have thrown!" + ); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + cr.removeCrashReportAnnotation("TestKey"); + + // Testing setting the minidumpPath field + cr.minidumpPath = cwd; + Assert.equal(cr.minidumpPath.path, cwd.path); +} diff --git a/toolkit/crashreporter/test/unit/test_crashreporter_appmem.js b/toolkit/crashreporter/test/unit/test_crashreporter_appmem.js new file mode 100644 index 0000000000..f42fe10f0c --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crashreporter_appmem.js @@ -0,0 +1,13 @@ +add_task(async function run_test() { + await do_crash( + function () { + let appAddr = CrashTestUtils.saveAppMemory(); + crashReporter.registerAppMemory(appAddr, 32); + }, + function (mdump, extra) { + Assert.ok(mdump.exists()); + Assert.ok(mdump.fileSize > 0); + Assert.ok(CrashTestUtils.dumpCheckMemory(mdump.path)); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_crashreporter_crash.js b/toolkit/crashreporter/test/unit/test_crashreporter_crash.js new file mode 100644 index 0000000000..4d0abbc2ef --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_crashreporter_crash.js @@ -0,0 +1,223 @@ +add_task(async function run_test() { + var is_win7_or_newer = false; + var is_windows = false; + var ph = Cc["@mozilla.org/network/protocol;1?name=http"].getService( + Ci.nsIHttpProtocolHandler + ); + var match = ph.userAgent.match(/Windows NT (\d+).(\d+)/); + if (match) { + is_windows = true; + } + if ( + match && + (parseInt(match[1]) > 6 || + (parseInt(match[1]) == 6 && parseInt(match[2]) >= 1)) + ) { + is_win7_or_newer = true; + } + + // try a basic crash + await do_content_crash(null, function (mdump, extra) { + Assert.ok(mdump.exists()); + Assert.ok(mdump.fileSize > 0); + Assert.ok("StartupTime" in extra); + Assert.ok("CrashTime" in extra); + Assert.ok( + CrashTestUtils.dumpHasStream( + mdump.path, + CrashTestUtils.MD_THREAD_LIST_STREAM + ) + ); + Assert.ok(CrashTestUtils.dumpHasInstructionPointerMemory(mdump.path)); + if (is_windows) { + [ + "SystemMemoryUsePercentage", + "TotalVirtualMemory", + "AvailableVirtualMemory", + "AvailablePageFile", + "AvailablePhysicalMemory", + ].forEach(function (prop) { + Assert.ok(/^\d+$/.test(extra[prop].toString())); + }); + } + if (is_win7_or_newer) { + Assert.ok( + CrashTestUtils.dumpHasStream( + mdump.path, + CrashTestUtils.MD_MEMORY_INFO_LIST_STREAM + ) + ); + } + }); + + // check setting some basic data + await do_crash( + function () { + // Add various annotations + crashReporter.annotateCrashReport("TestKey", "TestValue"); + crashReporter.annotateCrashReport( + "TestUnicode", + "\u{1F4A9}\n\u{0000}Escape" + ); + crashReporter.annotateCrashReport("Add-ons", "test%40mozilla.org:0.1"); + crashReporter.appendAppNotesToCrashReport("Junk"); + crashReporter.appendAppNotesToCrashReport("MoreJunk"); + + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + TelemetryController.testSetup(); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + Assert.equal(extra.TestUnicode, "\u{1F4A9}\n\u{0000}Escape"); + Assert.ok( + extra.Notes.endsWith("JunkMoreJunk"), + "Should include our notes" + ); + Assert.equal(extra["Add-ons"], "test%40mozilla.org:0.1"); + const UUID_REGEX = + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + Assert.ok( + "TelemetrySessionId" in extra, + "The TelemetrySessionId field is present in the extra file" + ); + Assert.ok( + UUID_REGEX.test(extra.TelemetrySessionId), + "The TelemetrySessionId is a UUID" + ); + Assert.ok( + !("TelemetryClientId" in extra), + "The TelemetryClientId field is omitted by default" + ); + Assert.ok( + !("TelemetryServerURL" in extra), + "The TelemetryServerURL field is omitted by default" + ); + } + ); + + await do_crash( + function () { + // Enable the FHR, official policy bypass (since we're in a test) and + // specify a telemetry server & client ID. + Services.prefs.setBoolPref( + "datareporting.policy.dataSubmissionPolicyBypassNotification", + true + ); + Services.prefs.setBoolPref( + "datareporting.healthreport.uploadEnabled", + true + ); + Services.prefs.setCharPref( + "toolkit.telemetry.server", + "http://a.telemetry.server" + ); + Services.prefs.setIntPref("telemetry.fog.test.localhost_port", -1); + Services.prefs.setCharPref( + "toolkit.telemetry.cachedClientID", + "f3582dee-22b9-4d73-96d1-79ef5bf2fc24" + ); + + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + let { TelemetrySend } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetrySend.sys.mjs" + ); + TelemetrySend.setTestModeEnabled(true); + TelemetryController.testSetup(); + }, + function (mdump, extra) { + Assert.ok( + "TelemetryClientId" in extra, + "The TelemetryClientId field is present when the FHR is on" + ); + Assert.equal( + extra.TelemetryClientId, + "f3582dee-22b9-4d73-96d1-79ef5bf2fc24", + "The TelemetryClientId matches the expected value" + ); + Assert.ok( + "TelemetryServerURL" in extra, + "The TelemetryServerURL field is present when the FHR is on" + ); + Assert.equal( + extra.TelemetryServerURL, + "http://a.telemetry.server", + "The TelemetryServerURL matches the expected value" + ); + } + ); + + await do_crash( + function () { + // Disable the FHR upload, no telemetry annotations should be present. + Services.prefs.setBoolPref( + "datareporting.policy.dataSubmissionPolicyBypassNotification", + true + ); + Services.prefs.setBoolPref( + "datareporting.healthreport.uploadEnabled", + false + ); + + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + let { TelemetrySend } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetrySend.sys.mjs" + ); + TelemetrySend.setTestModeEnabled(true); + TelemetryController.testSetup(); + }, + function (mdump, extra) { + Assert.ok( + !("TelemetryClientId" in extra), + "The TelemetryClientId field is omitted when FHR upload is disabled" + ); + Assert.ok( + !("TelemetryServerURL" in extra), + "The TelemetryServerURL field is omitted when FHR upload is disabled" + ); + } + ); + + await do_crash( + function () { + // No telemetry annotations should be present if the user has not been + // notified yet + Services.prefs.setBoolPref( + "datareporting.policy.dataSubmissionPolicyBypassNotification", + false + ); + Services.prefs.setBoolPref( + "datareporting.healthreport.uploadEnabled", + true + ); + + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + let { TelemetrySend } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetrySend.sys.mjs" + ); + TelemetrySend.setTestModeEnabled(true); + TelemetryController.testSetup(); + }, + function (mdump, extra) { + Assert.ok( + !("TelemetryClientId" in extra), + "The TelemetryClientId field is omitted when FHR upload is disabled" + ); + Assert.ok( + !("TelemetryServerURL" in extra), + "The TelemetryServerURL field is omitted when FHR upload is disabled" + ); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_event_files.js b/toolkit/crashreporter/test/unit/test_event_files.js new file mode 100644 index 0000000000..844d7700ff --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_event_files.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_setup() { + do_get_profile(); + await makeFakeAppDir(); +}); + +add_task(async function test_main_process_crash() { + let cm = Services.crashmanager; + Assert.ok(cm, "CrashManager available."); + + let basename; + let count = await new Promise((resolve, reject) => { + do_crash( + function () { + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + TelemetryController.testSetup(); + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("ShutdownProgress", "event-test"); + }, + (minidump, extra) => { + basename = minidump.leafName; + Object.defineProperty(cm, "_eventsDirs", { value: [getEventDir()] }); + cm.aggregateEventsFiles().then(resolve, reject); + }, + true + ); + }); + Assert.equal(count, 1, "A single crash event file was seen."); + let crashes = await cm.getCrashes(); + Assert.equal(crashes.length, 1); + let crash = crashes[0]; + Assert.ok( + crash.isOfType( + cm.processTypes[Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT], + cm.CRASH_TYPE_CRASH + ) + ); + Assert.equal(crash.id + ".dmp", basename, "ID recorded properly"); + Assert.equal(crash.metadata.ShutdownProgress, "event-test"); + Assert.ok("TelemetrySessionId" in crash.metadata); + Assert.ok("UptimeTS" in crash.metadata); + Assert.ok( + /^[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}$/.test( + crash.metadata.TelemetrySessionId + ) + ); + Assert.ok("CrashTime" in crash.metadata); + Assert.ok(/^\d+$/.test(crash.metadata.CrashTime)); +}); diff --git a/toolkit/crashreporter/test/unit/test_kill.js b/toolkit/crashreporter/test/unit/test_kill.js new file mode 100644 index 0000000000..3d8830bd22 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_kill.js @@ -0,0 +1,43 @@ +// Test that calling Services.processtools.kill doesn't create a crash report. +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_kill.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Let's launch a child process and kill it (from within, it's simpler). + + do_load_child_test_harness(); + + // Setting the minidump path won't work in the child, so we need to do + // that here. + Services.appinfo.minidumpPath = do_get_tempdir(); + let headfile = do_get_file("../unit/crasher_subprocess_head.js"); + const CRASH_THEN_WAIT = + "const ProcessTools = Cc['@mozilla.org/processtools-service;1'].getService(Ci.nsIProcessToolsService);\ + console.log('Child process commiting ritual self-sacrifice');\ + ProcessTools.kill(ProcessTools.pid);\ + console.error('Oops, I should be dead');\ + while (true) {} ;"; + do_get_profile(); + await makeFakeAppDir(); + await sendCommandAsync('load("' + headfile.path.replace(/\\/g, "/") + '");'); + await sendCommandAsync(CRASH_THEN_WAIT); + + // Let's wait a little to give the child process a chance to create a minidump. + let { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" + ); + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 100)); + + // Now make sure that we have no minidump. + let minidump = getMinidump(); + Assert.equal( + minidump, + null, + `There should be no minidump ${minidump == null ? "null" : minidump.path}` + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_oom_annotation.js b/toolkit/crashreporter/test/unit/test_oom_annotation.js new file mode 100644 index 0000000000..029497429a --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_oom_annotation.js @@ -0,0 +1,71 @@ +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_crash_oom.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_OOM; + crashReporter.annotateCrashReport("TestKey", "Yes"); + }, + function (mdump, extra) { + const { AppConstants } = ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" + ); + Assert.equal(extra.TestKey, "Yes"); + + // A list of pairs [annotation name, must be > 0] + let annotations; + switch (AppConstants.platform) { + case "win": + annotations = [ + ["OOMAllocationSize", true], + ["SystemMemoryUsePercentage", false], + ["TotalVirtualMemory", true], + ["AvailableVirtualMemory", false], + ["TotalPageFile", false], + ["AvailablePageFile", false], + ["TotalPhysicalMemory", true], + ["AvailablePhysicalMemory", false], + ]; + break; + case "linux": + annotations = [ + ["OOMAllocationSize", true], + ["AvailablePageFile", false], + ["AvailablePhysicalMemory", false], + ["AvailableSwapMemory", false], + ["AvailableVirtualMemory", false], + ["TotalPageFile", false], + ["TotalPhysicalMemory", true], + ]; + break; + case "macosx": + annotations = [ + ["OOMAllocationSize", true], + ["AvailablePhysicalMemory", false], + ["AvailableSwapMemory", false], + ["PurgeablePhysicalMemory", false], + ["TotalPhysicalMemory", true], + ]; + break; + default: + annotations = []; + } + for (let [label, shouldBeGreaterThanZero] of annotations) { + Assert.ok(label in extra, `Annotation ${label} is present`); + + // All these annotations should represent non-negative numbers. + // A few of them (e.g. physical memory) are guaranteed to be positive. + if (shouldBeGreaterThanZero) { + Assert.ok(Number(extra[label]) > 0); + } else { + Assert.ok(Number(extra[label]) >= 0); + } + } + } + ); +}); diff --git a/toolkit/crashreporter/test/unit/test_override_exception_handler.js b/toolkit/crashreporter/test/unit/test_override_exception_handler.js new file mode 100644 index 0000000000..1b4dec8a61 --- /dev/null +++ b/toolkit/crashreporter/test/unit/test_override_exception_handler.js @@ -0,0 +1,11 @@ +add_task(async function run_test() { + // Ensure that attempting to override the exception handler doesn't cause + // us to lose our exception handler. + await do_crash( + function () { + CrashTestUtils.TryOverrideExceptionHandler(); + }, + function (mdump, extra) {}, + true + ); +}); diff --git a/toolkit/crashreporter/test/unit/xpcshell-phc.toml b/toolkit/crashreporter/test/unit/xpcshell-phc.toml new file mode 100644 index 0000000000..278cf28193 --- /dev/null +++ b/toolkit/crashreporter/test/unit/xpcshell-phc.toml @@ -0,0 +1,12 @@ +[DEFAULT] +head = "head_crashreporter.js" +skip-if = [ + "toolkit == 'android'", # 1536217 + "os == 'win' && msix", # https://bugzilla.mozilla.org/show_bug.cgi?id=1807922 +] +support-files = [ + "crasher_subprocess_head.js", + "crasher_subprocess_tail.js", +] + +["test_crash_phc.js"] diff --git a/toolkit/crashreporter/test/unit/xpcshell.toml b/toolkit/crashreporter/test/unit/xpcshell.toml new file mode 100644 index 0000000000..ffa631d0a1 --- /dev/null +++ b/toolkit/crashreporter/test/unit/xpcshell.toml @@ -0,0 +1,152 @@ +[DEFAULT] +head = "head_crashreporter.js" +skip-if = [ + "os == 'android'", + "os == 'win' && msix", # https://bugzilla.mozilla.org/show_bug.cgi?id=1807922 +] +support-files = [ + "crasher_subprocess_head.js", + "crasher_subprocess_tail.js", +] + +["test_crash_AsyncShutdown.js"] + +["test_crash_abort.js"] +skip-if = ["os == 'win'"] + +["test_crash_after_js_large_allocation_failure.js"] + +["test_crash_after_js_large_allocation_failure_reporting.js"] + +["test_crash_after_js_oom_recovered.js"] + +["test_crash_after_js_oom_reported.js"] + +["test_crash_after_js_oom_reported_2.js"] + +["test_crash_backgroundtask_moz_crash.js"] + +["test_crash_exc_guard.js"] +run-if = ["os == 'mac'"] +reason = "Test covering macOS-specific crash type" + +["test_crash_heap_corruption.js"] +run-if = ["os == 'win'"] +reason = "Test covering Windows-specific crash type" +run-sequentially = "very high failure rate in parallel" + +["test_crash_modules.js"] +run-if = ["os == 'win'"] +reason = "Test covering Windows-specific module handling" +run-sequentially = "very high failure rate in parallel" + +["test_crash_moz_crash.js"] + +["test_crash_oom.js"] + +["test_crash_purevirtual.js"] + +["test_crash_rust_panic.js"] + +["test_crash_rust_panic_multiline.js"] + +["test_crash_stack_overflow.js"] +skip-if = ["os != 'linux'"] +reason = "Still broken on macOS and not yet supported on Windows" + +["test_crash_terminator.js"] + +["test_crash_uncaught_exception.js"] + +["test_crash_win64cfi_alloc_large.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_alloc_small.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_epilog.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_infinite_code_chain.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" +support-files = ["test_crash_win64cfi_infinite_code_chain.exe"] + +["test_crash_win64cfi_infinite_entry_chain.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" +support-files = ["test_crash_win64cfi_infinite_entry_chain.exe"] + +["test_crash_win64cfi_invalid_exception_rva.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" +support-files = ["test_crash_win64cfi_invalid_exception_rva.exe"] + +["test_crash_win64cfi_not_a_pe.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" +support-files = ["test_crash_win64cfi_not_a_pe.exe"] + +["test_crash_win64cfi_push_nonvol.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_save_nonvol.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_save_nonvol_far.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_save_xmm128.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_save_xmm128_far.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_win64cfi_unknown_op.js"] +head = "head_crashreporter.js head_win64cfi.js" +run-if = ["os == 'win' && bits == 64 && processor == 'x86_64'"] +reason = "Windows test specific to the x86-64 architecture" + +["test_crash_with_memory_report.js"] + +["test_crashreporter.js"] + +["test_crashreporter_appmem.js"] +# we need to skip this due to bug 838613 +skip-if = [ + "os != 'win' && os != 'linux'", + "os=='linux' && bits==32", +] + +["test_crashreporter_crash.js"] +run-sequentially = "very high failure rate in parallel" + +["test_event_files.js"] + +["test_kill.js"] + +["test_oom_annotation.js"] +run-sequentially = "very high failure rate in parallel" + +["test_override_exception_handler.js"] +skip-if = ["os != 'win'"] diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_annotation.js b/toolkit/crashreporter/test/unit_ipc/test_content_annotation.js new file mode 100644 index 0000000000..badc15c27d --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_annotation.js @@ -0,0 +1,33 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_annotation.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // TelemetrySession setup will trigger the session annotation + let { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" + ); + TelemetryController.testSetup(); + + // Try crashing with a runtime abort + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "TestValue"); + crashReporter.appendAppNotesToCrashReport("!!!foo!!!"); + }, + function (mdump, extra) { + Assert.equal(extra.TestKey, "TestValue"); + Assert.ok("ProcessType" in extra); + Assert.ok("StartupTime" in extra); + Assert.ok("TelemetrySessionId" in extra); + Assert.notEqual(extra.Notes.indexOf("!!!foo!!!"), -1); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_exception_time_annotation.js b/toolkit/crashreporter/test/unit_ipc/test_content_exception_time_annotation.js new file mode 100644 index 0000000000..95205a6017 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_exception_time_annotation.js @@ -0,0 +1,21 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_annotation.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with an OOM + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_OOM; + }, + function (mdump, extra) { + Assert.ok("OOMAllocationSize" in extra); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_large_annotation.js b/toolkit/crashreporter/test/unit_ipc/test_content_large_annotation.js new file mode 100644 index 0000000000..92875ccd99 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_large_annotation.js @@ -0,0 +1,25 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_large_annotation.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with a runtime abort + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_MOZ_CRASH; + crashReporter.annotateCrashReport("TestKey", "a".repeat(65536)); + }, + function (mdump, extra) { + Assert.ok( + extra.TestKey == "a".repeat(65536), + "The TestKey annotation matches the expected value" + ); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js b/toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js new file mode 100644 index 0000000000..733d224160 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_memory_list.js @@ -0,0 +1,33 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + var is_win7_or_newer = false; + var ph = Cc["@mozilla.org/network/protocol;1?name=http"].getService( + Ci.nsIHttpProtocolHandler + ); + var match = ph.userAgent.match(/Windows NT (\d+).(\d+)/); + if ( + match && + (parseInt(match[1]) > 6 || + (parseInt(match[1]) == 6 && parseInt(match[2]) >= 1)) + ) { + is_win7_or_newer = true; + } + + await do_content_crash(null, function (mdump, extra) { + Assert.ok(mdump.exists()); + Assert.ok(mdump.fileSize > 0); + if (is_win7_or_newer) { + Assert.ok( + CrashTestUtils.dumpHasStream( + mdump.path, + CrashTestUtils.MD_MEMORY_INFO_LIST_STREAM + ) + ); + } + }); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_oom_annotation.js b/toolkit/crashreporter/test/unit_ipc/test_content_oom_annotation.js new file mode 100644 index 0000000000..d17e01f5f5 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_oom_annotation.js @@ -0,0 +1,33 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_annotation.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with an OOM + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_OOM; + }, + function (mdump, extra) { + Assert.ok("TotalPhysicalMemory" in extra); + Assert.ok("AvailablePhysicalMemory" in extra); + + if (mozinfo.os == "win") { + Assert.ok("SystemMemoryUsePercentage" in extra); + Assert.ok("TotalVirtualMemory" in extra); + Assert.ok("AvailableVirtualMemory" in extra); + Assert.ok("TotalPageFile" in extra); + Assert.ok("AvailablePageFile" in extra); + } else if (mozinfo.os == "linux") { + Assert.ok("TotalPageFile" in extra); + Assert.ok("AvailablePageFile" in extra); + } + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_phc.js b/toolkit/crashreporter/test/unit_ipc/test_content_phc.js new file mode 100644 index 0000000000..1b54448135 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_phc.js @@ -0,0 +1,31 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_phc.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_USE_AFTER_FREE; + }, + function (mdump, extra) { + Assert.equal(extra.PHCKind, "FreedPage"); + + // This is a string holding a decimal address. + Assert.ok(/^\d+$/.test(extra.PHCBaseAddress)); + + // CRASH_PHC_USE_AFTER_FREE uses 32 for the size. + Assert.equal(extra.PHCUsableSize, 32); + + // These are strings holding comma-separated lists of decimal addresses. + // Sometimes on Mac they have a single entry. + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack)); + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack)); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_phc2.js b/toolkit/crashreporter/test/unit_ipc/test_content_phc2.js new file mode 100644 index 0000000000..0db9165b14 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_phc2.js @@ -0,0 +1,34 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_phc.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // For some unknown reason, having multiple do_content_crash() calls in a + // single test doesn't work. That explains why this test exists separately + // from test_content_phc.js. + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_DOUBLE_FREE; + }, + function (mdump, extra) { + Assert.equal(extra.PHCKind, "FreedPage"); + + // This is a string holding a decimal address. + Assert.ok(/^\d+$/.test(extra.PHCBaseAddress)); + + // CRASH_PHC_DOUBLE_FREE uses 64 for the size. + Assert.equal(extra.PHCUsableSize, 64); + + // These are strings holding comma-separated lists of decimal addresses. + // Sometimes on Mac they have a single entry. + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack)); + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCFreeStack)); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_phc3.js b/toolkit/crashreporter/test/unit_ipc/test_content_phc3.js new file mode 100644 index 0000000000..ab6b81f834 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_phc3.js @@ -0,0 +1,35 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_phc.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // For some unknown reason, having multiple do_content_crash() calls in a + // single test doesn't work. That explains why this test exists separately + // from test_content_phc.js. + await do_content_crash( + function () { + crashType = CrashTestUtils.CRASH_PHC_BOUNDS_VIOLATION; + }, + function (mdump, extra) { + Assert.equal(extra.PHCKind, "GuardPage"); + + // This is a string holding a decimal address. + Assert.ok(/^\d+$/.test(extra.PHCBaseAddress)); + + // CRASH_PHC_BOUNDS_VIOLATION uses 96 for the size. + Assert.equal(extra.PHCUsableSize, 96); + + // This is a string holding a comma-separated list of decimal addresses. + // Sometimes on Mac it has a single entry. + Assert.ok(/^(\d+,)*\d+$/.test(extra.PHCAllocStack)); + + Assert.ok(!extra.hasOwnProperty("PHCFreeStack")); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js new file mode 100644 index 0000000000..91b9b86bb6 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic.js @@ -0,0 +1,23 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_rust_panic.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with a Rust panic + await do_triggered_content_crash( + function () { + Cc["@mozilla.org/xpcom/debug;1"] + .getService(Ci.nsIDebug2) + .rustPanic("OH NO"); + }, + function (mdump, extra) { + Assert.equal(extra.MozCrashReason, "OH NO"); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic_multiline.js b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic_multiline.js new file mode 100644 index 0000000000..393afa42ab --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/test_content_rust_panic_multiline.js @@ -0,0 +1,23 @@ +/* import-globals-from ../unit/head_crashreporter.js */ +load("../unit/head_crashreporter.js"); + +add_task(async function run_test() { + if (!("@mozilla.org/toolkit/crash-reporter;1" in Cc)) { + dump( + "INFO | test_content_rust_panic.js | Can't test crashreporter in a non-libxul build.\n" + ); + return; + } + + // Try crashing with a Rust panic + await do_triggered_content_crash( + function () { + Cc["@mozilla.org/xpcom/debug;1"] + .getService(Ci.nsIDebug2) + .rustPanic("OH NO\nOH NOES!"); + }, + function (mdump, extra) { + Assert.equal(extra.MozCrashReason, "OH NO\nOH NOES!"); + } + ); +}); diff --git a/toolkit/crashreporter/test/unit_ipc/xpcshell-phc.toml b/toolkit/crashreporter/test/unit_ipc/xpcshell-phc.toml new file mode 100644 index 0000000000..af88f5d80c --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/xpcshell-phc.toml @@ -0,0 +1,13 @@ +[DEFAULT] +skip-if = ["os == 'android'"] # 1536217 +support-files = [ + "!/toolkit/crashreporter/test/unit/crasher_subprocess_head.js", + "!/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js", + "!/toolkit/crashreporter/test/unit/head_crashreporter.js", +] + +["test_content_phc.js"] + +["test_content_phc2.js"] + +["test_content_phc3.js"] diff --git a/toolkit/crashreporter/test/unit_ipc/xpcshell.toml b/toolkit/crashreporter/test/unit_ipc/xpcshell.toml new file mode 100644 index 0000000000..b7cdb7bc08 --- /dev/null +++ b/toolkit/crashreporter/test/unit_ipc/xpcshell.toml @@ -0,0 +1,24 @@ +[DEFAULT] +run-sequentially = "very high failure rate in parallel" +head = "" +skip-if = ["os == 'android'"] +support-files = [ + "!/toolkit/crashreporter/test/unit/crasher_subprocess_head.js", + "!/toolkit/crashreporter/test/unit/crasher_subprocess_tail.js", + "!/toolkit/crashreporter/test/unit/head_crashreporter.js", +] + +["test_content_annotation.js"] + +["test_content_exception_time_annotation.js"] + +["test_content_large_annotation.js"] + +["test_content_memory_list.js"] +skip-if = ["os != 'win'"] + +["test_content_oom_annotation.js"] + +["test_content_rust_panic.js"] + +["test_content_rust_panic_multiline.js"] diff --git a/toolkit/crashreporter/test/win64UnwindInfoTests.asm b/toolkit/crashreporter/test/win64UnwindInfoTests.asm new file mode 100644 index 0000000000..4dd5ce7646 --- /dev/null +++ b/toolkit/crashreporter/test/win64UnwindInfoTests.asm @@ -0,0 +1,378 @@ +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; Comments indicate stack memory layout during execution. +; For example at the top of a function, where RIP just points to the return +; address, the stack looks like +; rip = [ra] +; And after pushing rax to the stack, +; rip = [rax][ra] +; And then, after allocating 20h bytes on the stack, +; rip = [..20..][rax][ra] +; And then, after pushing a function pointer, +; rip = [pfn][..20..][rax][ra] + +include ksamd64.inc + +.code + +; It helps to add padding between functions so they're not right up against +; each other. Adds clarity to debugging, and gives a bit of leeway when +; searching for symbols (e.g. a function whose last instruction is CALL +; would push a return address that's in the next function.) +PaddingBetweenFunctions macro + repeat 10h + int 3 + endm +endm + +DoCrash macro + mov rax, 7 + mov byte ptr [rax], 9 +endm + +PaddingBetweenFunctions + +; There is no rip addressing mode in x64. The only way to get the value +; of rip is to call a function, and pop it from the stack. +WhoCalledMe proc + pop rax ; rax is now ra + push rax ; Restore ra so this function can return. + sub rax, 5 ; Correct for the size of the call instruction + ret +WhoCalledMe endp + +PaddingBetweenFunctions + +; Any function that we expect to test against on the stack, we'll need its +; real address. If we use function pointers in C, we'll get the address to jump +; table entries. This bit of code at the beginning of each function will +; return the real address we'd expect to see in stack traces. +; +; rcx (1st arg) = mode +; rax (return) = address of either NO_MANS_LAND or this function. +; +; When mode is 0, we place the address of NO_MANS_LAND in RAX, for the function +; to use as it wants. This is just for convenience because almost all functions +; here need this address at some point. +; +; When mode is 1, the address of this function is returned. +TestHeader macro + call WhoCalledMe + test rcx, rcx + je continue_test + ret +continue_test: + inc rcx + call x64CrashCFITest_NO_MANS_LAND + xor rcx, rcx +endm + +; The point of this is to add a stack frame to test against. +; void* x64CrashCFITest_Launcher(int getAddress, void* pTestFn) +x64CrashCFITest_Launcher proc frame + TestHeader + + .endprolog + call rdx + ret +x64CrashCFITest_Launcher endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_NO_MANS_LAND(uint64_t mode); +; Not meant to be called. Only when mode = 1 in order to return its address. +; Place this function's address on the stack so the stack scanning algorithm +; thinks this is a return address, and places it on the stack trace. +x64CrashCFITest_NO_MANS_LAND proc frame + TestHeader + .endprolog + ret +x64CrashCFITest_NO_MANS_LAND endp + +PaddingBetweenFunctions + +; Test that we: +; - handle unknown opcodes gracefully +; - fall back to other stack unwind strategies if CFI doesn't work +; +; In order to properly unwind this frame, we'd need to fully support +; SET_FPREG with offsets, plus restoring registers via PUSH_NONVOL. +; To do this, sprinkle the stack with bad return addresses +; and stack pointers. +x64CrashCFITest_UnknownOpcode proc frame + TestHeader + + push rax + .allocstack 8 + + push rbp + .pushreg rbp + + push rax + push rsp + push rax + push rsp + .allocstack 20h + ; rsp = [rsp][pfn][rsp][pfn][rbp][pfn][ra] + + lea rbp, [rsp+10h] + .setframe rbp, 10h + ; rsp = [rsp][pfn] [rsp][pfn][rbp][pfn][ra] + ; rbp = ^ + + .endprolog + + ; Now modify RSP so measuring stack size from unwind ops will not help + ; finding the return address. + push rax + push rsp + ; rsp = [rsp][pfn][rsp][pfn] [rsp][pfn][rbp][pfn][ra] + + DoCrash + +x64CrashCFITest_UnknownOpcode endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_PUSH_NONVOL(uint64_t mode); +; +; Test correct handling of PUSH_NONVOL unwind code. +; +x64CrashCFITest_PUSH_NONVOL proc frame + TestHeader + + push r10 + .pushreg r10 + push r15 + .pushreg r15 + push rbx + .pushreg rbx + push rsi + .pushreg rsi + push rbp + .pushreg rbp + ; rsp = [rbp][rsi][rbx][r15][r10][ra] + + push rax + .allocstack 8 + ; rsp = [pfn][rbp][rsi][rbx][r15][r10][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_PUSH_NONVOL endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_ALLOC_SMALL(uint64_t mode); +; +; Small allocations are between 8bytes and 512kb-8bytes +; +x64CrashCFITest_ALLOC_SMALL proc frame + TestHeader + + push rax + push rax + push rax + push rax + .allocstack 20h + ; rsp = [pfn][pfn][pfn][pfn][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_ALLOC_SMALL endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_ALLOC_LARGE(uint64_t mode); +; +; Allocations between 512kb and 4gb +; Note: ReserveStackSpace() in nsTestCrasher.cpp pre-allocates stack +; space for this. +x64CrashCFITest_ALLOC_LARGE proc frame + TestHeader + + sub rsp, 0a000h + .allocstack 0a000h + ; rsp = [..640kb..][ra] + + mov qword ptr [rsp], rax + ; rsp = [pfn][..640kb-8..][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_ALLOC_LARGE endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_SAVE_NONVOL(uint64_t mode); +; +; Test correct handling of SAVE_NONVOL unwind code. +; +x64CrashCFITest_SAVE_NONVOL proc frame + TestHeader + + sub rsp, 30h + .allocstack 30h + ; rsp = [..30..][ra] + + mov qword ptr [rsp+28h], r10 + .savereg r10, 28h + mov qword ptr [rsp+20h], rbp + .savereg rbp, 20h + mov qword ptr [rsp+18h], rsi + .savereg rsi, 18h + mov qword ptr [rsp+10h], rbx + .savereg rbx, 10h + mov qword ptr [rsp+8], r15 + .savereg r15, 8 + ; rsp = [r15][rbx][rsi][rbp][r10][ra] + + mov qword ptr [rsp], rax + + ; rsp = [pfn][r15][rbx][rsi][rbp][r10][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_SAVE_NONVOL endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_SAVE_NONVOL_FAR(uint64_t mode); +; +; Similar to the test above but adding 640kb to most offsets. +; Note: ReserveStackSpace() in nsTestCrasher.cpp pre-allocates stack +; space for this. +x64CrashCFITest_SAVE_NONVOL_FAR proc frame + TestHeader + + sub rsp, 0a0030h + .allocstack 0a0030h + ; rsp = [..640k..][..30..][ra] + + mov qword ptr [rsp+28h+0a0000h], r10 + .savereg r10, 28h+0a0000h + mov qword ptr [rsp+20h+0a0000h], rbp + .savereg rbp, 20h+0a0000h + mov qword ptr [rsp+18h+0a0000h], rsi + .savereg rsi, 18h+0a0000h + mov qword ptr [rsp+10h+0a0000h], rbx + .savereg rbx, 10h+0a0000h + mov qword ptr [rsp+8+0a0000h], r15 + .savereg r15, 8+0a0000h + ; rsp = [..640k..][..8..][r15][rbx][rsi][rbp][r10][ra] + + mov qword ptr [rsp], rax + + ; rsp = [pfn][..640k..][r15][rbx][rsi][rbp][r10][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_SAVE_NONVOL_FAR endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_SAVE_XMM128(uint64_t mode); +; +; Test correct handling of SAVE_XMM128 unwind code. +x64CrashCFITest_SAVE_XMM128 proc frame + TestHeader + + sub rsp, 30h + .allocstack 30h + ; rsp = [..30..][ra] + + movdqu [rsp+20h], xmm6 + .savexmm128 xmm6, 20h + ; rsp = [..20..][xmm6][ra] + + movdqu [rsp+10h], xmm15 + .savexmm128 xmm15, 10h + ; rsp = [..10..][xmm15][xmm6][ra] + + mov qword ptr [rsp], rax + ; rsp = [pfn][..8..][xmm15][xmm6][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_SAVE_XMM128 endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_SAVE_XMM128(uint64_t mode); +; +; Similar to the test above but adding 640kb to most offsets. +; Note: ReserveStackSpace() in nsTestCrasher.cpp pre-allocates stack +; space for this. +x64CrashCFITest_SAVE_XMM128_FAR proc frame + TestHeader + + sub rsp, 0a0030h + .allocstack 0a0030h + ; rsp = [..640kb..][..30..][ra] + + movdqu [rsp+20h+0a0000h], xmm6 + .savexmm128 xmm6, 20h+0a0000h + ; rsp = [..640kb..][..20..][xmm6][ra] + + movdqu [rsp+10h+0a0000h], xmm6 + .savexmm128 xmm15, 10h+0a0000h + ; rsp = [..640kb..][..10..][xmm15][xmm6][ra] + + mov qword ptr [rsp], rax + ; rsp = [pfn][..640kb..][..8..][xmm15][xmm6][ra] + + .endprolog + + DoCrash + +x64CrashCFITest_SAVE_XMM128_FAR endp + +PaddingBetweenFunctions + +; void* x64CrashCFITest_EPILOG(uint64_t mode); +; +; The epilog unwind op will also set the unwind version to 2. +; Test that we don't choke on UWOP_EPILOG or version 2 unwind info. +x64CrashCFITest_EPILOG proc frame + TestHeader + + push rax + .allocstack 8 + ; rsp = [pfn][ra] + + .endprolog + + DoCrash + + .beginepilog + + ret + +x64CrashCFITest_EPILOG endp + +PaddingBetweenFunctions + +; Having an EOF symbol at the end of this file contains symbolication to this +; file. So addresses beyond this file don't get mistakenly symbolicated as a +; meaningful function name. +x64CrashCFITest_EOF proc frame + TestHeader + .endprolog + ret +x64CrashCFITest_EOF endp + +end diff --git a/toolkit/crashreporter/tools/python.toml b/toolkit/crashreporter/tools/python.toml new file mode 100644 index 0000000000..778905df37 --- /dev/null +++ b/toolkit/crashreporter/tools/python.toml @@ -0,0 +1,3 @@ +[DEFAULT] + +["unit-symbolstore.py"] diff --git a/toolkit/crashreporter/tools/symbolstore.py b/toolkit/crashreporter/tools/symbolstore.py new file mode 100755 index 0000000000..bc16002503 --- /dev/null +++ b/toolkit/crashreporter/tools/symbolstore.py @@ -0,0 +1,1095 @@ +#!/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# Usage: symbolstore.py +# +# Runs dump_syms on each debug info file specified on the command line, +# then places the resulting symbol file in the proper directory +# structure in the symbol store path. Accepts multiple files +# on the command line, so can be called as part of a pipe using +# find | xargs symbolstore.pl +# But really, you might just want to pass it . +# +# Parameters accepted: +# -c : Copy debug info files to the same directory structure +# as sym files. On Windows, this will also copy +# binaries into the symbol store. +# -a "" : Run dump_syms -a for each space separated +# cpu architecture in (only on OS X) +# -s : Use as the top source directory to +# generate relative filenames. + +import ctypes +import errno +import os +import platform +import re +import shutil +import subprocess +import sys +import textwrap +import time +from optparse import OptionParser +from pathlib import Path + +import buildconfig +from mozbuild.generated_sources import ( + GENERATED_SOURCE_EXTS, + get_filename_with_digest, + get_s3_region_and_bucket, +) +from mozbuild.util import memoize +from mozpack import executables +from mozpack.copier import FileRegistry +from mozpack.manifests import InstallManifest, UnreadableInstallManifest + +# Utility classes + + +class VCSFileInfo: + """A base class for version-controlled file information. Ensures that the + following attributes are generated only once (successfully): + + self.root + self.clean_root + self.revision + self.filename + + The attributes are generated by a single call to the GetRoot, + GetRevision, and GetFilename methods. Those methods are explicitly not + implemented here and must be implemented in derived classes.""" + + def __init__(self, file): + if not file: + raise ValueError + self.file = file + + def __getattr__(self, name): + """__getattr__ is only called for attributes that are not set on self, + so setting self.[attr] will prevent future calls to the GetRoot, + GetRevision, and GetFilename methods. We don't set the values on + failure on the off chance that a future call might succeed.""" + + if name == "root": + root = self.GetRoot() + if root: + self.root = root + return root + + elif name == "clean_root": + clean_root = self.GetCleanRoot() + if clean_root: + self.clean_root = clean_root + return clean_root + + elif name == "revision": + revision = self.GetRevision() + if revision: + self.revision = revision + return revision + + elif name == "filename": + filename = self.GetFilename() + if filename: + self.filename = filename + return filename + + raise AttributeError + + def GetRoot(self): + """This method should return the unmodified root for the file or 'None' + on failure.""" + raise NotImplementedError + + def GetCleanRoot(self): + """This method should return the repository root for the file or 'None' + on failure.""" + raise NotImplementedError + + def GetRevision(self): + """This method should return the revision number for the file or 'None' + on failure.""" + raise NotImplementedError + + def GetFilename(self): + """This method should return the repository-specific filename for the + file or 'None' on failure.""" + raise NotImplementedError + + +# This regex separates protocol and optional username/password from a url. +# For instance, all the following urls will be transformed into +# 'foo.com/bar': +# +# http://foo.com/bar +# svn+ssh://user@foo.com/bar +# svn+ssh://user:pass@foo.com/bar +# +rootRegex = re.compile(r"^\S+?:/+(?:[^\s/]*@)?(\S+)$") + + +def read_output(*args): + (stdout, _) = subprocess.Popen( + args=args, universal_newlines=True, stdout=subprocess.PIPE + ).communicate() + return stdout.rstrip() + + +class HGRepoInfo: + def __init__(self, path): + self.path = path + + rev = os.environ.get("MOZ_SOURCE_CHANGESET") + if not rev: + rev = read_output("hg", "-R", path, "parent", "--template={node}") + + # Look for the default hg path. If MOZ_SOURCE_REPO is set, we + # don't bother asking hg. + hg_root = os.environ.get("MOZ_SOURCE_REPO") + if hg_root: + root = hg_root + else: + root = read_output("hg", "-R", path, "showconfig", "paths.default") + if not root: + print("Failed to get HG Repo for %s" % path, file=sys.stderr) + cleanroot = None + if root: + match = rootRegex.match(root) + if match: + cleanroot = match.group(1) + if cleanroot.endswith("/"): + cleanroot = cleanroot[:-1] + if cleanroot is None: + print( + textwrap.dedent( + """\ + Could not determine repo info for %s. This is either not a clone of the web-based + repository, or you have not specified MOZ_SOURCE_REPO, or the clone is corrupt.""" + ) + % path, + sys.stderr, + ) + sys.exit(1) + self.rev = rev + self.root = root + self.cleanroot = cleanroot + + def GetFileInfo(self, file): + return HGFileInfo(file, self) + + +class HGFileInfo(VCSFileInfo): + def __init__(self, file, repo): + VCSFileInfo.__init__(self, file) + self.repo = repo + self.file = os.path.relpath(file, repo.path) + + def GetRoot(self): + return self.repo.root + + def GetCleanRoot(self): + return self.repo.cleanroot + + def GetRevision(self): + return self.repo.rev + + def GetFilename(self): + if self.revision and self.clean_root: + return "hg:%s:%s:%s" % (self.clean_root, self.file, self.revision) + return self.file + + +class GitRepoInfo: + """ + Info about a local git repository. Does not currently + support discovering info about a git clone, the info must be + provided out-of-band. + """ + + def __init__(self, path, rev, root): + self.path = path + cleanroot = None + if root: + match = rootRegex.match(root) + if match: + cleanroot = match.group(1) + if cleanroot.endswith("/"): + cleanroot = cleanroot[:-1] + if cleanroot is None: + print( + textwrap.dedent( + """\ + Could not determine repo info for %s (%s). This is either not a clone of a web-based + repository, or you have not specified MOZ_SOURCE_REPO, or the clone is corrupt.""" + ) + % (path, root), + file=sys.stderr, + ) + sys.exit(1) + self.rev = rev + self.cleanroot = cleanroot + + def GetFileInfo(self, file): + return GitFileInfo(file, self) + + +class GitFileInfo(VCSFileInfo): + def __init__(self, file, repo): + VCSFileInfo.__init__(self, file) + self.repo = repo + self.file = os.path.relpath(file, repo.path) + + def GetRoot(self): + return self.repo.path + + def GetCleanRoot(self): + return self.repo.cleanroot + + def GetRevision(self): + return self.repo.rev + + def GetFilename(self): + if self.revision and self.clean_root: + return "git:%s:%s:%s" % (self.clean_root, self.file, self.revision) + return self.file + + +# Utility functions + + +# A cache of files for which VCS info has already been determined. Used to +# prevent extra filesystem activity or process launching. +vcsFileInfoCache = {} + +if platform.system() == "Windows": + + def realpath(path): + """ + Normalize a path using `GetFinalPathNameByHandleW` to get the + path with all components in the case they exist in on-disk, so + that making links to a case-sensitive server (hg.mozilla.org) works. + + This function also resolves any symlinks in the path. + """ + # Return the original path if something fails, which can happen for paths that + # don't exist on this system (like paths from the CRT). + result = path + + ctypes.windll.kernel32.SetErrorMode(ctypes.c_uint(1)) + handle = ctypes.windll.kernel32.CreateFileW( + path, + # GENERIC_READ + 0x80000000, + # FILE_SHARE_READ + 1, + None, + # OPEN_EXISTING + 3, + # FILE_FLAG_BACKUP_SEMANTICS + # This is necessary to open + # directory handles. + 0x02000000, + None, + ) + if handle != -1: + size = ctypes.windll.kernel32.GetFinalPathNameByHandleW(handle, None, 0, 0) + buf = ctypes.create_unicode_buffer(size) + if ( + ctypes.windll.kernel32.GetFinalPathNameByHandleW(handle, buf, size, 0) + > 0 + ): + # The return value of GetFinalPathNameByHandleW uses the + # '\\?\' prefix. + result = buf.value[4:] + ctypes.windll.kernel32.CloseHandle(handle) + return result + +else: + # Just use the os.path version otherwise. + realpath = os.path.realpath + + +def IsInDir(file, dir): + try: + Path(file).relative_to(dir) + return True + except ValueError: + return False + + +def GetVCSFilenameFromSrcdir(file, srcdir): + if srcdir not in Dumper.srcdirRepoInfo: + # Not in cache, so find it adnd cache it + if os.path.isdir(os.path.join(srcdir, ".hg")): + Dumper.srcdirRepoInfo[srcdir] = HGRepoInfo(srcdir) + else: + # Unknown VCS or file is not in a repo. + return None + return Dumper.srcdirRepoInfo[srcdir].GetFileInfo(file) + + +def GetVCSFilename(file, srcdirs): + """Given a full path to a file, and the top source directory, + look for version control information about this file, and return + a tuple containing + 1) a specially formatted filename that contains the VCS type, + VCS location, relative filename, and revision number, formatted like: + vcs:vcs location:filename:revision + For example: + cvs:cvs.mozilla.org/cvsroot:mozilla/browser/app/nsBrowserApp.cpp:1.36 + 2) the unmodified root information if it exists""" + (path, filename) = os.path.split(file) + if path == "" or filename == "": + return (file, None) + + fileInfo = None + root = "" + if file in vcsFileInfoCache: + # Already cached this info, use it. + fileInfo = vcsFileInfoCache[file] + else: + for srcdir in srcdirs: + if not IsInDir(file, srcdir): + continue + fileInfo = GetVCSFilenameFromSrcdir(file, srcdir) + if fileInfo: + vcsFileInfoCache[file] = fileInfo + break + + if fileInfo: + file = fileInfo.filename + root = fileInfo.root + + # we want forward slashes on win32 paths + return (file.replace("\\", "/"), root) + + +def validate_install_manifests(install_manifest_args): + args = [] + for arg in install_manifest_args: + bits = arg.split(",") + if len(bits) != 2: + raise ValueError( + "Invalid format for --install-manifest: " "specify manifest,target_dir" + ) + manifest_file, destination = [os.path.abspath(b) for b in bits] + if not os.path.isfile(manifest_file): + raise IOError(errno.ENOENT, "Manifest file not found", manifest_file) + if not os.path.isdir(destination): + raise IOError(errno.ENOENT, "Install directory not found", destination) + try: + manifest = InstallManifest(manifest_file) + except UnreadableInstallManifest: + raise IOError(errno.EINVAL, "Error parsing manifest file", manifest_file) + args.append((manifest, destination)) + return args + + +def make_file_mapping(install_manifests): + file_mapping = {} + for manifest, destination in install_manifests: + destination = os.path.abspath(destination) + reg = FileRegistry() + manifest.populate_registry(reg) + for dst, src in reg: + if hasattr(src, "path"): + # Any paths that get compared to source file names need to go through realpath. + abs_dest = realpath(os.path.join(destination, dst)) + file_mapping[abs_dest] = realpath(src.path) + return file_mapping + + +@memoize +def get_generated_file_s3_path(filename, rel_path, bucket): + """Given a filename, return a path formatted similarly to + GetVCSFilename but representing a file available in an s3 bucket.""" + with open(filename, "rb") as f: + path = get_filename_with_digest(rel_path, f.read()) + return "s3:{bucket}:{path}:".format(bucket=bucket, path=path) + + +def GetPlatformSpecificDumper(**kwargs): + """This function simply returns a instance of a subclass of Dumper + that is appropriate for the current platform.""" + return {"WINNT": Dumper_Win32, "Linux": Dumper_Linux, "Darwin": Dumper_Mac}[ + buildconfig.substs["OS_ARCH"] + ](**kwargs) + + +def SourceIndex(fileStream, outputPath, vcs_root, s3_bucket): + """Takes a list of files, writes info to a data block in a .stream file""" + # Creates a .pdb.stream file in the mozilla\objdir to be used for source indexing + # Create the srcsrv data block that indexes the pdb file + result = True + pdbStreamFile = open(outputPath, "w") + pdbStreamFile.write( + "SRCSRV: ini ------------------------------------------------\r\n" + + "VERSION=2\r\n" + + "INDEXVERSION=2\r\n" + + "VERCTRL=http\r\n" + + "SRCSRV: variables ------------------------------------------\r\n" + + "SRCSRVVERCTRL=http\r\n" + + "RUST_GITHUB_TARGET=https://github.com/rust-lang/rust/raw/%var4%/%var3%\r\n" + ) + pdbStreamFile.write("HGSERVER=" + vcs_root + "\r\n") + pdbStreamFile.write("HG_TARGET=%hgserver%/raw-file/%var4%/%var3%\r\n") + + if s3_bucket: + pdbStreamFile.write("S3_BUCKET=" + s3_bucket + "\r\n") + pdbStreamFile.write("S3_TARGET=https://%s3_bucket%.s3.amazonaws.com/%var3%\r\n") + + # Allow each entry to choose its template via "var2". + # Possible values for var2 are: HG_TARGET / S3_TARGET / RUST_GITHUB_TARGET + pdbStreamFile.write("SRCSRVTRG=%fnvar%(%var2%)\r\n") + + pdbStreamFile.write( + "SRCSRV: source files ---------------------------------------\r\n" + ) + pdbStreamFile.write(fileStream) + pdbStreamFile.write( + "SRCSRV: end ------------------------------------------------\r\n\n" + ) + pdbStreamFile.close() + return result + + +class Dumper: + """This class can dump symbols from a file with debug info, and + store the output in a directory structure that is valid for use as + a Breakpad symbol server. Requires a path to a dump_syms binary-- + |dump_syms| and a directory to store symbols in--|symbol_path|. + Optionally takes a list of processor architectures to process from + each debug file--|archs|, the full path to the top source + directory--|srcdir|, for generating relative source file names, + and an option to copy debug info files alongside the dumped + symbol files--|copy_debug|, mostly useful for creating a + Microsoft Symbol Server from the resulting output. + + You don't want to use this directly if you intend to process files. + Instead, call GetPlatformSpecificDumper to get an instance of a + subclass.""" + + srcdirRepoInfo = {} + + def __init__( + self, + dump_syms, + symbol_path, + archs=None, + srcdirs=[], + copy_debug=False, + vcsinfo=False, + srcsrv=False, + s3_bucket=None, + file_mapping=None, + ): + # popen likes absolute paths, at least on windows + self.dump_syms = os.path.abspath(dump_syms) + self.symbol_path = symbol_path + if archs is None: + # makes the loop logic simpler + self.archs = [""] + else: + self.archs = ["-a %s" % a for a in archs.split()] + # Any paths that get compared to source file names need to go through realpath. + self.srcdirs = [realpath(s) for s in srcdirs] + self.copy_debug = copy_debug + self.vcsinfo = vcsinfo + self.srcsrv = srcsrv + self.s3_bucket = s3_bucket + self.file_mapping = file_mapping or {} + # Add a static mapping for Rust sources. Since Rust 1.30 official Rust builds map + # source paths to start with "/rust//". + rust_sha = buildconfig.substs["RUSTC_COMMIT"] + rust_srcdir = "/rustc/" + rust_sha + self.srcdirs.append(rust_srcdir) + Dumper.srcdirRepoInfo[rust_srcdir] = GitRepoInfo( + rust_srcdir, rust_sha, "https://github.com/rust-lang/rust/" + ) + + # subclasses override this + def ShouldProcess(self, file): + return True + + # This is a no-op except on Win32 + def SourceServerIndexing( + self, debug_file, guid, sourceFileStream, vcs_root, s3_bucket + ): + return "" + + # subclasses override this if they want to support this + def CopyExeAndDebugInfo(self, file, debug_file, guid, code_file, code_id): + """This function will copy a library or executable and the file holding the + debug information to |symbol_path|""" + pass + + def Process(self, file_to_process, count_ctors=False): + """Process the given file.""" + if self.ShouldProcess(os.path.abspath(file_to_process)): + self.ProcessFile(file_to_process, count_ctors=count_ctors) + + def ProcessFile(self, file, dsymbundle=None, count_ctors=False): + """Dump symbols from these files into a symbol file, stored + in the proper directory structure in |symbol_path|; processing is performed + asynchronously, and Finish must be called to wait for it complete and cleanup. + All files after the first are fallbacks in case the first file does not process + successfully; if it does, no other files will be touched.""" + print("Beginning work for file: %s" % file, file=sys.stderr) + + # tries to get the vcs root from the .mozconfig first - if it's not set + # the tinderbox vcs path will be assigned further down + vcs_root = os.environ.get("MOZ_SOURCE_REPO") + for arch_num, arch in enumerate(self.archs): + self.ProcessFileWork( + file, arch_num, arch, vcs_root, dsymbundle, count_ctors=count_ctors + ) + + def dump_syms_cmdline(self, file, arch, dsymbundle=None): + """ + Get the commandline used to invoke dump_syms. + """ + # The Mac dumper overrides this. + return [self.dump_syms, "--inlines", file] + + def ProcessFileWork( + self, file, arch_num, arch, vcs_root, dsymbundle=None, count_ctors=False + ): + ctors = 0 + t_start = time.time() + print("Processing file: %s" % file, file=sys.stderr) + + sourceFileStream = "" + code_id, code_file = None, None + try: + cmd = self.dump_syms_cmdline(file, arch, dsymbundle=dsymbundle) + print(" ".join(cmd), file=sys.stderr) + proc = subprocess.Popen( + cmd, + universal_newlines=True, + stdout=subprocess.PIPE, + ) + try: + module_line = next(proc.stdout) + except StopIteration: + module_line = "" + if module_line.startswith("MODULE"): + # MODULE os cpu guid debug_file + (guid, debug_file) = (module_line.split())[3:5] + # strip off .pdb extensions, and append .sym + sym_file = re.sub("\.pdb$", "", debug_file) + ".sym" + # we do want forward slashes here + rel_path = os.path.join(debug_file, guid, sym_file).replace("\\", "/") + full_path = os.path.normpath(os.path.join(self.symbol_path, rel_path)) + try: + os.makedirs(os.path.dirname(full_path)) + except OSError: # already exists + pass + f = open(full_path, "w") + f.write(module_line) + # now process the rest of the output + for line in proc.stdout: + if line.startswith("FILE"): + # FILE index filename + (x, index, filename) = line.rstrip().split(None, 2) + # We want original file paths for the source server. + sourcepath = filename + filename = realpath(filename) + if filename in self.file_mapping: + filename = self.file_mapping[filename] + if self.vcsinfo: + try: + gen_path = Path(filename) + rel_gen_path = gen_path.relative_to( + buildconfig.topobjdir + ) + except ValueError: + gen_path = None + if ( + gen_path + and gen_path.exists() + and gen_path.suffix in GENERATED_SOURCE_EXTS + and self.s3_bucket + ): + filename = get_generated_file_s3_path( + filename, str(rel_gen_path), self.s3_bucket + ) + rootname = "" + else: + (filename, rootname) = GetVCSFilename( + filename, self.srcdirs + ) + # sets vcs_root in case the loop through files were to end + # on an empty rootname + if vcs_root is None: + if rootname: + vcs_root = rootname + # Emit an entry for the file mapping for the srcsrv stream + if filename.startswith("hg:"): + (vcs, repo, source_file, revision) = filename.split(":", 3) + sourceFileStream += sourcepath + "*HG_TARGET*" + source_file + sourceFileStream += "*" + revision + "\r\n" + elif filename.startswith("s3:"): + (vcs, bucket, source_file, nothing) = filename.split(":", 3) + sourceFileStream += sourcepath + "*S3_TARGET*" + sourceFileStream += source_file + "\r\n" + elif filename.startswith("git:github.com/rust-lang/rust:"): + (vcs, repo, source_file, revision) = filename.split(":", 3) + sourceFileStream += sourcepath + "*RUST_GITHUB_TARGET*" + sourceFileStream += source_file + "*" + revision + "\r\n" + f.write("FILE %s %s\n" % (index, filename)) + elif line.startswith("INFO CODE_ID "): + # INFO CODE_ID code_id code_file + # This gives some info we can use to + # store binaries in the symbol store. + bits = line.rstrip().split(None, 3) + if len(bits) == 4: + code_id, code_file = bits[2:] + f.write(line) + else: + if count_ctors and line.startswith("FUNC "): + # Static initializers, as created by clang and gcc + # have symbols that start with "_GLOBAL_sub" + if "_GLOBAL__sub_" in line: + ctors += 1 + # MSVC creates `dynamic initializer for '...'` + # symbols. + elif "`dynamic initializer for '" in line: + ctors += 1 + + # pass through all other lines unchanged + f.write(line) + f.close() + retcode = proc.wait() + if retcode != 0: + raise RuntimeError( + "dump_syms failed with error code %d while processing %s\n" + % (retcode, file) + ) + # we output relative paths so callers can get a list of what + # was generated + print(rel_path) + if self.srcsrv and vcs_root: + # add source server indexing to the pdb file + self.SourceServerIndexing( + debug_file, guid, sourceFileStream, vcs_root, self.s3_bucket + ) + # only copy debug the first time if we have multiple architectures + if self.copy_debug and arch_num == 0: + self.CopyExeAndDebugInfo(file, debug_file, guid, code_file, code_id) + else: + # For some reason, we didn't see the MODULE line as the first + # line of output, this is strictly required so fail irrespective + # of the process' return code. + retcode = proc.wait() + message = [ + "dump_syms failed to produce the expected output", + "file: %s" % file, + "return code: %d" % retcode, + "first line of output: %s" % module_line, + ] + raise RuntimeError("\n----------\n".join(message)) + except Exception as e: + print("Unexpected error: %s" % str(e), file=sys.stderr) + raise + + if dsymbundle: + shutil.rmtree(dsymbundle) + + if count_ctors: + import json + + perfherder_data = { + "framework": {"name": "build_metrics"}, + "suites": [ + { + "name": "compiler_metrics", + "subtests": [ + { + "name": "num_static_constructors", + "value": ctors, + "alertChangeType": "absolute", + "alertThreshold": 3, + } + ], + } + ], + } + perfherder_extra_options = os.environ.get("PERFHERDER_EXTRA_OPTIONS", "") + for opt in perfherder_extra_options.split(): + for suite in perfherder_data["suites"]: + if opt not in suite.get("extraOptions", []): + suite.setdefault("extraOptions", []).append(opt) + + if "asan" not in perfherder_extra_options.lower(): + print( + "PERFHERDER_DATA: %s" % json.dumps(perfherder_data), file=sys.stderr + ) + + elapsed = time.time() - t_start + print("Finished processing %s in %.2fs" % (file, elapsed), file=sys.stderr) + + +# Platform-specific subclasses. For the most part, these just have +# logic to determine what files to extract symbols from. + + +def locate_pdb(path): + """Given a path to a binary, attempt to locate the matching pdb file with simple heuristics: + * Look for a pdb file with the same base name next to the binary + * Look for a pdb file with the same base name in the cwd + + Returns the path to the pdb file if it exists, or None if it could not be located. + """ + path, ext = os.path.splitext(path) + pdb = path + ".pdb" + if os.path.isfile(pdb): + return pdb + # If there's no pdb next to the file, see if there's a pdb with the same root name + # in the cwd. We build some binaries directly into dist/bin, but put the pdb files + # in the relative objdir, which is the cwd when running this script. + base = os.path.basename(pdb) + pdb = os.path.join(os.getcwd(), base) + if os.path.isfile(pdb): + return pdb + return None + + +class Dumper_Win32(Dumper): + fixedFilenameCaseCache = {} + + def ShouldProcess(self, file): + """This function will allow processing of exe or dll files that have pdb + files with the same base name next to them.""" + if file.endswith(".exe") or file.endswith(".dll"): + if locate_pdb(file) is not None: + return True + return False + + def CopyExeAndDebugInfo(self, file, debug_file, guid, code_file, code_id): + """This function will copy the executable or dll and pdb files to |symbol_path|""" + pdb_file = locate_pdb(file) + + rel_path = os.path.join(debug_file, guid, debug_file).replace("\\", "/") + full_path = os.path.normpath(os.path.join(self.symbol_path, rel_path)) + shutil.copyfile(pdb_file, full_path) + print(rel_path) + + # Copy the binary file as well + if code_file and code_id: + full_code_path = os.path.join(os.path.dirname(file), code_file) + if os.path.exists(full_code_path): + rel_path = os.path.join(code_file, code_id, code_file).replace( + "\\", "/" + ) + full_path = os.path.normpath(os.path.join(self.symbol_path, rel_path)) + try: + os.makedirs(os.path.dirname(full_path)) + except OSError as e: + if e.errno != errno.EEXIST: + raise + shutil.copyfile(full_code_path, full_path) + print(rel_path) + + def SourceServerIndexing( + self, debug_file, guid, sourceFileStream, vcs_root, s3_bucket + ): + # Creates a .pdb.stream file in the mozilla\objdir to be used for source indexing + streamFilename = debug_file + ".stream" + stream_output_path = os.path.abspath(streamFilename) + # Call SourceIndex to create the .stream file + result = SourceIndex(sourceFileStream, stream_output_path, vcs_root, s3_bucket) + if self.copy_debug: + pdbstr = buildconfig.substs["PDBSTR"] + wine = buildconfig.substs.get("WINE") + if wine: + cmd = [wine, pdbstr] + else: + cmd = [pdbstr] + subprocess.call( + cmd + + [ + "-w", + "-p:" + os.path.basename(debug_file), + "-i:" + os.path.basename(streamFilename), + "-s:srcsrv", + ], + cwd=os.path.dirname(stream_output_path), + ) + # clean up all the .stream files when done + os.remove(stream_output_path) + return result + + +class Dumper_Linux(Dumper): + objcopy = os.environ["OBJCOPY"] if "OBJCOPY" in os.environ else "objcopy" + + def ShouldProcess(self, file): + """This function will allow processing of files that are + executable, or end with the .so extension, and additionally + file(1) reports as being ELF files. It expects to find the file + command in PATH.""" + if file.endswith(".so") or os.access(file, os.X_OK): + return executables.get_type(file) == executables.ELF + return False + + def CopyExeAndDebugInfo(self, file, debug_file, guid, code_file, code_id): + # We want to strip out the debug info, and add a + # .gnu_debuglink section to the object, so the debugger can + # actually load our debug info later. + # In some odd cases, the object might already have an irrelevant + # .gnu_debuglink section, and objcopy doesn't want to add one in + # such cases, so we make it remove it any existing one first. + file_dbg = file + ".dbg" + if ( + subprocess.call([self.objcopy, "--only-keep-debug", file, file_dbg]) == 0 + and subprocess.call( + [ + self.objcopy, + "--remove-section", + ".gnu_debuglink", + "--add-gnu-debuglink=%s" % file_dbg, + file, + ] + ) + == 0 + ): + rel_path = os.path.join(debug_file, guid, debug_file + ".dbg") + full_path = os.path.normpath(os.path.join(self.symbol_path, rel_path)) + shutil.move(file_dbg, full_path) + print(rel_path) + else: + if os.path.isfile(file_dbg): + os.unlink(file_dbg) + + +class Dumper_Solaris(Dumper): + def ShouldProcess(self, file): + """This function will allow processing of files that are + executable, or end with the .so extension, and additionally + file(1) reports as being ELF files. It expects to find the file + command in PATH.""" + if file.endswith(".so") or os.access(file, os.X_OK): + return executables.get_type(file) == executables.ELF + return False + + +class Dumper_Mac(Dumper): + def ShouldProcess(self, file): + """This function will allow processing of files that are + executable, or end with the .dylib extension, and additionally + file(1) reports as being Mach-O files. It expects to find the file + command in PATH.""" + if file.endswith(".dylib") or os.access(file, os.X_OK): + return executables.get_type(file) == executables.MACHO + return False + + def ProcessFile(self, file, count_ctors=False): + print("Starting Mac pre-processing on file: %s" % file, file=sys.stderr) + dsymbundle = self.GenerateDSYM(file) + if dsymbundle: + # kick off new jobs per-arch with our new list of files + Dumper.ProcessFile( + self, file, dsymbundle=dsymbundle, count_ctors=count_ctors + ) + + def dump_syms_cmdline(self, file, arch, dsymbundle=None): + """ + Get the commandline used to invoke dump_syms. + """ + # dump_syms wants the path to the original binary and the .dSYM + # in order to dump all the symbols. + if dsymbundle: + # This is the .dSYM bundle. + return ( + [self.dump_syms] + + arch.split() + + ["--inlines", "-j", "2", dsymbundle, file] + ) + return Dumper.dump_syms_cmdline(self, file, arch) + + def GenerateDSYM(self, file): + """dump_syms on Mac needs to be run on a dSYM bundle produced + by dsymutil(1), so run dsymutil here and pass the bundle name + down to the superclass method instead.""" + t_start = time.time() + print("Running Mac pre-processing on file: %s" % (file,), file=sys.stderr) + + dsymbundle = file + ".dSYM" + if os.path.exists(dsymbundle): + shutil.rmtree(dsymbundle) + dsymutil = buildconfig.substs["DSYMUTIL"] + # dsymutil takes --arch=foo instead of -a foo like everything else + cmd = ( + [dsymutil] + [a.replace("-a ", "--arch=") for a in self.archs if a] + [file] + ) + print(" ".join(cmd), file=sys.stderr) + + dsymutil_proc = subprocess.Popen( + cmd, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + dsymout, dsymerr = dsymutil_proc.communicate() + if dsymutil_proc.returncode != 0: + raise RuntimeError("Error running dsymutil: %s" % dsymerr) + + # Regular dsymutil won't produce a .dSYM for files without symbols. + if not os.path.exists(dsymbundle): + print("No symbols found in file: %s" % (file,), file=sys.stderr) + return False + + # llvm-dsymutil will produce a .dSYM for files without symbols or + # debug information, but only sometimes will it warn you about this. + # We don't want to run dump_syms on such bundles, because asserts + # will fire in debug mode and who knows what will happen in release. + # + # So we check for the error message and bail if it appears. If it + # doesn't, we carefully check the bundled DWARF to see if dump_syms + # will be OK with it. + if "warning: no debug symbols in" in dsymerr: + print(dsymerr, file=sys.stderr) + return False + + contents_dir = os.path.join(dsymbundle, "Contents", "Resources", "DWARF") + if not os.path.exists(contents_dir): + print( + "No DWARF information in .dSYM bundle %s" % (dsymbundle,), + file=sys.stderr, + ) + return False + + files = os.listdir(contents_dir) + if len(files) != 1: + print("Unexpected files in .dSYM bundle %s" % (files,), file=sys.stderr) + return False + + otool_out = subprocess.check_output( + [buildconfig.substs["OTOOL"], "-l", os.path.join(contents_dir, files[0])], + universal_newlines=True, + ) + if "sectname __debug_info" not in otool_out: + print("No symbols in .dSYM bundle %s" % (dsymbundle,), file=sys.stderr) + return False + + elapsed = time.time() - t_start + print("Finished processing %s in %.2fs" % (file, elapsed), file=sys.stderr) + return dsymbundle + + def CopyExeAndDebugInfo(self, file, debug_file, guid, code_file, code_id): + """ProcessFile has already produced a dSYM bundle, so we should just + copy that to the destination directory. However, we'll package it + into a .tar because it's a bundle, so it's a directory. |file| here is + the original filename.""" + dsymbundle = file + ".dSYM" + rel_path = os.path.join(debug_file, guid, os.path.basename(dsymbundle) + ".tar") + full_path = os.path.abspath(os.path.join(self.symbol_path, rel_path)) + success = subprocess.call( + ["tar", "cf", full_path, os.path.basename(dsymbundle)], + cwd=os.path.dirname(dsymbundle), + stdout=open(os.devnull, "w"), + stderr=subprocess.STDOUT, + ) + if success == 0 and os.path.exists(full_path): + print(rel_path) + + +# Entry point if called as a standalone program + + +def main(): + parser = OptionParser( + usage="usage: %prog [options] " + ) + parser.add_option( + "-c", + "--copy", + action="store_true", + dest="copy_debug", + default=False, + help="Copy debug info files into the same directory structure as symbol files", + ) + parser.add_option( + "-a", + "--archs", + action="store", + dest="archs", + help="Run dump_syms -a for each space separated" + + "cpu architecture in ARCHS (only on OS X)", + ) + parser.add_option( + "-s", + "--srcdir", + action="append", + dest="srcdir", + default=[], + help="Use SRCDIR to determine relative paths to source files", + ) + parser.add_option( + "-v", + "--vcs-info", + action="store_true", + dest="vcsinfo", + help="Try to retrieve VCS info for each FILE listed in the output", + ) + parser.add_option( + "-i", + "--source-index", + action="store_true", + dest="srcsrv", + default=False, + help="Add source index information to debug files, making them suitable" + + " for use in a source server.", + ) + parser.add_option( + "--install-manifest", + action="append", + dest="install_manifests", + default=[], + help="""Use this install manifest to map filenames back +to canonical locations in the source repository. Specify +, as a comma-separated pair.""", + ) + parser.add_option( + "--count-ctors", + action="store_true", + dest="count_ctors", + default=False, + help="Count static initializers", + ) + (options, args) = parser.parse_args() + + # check to see if the pdbstr.exe exists + if options.srcsrv: + if "PDBSTR" not in buildconfig.substs: + print("pdbstr was not found by configure.\n", file=sys.stderr) + sys.exit(1) + + if len(args) < 3: + parser.error("not enough arguments") + exit(1) + + try: + manifests = validate_install_manifests(options.install_manifests) + except (IOError, ValueError) as e: + parser.error(str(e)) + exit(1) + file_mapping = make_file_mapping(manifests) + _, bucket = get_s3_region_and_bucket() + dumper = GetPlatformSpecificDumper( + dump_syms=args[0], + symbol_path=args[1], + copy_debug=options.copy_debug, + archs=options.archs, + srcdirs=options.srcdir, + vcsinfo=options.vcsinfo, + srcsrv=options.srcsrv, + s3_bucket=bucket, + file_mapping=file_mapping, + ) + + dumper.Process(args[2], options.count_ctors) + + +# run main if run directly +if __name__ == "__main__": + main() diff --git a/toolkit/crashreporter/tools/unit-symbolstore.py b/toolkit/crashreporter/tools/unit-symbolstore.py new file mode 100755 index 0000000000..21d577fb63 --- /dev/null +++ b/toolkit/crashreporter/tools/unit-symbolstore.py @@ -0,0 +1,617 @@ +#!/usr/bin/env python +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import shutil +import struct +import subprocess +import sys +import tempfile +import unittest +from unittest import mock +from unittest.mock import patch + +import buildconfig +import mozpack.path as mozpath +import mozunit +import symbolstore +from mozpack.manifests import InstallManifest +from symbolstore import realpath + +# Some simple functions to mock out files that the platform-specific dumpers will accept. +# dump_syms itself will not be run (we mock that call out), but we can't override +# the ShouldProcessFile method since we actually want to test that. + + +def write_elf(filename): + open(filename, "wb").write( + struct.pack("<7B45x", 0x7F, ord("E"), ord("L"), ord("F"), 1, 1, 1) + ) + + +def write_macho(filename): + open(filename, "wb").write(struct.pack("= 1, "should have a FILE line for " + match + ) + # Skip this check for local git repositories. + if not os.path.isdir(mozpath.join(self.topsrcdir, ".hg")): + return + for line in match_lines: + filename = line.split(None, 2)[2] + self.assertEqual("hg:", filename[:3]) + + # Check that nsBrowserApp.cpp is listed as a FILE line, and that + # it was properly mapped to the source repo. + check_hg_path(file_lines, "nsBrowserApp.cpp") + # Also check Sprintf.h to verify that files from dist/include + # are properly mapped. + check_hg_path(file_lines, "mfbt/Sprintf.h") + + +if __name__ == "__main__": + mozunit.main() diff --git a/toolkit/crashreporter/tools/upload_symbols.py b/toolkit/crashreporter/tools/upload_symbols.py new file mode 100644 index 0000000000..eff1f43b2b --- /dev/null +++ b/toolkit/crashreporter/tools/upload_symbols.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This script uploads a symbol archive file from a path or URL passed on the commandline +# to the symbol server at https://symbols.mozilla.org/ . +# +# Using this script requires you to have generated an authentication +# token in the symbol server web interface. You must store the token in a Taskcluster +# secret as the JSON blob `{"token": ""}` and set the `SYMBOL_SECRET` +# environment variable to the name of the Taskcluster secret. Alternately, +# you can put the token in a file and set `SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE` +# environment variable to the path to the file. + +import argparse +import logging +import os +import sys +import tempfile + +import redo +import requests + +log = logging.getLogger("upload-symbols") +log.setLevel(logging.INFO) + +DEFAULT_URL = "https://symbols.mozilla.org/upload/" +MAX_RETRIES = 7 +MAX_ZIP_SIZE = 500000000 # 500 MB + + +def print_error(r): + if r.status_code < 400: + log.error("Error: bad auth token? ({0}: {1})".format(r.status_code, r.reason)) + else: + log.error("Error: got HTTP response {0}: {1}".format(r.status_code, r.reason)) + + log.error( + "Response body:\n{sep}\n{body}\n{sep}\n".format(sep="=" * 20, body=r.text) + ) + + +def get_taskcluster_secret(secret_name): + secrets_url = "http://taskcluster/secrets/v1/secret/{}".format(secret_name) + log.info( + 'Using symbol upload token from the secrets service: "{}"'.format(secrets_url) + ) + res = requests.get(secrets_url) + res.raise_for_status() + secret = res.json() + auth_token = secret["secret"]["token"] + + return auth_token + + +def main(): + logging.basicConfig() + parser = argparse.ArgumentParser( + description="Upload symbols in ZIP using token from Taskcluster secrets service." + ) + parser.add_argument( + "archive", help="Symbols archive file - URL or path to local file" + ) + parser.add_argument( + "--ignore-missing", help="No error on missing files", action="store_true" + ) + args = parser.parse_args() + + def check_file_exists(url): + for i, _ in enumerate(redo.retrier(attempts=MAX_RETRIES), start=1): + try: + resp = requests.head(url, allow_redirects=True) + return resp.status_code == requests.codes.ok + except requests.exceptions.RequestException as e: + log.error("Error: {0}".format(e)) + log.info("Retrying...") + return False + + if args.archive.startswith("http"): + is_existing = check_file_exists(args.archive) + else: + is_existing = os.path.isfile(args.archive) + + if not is_existing: + if args.ignore_missing: + log.info('Archive file "{0}" does not exist!'.format(args.archive)) + return 0 + else: + log.error('Error: archive file "{0}" does not exist!'.format(args.archive)) + return 1 + + try: + tmpdir = None + if args.archive.endswith(".tar.zst"): + tmpdir = tempfile.TemporaryDirectory() + zip_paths = convert_zst_archive(args.archive, tmpdir) + else: + zip_paths = [args.archive] + + for zip_path in zip_paths: + result = upload_symbols(zip_path) + if result: + return result + return 0 + finally: + if tmpdir: + tmpdir.cleanup() + + +def convert_zst_archive(zst_archive, tmpdir): + """ + Convert a .tar.zst file to a zip file + + Our build tasks output .tar.zst files, but the tecken server only allows + .zip files to be uploaded. + + :param zst_archive: path or URL to a .tar.zst source file + :param tmpdir: TemporaryDirectory to store the output zip file in + :returns: path to output zip file + """ + import concurrent.futures + import gzip + import itertools + import tarfile + + import zstandard + from mozpack.files import File + from mozpack.mozjar import Deflater, JarWriter + + def iter_files_from_tar(reader): + ctx = zstandard.ZstdDecompressor() + uncompressed = ctx.stream_reader(reader) + with tarfile.open(mode="r|", fileobj=uncompressed, bufsize=1024 * 1024) as tar: + while True: + info = tar.next() + if info is None: + break + data = tar.extractfile(info).read() + yield (info.name, data) + + def prepare_from(archive, tmpdir): + if archive.startswith("http"): + resp = requests.get(archive, allow_redirects=True, stream=True) + resp.raise_for_status() + reader = resp.raw + # Work around taskcluster generic-worker possibly gzipping the tar.zst. + if resp.headers.get("Content-Encoding") == "gzip": + reader = gzip.GzipFile(fileobj=reader) + else: + reader = open(archive, "rb") + + def handle_file(data): + name, data = data + log.info("Compressing %s", name) + path = os.path.join(tmpdir, name.lstrip("/")) + if name.endswith(".dbg"): + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "wb") as fh: + with gzip.GzipFile(fileobj=fh, mode="wb", compresslevel=5) as c: + c.write(data) + return (name + ".gz", File(path)) + elif name.endswith(".dSYM.tar"): + import bz2 + + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "wb") as fh: + fh.write(bz2.compress(data)) + return (name + ".bz2", File(path)) + elif name.endswith((".pdb", ".exe", ".dll")): + import subprocess + + makecab = os.environ.get("MAKECAB", "makecab") + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "wb") as fh: + fh.write(data) + + subprocess.check_call( + [makecab, "-D", "CompressionType=MSZIP", path, path + "_"], + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, + ) + + return (name[:-1] + "_", File(path + "_")) + else: + deflater = Deflater(compress_level=5) + deflater.write(data) + return (name, deflater) + + with concurrent.futures.ThreadPoolExecutor( + max_workers=os.cpu_count() + ) as executor: + yield from executor.map(handle_file, iter_files_from_tar(reader)) + + reader.close() + + zip_paths_iter = iter( + os.path.join(tmpdir.name, "symbols{}.zip".format("" if i == 1 else i)) + for i in itertools.count(start=1) + ) + zip_path = next(zip_paths_iter) + log.info('Preparing symbol archive "{0}" from "{1}"'.format(zip_path, zst_archive)) + for i, _ in enumerate(redo.retrier(attempts=MAX_RETRIES), start=1): + zip_paths = [] + jar = None + try: + for name, data in prepare_from(zst_archive, tmpdir.name): + if not jar: + jar = JarWriter(zip_path) + zip_paths.append(zip_path) + size = 0 + log.info("Adding %s", name) + jar.add(name, data, compress=not isinstance(data, File)) + size += data.size() if isinstance(data, File) else data.compressed_size + if size > MAX_ZIP_SIZE: + jar.finish() + jar = None + zip_path = next(zip_paths_iter) + log.info('Continuing with symbol archive "{}"'.format(zip_path)) + if jar: + jar.finish() + return zip_paths + except requests.exceptions.RequestException as e: + log.error("Error: {0}".format(e)) + log.info("Retrying...") + + return [] + + +def upload_symbols(zip_path): + """ + Upload symbols to the tecken server + + :param zip_path: path to the zip file to upload + :returns: 0 indicates the upload was successful, non-zero indicates an + error that should be used for the script's exit code + """ + secret_name = os.environ.get("SYMBOL_SECRET") + if secret_name is not None: + auth_token = get_taskcluster_secret(secret_name) + elif "SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE" in os.environ: + token_file = os.environ["SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE"] + + if not os.path.isfile(token_file): + log.error( + 'SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE "{0}" does not exist!'.format( + token_file + ) + ) + return 1 + auth_token = open(token_file, "r").read().strip() + else: + log.error( + "You must set the SYMBOL_SECRET or SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE " + "environment variables!" + ) + return 1 + + # Allow overwriting of the upload url with an environmental variable + if "SOCORRO_SYMBOL_UPLOAD_URL" in os.environ: + url = os.environ["SOCORRO_SYMBOL_UPLOAD_URL"] + else: + url = DEFAULT_URL + + log.info('Uploading symbol file "{0}" to "{1}"'.format(zip_path, url)) + + for i, _ in enumerate(redo.retrier(attempts=MAX_RETRIES), start=1): + log.info("Attempt %d of %d..." % (i, MAX_RETRIES)) + try: + if zip_path.startswith("http"): + zip_arg = {"data": {"url": zip_path}} + else: + zip_arg = {"files": {"symbols.zip": open(zip_path, "rb")}} + r = requests.post( + url, + headers={"Auth-Token": auth_token}, + allow_redirects=False, + # Allow a longer read timeout because uploading by URL means the server + # has to fetch the entire zip file, which can take a while. The load balancer + # in front of symbols.mozilla.org has a 300 second timeout, so we'll use that. + timeout=(300, 300), + **zip_arg + ) + # 408, 429 or any 5XX is likely to be a transient failure. + # Break out for success or other error codes. + if r.ok or (r.status_code < 500 and (r.status_code not in (408, 429))): + break + print_error(r) + except requests.exceptions.RequestException as e: + log.error("Error: {0}".format(e)) + log.info("Retrying...") + else: + log.warning("Maximum retries hit, giving up!") + return 1 + + if r.status_code >= 200 and r.status_code < 300: + log.info("Uploaded successfully!") + return 0 + + print_error(r) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/toolkit/crashreporter/update-breakpad.sh b/toolkit/crashreporter/update-breakpad.sh new file mode 100755 index 0000000000..67c17338d4 --- /dev/null +++ b/toolkit/crashreporter/update-breakpad.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +set -v -e -x + +# Usage: update-breakpad.sh [rev, defaults to HEAD] + +if [ $# -lt 1 ]; then + echo "Usage: update-breakpad.sh /path/to/breakpad/src [rev]" + exit 1 +fi + +crashreporter_dir=`realpath $(dirname $0)` +repo=${crashreporter_dir}/../.. +rm -rf ${crashreporter_dir}/google-breakpad + +breakpad_repo=$1 +rev=${2-HEAD} +(cd $breakpad_repo; git archive --prefix=toolkit/crashreporter/google-breakpad/ $rev) | (cd $repo; tar xf -) +# Breakpad uses gclient for externals, so manually export what we need. +lss_rev=$(cd $breakpad_repo; git show ${rev}:DEPS | python -c "import sys; exec(sys.stdin.read()); sys.stdout.write('%s\n' % deps['src/src/third_party/lss'].split('@')[1])") +(cd $breakpad_repo/src/third_party/lss; git archive --prefix=toolkit/crashreporter/google-breakpad/src/third_party/lss/ $lss_rev) | (cd $repo; tar xf -) + +# remove some extraneous bits +# We've forked src/client toolkit/crashreporter/breakpad-client. +rm -rf \ + ${crashreporter_dir}/google-breakpad/appveyor.yml \ + ${crashreporter_dir}/google-breakpad/autotools/ \ + ${crashreporter_dir}/google-breakpad/docs/ \ + ${crashreporter_dir}/google-breakpad/m4/ \ + ${crashreporter_dir}/google-breakpad/scripts/ \ + ${crashreporter_dir}/google-breakpad/src/client/ \ + ${crashreporter_dir}/google-breakpad/src/processor/testdata/ \ + ${crashreporter_dir}/google-breakpad/src/testing/ \ + ${crashreporter_dir}/google-breakpad/src/third_party/linux \ + ${crashreporter_dir}/google-breakpad/src/third_party/protobuf \ + ${crashreporter_dir}/google-breakpad/src/tools/gyp/ \ + ${crashreporter_dir}/google-breakpad/src/tools/windows/dump_syms/testdata/ \ + ${crashreporter_dir}/google-breakpad/.github/mistaken-pull-closer.yml \ + ${crashreporter_dir}/google-breakpad/.travis.yml + +# restore our Makefile.ins +hg -R ${repo} st -n | grep "Makefile\.in$" | xargs hg revert --no-backup +# and moz.build files +hg -R ${repo} st -n | grep "moz\.build$" | xargs hg revert --no-backup +# and some other makefiles +hg -R ${repo} st -n | grep "objs\.mozbuild$" | xargs hg revert --no-backup + +# Record git rev +(cd $breakpad_repo; git rev-parse $rev) > ${crashreporter_dir}/google-breakpad/GIT-INFO + +# Apply any local patches +shopt -s nullglob +for p in ${crashreporter_dir}/breakpad-patches/*.patch; do + if grep -q -e "--git" $p; then + patch_opts="-p1" + else + patch_opts="-p0" + fi + echo "Applying $p" + if ! filterdiff -x '*/Makefile*' $p | \ + patch -d ${crashreporter_dir}/google-breakpad ${patch_opts}; then + echo "Failed to apply $p" + exit 1 + fi +done +# remove any .orig files that snuck in +find ${crashreporter_dir}/google-breakpad -name "*.orig" -exec rm '{}' \; + +hg addremove ${crashreporter_dir}/google-breakpad/ -- cgit v1.2.3